Merge "Use compile scope when inserting default platform dependency" into androidx-main
diff --git a/OWNERS b/OWNERS
index de833df..b88cc13 100644
--- a/OWNERS
+++ b/OWNERS
@@ -28,6 +28,8 @@
per-file *settings.gradle = [email protected], [email protected]
per-file *libraryversions.toml = [email protected]
per-file *libraryversions.toml = [email protected], [email protected], [email protected]
+# WebKit
+per-file *libraryversions.toml = [email protected], [email protected]
per-file *docs-public/build.gradle = [email protected], [email protected]
# Copybara can self-approve CLs within synced docs.
diff --git a/activity/activity-ktx/src/main/java/androidx/activity/PipHintTracker.kt b/activity/activity-ktx/src/main/java/androidx/activity/PipHintTracker.kt
index 710602a..d130d7f 100644
--- a/activity/activity-ktx/src/main/java/androidx/activity/PipHintTracker.kt
+++ b/activity/activity-ktx/src/main/java/androidx/activity/PipHintTracker.kt
@@ -75,7 +75,7 @@
}
// Check if the view is already attached to the window, if it is then emit the current
// position and start listening for layout changes to track movement.
- if (Api19Impl.isAttachedToWindow(view)) {
+ if (view.isAttachedToWindow) {
trySend(view.positionInWindow())
view.viewTreeObserver.addOnScrollChangedListener(scrollChangeListener)
view.addOnLayoutChangeListener(layoutChangeListener)
@@ -93,11 +93,6 @@
}
}
-@RequiresApi(Build.VERSION_CODES.KITKAT)
-internal object Api19Impl {
- fun isAttachedToWindow(view: View): Boolean = view.isAttachedToWindow
-}
-
@RequiresApi(Build.VERSION_CODES.O)
internal object Api26Impl {
fun setPipParamsSourceRectHint(activity: Activity, hint: Rect) {
diff --git a/activity/activity/src/androidTest/java/androidx/activity/FullyDrawnReporterTest.kt b/activity/activity/src/androidTest/java/androidx/activity/FullyDrawnReporterTest.kt
index 955b8df..0edb154 100644
--- a/activity/activity/src/androidTest/java/androidx/activity/FullyDrawnReporterTest.kt
+++ b/activity/activity/src/androidTest/java/androidx/activity/FullyDrawnReporterTest.kt
@@ -15,14 +15,12 @@
*/
package androidx.activity
-import android.os.Build
import android.view.View
import android.view.ViewTreeObserver.OnDrawListener
import androidx.core.view.OneShotPreDrawListener
import androidx.test.core.app.ActivityScenario
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
-import androidx.test.filters.SdkSuppress
import androidx.testutils.withActivity
import androidx.testutils.withUse
import com.google.common.truth.Truth.assertThat
@@ -39,7 +37,6 @@
@MediumTest
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
class FullyDrawnReporterTest {
@get:Rule
diff --git a/activity/integration-tests/testapp/src/main/java/androidx/activity/integration/testapp/MainActivity.kt b/activity/integration-tests/testapp/src/main/java/androidx/activity/integration/testapp/MainActivity.kt
index 6c46125..819a7dd 100644
--- a/activity/integration-tests/testapp/src/main/java/androidx/activity/integration/testapp/MainActivity.kt
+++ b/activity/integration-tests/testapp/src/main/java/androidx/activity/integration/testapp/MainActivity.kt
@@ -98,28 +98,26 @@
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- if (android.os.Build.VERSION.SDK_INT >= 19) {
- pickVisualMedia = registerForActivityResult(PickVisualMedia()) { uri ->
- toast("Got image: $uri")
- }
- pickMultipleVisualMedia =
- registerForActivityResult(PickMultipleVisualMedia(5)) { uris ->
- var media = ""
- uris.forEach {
- media += "uri: $it \n"
- }
- toast("Got media files: $media")
- }
- createDocument = registerForActivityResult(CreateDocument("image/png")) { uri ->
- toast("Created document: $uri")
- }
- openDocuments = registerForActivityResult(OpenMultipleDocuments()) { uris ->
- var docs = ""
+ pickVisualMedia = registerForActivityResult(PickVisualMedia()) { uri ->
+ toast("Got image: $uri")
+ }
+ pickMultipleVisualMedia =
+ registerForActivityResult(PickMultipleVisualMedia(5)) { uris ->
+ var media = ""
uris.forEach {
- docs += "uri: $it \n"
+ media += "uri: $it \n"
}
- toast("Got documents: $docs")
+ toast("Got media files: $media")
}
+ createDocument = registerForActivityResult(CreateDocument("image/png")) { uri ->
+ toast("Created document: $uri")
+ }
+ openDocuments = registerForActivityResult(OpenMultipleDocuments()) { uris ->
+ var docs = ""
+ uris.forEach {
+ docs += "uri: $it \n"
+ }
+ toast("Got documents: $docs")
}
setContentView {
@@ -145,28 +143,26 @@
button("Pick an image (w/ GET_CONTENT)") {
getContent.launch("image/*")
}
- if (android.os.Build.VERSION.SDK_INT >= 19) {
- button("Pick an image (w/ photo picker)") {
- pickVisualMedia.launch(
- PickVisualMediaRequest(PickVisualMedia.ImageOnly)
- )
- }
- button("Pick a GIF (w/ photo picker)") {
- pickVisualMedia.launch(
- PickVisualMediaRequest(PickVisualMedia.SingleMimeType("image/gif"))
- )
- }
- button("Pick 5 visual media max (w/ photo picker)") {
- pickMultipleVisualMedia.launch(
- PickVisualMediaRequest(PickVisualMedia.ImageAndVideo)
- )
- }
- button("Create document") {
- createDocument.launch("Temp")
- }
- button("Open documents") {
- openDocuments.launch(arrayOf("*/*"))
- }
+ button("Pick an image (w/ photo picker)") {
+ pickVisualMedia.launch(
+ PickVisualMediaRequest(PickVisualMedia.ImageOnly)
+ )
+ }
+ button("Pick a GIF (w/ photo picker)") {
+ pickVisualMedia.launch(
+ PickVisualMediaRequest(PickVisualMedia.SingleMimeType("image/gif"))
+ )
+ }
+ button("Pick 5 visual media max (w/ photo picker)") {
+ pickMultipleVisualMedia.launch(
+ PickVisualMediaRequest(PickVisualMedia.ImageAndVideo)
+ )
+ }
+ button("Create document") {
+ createDocument.launch("Temp")
+ }
+ button("Open documents") {
+ openDocuments.launch(arrayOf("*/*"))
}
button("Start IntentSender") {
val request = IntentSenderRequest.Builder(
diff --git a/annotation/annotation-experimental-lint/src/main/java/androidx/annotation/experimental/lint/ExperimentalDetector.kt b/annotation/annotation-experimental-lint/src/main/java/androidx/annotation/experimental/lint/ExperimentalDetector.kt
index 77b733f..a5cc9aa 100644
--- a/annotation/annotation-experimental-lint/src/main/java/androidx/annotation/experimental/lint/ExperimentalDetector.kt
+++ b/annotation/annotation-experimental-lint/src/main/java/androidx/annotation/experimental/lint/ExperimentalDetector.kt
@@ -75,6 +75,7 @@
import org.jetbrains.uast.getContainingUMethod
import org.jetbrains.uast.java.JavaUAnnotation
import org.jetbrains.uast.toUElement
+import org.jetbrains.uast.toUElementOfType
import org.jetbrains.uast.tryResolve
class ExperimentalDetector : Detector(), SourceCodeScanner {
@@ -98,13 +99,11 @@
// Infer the overridden method by taking the first (and only) abstract method from the
// functional interface being implemented.
val superClass = (lambda.functionalInterfaceType as? PsiClassReferenceType)?.resolve()
- val superMethod = superClass?.allMethods
+ superClass?.toUElementOfType<UClass>()?.methods
?.first { method -> method.isAbstract() }
- ?.toUElement()
-
- if (superMethod is UMethod) {
- checkMethodOverride(context, lambda, superMethod)
- }
+ ?.let { superMethod ->
+ checkMethodOverride(context, lambda, superMethod)
+ }
}
override fun visitClass(
@@ -920,4 +919,5 @@
} == true
private fun PsiModifierListOwner.isAbstract(): Boolean =
- modifierList?.hasModifierProperty(PsiModifier.ABSTRACT) == true
+ modifierList?.hasModifierProperty(PsiModifier.ABSTRACT) == true ||
+ hasModifierProperty(PsiModifier.ABSTRACT)
diff --git a/annotation/annotation-experimental-lint/src/test/kotlin/androidx/annotation/experimental/lint/ExperimentalDetectorTest.kt b/annotation/annotation-experimental-lint/src/test/kotlin/androidx/annotation/experimental/lint/ExperimentalDetectorTest.kt
index d1f5856..3c4ede5 100644
--- a/annotation/annotation-experimental-lint/src/test/kotlin/androidx/annotation/experimental/lint/ExperimentalDetectorTest.kt
+++ b/annotation/annotation-experimental-lint/src/test/kotlin/androidx/annotation/experimental/lint/ExperimentalDetectorTest.kt
@@ -344,6 +344,33 @@
check(*input).expect(expected)
}
+ @Test
+ fun resolveSamWithValueClass() {
+ val input = arrayOf(
+ kotlin(
+ """
+ @JvmInline
+ value class MyValue(val p: Int)
+
+ fun interface FunInterface {
+ fun sam(): MyValue
+ }
+
+ fun itfConsumer(itf: FunInterface) {
+ itf.sam().p
+ }
+
+ fun test() {
+ itfConsumer {
+ MyValue(42)
+ }
+ }
+ """.trimIndent()
+ )
+ )
+ check(*input).expectClean()
+ }
+
/* ktlint-disable max-line-length */
companion object {
/**
diff --git a/appactions/builtintypes/builtintypes/samples/src/main/java/androidx/appactions/builtintypes/samples/properties/ExceptDateSamples.kt b/appactions/builtintypes/builtintypes/samples/src/main/java/androidx/appactions/builtintypes/samples/properties/ExceptDateSamples.kt
index a265e12..56c43e7 100644
--- a/appactions/builtintypes/builtintypes/samples/src/main/java/androidx/appactions/builtintypes/samples/properties/ExceptDateSamples.kt
+++ b/appactions/builtintypes/builtintypes/samples/src/main/java/androidx/appactions/builtintypes/samples/properties/ExceptDateSamples.kt
@@ -26,14 +26,13 @@
public fun exceptDateMapWhenUsage(exceptDate: ExceptDate) =
exceptDate.mapWhen(
object : ExceptDate.Mapper<String> {
- public override fun date(instance: LocalDate): String = """Got LocalDate: $instance"""
+ override fun date(instance: LocalDate): String = """Got LocalDate: $instance"""
- public override fun localDateTime(instance: LocalDateTime): String =
+ override fun localDateTime(instance: LocalDateTime): String =
"""Got a local DateTime: $instance"""
- public override fun instant(instance: Instant): String =
- """Got an absolute DateTime: $instance"""
+ override fun instant(instance: Instant): String = """Got an absolute DateTime: $instance"""
- public override fun orElse(): String = """Got some unrecognized variant: $exceptDate"""
+ override fun orElse(): String = """Got some unrecognized variant: $exceptDate"""
}
)
diff --git a/appactions/builtintypes/builtintypes/samples/src/main/java/androidx/appactions/builtintypes/samples/types/DayOfWeekSamples.kt b/appactions/builtintypes/builtintypes/samples/src/main/java/androidx/appactions/builtintypes/samples/types/DayOfWeekSamples.kt
index 395abf4..1bdc8b2 100644
--- a/appactions/builtintypes/builtintypes/samples/src/main/java/androidx/appactions/builtintypes/samples/types/DayOfWeekSamples.kt
+++ b/appactions/builtintypes/builtintypes/samples/src/main/java/androidx/appactions/builtintypes/samples/types/DayOfWeekSamples.kt
@@ -23,22 +23,22 @@
public fun dayOfWeekMapWhenUsage(dayOfWeek: DayOfWeek) =
dayOfWeek.mapWhen(
object : DayOfWeek.Mapper<String> {
- public override fun friday(): String = "Got Friday"
+ override fun friday(): String = "Got Friday"
- public override fun monday(): String = "Got Monday"
+ override fun monday(): String = "Got Monday"
- public override fun publicHolidays(): String = "Got PublicHolidays"
+ override fun publicHolidays(): String = "Got PublicHolidays"
- public override fun saturday(): String = "Got Saturday"
+ override fun saturday(): String = "Got Saturday"
- public override fun sunday(): String = "Got Sunday"
+ override fun sunday(): String = "Got Sunday"
- public override fun thursday(): String = "Got Thursday"
+ override fun thursday(): String = "Got Thursday"
- public override fun tuesday(): String = "Got Tuesday"
+ override fun tuesday(): String = "Got Tuesday"
- public override fun wednesday(): String = "Got Wednesday"
+ override fun wednesday(): String = "Got Wednesday"
- public override fun orElse(): String = """Got some unrecognized DayOfWeek: $dayOfWeek"""
+ override fun orElse(): String = """Got some unrecognized DayOfWeek: $dayOfWeek"""
}
)
diff --git a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/ByDay.kt b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/ByDay.kt
index 1f536336..1f085e1 100644
--- a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/ByDay.kt
+++ b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/ByDay.kt
@@ -51,7 +51,7 @@
/** Constructor for the [DayOfWeek] variant. */
public constructor(dayOfWeek: DayOfWeek) : this(asDayOfWeek = dayOfWeek)
- public override fun toString(): String = toString(includeWrapperName = true)
+ override fun toString(): String = toString(includeWrapperName = true)
internal fun toString(includeWrapperName: Boolean): String =
when {
@@ -64,12 +64,12 @@
else -> error("No variant present in ByDay")
}
- public override fun equals(other: Any?): Boolean {
+ override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is ByDay) return false
if (asDayOfWeek != other.asDayOfWeek) return false
return true
}
- public override fun hashCode(): Int = Objects.hash(asDayOfWeek)
+ override fun hashCode(): Int = Objects.hash(asDayOfWeek)
}
diff --git a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/EndDate.kt b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/EndDate.kt
index 2c5db36..18964fb 100644
--- a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/EndDate.kt
+++ b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/EndDate.kt
@@ -51,7 +51,7 @@
/** Constructor for the [LocalDate] variant. */
public constructor(date: LocalDate) : this(asDate = date)
- public override fun toString(): String = toString(includeWrapperName = true)
+ override fun toString(): String = toString(includeWrapperName = true)
internal fun toString(includeWrapperName: Boolean): String =
when {
@@ -64,12 +64,12 @@
else -> error("No variant present in EndDate")
}
- public override fun equals(other: Any?): Boolean {
+ override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is EndDate) return false
if (asDate != other.asDate) return false
return true
}
- public override fun hashCode(): Int = Objects.hash(asDate)
+ override fun hashCode(): Int = Objects.hash(asDate)
}
diff --git a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/EndTime.kt b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/EndTime.kt
index 7b66224..58d1b00 100644
--- a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/EndTime.kt
+++ b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/EndTime.kt
@@ -56,7 +56,7 @@
/** Constructor for the [LocalTime] variant. */
public constructor(time: LocalTime) : this(asTime = time)
- public override fun toString(): String = toString(includeWrapperName = true)
+ override fun toString(): String = toString(includeWrapperName = true)
internal fun toString(includeWrapperName: Boolean): String =
when {
@@ -69,12 +69,12 @@
else -> error("No variant present in EndTime")
}
- public override fun equals(other: Any?): Boolean {
+ override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is EndTime) return false
if (asTime != other.asTime) return false
return true
}
- public override fun hashCode(): Int = Objects.hash(asTime)
+ override fun hashCode(): Int = Objects.hash(asTime)
}
diff --git a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/ExceptDate.kt b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/ExceptDate.kt
index a2e81d0..4e15b62 100644
--- a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/ExceptDate.kt
+++ b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/ExceptDate.kt
@@ -92,7 +92,7 @@
else -> error("No variant present in ExceptDate")
}
- public override fun toString(): String = toString(includeWrapperName = true)
+ override fun toString(): String = toString(includeWrapperName = true)
internal fun toString(includeWrapperName: Boolean): String =
when {
@@ -117,7 +117,7 @@
else -> error("No variant present in ExceptDate")
}
- public override fun equals(other: Any?): Boolean {
+ override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is ExceptDate) return false
if (asDate != other.asDate) return false
@@ -126,7 +126,7 @@
return true
}
- public override fun hashCode(): Int = Objects.hash(asDate, asLocalDateTime, asInstant)
+ override fun hashCode(): Int = Objects.hash(asDate, asLocalDateTime, asInstant)
/** Maps each of the possible variants of [ExceptDate] to some [R]. */
public interface Mapper<R> {
diff --git a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/Name.kt b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/Name.kt
index 5348a83..a2d3f08 100644
--- a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/Name.kt
+++ b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/Name.kt
@@ -47,7 +47,7 @@
/** Constructor for the [String] variant. */
public constructor(text: String) : this(asText = text)
- public override fun toString(): String = toString(includeWrapperName = true)
+ override fun toString(): String = toString(includeWrapperName = true)
internal fun toString(includeWrapperName: Boolean): String =
when {
@@ -60,12 +60,12 @@
else -> error("No variant present in Name")
}
- public override fun equals(other: Any?): Boolean {
+ override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Name) return false
if (asText != other.asText) return false
return true
}
- public override fun hashCode(): Int = Objects.hash(asText)
+ override fun hashCode(): Int = Objects.hash(asText)
}
diff --git a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/RepeatFrequency.kt b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/RepeatFrequency.kt
index c66b581..861e71d 100644
--- a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/RepeatFrequency.kt
+++ b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/RepeatFrequency.kt
@@ -52,7 +52,7 @@
/** Constructor for the [Duration] variant. */
public constructor(duration: Duration) : this(asDuration = duration)
- public override fun toString(): String = toString(includeWrapperName = true)
+ override fun toString(): String = toString(includeWrapperName = true)
internal fun toString(includeWrapperName: Boolean): String =
when {
@@ -65,12 +65,12 @@
else -> error("No variant present in RepeatFrequency")
}
- public override fun equals(other: Any?): Boolean {
+ override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is RepeatFrequency) return false
if (asDuration != other.asDuration) return false
return true
}
- public override fun hashCode(): Int = Objects.hash(asDuration)
+ override fun hashCode(): Int = Objects.hash(asDuration)
}
diff --git a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/StartDate.kt b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/StartDate.kt
index f6c2b67..431b420 100644
--- a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/StartDate.kt
+++ b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/StartDate.kt
@@ -51,7 +51,7 @@
/** Constructor for the [LocalDate] variant. */
public constructor(date: LocalDate) : this(asDate = date)
- public override fun toString(): String = toString(includeWrapperName = true)
+ override fun toString(): String = toString(includeWrapperName = true)
internal fun toString(includeWrapperName: Boolean): String =
when {
@@ -64,12 +64,12 @@
else -> error("No variant present in StartDate")
}
- public override fun equals(other: Any?): Boolean {
+ override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is StartDate) return false
if (asDate != other.asDate) return false
return true
}
- public override fun hashCode(): Int = Objects.hash(asDate)
+ override fun hashCode(): Int = Objects.hash(asDate)
}
diff --git a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/StartTime.kt b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/StartTime.kt
index f6d9144..ea72193 100644
--- a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/StartTime.kt
+++ b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/properties/StartTime.kt
@@ -56,7 +56,7 @@
/** Constructor for the [LocalTime] variant. */
public constructor(time: LocalTime) : this(asTime = time)
- public override fun toString(): String = toString(includeWrapperName = true)
+ override fun toString(): String = toString(includeWrapperName = true)
internal fun toString(includeWrapperName: Boolean): String =
when {
@@ -69,12 +69,12 @@
else -> error("No variant present in StartTime")
}
- public override fun equals(other: Any?): Boolean {
+ override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is StartTime) return false
if (asTime != other.asTime) return false
return true
}
- public override fun hashCode(): Int = Objects.hash(asTime)
+ override fun hashCode(): Int = Objects.hash(asTime)
}
diff --git a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/serializers/DayOfWeekAsCanonicalUrlSerializer.kt b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/serializers/DayOfWeekAsCanonicalUrlSerializer.kt
index 5dfdb1e..0579bf4 100644
--- a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/serializers/DayOfWeekAsCanonicalUrlSerializer.kt
+++ b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/serializers/DayOfWeekAsCanonicalUrlSerializer.kt
@@ -27,8 +27,8 @@
* @see DayOfWeek.canonicalUrl
*/
public class DayOfWeekAsCanonicalUrlSerializer : StringSerializer<DayOfWeek> {
- public override fun serialize(instance: DayOfWeek): String = instance.canonicalUrl
+ override fun serialize(instance: DayOfWeek): String = instance.canonicalUrl
- public override fun deserialize(`value`: String): DayOfWeek? =
+ override fun deserialize(`value`: String): DayOfWeek? =
DayOfWeek.values().firstOrNull { it.canonicalUrl == value }
}
diff --git a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/Alarm.kt b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/Alarm.kt
index a1ff043..4ed329e 100644
--- a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/Alarm.kt
+++ b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/Alarm.kt
@@ -67,7 +67,7 @@
get() = null
/** Converts this [Alarm] to its builder with all the properties copied over. */
- public override fun toBuilder(): Builder<*>
+ override fun toBuilder(): Builder<*>
public companion object {
/** Returns a default implementation of [Builder]. */
@@ -82,7 +82,7 @@
*/
public interface Builder<Self : Builder<Self>> : Thing.Builder<Self> {
/** Returns a built [Alarm]. */
- public override fun build(): Alarm
+ override fun build(): Alarm
/** Sets the `alarmSchedule`. */
@Suppress("DocumentExceptions")
@@ -106,8 +106,8 @@
* )
* class MyAlarm internal constructor(
* alarm: Alarm,
- * val foo: String,
- * val bars: List<Int>,
+ * @Document.StringProperty val foo: String,
+ * @Document.LongProperty val bars: List<Int>,
* ) : AbstractAlarm<
* MyAlarm,
* MyAlarm.Builder
@@ -127,6 +127,7 @@
* .addBars(bars)
* }
*
+ * @Document.BuilderProducer
* class Builder :
* AbstractAlarm.Builder<
* Builder,
@@ -142,11 +143,11 @@
Builder : AbstractAlarm.Builder<Builder, Self>
>
internal constructor(
- public final override val namespace: String,
- public final override val alarmSchedule: Schedule?,
- @get:Suppress("AutoBoxing") public final override val isAlarmEnabled: Boolean?,
- public final override val identifier: String,
- public final override val name: Name?,
+ final override val namespace: String,
+ final override val alarmSchedule: Schedule?,
+ @get:Suppress("AutoBoxing") final override val isAlarmEnabled: Boolean?,
+ final override val identifier: String,
+ final override val name: Name?,
) : Alarm {
/**
* Human readable name for the concrete [Self] class.
@@ -170,7 +171,7 @@
/** Returns a concrete [Builder] with the additional, non-[Alarm] properties copied over. */
protected abstract fun toBuilderWithAdditionalPropertiesOnly(): Builder
- public final override fun toBuilder(): Builder =
+ final override fun toBuilder(): Builder =
toBuilderWithAdditionalPropertiesOnly()
.setNamespace(namespace)
.setAlarmSchedule(alarmSchedule)
@@ -178,7 +179,7 @@
.setIdentifier(identifier)
.setName(name)
- public final override fun equals(other: Any?): Boolean {
+ final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
other as Self
@@ -191,10 +192,10 @@
return true
}
- public final override fun hashCode(): Int =
+ final override fun hashCode(): Int =
Objects.hash(namespace, alarmSchedule, isAlarmEnabled, identifier, name, additionalProperties)
- public final override fun toString(): String {
+ final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
if (namespace.isNotEmpty()) {
attributes["namespace"] = namespace
@@ -221,11 +222,13 @@
*
* Allows for extension like:
* ```kt
+ * @Document(...)
* class MyAlarm :
* : AbstractAlarm<
* MyAlarm,
* MyAlarm.Builder>(...) {
*
+ * @Document.BuilderProducer
* class Builder
* : AbstractAlarm.Builder<
* Builder,
@@ -307,36 +310,36 @@
*/
@Suppress("BuilderSetStyle") protected abstract fun buildFromAlarm(alarm: Alarm): Built
- public final override fun build(): Built =
+ final override fun build(): Built =
buildFromAlarm(AlarmImpl(namespace, alarmSchedule, isAlarmEnabled, identifier, name))
- public final override fun setNamespace(namespace: String): Self {
+ final override fun setNamespace(namespace: String): Self {
this.namespace = namespace
return this as Self
}
- public final override fun setAlarmSchedule(schedule: Schedule?): Self {
+ final override fun setAlarmSchedule(schedule: Schedule?): Self {
this.alarmSchedule = schedule
return this as Self
}
- public final override fun setAlarmEnabled(@Suppress("AutoBoxing") boolean: Boolean?): Self {
+ final override fun setAlarmEnabled(@Suppress("AutoBoxing") boolean: Boolean?): Self {
this.isAlarmEnabled = boolean
return this as Self
}
- public final override fun setIdentifier(text: String): Self {
+ final override fun setIdentifier(text: String): Self {
this.identifier = text
return this as Self
}
- public final override fun setName(name: Name?): Self {
+ final override fun setName(name: Name?): Self {
this.name = name
return this as Self
}
@Suppress("BuilderSetStyle")
- public final override fun equals(other: Any?): Boolean {
+ final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
other as Self
@@ -350,11 +353,11 @@
}
@Suppress("BuilderSetStyle")
- public final override fun hashCode(): Int =
+ final override fun hashCode(): Int =
Objects.hash(namespace, alarmSchedule, isAlarmEnabled, identifier, name, additionalProperties)
@Suppress("BuilderSetStyle")
- public final override fun toString(): String {
+ final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
if (namespace.isNotEmpty()) {
attributes["namespace"] = namespace
diff --git a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/CommonExecutionStatus.kt b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/CommonExecutionStatus.kt
index 067ccb1..9bf51a9 100644
--- a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/CommonExecutionStatus.kt
+++ b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/CommonExecutionStatus.kt
@@ -49,7 +49,7 @@
)
public interface CommonExecutionStatus : ExecutionStatus {
/** Converts this [CommonExecutionStatus] to its builder with all the properties copied over. */
- public override fun toBuilder(): Builder<*>
+ override fun toBuilder(): Builder<*>
public companion object {
/** Returns a default implementation of [Builder]. */
@@ -66,7 +66,7 @@
*/
public interface Builder<Self : Builder<Self>> : ExecutionStatus.Builder<Self> {
/** Returns a built [CommonExecutionStatus]. */
- public override fun build(): CommonExecutionStatus
+ override fun build(): CommonExecutionStatus
}
}
@@ -81,8 +81,8 @@
* )
* class MyCommonExecutionStatus internal constructor(
* commonExecutionStatus: CommonExecutionStatus,
- * val foo: String,
- * val bars: List<Int>,
+ * @Document.StringProperty val foo: String,
+ * @Document.LongProperty val bars: List<Int>,
* ) : AbstractCommonExecutionStatus<
* MyCommonExecutionStatus,
* MyCommonExecutionStatus.Builder
@@ -102,6 +102,7 @@
* .addBars(bars)
* }
*
+ * @Document.BuilderProducer
* class Builder :
* AbstractCommonExecutionStatus.Builder<
* Builder,
@@ -113,13 +114,13 @@
*/
@Suppress("UNCHECKED_CAST")
public abstract class AbstractCommonExecutionStatus<
- Self : AbstractCommonExecutionStatus<Self, Builder>,
- Builder : AbstractCommonExecutionStatus.Builder<Builder, Self>
- >
+ Self : AbstractCommonExecutionStatus<Self, Builder>,
+ Builder : AbstractCommonExecutionStatus.Builder<Builder, Self>
+>
internal constructor(
- public final override val namespace: String,
- public final override val identifier: String,
- public final override val name: Name?,
+ final override val namespace: String,
+ final override val identifier: String,
+ final override val name: Name?,
) : CommonExecutionStatus {
/**
* Human readable name for the concrete [Self] class.
@@ -152,13 +153,13 @@
*/
protected abstract fun toBuilderWithAdditionalPropertiesOnly(): Builder
- public final override fun toBuilder(): Builder =
+ final override fun toBuilder(): Builder =
toBuilderWithAdditionalPropertiesOnly()
.setNamespace(namespace)
.setIdentifier(identifier)
.setName(name)
- public final override fun equals(other: Any?): Boolean {
+ final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
other as Self
@@ -169,10 +170,10 @@
return true
}
- public final override fun hashCode(): Int =
+ final override fun hashCode(): Int =
Objects.hash(namespace, identifier, name, additionalProperties)
- public final override fun toString(): String {
+ final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
if (namespace.isNotEmpty()) {
attributes["namespace"] = namespace
@@ -193,11 +194,13 @@
*
* Allows for extension like:
* ```kt
+ * @Document(...)
* class MyCommonExecutionStatus :
* : AbstractCommonExecutionStatus<
* MyCommonExecutionStatus,
* MyCommonExecutionStatus.Builder>(...) {
*
+ * @Document.BuilderProducer
* class Builder
* : AbstractCommonExecutionStatus.Builder<
* Builder,
@@ -244,9 +247,9 @@
*/
@Suppress("StaticFinalBuilder")
public abstract class Builder<
- Self : Builder<Self, Built>,
- Built : AbstractCommonExecutionStatus<Built, Self>
- > : CommonExecutionStatus.Builder<Self> {
+ Self : Builder<Self, Built>,
+ Built : AbstractCommonExecutionStatus<Built, Self>
+ > : CommonExecutionStatus.Builder<Self> {
/**
* Human readable name for the concrete [Self] class.
*
@@ -281,26 +284,26 @@
commonExecutionStatus: CommonExecutionStatus
): Built
- public final override fun build(): Built =
+ final override fun build(): Built =
buildFromCommonExecutionStatus(CommonExecutionStatusImpl(namespace, identifier, name))
- public final override fun setNamespace(namespace: String): Self {
+ final override fun setNamespace(namespace: String): Self {
this.namespace = namespace
return this as Self
}
- public final override fun setIdentifier(text: String): Self {
+ final override fun setIdentifier(text: String): Self {
this.identifier = text
return this as Self
}
- public final override fun setName(name: Name?): Self {
+ final override fun setName(name: Name?): Self {
this.name = name
return this as Self
}
@Suppress("BuilderSetStyle")
- public final override fun equals(other: Any?): Boolean {
+ final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
other as Self
@@ -312,11 +315,11 @@
}
@Suppress("BuilderSetStyle")
- public final override fun hashCode(): Int =
+ final override fun hashCode(): Int =
Objects.hash(namespace, identifier, name, additionalProperties)
@Suppress("BuilderSetStyle")
- public final override fun toString(): String {
+ final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
if (namespace.isNotEmpty()) {
attributes["namespace"] = namespace
diff --git a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/DayOfWeek.kt b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/DayOfWeek.kt
index 5eb1d15..450fdc3 100644
--- a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/DayOfWeek.kt
+++ b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/DayOfWeek.kt
@@ -54,7 +54,7 @@
else -> mapper.orElse()
}
- public override fun toString(): String = """DayOfWeek($canonicalUrl)"""
+ override fun toString(): String = """DayOfWeek($canonicalUrl)"""
public companion object {
/** The day of the week between Thursday and Saturday. */
diff --git a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/ExecutionStatus.kt b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/ExecutionStatus.kt
index 83fec04..52faa64 100644
--- a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/ExecutionStatus.kt
+++ b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/ExecutionStatus.kt
@@ -49,7 +49,7 @@
)
public interface ExecutionStatus : Intangible {
/** Converts this [ExecutionStatus] to its builder with all the properties copied over. */
- public override fun toBuilder(): Builder<*>
+ override fun toBuilder(): Builder<*>
public companion object {
/** Returns a default implementation of [Builder]. */
@@ -66,7 +66,7 @@
*/
public interface Builder<Self : Builder<Self>> : Intangible.Builder<Self> {
/** Returns a built [ExecutionStatus]. */
- public override fun build(): ExecutionStatus
+ override fun build(): ExecutionStatus
}
}
@@ -81,8 +81,8 @@
* )
* class MyExecutionStatus internal constructor(
* executionStatus: ExecutionStatus,
- * val foo: String,
- * val bars: List<Int>,
+ * @Document.StringProperty val foo: String,
+ * @Document.LongProperty val bars: List<Int>,
* ) : AbstractExecutionStatus<
* MyExecutionStatus,
* MyExecutionStatus.Builder
@@ -102,6 +102,7 @@
* .addBars(bars)
* }
*
+ * @Document.BuilderProducer
* class Builder :
* AbstractExecutionStatus.Builder<
* Builder,
@@ -113,13 +114,13 @@
*/
@Suppress("UNCHECKED_CAST")
public abstract class AbstractExecutionStatus<
- Self : AbstractExecutionStatus<Self, Builder>,
- Builder : AbstractExecutionStatus.Builder<Builder, Self>
- >
+ Self : AbstractExecutionStatus<Self, Builder>,
+ Builder : AbstractExecutionStatus.Builder<Builder, Self>
+>
internal constructor(
- public final override val namespace: String,
- public final override val identifier: String,
- public final override val name: Name?,
+ final override val namespace: String,
+ final override val identifier: String,
+ final override val name: Name?,
) : ExecutionStatus {
/**
* Human readable name for the concrete [Self] class.
@@ -145,13 +146,13 @@
*/
protected abstract fun toBuilderWithAdditionalPropertiesOnly(): Builder
- public final override fun toBuilder(): Builder =
+ final override fun toBuilder(): Builder =
toBuilderWithAdditionalPropertiesOnly()
.setNamespace(namespace)
.setIdentifier(identifier)
.setName(name)
- public final override fun equals(other: Any?): Boolean {
+ final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
other as Self
@@ -162,10 +163,10 @@
return true
}
- public final override fun hashCode(): Int =
+ final override fun hashCode(): Int =
Objects.hash(namespace, identifier, name, additionalProperties)
- public final override fun toString(): String {
+ final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
if (namespace.isNotEmpty()) {
attributes["namespace"] = namespace
@@ -186,11 +187,13 @@
*
* Allows for extension like:
* ```kt
+ * @Document(...)
* class MyExecutionStatus :
* : AbstractExecutionStatus<
* MyExecutionStatus,
* MyExecutionStatus.Builder>(...) {
*
+ * @Document.BuilderProducer
* class Builder
* : AbstractExecutionStatus.Builder<
* Builder,
@@ -237,9 +240,9 @@
*/
@Suppress("StaticFinalBuilder")
public abstract class Builder<
- Self : Builder<Self, Built>,
- Built : AbstractExecutionStatus<Built, Self>
- > : ExecutionStatus.Builder<Self> {
+ Self : Builder<Self, Built>,
+ Built : AbstractExecutionStatus<Built, Self>
+ > : ExecutionStatus.Builder<Self> {
/**
* Human readable name for the concrete [Self] class.
*
@@ -271,26 +274,26 @@
@Suppress("BuilderSetStyle")
protected abstract fun buildFromExecutionStatus(executionStatus: ExecutionStatus): Built
- public final override fun build(): Built =
+ final override fun build(): Built =
buildFromExecutionStatus(ExecutionStatusImpl(namespace, identifier, name))
- public final override fun setNamespace(namespace: String): Self {
+ final override fun setNamespace(namespace: String): Self {
this.namespace = namespace
return this as Self
}
- public final override fun setIdentifier(text: String): Self {
+ final override fun setIdentifier(text: String): Self {
this.identifier = text
return this as Self
}
- public final override fun setName(name: Name?): Self {
+ final override fun setName(name: Name?): Self {
this.name = name
return this as Self
}
@Suppress("BuilderSetStyle")
- public final override fun equals(other: Any?): Boolean {
+ final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
other as Self
@@ -302,11 +305,11 @@
}
@Suppress("BuilderSetStyle")
- public final override fun hashCode(): Int =
+ final override fun hashCode(): Int =
Objects.hash(namespace, identifier, name, additionalProperties)
@Suppress("BuilderSetStyle")
- public final override fun toString(): String {
+ final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
if (namespace.isNotEmpty()) {
attributes["namespace"] = namespace
diff --git a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/GenericErrorStatus.kt b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/GenericErrorStatus.kt
index 6fd1add..9b05a4a 100644
--- a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/GenericErrorStatus.kt
+++ b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/GenericErrorStatus.kt
@@ -45,7 +45,7 @@
)
public interface GenericErrorStatus : CommonExecutionStatus {
/** Converts this [GenericErrorStatus] to its builder with all the properties copied over. */
- public override fun toBuilder(): Builder<*>
+ override fun toBuilder(): Builder<*>
public companion object {
/** Returns a default implementation of [Builder]. */
@@ -62,7 +62,7 @@
*/
public interface Builder<Self : Builder<Self>> : CommonExecutionStatus.Builder<Self> {
/** Returns a built [GenericErrorStatus]. */
- public override fun build(): GenericErrorStatus
+ override fun build(): GenericErrorStatus
}
}
@@ -77,8 +77,8 @@
* )
* class MyGenericErrorStatus internal constructor(
* genericErrorStatus: GenericErrorStatus,
- * val foo: String,
- * val bars: List<Int>,
+ * @Document.StringProperty val foo: String,
+ * @Document.LongProperty val bars: List<Int>,
* ) : AbstractGenericErrorStatus<
* MyGenericErrorStatus,
* MyGenericErrorStatus.Builder
@@ -98,6 +98,7 @@
* .addBars(bars)
* }
*
+ * @Document.BuilderProducer
* class Builder :
* AbstractGenericErrorStatus.Builder<
* Builder,
@@ -109,13 +110,13 @@
*/
@Suppress("UNCHECKED_CAST")
public abstract class AbstractGenericErrorStatus<
- Self : AbstractGenericErrorStatus<Self, Builder>,
- Builder : AbstractGenericErrorStatus.Builder<Builder, Self>
- >
+ Self : AbstractGenericErrorStatus<Self, Builder>,
+ Builder : AbstractGenericErrorStatus.Builder<Builder, Self>
+>
internal constructor(
- public final override val namespace: String,
- public final override val identifier: String,
- public final override val name: Name?,
+ final override val namespace: String,
+ final override val identifier: String,
+ final override val name: Name?,
) : GenericErrorStatus {
/**
* Human readable name for the concrete [Self] class.
@@ -142,13 +143,13 @@
*/
protected abstract fun toBuilderWithAdditionalPropertiesOnly(): Builder
- public final override fun toBuilder(): Builder =
+ final override fun toBuilder(): Builder =
toBuilderWithAdditionalPropertiesOnly()
.setNamespace(namespace)
.setIdentifier(identifier)
.setName(name)
- public final override fun equals(other: Any?): Boolean {
+ final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
other as Self
@@ -159,10 +160,10 @@
return true
}
- public final override fun hashCode(): Int =
+ final override fun hashCode(): Int =
Objects.hash(namespace, identifier, name, additionalProperties)
- public final override fun toString(): String {
+ final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
if (namespace.isNotEmpty()) {
attributes["namespace"] = namespace
@@ -183,11 +184,13 @@
*
* Allows for extension like:
* ```kt
+ * @Document(...)
* class MyGenericErrorStatus :
* : AbstractGenericErrorStatus<
* MyGenericErrorStatus,
* MyGenericErrorStatus.Builder>(...) {
*
+ * @Document.BuilderProducer
* class Builder
* : AbstractGenericErrorStatus.Builder<
* Builder,
@@ -234,9 +237,9 @@
*/
@Suppress("StaticFinalBuilder")
public abstract class Builder<
- Self : Builder<Self, Built>,
- Built : AbstractGenericErrorStatus<Built, Self>
- > : GenericErrorStatus.Builder<Self> {
+ Self : Builder<Self, Built>,
+ Built : AbstractGenericErrorStatus<Built, Self>
+ > : GenericErrorStatus.Builder<Self> {
/**
* Human readable name for the concrete [Self] class.
*
@@ -271,26 +274,26 @@
genericErrorStatus: GenericErrorStatus
): Built
- public final override fun build(): Built =
+ final override fun build(): Built =
buildFromGenericErrorStatus(GenericErrorStatusImpl(namespace, identifier, name))
- public final override fun setNamespace(namespace: String): Self {
+ final override fun setNamespace(namespace: String): Self {
this.namespace = namespace
return this as Self
}
- public final override fun setIdentifier(text: String): Self {
+ final override fun setIdentifier(text: String): Self {
this.identifier = text
return this as Self
}
- public final override fun setName(name: Name?): Self {
+ final override fun setName(name: Name?): Self {
this.name = name
return this as Self
}
@Suppress("BuilderSetStyle")
- public final override fun equals(other: Any?): Boolean {
+ final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
other as Self
@@ -302,11 +305,11 @@
}
@Suppress("BuilderSetStyle")
- public final override fun hashCode(): Int =
+ final override fun hashCode(): Int =
Objects.hash(namespace, identifier, name, additionalProperties)
@Suppress("BuilderSetStyle")
- public final override fun toString(): String {
+ final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
if (namespace.isNotEmpty()) {
attributes["namespace"] = namespace
diff --git a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/Intangible.kt b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/Intangible.kt
index 7f3e192..09aaac6 100644
--- a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/Intangible.kt
+++ b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/Intangible.kt
@@ -46,7 +46,7 @@
)
public interface Intangible : Thing {
/** Converts this [Intangible] to its builder with all the properties copied over. */
- public override fun toBuilder(): Builder<*>
+ override fun toBuilder(): Builder<*>
public companion object {
/** Returns a default implementation of [Builder]. */
@@ -61,7 +61,7 @@
*/
public interface Builder<Self : Builder<Self>> : Thing.Builder<Self> {
/** Returns a built [Intangible]. */
- public override fun build(): Intangible
+ override fun build(): Intangible
}
}
@@ -76,8 +76,8 @@
* )
* class MyIntangible internal constructor(
* intangible: Intangible,
- * val foo: String,
- * val bars: List<Int>,
+ * @Document.StringProperty val foo: String,
+ * @Document.LongProperty val bars: List<Int>,
* ) : AbstractIntangible<
* MyIntangible,
* MyIntangible.Builder
@@ -97,6 +97,7 @@
* .addBars(bars)
* }
*
+ * @Document.BuilderProducer
* class Builder :
* AbstractIntangible.Builder<
* Builder,
@@ -108,13 +109,13 @@
*/
@Suppress("UNCHECKED_CAST")
public abstract class AbstractIntangible<
- Self : AbstractIntangible<Self, Builder>,
- Builder : AbstractIntangible.Builder<Builder, Self>
- >
+ Self : AbstractIntangible<Self, Builder>,
+ Builder : AbstractIntangible.Builder<Builder, Self>
+>
internal constructor(
- public final override val namespace: String,
- public final override val identifier: String,
- public final override val name: Name?,
+ final override val namespace: String,
+ final override val identifier: String,
+ final override val name: Name?,
) : Intangible {
/**
* Human readable name for the concrete [Self] class.
@@ -138,13 +139,13 @@
/** Returns a concrete [Builder] with the additional, non-[Intangible] properties copied over. */
protected abstract fun toBuilderWithAdditionalPropertiesOnly(): Builder
- public final override fun toBuilder(): Builder =
+ final override fun toBuilder(): Builder =
toBuilderWithAdditionalPropertiesOnly()
.setNamespace(namespace)
.setIdentifier(identifier)
.setName(name)
- public final override fun equals(other: Any?): Boolean {
+ final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
other as Self
@@ -155,10 +156,10 @@
return true
}
- public final override fun hashCode(): Int =
+ final override fun hashCode(): Int =
Objects.hash(namespace, identifier, name, additionalProperties)
- public final override fun toString(): String {
+ final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
if (namespace.isNotEmpty()) {
attributes["namespace"] = namespace
@@ -179,11 +180,13 @@
*
* Allows for extension like:
* ```kt
+ * @Document(...)
* class MyIntangible :
* : AbstractIntangible<
* MyIntangible,
* MyIntangible.Builder>(...) {
*
+ * @Document.BuilderProducer
* class Builder
* : AbstractIntangible.Builder<
* Builder,
@@ -230,9 +233,9 @@
*/
@Suppress("StaticFinalBuilder")
public abstract class Builder<
- Self : Builder<Self, Built>,
- Built : AbstractIntangible<Built, Self>
- > : Intangible.Builder<Self> {
+ Self : Builder<Self, Built>,
+ Built : AbstractIntangible<Built, Self>
+ > : Intangible.Builder<Self> {
/**
* Human readable name for the concrete [Self] class.
*
@@ -264,26 +267,26 @@
@Suppress("BuilderSetStyle")
protected abstract fun buildFromIntangible(intangible: Intangible): Built
- public final override fun build(): Built =
+ final override fun build(): Built =
buildFromIntangible(IntangibleImpl(namespace, identifier, name))
- public final override fun setNamespace(namespace: String): Self {
+ final override fun setNamespace(namespace: String): Self {
this.namespace = namespace
return this as Self
}
- public final override fun setIdentifier(text: String): Self {
+ final override fun setIdentifier(text: String): Self {
this.identifier = text
return this as Self
}
- public final override fun setName(name: Name?): Self {
+ final override fun setName(name: Name?): Self {
this.name = name
return this as Self
}
@Suppress("BuilderSetStyle")
- public final override fun equals(other: Any?): Boolean {
+ final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
other as Self
@@ -295,11 +298,11 @@
}
@Suppress("BuilderSetStyle")
- public final override fun hashCode(): Int =
+ final override fun hashCode(): Int =
Objects.hash(namespace, identifier, name, additionalProperties)
@Suppress("BuilderSetStyle")
- public final override fun toString(): String {
+ final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
if (namespace.isNotEmpty()) {
attributes["namespace"] = namespace
diff --git a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/ObjectCreationLimitReachedStatus.kt b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/ObjectCreationLimitReachedStatus.kt
index e5cc7ed..bb7888c 100644
--- a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/ObjectCreationLimitReachedStatus.kt
+++ b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/ObjectCreationLimitReachedStatus.kt
@@ -50,7 +50,7 @@
* Converts this [ObjectCreationLimitReachedStatus] to its builder with all the properties copied
* over.
*/
- public override fun toBuilder(): Builder<*>
+ override fun toBuilder(): Builder<*>
public companion object {
/** Returns a default implementation of [Builder]. */
@@ -67,7 +67,7 @@
*/
public interface Builder<Self : Builder<Self>> : ExecutionStatus.Builder<Self> {
/** Returns a built [ObjectCreationLimitReachedStatus]. */
- public override fun build(): ObjectCreationLimitReachedStatus
+ override fun build(): ObjectCreationLimitReachedStatus
}
}
@@ -82,8 +82,8 @@
* )
* class MyObjectCreationLimitReachedStatus internal constructor(
* objectCreationLimitReachedStatus: ObjectCreationLimitReachedStatus,
- * val foo: String,
- * val bars: List<Int>,
+ * @Document.StringProperty val foo: String,
+ * @Document.LongProperty val bars: List<Int>,
* ) : AbstractObjectCreationLimitReachedStatus<
* MyObjectCreationLimitReachedStatus,
* MyObjectCreationLimitReachedStatus.Builder
@@ -103,6 +103,7 @@
* .addBars(bars)
* }
*
+ * @Document.BuilderProducer
* class Builder :
* AbstractObjectCreationLimitReachedStatus.Builder<
* Builder,
@@ -114,13 +115,13 @@
*/
@Suppress("UNCHECKED_CAST")
public abstract class AbstractObjectCreationLimitReachedStatus<
- Self : AbstractObjectCreationLimitReachedStatus<Self, Builder>,
- Builder : AbstractObjectCreationLimitReachedStatus.Builder<Builder, Self>
- >
+ Self : AbstractObjectCreationLimitReachedStatus<Self, Builder>,
+ Builder : AbstractObjectCreationLimitReachedStatus.Builder<Builder, Self>
+>
internal constructor(
- public final override val namespace: String,
- public final override val identifier: String,
- public final override val name: Name?,
+ final override val namespace: String,
+ final override val identifier: String,
+ final override val name: Name?,
) : ObjectCreationLimitReachedStatus {
/**
* Human readable name for the concrete [Self] class.
@@ -154,13 +155,13 @@
*/
protected abstract fun toBuilderWithAdditionalPropertiesOnly(): Builder
- public final override fun toBuilder(): Builder =
+ final override fun toBuilder(): Builder =
toBuilderWithAdditionalPropertiesOnly()
.setNamespace(namespace)
.setIdentifier(identifier)
.setName(name)
- public final override fun equals(other: Any?): Boolean {
+ final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
other as Self
@@ -171,10 +172,10 @@
return true
}
- public final override fun hashCode(): Int =
+ final override fun hashCode(): Int =
Objects.hash(namespace, identifier, name, additionalProperties)
- public final override fun toString(): String {
+ final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
if (namespace.isNotEmpty()) {
attributes["namespace"] = namespace
@@ -195,11 +196,13 @@
*
* Allows for extension like:
* ```kt
+ * @Document(...)
* class MyObjectCreationLimitReachedStatus :
* : AbstractObjectCreationLimitReachedStatus<
* MyObjectCreationLimitReachedStatus,
* MyObjectCreationLimitReachedStatus.Builder>(...) {
*
+ * @Document.BuilderProducer
* class Builder
* : AbstractObjectCreationLimitReachedStatus.Builder<
* Builder,
@@ -246,9 +249,9 @@
*/
@Suppress("StaticFinalBuilder")
public abstract class Builder<
- Self : Builder<Self, Built>,
- Built : AbstractObjectCreationLimitReachedStatus<Built, Self>
- > : ObjectCreationLimitReachedStatus.Builder<Self> {
+ Self : Builder<Self, Built>,
+ Built : AbstractObjectCreationLimitReachedStatus<Built, Self>
+ > : ObjectCreationLimitReachedStatus.Builder<Self> {
/**
* Human readable name for the concrete [Self] class.
*
@@ -283,28 +286,28 @@
objectCreationLimitReachedStatus: ObjectCreationLimitReachedStatus
): Built
- public final override fun build(): Built =
+ final override fun build(): Built =
buildFromObjectCreationLimitReachedStatus(
ObjectCreationLimitReachedStatusImpl(namespace, identifier, name)
)
- public final override fun setNamespace(namespace: String): Self {
+ final override fun setNamespace(namespace: String): Self {
this.namespace = namespace
return this as Self
}
- public final override fun setIdentifier(text: String): Self {
+ final override fun setIdentifier(text: String): Self {
this.identifier = text
return this as Self
}
- public final override fun setName(name: Name?): Self {
+ final override fun setName(name: Name?): Self {
this.name = name
return this as Self
}
@Suppress("BuilderSetStyle")
- public final override fun equals(other: Any?): Boolean {
+ final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
other as Self
@@ -316,11 +319,11 @@
}
@Suppress("BuilderSetStyle")
- public final override fun hashCode(): Int =
+ final override fun hashCode(): Int =
Objects.hash(namespace, identifier, name, additionalProperties)
@Suppress("BuilderSetStyle")
- public final override fun toString(): String {
+ final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
if (namespace.isNotEmpty()) {
attributes["namespace"] = namespace
@@ -341,8 +344,8 @@
private class ObjectCreationLimitReachedStatusImpl :
AbstractObjectCreationLimitReachedStatus<
- ObjectCreationLimitReachedStatusImpl, ObjectCreationLimitReachedStatusImpl.Builder
- > {
+ ObjectCreationLimitReachedStatusImpl, ObjectCreationLimitReachedStatusImpl.Builder
+ > {
protected override val selfTypeName: String
get() = "ObjectCreationLimitReachedStatus"
@@ -363,8 +366,8 @@
public class Builder :
AbstractObjectCreationLimitReachedStatus.Builder<
- Builder, ObjectCreationLimitReachedStatusImpl
- >() {
+ Builder, ObjectCreationLimitReachedStatusImpl
+ >() {
protected override val selfTypeName: String
get() = "ObjectCreationLimitReachedStatus.Builder"
diff --git a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/Person.kt b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/Person.kt
index 35da28c..51aca82 100644
--- a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/Person.kt
+++ b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/Person.kt
@@ -64,7 +64,7 @@
get() = null
/** Converts this [Person] to its builder with all the properties copied over. */
- public override fun toBuilder(): Builder<*>
+ override fun toBuilder(): Builder<*>
public companion object {
/** Returns a default implementation of [Builder]. */
@@ -79,7 +79,7 @@
*/
public interface Builder<Self : Builder<Self>> : Thing.Builder<Self> {
/** Returns a built [Person]. */
- public override fun build(): Person
+ override fun build(): Person
/** Sets the `email`. */
@Suppress("DocumentExceptions")
@@ -102,8 +102,8 @@
* )
* class MyPerson internal constructor(
* person: Person,
- * val foo: String,
- * val bars: List<Int>,
+ * @Document.StringProperty val foo: String,
+ * @Document.LongProperty val bars: List<Int>,
* ) : AbstractPerson<
* MyPerson,
* MyPerson.Builder
@@ -123,6 +123,7 @@
* .addBars(bars)
* }
*
+ * @Document.BuilderProducer
* class Builder :
* AbstractPerson.Builder<
* Builder,
@@ -138,11 +139,11 @@
Builder : AbstractPerson.Builder<Builder, Self>
>
internal constructor(
- public final override val namespace: String,
- public final override val email: String?,
- public final override val telephoneNumber: String?,
- public final override val identifier: String,
- public final override val name: Name?,
+ final override val namespace: String,
+ final override val email: String?,
+ final override val telephoneNumber: String?,
+ final override val identifier: String,
+ final override val name: Name?,
) : Person {
/**
* Human readable name for the concrete [Self] class.
@@ -166,7 +167,7 @@
/** Returns a concrete [Builder] with the additional, non-[Person] properties copied over. */
protected abstract fun toBuilderWithAdditionalPropertiesOnly(): Builder
- public final override fun toBuilder(): Builder =
+ final override fun toBuilder(): Builder =
toBuilderWithAdditionalPropertiesOnly()
.setNamespace(namespace)
.setEmail(email)
@@ -174,7 +175,7 @@
.setIdentifier(identifier)
.setName(name)
- public final override fun equals(other: Any?): Boolean {
+ final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
other as Self
@@ -187,10 +188,10 @@
return true
}
- public final override fun hashCode(): Int =
+ final override fun hashCode(): Int =
Objects.hash(namespace, email, telephoneNumber, identifier, name, additionalProperties)
- public final override fun toString(): String {
+ final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
if (namespace.isNotEmpty()) {
attributes["namespace"] = namespace
@@ -217,11 +218,13 @@
*
* Allows for extension like:
* ```kt
+ * @Document(...)
* class MyPerson :
* : AbstractPerson<
* MyPerson,
* MyPerson.Builder>(...) {
*
+ * @Document.BuilderProducer
* class Builder
* : AbstractPerson.Builder<
* Builder,
@@ -303,36 +306,36 @@
*/
@Suppress("BuilderSetStyle") protected abstract fun buildFromPerson(person: Person): Built
- public final override fun build(): Built =
+ final override fun build(): Built =
buildFromPerson(PersonImpl(namespace, email, telephoneNumber, identifier, name))
- public final override fun setNamespace(namespace: String): Self {
+ final override fun setNamespace(namespace: String): Self {
this.namespace = namespace
return this as Self
}
- public final override fun setEmail(text: String?): Self {
+ final override fun setEmail(text: String?): Self {
this.email = text
return this as Self
}
- public final override fun setTelephoneNumber(text: String?): Self {
+ final override fun setTelephoneNumber(text: String?): Self {
this.telephoneNumber = text
return this as Self
}
- public final override fun setIdentifier(text: String): Self {
+ final override fun setIdentifier(text: String): Self {
this.identifier = text
return this as Self
}
- public final override fun setName(name: Name?): Self {
+ final override fun setName(name: Name?): Self {
this.name = name
return this as Self
}
@Suppress("BuilderSetStyle")
- public final override fun equals(other: Any?): Boolean {
+ final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
other as Self
@@ -346,11 +349,11 @@
}
@Suppress("BuilderSetStyle")
- public final override fun hashCode(): Int =
+ final override fun hashCode(): Int =
Objects.hash(namespace, email, telephoneNumber, identifier, name, additionalProperties)
@Suppress("BuilderSetStyle")
- public final override fun toString(): String {
+ final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
if (namespace.isNotEmpty()) {
attributes["namespace"] = namespace
diff --git a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/Schedule.kt b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/Schedule.kt
index 0f2ec37..8a83a84 100644
--- a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/Schedule.kt
+++ b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/Schedule.kt
@@ -201,7 +201,7 @@
get() = null
/** Converts this [Schedule] to its builder with all the properties copied over. */
- public override fun toBuilder(): Builder<*>
+ override fun toBuilder(): Builder<*>
public companion object {
/** Returns a default implementation of [Builder]. */
@@ -216,7 +216,7 @@
*/
public interface Builder<Self : Builder<Self>> : Intangible.Builder<Self> {
/** Returns a built [Schedule]. */
- public override fun build(): Schedule
+ override fun build(): Schedule
/** Appends [DayOfWeek] as a value to `byDays`. */
public fun addByDay(dayOfWeek: DayOfWeek): Self = addByDay(ByDay(dayOfWeek))
@@ -340,8 +340,8 @@
* )
* class MySchedule internal constructor(
* schedule: Schedule,
- * val foo: String,
- * val bars: List<Int>,
+ * @Document.StringProperty val foo: String,
+ * @Document.LongProperty val bars: List<Int>,
* ) : AbstractSchedule<
* MySchedule,
* MySchedule.Builder
@@ -361,6 +361,7 @@
* .addBars(bars)
* }
*
+ * @Document.BuilderProducer
* class Builder :
* AbstractSchedule.Builder<
* Builder,
@@ -376,21 +377,21 @@
Builder : AbstractSchedule.Builder<Builder, Self>
>
internal constructor(
- public final override val namespace: String,
- public final override val byDays: List<ByDay>,
- public final override val byMonths: List<Long>,
- public final override val byMonthDays: List<Long>,
- public final override val byMonthWeeks: List<Long>,
- public final override val endDate: EndDate?,
- public final override val endTime: EndTime?,
- public final override val exceptDate: ExceptDate?,
- @get:Suppress("AutoBoxing") public final override val repeatCount: Long?,
- public final override val repeatFrequency: RepeatFrequency?,
- public final override val scheduleTimezone: String?,
- public final override val startDate: StartDate?,
- public final override val startTime: StartTime?,
- public final override val identifier: String,
- public final override val name: Name?,
+ final override val namespace: String,
+ final override val byDays: List<ByDay>,
+ final override val byMonths: List<Long>,
+ final override val byMonthDays: List<Long>,
+ final override val byMonthWeeks: List<Long>,
+ final override val endDate: EndDate?,
+ final override val endTime: EndTime?,
+ final override val exceptDate: ExceptDate?,
+ @get:Suppress("AutoBoxing") final override val repeatCount: Long?,
+ final override val repeatFrequency: RepeatFrequency?,
+ final override val scheduleTimezone: String?,
+ final override val startDate: StartDate?,
+ final override val startTime: StartTime?,
+ final override val identifier: String,
+ final override val name: Name?,
) : Schedule {
/**
* Human readable name for the concrete [Self] class.
@@ -430,7 +431,7 @@
/** Returns a concrete [Builder] with the additional, non-[Schedule] properties copied over. */
protected abstract fun toBuilderWithAdditionalPropertiesOnly(): Builder
- public final override fun toBuilder(): Builder =
+ final override fun toBuilder(): Builder =
toBuilderWithAdditionalPropertiesOnly()
.setNamespace(namespace)
.addByDays(byDays)
@@ -448,7 +449,7 @@
.setIdentifier(identifier)
.setName(name)
- public final override fun equals(other: Any?): Boolean {
+ final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
other as Self
@@ -471,7 +472,7 @@
return true
}
- public final override fun hashCode(): Int =
+ final override fun hashCode(): Int =
Objects.hash(
namespace,
byDays,
@@ -491,7 +492,7 @@
additionalProperties
)
- public final override fun toString(): String {
+ final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
if (namespace.isNotEmpty()) {
attributes["namespace"] = namespace
@@ -548,11 +549,13 @@
*
* Allows for extension like:
* ```kt
+ * @Document(...)
* class MySchedule :
* : AbstractSchedule<
* MySchedule,
* MySchedule.Builder>(...) {
*
+ * @Document.BuilderProducer
* class Builder
* : AbstractSchedule.Builder<
* Builder,
@@ -656,7 +659,7 @@
*/
@Suppress("BuilderSetStyle") protected abstract fun buildFromSchedule(schedule: Schedule): Built
- public final override fun build(): Built =
+ final override fun build(): Built =
buildFromSchedule(
ScheduleImpl(
namespace,
@@ -677,123 +680,123 @@
)
)
- public final override fun setNamespace(namespace: String): Self {
+ final override fun setNamespace(namespace: String): Self {
this.namespace = namespace
return this as Self
}
- public final override fun addByDay(byDay: ByDay): Self {
+ final override fun addByDay(byDay: ByDay): Self {
byDays += byDay
return this as Self
}
- public final override fun addByDays(values: Iterable<ByDay>): Self {
+ final override fun addByDays(values: Iterable<ByDay>): Self {
byDays += values
return this as Self
}
- public final override fun clearByDays(): Self {
+ final override fun clearByDays(): Self {
byDays.clear()
return this as Self
}
- public final override fun addByMonth(integer: Long): Self {
+ final override fun addByMonth(integer: Long): Self {
byMonths += integer
return this as Self
}
- public final override fun addByMonths(values: Iterable<Long>): Self {
+ final override fun addByMonths(values: Iterable<Long>): Self {
byMonths += values
return this as Self
}
- public final override fun clearByMonths(): Self {
+ final override fun clearByMonths(): Self {
byMonths.clear()
return this as Self
}
- public final override fun addByMonthDay(integer: Long): Self {
+ final override fun addByMonthDay(integer: Long): Self {
byMonthDays += integer
return this as Self
}
- public final override fun addByMonthDays(values: Iterable<Long>): Self {
+ final override fun addByMonthDays(values: Iterable<Long>): Self {
byMonthDays += values
return this as Self
}
- public final override fun clearByMonthDays(): Self {
+ final override fun clearByMonthDays(): Self {
byMonthDays.clear()
return this as Self
}
- public final override fun addByMonthWeek(integer: Long): Self {
+ final override fun addByMonthWeek(integer: Long): Self {
byMonthWeeks += integer
return this as Self
}
- public final override fun addByMonthWeeks(values: Iterable<Long>): Self {
+ final override fun addByMonthWeeks(values: Iterable<Long>): Self {
byMonthWeeks += values
return this as Self
}
- public final override fun clearByMonthWeeks(): Self {
+ final override fun clearByMonthWeeks(): Self {
byMonthWeeks.clear()
return this as Self
}
- public final override fun setEndDate(endDate: EndDate?): Self {
+ final override fun setEndDate(endDate: EndDate?): Self {
this.endDate = endDate
return this as Self
}
- public final override fun setEndTime(endTime: EndTime?): Self {
+ final override fun setEndTime(endTime: EndTime?): Self {
this.endTime = endTime
return this as Self
}
- public final override fun setExceptDate(exceptDate: ExceptDate?): Self {
+ final override fun setExceptDate(exceptDate: ExceptDate?): Self {
this.exceptDate = exceptDate
return this as Self
}
- public final override fun setRepeatCount(@Suppress("AutoBoxing") integer: Long?): Self {
+ final override fun setRepeatCount(@Suppress("AutoBoxing") integer: Long?): Self {
this.repeatCount = integer
return this as Self
}
- public final override fun setRepeatFrequency(repeatFrequency: RepeatFrequency?): Self {
+ final override fun setRepeatFrequency(repeatFrequency: RepeatFrequency?): Self {
this.repeatFrequency = repeatFrequency
return this as Self
}
- public final override fun setScheduleTimezone(text: String?): Self {
+ final override fun setScheduleTimezone(text: String?): Self {
this.scheduleTimezone = text
return this as Self
}
- public final override fun setStartDate(startDate: StartDate?): Self {
+ final override fun setStartDate(startDate: StartDate?): Self {
this.startDate = startDate
return this as Self
}
- public final override fun setStartTime(startTime: StartTime?): Self {
+ final override fun setStartTime(startTime: StartTime?): Self {
this.startTime = startTime
return this as Self
}
- public final override fun setIdentifier(text: String): Self {
+ final override fun setIdentifier(text: String): Self {
this.identifier = text
return this as Self
}
- public final override fun setName(name: Name?): Self {
+ final override fun setName(name: Name?): Self {
this.name = name
return this as Self
}
@Suppress("BuilderSetStyle")
- public final override fun equals(other: Any?): Boolean {
+ final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
other as Self
@@ -817,7 +820,7 @@
}
@Suppress("BuilderSetStyle")
- public final override fun hashCode(): Int =
+ final override fun hashCode(): Int =
Objects.hash(
namespace,
byDays,
@@ -838,7 +841,7 @@
)
@Suppress("BuilderSetStyle")
- public final override fun toString(): String {
+ final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
if (namespace.isNotEmpty()) {
attributes["namespace"] = namespace
diff --git a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/SuccessStatus.kt b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/SuccessStatus.kt
index 48d1590..65ac499 100644
--- a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/SuccessStatus.kt
+++ b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/SuccessStatus.kt
@@ -45,7 +45,7 @@
)
public interface SuccessStatus : CommonExecutionStatus {
/** Converts this [SuccessStatus] to its builder with all the properties copied over. */
- public override fun toBuilder(): Builder<*>
+ override fun toBuilder(): Builder<*>
public companion object {
/** Returns a default implementation of [Builder]. */
@@ -62,7 +62,7 @@
*/
public interface Builder<Self : Builder<Self>> : CommonExecutionStatus.Builder<Self> {
/** Returns a built [SuccessStatus]. */
- public override fun build(): SuccessStatus
+ override fun build(): SuccessStatus
}
}
@@ -77,8 +77,8 @@
* )
* class MySuccessStatus internal constructor(
* successStatus: SuccessStatus,
- * val foo: String,
- * val bars: List<Int>,
+ * @Document.StringProperty val foo: String,
+ * @Document.LongProperty val bars: List<Int>,
* ) : AbstractSuccessStatus<
* MySuccessStatus,
* MySuccessStatus.Builder
@@ -98,6 +98,7 @@
* .addBars(bars)
* }
*
+ * @Document.BuilderProducer
* class Builder :
* AbstractSuccessStatus.Builder<
* Builder,
@@ -109,13 +110,13 @@
*/
@Suppress("UNCHECKED_CAST")
public abstract class AbstractSuccessStatus<
- Self : AbstractSuccessStatus<Self, Builder>,
- Builder : AbstractSuccessStatus.Builder<Builder, Self>
- >
+ Self : AbstractSuccessStatus<Self, Builder>,
+ Builder : AbstractSuccessStatus.Builder<Builder, Self>
+>
internal constructor(
- public final override val namespace: String,
- public final override val identifier: String,
- public final override val name: Name?,
+ final override val namespace: String,
+ final override val identifier: String,
+ final override val name: Name?,
) : SuccessStatus {
/**
* Human readable name for the concrete [Self] class.
@@ -141,13 +142,13 @@
*/
protected abstract fun toBuilderWithAdditionalPropertiesOnly(): Builder
- public final override fun toBuilder(): Builder =
+ final override fun toBuilder(): Builder =
toBuilderWithAdditionalPropertiesOnly()
.setNamespace(namespace)
.setIdentifier(identifier)
.setName(name)
- public final override fun equals(other: Any?): Boolean {
+ final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
other as Self
@@ -158,10 +159,10 @@
return true
}
- public final override fun hashCode(): Int =
+ final override fun hashCode(): Int =
Objects.hash(namespace, identifier, name, additionalProperties)
- public final override fun toString(): String {
+ final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
if (namespace.isNotEmpty()) {
attributes["namespace"] = namespace
@@ -182,11 +183,13 @@
*
* Allows for extension like:
* ```kt
+ * @Document(...)
* class MySuccessStatus :
* : AbstractSuccessStatus<
* MySuccessStatus,
* MySuccessStatus.Builder>(...) {
*
+ * @Document.BuilderProducer
* class Builder
* : AbstractSuccessStatus.Builder<
* Builder,
@@ -233,9 +236,9 @@
*/
@Suppress("StaticFinalBuilder")
public abstract class Builder<
- Self : Builder<Self, Built>,
- Built : AbstractSuccessStatus<Built, Self>
- > : SuccessStatus.Builder<Self> {
+ Self : Builder<Self, Built>,
+ Built : AbstractSuccessStatus<Built, Self>
+ > : SuccessStatus.Builder<Self> {
/**
* Human readable name for the concrete [Self] class.
*
@@ -267,26 +270,26 @@
@Suppress("BuilderSetStyle")
protected abstract fun buildFromSuccessStatus(successStatus: SuccessStatus): Built
- public final override fun build(): Built =
+ final override fun build(): Built =
buildFromSuccessStatus(SuccessStatusImpl(namespace, identifier, name))
- public final override fun setNamespace(namespace: String): Self {
+ final override fun setNamespace(namespace: String): Self {
this.namespace = namespace
return this as Self
}
- public final override fun setIdentifier(text: String): Self {
+ final override fun setIdentifier(text: String): Self {
this.identifier = text
return this as Self
}
- public final override fun setName(name: Name?): Self {
+ final override fun setName(name: Name?): Self {
this.name = name
return this as Self
}
@Suppress("BuilderSetStyle")
- public final override fun equals(other: Any?): Boolean {
+ final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
other as Self
@@ -298,11 +301,11 @@
}
@Suppress("BuilderSetStyle")
- public final override fun hashCode(): Int =
+ final override fun hashCode(): Int =
Objects.hash(namespace, identifier, name, additionalProperties)
@Suppress("BuilderSetStyle")
- public final override fun toString(): String {
+ final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
if (namespace.isNotEmpty()) {
attributes["namespace"] = namespace
diff --git a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/Thing.kt b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/Thing.kt
index 585d0c9..f86de3b 100644
--- a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/Thing.kt
+++ b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/Thing.kt
@@ -113,8 +113,8 @@
* )
* class MyThing internal constructor(
* thing: Thing,
- * val foo: String,
- * val bars: List<Int>,
+ * @Document.StringProperty val foo: String,
+ * @Document.LongProperty val bars: List<Int>,
* ) : AbstractThing<
* MyThing,
* MyThing.Builder
@@ -134,6 +134,7 @@
* .addBars(bars)
* }
*
+ * @Document.BuilderProducer
* class Builder :
* AbstractThing.Builder<
* Builder,
@@ -149,9 +150,9 @@
Builder : AbstractThing.Builder<Builder, Self>
>
internal constructor(
- public final override val namespace: String,
- public final override val identifier: String,
- public final override val name: Name?,
+ final override val namespace: String,
+ final override val identifier: String,
+ final override val name: Name?,
) : Thing {
/**
* Human readable name for the concrete [Self] class.
@@ -173,13 +174,13 @@
/** Returns a concrete [Builder] with the additional, non-[Thing] properties copied over. */
protected abstract fun toBuilderWithAdditionalPropertiesOnly(): Builder
- public final override fun toBuilder(): Builder =
+ final override fun toBuilder(): Builder =
toBuilderWithAdditionalPropertiesOnly()
.setNamespace(namespace)
.setIdentifier(identifier)
.setName(name)
- public final override fun equals(other: Any?): Boolean {
+ final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
other as Self
@@ -190,10 +191,10 @@
return true
}
- public final override fun hashCode(): Int =
+ final override fun hashCode(): Int =
Objects.hash(namespace, identifier, name, additionalProperties)
- public final override fun toString(): String {
+ final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
if (namespace.isNotEmpty()) {
attributes["namespace"] = namespace
@@ -214,11 +215,13 @@
*
* Allows for extension like:
* ```kt
+ * @Document(...)
* class MyThing :
* : AbstractThing<
* MyThing,
* MyThing.Builder>(...) {
*
+ * @Document.BuilderProducer
* class Builder
* : AbstractThing.Builder<
* Builder,
@@ -296,26 +299,25 @@
*/
@Suppress("BuilderSetStyle") protected abstract fun buildFromThing(thing: Thing): Built
- public final override fun build(): Built =
- buildFromThing(ThingImpl(namespace, identifier, name))
+ final override fun build(): Built = buildFromThing(ThingImpl(namespace, identifier, name))
- public final override fun setNamespace(namespace: String): Self {
+ final override fun setNamespace(namespace: String): Self {
this.namespace = namespace
return this as Self
}
- public final override fun setIdentifier(text: String): Self {
+ final override fun setIdentifier(text: String): Self {
this.identifier = text
return this as Self
}
- public final override fun setName(name: Name?): Self {
+ final override fun setName(name: Name?): Self {
this.name = name
return this as Self
}
@Suppress("BuilderSetStyle")
- public final override fun equals(other: Any?): Boolean {
+ final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
other as Self
@@ -327,11 +329,11 @@
}
@Suppress("BuilderSetStyle")
- public final override fun hashCode(): Int =
+ final override fun hashCode(): Int =
Objects.hash(namespace, identifier, name, additionalProperties)
@Suppress("BuilderSetStyle")
- public final override fun toString(): String {
+ final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
if (namespace.isNotEmpty()) {
attributes["namespace"] = namespace
diff --git a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/Timer.kt b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/Timer.kt
index a40ebf1..c34b587 100644
--- a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/Timer.kt
+++ b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/Timer.kt
@@ -57,7 +57,7 @@
get() = null
/** Converts this [Timer] to its builder with all the properties copied over. */
- public override fun toBuilder(): Builder<*>
+ override fun toBuilder(): Builder<*>
public companion object {
/** Returns a default implementation of [Builder]. */
@@ -72,7 +72,7 @@
*/
public interface Builder<Self : Builder<Self>> : Thing.Builder<Self> {
/** Returns a built [Timer]. */
- public override fun build(): Timer
+ override fun build(): Timer
/** Sets the `duration`. */
@Suppress("DocumentExceptions")
@@ -91,8 +91,8 @@
* )
* class MyTimer internal constructor(
* timer: Timer,
- * val foo: String,
- * val bars: List<Int>,
+ * @Document.StringProperty val foo: String,
+ * @Document.LongProperty val bars: List<Int>,
* ) : AbstractTimer<
* MyTimer,
* MyTimer.Builder
@@ -112,6 +112,7 @@
* .addBars(bars)
* }
*
+ * @Document.BuilderProducer
* class Builder :
* AbstractTimer.Builder<
* Builder,
@@ -127,10 +128,10 @@
Builder : AbstractTimer.Builder<Builder, Self>
>
internal constructor(
- public final override val namespace: String,
- public final override val duration: Duration?,
- public final override val identifier: String,
- public final override val name: Name?,
+ final override val namespace: String,
+ final override val duration: Duration?,
+ final override val identifier: String,
+ final override val name: Name?,
) : Timer {
/**
* Human readable name for the concrete [Self] class.
@@ -154,14 +155,14 @@
/** Returns a concrete [Builder] with the additional, non-[Timer] properties copied over. */
protected abstract fun toBuilderWithAdditionalPropertiesOnly(): Builder
- public final override fun toBuilder(): Builder =
+ final override fun toBuilder(): Builder =
toBuilderWithAdditionalPropertiesOnly()
.setNamespace(namespace)
.setDuration(duration)
.setIdentifier(identifier)
.setName(name)
- public final override fun equals(other: Any?): Boolean {
+ final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
other as Self
@@ -173,10 +174,10 @@
return true
}
- public final override fun hashCode(): Int =
+ final override fun hashCode(): Int =
Objects.hash(namespace, duration, identifier, name, additionalProperties)
- public final override fun toString(): String {
+ final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
if (namespace.isNotEmpty()) {
attributes["namespace"] = namespace
@@ -200,11 +201,13 @@
*
* Allows for extension like:
* ```kt
+ * @Document(...)
* class MyTimer :
* : AbstractTimer<
* MyTimer,
* MyTimer.Builder>(...) {
*
+ * @Document.BuilderProducer
* class Builder
* : AbstractTimer.Builder<
* Builder,
@@ -284,31 +287,31 @@
*/
@Suppress("BuilderSetStyle") protected abstract fun buildFromTimer(timer: Timer): Built
- public final override fun build(): Built =
+ final override fun build(): Built =
buildFromTimer(TimerImpl(namespace, duration, identifier, name))
- public final override fun setNamespace(namespace: String): Self {
+ final override fun setNamespace(namespace: String): Self {
this.namespace = namespace
return this as Self
}
- public final override fun setDuration(duration: Duration?): Self {
+ final override fun setDuration(duration: Duration?): Self {
this.duration = duration
return this as Self
}
- public final override fun setIdentifier(text: String): Self {
+ final override fun setIdentifier(text: String): Self {
this.identifier = text
return this as Self
}
- public final override fun setName(name: Name?): Self {
+ final override fun setName(name: Name?): Self {
this.name = name
return this as Self
}
@Suppress("BuilderSetStyle")
- public final override fun equals(other: Any?): Boolean {
+ final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
other as Self
@@ -321,11 +324,11 @@
}
@Suppress("BuilderSetStyle")
- public final override fun hashCode(): Int =
+ final override fun hashCode(): Int =
Objects.hash(namespace, duration, identifier, name, additionalProperties)
@Suppress("BuilderSetStyle")
- public final override fun toString(): String {
+ final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
if (namespace.isNotEmpty()) {
attributes["namespace"] = namespace
diff --git a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/UnsupportedOperationStatus.kt b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/UnsupportedOperationStatus.kt
index f4c63a4..7743764 100644
--- a/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/UnsupportedOperationStatus.kt
+++ b/appactions/builtintypes/builtintypes/src/main/java/androidx/appactions/builtintypes/types/UnsupportedOperationStatus.kt
@@ -48,7 +48,7 @@
/**
* Converts this [UnsupportedOperationStatus] to its builder with all the properties copied over.
*/
- public override fun toBuilder(): Builder<*>
+ override fun toBuilder(): Builder<*>
public companion object {
/** Returns a default implementation of [Builder]. */
@@ -65,7 +65,7 @@
*/
public interface Builder<Self : Builder<Self>> : ExecutionStatus.Builder<Self> {
/** Returns a built [UnsupportedOperationStatus]. */
- public override fun build(): UnsupportedOperationStatus
+ override fun build(): UnsupportedOperationStatus
}
}
@@ -80,8 +80,8 @@
* )
* class MyUnsupportedOperationStatus internal constructor(
* unsupportedOperationStatus: UnsupportedOperationStatus,
- * val foo: String,
- * val bars: List<Int>,
+ * @Document.StringProperty val foo: String,
+ * @Document.LongProperty val bars: List<Int>,
* ) : AbstractUnsupportedOperationStatus<
* MyUnsupportedOperationStatus,
* MyUnsupportedOperationStatus.Builder
@@ -101,6 +101,7 @@
* .addBars(bars)
* }
*
+ * @Document.BuilderProducer
* class Builder :
* AbstractUnsupportedOperationStatus.Builder<
* Builder,
@@ -112,13 +113,13 @@
*/
@Suppress("UNCHECKED_CAST")
public abstract class AbstractUnsupportedOperationStatus<
- Self : AbstractUnsupportedOperationStatus<Self, Builder>,
- Builder : AbstractUnsupportedOperationStatus.Builder<Builder, Self>
- >
+ Self : AbstractUnsupportedOperationStatus<Self, Builder>,
+ Builder : AbstractUnsupportedOperationStatus.Builder<Builder, Self>
+>
internal constructor(
- public final override val namespace: String,
- public final override val identifier: String,
- public final override val name: Name?,
+ final override val namespace: String,
+ final override val identifier: String,
+ final override val name: Name?,
) : UnsupportedOperationStatus {
/**
* Human readable name for the concrete [Self] class.
@@ -152,13 +153,13 @@
*/
protected abstract fun toBuilderWithAdditionalPropertiesOnly(): Builder
- public final override fun toBuilder(): Builder =
+ final override fun toBuilder(): Builder =
toBuilderWithAdditionalPropertiesOnly()
.setNamespace(namespace)
.setIdentifier(identifier)
.setName(name)
- public final override fun equals(other: Any?): Boolean {
+ final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
other as Self
@@ -169,10 +170,10 @@
return true
}
- public final override fun hashCode(): Int =
+ final override fun hashCode(): Int =
Objects.hash(namespace, identifier, name, additionalProperties)
- public final override fun toString(): String {
+ final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
if (namespace.isNotEmpty()) {
attributes["namespace"] = namespace
@@ -193,11 +194,13 @@
*
* Allows for extension like:
* ```kt
+ * @Document(...)
* class MyUnsupportedOperationStatus :
* : AbstractUnsupportedOperationStatus<
* MyUnsupportedOperationStatus,
* MyUnsupportedOperationStatus.Builder>(...) {
*
+ * @Document.BuilderProducer
* class Builder
* : AbstractUnsupportedOperationStatus.Builder<
* Builder,
@@ -244,9 +247,9 @@
*/
@Suppress("StaticFinalBuilder")
public abstract class Builder<
- Self : Builder<Self, Built>,
- Built : AbstractUnsupportedOperationStatus<Built, Self>
- > : UnsupportedOperationStatus.Builder<Self> {
+ Self : Builder<Self, Built>,
+ Built : AbstractUnsupportedOperationStatus<Built, Self>
+ > : UnsupportedOperationStatus.Builder<Self> {
/**
* Human readable name for the concrete [Self] class.
*
@@ -281,28 +284,28 @@
unsupportedOperationStatus: UnsupportedOperationStatus
): Built
- public final override fun build(): Built =
+ final override fun build(): Built =
buildFromUnsupportedOperationStatus(
UnsupportedOperationStatusImpl(namespace, identifier, name)
)
- public final override fun setNamespace(namespace: String): Self {
+ final override fun setNamespace(namespace: String): Self {
this.namespace = namespace
return this as Self
}
- public final override fun setIdentifier(text: String): Self {
+ final override fun setIdentifier(text: String): Self {
this.identifier = text
return this as Self
}
- public final override fun setName(name: Name?): Self {
+ final override fun setName(name: Name?): Self {
this.name = name
return this as Self
}
@Suppress("BuilderSetStyle")
- public final override fun equals(other: Any?): Boolean {
+ final override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class.java != other::class.java) return false
other as Self
@@ -314,11 +317,11 @@
}
@Suppress("BuilderSetStyle")
- public final override fun hashCode(): Int =
+ final override fun hashCode(): Int =
Objects.hash(namespace, identifier, name, additionalProperties)
@Suppress("BuilderSetStyle")
- public final override fun toString(): String {
+ final override fun toString(): String {
val attributes = mutableMapOf<String, String>()
if (namespace.isNotEmpty()) {
attributes["namespace"] = namespace
@@ -339,8 +342,8 @@
private class UnsupportedOperationStatusImpl :
AbstractUnsupportedOperationStatus<
- UnsupportedOperationStatusImpl, UnsupportedOperationStatusImpl.Builder
- > {
+ UnsupportedOperationStatusImpl, UnsupportedOperationStatusImpl.Builder
+ > {
protected override val selfTypeName: String
get() = "UnsupportedOperationStatus"
diff --git a/appcompat/appcompat-resources/api/restricted_current.txt b/appcompat/appcompat-resources/api/restricted_current.txt
index 6a66d3a..1278c5d 100644
--- a/appcompat/appcompat-resources/api/restricted_current.txt
+++ b/appcompat/appcompat-resources/api/restricted_current.txt
@@ -58,7 +58,7 @@
package androidx.appcompat.widget {
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class DrawableUtils {
- method public static boolean canSafelyMutateDrawable(android.graphics.drawable.Drawable);
+ method @Deprecated public static boolean canSafelyMutateDrawable(android.graphics.drawable.Drawable);
method public static android.graphics.Rect getOpticalBounds(android.graphics.drawable.Drawable);
method public static android.graphics.PorterDuff.Mode! parseTintMode(int, android.graphics.PorterDuff.Mode!);
field public static final android.graphics.Rect! INSETS_NONE;
diff --git a/appcompat/appcompat-resources/src/main/java/androidx/appcompat/graphics/drawable/DrawableContainerCompat.java b/appcompat/appcompat-resources/src/main/java/androidx/appcompat/graphics/drawable/DrawableContainerCompat.java
index d9730ce..9fd6026 100644
--- a/appcompat/appcompat-resources/src/main/java/androidx/appcompat/graphics/drawable/DrawableContainerCompat.java
+++ b/appcompat/appcompat-resources/src/main/java/androidx/appcompat/graphics/drawable/DrawableContainerCompat.java
@@ -517,9 +517,7 @@
if (Build.VERSION.SDK_INT >= 23) {
DrawableCompat.setLayoutDirection(d, DrawableCompat.getLayoutDirection(this));
}
- if (Build.VERSION.SDK_INT >= 19) {
- DrawableCompat.setAutoMirrored(d, mDrawableContainerState.mAutoMirrored);
- }
+ DrawableCompat.setAutoMirrored(d, mDrawableContainerState.mAutoMirrored);
final Rect hotspotBounds = mHotspotBounds;
if (Build.VERSION.SDK_INT >= 21 && hotspotBounds != null) {
DrawableCompat.setHotspotBounds(d, hotspotBounds.left, hotspotBounds.top,
diff --git a/appcompat/appcompat-resources/src/main/java/androidx/appcompat/widget/DrawableUtils.java b/appcompat/appcompat-resources/src/main/java/androidx/appcompat/widget/DrawableUtils.java
index 9349881..04e9541 100644
--- a/appcompat/appcompat-resources/src/main/java/androidx/appcompat/widget/DrawableUtils.java
+++ b/appcompat/appcompat-resources/src/main/java/androidx/appcompat/widget/DrawableUtils.java
@@ -24,20 +24,13 @@
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.DrawableContainer;
-import android.graphics.drawable.GradientDrawable;
-import android.graphics.drawable.InsetDrawable;
-import android.graphics.drawable.LayerDrawable;
-import android.graphics.drawable.ScaleDrawable;
import android.os.Build;
import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
-import androidx.appcompat.graphics.drawable.DrawableWrapperCompat;
import androidx.core.graphics.drawable.DrawableCompat;
-import androidx.core.graphics.drawable.WrappedDrawable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
@@ -69,13 +62,9 @@
insets.right,
insets.bottom
);
- } else if (Build.VERSION.SDK_INT >= 18) {
+ } else {
return Api18Impl.getOpticalInsets(DrawableCompat.unwrap(drawable));
}
-
- // If we reach here, either we're running on a device pre-v18, the Drawable didn't have
- // any optical insets, or a reflection issue, so we'll just return an empty rect.
- return INSETS_NONE;
}
/**
@@ -101,43 +90,11 @@
/**
* Some drawable implementations have problems with mutation. This method returns false if
* there is a known issue in the given drawable's implementation.
+ *
+ * @deprecated it is always true.
*/
+ @Deprecated
public static boolean canSafelyMutateDrawable(@NonNull Drawable drawable) {
- if (Build.VERSION.SDK_INT >= 17) {
- // We'll never return false on API level >= 17, stop early.
- return true;
- }
-
- if (Build.VERSION.SDK_INT < 15 && drawable instanceof InsetDrawable) {
- return false;
- } else if (Build.VERSION.SDK_INT < 15 && drawable instanceof GradientDrawable) {
- // GradientDrawable has a bug pre-ICS which results in mutate() resulting
- // in loss of color
- return false;
- } else if (Build.VERSION.SDK_INT < 17 && drawable instanceof LayerDrawable) {
- return false;
- }
-
- if (drawable instanceof DrawableContainer) {
- // If we have a DrawableContainer, let's traverse its child array
- final Drawable.ConstantState state = drawable.getConstantState();
- if (state instanceof DrawableContainer.DrawableContainerState) {
- final DrawableContainer.DrawableContainerState containerState =
- (DrawableContainer.DrawableContainerState) state;
- for (final Drawable child : containerState.getChildren()) {
- if (!canSafelyMutateDrawable(child)) {
- return false;
- }
- }
- }
- } else if (drawable instanceof WrappedDrawable) {
- return canSafelyMutateDrawable(((WrappedDrawable) drawable).getWrappedDrawable());
- } else if (drawable instanceof DrawableWrapperCompat) {
- return canSafelyMutateDrawable(((DrawableWrapperCompat) drawable).getDrawable());
- } else if (drawable instanceof ScaleDrawable) {
- return canSafelyMutateDrawable(((ScaleDrawable) drawable).getDrawable());
- }
-
return true;
}
@@ -179,8 +136,7 @@
}
}
- // Only accessible on SDK_INT >= 18 and < 29.
- @RequiresApi(18)
+ // Only accessible on SDK_INT < 29.
static class Api18Impl {
private static final boolean sReflectionSuccessful;
private static final Method sGetOpticalInsets;
diff --git a/appcompat/appcompat-resources/src/main/java/androidx/appcompat/widget/ResourceManagerInternal.java b/appcompat/appcompat-resources/src/main/java/androidx/appcompat/widget/ResourceManagerInternal.java
index 916e4ac..d64a144e 100644
--- a/appcompat/appcompat-resources/src/main/java/androidx/appcompat/widget/ResourceManagerInternal.java
+++ b/appcompat/appcompat-resources/src/main/java/androidx/appcompat/widget/ResourceManagerInternal.java
@@ -203,9 +203,7 @@
final ColorStateList tintList = getTintList(context, resId);
if (tintList != null) {
// First mutate the Drawable, then wrap it and set the tint list
- if (DrawableUtils.canSafelyMutateDrawable(drawable)) {
- drawable = drawable.mutate();
- }
+ drawable = drawable.mutate();
drawable = DrawableCompat.wrap(drawable);
DrawableCompat.setTintList(drawable, tintList);
@@ -438,13 +436,10 @@
static void tintDrawable(Drawable drawable, TintInfo tint, int[] state) {
int[] drawableState = drawable.getState();
- boolean mutated = false;
- if (DrawableUtils.canSafelyMutateDrawable(drawable)) {
- mutated = drawable.mutate() == drawable;
- if (!mutated) {
- Log.d(TAG, "Mutated drawable is not the same instance as the input.");
- return;
- }
+ boolean mutated = drawable.mutate() == drawable;
+ if (!mutated) {
+ Log.d(TAG, "Mutated drawable is not the same instance as the input.");
+ return;
}
// Workaround for b/232275112 where LayerDrawable loses its state on mutate().
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/AppCompatVectorDrawableIntegrationTest.java b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/AppCompatVectorDrawableIntegrationTest.java
index 8ed530e..d05ef8a 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/AppCompatVectorDrawableIntegrationTest.java
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/AppCompatVectorDrawableIntegrationTest.java
@@ -89,17 +89,13 @@
assertEquals("Left side should be white", Color.red(leftColor), 255);
assertEquals("Right side should be black", Color.red(rightColor), 0);
- if (Build.VERSION.SDK_INT >= 19) {
- // setLayoutDirection is only available after API 17. However, it correctly set its
- // drawable's layout direction until API 19.
- view1.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
- vectorDrawable.draw(mCanvas);
+ view1.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
+ vectorDrawable.draw(mCanvas);
- leftColor = mBitmap.getPixel(LEFT_CENTER_X, CENTER_Y);
- rightColor = mBitmap.getPixel(RIGHT_CENTER_X, CENTER_Y);
+ leftColor = mBitmap.getPixel(LEFT_CENTER_X, CENTER_Y);
+ rightColor = mBitmap.getPixel(RIGHT_CENTER_X, CENTER_Y);
- assertEquals("Left side should be black", Color.red(leftColor), 0);
- assertEquals("Right side should be white", Color.red(rightColor), 255);
- }
+ assertEquals("Left side should be black", Color.red(leftColor), 0);
+ assertEquals("Right side should be white", Color.red(rightColor), 255);
}
}
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/LocalesLateOnCreateActivity.java b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/LocalesLateOnCreateActivity.java
index 35ee8d3..a25e6a5 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/LocalesLateOnCreateActivity.java
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/LocalesLateOnCreateActivity.java
@@ -68,10 +68,8 @@
Configuration conf = context.getResources().getConfiguration();
if (Build.VERSION.SDK_INT >= 24) {
conf.setLocales(LocaleList.forLanguageTags(locales.toLanguageTags()));
- } else if (Build.VERSION.SDK_INT >= 17) {
- conf.setLocale(locales.get(0));
} else {
- conf.locale = locales.get(0);
+ conf.setLocale(locales.get(0));
}
// updateConfiguration is required to make the configuration change stick.
// updateConfiguration must be called before any use of the actual Resources.
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeCustomApplicationConfigurationTestCase.kt b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeCustomApplicationConfigurationTestCase.kt
index bab064a..80561e1 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeCustomApplicationConfigurationTestCase.kt
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeCustomApplicationConfigurationTestCase.kt
@@ -18,7 +18,6 @@
import android.content.res.Configuration
import android.content.res.Resources
-import android.os.Build
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
import androidx.appcompat.app.NightModeCustomAttachBaseContextActivity.CUSTOM_FONT_SCALE
import androidx.appcompat.app.NightModeCustomAttachBaseContextActivity.CUSTOM_LOCALE
@@ -115,10 +114,6 @@
companion object {
@JvmStatic
@Parameterized.Parameters
- fun data() = if (Build.VERSION.SDK_INT >= 17) {
- listOf(NightSetMode.DEFAULT, NightSetMode.LOCAL)
- } else {
- listOf(NightSetMode.DEFAULT)
- }
+ fun data() = listOf(NightSetMode.DEFAULT, NightSetMode.LOCAL)
}
}
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeCustomApplyOverrideConfigurationActivity.java b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeCustomApplyOverrideConfigurationActivity.java
index 5c9e24e..9e0e311 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeCustomApplyOverrideConfigurationActivity.java
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeCustomApplyOverrideConfigurationActivity.java
@@ -59,11 +59,7 @@
if (locale != null) {
// Configuration.setLocale is added after 17 and Configuration.locale is deprecated
// after 24
- if (Build.VERSION.SDK_INT >= 17) {
- config.setLocale(locale);
- } else {
- config.locale = locale;
- }
+ config.setLocale(locale);
}
return config;
}
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeCustomApplyOverrideConfigurationTestCase.kt b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeCustomApplyOverrideConfigurationTestCase.kt
index fea48d4..e502df0 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeCustomApplyOverrideConfigurationTestCase.kt
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeCustomApplyOverrideConfigurationTestCase.kt
@@ -16,7 +16,6 @@
package androidx.appcompat.app
-import android.os.Build
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
import androidx.appcompat.app.NightModeCustomApplyOverrideConfigurationActivity.CUSTOM_FONT_SCALE
import androidx.appcompat.app.NightModeCustomApplyOverrideConfigurationActivity.CUSTOM_LOCALE
@@ -83,10 +82,6 @@
companion object {
@JvmStatic
@Parameterized.Parameters
- fun data() = if (Build.VERSION.SDK_INT >= 17) {
- listOf(NightSetMode.DEFAULT, NightSetMode.LOCAL)
- } else {
- listOf(NightSetMode.DEFAULT)
- }
+ fun data() = listOf(NightSetMode.DEFAULT, NightSetMode.LOCAL)
}
}
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeCustomAttachBaseContextTestCase.kt b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeCustomAttachBaseContextTestCase.kt
index da4f6d1..62d0906 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeCustomAttachBaseContextTestCase.kt
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeCustomAttachBaseContextTestCase.kt
@@ -16,7 +16,6 @@
package androidx.appcompat.app
-import android.os.Build
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
import androidx.appcompat.app.NightModeCustomAttachBaseContextActivity.CUSTOM_FONT_SCALE
import androidx.appcompat.app.NightModeCustomAttachBaseContextActivity.CUSTOM_LOCALE
@@ -78,10 +77,6 @@
companion object {
@JvmStatic
@Parameterized.Parameters
- fun data() = if (Build.VERSION.SDK_INT >= 17) {
- listOf(NightSetMode.DEFAULT, NightSetMode.LOCAL)
- } else {
- listOf(NightSetMode.DEFAULT)
- }
+ fun data() = listOf(NightSetMode.DEFAULT, NightSetMode.LOCAL)
}
}
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModePreventOverrideConfigTestCase.kt b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModePreventOverrideConfigTestCase.kt
index 29d06b1..075ff08 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModePreventOverrideConfigTestCase.kt
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModePreventOverrideConfigTestCase.kt
@@ -17,7 +17,6 @@
package androidx.appcompat.app
import android.content.res.Configuration
-import android.os.Build
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
import androidx.appcompat.testutils.NightModeActivityTestRule
import androidx.appcompat.testutils.NightModeUtils.NightSetMode
@@ -67,10 +66,6 @@
companion object {
@JvmStatic
@Parameterized.Parameters
- fun data() = if (Build.VERSION.SDK_INT >= 17) {
- listOf(NightSetMode.DEFAULT, NightSetMode.LOCAL)
- } else {
- listOf(NightSetMode.DEFAULT)
- }
+ fun data() = listOf(NightSetMode.DEFAULT, NightSetMode.LOCAL)
}
}
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotateDoesNotRecreateActivityTestCase.kt b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotateDoesNotRecreateActivityTestCase.kt
index 523d88d..c698bba 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotateDoesNotRecreateActivityTestCase.kt
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotateDoesNotRecreateActivityTestCase.kt
@@ -17,7 +17,6 @@
package androidx.appcompat.app
import android.content.res.Configuration
-import android.os.Build
import androidx.appcompat.Orientation
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
@@ -109,10 +108,6 @@
public companion object {
@JvmStatic
@Parameterized.Parameters
- public fun data(): List<NightSetMode> = if (Build.VERSION.SDK_INT >= 17) {
- listOf(NightSetMode.DEFAULT, NightSetMode.LOCAL)
- } else {
- listOf(NightSetMode.DEFAULT)
- }
+ public fun data(): List<NightSetMode> = listOf(NightSetMode.DEFAULT, NightSetMode.LOCAL)
}
}
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotateRecreatesActivityWithConfigTestCase.kt b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotateRecreatesActivityWithConfigTestCase.kt
index f5f1e53..962dfd5 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotateRecreatesActivityWithConfigTestCase.kt
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotateRecreatesActivityWithConfigTestCase.kt
@@ -19,7 +19,6 @@
import android.app.Activity
import android.app.Instrumentation
import android.content.res.Configuration
-import android.os.Build
import androidx.appcompat.Orientation
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
@@ -132,10 +131,6 @@
public companion object {
@JvmStatic
@Parameterized.Parameters
- public fun data(): List<NightSetMode> = if (Build.VERSION.SDK_INT >= 17) {
- listOf(NightSetMode.DEFAULT, NightSetMode.LOCAL)
- } else {
- listOf(NightSetMode.DEFAULT)
- }
+ public fun data(): List<NightSetMode> = listOf(NightSetMode.DEFAULT, NightSetMode.LOCAL)
}
}
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeTestCase.kt b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeTestCase.kt
index 1e3451f..51fc6d3a 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeTestCase.kt
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeTestCase.kt
@@ -19,7 +19,6 @@
import android.content.Context
import android.content.res.Configuration
import android.location.LocationManager
-import android.os.Build
import android.webkit.WebView
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO
@@ -282,10 +281,6 @@
@Parameterized.Parameters
@JvmStatic
- fun data() = if (Build.VERSION.SDK_INT >= 17) {
- listOf(NightSetMode.DEFAULT, NightSetMode.LOCAL)
- } else {
- listOf(NightSetMode.DEFAULT)
- }
+ fun data() = listOf(NightSetMode.DEFAULT, NightSetMode.LOCAL)
}
}
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeUiModeConfigChangesTestCase.kt b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeUiModeConfigChangesTestCase.kt
index fe35b47..f0ebe47 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeUiModeConfigChangesTestCase.kt
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeUiModeConfigChangesTestCase.kt
@@ -17,7 +17,6 @@
package androidx.appcompat.app
import android.content.res.Configuration
-import android.os.Build
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
import androidx.appcompat.testutils.NightModeUtils.NightSetMode
@@ -161,10 +160,6 @@
companion object {
@JvmStatic
@Parameterized.Parameters
- fun data() = if (Build.VERSION.SDK_INT >= 17) {
- listOf(NightSetMode.DEFAULT, NightSetMode.LOCAL)
- } else {
- listOf(NightSetMode.DEFAULT)
- }
+ fun data() = listOf(NightSetMode.DEFAULT, NightSetMode.LOCAL)
}
}
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/testutils/NightModeUtils.kt b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/testutils/NightModeUtils.kt
index 1fb9286..a666cda 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/testutils/NightModeUtils.kt
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/testutils/NightModeUtils.kt
@@ -20,7 +20,6 @@
import android.content.Context
import android.content.pm.ActivityInfo
import android.content.res.Configuration
-import android.os.Build
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
@@ -189,12 +188,7 @@
setMode: NightSetMode
) = when (setMode) {
NightSetMode.DEFAULT -> AppCompatDelegate.setDefaultNightMode(nightMode)
- NightSetMode.LOCAL ->
- if (Build.VERSION.SDK_INT >= 17) {
- activity!!.delegate.localNightMode = nightMode
- } else {
- throw Exception("Local night mode is not supported on SDK_INT < 17")
- }
+ NightSetMode.LOCAL -> activity!!.delegate.localNightMode = nightMode
}
@NightMode
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatBaseAutoSizeTest.java b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatBaseAutoSizeTest.java
index 525e43a..8502458 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatBaseAutoSizeTest.java
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatBaseAutoSizeTest.java
@@ -431,10 +431,8 @@
mActivityTestRule.runOnUiThread(new Runnable() {
@Override
public void run() {
- if (Build.VERSION.SDK_INT >= 17) {
- autoSizeView.setCompoundDrawablesRelative(
- drawable, drawable, drawable, drawable);
- }
+ autoSizeView.setCompoundDrawablesRelative(
+ drawable, drawable, drawable, drawable);
}
});
mInstrumentation.waitForIdleSync();
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java b/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java
index 4976f99..28d90ef 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java
@@ -475,7 +475,7 @@
// Workaround for incorrect default fontScale on earlier SDKs.
overrideConfig.fontScale = 0f;
Configuration referenceConfig =
- Api17Impl.createConfigurationContext(baseContext, overrideConfig)
+ baseContext.createConfigurationContext(overrideConfig)
.getResources().getConfiguration();
// Revert the uiMode change so that the diff doesn't include uiMode.
Configuration baseConfig = baseContext.getResources().getConfiguration();
@@ -2687,11 +2687,9 @@
void setConfigurationLocales(Configuration conf, @NonNull LocaleListCompat locales) {
if (Build.VERSION.SDK_INT >= 24) {
Api24Impl.setLocales(conf, locales);
- } else if (Build.VERSION.SDK_INT >= 17) {
- Api17Impl.setLocale(conf, locales.get(0));
- Api17Impl.setLayoutDirection(conf, locales.get(0));
} else {
- conf.locale = locales.get(0);
+ conf.setLocale(locales.get(0));
+ conf.setLayoutDirection(locales.get(0));
}
}
@@ -2795,9 +2793,7 @@
}
if (newLocales != null && !currentLocales.equals(newLocales)) {
configChanges |= ActivityInfo.CONFIG_LOCALE;
- if (Build.VERSION.SDK_INT >= 17) {
- configChanges |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
- }
+ configChanges |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
}
if (DEBUG) {
@@ -2836,9 +2832,8 @@
// layout direction after recreating in Android S.
if (Build.VERSION.SDK_INT >= 31
&& (configChanges & ActivityInfo.CONFIG_LAYOUT_DIRECTION) != 0) {
- Api17Impl.setLayoutDirection(
- ((Activity) mHost).getWindow().getDecorView(),
- Api17Impl.getLayoutDirection(overrideConfig));
+ View view = ((Activity) mHost).getWindow().getDecorView();
+ view.setLayoutDirection(overrideConfig.getLayoutDirection());
}
ActivityCompat.recreate((Activity) mHost);
handled = true;
@@ -3908,8 +3903,8 @@
delta.smallestScreenWidthDp = change.smallestScreenWidthDp;
}
- if (Build.VERSION.SDK_INT >= 17) {
- Api17Impl.generateConfigDelta_densityDpi(base, change, delta);
+ if (base.densityDpi != change.densityDpi) {
+ delta.densityDpi = change.densityDpi;
}
// Assets sequence and window configuration are not supported.
@@ -3917,44 +3912,6 @@
return delta;
}
- @RequiresApi(17)
- static class Api17Impl {
- private Api17Impl() { }
-
- static void generateConfigDelta_densityDpi(@NonNull Configuration base,
- @NonNull Configuration change, @NonNull Configuration delta) {
- if (base.densityDpi != change.densityDpi) {
- delta.densityDpi = change.densityDpi;
- }
- }
-
- @DoNotInline
- static Context createConfigurationContext(@NonNull Context context,
- @NonNull Configuration overrideConfiguration) {
- return context.createConfigurationContext(overrideConfiguration);
- }
-
- @DoNotInline
- static void setLayoutDirection(Configuration configuration, Locale loc) {
- configuration.setLayoutDirection(loc);
- }
-
- @DoNotInline
- static void setLayoutDirection(View view, int layoutDirection) {
- view.setLayoutDirection(layoutDirection);
- }
-
- @DoNotInline
- static void setLocale(Configuration configuration, Locale loc) {
- configuration.setLocale(loc);
- }
-
- @DoNotInline
- static int getLayoutDirection(Configuration configuration) {
- return configuration.getLayoutDirection();
- }
- }
-
@RequiresApi(21)
static class Api21Impl {
private Api21Impl() { }
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatViewInflater.java b/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatViewInflater.java
index a8936f8..317cd76 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatViewInflater.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatViewInflater.java
@@ -419,7 +419,7 @@
private void backportAccessibilityAttributes(@NonNull Context context, @NonNull View view,
@NonNull AttributeSet attrs) {
- if (Build.VERSION.SDK_INT < 19 || Build.VERSION.SDK_INT > 28) {
+ if (Build.VERSION.SDK_INT > 28) {
return;
}
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/view/ActionBarPolicy.java b/appcompat/appcompat/src/main/java/androidx/appcompat/view/ActionBarPolicy.java
index 9566fa3..9d0943c 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/view/ActionBarPolicy.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/view/ActionBarPolicy.java
@@ -23,7 +23,6 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.os.Build;
-import android.view.ViewConfiguration;
import androidx.annotation.RestrictTo;
import androidx.appcompat.R;
@@ -74,11 +73,7 @@
}
public boolean showsOverflowMenuButton() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- return true;
- } else {
- return !ViewConfiguration.get(mContext).hasPermanentMenuKey();
- }
+ return true;
}
public int getEmbeddedMenuWidthLimit() {
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/view/menu/MenuItemImpl.java b/appcompat/appcompat/src/main/java/androidx/appcompat/view/menu/MenuItemImpl.java
index 6d20471..dbdc39a 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/view/menu/MenuItemImpl.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/view/menu/MenuItemImpl.java
@@ -25,7 +25,6 @@
import android.content.res.Resources;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
-import android.os.Build;
import android.util.Log;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.KeyEvent;
@@ -471,17 +470,7 @@
@Override
public CharSequence getTitleCondensed() {
- final CharSequence ctitle = mTitleCondensed != null ? mTitleCondensed : mTitle;
-
- if (Build.VERSION.SDK_INT < 18 && ctitle != null && !(ctitle instanceof String)) {
- // For devices pre-JB-MR2, where we have a non-String CharSequence, we need to
- // convert this to a String so that EventLog.writeEvent() does not throw an exception
- // in Activity.onMenuItemSelected()
- return ctitle.toString();
- } else {
- // Else, we just return the condensed title
- return ctitle;
- }
+ return mTitleCondensed != null ? mTitleCondensed : mTitle;
}
@Override
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/view/menu/MenuPopupHelper.java b/appcompat/appcompat/src/main/java/androidx/appcompat/view/menu/MenuPopupHelper.java
index 69c498c..aa98768 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/view/menu/MenuPopupHelper.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/view/menu/MenuPopupHelper.java
@@ -22,7 +22,6 @@
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
-import android.os.Build;
import android.view.Display;
import android.view.Gravity;
import android.view.View;
@@ -32,10 +31,8 @@
import android.widget.PopupWindow.OnDismissListener;
import androidx.annotation.AttrRes;
-import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.annotation.StyleRes;
import androidx.appcompat.R;
@@ -233,11 +230,7 @@
final Display display = windowManager.getDefaultDisplay();
final Point displaySize = new Point();
- if (Build.VERSION.SDK_INT >= 17) {
- Api17Impl.getRealSize(display, displaySize);
- } else {
- display.getSize(displaySize);
- }
+ display.getRealSize(displaySize);
final int smallestWidth = Math.min(displaySize.x, displaySize.y);
final int minSmallestWidthCascading = mContext.getResources().getDimensionPixelSize(
@@ -351,16 +344,4 @@
public ListView getListView() {
return getPopup().getListView();
}
-
- @RequiresApi(17)
- static class Api17Impl {
- private Api17Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static void getRealSize(Display display, Point outSize) {
- display.getRealSize(outSize);
- }
- }
}
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/ActionBarOverlayLayout.java b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/ActionBarOverlayLayout.java
index 985c7e2..8fc7067 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/ActionBarOverlayLayout.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/ActionBarOverlayLayout.java
@@ -78,7 +78,6 @@
// Content overlay drawable - generally the action bar's shadow
private Drawable mWindowContentOverlay;
- private boolean mIgnoreWindowContentOverlay;
private boolean mOverlayMode;
private boolean mHasNonEmbeddedTabs;
@@ -168,9 +167,6 @@
setWillNotDraw(mWindowContentOverlay == null);
ta.recycle();
- mIgnoreWindowContentOverlay = context.getApplicationInfo().targetSdkVersion <
- Build.VERSION_CODES.KITKAT;
-
mFlingEstimator = new OverScroller(context);
}
@@ -196,14 +192,6 @@
public void setOverlayMode(boolean overlayMode) {
mOverlayMode = overlayMode;
-
- /*
- * Drawing the window content overlay was broken before K so starting to draw it
- * again unexpectedly will cause artifacts in some apps. They should fix it.
- */
- mIgnoreWindowContentOverlay = overlayMode &&
- getContext().getApplicationInfo().targetSdkVersion <
- Build.VERSION_CODES.KITKAT;
}
public boolean isInOverlayMode() {
@@ -538,7 +526,7 @@
@Override
public void draw(@NonNull Canvas c) {
super.draw(c);
- if (mWindowContentOverlay != null && !mIgnoreWindowContentOverlay) {
+ if (mWindowContentOverlay != null) {
final int top = mActionBarTop.getVisibility() == VISIBLE ?
(int) (mActionBarTop.getBottom() + mActionBarTop.getTranslationY() + 0.5f)
: 0;
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatCheckBox.java b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatCheckBox.java
index 82d92e2..c7d4f79 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatCheckBox.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatCheckBox.java
@@ -117,14 +117,6 @@
setButtonDrawable(AppCompatResources.getDrawable(getContext(), resId));
}
- @Override
- public int getCompoundPaddingLeft() {
- final int value = super.getCompoundPaddingLeft();
- return mCompoundButtonHelper != null
- ? mCompoundButtonHelper.getCompoundPaddingLeft(value)
- : value;
- }
-
/**
* This should be accessed from {@link androidx.core.widget.CompoundButtonCompat}
*/
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatCompoundButtonHelper.java b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatCompoundButtonHelper.java
index 3513f72..bf9b410 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatCompoundButtonHelper.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatCompoundButtonHelper.java
@@ -20,7 +20,6 @@
import android.content.res.Resources;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
-import android.os.Build;
import android.util.AttributeSet;
import android.widget.CompoundButton;
@@ -144,15 +143,4 @@
}
}
- int getCompoundPaddingLeft(int superValue) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
- // Before JB-MR1 the button drawable wasn't taken into account for padding. We'll
- // workaround that here
- Drawable buttonDrawable = CompoundButtonCompat.getButtonDrawable(mView);
- if (buttonDrawable != null) {
- superValue += buttonDrawable.getIntrinsicWidth();
- }
- }
- return superValue;
- }
}
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatDrawableManager.java b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatDrawableManager.java
index 6bd8f11..479200e 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatDrawableManager.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatDrawableManager.java
@@ -309,9 +309,7 @@
}
private void setPorterDuffColorFilter(Drawable d, int color, PorterDuff.Mode mode) {
- if (DrawableUtils.canSafelyMutateDrawable(d)) {
- d = d.mutate();
- }
+ d = d.mutate();
d.setColorFilter(getPorterDuffColorFilter(color, mode == null ? DEFAULT_MODE
: mode));
}
@@ -423,9 +421,7 @@
}
if (colorAttrSet) {
- if (DrawableUtils.canSafelyMutateDrawable(drawable)) {
- drawable = drawable.mutate();
- }
+ drawable = drawable.mutate();
final int color = getThemeAttrColor(context, colorAttr);
drawable.setColorFilter(getPorterDuffColorFilter(color, tintMode));
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatRadioButton.java b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatRadioButton.java
index 693f95f..dee338b 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatRadioButton.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatRadioButton.java
@@ -115,14 +115,6 @@
setButtonDrawable(AppCompatResources.getDrawable(getContext(), resId));
}
- @Override
- public int getCompoundPaddingLeft() {
- final int value = super.getCompoundPaddingLeft();
- return mCompoundButtonHelper != null
- ? mCompoundButtonHelper.getCompoundPaddingLeft(value)
- : value;
- }
-
/**
* This should be accessed from {@link androidx.core.widget.CompoundButtonCompat}
*/
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatTextHelper.java b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatTextHelper.java
index 4eb3371..8408ef6 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatTextHelper.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatTextHelper.java
@@ -548,12 +548,10 @@
applyCompoundDrawableTint(compoundDrawables[2], mDrawableRightTint);
applyCompoundDrawableTint(compoundDrawables[3], mDrawableBottomTint);
}
- if (Build.VERSION.SDK_INT >= 17) {
- if (mDrawableStartTint != null || mDrawableEndTint != null) {
- final Drawable[] compoundDrawables = Api17Impl.getCompoundDrawablesRelative(mView);
- applyCompoundDrawableTint(compoundDrawables[0], mDrawableStartTint);
- applyCompoundDrawableTint(compoundDrawables[2], mDrawableEndTint);
- }
+ if (mDrawableStartTint != null || mDrawableEndTint != null) {
+ final Drawable[] compoundDrawables = Api17Impl.getCompoundDrawablesRelative(mView);
+ applyCompoundDrawableTint(compoundDrawables[0], mDrawableStartTint);
+ applyCompoundDrawableTint(compoundDrawables[2], mDrawableEndTint);
}
}
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatTextViewAutoSizeHelper.java b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatTextViewAutoSizeHelper.java
index 446b6d8..684696a 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatTextViewAutoSizeHelper.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatTextViewAutoSizeHelper.java
@@ -34,7 +34,6 @@
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
-import android.view.View;
import android.widget.TextView;
import androidx.annotation.DoNotInline;
@@ -47,7 +46,6 @@
import androidx.core.view.ViewCompat;
import androidx.core.widget.TextViewCompat;
-import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
@@ -75,11 +73,6 @@
@SuppressLint("BanConcurrentHashMap")
private static java.util.concurrent.ConcurrentHashMap<String, Method>
sTextViewMethodByNameCache = new java.util.concurrent.ConcurrentHashMap<>();
- // Cache of TextView fields used via reflection; the key is the field name and the value is
- // the field itself or null if it can not be found.
- @SuppressLint("BanConcurrentHashMap")
- private static java.util.concurrent.ConcurrentHashMap<String, Field> sTextViewFieldByNameCache =
- new java.util.concurrent.ConcurrentHashMap<>();
// Use this to specify that any of the auto-size configuration int values have not been set.
static final float UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE = -1f;
// Ported from TextView#VERY_WIDE. Represents a maximum width in pixels the TextView takes when
@@ -647,14 +640,12 @@
setRawTextSize(TypedValue.applyDimension(unit, size, res.getDisplayMetrics()));
}
+ @SuppressLint("BanUncheckedReflection")
private void setRawTextSize(float size) {
if (size != mTextView.getPaint().getTextSize()) {
mTextView.getPaint().setTextSize(size);
- boolean isInLayout = false;
- if (Build.VERSION.SDK_INT >= 18) {
- isInLayout = Api18Impl.isInLayout(mTextView);
- }
+ boolean isInLayout = mTextView.isInLayout();
if (mTextView.getLayout() != null) {
// Do not auto-size right after setting the text size.
@@ -731,11 +722,18 @@
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return Api23Impl.createStaticLayoutForMeasuring(
text, alignment, availableWidth, maxLines, mTextView, mTempTextPaint, mImpl);
- } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- return Api16Impl.createStaticLayoutForMeasuring(
- text, alignment, availableWidth, mTextView, mTempTextPaint);
} else {
- return createStaticLayoutForMeasuringPre16(text, alignment, availableWidth);
+ final float lineSpacingMultiplier = mTextView.getLineSpacingMultiplier();
+ final float lineSpacingAdd = mTextView.getLineSpacingExtra();
+ final boolean includePad = mTextView.getIncludeFontPadding();
+
+ // The layout could not be constructed using the builder so fall back to the
+ // most broad constructor.
+ return new StaticLayout(text, mTempTextPaint, availableWidth,
+ alignment,
+ lineSpacingMultiplier,
+ lineSpacingAdd,
+ includePad);
}
}
@@ -749,7 +747,7 @@
}
}
- final int maxLines = Build.VERSION.SDK_INT >= 16 ? Api16Impl.getMaxLines(mTextView) : -1;
+ final int maxLines = mTextView.getMaxLines();
initTempTextPaint(suggestedSizeInPx);
// Needs reflection call due to being private.
@@ -771,25 +769,7 @@
return true;
}
-
- private StaticLayout createStaticLayoutForMeasuringPre16(CharSequence text,
- Layout.Alignment alignment, int availableWidth) {
- // The default values have been inlined with the StaticLayout defaults.
-
- final float lineSpacingMultiplier = accessAndReturnWithDefault(mTextView,
- "mSpacingMult", 1.0f);
- final float lineSpacingAdd = accessAndReturnWithDefault(mTextView,
- "mSpacingAdd", 0.0f);
- final boolean includePad = accessAndReturnWithDefault(mTextView,
- "mIncludePad", true);
-
- return new StaticLayout(text, mTempTextPaint, availableWidth,
- alignment,
- lineSpacingMultiplier,
- lineSpacingAdd,
- includePad);
- }
-
+ @SuppressLint("BanUncheckedReflection")
@SuppressWarnings("unchecked")
// This is marked package-protected so that it doesn't require a synthetic accessor
// when being used from the Impl inner classes
@@ -814,22 +794,6 @@
return result;
}
- @SuppressWarnings("unchecked")
- private static <T> T accessAndReturnWithDefault(@NonNull Object object,
- @NonNull final String fieldName, @NonNull final T defaultValue) {
- try {
- final Field field = getTextViewField(fieldName);
- if (field == null) {
- return defaultValue;
- }
-
- return (T) field.get(object);
- } catch (IllegalAccessException e) {
- Log.w(TAG, "Failed to access TextView#" + fieldName + " member", e);
- return defaultValue;
- }
- }
-
@Nullable
private static Method getTextViewMethod(@NonNull final String methodName) {
try {
@@ -850,25 +814,6 @@
}
}
- @Nullable
- private static Field getTextViewField(@NonNull final String fieldName) {
- try {
- Field field = sTextViewFieldByNameCache.get(fieldName);
- if (field == null) {
- field = TextView.class.getDeclaredField(fieldName);
- if (field != null) {
- field.setAccessible(true);
- sTextViewFieldByNameCache.put(fieldName, field);
- }
- }
-
- return field;
- } catch (NoSuchFieldException e) {
- Log.w(TAG, "Failed to access TextView#" + fieldName + " member", e);
- return null;
- }
- }
-
/**
* @return {@code true} if this widget supports auto-sizing text and has been configured to
* auto-size.
@@ -928,50 +873,4 @@
return layoutBuilder.build();
}
}
-
- @RequiresApi(18)
- private static final class Api18Impl {
- private Api18Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static boolean isInLayout(@NonNull View view) {
- return view.isInLayout();
- }
- }
-
- @RequiresApi(16)
- private static final class Api16Impl {
- private Api16Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static int getMaxLines(@NonNull TextView textView) {
- return textView.getMaxLines();
- }
-
- @DoNotInline
- @NonNull
- static StaticLayout createStaticLayoutForMeasuring(
- @NonNull CharSequence text,
- @NonNull Layout.Alignment alignment,
- int availableWidth,
- @NonNull TextView textView,
- @NonNull TextPaint tempTextPaint
- ) {
- final float lineSpacingMultiplier = textView.getLineSpacingMultiplier();
- final float lineSpacingAdd = textView.getLineSpacingExtra();
- final boolean includePad = textView.getIncludeFontPadding();
-
- // The layout could not be constructed using the builder so fall back to the
- // most broad constructor.
- return new StaticLayout(text, tempTextPaint, availableWidth,
- alignment,
- lineSpacingMultiplier,
- lineSpacingAdd,
- includePad);
- }
- }
}
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/SwitchCompat.java b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/SwitchCompat.java
index c764cb6..24ca26b 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/SwitchCompat.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/SwitchCompat.java
@@ -48,11 +48,9 @@
import android.widget.Switch;
import android.widget.TextView;
-import androidx.annotation.DoNotInline;
import androidx.annotation.FloatRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
import androidx.appcompat.R;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.appcompat.text.AllCapsTransformationMethod;
@@ -1139,9 +1137,7 @@
final float targetPosition = newCheckedState ? 1 : 0;
mPositionAnimator = ObjectAnimator.ofFloat(this, THUMB_POS, targetPosition);
mPositionAnimator.setDuration(THUMB_ANIMATION_DURATION);
- if (Build.VERSION.SDK_INT >= 18) {
- Api18Impl.setAutoCancel(mPositionAnimator, true);
- }
+ mPositionAnimator.setAutoCancel(true);
mPositionAnimator.start();
}
@@ -1692,16 +1688,4 @@
}
}
}
-
- @RequiresApi(18)
- static class Api18Impl {
- private Api18Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static void setAutoCancel(ObjectAnimator objectAnimator, boolean cancel) {
- objectAnimator.setAutoCancel(cancel);
- }
- }
}
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/Toolbar.java b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/Toolbar.java
index b48c66c..9198f6a 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/Toolbar.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/Toolbar.java
@@ -559,9 +559,7 @@
@Override
public void onRtlPropertiesChanged(int layoutDirection) {
- if (Build.VERSION.SDK_INT >= 17) {
- super.onRtlPropertiesChanged(layoutDirection);
- }
+ super.onRtlPropertiesChanged(layoutDirection);
ensureContentInsets();
mContentInsets.setDirection(layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL);
diff --git a/appsearch/appsearch-debug-view/samples/src/main/java/androidx/appsearch/debugview/samples/NotesActivity.java b/appsearch/appsearch-debug-view/samples/src/main/java/androidx/appsearch/debugview/samples/NotesActivity.java
index ab3e69c..5d84149 100644
--- a/appsearch/appsearch-debug-view/samples/src/main/java/androidx/appsearch/debugview/samples/NotesActivity.java
+++ b/appsearch/appsearch-debug-view/samples/src/main/java/androidx/appsearch/debugview/samples/NotesActivity.java
@@ -121,14 +121,13 @@
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
- switch (item.getItemId()) {
- case R.id.app_search_debug:
- Intent intent = new Intent(this, AppSearchDebugActivity.class);
- intent.putExtra(AppSearchDebugActivity.DB_INTENT_KEY, DB_NAME);
- intent.putExtra(AppSearchDebugActivity.STORAGE_TYPE_INTENT_KEY,
- AppSearchDebugActivity.STORAGE_TYPE_LOCAL);
- startActivity(intent);
- return true;
+ if (item.getItemId() == R.id.app_search_debug) {
+ Intent intent = new Intent(this, AppSearchDebugActivity.class);
+ intent.putExtra(AppSearchDebugActivity.DB_INTENT_KEY, DB_NAME);
+ intent.putExtra(AppSearchDebugActivity.STORAGE_TYPE_INTENT_KEY,
+ AppSearchDebugActivity.STORAGE_TYPE_LOCAL);
+ startActivity(intent);
+ return true;
}
return false;
diff --git a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchConfigImpl.java b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchConfigImpl.java
index 13b63f5..d2cb2cf 100644
--- a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchConfigImpl.java
+++ b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchConfigImpl.java
@@ -114,6 +114,16 @@
}
@Override
+ public boolean getUseNewQualifiedIdJoinIndex() {
+ return mIcingOptionsConfig.getUseNewQualifiedIdJoinIndex();
+ }
+
+ @Override
+ public boolean getBuildPropertyExistenceMetadataHits() {
+ return mIcingOptionsConfig.getBuildPropertyExistenceMetadataHits();
+ }
+
+ @Override
public int getMaxDocumentSizeBytes() {
return mLimitConfig.getMaxDocumentSizeBytes();
}
diff --git a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchImpl.java b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchImpl.java
index ecb9768..4c9fbfe 100644
--- a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchImpl.java
+++ b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchImpl.java
@@ -312,6 +312,9 @@
mConfig.getIntegerIndexBucketSplitThreshold())
.setLiteIndexSortAtIndexing(mConfig.getLiteIndexSortAtIndexing())
.setLiteIndexSortSize(mConfig.getLiteIndexSortSize())
+ .setUseNewQualifiedIdJoinIndex(mConfig.getUseNewQualifiedIdJoinIndex())
+ .setBuildPropertyExistenceMetadataHits(
+ mConfig.getBuildPropertyExistenceMetadataHits())
.build();
LogUtil.piiTrace(TAG, "Constructing IcingSearchEngine, request", options);
mIcingSearchEngineLocked = new IcingSearchEngine(options);
diff --git a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/DefaultIcingOptionsConfig.java b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/DefaultIcingOptionsConfig.java
index 4201c4e..11a0c04 100644
--- a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/DefaultIcingOptionsConfig.java
+++ b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/DefaultIcingOptionsConfig.java
@@ -88,4 +88,14 @@
public int getLiteIndexSortSize() {
return DEFAULT_LITE_INDEX_SORT_SIZE;
}
+
+ @Override
+ public boolean getUseNewQualifiedIdJoinIndex() {
+ return DEFAULT_USE_NEW_QUALIFIED_ID_JOIN_INDEX;
+ }
+
+ @Override
+ public boolean getBuildPropertyExistenceMetadataHits() {
+ return DEFAULT_BUILD_PROPERTY_EXISTENCE_METADATA_HITS;
+ }
}
diff --git a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/IcingOptionsConfig.java b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/IcingOptionsConfig.java
index 418569a..870df5a 100644
--- a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/IcingOptionsConfig.java
+++ b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/IcingOptionsConfig.java
@@ -70,6 +70,10 @@
*/
int DEFAULT_LITE_INDEX_SORT_SIZE = 8192; // 8Kib
+ boolean DEFAULT_USE_NEW_QUALIFIED_ID_JOIN_INDEX = false;
+
+ boolean DEFAULT_BUILD_PROPERTY_EXISTENCE_METADATA_HITS = false;
+
/**
* The maximum allowable token length. All tokens in excess of this size will be truncated to
* max_token_length before being indexed.
@@ -206,4 +210,19 @@
* <p>Setting a lower sort size reduces querying latency at the expense of indexing latency.
*/
int getLiteIndexSortSize();
+
+ /**
+ * Flag for {@link com.google.android.icing.proto.IcingSearchEngineOptions}.
+ *
+ * <p>Whether to use the new qualified Id join index.
+ */
+ boolean getUseNewQualifiedIdJoinIndex();
+
+ /**
+ * Flag for {@link com.google.android.icing.proto.IcingSearchEngineOptions}.
+ *
+ * <p>Whether to build the metadata hits used for property existence check, which is required
+ * to support the hasProperty function in advanced query.
+ */
+ boolean getBuildPropertyExistenceMetadataHits();
}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/DocumentClassCreationInfo.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/DocumentClassCreationInfo.java
index 65c7b554..f882f0f 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/DocumentClassCreationInfo.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/DocumentClassCreationInfo.java
@@ -450,8 +450,8 @@
}
/**
- * Makes sure the type is a {@link DeclaredType} with a non-private & non-static method
- * of the form {@code DocumentClass build()}.
+ * Makes sure the builder type is a {@link DeclaredType} with a non-private & non-static
+ * method of the form {@code DocumentClass build()}.
*
* @param annotatedElement The method/class annotated with
* {@code @Document.BuilderProducer}.
@@ -469,12 +469,12 @@
if (builderType.getKind() != TypeKind.DECLARED) {
throw exception;
}
- TypeElement builderClass = (TypeElement) ((DeclaredType) builderType).asElement();
- boolean hasBuildMethod = helper.getAllMethods(builderClass).stream()
- .anyMatch(method -> !method.getModifiers().contains(Modifier.STATIC)
- && !method.getModifiers().contains(Modifier.PRIVATE)
- && helper.isReturnTypeMatching(method, documentClass.asType())
- && method.getParameters().isEmpty());
+ boolean hasBuildMethod = helper.getAllMethods((DeclaredType) builderType)
+ .anyMatch(method -> method.getElement().getSimpleName().contentEquals("build")
+ && !method.getElement().getModifiers().contains(Modifier.STATIC)
+ && !method.getElement().getModifiers().contains(Modifier.PRIVATE)
+ && helper.isReturnTypeMatching(method.getType(), documentClass.asType())
+ && method.getType().getParameterTypes().isEmpty());
if (!hasBuildMethod) {
throw exception;
}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java
index 7884791..8ad865d 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java
@@ -41,6 +41,7 @@
import java.util.Objects;
import java.util.Set;
import java.util.WeakHashMap;
+import java.util.stream.Stream;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
@@ -121,6 +122,7 @@
final TypeMirror mBytePrimitiveType;
private final ProcessingEnvironment mEnv;
private final Types mTypeUtils;
+ private final Elements mElementUtils;
private final WeakHashMap<TypeElement, LinkedHashSet<ExecutableElement>> mAllMethodsCache =
new WeakHashMap<>();
@@ -128,27 +130,27 @@
IntrospectionHelper(ProcessingEnvironment env) {
mEnv = env;
- Elements elementUtil = env.getElementUtils();
+ mElementUtils = env.getElementUtils();
mTypeUtils = env.getTypeUtils();
- mCollectionType = elementUtil.getTypeElement(Collection.class.getName()).asType();
- mListType = elementUtil.getTypeElement(List.class.getName()).asType();
- mStringType = elementUtil.getTypeElement(String.class.getName()).asType();
- mIntegerBoxType = elementUtil.getTypeElement(Integer.class.getName()).asType();
+ mCollectionType = mElementUtils.getTypeElement(Collection.class.getName()).asType();
+ mListType = mElementUtils.getTypeElement(List.class.getName()).asType();
+ mStringType = mElementUtils.getTypeElement(String.class.getName()).asType();
+ mIntegerBoxType = mElementUtils.getTypeElement(Integer.class.getName()).asType();
mIntPrimitiveType = mTypeUtils.unboxedType(mIntegerBoxType);
- mLongBoxType = elementUtil.getTypeElement(Long.class.getName()).asType();
+ mLongBoxType = mElementUtils.getTypeElement(Long.class.getName()).asType();
mLongPrimitiveType = mTypeUtils.unboxedType(mLongBoxType);
- mFloatBoxType = elementUtil.getTypeElement(Float.class.getName()).asType();
+ mFloatBoxType = mElementUtils.getTypeElement(Float.class.getName()).asType();
mFloatPrimitiveType = mTypeUtils.unboxedType(mFloatBoxType);
- mDoubleBoxType = elementUtil.getTypeElement(Double.class.getName()).asType();
+ mDoubleBoxType = mElementUtils.getTypeElement(Double.class.getName()).asType();
mDoublePrimitiveType = mTypeUtils.unboxedType(mDoubleBoxType);
- mBooleanBoxType = elementUtil.getTypeElement(Boolean.class.getName()).asType();
+ mBooleanBoxType = mElementUtils.getTypeElement(Boolean.class.getName()).asType();
mBooleanPrimitiveType = mTypeUtils.unboxedType(mBooleanBoxType);
- mByteBoxType = elementUtil.getTypeElement(Byte.class.getName()).asType();
+ mByteBoxType = mElementUtils.getTypeElement(Byte.class.getName()).asType();
mByteBoxArrayType = mTypeUtils.getArrayType(mByteBoxType);
mBytePrimitiveType = mTypeUtils.unboxedType(mByteBoxType);
mBytePrimitiveArrayType = mTypeUtils.getArrayType(mBytePrimitiveType);
mGenericDocumentType =
- elementUtil.getTypeElement(GENERIC_DOCUMENT_CLASS.canonicalName()).asType();
+ mElementUtils.getTypeElement(GENERIC_DOCUMENT_CLASS.canonicalName()).asType();
}
/**
@@ -402,13 +404,62 @@
}
/**
- * Whether the method returns the specified type.
+ * A method's type and element (i.e. declaration).
+ *
+ * <p>Note: The parameter and return types may differ between the type and the element.
+ * For example,
+ *
+ * <pre>
+ * {@code
+ * public class StringSet implements Set<String> {...}
+ * }
+ * </pre>
+ *
+ * <p>Here, the type of {@code StringSet.add()} is {@code (String) -> boolean} and the element
+ * points to the generic declaration within {@code Set<T>} with a return type of
+ * {@code boolean} and a single parameter of type {@code T}.
+ */
+ public static class MethodTypeAndElement {
+ private final ExecutableType mType;
+ private final ExecutableElement mElement;
+
+ public MethodTypeAndElement(
+ @NonNull ExecutableType type, @NonNull ExecutableElement element) {
+ mType = type;
+ mElement = element;
+ }
+
+ @NonNull
+ public ExecutableType getType() {
+ return mType;
+ }
+
+ @NonNull
+ public ExecutableElement getElement() {
+ return mElement;
+ }
+ }
+
+ /**
+ * Returns a stream of all the methods (including inherited) within a {@link DeclaredType}.
+ *
+ * <p>Does not include constructors.
+ */
+ @NonNull
+ public Stream<MethodTypeAndElement> getAllMethods(@NonNull DeclaredType type) {
+ return mElementUtils.getAllMembers((TypeElement) type.asElement()).stream()
+ .filter(el -> el.getKind() == ElementKind.METHOD)
+ .map(el -> new MethodTypeAndElement(
+ (ExecutableType) mTypeUtils.asMemberOf(type, el),
+ (ExecutableElement) el));
+ }
+
+ /**
+ * Whether the method returns the specified type (or subtype).
*/
public boolean isReturnTypeMatching(
- @NonNull ExecutableElement method, @NonNull TypeMirror type) {
- TypeMirror target = method.getKind() == ElementKind.CONSTRUCTOR
- ? method.getEnclosingElement().asType() : method.getReturnType();
- return mTypeUtils.isSameType(type, target);
+ @NonNull ExecutableType method, @NonNull TypeMirror type) {
+ return mTypeUtils.isAssignable(method.getReturnType(), type);
}
/**
diff --git a/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java b/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java
index 0b5e501..2c9e09d 100644
--- a/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java
+++ b/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java
@@ -2678,6 +2678,48 @@
}
@Test
+ public void testBuilderThatUsesGenerics() throws Exception {
+ Compilation compilation = compile(
+ "@Document\n"
+ + "public class Gift {\n"
+ + " @Document.Namespace private final String mNamespace;\n"
+ + " @Document.Id private final String mId;\n"
+ + " private Gift(String namespace, String id) {\n"
+ + " mNamespace = namespace;\n"
+ + " mId = id;\n"
+ + " }\n"
+ + " public String getNamespace() { return mNamespace; }\n"
+ + " public String getId() { return mId; }\n"
+ + " public static abstract class BaseBuilder<T> {\n"
+ + " public final T build() { return buildInternal(false); }\n"
+ + " // Give this a param to have zero methods with the signature\n"
+ + " // () -> DocumentClass\n"
+ + " protected abstract T buildInternal(boolean ignore);\n"
+ + " }\n"
+ + " @Document.BuilderProducer\n"
+ + " public static class Builder extends BaseBuilder<Gift> {\n"
+ + " private String mNamespace = \"\";\n"
+ + " private String mId = \"\";\n"
+ + " @Override\n"
+ + " protected Gift buildInternal(boolean ignore) {\n"
+ + " return new Gift(mNamespace, mId);\n"
+ + " }\n"
+ + " public Builder setNamespace(String namespace) {\n"
+ + " mNamespace = namespace;\n"
+ + " return this;\n"
+ + " }\n"
+ + " public Builder setId(String id) {\n"
+ + " mId = id;\n"
+ + " return this;\n"
+ + " }\n"
+ + " }\n"
+ + "}");
+ assertThat(compilation).succeededWithoutWarnings();
+ checkResultContains("Gift.java", "Gift.Builder builder = new Gift.Builder()");
+ checkResultContains("Gift.java", "return builder.build()");
+ }
+
+ @Test
public void testCreationByBuilderWithParameter() throws Exception {
Compilation compilation = compile(
"@Document\n"
diff --git a/arch/core/core-runtime/src/main/java/androidx/arch/core/executor/DefaultTaskExecutor.java b/arch/core/core-runtime/src/main/java/androidx/arch/core/executor/DefaultTaskExecutor.java
index b164eb5..99433a0 100644
--- a/arch/core/core-runtime/src/main/java/androidx/arch/core/executor/DefaultTaskExecutor.java
+++ b/arch/core/core-runtime/src/main/java/androidx/arch/core/executor/DefaultTaskExecutor.java
@@ -82,7 +82,7 @@
private static Handler createAsync(@NonNull Looper looper) {
if (Build.VERSION.SDK_INT >= 28) {
return Api28Impl.createAsync(looper);
- } else if (Build.VERSION.SDK_INT >= 17) {
+ } else {
try {
// This constructor was added as private in JB MR1:
// https://android.googlesource.com/platform/frameworks/base/+/refs/heads/jb-mr1-release/core/java/android/os/Handler.java
diff --git a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/task/MergeBaselineProfileTask.kt b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/task/MergeBaselineProfileTask.kt
index 2f2b284..40b06ab 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/task/MergeBaselineProfileTask.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/task/MergeBaselineProfileTask.kt
@@ -20,6 +20,7 @@
import androidx.baselineprofile.gradle.utils.TASK_NAME_SUFFIX
import androidx.baselineprofile.gradle.utils.maybeRegister
import java.io.File
+import kotlin.io.path.Path
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.Project
@@ -262,7 +263,7 @@
logger.warn(
"""
A baseline profile was generated for the variant `${variantName.get()}`:
- file:///$absolutePath
+ ${Path(absolutePath).toUri()}
""".trimIndent()
)
}
@@ -312,7 +313,7 @@
logger.warn(
"""
A startup profile was generated for the variant `${variantName.get()}`:
- file:///$absolutePath
+ ${Path(absolutePath).toUri()}
""".trimIndent()
)
}
diff --git a/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPluginTest.kt b/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPluginTest.kt
index aa4cf94..0fec0ff 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPluginTest.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPluginTest.kt
@@ -35,6 +35,7 @@
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import java.io.File
+import kotlin.io.path.Path
import org.junit.Assume.assumeTrue
import org.junit.Rule
import org.junit.Test
@@ -68,6 +69,8 @@
"src/$variantName/$EXPECTED_PROFILE_FOLDER/startup-prof.txt"
)
+ private fun File.toUri() = Path(canonicalPath).toUri()
+
private fun mergedArtProfile(variantName: String): File {
// Task name folder in path was first observed in the update to AGP 8.3.0-alpha10.
// Before that, the folder was omitted in path.
@@ -111,7 +114,7 @@
gradleRunner.build("generateBaselineProfile") {
val notFound = it.lines().requireInOrder(
"A baseline profile was generated for the variant `release`:",
- "file:///${baselineProfileFile("main").canonicalPath}"
+ "${baselineProfileFile("main").toUri()}"
)
assertThat(notFound).isEmpty()
}
@@ -154,9 +157,9 @@
gradleRunner.build("generateBaselineProfile") {
val notFound = it.lines().requireInOrder(
"A baseline profile was generated for the variant `release`:",
- "file:///${baselineProfileFile("release").canonicalPath}",
+ "${baselineProfileFile("release").toUri()}",
"A startup profile was generated for the variant `release`:",
- "file:///${startupProfileFile("release").canonicalPath}"
+ "${startupProfileFile("release").toUri()}"
)
assertThat(notFound).isEmpty()
}
@@ -237,9 +240,9 @@
val notFound = it.lines().requireInOrder(
"A baseline profile was generated for the variant `$variantName`:",
- "file:///${baselineProfileFile(variantName).canonicalPath}",
+ "${baselineProfileFile(variantName).toUri()}",
"A startup profile was generated for the variant `$variantName`:",
- "file:///${startupProfileFile(variantName).canonicalPath}"
+ "${startupProfileFile(variantName).toUri()}"
)
assertWithMessage(
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/AndroidxTracingTraceTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/AndroidxTracingTraceTest.kt
index 93b9fb4..798062a 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/AndroidxTracingTraceTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/AndroidxTracingTraceTest.kt
@@ -65,8 +65,6 @@
val traceFilePath = linkRule.createReportedTracePath(Packages.TEST)
val perfettoCapture = PerfettoCapture()
- verifyTraceEnable(false)
-
perfettoCapture.start(
PerfettoConfig.Benchmark(
appTagPackages = listOf(Packages.TEST),
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureSweepTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureSweepTest.kt
index 41d9868..5b04350c 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureSweepTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureSweepTest.kt
@@ -28,11 +28,9 @@
import androidx.benchmark.perfetto.PerfettoTraceProcessor
import androidx.test.filters.LargeTest
import androidx.test.filters.SdkSuppress
-import androidx.testutils.verifyWithPolling
import androidx.tracing.Trace
import androidx.tracing.trace
import kotlin.test.assertEquals
-import kotlin.test.fail
import org.junit.After
import org.junit.Assert.assertTrue
import org.junit.Assume.assumeTrue
@@ -94,8 +92,6 @@
val traceFilePath = linkRule.createReportedTracePath(Packages.TEST)
val perfettoCapture = PerfettoCapture(unbundled)
- verifyTraceEnable(false)
-
perfettoCapture.start(
PerfettoConfig.Benchmark(
appTagPackages = listOf(Packages.TEST),
@@ -103,14 +99,10 @@
)
)
- if (!Trace.isEnabled()) {
- // Should be available immediately, but let's wait a while to see if it works slowly.
- val delayMs = verifyTraceEnable(true)
- fail(
- "In-process tracing should be enabled immediately after trace " +
- "capture is started. Had to poll for approx $delayMs ms"
- )
- }
+ assertTrue(
+ "In-process tracing should be enabled immediately after trace capture is started",
+ Trace.isEnabled()
+ )
/**
* Trace section labels, in order
@@ -155,27 +147,3 @@
}
}
}
-
-fun verifyTraceEnable(enabled: Boolean): Long {
- // We poll here, since we may need to wait for enable flags to propagate to apps
- return verifyWithPolling(
- "Timeout waiting for Trace.isEnabled == $enabled, tags=${getTags()}",
- periodMs = 50,
- timeoutMs = 5000
- ) {
- Trace.isEnabled() == enabled
- }
-}
-
-private fun getTags(): String {
- val method = android.os.Trace::class.java.getMethod(
- "isTagEnabled",
- Long::class.javaPrimitiveType
- )
- val never = method.invoke(null, /*TRACE_TAG_NEVER*/ 0)
- val always = method.invoke(null, /*TRACE_TAG_ALWAYS*/ 1L shl 0)
- val view = method.invoke(null, /*TRACE_TAG_VIEW*/ 1L shl 3)
- val app = method.invoke(null, /*TRACE_TAG_APP*/ 1L shl 12)
-
- return "n $never, a $always, v $view, app $app"
-}
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoSdkHandshakeTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoSdkHandshakeTest.kt
index 441f9ff..e888c7b 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoSdkHandshakeTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoSdkHandshakeTest.kt
@@ -48,7 +48,7 @@
import org.junit.runners.Parameterized
import org.junit.runners.Parameterized.Parameters
-private const val tracingPerfettoVersion = "1.0.0-beta03" // TODO(224510255): get by 'reflection'
+private const val tracingPerfettoVersion = "1.0.0" // TODO(224510255): get by 'reflection'
private const val minSupportedSdk = Build.VERSION_CODES.R // TODO(234351579): Support API < 30
@RunWith(Parameterized::class)
diff --git a/benchmark/integration-tests/baselineprofile-producer/src/main/java/androidx/benchmark/integration/baselineprofile/producer/BaselineProfileTest.kt b/benchmark/integration-tests/baselineprofile-producer/src/main/java/androidx/benchmark/integration/baselineprofile/producer/BaselineProfileTest.kt
index 7b55cde..8e04606 100644
--- a/benchmark/integration-tests/baselineprofile-producer/src/main/java/androidx/benchmark/integration/baselineprofile/producer/BaselineProfileTest.kt
+++ b/benchmark/integration-tests/baselineprofile-producer/src/main/java/androidx/benchmark/integration/baselineprofile/producer/BaselineProfileTest.kt
@@ -43,6 +43,7 @@
fun standardBaselineProfile() = baselineRule.collect(
packageName = PACKAGE_NAME,
includeInStartupProfile = false,
+ maxIterations = 1,
profileBlock = {
startActivityAndWait(Intent(ACTION))
device.waitForIdle()
@@ -53,6 +54,7 @@
fun startupBaselineProfile() = baselineRule.collect(
packageName = PACKAGE_NAME,
includeInStartupProfile = true,
+ maxIterations = 1,
profileBlock = {
startActivityAndWait(Intent(ACTION))
device.waitForIdle()
diff --git a/biometric/biometric/src/main/java/androidx/biometric/BiometricFragment.java b/biometric/biometric/src/main/java/androidx/biometric/BiometricFragment.java
index a0f89e9..0c4eff7 100644
--- a/biometric/biometric/src/main/java/androidx/biometric/BiometricFragment.java
+++ b/biometric/biometric/src/main/java/androidx/biometric/BiometricFragment.java
@@ -449,11 +449,6 @@
return;
}
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
- Log.e(TAG, "Unable to show fingerprint dialog on API <19.");
- return;
- }
-
if (isAdded()) {
mViewModel.setFingerprintDialogDismissedInstantly(true);
if (!DeviceUtils.shouldHideFingerprintDialog(context, Build.MODEL)) {
diff --git a/biometric/biometric/src/main/java/androidx/biometric/FingerprintDialogFragment.java b/biometric/biometric/src/main/java/androidx/biometric/FingerprintDialogFragment.java
index ac10446..878dfad 100644
--- a/biometric/biometric/src/main/java/androidx/biometric/FingerprintDialogFragment.java
+++ b/biometric/biometric/src/main/java/androidx/biometric/FingerprintDialogFragment.java
@@ -149,7 +149,6 @@
*
* @return A {@link FingerprintDialogFragment}.
*/
- @RequiresApi(Build.VERSION_CODES.KITKAT)
@NonNull
static FingerprintDialogFragment newInstance(boolean hostedInActivity) {
final FingerprintDialogFragment fragment = new FingerprintDialogFragment();
diff --git a/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/ScanResultTest.kt b/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/ScanResultTest.kt
index 9236324..df5d8b1 100644
--- a/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/ScanResultTest.kt
+++ b/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/ScanResultTest.kt
@@ -17,11 +17,13 @@
package androidx.bluetooth
import android.bluetooth.BluetoothAdapter
+import android.bluetooth.BluetoothDevice as FwkBluetoothDevice
import android.bluetooth.BluetoothManager
import android.bluetooth.le.ScanResult as FwkScanResult
import android.content.Context
import android.os.Build
import android.os.ParcelUuid
+import androidx.bluetooth.utils.addressType
import androidx.test.core.app.ApplicationProvider
import androidx.test.filters.SdkSuppress
import androidx.test.rule.GrantPermissionRule
@@ -39,6 +41,7 @@
*/
@RunWith(JUnit4::class)
class ScanResultTest {
+
@Rule
@JvmField
val permissionRule: GrantPermissionRule = if (Build.VERSION.SDK_INT >= 31) {
@@ -53,6 +56,7 @@
private val bluetoothManager: BluetoothManager? =
context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager?
private val bluetoothAdapter: BluetoothAdapter? = bluetoothManager?.adapter
+ private val bluetoothLe = BluetoothLe(context)
@Before
fun setUp() {
@@ -90,8 +94,13 @@
assertThat(BluetoothDevice(fwkBluetoothDevice).bondState)
.isEqualTo(scanResult.device.bondState)
assertThat(address).isEqualTo(scanResult.deviceAddress.address)
- assertThat(BluetoothAddress.ADDRESS_TYPE_UNKNOWN)
- .isEqualTo(scanResult.deviceAddress.addressType)
+ val expectedAddressType = if (Build.VERSION.SDK_INT >= 34) {
+ BluetoothAddress.ADDRESS_TYPE_PUBLIC
+ } else {
+ BluetoothAddress.ADDRESS_TYPE_UNKNOWN
+ }
+ assertThat(scanResult.deviceAddress.addressType)
+ .isEqualTo(expectedAddressType)
assertThat(true).isEqualTo(scanResult.isConnectable())
assertThat(timeStampNanos).isEqualTo(scanResult.timestampNanos)
assertThat(scanResult.getManufacturerSpecificData(1)).isNull()
@@ -129,4 +138,100 @@
assertThat(scanResult.device).isEqualTo(scanResult.device)
assertThat(scanResult.deviceAddress).isEqualTo(scanResult.deviceAddress)
}
+
+ @SdkSuppress(minSdkVersion = 34)
+ @Test
+ fun frameworkScanResultAddressTypeRandomStatic() {
+ val address = "F0:43:A8:23:10:11"
+ val fwkBluetoothDevice = bluetoothAdapter!!
+ .getRemoteLeDevice(address, FwkBluetoothDevice.ADDRESS_TYPE_RANDOM)
+ val rssi = 34
+ val periodicAdvertisingInterval = 8
+ val timeStampNanos: Long = 1
+
+ val fwkScanResult = FwkScanResult(
+ fwkBluetoothDevice,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ rssi,
+ periodicAdvertisingInterval,
+ null,
+ timeStampNanos
+ )
+
+ val bluetoothAddress = BluetoothAddress(
+ fwkScanResult.device.address,
+ fwkScanResult.device.addressType()
+ )
+
+ assertThat(bluetoothAddress.addressType)
+ .isEqualTo(BluetoothAddress.ADDRESS_TYPE_RANDOM_STATIC)
+ }
+
+ @SdkSuppress(minSdkVersion = 34)
+ @Test
+ fun frameworkScanResultAddressTypeRandomResolvable() {
+ val address = "40:01:02:03:04:05"
+ val fwkBluetoothDevice = bluetoothAdapter!!
+ .getRemoteLeDevice(address, FwkBluetoothDevice.ADDRESS_TYPE_RANDOM)
+ val rssi = 34
+ val periodicAdvertisingInterval = 8
+ val timeStampNanos: Long = 1
+
+ val fwkScanResult = FwkScanResult(
+ fwkBluetoothDevice,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ rssi,
+ periodicAdvertisingInterval,
+ null,
+ timeStampNanos
+ )
+
+ val bluetoothAddress = BluetoothAddress(
+ fwkScanResult.device.address,
+ fwkScanResult.device.addressType()
+ )
+
+ assertThat(bluetoothAddress.addressType)
+ .isEqualTo(BluetoothAddress.ADDRESS_TYPE_RANDOM_RESOLVABLE)
+ }
+
+ @SdkSuppress(minSdkVersion = 34)
+ @Test
+ fun frameworkScanResultAddressTypeRandomNonResolvable() {
+ val address = "00:01:02:03:04:05"
+ val fwkBluetoothDevice = bluetoothAdapter!!
+ .getRemoteLeDevice(address, FwkBluetoothDevice.ADDRESS_TYPE_RANDOM)
+ val rssi = 34
+ val periodicAdvertisingInterval = 8
+ val timeStampNanos: Long = 1
+
+ val fwkScanResult = FwkScanResult(
+ fwkBluetoothDevice,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ rssi,
+ periodicAdvertisingInterval,
+ null,
+ timeStampNanos
+ )
+
+ val bluetoothAddress = BluetoothAddress(
+ fwkScanResult.device.address,
+ fwkScanResult.device.addressType()
+ )
+
+ assertThat(bluetoothAddress.addressType)
+ .isEqualTo(BluetoothAddress.ADDRESS_TYPE_RANDOM_NON_RESOLVABLE)
+ }
}
diff --git a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothAddress.kt b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothAddress.kt
index 7846be5..c104d69 100644
--- a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothAddress.kt
+++ b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothAddress.kt
@@ -44,15 +44,6 @@
/** Address type is unknown. */
const val ADDRESS_TYPE_UNKNOWN: Int = 0xFFFF
-
- /** Address type random static bits value */
- internal const val TYPE_RANDOM_STATIC_BITS_VALUE: Int = 3
-
- /** Address type random resolvable bits value */
- internal const val TYPE_RANDOM_RESOLVABLE_BITS_VALUE: Int = 1
-
- /** Address type random non resolvable bits value */
- internal const val TYPE_RANDOM_NON_RESOLVABLE_BITS_VALUE: Int = 0
}
@Target(
diff --git a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/ScanResult.kt b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/ScanResult.kt
index b9af5f7..2e3cf987 100644
--- a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/ScanResult.kt
+++ b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/ScanResult.kt
@@ -22,6 +22,7 @@
import androidx.annotation.DoNotInline
import androidx.annotation.RequiresApi
import androidx.annotation.RestrictTo
+import androidx.bluetooth.utils.addressType
import java.util.UUID
/**
@@ -74,12 +75,10 @@
/** Remote Bluetooth device found. */
val device: BluetoothDevice = BluetoothDevice(fwkScanResult.device)
- // TODO(kihongs) Find a way to get address type from framework scan result
/** Bluetooth address for the remote device found. */
-
val deviceAddress: BluetoothAddress = BluetoothAddress(
fwkScanResult.device.address,
- BluetoothAddress.ADDRESS_TYPE_UNKNOWN
+ fwkScanResult.device.addressType()
)
/** Device timestamp when the advertisement was last seen. */
diff --git a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/utils/FwkBluetoothDevice.kt b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/utils/FwkBluetoothDevice.kt
new file mode 100644
index 0000000..3e39c67
--- /dev/null
+++ b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/utils/FwkBluetoothDevice.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2023 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.bluetooth.utils
+
+import android.bluetooth.BluetoothDevice as FwkBluetoothDevice
+import android.os.Build
+import android.os.Parcel
+import androidx.annotation.RequiresApi
+import androidx.bluetooth.BluetoothAddress
+
+/** Address type random static bits value */
+private const val ADDRESS_TYPE_RANDOM_STATIC_BITS_VALUE: Int = 3
+
+/** Address type random resolvable bits value */
+private const val ADDRESS_TYPE_RANDOM_RESOLVABLE_BITS_VALUE: Int = 1
+
+/** Address type random non resolvable bits value */
+private const val ADDRESS_TYPE_RANDOM_NON_RESOLVABLE_BITS_VALUE: Int = 0
+
+// mAddressType is added to the parcel in API 34
+internal fun FwkBluetoothDevice.addressType(): @BluetoothAddress.AddressType Int {
+ return if (Build.VERSION.SDK_INT >= 34) {
+ return addressType34()
+ } else {
+ BluetoothAddress.ADDRESS_TYPE_UNKNOWN
+ }
+}
+
+@RequiresApi(34)
+private fun FwkBluetoothDevice.addressType34(): @BluetoothAddress.AddressType Int {
+ val parcel = Parcel.obtain()
+ writeToParcel(parcel, 0)
+ parcel.setDataPosition(0)
+ parcel.readString() // Skip address
+ val mAddressType = parcel.readInt()
+ parcel.recycle()
+
+ return when (mAddressType) {
+ FwkBluetoothDevice.ADDRESS_TYPE_PUBLIC -> BluetoothAddress.ADDRESS_TYPE_PUBLIC
+ FwkBluetoothDevice.ADDRESS_TYPE_RANDOM ->
+ when (address.substring(0, 1).toInt(16).shr(2)) {
+ ADDRESS_TYPE_RANDOM_STATIC_BITS_VALUE ->
+ BluetoothAddress.ADDRESS_TYPE_RANDOM_STATIC
+
+ ADDRESS_TYPE_RANDOM_RESOLVABLE_BITS_VALUE ->
+ BluetoothAddress.ADDRESS_TYPE_RANDOM_RESOLVABLE
+
+ ADDRESS_TYPE_RANDOM_NON_RESOLVABLE_BITS_VALUE ->
+ BluetoothAddress.ADDRESS_TYPE_RANDOM_NON_RESOLVABLE
+
+ else -> BluetoothAddress.ADDRESS_TYPE_UNKNOWN
+ }
+
+ FwkBluetoothDevice.ADDRESS_TYPE_UNKNOWN -> BluetoothAddress.ADDRESS_TYPE_UNKNOWN
+ else -> BluetoothAddress.ADDRESS_TYPE_UNKNOWN
+ }
+}
diff --git a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/utils/Utils.kt b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/utils/Utils.kt
index 6dac023..ed4f1dd 100644
--- a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/utils/Utils.kt
+++ b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/utils/Utils.kt
@@ -17,11 +17,7 @@
package androidx.bluetooth.utils
import android.bluetooth.BluetoothDevice as FwkBluetoothDevice
-import android.os.Build
-import android.os.Parcel
-import androidx.annotation.RequiresApi
import androidx.annotation.RestrictTo
-import androidx.bluetooth.BluetoothAddress
import java.security.MessageDigest
import java.util.UUID
import kotlin.experimental.and
@@ -32,19 +28,7 @@
packageName: String,
fwkDevice: FwkBluetoothDevice
): UUID {
- return if (Build.VERSION.SDK_INT >= 34) {
- deviceId(packageName, fwkDevice.address, fwkDevice.addressType())
- } else {
- deviceId(packageName, fwkDevice.address, BluetoothAddress.ADDRESS_TYPE_UNKNOWN)
- }
-}
-
-private fun deviceId(
- packageName: String,
- address: String,
- @BluetoothAddress.AddressType addressType: Int
-): UUID {
- val name = packageName + address + addressType
+ val name = packageName + fwkDevice.address + fwkDevice.addressType()
val md = MessageDigest.getInstance("SHA-1")
md.update(name.toByteArray())
val hash = md.digest()
@@ -68,30 +52,3 @@
return UUID(msb, lsb)
}
-
-// mAddressType is added to the parcel in API 34
-@RequiresApi(34)
-private fun FwkBluetoothDevice.addressType(): @BluetoothAddress.AddressType Int {
- val parcel = Parcel.obtain()
- writeToParcel(parcel, 0)
- parcel.setDataPosition(0)
- parcel.readString() // Skip address
- val mAddressType = parcel.readInt()
- parcel.recycle()
-
- return when (mAddressType) {
- FwkBluetoothDevice.ADDRESS_TYPE_PUBLIC -> BluetoothAddress.ADDRESS_TYPE_PUBLIC
- FwkBluetoothDevice.ADDRESS_TYPE_RANDOM ->
- when (address.substring(0, 0).toInt(16).shr(2)) {
- BluetoothAddress.TYPE_RANDOM_STATIC_BITS_VALUE ->
- BluetoothAddress.ADDRESS_TYPE_RANDOM_STATIC
- BluetoothAddress.TYPE_RANDOM_RESOLVABLE_BITS_VALUE ->
- BluetoothAddress.ADDRESS_TYPE_RANDOM_RESOLVABLE
- BluetoothAddress.TYPE_RANDOM_NON_RESOLVABLE_BITS_VALUE ->
- BluetoothAddress.ADDRESS_TYPE_RANDOM_NON_RESOLVABLE
- else -> BluetoothAddress.ADDRESS_TYPE_UNKNOWN
- }
- FwkBluetoothDevice.ADDRESS_TYPE_UNKNOWN -> BluetoothAddress.ADDRESS_TYPE_UNKNOWN
- else -> BluetoothAddress.ADDRESS_TYPE_UNKNOWN
- }
-}
diff --git a/buildSrc-tests/src/test/java/androidx/build/dependencyTracker/AffectedModuleDetectorImplTest.kt b/buildSrc-tests/src/test/java/androidx/build/dependencyTracker/AffectedModuleDetectorImplTest.kt
index b1b65e6..88bc085 100644
--- a/buildSrc-tests/src/test/java/androidx/build/dependencyTracker/AffectedModuleDetectorImplTest.kt
+++ b/buildSrc-tests/src/test/java/androidx/build/dependencyTracker/AffectedModuleDetectorImplTest.kt
@@ -18,11 +18,11 @@
import java.io.File
import java.util.function.BiFunction
-import java.util.function.Predicate
import org.gradle.api.Project
import org.gradle.api.Transformer
import org.gradle.api.plugins.ExtraPropertiesExtension
import org.gradle.api.provider.Provider
+import org.gradle.api.specs.Spec
import org.gradle.testfixtures.ProjectBuilder
import org.hamcrest.CoreMatchers
import org.hamcrest.MatcherAssert
@@ -171,26 +171,24 @@
class TestProvider(private val list: List<String>) : Provider<List<String>> {
override fun get(): List<String> = list
override fun getOrNull(): List<String> = list
- override fun isPresent(): Boolean = TODO("used")
- override fun forUseAtConfigurationTime(): Provider<List<String>> = TODO("used")
+ override fun isPresent(): Boolean = TODO("unused")
+ override fun forUseAtConfigurationTime(): Provider<List<String>> = TODO("unused")
override fun <U : Any?, R : Any?> zip(
right: Provider<U>,
combiner: BiFunction<in List<String>, in U, out R?>
- ): Provider<R> = TODO("used")
+ ): Provider<R> = TODO("unused")
override fun orElse(provider: Provider<out List<String>>): Provider<List<String>> {
- TODO("used")
+ TODO("unused")
}
- override fun orElse(value: List<String>): Provider<List<String>> = TODO("used")
+ override fun orElse(value: List<String>): Provider<List<String>> = TODO("unused")
override fun <S : Any?> flatMap(
transformer: Transformer<out Provider<out S>?, in List<String>>
- ): Provider<S> = TODO("used")
- override fun filter(predicate: Predicate<in List<String>>): Provider<List<String>> {
- TODO("used")
- }
+ ): Provider<S> = TODO("unused")
+ override fun filter(spec: Spec<in List<String>>): Provider<List<String>> = TODO("unused")
override fun <S : Any?> map(
transformer: Transformer<out S?, in List<String>>
- ): Provider<S> = TODO("used")
- override fun getOrElse(defaultValue: List<String>): List<String> = TODO("used")
+ ): Provider<S> = TODO("unused")
+ override fun getOrElse(defaultValue: List<String>): List<String> = TODO("unused")
}
@Test
diff --git a/buildSrc/public/src/main/kotlin/androidx/build/SdkResourceGenerator.kt b/buildSrc/public/src/main/kotlin/androidx/build/SdkResourceGenerator.kt
index 1a4dc97..991a22c 100644
--- a/buildSrc/public/src/main/kotlin/androidx/build/SdkResourceGenerator.kt
+++ b/buildSrc/public/src/main/kotlin/androidx/build/SdkResourceGenerator.kt
@@ -61,7 +61,7 @@
@get:Input val agpDependency: String = AGP_LATEST
@get:Input
- val navigationRuntime: String = "androidx.navigation:navigation-runtime:2.4.0-alpha01"
+ val navigationRuntime: String = "androidx.navigation:navigation-runtime:2.4.0"
@get:Input abstract val kotlinStdlib: Property<String>
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapter.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapter.kt
index 57ccca4..05fed81 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapter.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapter.kt
@@ -24,13 +24,13 @@
import android.hardware.camera2.CameraCharacteristics.CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION
import android.hardware.camera2.CameraMetadata
import android.hardware.camera2.params.DynamicRangeProfiles
-import android.os.Build
import android.util.Range
import android.util.Size
import android.view.Surface
import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.CameraPipe
import androidx.camera.camera2.pipe.core.Log
+import androidx.camera.camera2.pipe.integration.compat.DynamicRangeProfilesCompat
import androidx.camera.camera2.pipe.integration.compat.StreamConfigurationMapCompat
import androidx.camera.camera2.pipe.integration.compat.quirk.CameraQuirks
import androidx.camera.camera2.pipe.integration.compat.workaround.isFlashAvailable
@@ -57,6 +57,7 @@
import androidx.camera.core.ZoomState
import androidx.camera.core.impl.CameraCaptureCallback
import androidx.camera.core.impl.CameraInfoInternal
+import androidx.camera.core.impl.DynamicRanges
import androidx.camera.core.impl.EncoderProfilesProvider
import androidx.camera.core.impl.Quirks
import androidx.camera.core.impl.Timebase
@@ -199,17 +200,16 @@
return false
}
- @SuppressLint("ClassVerificationFailure")
override fun getSupportedDynamicRanges(): Set<DynamicRange> {
- // TODO: use DynamicRangesCompat instead after it is migrates from camera-camera2.
- if (Build.VERSION.SDK_INT >= 33) {
- val availableProfiles = cameraProperties.metadata[
- CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES]
- if (availableProfiles != null) {
- return profileSetToDynamicRangeSet(availableProfiles.supportedProfiles)
- }
- }
- return setOf(SDR)
+ return DynamicRangeProfilesCompat
+ .fromCameraMetaData(cameraProperties.metadata)
+ .supportedDynamicRanges
+ }
+
+ override fun querySupportedDynamicRanges(
+ candidateDynamicRanges: Set<DynamicRange>
+ ): Set<DynamicRange> {
+ return DynamicRanges.findAllPossibleMatches(candidateDynamicRanges, supportedDynamicRanges)
}
override fun isPreviewStabilizationSupported(): Boolean {
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/DynamicRangeProfilesCompat.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/DynamicRangeProfilesCompat.kt
index 4d1fddd6..37150eb 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/DynamicRangeProfilesCompat.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/DynamicRangeProfilesCompat.kt
@@ -29,14 +29,18 @@
*/
@RequiresApi(21)
class DynamicRangeProfilesCompat internal constructor(
- private val mImpl: DynamicRangeProfilesCompatImpl
+ private val impl: DynamicRangeProfilesCompatImpl
) {
+ /** The set of supported dynamic ranges. */
+ val supportedDynamicRanges: Set<DynamicRange>
+ get() = impl.supportedDynamicRanges
+
/**
* Returns a set of supported [DynamicRange] that can be referenced in a single
* capture request.
*
* For example if a particular 10-bit output capable device returns (STANDARD,
- * HLG10, HDR10) as result from calling [getSupportedDynamicRanges] and
+ * HLG10, HDR10) as result from calling [supportedDynamicRanges] and
* [DynamicRangeProfiles.getProfileCaptureRequestConstraints]
* returns (STANDARD, HLG10) when given an argument
* of STANDARD. This means that the corresponding camera device will only accept and process
@@ -50,21 +54,12 @@
* @param dynamicRange The dynamic range that will be checked for constraints
* @return non-modifiable set of dynamic ranges
* @throws IllegalArgumentException If the dynamic range argument is not within the set
- * returned by [getSupportedDynamicRanges].
+ * returned by [supportedDynamicRanges].
*/
fun getDynamicRangeCaptureRequestConstraints(
dynamicRange: DynamicRange
): Set<DynamicRange> {
- return mImpl.getDynamicRangeCaptureRequestConstraints(dynamicRange)
- }
-
- /**
- * Returns a set of supported dynamic ranges.
- *
- * @return a non-modifiable set of dynamic ranges.
- */
- fun getSupportedDynamicRanges(): Set<DynamicRange> {
- return mImpl.getSupportedDynamicRanges()
+ return impl.getDynamicRangeCaptureRequestConstraints(dynamicRange)
}
/**
@@ -80,10 +75,10 @@
* @return `true` if the given profile is not suitable for latency sensitive use cases,
* `false` otherwise.
* @throws IllegalArgumentException If the dynamic range argument is not within the set
- * returned by [getSupportedDynamicRanges].
+ * returned by [supportedDynamicRanges].
*/
fun isExtraLatencyPresent(dynamicRange: DynamicRange): Boolean {
- return mImpl.isExtraLatencyPresent(dynamicRange)
+ return impl.isExtraLatencyPresent(dynamicRange)
}
/**
@@ -99,16 +94,15 @@
33, "DynamicRangesCompat can only be " +
"converted to DynamicRangeProfiles on API 33 or higher."
)
- return mImpl.unwrap()
+ return impl.unwrap()
}
internal interface DynamicRangeProfilesCompatImpl {
+ val supportedDynamicRanges: Set<DynamicRange>
fun getDynamicRangeCaptureRequestConstraints(
dynamicRange: DynamicRange
): Set<DynamicRange>
- fun getSupportedDynamicRanges(): Set<DynamicRange>
-
fun isExtraLatencyPresent(dynamicRange: DynamicRange): Boolean
fun unwrap(): DynamicRangeProfiles?
}
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/DynamicRangeProfilesCompatApi33Impl.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/DynamicRangeProfilesCompatApi33Impl.kt
index 12a5687..0197afe 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/DynamicRangeProfilesCompatApi33Impl.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/DynamicRangeProfilesCompatApi33Impl.kt
@@ -26,6 +26,10 @@
internal class DynamicRangeProfilesCompatApi33Impl(
private val dynamicRangeProfiles: DynamicRangeProfiles
) : DynamicRangeProfilesCompat.DynamicRangeProfilesCompatImpl {
+ override val supportedDynamicRanges: Set<DynamicRange>
+ get() = profileSetToDynamicRangeSet(
+ dynamicRangeProfiles.supportedProfiles
+ )
override fun getDynamicRangeCaptureRequestConstraints(
dynamicRange: DynamicRange
@@ -39,10 +43,6 @@
)
}
- override fun getSupportedDynamicRanges() = profileSetToDynamicRangeSet(
- dynamicRangeProfiles.supportedProfiles
- )
-
override fun isExtraLatencyPresent(dynamicRange: DynamicRange): Boolean {
val dynamicRangeProfile = dynamicRangeToFirstSupportedProfile(dynamicRange)
require(
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/DynamicRangeProfilesCompatBaseImpl.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/DynamicRangeProfilesCompatBaseImpl.kt
index b9a0cad..2d5cc50 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/DynamicRangeProfilesCompatBaseImpl.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/DynamicRangeProfilesCompatBaseImpl.kt
@@ -24,6 +24,9 @@
@RequiresApi(21)
internal class DynamicRangeProfilesCompatBaseImpl :
DynamicRangeProfilesCompat.DynamicRangeProfilesCompatImpl {
+ override val supportedDynamicRanges: Set<DynamicRange>
+ get() = SDR_ONLY
+
override fun getDynamicRangeCaptureRequestConstraints(
dynamicRange: DynamicRange
): Set<DynamicRange> {
@@ -34,10 +37,6 @@
return SDR_ONLY
}
- override fun getSupportedDynamicRanges(): Set<DynamicRange> {
- return SDR_ONLY
- }
-
override fun isExtraLatencyPresent(dynamicRange: DynamicRange): Boolean {
Preconditions.checkArgument(
DynamicRange.SDR == dynamicRange,
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/internal/DynamicRangeResolver.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/internal/DynamicRangeResolver.kt
index 947d31c..7871614 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/internal/DynamicRangeResolver.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/internal/DynamicRangeResolver.kt
@@ -54,7 +54,7 @@
}
// Get the supported dynamic ranges from the device
- val supportedDynamicRanges = dynamicRangesInfo.getSupportedDynamicRanges()
+ val supportedDynamicRanges = dynamicRangesInfo.supportedDynamicRanges
// Collect initial dynamic range constraints. This set will potentially shrink as we add
// more dynamic ranges. We start with the initial set of supported dynamic ranges to
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapterTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapterTest.kt
index e845092..d352ea7 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapterTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapterTest.kt
@@ -24,6 +24,8 @@
import android.util.Range
import android.util.Size
import androidx.camera.camera2.pipe.integration.impl.ZoomControl
+import androidx.camera.camera2.pipe.integration.internal.DOLBY_VISION_10B_UNCONSTRAINED
+import androidx.camera.camera2.pipe.integration.internal.HLG10_UNCONSTRAINED
import androidx.camera.camera2.pipe.integration.testing.FakeCameraInfoAdapterCreator.createCameraInfoAdapter
import androidx.camera.camera2.pipe.integration.testing.FakeCameraInfoAdapterCreator.useCaseThreads
import androidx.camera.camera2.pipe.integration.testing.FakeCameraProperties
@@ -31,6 +33,12 @@
import androidx.camera.camera2.pipe.integration.testing.FakeZoomCompat
import androidx.camera.camera2.pipe.testing.FakeCameraMetadata
import androidx.camera.core.CameraInfo
+import androidx.camera.core.DynamicRange
+import androidx.camera.core.DynamicRange.DOLBY_VISION_10_BIT
+import androidx.camera.core.DynamicRange.DOLBY_VISION_8_BIT
+import androidx.camera.core.DynamicRange.HDR10_10_BIT
+import androidx.camera.core.DynamicRange.HDR10_PLUS_10_BIT
+import androidx.camera.core.DynamicRange.HLG_10_BIT
import androidx.camera.core.FocusMeteringAction
import androidx.camera.core.SurfaceOrientedMeteringPointFactory
import androidx.camera.core.ZoomState
@@ -256,4 +264,131 @@
assertThat(cameraInfo.isVideoStabilizationSupported).isFalse()
}
+
+ // Analog to Camera2CameraInfoImplTest#apiVersionMet_canReturnSupportedHdrDynamicRanges()
+ @Config(minSdk = Build.VERSION_CODES.TIRAMISU)
+ @Test
+ fun cameraInfo_hdrDynamicRangeSupported() {
+ val cameraInfo: CameraInfo = createCameraInfoAdapter(
+ cameraProperties = FakeCameraProperties(
+ FakeCameraMetadata(
+ characteristics = mapOf(
+ CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES to
+ HLG10_UNCONSTRAINED
+ )
+ )
+ )
+ )
+
+ assertThat(cameraInfo.querySupportedDynamicRanges(
+ setOf(
+ HLG_10_BIT, HDR10_10_BIT, HDR10_PLUS_10_BIT, DOLBY_VISION_10_BIT, DOLBY_VISION_8_BIT
+ )
+ )).containsExactly(HLG_10_BIT)
+
+ assertThat(cameraInfo.querySupportedDynamicRanges(
+ setOf(DynamicRange.HDR_UNSPECIFIED_10_BIT)
+ )).containsExactly(HLG_10_BIT)
+ }
+
+ @Config(minSdk = Build.VERSION_CODES.TIRAMISU)
+ @Test
+ fun cameraInfo_tenBitHdrDynamicRangeSupported_whenAlsoQuerying8Bit() {
+ val cameraInfo: CameraInfo = createCameraInfoAdapter(
+ cameraProperties = FakeCameraProperties(
+ FakeCameraMetadata(
+ characteristics = mapOf(
+ CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES to
+ DOLBY_VISION_10B_UNCONSTRAINED
+ )
+ )
+ )
+ )
+
+ assertThat(cameraInfo.querySupportedDynamicRanges(
+ setOf(DOLBY_VISION_10_BIT, DOLBY_VISION_8_BIT)
+ )).containsExactly(DOLBY_VISION_10_BIT)
+ }
+
+ // Analog to Camera2CameraInfoImplTest#apiVersionMet_canReturnSupportedDynamicRanges()
+ @Config(minSdk = Build.VERSION_CODES.TIRAMISU)
+ @Test
+ fun cameraInfo_returnsAllSupportedDynamicRanges_whenQueryingWithUnspecified() {
+ val cameraInfo: CameraInfo = createCameraInfoAdapter(
+ cameraProperties = FakeCameraProperties(
+ FakeCameraMetadata(
+ characteristics = mapOf(
+ CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES to
+ HLG10_UNCONSTRAINED
+ )
+ )
+ )
+ )
+
+ assertThat(cameraInfo.querySupportedDynamicRanges(
+ setOf(DynamicRange.UNSPECIFIED)
+ )).containsExactly(DynamicRange.SDR, HLG_10_BIT)
+ }
+
+ // Analog to
+ // Camera2CameraInfoImplTest#apiVersionMet_canReturnSupportedDynamicRanges_fromFullySpecified()
+ @Config(minSdk = Build.VERSION_CODES.TIRAMISU)
+ @Test
+ fun cameraInfo_hdrAndSdrDynamicRangesSupported_whenQueryingWithFullySpecified() {
+ val cameraInfo: CameraInfo = createCameraInfoAdapter(
+ cameraProperties = FakeCameraProperties(
+ FakeCameraMetadata(
+ characteristics = mapOf(
+ CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES to
+ HLG10_UNCONSTRAINED
+ )
+ )
+ )
+ )
+
+ assertThat(
+ cameraInfo.querySupportedDynamicRanges(
+ setOf(
+ DynamicRange.SDR,
+ HLG_10_BIT
+ )
+ )
+ ).containsExactly(DynamicRange.SDR, HLG_10_BIT)
+ }
+
+ // Analog to Camera2CameraInfoImplTest#apiVersionNotMet_canReturnSupportedDynamicRanges()
+ @Test
+ fun cameraInfo_queryUnspecifiedDynamicRangeSupported() {
+ val cameraInfo: CameraInfo = createCameraInfoAdapter()
+
+ assertThat(cameraInfo.querySupportedDynamicRanges(
+ setOf(DynamicRange.UNSPECIFIED))).containsExactly(DynamicRange.SDR)
+ }
+
+ // Analog to Camera2CameraInfoImplTest#apiVersionNotMet_queryHdrDynamicRangeNotSupported()
+ @Test
+ fun cameraInfo_queryForHdrWhenUnsupported_returnsEmptySet() {
+ val cameraInfo: CameraInfo = createCameraInfoAdapter()
+
+ assertThat(cameraInfo.querySupportedDynamicRanges(
+ setOf(DynamicRange.HDR_UNSPECIFIED_10_BIT))).isEmpty()
+ }
+
+ // Analog to Camera2CameraInfoImplTest#querySdrDynamicRange_alwaysSupported()
+ @Test
+ fun cameraInfo_querySdrSupported() {
+ val cameraInfo: CameraInfo = createCameraInfoAdapter()
+
+ assertThat(cameraInfo.querySupportedDynamicRanges(setOf(DynamicRange.SDR))).containsExactly(
+ DynamicRange.SDR
+ )
+ }
+
+ // Analog to Camera2CameraInfoImplTest#queryDynamicRangeWithEmptySet_returnsEmptySet()
+ @Test
+ fun cameraInfo_queryWithEmptySet_returnsEmptySet() {
+ val cameraInfo: CameraInfo = createCameraInfoAdapter()
+
+ assertThat(cameraInfo.querySupportedDynamicRanges(emptySet())).isEmpty()
+ }
}
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/DynamicRangeProfilesCompatTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/DynamicRangeProfilesCompatTest.kt
index b06ab92..73172a95 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/DynamicRangeProfilesCompatTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/DynamicRangeProfilesCompatTest.kt
@@ -64,7 +64,7 @@
fun canSupportDynamicRangeFromHlg10Profile() {
val dynamicRangeProfilesCompat =
DynamicRangeProfilesCompat.toDynamicRangesCompat(HLG10_UNCONSTRAINED)
- Truth.assertThat(dynamicRangeProfilesCompat?.getSupportedDynamicRanges())
+ Truth.assertThat(dynamicRangeProfilesCompat?.supportedDynamicRanges)
.contains(DynamicRange.HLG_10_BIT)
}
@@ -73,7 +73,7 @@
fun canSupportDynamicRangeFromHdr10Profile() {
val dynamicRangeProfilesCompat =
DynamicRangeProfilesCompat.toDynamicRangesCompat(HDR10_UNCONSTRAINED)
- Truth.assertThat(dynamicRangeProfilesCompat?.getSupportedDynamicRanges())
+ Truth.assertThat(dynamicRangeProfilesCompat?.supportedDynamicRanges)
.contains(DynamicRange.HDR10_10_BIT)
}
@@ -82,7 +82,7 @@
fun canSupportDynamicRangeFromHdr10PlusProfile() {
val dynamicRangeProfilesCompat =
DynamicRangeProfilesCompat.toDynamicRangesCompat(HDR10_PLUS_UNCONSTRAINED)
- Truth.assertThat(dynamicRangeProfilesCompat?.getSupportedDynamicRanges())
+ Truth.assertThat(dynamicRangeProfilesCompat?.supportedDynamicRanges)
.contains(DynamicRange.HDR10_PLUS_10_BIT)
}
@@ -91,7 +91,7 @@
fun canSupportDynamicRangeFromDolbyVision10bProfile() {
val dynamicRangeProfilesCompat =
DynamicRangeProfilesCompat.toDynamicRangesCompat(DOLBY_VISION_10B_UNCONSTRAINED)
- Truth.assertThat(dynamicRangeProfilesCompat?.getSupportedDynamicRanges())
+ Truth.assertThat(dynamicRangeProfilesCompat?.supportedDynamicRanges)
.contains(DynamicRange.DOLBY_VISION_10_BIT)
}
@@ -100,7 +100,7 @@
fun canSupportDynamicRangeFromDolbyVision8bProfile() {
val dynamicRangeProfilesCompat =
DynamicRangeProfilesCompat.toDynamicRangesCompat(DOLBY_VISION_8B_UNCONSTRAINED)
- Truth.assertThat(dynamicRangeProfilesCompat?.getSupportedDynamicRanges())
+ Truth.assertThat(dynamicRangeProfilesCompat?.supportedDynamicRanges)
.contains(DynamicRange.DOLBY_VISION_8_BIT)
}
@@ -203,7 +203,7 @@
val dynamicRangeProfilesCompat =
DynamicRangeProfilesCompat.fromCameraMetaData(cameraMetadata)
- Truth.assertThat(dynamicRangeProfilesCompat.getSupportedDynamicRanges())
+ Truth.assertThat(dynamicRangeProfilesCompat.supportedDynamicRanges)
.containsExactly(DynamicRange.SDR)
Truth.assertThat(
dynamicRangeProfilesCompat.getDynamicRangeCaptureRequestConstraints(DynamicRange.SDR)
@@ -225,10 +225,10 @@
DynamicRangeProfilesCompat.fromCameraMetaData(cameraMetadata)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
- Truth.assertThat(dynamicRangeProfilesCompat.getSupportedDynamicRanges())
+ Truth.assertThat(dynamicRangeProfilesCompat.supportedDynamicRanges)
.containsExactly(DynamicRange.SDR)
} else {
- Truth.assertThat(dynamicRangeProfilesCompat.getSupportedDynamicRanges())
+ Truth.assertThat(dynamicRangeProfilesCompat.supportedDynamicRanges)
.containsExactly(
DynamicRange.SDR, DynamicRange.DOLBY_VISION_8_BIT
)
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/internal/DynamicRangeTestCases.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/internal/DynamicRangeTestCases.kt
index bcaae5a..9f2b153 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/internal/DynamicRangeTestCases.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/internal/DynamicRangeTestCases.kt
@@ -27,7 +27,7 @@
import androidx.annotation.RequiresApi
val HLG10_UNCONSTRAINED by lazy {
- DynamicRangeProfiles(longArrayOf(HLG10, 0, 0))
+ DynamicRangeProfiles(longArrayOf(HLG10, CONSTRAINTS_NONE, LATENCY_NONE))
}
val HLG10_CONSTRAINED by lazy {
diff --git a/camera/camera-camera2-pipe-testing/src/main/java/androidx/camera/camera2/pipe/testing/FakeImage.kt b/camera/camera-camera2-pipe-testing/src/main/java/androidx/camera/camera2/pipe/testing/FakeImage.kt
index c579ad3..3a38d47 100644
--- a/camera/camera-camera2-pipe-testing/src/main/java/androidx/camera/camera2/pipe/testing/FakeImage.kt
+++ b/camera/camera-camera2-pipe-testing/src/main/java/androidx/camera/camera2/pipe/testing/FakeImage.kt
@@ -16,8 +16,6 @@
package androidx.camera.camera2.pipe.testing
-import android.os.Build
-import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.media.ImagePlane
import androidx.camera.camera2.pipe.media.ImageWrapper
import kotlin.reflect.KClass
@@ -26,7 +24,6 @@
/**
* FakeImage that can be used for testing classes that accept [ImageWrapper].
*/
-@RequiresApi(Build.VERSION_CODES.KITKAT)
class FakeImage(
override val width: Int,
override val height: Int,
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/media/ImageWrapper.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/media/ImageWrapper.kt
index 6ccedd7..923652f 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/media/ImageWrapper.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/media/ImageWrapper.kt
@@ -16,15 +16,12 @@
package androidx.camera.camera2.pipe.media
-import android.os.Build
-import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.UnsafeWrapper
import java.nio.ByteBuffer
/**
* Wrapper interfaces that mirrors the primary read-only properties of {@link android.media.Image}.
*/
-@RequiresApi(Build.VERSION_CODES.KITKAT)
interface ImageWrapper : UnsafeWrapper, AutoCloseable {
/**
* @see {@link android.media.Image.getWidth}
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/media/OutputImage.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/media/OutputImage.kt
index 5ef904c..98c6d0d 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/media/OutputImage.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/media/OutputImage.kt
@@ -16,8 +16,6 @@
package androidx.camera.camera2.pipe.media
-import android.os.Build
-import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.OutputId
import androidx.camera.camera2.pipe.StreamId
import kotlin.reflect.KClass
@@ -26,7 +24,6 @@
* An OutputImage is a reference to an [ImageWrapper] that was produced from CameraPipe for a
* specific [StreamId]/[OutputId] combination.
*/
-@RequiresApi(Build.VERSION_CODES.KITKAT)
interface OutputImage : ImageWrapper {
val streamId: StreamId
val outputId: OutputId
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/CaptureSessionTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/CaptureSessionTest.java
index bfb685b..9e116f4 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/CaptureSessionTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/CaptureSessionTest.java
@@ -24,7 +24,6 @@
import static android.hardware.DataSpace.TRANSFER_SMPTE_170M;
import static android.hardware.DataSpace.TRANSFER_SRGB;
import static android.hardware.DataSpace.TRANSFER_UNSPECIFIED;
-import static android.os.Build.VERSION.SDK_INT;
import static androidx.camera.core.DynamicRange.HLG_10_BIT;
@@ -114,9 +113,7 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
-import org.junit.runner.Description;
import org.junit.runner.RunWith;
-import org.junit.runners.model.Statement;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
@@ -194,26 +191,9 @@
@Rule
public TestRule getUseCameraRule() {
- if (SDK_INT >= 19) {
- return CameraUtil.grantCameraPermissionAndPreTest(
- new CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
- );
- } else {
- // Camera2Config.defaultConfig() requires API 19, so returning
- // a noop rule so it doesn't crash when run on API <19
- return new NoopRule();
- }
- }
-
- public static class NoopRule implements TestRule {
- @NonNull
- @Override
- public Statement apply(@NonNull Statement base, @NonNull Description description) {
- return new Statement() {
- @Override
- public void evaluate() {}
- };
- }
+ return CameraUtil.grantCameraPermissionAndPreTest(
+ new CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+ );
}
@BeforeClass
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraInfoImpl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraInfoImpl.java
index ffffd60..5dd2cf2 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraInfoImpl.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraInfoImpl.java
@@ -59,6 +59,7 @@
import androidx.camera.core.ZoomState;
import androidx.camera.core.impl.CameraCaptureCallback;
import androidx.camera.core.impl.CameraInfoInternal;
+import androidx.camera.core.impl.DynamicRanges;
import androidx.camera.core.impl.EncoderProfilesProvider;
import androidx.camera.core.impl.ImageOutputConfig.RotationValue;
import androidx.camera.core.impl.Quirks;
@@ -451,6 +452,14 @@
return dynamicRangesCompat.getSupportedDynamicRanges();
}
+ @NonNull
+ @Override
+ public Set<DynamicRange> querySupportedDynamicRanges(
+ @NonNull Set<DynamicRange> candidateDynamicRanges) {
+ return DynamicRanges.findAllPossibleMatches(candidateDynamicRanges,
+ getSupportedDynamicRanges());
+ }
+
@Override
public void addSessionCaptureCallback(@NonNull Executor executor,
@NonNull CameraCaptureCallback callback) {
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CameraInfoImplTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CameraInfoImplTest.java
index 8a876ca..96f94bd 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CameraInfoImplTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CameraInfoImplTest.java
@@ -20,9 +20,18 @@
import static android.hardware.camera2.CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_OFF;
import static android.hardware.camera2.CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON;
import static android.hardware.camera2.CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION;
+
+import static androidx.camera.core.DynamicRange.DOLBY_VISION_10_BIT;
+import static androidx.camera.core.DynamicRange.DOLBY_VISION_8_BIT;
+import static androidx.camera.core.DynamicRange.HDR10_10_BIT;
+import static androidx.camera.core.DynamicRange.HDR10_PLUS_10_BIT;
+import static androidx.camera.core.DynamicRange.HDR_UNSPECIFIED_10_BIT;
import static androidx.camera.core.DynamicRange.HLG_10_BIT;
import static androidx.camera.core.DynamicRange.SDR;
+import static androidx.camera.core.DynamicRange.UNSPECIFIED;
+
import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -77,6 +86,7 @@
import org.robolectric.util.ReflectionHelpers;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -728,13 +738,44 @@
@Config(minSdk = 33)
@Test
- public void apiVersionMet_canReturnSupportedDynamicRanges() throws CameraAccessExceptionCompat {
+ public void apiVersionMet_canReturnOnlySupportedHdrDynamicRanges()
+ throws CameraAccessExceptionCompat {
init(/* hasAvailableCapabilities = */ true);
- final Camera2CameraInfoImpl cameraInfo = new Camera2CameraInfoImpl(
- CAMERA0_ID, mCameraManagerCompat);
+ final CameraInfo cameraInfo = new Camera2CameraInfoImpl(CAMERA0_ID, mCameraManagerCompat);
- Set<DynamicRange> supportedDynamicRanges = cameraInfo.getSupportedDynamicRanges();
+ Set<DynamicRange> supportedDynamicRanges = cameraInfo.querySupportedDynamicRanges(
+ new HashSet<>(Arrays.asList(HLG_10_BIT, HDR10_10_BIT, HDR10_PLUS_10_BIT,
+ DOLBY_VISION_10_BIT, DOLBY_VISION_8_BIT)));
+ assertThat(supportedDynamicRanges).containsExactly(HLG_10_BIT);
+ supportedDynamicRanges = cameraInfo.querySupportedDynamicRanges(
+ Collections.singleton(HDR_UNSPECIFIED_10_BIT));
+ assertThat(supportedDynamicRanges).containsExactly(HLG_10_BIT);
+ }
+
+ @Config(minSdk = 33)
+ @Test
+ public void apiVersionMet_canReturnSupportedDynamicRanges()
+ throws CameraAccessExceptionCompat {
+ init(/* hasAvailableCapabilities = */ true);
+
+ final CameraInfo cameraInfo = new Camera2CameraInfoImpl(CAMERA0_ID, mCameraManagerCompat);
+
+ Set<DynamicRange> supportedDynamicRanges = cameraInfo.querySupportedDynamicRanges(
+ Collections.singleton(UNSPECIFIED));
+ assertThat(supportedDynamicRanges).containsExactly(SDR, HLG_10_BIT);
+ }
+
+ @Config(minSdk = 33)
+ @Test
+ public void apiVersionMet_canReturnSupportedDynamicRanges_fromFullySpecified()
+ throws CameraAccessExceptionCompat {
+ init(/* hasAvailableCapabilities = */ true);
+
+ final CameraInfo cameraInfo = new Camera2CameraInfoImpl(CAMERA0_ID, mCameraManagerCompat);
+
+ Set<DynamicRange> supportedDynamicRanges = cameraInfo.querySupportedDynamicRanges(
+ new HashSet<>(Arrays.asList(SDR, HLG_10_BIT)));
assertThat(supportedDynamicRanges).containsExactly(SDR, HLG_10_BIT);
}
@@ -744,13 +785,44 @@
throws CameraAccessExceptionCompat {
init(/* hasAvailableCapabilities = */ true);
- final Camera2CameraInfoImpl cameraInfo = new Camera2CameraInfoImpl(
- CAMERA0_ID, mCameraManagerCompat);
+ final CameraInfo cameraInfo = new Camera2CameraInfoImpl(CAMERA0_ID, mCameraManagerCompat);
- Set<DynamicRange> supportedDynamicRanges = cameraInfo.getSupportedDynamicRanges();
+ Set<DynamicRange> supportedDynamicRanges = cameraInfo.querySupportedDynamicRanges(
+ Collections.singleton(UNSPECIFIED));
assertThat(supportedDynamicRanges).containsExactly(SDR);
}
+ @Config(maxSdk = 32)
+ @Test
+ public void apiVersionNotMet_queryHdrDynamicRangeNotSupported()
+ throws CameraAccessExceptionCompat {
+ init(/* hasAvailableCapabilities = */ true);
+
+ final CameraInfo cameraInfo = new Camera2CameraInfoImpl(CAMERA0_ID, mCameraManagerCompat);
+
+ Set<DynamicRange> supportedDynamicRanges = cameraInfo.querySupportedDynamicRanges(
+ Collections.singleton(HDR_UNSPECIFIED_10_BIT));
+ assertThat(supportedDynamicRanges).isEmpty();
+ }
+
+ @Test
+ public void querySdrDynamicRange_alwaysSupported() throws CameraAccessExceptionCompat {
+ init(/* hasAvailableCapabilities = */ true);
+
+ final CameraInfo cameraInfo = new Camera2CameraInfoImpl(CAMERA0_ID, mCameraManagerCompat);
+
+ assertThat(cameraInfo.querySupportedDynamicRanges(Collections.singleton(SDR))).isNotEmpty();
+ }
+
+ @Test
+ public void queryDynamicRangeWithEmptySet_returnsEmptySet() throws CameraAccessExceptionCompat {
+ init(/* hasAvailableCapabilities = */ true);
+
+ final CameraInfo cameraInfo = new Camera2CameraInfoImpl(CAMERA0_ID, mCameraManagerCompat);
+
+ assertThat(cameraInfo.querySupportedDynamicRanges(Collections.emptySet())).isEmpty();
+ }
+
private CameraManagerCompat initCameraManagerWithPhysicalIds(
List<Pair<String, CameraCharacteristics>> cameraIdsAndCharacteristicsList) {
FakeCameraManagerImpl cameraManagerImpl = new FakeCameraManagerImpl();
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/CameraEffect.java b/camera/camera-core/src/main/java/androidx/camera/core/CameraEffect.java
index 311d07f..ce442af 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/CameraEffect.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/CameraEffect.java
@@ -20,6 +20,7 @@
import static androidx.core.util.Preconditions.checkArgument;
import android.graphics.ImageFormat;
+import android.view.Display;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
@@ -84,6 +85,16 @@
public abstract class CameraEffect {
/**
+ * Options for the transformation handled by the effect.
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @IntDef(flag = true, value = {TRANSFORMATION_ARBITRARY,
+ TRANSFORMATION_CAMERA_AND_SURFACE_ROTATION})
+ public @interface Transformations {
+ }
+
+ /**
* Bitmask options for the effect targets.
*/
@Retention(RetentionPolicy.SOURCE)
@@ -93,7 +104,7 @@
}
/**
- * Bitmask options for the effect targets.
+ * Bitmask options for the effect buffer formats.
*/
@Retention(RetentionPolicy.SOURCE)
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@@ -123,8 +134,39 @@
PREVIEW | VIDEO_CAPTURE,
PREVIEW | VIDEO_CAPTURE | IMAGE_CAPTURE);
+ /**
+ * Flag to indicate that the implementation will handle arbitrary transformation.
+ *
+ * <p>When this flag is used, CameraX may suggest arbitrary transformation via
+ * {@link SurfaceOutput#updateTransformMatrix} for the {@link SurfaceProcessor} to handle,
+ * including mirroring, rotating, cropping and/or scaling.
+ *
+ * <p>Use this flag if the {@link CameraEffect} implementation can handle arbitrary
+ * transformation.
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public static final int TRANSFORMATION_ARBITRARY = 0;
+
+ /**
+ * Flag to indicate that the implementation will handle the camera and the Surface rotation.
+ *
+ * <p>When this flag is used, the value of {@link SurfaceOutput#updateTransformMatrix} will
+ * be a combination of the camera sensor orientation and the Surface rotation. The camera
+ * rotation is the value written by camera framework, which can be retrieved via
+ * {@link android.graphics.SurfaceTexture#getTransformMatrix(float[])} if the consumer is a
+ * {@link android.graphics.SurfaceTexture}. The Surface rotation is the value of the default
+ * {@link Display#getRotation()}.
+ *
+ * <p>Use this flag if the {@link CameraEffect} implementation handles the camera and the
+ * Surface rotation.
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public static final int TRANSFORMATION_CAMERA_AND_SURFACE_ROTATION = 1;
+
@Targets
private final int mTargets;
+ @Transformations
+ private final int mTransformation;
@NonNull
private final Executor mExecutor;
@Nullable
@@ -155,6 +197,7 @@
checkArgument(targets == IMAGE_CAPTURE,
"Currently ImageProcessor can only target IMAGE_CAPTURE.");
mTargets = targets;
+ mTransformation = TRANSFORMATION_ARBITRARY;
mExecutor = executor;
mSurfaceProcessor = null;
mImageProcessor = imageProcessor;
@@ -173,6 +216,46 @@
* </ul>
* Targeting other {@link UseCase} combinations will throw
* {@link IllegalArgumentException}.
+ * @param transformation the transformation that the {@link SurfaceProcessor} will handle.
+ * @param executor the {@link Executor} on which the {@param imageProcessor} and
+ * {@param errorListener} will be invoked.
+ * @param surfaceProcessor a {@link SurfaceProcessor} implementation. Once the effect is
+ * active, CameraX will send frames to the {@link SurfaceProcessor}
+ * on the {@param executor}, and deliver the processed frames to the
+ * app.
+ * @param errorListener invoked if the effect runs into unrecoverable errors. The
+ * {@link Throwable} will be the error thrown by this
+ * {@link CameraEffect}. For example, {@link ProcessingException}.
+ * This is invoked on the provided {@param executor}.
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ protected CameraEffect(
+ @Targets int targets,
+ @Transformations int transformation,
+ @NonNull Executor executor,
+ @NonNull SurfaceProcessor surfaceProcessor,
+ @NonNull Consumer<Throwable> errorListener) {
+ checkSupportedTargets(SURFACE_PROCESSOR_TARGETS, targets);
+ mTargets = targets;
+ mTransformation = transformation;
+ mExecutor = executor;
+ mSurfaceProcessor = surfaceProcessor;
+ mImageProcessor = null;
+ mErrorListener = errorListener;
+ }
+
+ /**
+ * @param targets the target {@link UseCase} to which this effect should be applied.
+ * Currently {@link SurfaceProcessor} can target the following
+ * combinations:
+ * <ul>
+ * <li>{@link #PREVIEW}
+ * <li>{@link #PREVIEW} | {@link #VIDEO_CAPTURE}
+ * <li>{@link #PREVIEW} | {@link #VIDEO_CAPTURE} |
+ * {@link #IMAGE_CAPTURE}
+ * </ul>
+ * Targeting other {@link UseCase} combinations will throw
+ * {@link IllegalArgumentException}.
* @param executor the {@link Executor} on which the {@param imageProcessor} and
* {@param errorListener} will be invoked.
* @param surfaceProcessor a {@link SurfaceProcessor} implementation. Once the effect is
@@ -191,6 +274,7 @@
@NonNull Consumer<Throwable> errorListener) {
checkSupportedTargets(SURFACE_PROCESSOR_TARGETS, targets);
mTargets = targets;
+ mTransformation = TRANSFORMATION_ARBITRARY;
mExecutor = executor;
mSurfaceProcessor = surfaceProcessor;
mImageProcessor = null;
@@ -206,6 +290,15 @@
}
/**
+ * Gets the transformation that the {@link SurfaceProcessor} will handle.
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @Transformations
+ public int getTransformation() {
+ return mTransformation;
+ }
+
+ /**
* Gets the {@link Executor} associated with this effect.
*
* <p>This method returns the value set in the constructor.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/CameraInfo.java b/camera/camera-core/src/main/java/androidx/camera/core/CameraInfo.java
index 57fd948..e712179 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/CameraInfo.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/CameraInfo.java
@@ -27,6 +27,7 @@
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
import androidx.annotation.StringDef;
+import androidx.camera.core.impl.DynamicRanges;
import androidx.camera.core.impl.ImageOutputConfig;
import androidx.camera.core.internal.compat.MediaActionSoundCompat;
import androidx.lifecycle.LifecycleOwner;
@@ -340,6 +341,71 @@
return false;
}
+ /**
+ * Returns the supported dynamic ranges of this camera from a set of candidate dynamic ranges.
+ *
+ * <p>Dynamic range specifies how the range of colors, highlights and shadows captured by
+ * the frame producer are represented on a display. Some dynamic ranges allow the preview
+ * surface to make full use of the extended range of brightness of the display.
+ *
+ * <p>The returned dynamic ranges are those which the camera can produce. However, because
+ * care usually needs to be taken to ensure the frames produced can be displayed correctly,
+ * the returned dynamic ranges will be limited to those passed in to {@code
+ * candidateDynamicRanges}. For example, if the device display supports HLG, HDR10 and
+ * HDR10+, and you're attempting to use a UI component to receive frames from those dynamic
+ * ranges that you know will be display correctly, you would use a {@code
+ * candidateDynamicRanges} set consisting of {@code {DynamicRange.HLG_10_BIT,
+ * DynamicRange.HDR10_10_BIT, DynamicRange.HDR10_PLUS_10_BIT}}. If the only 10-bit/HDR {@code
+ * DynamicRange} the camera can produce is {@code HLG_10_BIT}, then that will be the only
+ * dynamic range returned by this method given the above candidate list.
+ *
+ * <p>Consult the documentation of each use case to determine whether using the dynamic ranges
+ * published here are appropriate. Some use cases may have complex requirements that prohibit
+ * them from publishing a candidate list for use with this method, such as
+ * {@link androidx.camera.video.Recorder Recorder}. For those cases, alternative APIs may be
+ * present for querying the supported dynamic ranges that can be set on the use case.
+ *
+ * <p>The dynamic ranges published as return values by this method are fully-defined. That is,
+ * the resulting set will not contain dynamic ranges such as {@link DynamicRange#UNSPECIFIED} or
+ * {@link DynamicRange#HDR_UNSPECIFIED_10_BIT}. However, non-fully-defined dynamic ranges can
+ * be used in {@code candidateDynamicRanges}, and will resolve to fully-defined dynamic ranges
+ * in the resulting set. To query all dynamic ranges the camera can produce, {@code
+ * Collections.singleton(DynamicRange.UNSPECIFIED}} can be used as the candidate set.
+ *
+ * <p>Because SDR is always supported, including {@link DynamicRange#SDR} in {@code
+ * candidateDynamicRanges} will always result in {@code SDR} being present in the result set.
+ * If an empty candidate set is provided, it is treated as a no-op, and an empty set will be
+ * returned.
+ *
+ * @param candidateDynamicRanges a set of dynamic ranges representing the dynamic ranges the
+ * consumer of frames can support. Note that each use case may
+ * have its own requirements on which dynamic ranges it can
+ * consume based on how it is configured, and those dynamic
+ * ranges may not be published as a set of candidate dynamic
+ * ranges. In that case, this API may not be appropriate. An
+ * example of this is
+ * {@link androidx.camera.video.VideoCapture VideoCapture}'s
+ * {@link androidx.camera.video.Recorder Recorder} class, which
+ * must also take into account the dynamic ranges supported by
+ * the media codecs on the device, and the quality of the video
+ * being recorded. For that class, it is recommended to use
+ * {@link androidx.camera.video.RecorderVideoCapabilities#getSupportedDynamicRanges()
+ * RecorderVideoCapabilities.getSupportedDynamicRanges()}
+ * instead.
+ * @return a set of dynamic ranges supported by the camera based on the candidate dynamic ranges
+ *
+ * @see Preview.Builder#setDynamicRange(DynamicRange)
+ * @see androidx.camera.video.RecorderVideoCapabilities#getSupportedDynamicRanges()
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ default Set<DynamicRange> querySupportedDynamicRanges(
+ @NonNull Set<DynamicRange> candidateDynamicRanges) {
+ // For the default implementation, only assume SDR is supported.
+ return DynamicRanges.findAllPossibleMatches(candidateDynamicRanges,
+ Collections.singleton(DynamicRange.SDR));
+ }
+
@StringDef(open = true, value = {IMPLEMENTATION_TYPE_UNKNOWN,
IMPLEMENTATION_TYPE_CAMERA2_LEGACY, IMPLEMENTATION_TYPE_CAMERA2,
IMPLEMENTATION_TYPE_FAKE})
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageProcessingUtil.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageProcessingUtil.java
index dc55aec..e448993 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageProcessingUtil.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageProcessingUtil.java
@@ -146,11 +146,25 @@
}
/**
- * Convert a YUV_420_888 ImageProxy to a JPEG bytes data as an Image into the Surface.
+ * Convert a YUV_420_888 Image to a JPEG bytes data as an Image into the Surface.
*
* <p>Returns true if it succeeds and false otherwise.
*/
public static boolean convertYuvToJpegBytesIntoSurface(
+ @NonNull Image image,
+ @IntRange(from = 1, to = 100) int jpegQuality,
+ @ImageOutputConfig.RotationDegreesValue int rotationDegrees,
+ @NonNull Surface outputSurface) {
+ return convertYuvToJpegBytesIntoSurface(new AndroidImageProxy(image), jpegQuality,
+ rotationDegrees, outputSurface);
+ }
+
+ /**
+ * Convert a YUV_420_888 ImageProxy to a JPEG bytes data as an Image into the Surface.
+ *
+ * <p>Returns true if it succeeds and false otherwise.
+ */
+ public static boolean convertYuvToJpegBytesIntoSurface(
@NonNull ImageProxy imageProxy,
@IntRange(from = 1, to = 100) int jpegQuality,
@ImageOutputConfig.RotationDegreesValue int rotationDegrees,
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/Preview.java b/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
index 8bc0b73..d804dab 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
@@ -19,6 +19,7 @@
import static androidx.camera.core.CameraEffect.PREVIEW;
import static androidx.camera.core.MirrorMode.MIRROR_MODE_ON_FRONT_ONLY;
import static androidx.camera.core.impl.ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE;
+import static androidx.camera.core.impl.ImageInputConfig.OPTION_INPUT_DYNAMIC_RANGE;
import static androidx.camera.core.impl.ImageInputConfig.OPTION_INPUT_FORMAT;
import static androidx.camera.core.impl.ImageOutputConfig.OPTION_APP_TARGET_ROTATION;
import static androidx.camera.core.impl.ImageOutputConfig.OPTION_CUSTOM_ORDERED_RESOLUTIONS;
@@ -62,7 +63,6 @@
import android.view.SurfaceView;
import android.view.TextureView;
-import androidx.annotation.IntRange;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -77,6 +77,7 @@
import androidx.camera.core.impl.Config;
import androidx.camera.core.impl.ConfigProvider;
import androidx.camera.core.impl.DeferrableSurface;
+import androidx.camera.core.impl.ImageInputConfig;
import androidx.camera.core.impl.ImageOutputConfig;
import androidx.camera.core.impl.MutableConfig;
import androidx.camera.core.impl.MutableOptionsBundle;
@@ -288,20 +289,6 @@
}
}
- @RestrictTo(Scope.LIBRARY_GROUP)
- @Override
- @IntRange(from = 0, to = 359)
- protected int getRelativeRotation(@NonNull CameraInternal cameraInternal,
- boolean requireMirroring) {
- if (cameraInternal.getHasTransform()) {
- return super.getRelativeRotation(cameraInternal, requireMirroring);
- } else {
- // If there is a virtual parent camera, the buffer is already rotated because
- // SurfaceView cannot handle additional rotation.
- return 0;
- }
- }
-
private boolean shouldMirror(@NonNull CameraInternal camera) {
// Since PreviewView cannot mirror, we will always mirror preview stream during buffer
// copy. If there has been a buffer copy, it means it's already mirrored. Otherwise,
@@ -673,6 +660,37 @@
}
/**
+ * Returns the dynamic range.
+ *
+ * <p>The dynamic range is set by {@link Preview.Builder#setDynamicRange(DynamicRange)}.
+ * If the dynamic range set is not a fully defined dynamic range, such as
+ * {@link DynamicRange#HDR_UNSPECIFIED_10_BIT}, then it will be returned just as provided,
+ * and will not be returned as a fully defined dynamic range. The fully defined dynamic
+ * range, which is determined by resolving the combination of requested dynamic ranges from
+ * other use cases according to the device capabilities, will be
+ * communicated to the {@link Preview.SurfaceProvider} via
+ * {@link SurfaceRequest#getDynamicRange()}}.
+ *
+ * <p>If the dynamic range was not provided to
+ * {@link Preview.Builder#setDynamicRange(DynamicRange)}, this will return the default of
+ * {@link DynamicRange#UNSPECIFIED}
+ *
+ * @return the dynamic range set for this {@code Preview} use case.
+ *
+ * @see Preview.Builder#setDynamicRange(DynamicRange)
+ */
+ // Internal implementation note: this method should not be used to retrieve the dynamic range
+ // that will be sent to the SurfaceProvider. That should always be retrieved from the StreamSpec
+ // since that will be the final DynamicRange chosen by the camera based on other use case
+ // combinations.
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public DynamicRange getDynamicRange() {
+ return getCurrentConfig().hasDynamicRange() ? getCurrentConfig().getDynamicRange() :
+ Defaults.DEFAULT_DYNAMIC_RANGE;
+ }
+
+ /**
* Returns {@link PreviewCapabilities} to query preview stream related device capability.
*
* @return {@link PreviewCapabilities}
@@ -776,11 +794,19 @@
private static final PreviewConfig DEFAULT_CONFIG;
+ /**
+ * Preview uses an UNSPECIFIED dynamic range by default. This means the dynamic range can be
+ * inherited from other use cases during dynamic range resolution when the use case is
+ * bound.
+ */
+ private static final DynamicRange DEFAULT_DYNAMIC_RANGE = DynamicRange.UNSPECIFIED;
+
static {
Builder builder = new Builder()
.setSurfaceOccupancyPriority(DEFAULT_SURFACE_OCCUPANCY_PRIORITY)
.setTargetAspectRatio(DEFAULT_ASPECT_RATIO)
- .setResolutionSelector(DEFAULT_RESOLUTION_SELECTOR);
+ .setResolutionSelector(DEFAULT_RESOLUTION_SELECTOR)
+ .setDynamicRange(DEFAULT_DYNAMIC_RANGE);
DEFAULT_CONFIG = builder.getUseCaseConfig();
}
@@ -796,6 +822,7 @@
public static final class Builder
implements UseCaseConfig.Builder<Preview, PreviewConfig, Builder>,
ImageOutputConfig.Builder<Builder>,
+ ImageInputConfig.Builder<Builder>,
ThreadConfig.Builder<Builder> {
private final MutableOptionsBundle mMutableConfig;
@@ -1125,6 +1152,88 @@
return this;
}
+ // Implementations of ImageInputConfig.Builder default methods
+
+ /**
+ * Sets the {@link DynamicRange}.
+ *
+ * <p>Dynamic range specifies how the range of colors, highlights and shadows captured by
+ * the frame producer are represented on a display. Some dynamic ranges allow the preview
+ * surface to make full use of the extended range of brightness of the display.
+ *
+ * <p>The supported dynamic ranges for preview depend on the capabilities of the
+ * camera and the ability of the {@link Surface} provided by the
+ * {@link Preview.SurfaceProvider} to consume the dynamic range. The supported dynamic
+ * ranges of the camera can be queried using
+ * {@link CameraInfo#querySupportedDynamicRanges(Set)}.
+ *
+ * <p>As an example, if the {@link Surface} provided by {@link Preview.SurfaceProvider}
+ * comes from a {@link SurfaceView}, such as with
+ * {@link androidx.camera.viewfinder.CameraViewfinder CameraViewfinder} set to
+ * implementation mode
+ * {@link androidx.camera.viewfinder.CameraViewfinder.ImplementationMode#PERFORMANCE
+ * PERFORMANCE}, you may want to query the dynamic ranges supported by the display:
+ * <pre>
+ * <code>
+ *
+ * // Get supported HDR dynamic ranges from the display
+ * Display display = requireContext().getDisplay();
+ * List<Integer> displayHdrTypes =
+ * display.getHdrCapabilities().getSupportedHdrTypes();
+ * Set<DynamicRange> displayHighDynamicRanges =
+ * // Simple map of Display.HdrCapabilities enums to CameraX DynamicRange
+ * convertToDynamicRangeSet(displayHdrTypes);
+ *
+ * // Query dynamic ranges supported by the camera from our
+ * // dynamic ranges supported by the display.
+ * mSupportedHighDynamicRanges =
+ * mCameraInfo.querySupportedDynamicRanges(
+ * displayHighDynamicRanges);
+ *
+ * // Update our UI picker for dynamic range.
+ * ...
+ *
+ *
+ * // Create the Preview use case from the dynamic range
+ * // selected by the UI picker.
+ * mPreview = new Preview.Builder()
+ * .setDynamicRange(mSelectedDynamicRange)
+ * .build();
+ * </code>
+ * </pre>
+ *
+ * <p>If the dynamic range is not provided, the returned {@code Preview} use case will use
+ * a default of {@link DynamicRange#UNSPECIFIED}. When a {@code Preview} is bound with
+ * other use cases that specify a dynamic range, such as
+ * {@link androidx.camera.video.VideoCapture}, and the preview dynamic range is {@code
+ * UNSPECIFIED}, the resulting dynamic range of the preview will usually match the other
+ * use case's dynamic range. If no other use cases are bound with the preview, an
+ * {@code UNSPECIFIED} dynamic range will resolve to {@link DynamicRange#SDR}. When
+ * using a {@code Preview} with another use case, it is recommended to leave the dynamic
+ * range of the {@code Preview} as {@link DynamicRange#UNSPECIFIED}, so the camera can
+ * choose the best supported dynamic range that satisfies the requirements of both use
+ * cases.
+ *
+ * <p>If an unspecified dynamic range is used, the resolved fully-defined dynamic range of
+ * frames sent from the camera will be communicated to the
+ * {@link Preview.SurfaceProvider} via {@link SurfaceRequest#getDynamicRange()}, and the
+ * provided {@link Surface} should be configured to use that dynamic range.
+ *
+ * <p>It is possible to choose a high dynamic range (HDR) with unspecified encoding by
+ * providing {@link DynamicRange#HDR_UNSPECIFIED_10_BIT}.
+ *
+ * @return The current Builder.
+ * @see DynamicRange
+ * @see CameraInfo#querySupportedDynamicRanges(Set)
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ @Override
+ public Builder setDynamicRange(@NonNull DynamicRange dynamicRange) {
+ getMutableConfig().insertOption(OPTION_INPUT_DYNAMIC_RANGE, dynamicRange);
+ return this;
+ }
+
// Implementations of ThreadConfig.Builder default methods
/**
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/DynamicRanges.kt b/camera/camera-core/src/main/java/androidx/camera/core/impl/DynamicRanges.kt
new file mode 100644
index 0000000..3137051
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/DynamicRanges.kt
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2023 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.camera.core.impl
+
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.camera.core.DynamicRange
+import androidx.core.util.Preconditions
+
+/**
+ * Utility methods for handling dynamic range.
+ */
+@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+object DynamicRanges {
+
+ /**
+ * Returns `true` if the test dynamic range can resolve to the fully specified dynamic
+ * range set.
+ *
+ * A range can resolve if test fields are unspecified and appropriately match the fields
+ * of the fully specified dynamic range, or the test fields exactly match the fields of
+ * the fully specified dynamic range.
+ */
+ @JvmStatic
+ fun canResolve(
+ dynamicRangeToTest: DynamicRange,
+ fullySpecifiedDynamicRanges: Set<DynamicRange>,
+
+ ): Boolean {
+ return if (dynamicRangeToTest.isFullySpecified) {
+ fullySpecifiedDynamicRanges.contains(dynamicRangeToTest)
+ } else {
+ fullySpecifiedDynamicRanges.firstOrNull { fullySpecifiedDynamicRange ->
+ canResolveUnderSpecifiedTo(
+ dynamicRangeToTest,
+ fullySpecifiedDynamicRange
+ )
+ } != null
+ }
+ }
+ /**
+ * Returns a set of all possible matches from a set of dynamic ranges that may contain
+ * under-specified dynamic ranges to a set that contains only fully-specified dynamic ranges.
+ *
+ * A dynamic range can resolve if test fields are unspecified and appropriately match the fields
+ * of the fully specified dynamic range, or the test fields exactly match the fields of
+ * the fully specified dynamic range.
+ */
+ @JvmStatic
+ fun findAllPossibleMatches(
+ dynamicRangesToTest: Set<DynamicRange>,
+ fullySpecifiedDynamicRanges: Set<DynamicRange>
+ ): Set<DynamicRange> {
+ return buildSet {
+ dynamicRangesToTest.forEach {
+ if (it.isFullySpecified) {
+ // Add matching fully-specified dynamic ranges directly
+ if (fullySpecifiedDynamicRanges.contains(it)) {
+ add(it)
+ }
+ } else {
+ // Iterate through fully-specified dynamic ranges to find which could be used
+ // by the corresponding under-specified dynamic ranges
+ fullySpecifiedDynamicRanges.forEach { fullySpecifiedDynamicRange ->
+ if (canResolveUnderSpecifiedTo(it, fullySpecifiedDynamicRange)) {
+ add(fullySpecifiedDynamicRange)
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private fun canResolveUnderSpecifiedTo(
+ underSpecifiedDynamicRange: DynamicRange,
+ fullySpecifiedDynamicRange: DynamicRange
+ ): Boolean {
+ return canMatchBitDepth(underSpecifiedDynamicRange, fullySpecifiedDynamicRange) &&
+ canMatchEncoding(underSpecifiedDynamicRange, fullySpecifiedDynamicRange)
+ }
+
+ private fun canMatchBitDepth(
+ dynamicRangeToTest: DynamicRange,
+ fullySpecifiedDynamicRange: DynamicRange
+ ): Boolean {
+ Preconditions.checkState(
+ fullySpecifiedDynamicRange.isFullySpecified, "Fully specified " +
+ "range is not actually fully specified."
+ )
+ return if (dynamicRangeToTest.bitDepth == DynamicRange.BIT_DEPTH_UNSPECIFIED) {
+ true
+ } else {
+ dynamicRangeToTest.bitDepth == fullySpecifiedDynamicRange.bitDepth
+ }
+ }
+
+ private fun canMatchEncoding(
+ dynamicRangeToTest: DynamicRange,
+ fullySpecifiedDynamicRange: DynamicRange
+ ): Boolean {
+ Preconditions.checkState(
+ fullySpecifiedDynamicRange.isFullySpecified, "Fully specified " +
+ "range is not actually fully specified."
+ )
+ val encodingToTest = dynamicRangeToTest.encoding
+ if (encodingToTest == DynamicRange.ENCODING_UNSPECIFIED) {
+ return true
+ }
+ val fullySpecifiedEncoding = fullySpecifiedDynamicRange.encoding
+ return if (encodingToTest == DynamicRange.ENCODING_HDR_UNSPECIFIED &&
+ fullySpecifiedEncoding != DynamicRange.ENCODING_SDR) {
+ true
+ } else {
+ encodingToTest == fullySpecifiedEncoding
+ }
+ }
+}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/ForwardingCameraInfo.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/ForwardingCameraInfo.java
index 5ce2595..fc397ff3 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/ForwardingCameraInfo.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/ForwardingCameraInfo.java
@@ -183,6 +183,13 @@
@NonNull
@Override
+ public Set<DynamicRange> querySupportedDynamicRanges(
+ @NonNull Set<DynamicRange> candidateDynamicRanges) {
+ return mCameraInfoInternal.querySupportedDynamicRanges(candidateDynamicRanges);
+ }
+
+ @NonNull
+ @Override
public CameraInfoInternal getImplementation() {
return mCameraInfoInternal.getImplementation();
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/processing/DefaultSurfaceProcessor.java b/camera/camera-core/src/main/java/androidx/camera/core/processing/DefaultSurfaceProcessor.java
index 94583c4..5477b9c 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/processing/DefaultSurfaceProcessor.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/processing/DefaultSurfaceProcessor.java
@@ -26,7 +26,6 @@
import android.graphics.Bitmap;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
-import android.opengl.Matrix;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Size;
@@ -314,17 +313,13 @@
private Bitmap getBitmap(@NonNull Size size,
@NonNull float[] textureTransform,
int rotationDegrees) {
- float[] snapshotTransform = new float[16];
- Matrix.setIdentityM(snapshotTransform, 0);
-
- // Flip the snapshot. This is for reverting the GL transform added in SurfaceOutputImpl.
- MatrixExt.preVerticalFlip(snapshotTransform, 0.5f);
+ float[] snapshotTransform = textureTransform.clone();
// Rotate the output if requested.
MatrixExt.preRotate(snapshotTransform, rotationDegrees, 0.5f, 0.5f);
- // Apply the texture transform.
- Matrix.multiplyMM(snapshotTransform, 0, snapshotTransform, 0, textureTransform, 0);
+ // Flip the snapshot. This is for reverting the GL transform added in SurfaceOutputImpl.
+ MatrixExt.preVerticalFlip(snapshotTransform, 0.5f);
// Update the size based on the rotation degrees.
size = rotateSize(size, rotationDegrees);
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharing.java b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharing.java
index f614de1..287eed3 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharing.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharing.java
@@ -42,6 +42,7 @@
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.annotation.VisibleForTesting;
+import androidx.camera.core.CameraEffect;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.UseCase;
import androidx.camera.core.impl.CameraInfoInternal;
@@ -80,7 +81,7 @@
private final StreamSharingConfig mDefaultConfig;
@NonNull
- private final VirtualCamera mVirtualCamera;
+ private final VirtualCameraAdapter mVirtualCameraAdapter;
// Node that applies effect to the input.
@Nullable
private SurfaceProcessorNode mEffectNode;
@@ -114,7 +115,6 @@
return new StreamSharingConfig(OptionsBundle.from(mutableConfig));
}
-
/**
* Constructs a {@link StreamSharing} with a parent {@link CameraInternal}, children
* {@link UseCase}s, and a {@link UseCaseConfigFactory} for getting default {@link UseCase}
@@ -125,17 +125,17 @@
@NonNull UseCaseConfigFactory useCaseConfigFactory) {
super(getDefaultConfig(children));
mDefaultConfig = getDefaultConfig(children);
- mVirtualCamera = new VirtualCamera(parentCamera, children, useCaseConfigFactory,
- (jpegQuality, rotationDegrees) -> {
- SurfaceProcessorNode sharingNode = mSharingNode;
- if (sharingNode != null) {
- return sharingNode.getSurfaceProcessor().snapshot(
- jpegQuality, rotationDegrees);
- } else {
- return Futures.immediateFailedFuture(new Exception(
- "Failed to take picture: pipeline is not ready."));
- }
- });
+ mVirtualCameraAdapter = new VirtualCameraAdapter(
+ parentCamera, children, useCaseConfigFactory, (jpegQuality, rotationDegrees) -> {
+ SurfaceProcessorNode sharingNode = mSharingNode;
+ if (sharingNode != null) {
+ return sharingNode.getSurfaceProcessor().snapshot(
+ jpegQuality, rotationDegrees);
+ } else {
+ return Futures.immediateFailedFuture(new Exception(
+ "Failed to take picture: pipeline is not ready."));
+ }
+ });
}
@Nullable
@@ -164,7 +164,7 @@
@Override
protected UseCaseConfig<?> onMergeConfig(@NonNull CameraInfoInternal cameraInfo,
@NonNull UseCaseConfig.Builder<?, ?, ?> builder) {
- mVirtualCamera.mergeChildrenConfigs(builder.getMutableConfig());
+ mVirtualCameraAdapter.mergeChildrenConfigs(builder.getMutableConfig());
return builder.getUseCaseConfig();
}
@@ -192,31 +192,31 @@
@Override
public void onBind() {
super.onBind();
- mVirtualCamera.bindChildren();
+ mVirtualCameraAdapter.bindChildren();
}
@Override
public void onUnbind() {
super.onUnbind();
clearPipeline();
- mVirtualCamera.unbindChildren();
+ mVirtualCameraAdapter.unbindChildren();
}
@Override
public void onStateAttached() {
super.onStateAttached();
- mVirtualCamera.notifyStateAttached();
+ mVirtualCameraAdapter.notifyStateAttached();
}
@Override
public void onStateDetached() {
super.onStateDetached();
- mVirtualCamera.notifyStateDetached();
+ mVirtualCameraAdapter.notifyStateDetached();
}
@NonNull
public Set<UseCase> getChildren() {
- return mVirtualCamera.getChildren();
+ return mVirtualCameraAdapter.getChildren();
}
/**
@@ -257,7 +257,8 @@
// Transform the input based on virtual camera configuration.
Map<UseCase, SurfaceProcessorNode.OutConfig> outConfigMap =
- mVirtualCamera.getChildrenOutConfigs(mSharingInputEdge);
+ mVirtualCameraAdapter.getChildrenOutConfigs(mSharingInputEdge,
+ getTargetRotationInternal());
SurfaceProcessorNode.Out out = mSharingNode.transform(
SurfaceProcessorNode.In.of(mSharingInputEdge,
new ArrayList<>(outConfigMap.values())));
@@ -267,7 +268,7 @@
for (Map.Entry<UseCase, SurfaceProcessorNode.OutConfig> entry : outConfigMap.entrySet()) {
outputEdges.put(entry.getKey(), out.get(entry.getValue()));
}
- mVirtualCamera.setChildrenEdges(outputEdges);
+ mVirtualCameraAdapter.setChildrenEdges(outputEdges);
// Send the camera edge Surface to the camera2.
SessionConfig.Builder builder = SessionConfig.Builder.createFrom(config,
@@ -276,7 +277,8 @@
propagateChildrenCamera2Interop(streamSpec.getResolution(), builder);
builder.addSurface(mCameraEdge.getDeferrableSurface());
- builder.addRepeatingCameraCaptureCallback(mVirtualCamera.getParentMetadataCallback());
+ builder.addRepeatingCameraCaptureCallback(
+ mVirtualCameraAdapter.getParentMetadataCallback());
if (streamSpec.getImplementationOptions() != null) {
builder.addImplementationOptions(streamSpec.getImplementationOptions());
}
@@ -318,7 +320,7 @@
mEffectNode = new SurfaceProcessorNode(camera,
getEffect().createSurfaceProcessorInternal());
// Effect does not apply rotation.
- int rotationAppliedByEffect = 0;
+ int rotationAppliedByEffect = getRotationAppliedByEffect();
SurfaceProcessorNode.OutConfig outConfig = SurfaceProcessorNode.OutConfig.of(
cameraEdge.getTargets(),
cameraEdge.getFormat(),
@@ -332,6 +334,18 @@
return requireNonNull(out.get(outConfig));
}
+ private int getRotationAppliedByEffect() {
+ CameraEffect effect = checkNotNull(getEffect());
+ if (effect.getTransformation() == CameraEffect.TRANSFORMATION_CAMERA_AND_SURFACE_ROTATION) {
+ // Apply the rotation degrees if the effect is configured to do so.
+ // TODO: handle this option in VideoCapture.
+ return getRelativeRotation(checkNotNull(getCamera()));
+ } else {
+ // By default, the effect node does not apply any rotation.
+ return 0;
+ }
+ }
+
private void addCameraErrorListener(
@NonNull SessionConfig.Builder sessionConfigBuilder,
@NonNull String cameraId,
@@ -349,7 +363,7 @@
// children UseCase does not have additional logic in SessionConfig error listener
// so this is OK. If they do, we need to invoke the children's SessionConfig
// error listeners instead.
- mVirtualCamera.resetChildren();
+ mVirtualCameraAdapter.resetChildren();
}
});
}
@@ -409,8 +423,8 @@
@VisibleForTesting
@NonNull
- VirtualCamera getVirtualCamera() {
- return mVirtualCamera;
+ VirtualCameraAdapter getVirtualCameraAdapter() {
+ return mVirtualCameraAdapter;
}
/**
@@ -437,4 +451,10 @@
public static boolean isStreamSharing(@Nullable UseCase useCase) {
return useCase instanceof StreamSharing;
}
+
+ @VisibleForTesting
+ @Nullable
+ public SurfaceEdge getSharingInputEdge() {
+ return mSharingInputEdge;
+ }
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/VirtualCamera.java b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/VirtualCamera.java
index 2d939b7..4d3ad88 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/VirtualCamera.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/VirtualCamera.java
@@ -15,63 +15,22 @@
*/
package androidx.camera.core.streamsharing;
-import static androidx.camera.core.CameraEffect.IMAGE_CAPTURE;
-import static androidx.camera.core.CameraEffect.PREVIEW;
-import static androidx.camera.core.CameraEffect.VIDEO_CAPTURE;
-import static androidx.camera.core.impl.ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE;
-import static androidx.camera.core.impl.ImageInputConfig.OPTION_INPUT_DYNAMIC_RANGE;
-import static androidx.camera.core.impl.ImageOutputConfig.OPTION_CUSTOM_ORDERED_RESOLUTIONS;
-import static androidx.camera.core.impl.UseCaseConfig.OPTION_PREVIEW_STABILIZATION_MODE;
-import static androidx.camera.core.impl.UseCaseConfig.OPTION_SURFACE_OCCUPANCY_PRIORITY;
-import static androidx.camera.core.impl.UseCaseConfig.OPTION_VIDEO_STABILIZATION_MODE;
import static androidx.camera.core.impl.utils.Threads.checkMainThread;
-import static androidx.camera.core.impl.utils.TransformUtils.getRotatedSize;
-import static androidx.camera.core.impl.utils.TransformUtils.rectToSize;
-import static androidx.camera.core.streamsharing.DynamicRangeUtils.resolveDynamicRange;
-import static androidx.camera.core.streamsharing.ResolutionUtils.getMergedResolutions;
-import static androidx.core.util.Preconditions.checkState;
-import static java.util.Objects.requireNonNull;
-
-import android.graphics.ImageFormat;
import android.os.Build;
-import android.util.Size;
-import androidx.annotation.IntRange;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
-import androidx.annotation.VisibleForTesting;
-import androidx.camera.core.CameraEffect;
-import androidx.camera.core.DynamicRange;
-import androidx.camera.core.ImageCapture;
-import androidx.camera.core.Preview;
import androidx.camera.core.UseCase;
-import androidx.camera.core.impl.CameraCaptureCallback;
-import androidx.camera.core.impl.CameraCaptureResult;
import androidx.camera.core.impl.CameraControlInternal;
import androidx.camera.core.impl.CameraInfoInternal;
import androidx.camera.core.impl.CameraInternal;
-import androidx.camera.core.impl.DeferrableSurface;
-import androidx.camera.core.impl.MutableConfig;
import androidx.camera.core.impl.Observable;
-import androidx.camera.core.impl.SessionConfig;
-import androidx.camera.core.impl.UseCaseConfig;
-import androidx.camera.core.impl.UseCaseConfigFactory;
-import androidx.camera.core.impl.stabilization.StabilizationMode;
-import androidx.camera.core.processing.SurfaceEdge;
-import androidx.camera.core.processing.SurfaceProcessorNode.OutConfig;
import com.google.common.util.concurrent.ListenableFuture;
-import java.util.ArrayList;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
/**
* A virtual implementation of {@link CameraInternal}.
@@ -82,249 +41,65 @@
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
class VirtualCamera implements CameraInternal {
private static final String UNSUPPORTED_MESSAGE = "Operation not supported by VirtualCamera.";
- // Children UseCases associated with this virtual camera.
- @NonNull
- final Set<UseCase> mChildren;
- // Specs for children UseCase, calculated and set by StreamSharing.
- @NonNull
- final Map<UseCase, SurfaceEdge> mChildrenEdges = new HashMap<>();
- // Whether a children is in the active state. See: UseCase.State.ACTIVE
- @NonNull
- final Map<UseCase, Boolean> mChildrenActiveState = new HashMap<>();
- // Config factory for getting children's config.
- @NonNull
- private final UseCaseConfigFactory mUseCaseConfigFactory;
// The parent camera instance.
@NonNull
private final CameraInternal mParentCamera;
- // The callback that receives the parent camera's metadata.
- @NonNull
- private final CameraCaptureCallback mParentMetadataCallback = createCameraCaptureCallback();
@NonNull
private final VirtualCameraControl mVirtualCameraControl;
@NonNull
private final VirtualCameraInfo mVirtualCameraInfo;
+ private final UseCase.StateChangeCallback mStateChangeCallback;
+
/**
- * @param parentCamera the parent {@link CameraInternal} instance. For example, the
- * real camera.
- * @param children the children {@link UseCase}.
- * @param useCaseConfigFactory the factory for configuring children {@link UseCase}.
+ * @param parentCamera the parent {@link CameraInternal} instance. For example, the
+ * real camera.
*/
VirtualCamera(@NonNull CameraInternal parentCamera,
- @NonNull Set<UseCase> children,
- @NonNull UseCaseConfigFactory useCaseConfigFactory,
+ @NonNull UseCase.StateChangeCallback useCaseStateCallback,
@NonNull StreamSharing.Control streamSharingControl) {
mParentCamera = parentCamera;
- mUseCaseConfigFactory = useCaseConfigFactory;
- mChildren = children;
+ mStateChangeCallback = useCaseStateCallback;
mVirtualCameraControl = new VirtualCameraControl(parentCamera.getCameraControlInternal(),
streamSharingControl);
mVirtualCameraInfo = new VirtualCameraInfo(parentCamera.getCameraInfoInternal());
- // Set children state to inactive by default.
- for (UseCase child : children) {
- mChildrenActiveState.put(child, false);
- }
- }
-
- // --- API for StreamSharing ---
- void mergeChildrenConfigs(@NonNull MutableConfig mutableConfig) {
- Set<UseCaseConfig<?>> childrenConfigs = new HashSet<>();
- for (UseCase useCase : mChildren) {
- childrenConfigs.add(useCase.mergeConfigs(mParentCamera.getCameraInfoInternal(),
- null,
- useCase.getDefaultConfig(true, mUseCaseConfigFactory)));
- }
-
- // Merge resolution configs.
- List<Size> cameraSupportedResolutions =
- new ArrayList<>(mParentCamera.getCameraInfoInternal().getSupportedResolutions(
- INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE));
- Size sensorSize = rectToSize(mParentCamera.getCameraControlInternal().getSensorRect());
- List<Size> mergedResolutions = getMergedResolutions(cameraSupportedResolutions, sensorSize,
- mutableConfig, childrenConfigs);
- mutableConfig.insertOption(OPTION_CUSTOM_ORDERED_RESOLUTIONS, mergedResolutions);
-
- // Merge Surface occupancy priority.
- mutableConfig.insertOption(OPTION_SURFACE_OCCUPANCY_PRIORITY,
- getHighestSurfacePriority(childrenConfigs));
-
- // Merge dynamic range configs. Try to find a dynamic range that can match all child
- // requirements, or throw an exception if no matching dynamic range.
- // TODO: This approach works for the current code base, where only VideoCapture can be
- // configured (Preview follows the settings, ImageCapture is fixed as SDR). When
- // dynamic range APIs opened on other use cases, we might want a more advanced approach
- // that allows conflicts, e.g. converting HDR stream to SDR stream.
- DynamicRange dynamicRange = resolveDynamicRange(childrenConfigs);
- if (dynamicRange == null) {
- throw new IllegalArgumentException("Failed to merge child dynamic ranges, can not find"
- + " a dynamic range that satisfies all children.");
- }
- mutableConfig.insertOption(OPTION_INPUT_DYNAMIC_RANGE, dynamicRange);
-
- // Merge Preview stabilization and video stabilization configs.
- for (UseCase useCase : mChildren) {
- if (useCase.getCurrentConfig().getVideoStabilizationMode()
- != StabilizationMode.UNSPECIFIED) {
- mutableConfig.insertOption(OPTION_VIDEO_STABILIZATION_MODE,
- useCase.getCurrentConfig().getVideoStabilizationMode());
- }
-
- if (useCase.getCurrentConfig().getPreviewStabilizationMode()
- != StabilizationMode.UNSPECIFIED) {
- mutableConfig.insertOption(OPTION_PREVIEW_STABILIZATION_MODE,
- useCase.getCurrentConfig().getPreviewStabilizationMode());
- }
- }
- }
-
- void bindChildren() {
- for (UseCase useCase : mChildren) {
- useCase.bindToCamera(this, null,
- useCase.getDefaultConfig(true, mUseCaseConfigFactory));
- }
- }
-
- void unbindChildren() {
- for (UseCase useCase : mChildren) {
- useCase.unbindFromCamera(this);
- }
- }
-
- void notifyStateAttached() {
- for (UseCase useCase : mChildren) {
- useCase.onStateAttached();
- }
- }
-
- void notifyStateDetached() {
- for (UseCase useCase : mChildren) {
- useCase.onStateDetached();
- }
- }
-
- @NonNull
- Set<UseCase> getChildren() {
- return mChildren;
}
/**
- * Gets {@link OutConfig} for children {@link UseCase} based on the input edge.
+ * Sets the rotation applied by this virtual camera.
*/
- @NonNull
- Map<UseCase, OutConfig> getChildrenOutConfigs(@NonNull SurfaceEdge cameraEdge) {
- Map<UseCase, OutConfig> outConfigs = new HashMap<>();
- for (UseCase useCase : mChildren) {
- // TODO(b/264936115): This is a temporary solution where children use the parent
- // stream without changing it. Later we will update it to allow
- // cropping/down-sampling to better match children UseCase config.
- int rotationDegrees = getChildRotationDegrees(useCase);
- outConfigs.put(useCase, OutConfig.of(
- getChildTargetType(useCase),
- getChildFormat(useCase),
- cameraEdge.getCropRect(),
- getRotatedSize(cameraEdge.getCropRect(), rotationDegrees),
- rotationDegrees,
- useCase.isMirroringRequired(this)));
- }
- return outConfigs;
+ void setRotationDegrees(int sensorRotationDegrees) {
+ mVirtualCameraInfo.setVirtualCameraRotationDegrees(sensorRotationDegrees);
}
- /**
- * Update children {@link SurfaceEdge} calculated by {@link StreamSharing}.
- */
- void setChildrenEdges(@NonNull Map<UseCase, SurfaceEdge> childrenEdges) {
- mChildrenEdges.clear();
- mChildrenEdges.putAll(childrenEdges);
- for (Map.Entry<UseCase, SurfaceEdge> entry : mChildrenEdges.entrySet()) {
- UseCase useCase = entry.getKey();
- SurfaceEdge surfaceEdge = entry.getValue();
- useCase.setViewPortCropRect(surfaceEdge.getCropRect());
- useCase.setSensorToBufferTransformMatrix(surfaceEdge.getSensorToBufferTransform());
- useCase.updateSuggestedStreamSpec(surfaceEdge.getStreamSpec());
- useCase.notifyState();
- }
- }
+ // --- Forward UseCase state change to VirtualCameraAdapter ---
- /**
- * Invokes {@link UseCase.StateChangeCallback#onUseCaseReset} for all children.
- */
- void resetChildren() {
- checkMainThread();
- for (UseCase useCase : mChildren) {
- onUseCaseReset(useCase);
- }
- }
-
- /**
- * Gets the callback for receiving parent camera's metadata.
- */
- @NonNull
- CameraCaptureCallback getParentMetadataCallback() {
- return mParentMetadataCallback;
- }
-
- // --- Handle children state change ---
@MainThread
@Override
public void onUseCaseActive(@NonNull UseCase useCase) {
checkMainThread();
- if (isUseCaseActive(useCase)) {
- return;
- }
- mChildrenActiveState.put(useCase, true);
- DeferrableSurface childSurface = getChildSurface(useCase);
- if (childSurface != null) {
- forceSetProvider(getUseCaseEdge(useCase), childSurface, useCase.getSessionConfig());
- }
+ mStateChangeCallback.onUseCaseActive(useCase);
}
@MainThread
@Override
public void onUseCaseInactive(@NonNull UseCase useCase) {
checkMainThread();
- if (!isUseCaseActive(useCase)) {
- return;
- }
- mChildrenActiveState.put(useCase, false);
- getUseCaseEdge(useCase).disconnect();
+ mStateChangeCallback.onUseCaseInactive(useCase);
}
@MainThread
@Override
public void onUseCaseUpdated(@NonNull UseCase useCase) {
checkMainThread();
- if (!isUseCaseActive(useCase)) {
- // No-op if the child is inactive. It will connect when it becomes active.
- return;
- }
- SurfaceEdge edge = getUseCaseEdge(useCase);
- DeferrableSurface childSurface = getChildSurface(useCase);
- if (childSurface != null) {
- // If the child has a Surface, connect. VideoCapture uses this mechanism to
- // resume/start recording.
- forceSetProvider(edge, childSurface, useCase.getSessionConfig());
- } else {
- // If the child has no Surface, disconnect. VideoCapture uses this mechanism to
- // pause/stop recording.
- edge.disconnect();
- }
+ mStateChangeCallback.onUseCaseUpdated(useCase);
}
@MainThread
@Override
public void onUseCaseReset(@NonNull UseCase useCase) {
checkMainThread();
- SurfaceEdge edge = getUseCaseEdge(useCase);
- edge.invalidate();
- if (!isUseCaseActive(useCase)) {
- // No-op if the child is inactive. It will connect when it becomes active.
- return;
- }
- DeferrableSurface childSurface = getChildSurface(useCase);
- if (childSurface != null) {
- forceSetProvider(edge, childSurface, useCase.getSessionConfig());
- }
+ mStateChangeCallback.onUseCaseReset(useCase);
}
// --- Forward parent camera properties and events ---
@@ -352,112 +127,8 @@
return mParentCamera.getCameraState();
}
- // --- private methods ---
-
- @IntRange(from = 0, to = 359)
- private int getChildRotationDegrees(@NonNull UseCase child) {
- if (child instanceof Preview) {
- // Rotate the buffer for Preview because SurfaceView cannot handle rotation.
- return mParentCamera.getCameraInfo().getSensorRotationDegrees(
- ((Preview) child).getTargetRotation());
- }
- // By default, sharing node does not rotate
- return 0;
- }
-
- private static int getChildFormat(@NonNull UseCase useCase) {
- return useCase instanceof ImageCapture ? ImageFormat.JPEG
- : INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE;
- }
-
- @CameraEffect.Targets
- private static int getChildTargetType(@NonNull UseCase useCase) {
- if (useCase instanceof Preview) {
- return PREVIEW;
- } else if (useCase instanceof ImageCapture) {
- return IMAGE_CAPTURE;
- } else {
- return VIDEO_CAPTURE;
- }
- }
-
- private static int getHighestSurfacePriority(Set<UseCaseConfig<?>> childrenConfigs) {
- int highestPriority = 0;
- for (UseCaseConfig<?> childConfig : childrenConfigs) {
- highestPriority = Math.max(highestPriority,
- childConfig.getSurfaceOccupancyPriority(0));
- }
- return highestPriority;
- }
-
- @NonNull
- private SurfaceEdge getUseCaseEdge(@NonNull UseCase useCase) {
- return requireNonNull(mChildrenEdges.get(useCase));
- }
-
- private boolean isUseCaseActive(@NonNull UseCase useCase) {
- return requireNonNull(mChildrenActiveState.get(useCase));
- }
-
- private void forceSetProvider(@NonNull SurfaceEdge edge,
- @NonNull DeferrableSurface childSurface,
- @NonNull SessionConfig childSessionConfig) {
- edge.invalidate();
- try {
- edge.setProvider(childSurface);
- } catch (DeferrableSurface.SurfaceClosedException e) {
- // The Surface is closed by the child. This will happen when e.g. the child is Preview
- // with SurfaceView implementation.
- // Invoke the error listener so it will recreate the pipeline.
- for (SessionConfig.ErrorListener listener : childSessionConfig.getErrorListeners()) {
- listener.onError(childSessionConfig,
- SessionConfig.SessionError.SESSION_ERROR_SURFACE_NEEDS_RESET);
- }
- }
- }
-
- /**
- * Gets the {@link DeferrableSurface} associated with the child.
- */
- @VisibleForTesting
- @Nullable
- static DeferrableSurface getChildSurface(@NonNull UseCase child) {
- // Get repeating Surface for preview & video, regular Surface for image capture.
- List<DeferrableSurface> surfaces = child instanceof ImageCapture
- ? child.getSessionConfig().getSurfaces() :
- child.getSessionConfig().getRepeatingCaptureConfig().getSurfaces();
- checkState(surfaces.size() <= 1);
- if (surfaces.size() == 1) {
- return surfaces.get(0);
- }
- return null;
- }
-
- CameraCaptureCallback createCameraCaptureCallback() {
- return new CameraCaptureCallback() {
- @Override
- public void onCaptureCompleted(@NonNull CameraCaptureResult cameraCaptureResult) {
- super.onCaptureCompleted(cameraCaptureResult);
- for (UseCase child : mChildren) {
- sendCameraCaptureResultToChild(cameraCaptureResult,
- child.getSessionConfig());
- }
- }
- };
- }
-
- static void sendCameraCaptureResultToChild(
- @NonNull CameraCaptureResult cameraCaptureResult,
- @NonNull SessionConfig sessionConfig) {
- for (CameraCaptureCallback callback :
- sessionConfig.getRepeatingCameraCaptureCallbacks()) {
- callback.onCaptureCompleted(new VirtualCameraCaptureResult(
- sessionConfig.getRepeatingCaptureConfig().getTagBundle(),
- cameraCaptureResult));
- }
- }
-
// --- Unused overrides ---
+
@Override
public void open() {
throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE);
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/VirtualCameraAdapter.java b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/VirtualCameraAdapter.java
new file mode 100644
index 0000000..6323d6c
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/VirtualCameraAdapter.java
@@ -0,0 +1,437 @@
+/*
+ * Copyright 2023 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.camera.core.streamsharing;
+
+import static androidx.camera.core.CameraEffect.IMAGE_CAPTURE;
+import static androidx.camera.core.CameraEffect.PREVIEW;
+import static androidx.camera.core.CameraEffect.VIDEO_CAPTURE;
+import static androidx.camera.core.impl.ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE;
+import static androidx.camera.core.impl.ImageInputConfig.OPTION_INPUT_DYNAMIC_RANGE;
+import static androidx.camera.core.impl.ImageOutputConfig.OPTION_CUSTOM_ORDERED_RESOLUTIONS;
+import static androidx.camera.core.impl.UseCaseConfig.OPTION_PREVIEW_STABILIZATION_MODE;
+import static androidx.camera.core.impl.UseCaseConfig.OPTION_SURFACE_OCCUPANCY_PRIORITY;
+import static androidx.camera.core.impl.UseCaseConfig.OPTION_VIDEO_STABILIZATION_MODE;
+import static androidx.camera.core.impl.utils.Threads.checkMainThread;
+import static androidx.camera.core.impl.utils.TransformUtils.getRotatedSize;
+import static androidx.camera.core.impl.utils.TransformUtils.rectToSize;
+import static androidx.camera.core.impl.utils.TransformUtils.within360;
+import static androidx.camera.core.streamsharing.DynamicRangeUtils.resolveDynamicRange;
+import static androidx.camera.core.streamsharing.ResolutionUtils.getMergedResolutions;
+import static androidx.core.util.Preconditions.checkState;
+
+import static java.util.Objects.requireNonNull;
+
+import android.graphics.ImageFormat;
+import android.os.Build;
+import android.util.Size;
+import android.view.Surface;
+
+import androidx.annotation.IntRange;
+import androidx.annotation.MainThread;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.VisibleForTesting;
+import androidx.camera.core.CameraEffect;
+import androidx.camera.core.DynamicRange;
+import androidx.camera.core.ImageCapture;
+import androidx.camera.core.Preview;
+import androidx.camera.core.UseCase;
+import androidx.camera.core.impl.CameraCaptureCallback;
+import androidx.camera.core.impl.CameraCaptureResult;
+import androidx.camera.core.impl.CameraInternal;
+import androidx.camera.core.impl.DeferrableSurface;
+import androidx.camera.core.impl.ImageOutputConfig;
+import androidx.camera.core.impl.MutableConfig;
+import androidx.camera.core.impl.SessionConfig;
+import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
+import androidx.camera.core.impl.stabilization.StabilizationMode;
+import androidx.camera.core.processing.SurfaceEdge;
+import androidx.camera.core.processing.SurfaceProcessorNode.OutConfig;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A virtual implementation of {@link CameraInternal}.
+ *
+ * <p> This class manages children {@link UseCase} and connects/disconnects them to the
+ * parent {@link StreamSharing}. It also forwards parent camera properties/events to the children.
+ */
+@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+class VirtualCameraAdapter implements UseCase.StateChangeCallback {
+
+ // Children UseCases associated with this virtual camera.
+ @NonNull
+ final Set<UseCase> mChildren;
+ // Specs for children UseCase, calculated and set by StreamSharing.
+ @NonNull
+ final Map<UseCase, SurfaceEdge> mChildrenEdges = new HashMap<>();
+ @NonNull
+ private final Map<UseCase, VirtualCamera> mChildrenVirtualCameras = new HashMap<>();
+ // Whether a children is in the active state. See: UseCase.State.ACTIVE
+ @NonNull
+ final Map<UseCase, Boolean> mChildrenActiveState = new HashMap<>();
+ // Config factory for getting children's config.
+ @NonNull
+ private final UseCaseConfigFactory mUseCaseConfigFactory;
+ // The parent camera instance.
+ @NonNull
+ private final CameraInternal mParentCamera;
+ // The callback that receives the parent camera's metadata.
+ @NonNull
+ private final CameraCaptureCallback mParentMetadataCallback = createCameraCaptureCallback();
+
+
+ /**
+ * @param parentCamera the parent {@link CameraInternal} instance. For example, the
+ * real camera.
+ * @param children the children {@link UseCase}.
+ * @param useCaseConfigFactory the factory for configuring children {@link UseCase}.
+ */
+ VirtualCameraAdapter(@NonNull CameraInternal parentCamera,
+ @NonNull Set<UseCase> children,
+ @NonNull UseCaseConfigFactory useCaseConfigFactory,
+ @NonNull StreamSharing.Control streamSharingControl) {
+ mParentCamera = parentCamera;
+ mUseCaseConfigFactory = useCaseConfigFactory;
+ mChildren = children;
+ // Set children state to inactive by default.
+ for (UseCase child : children) {
+ mChildrenActiveState.put(child, false);
+ mChildrenVirtualCameras.put(child, new VirtualCamera(
+ parentCamera,
+ this,
+ streamSharingControl));
+ }
+ }
+
+ // --- API for StreamSharing ---
+ void mergeChildrenConfigs(@NonNull MutableConfig mutableConfig) {
+ Set<UseCaseConfig<?>> childrenConfigs = new HashSet<>();
+ for (UseCase useCase : mChildren) {
+ childrenConfigs.add(useCase.mergeConfigs(mParentCamera.getCameraInfoInternal(),
+ null,
+ useCase.getDefaultConfig(true, mUseCaseConfigFactory)));
+ }
+
+ // Merge resolution configs.
+ List<Size> cameraSupportedResolutions =
+ new ArrayList<>(mParentCamera.getCameraInfoInternal().getSupportedResolutions(
+ INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE));
+ Size sensorSize = rectToSize(mParentCamera.getCameraControlInternal().getSensorRect());
+ List<Size> mergedResolutions = getMergedResolutions(cameraSupportedResolutions, sensorSize,
+ mutableConfig, childrenConfigs);
+ mutableConfig.insertOption(OPTION_CUSTOM_ORDERED_RESOLUTIONS, mergedResolutions);
+
+ // Merge Surface occupancy priority.
+ mutableConfig.insertOption(OPTION_SURFACE_OCCUPANCY_PRIORITY,
+ getHighestSurfacePriority(childrenConfigs));
+
+ // Merge dynamic range configs. Try to find a dynamic range that can match all child
+ // requirements, or throw an exception if no matching dynamic range.
+ // TODO: This approach works for the current code base, where only VideoCapture can be
+ // configured (Preview follows the settings, ImageCapture is fixed as SDR). When
+ // dynamic range APIs opened on other use cases, we might want a more advanced approach
+ // that allows conflicts, e.g. converting HDR stream to SDR stream.
+ DynamicRange dynamicRange = resolveDynamicRange(childrenConfigs);
+ if (dynamicRange == null) {
+ throw new IllegalArgumentException("Failed to merge child dynamic ranges, can not find"
+ + " a dynamic range that satisfies all children.");
+ }
+ mutableConfig.insertOption(OPTION_INPUT_DYNAMIC_RANGE, dynamicRange);
+
+ // Merge Preview stabilization and video stabilization configs.
+ for (UseCase useCase : mChildren) {
+ if (useCase.getCurrentConfig().getVideoStabilizationMode()
+ != StabilizationMode.UNSPECIFIED) {
+ mutableConfig.insertOption(OPTION_VIDEO_STABILIZATION_MODE,
+ useCase.getCurrentConfig().getVideoStabilizationMode());
+ }
+
+ if (useCase.getCurrentConfig().getPreviewStabilizationMode()
+ != StabilizationMode.UNSPECIFIED) {
+ mutableConfig.insertOption(OPTION_PREVIEW_STABILIZATION_MODE,
+ useCase.getCurrentConfig().getPreviewStabilizationMode());
+ }
+ }
+ }
+
+ void bindChildren() {
+ for (UseCase useCase : mChildren) {
+ useCase.bindToCamera(
+ requireNonNull(mChildrenVirtualCameras.get(useCase)),
+ null,
+ useCase.getDefaultConfig(true, mUseCaseConfigFactory));
+ }
+ }
+
+ void unbindChildren() {
+ for (UseCase useCase : mChildren) {
+ useCase.unbindFromCamera(requireNonNull(mChildrenVirtualCameras.get(useCase)));
+ }
+ }
+
+ void notifyStateAttached() {
+ for (UseCase useCase : mChildren) {
+ useCase.onStateAttached();
+ }
+ }
+
+ void notifyStateDetached() {
+ for (UseCase useCase : mChildren) {
+ useCase.onStateDetached();
+ }
+ }
+
+ @NonNull
+ Set<UseCase> getChildren() {
+ return mChildren;
+ }
+
+ /**
+ * Gets {@link OutConfig} for children {@link UseCase} based on the input edge.
+ */
+ @NonNull
+ Map<UseCase, OutConfig> getChildrenOutConfigs(@NonNull SurfaceEdge cameraEdge,
+ @ImageOutputConfig.RotationValue int parentTargetRotation) {
+ Map<UseCase, OutConfig> outConfigs = new HashMap<>();
+ int parentRotationDegrees = mParentCamera.getCameraInfo().getSensorRotationDegrees(
+ parentTargetRotation);
+ for (UseCase useCase : mChildren) {
+ // TODO(b/264936115): This is a temporary solution where children use the parent
+ // stream without changing it. Later we will update it to allow
+ // cropping/down-sampling to better match children UseCase config.
+ int childRotationDegrees = getChildRotationDegrees(useCase);
+ requireNonNull(mChildrenVirtualCameras.get(useCase))
+ .setRotationDegrees(childRotationDegrees);
+ int childParentDelta = within360(
+ cameraEdge.getRotationDegrees() + childRotationDegrees - parentRotationDegrees);
+ outConfigs.put(useCase, OutConfig.of(
+ getChildTargetType(useCase),
+ getChildFormat(useCase),
+ cameraEdge.getCropRect(),
+ getRotatedSize(cameraEdge.getCropRect(), childParentDelta),
+ childParentDelta,
+ useCase.isMirroringRequired(mParentCamera)));
+ }
+ return outConfigs;
+ }
+
+ /**
+ * Update children {@link SurfaceEdge} calculated by {@link StreamSharing}.
+ */
+ void setChildrenEdges(@NonNull Map<UseCase, SurfaceEdge> childrenEdges) {
+ mChildrenEdges.clear();
+ mChildrenEdges.putAll(childrenEdges);
+ for (Map.Entry<UseCase, SurfaceEdge> entry : mChildrenEdges.entrySet()) {
+ UseCase useCase = entry.getKey();
+ SurfaceEdge surfaceEdge = entry.getValue();
+ useCase.setViewPortCropRect(surfaceEdge.getCropRect());
+ useCase.setSensorToBufferTransformMatrix(surfaceEdge.getSensorToBufferTransform());
+ useCase.updateSuggestedStreamSpec(surfaceEdge.getStreamSpec());
+ useCase.notifyState();
+ }
+ }
+
+ /**
+ * Invokes {@link UseCase.StateChangeCallback#onUseCaseReset} for all children.
+ */
+ void resetChildren() {
+ checkMainThread();
+ for (UseCase useCase : mChildren) {
+ onUseCaseReset(useCase);
+ }
+ }
+
+ /**
+ * Gets the callback for receiving parent camera's metadata.
+ */
+ @NonNull
+ CameraCaptureCallback getParentMetadataCallback() {
+ return mParentMetadataCallback;
+ }
+
+ // --- Handle children state change ---
+ @MainThread
+ @Override
+ public void onUseCaseActive(@NonNull UseCase useCase) {
+ checkMainThread();
+ if (isUseCaseActive(useCase)) {
+ return;
+ }
+ mChildrenActiveState.put(useCase, true);
+ DeferrableSurface childSurface = getChildSurface(useCase);
+ if (childSurface != null) {
+ forceSetProvider(getUseCaseEdge(useCase), childSurface, useCase.getSessionConfig());
+ }
+ }
+
+ @MainThread
+ @Override
+ public void onUseCaseInactive(@NonNull UseCase useCase) {
+ checkMainThread();
+ if (!isUseCaseActive(useCase)) {
+ return;
+ }
+ mChildrenActiveState.put(useCase, false);
+ getUseCaseEdge(useCase).disconnect();
+ }
+
+ @MainThread
+ @Override
+ public void onUseCaseUpdated(@NonNull UseCase useCase) {
+ checkMainThread();
+ if (!isUseCaseActive(useCase)) {
+ // No-op if the child is inactive. It will connect when it becomes active.
+ return;
+ }
+ SurfaceEdge edge = getUseCaseEdge(useCase);
+ DeferrableSurface childSurface = getChildSurface(useCase);
+ if (childSurface != null) {
+ // If the child has a Surface, connect. VideoCapture uses this mechanism to
+ // resume/start recording.
+ forceSetProvider(edge, childSurface, useCase.getSessionConfig());
+ } else {
+ // If the child has no Surface, disconnect. VideoCapture uses this mechanism to
+ // pause/stop recording.
+ edge.disconnect();
+ }
+ }
+
+ @MainThread
+ @Override
+ public void onUseCaseReset(@NonNull UseCase useCase) {
+ checkMainThread();
+ SurfaceEdge edge = getUseCaseEdge(useCase);
+ edge.invalidate();
+ if (!isUseCaseActive(useCase)) {
+ // No-op if the child is inactive. It will connect when it becomes active.
+ return;
+ }
+ DeferrableSurface childSurface = getChildSurface(useCase);
+ if (childSurface != null) {
+ forceSetProvider(edge, childSurface, useCase.getSessionConfig());
+ }
+ }
+
+ // --- private methods ---
+
+ @IntRange(from = 0, to = 359)
+ private int getChildRotationDegrees(@NonNull UseCase child) {
+ int childTargetRotation = ((ImageOutputConfig) child.getCurrentConfig())
+ .getTargetRotation(Surface.ROTATION_0);
+ return mParentCamera.getCameraInfo().getSensorRotationDegrees(
+ childTargetRotation);
+ }
+
+ private static int getChildFormat(@NonNull UseCase useCase) {
+ return useCase instanceof ImageCapture ? ImageFormat.JPEG
+ : INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE;
+ }
+
+ @CameraEffect.Targets
+ private static int getChildTargetType(@NonNull UseCase useCase) {
+ if (useCase instanceof Preview) {
+ return PREVIEW;
+ } else if (useCase instanceof ImageCapture) {
+ return IMAGE_CAPTURE;
+ } else {
+ return VIDEO_CAPTURE;
+ }
+ }
+
+ private static int getHighestSurfacePriority(Set<UseCaseConfig<?>> childrenConfigs) {
+ int highestPriority = 0;
+ for (UseCaseConfig<?> childConfig : childrenConfigs) {
+ highestPriority = Math.max(highestPriority,
+ childConfig.getSurfaceOccupancyPriority(0));
+ }
+ return highestPriority;
+ }
+
+ @NonNull
+ private SurfaceEdge getUseCaseEdge(@NonNull UseCase useCase) {
+ return requireNonNull(mChildrenEdges.get(useCase));
+ }
+
+ private boolean isUseCaseActive(@NonNull UseCase useCase) {
+ return requireNonNull(mChildrenActiveState.get(useCase));
+ }
+
+ private static void forceSetProvider(@NonNull SurfaceEdge edge,
+ @NonNull DeferrableSurface childSurface,
+ @NonNull SessionConfig childSessionConfig) {
+ edge.invalidate();
+ try {
+ edge.setProvider(childSurface);
+ } catch (DeferrableSurface.SurfaceClosedException e) {
+ // The Surface is closed by the child. This will happen when e.g. the child is Preview
+ // with SurfaceView implementation.
+ // Invoke the error listener so it will recreate the pipeline.
+ for (SessionConfig.ErrorListener listener : childSessionConfig.getErrorListeners()) {
+ listener.onError(childSessionConfig,
+ SessionConfig.SessionError.SESSION_ERROR_SURFACE_NEEDS_RESET);
+ }
+ }
+ }
+
+ /**
+ * Gets the {@link DeferrableSurface} associated with the child.
+ */
+ @VisibleForTesting
+ @Nullable
+ static DeferrableSurface getChildSurface(@NonNull UseCase child) {
+ // Get repeating Surface for preview & video, regular Surface for image capture.
+ List<DeferrableSurface> surfaces = child instanceof ImageCapture
+ ? child.getSessionConfig().getSurfaces() :
+ child.getSessionConfig().getRepeatingCaptureConfig().getSurfaces();
+ checkState(surfaces.size() <= 1);
+ if (surfaces.size() == 1) {
+ return surfaces.get(0);
+ }
+ return null;
+ }
+
+ CameraCaptureCallback createCameraCaptureCallback() {
+ return new CameraCaptureCallback() {
+ @Override
+ public void onCaptureCompleted(@NonNull CameraCaptureResult cameraCaptureResult) {
+ super.onCaptureCompleted(cameraCaptureResult);
+ for (UseCase child : mChildren) {
+ sendCameraCaptureResultToChild(cameraCaptureResult,
+ child.getSessionConfig());
+ }
+ }
+ };
+ }
+
+ static void sendCameraCaptureResultToChild(
+ @NonNull CameraCaptureResult cameraCaptureResult,
+ @NonNull SessionConfig sessionConfig) {
+ for (CameraCaptureCallback callback :
+ sessionConfig.getRepeatingCameraCaptureCallbacks()) {
+ callback.onCaptureCompleted(new VirtualCameraCaptureResult(
+ sessionConfig.getRepeatingCaptureConfig().getTagBundle(),
+ cameraCaptureResult));
+ }
+ }
+}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/VirtualCameraInfo.java b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/VirtualCameraInfo.java
index cdd2e3e..88d96ad 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/VirtualCameraInfo.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/VirtualCameraInfo.java
@@ -16,12 +16,15 @@
package androidx.camera.core.streamsharing;
+import static androidx.camera.core.impl.utils.TransformUtils.within360;
+
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.camera.core.impl.CameraInfoInternal;
import androidx.camera.core.impl.ForwardingCameraInfo;
+import androidx.camera.core.impl.ImageOutputConfig;
import java.util.UUID;
@@ -32,6 +35,7 @@
public class VirtualCameraInfo extends ForwardingCameraInfo {
private final String mVirtualCameraId;
+ private int mVirtualCameraRotationDegrees;
VirtualCameraInfo(@NonNull CameraInfoInternal cameraInfoInternal) {
super(cameraInfoInternal);
@@ -48,4 +52,19 @@
public String getCameraId() {
return mVirtualCameraId;
}
+
+ /**
+ * Sets the rotation applied by this virtual camera.
+ */
+ void setVirtualCameraRotationDegrees(int virtualCameraRotationDegrees) {
+ mVirtualCameraRotationDegrees = virtualCameraRotationDegrees;
+ }
+
+ @Override
+ public int getSensorRotationDegrees(@ImageOutputConfig.RotationValue int relativeRotation) {
+ // The child UseCase calls this method to get the remaining rotation degrees, which is the
+ // original rotation minus the rotation applied by the virtual camera.
+ return within360(
+ super.getSensorRotationDegrees(relativeRotation) - mVirtualCameraRotationDegrees);
+ }
}
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/PreviewTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/PreviewTest.kt
index 4d2bc37..ab1c29f 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/PreviewTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/PreviewTest.kt
@@ -505,19 +505,6 @@
}
@Test
- fun noCameraTransform_rotationDegreesIsZero() {
- // Act: create preview with hasCameraTransform == false
- frontCamera.hasTransform = false
- val preview = createPreview(
- effect,
- frontCamera,
- targetRotation = ROTATION_90
- )
- // Assert: rotationDegrees is 0.
- assertThat(preview.cameraEdge.rotationDegrees).isEqualTo(0)
- }
-
- @Test
fun setNoCameraTransform_propagatesToCameraEdge() {
// Act: create preview with hasCameraTransform == false
frontCamera.hasTransform = false
@@ -787,6 +774,21 @@
assertThat(preview.isPreviewStabilizationEnabled).isTrue()
}
+ @Test
+ fun canSetDynamicRange() {
+ // Use an unspecified dynamic range that isn't the default, UNSPECIFIED.
+ val preview = Preview.Builder().setDynamicRange(DynamicRange.HDR_UNSPECIFIED_10_BIT).build()
+
+ assertThat(preview.dynamicRange).isEqualTo(DynamicRange.HDR_UNSPECIFIED_10_BIT)
+ }
+
+ @Test
+ fun defaultDynamicRange_isUnspecified() {
+ val preview = Preview.Builder().build()
+
+ assertThat(preview.dynamicRange).isEqualTo(DynamicRange.UNSPECIFIED)
+ }
+
private fun bindToLifecycleAndGetSurfaceRequest(): SurfaceRequest {
return bindToLifecycleAndGetResult(null).first
}
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/StreamSharingTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/StreamSharingTest.kt
index e36141d..00cadd4 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/StreamSharingTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/StreamSharingTest.kt
@@ -136,10 +136,42 @@
streamSharing.unbindFromCamera(streamSharing.camera!!)
}
effectProcessor.release()
+ sharingProcessor.cleanUp()
+ effectProcessor.cleanUp()
shadowOf(getMainLooper()).idle()
}
@Test
+ fun effectHandleRotation_remainingRotationIs0() {
+ // Arrange: create an effect that handles rotation.
+ effect = FakeSurfaceEffect(
+ PREVIEW or VIDEO_CAPTURE,
+ CameraEffect.TRANSFORMATION_CAMERA_AND_SURFACE_ROTATION,
+ effectProcessor
+ )
+ streamSharing = StreamSharing(camera, setOf(child1), useCaseConfigFactory)
+ streamSharing.effect = effect
+ // Act: Bind effect and get sharing input edge.
+ streamSharing.bindToCamera(frontCamera, null, defaultConfig)
+ streamSharing.onSuggestedStreamSpecUpdated(StreamSpec.builder(size).build())
+ // Assert: no remaining rotation because it's handled by the effect.
+ assertThat(streamSharing.sharingInputEdge!!.rotationDegrees).isEqualTo(0)
+ }
+
+ @Test
+ fun effectDoNotHandleRotation_remainingRotationIsNot0() {
+ // Arrange: create an effect that does not handle rotation.
+ streamSharing = StreamSharing(camera, setOf(child1), useCaseConfigFactory)
+ streamSharing.effect = effect
+ // Act: bind effect.
+ streamSharing.bindToCamera(frontCamera, null, defaultConfig)
+ streamSharing.onSuggestedStreamSpecUpdated(StreamSpec.builder(size).build())
+ // Assert: the remaining rotation still exists because the effect doesn't handle it. It will
+ // be handled by downstream pipeline.
+ assertThat(streamSharing.sharingInputEdge!!.rotationDegrees).isEqualTo(SENSOR_ROTATION)
+ }
+
+ @Test
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
fun invokeParentSessionCaptureCallbacks_receivedByChildren() {
// Arrange.
@@ -220,12 +252,12 @@
fun childTakingPicture_getJpegQuality() {
// Arrange: set up StreamSharing with min latency ImageCapture as child
val imageCapture = ImageCapture.Builder()
- .setTargetRotation(Surface.ROTATION_90)
.setCaptureMode(CAPTURE_MODE_MINIMIZE_LATENCY)
.build()
streamSharing = StreamSharing(camera, setOf(child1, imageCapture), useCaseConfigFactory)
streamSharing.bindToCamera(camera, null, defaultConfig)
streamSharing.onSuggestedStreamSpecUpdated(StreamSpec.builder(size).build())
+ imageCapture.targetRotation = Surface.ROTATION_90
// Act: the child takes a picture.
imageCapture.takePicture(directExecutor(), object : ImageCapture.OnImageCapturedCallback() {
@@ -500,12 +532,12 @@
assertThat(child2.pipelineCreationCount).isEqualTo(2)
shadowOf(getMainLooper()).idle()
// Assert: child Surface are propagated to StreamSharing.
- val child1Surface =
- streamSharing.virtualCamera.mChildrenEdges[child1]!!.deferrableSurfaceForTesting.surface
+ val child1Surface = streamSharing.virtualCameraAdapter.mChildrenEdges[child1]!!
+ .deferrableSurfaceForTesting.surface
assertThat(child1Surface.isDone).isTrue()
assertThat(child1Surface.get()).isEqualTo(surface1)
- val child2Surface =
- streamSharing.virtualCamera.mChildrenEdges[child2]!!.deferrableSurfaceForTesting.surface
+ val child2Surface = streamSharing.virtualCameraAdapter.mChildrenEdges[child2]!!
+ .deferrableSurfaceForTesting.surface
assertThat(child2Surface.isDone).isTrue()
assertThat(child2Surface.get()).isEqualTo(surface2)
@@ -526,6 +558,17 @@
}
@Test
+ fun bindChildToCamera_virtualCameraHasNoRotationDegrees() {
+ // Act.
+ streamSharing.bindToCamera(frontCamera, null, null)
+ // Assert.
+ assertThat(child1.camera!!.cameraInfoInternal.getSensorRotationDegrees(Surface.ROTATION_0))
+ .isEqualTo(0)
+ assertThat(child2.camera!!.cameraInfoInternal.getSensorRotationDegrees(Surface.ROTATION_0))
+ .isEqualTo(0)
+ }
+
+ @Test
fun bindAndUnbindParent_propagatesToChildren() {
// Assert: children not bound to camera by default.
assertThat(child1.camera).isNull()
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/VirtualCameraAdapterTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/VirtualCameraAdapterTest.kt
new file mode 100644
index 0000000..9c85fe8
--- /dev/null
+++ b/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/VirtualCameraAdapterTest.kt
@@ -0,0 +1,334 @@
+/*
+ * Copyright 2023 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.camera.core.streamsharing
+
+import android.graphics.ImageFormat
+import android.graphics.Matrix
+import android.graphics.Rect
+import android.graphics.SurfaceTexture
+import android.os.Build
+import android.os.Looper.getMainLooper
+import android.util.Size
+import android.view.Surface
+import androidx.camera.core.CameraEffect.IMAGE_CAPTURE
+import androidx.camera.core.CameraEffect.PREVIEW
+import androidx.camera.core.CameraEffect.VIDEO_CAPTURE
+import androidx.camera.core.ImageCapture
+import androidx.camera.core.ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY
+import androidx.camera.core.ImageCapture.FLASH_MODE_AUTO
+import androidx.camera.core.MirrorMode.MIRROR_MODE_ON
+import androidx.camera.core.Preview
+import androidx.camera.core.UseCase
+import androidx.camera.core.impl.CameraControlInternal
+import androidx.camera.core.impl.CaptureConfig
+import androidx.camera.core.impl.DeferrableSurface
+import androidx.camera.core.impl.ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE
+import androidx.camera.core.impl.ImageOutputConfig.ROTATION_NOT_SPECIFIED
+import androidx.camera.core.impl.SessionConfig
+import androidx.camera.core.impl.SessionConfig.defaultEmptySessionConfig
+import androidx.camera.core.impl.StreamSpec
+import androidx.camera.core.impl.utils.executor.CameraXExecutors.directExecutor
+import androidx.camera.core.impl.utils.futures.Futures
+import androidx.camera.core.processing.SurfaceEdge
+import androidx.camera.testing.fakes.FakeCamera
+import androidx.camera.testing.impl.fakes.FakeDeferrableSurface
+import androidx.camera.testing.impl.fakes.FakeUseCaseConfig
+import androidx.camera.testing.impl.fakes.FakeUseCaseConfigFactory
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.Shadows.shadowOf
+import org.robolectric.annotation.Config
+import org.robolectric.annotation.internal.DoNotInstrument
+
+/**
+ * Unit tests for [VirtualCameraAdapter].
+ */
+@RunWith(RobolectricTestRunner::class)
+@DoNotInstrument
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
+class VirtualCameraAdapterTest {
+
+ companion object {
+ private const val CLOSED = true
+ private const val OPEN = false
+ private const val HAS_PROVIDER = true
+ private const val NO_PROVIDER = false
+ private val INPUT_SIZE = Size(800, 600)
+ private val CROP_RECT = Rect(0, 0, 800, 600)
+
+ // Arbitrary transform to test that the transform is propagated.
+ private val SENSOR_TO_BUFFER = Matrix().apply { setScale(1f, -1f) }
+ private var receivedSessionConfigError: SessionConfig.SessionError? = null
+ private val SESSION_CONFIG_WITH_SURFACE = SessionConfig.Builder()
+ .addSurface(FakeDeferrableSurface(INPUT_SIZE, ImageFormat.PRIVATE))
+ .addErrorListener { _, error ->
+ receivedSessionConfigError = error
+ }.build()
+ }
+
+ private val surfaceEdgesToClose = mutableListOf<SurfaceEdge>()
+ private val parentCamera = FakeCamera()
+ private val child1 = FakeUseCaseConfig.Builder().setTargetRotation(Surface.ROTATION_0).build()
+ private val child2 = FakeUseCaseConfig.Builder()
+ .setMirrorMode(MIRROR_MODE_ON)
+ .build()
+ private val childrenEdges = mapOf(
+ Pair(child1 as UseCase, createSurfaceEdge()),
+ Pair(child2 as UseCase, createSurfaceEdge())
+ )
+ private val useCaseConfigFactory = FakeUseCaseConfigFactory()
+ private lateinit var adapter: VirtualCameraAdapter
+ private var snapshotTriggered = false
+
+ @Before
+ fun setUp() {
+ adapter = VirtualCameraAdapter(
+ parentCamera, setOf(child1, child2), useCaseConfigFactory
+ ) { _, _ ->
+ snapshotTriggered = true
+ Futures.immediateFuture(null)
+ }
+ }
+
+ @After
+ fun tearDown() {
+ for (surfaceEdge in surfaceEdgesToClose) {
+ surfaceEdge.close()
+ }
+ }
+
+ @Test
+ fun submitStillCaptureRequests_triggersSnapshot() {
+ // Arrange.
+ adapter.bindChildren()
+
+ // Act: submit a still capture request from a child.
+ val cameraControl = child1.camera!!.cameraControl as CameraControlInternal
+ cameraControl.submitStillCaptureRequests(
+ listOf(CaptureConfig.Builder().build()),
+ CAPTURE_MODE_MINIMIZE_LATENCY,
+ FLASH_MODE_AUTO
+ )
+ shadowOf(getMainLooper()).idle()
+
+ // The StreamSharing.Control is called to take a snapshot.
+ assertThat(snapshotTriggered).isTrue()
+ }
+
+ @Test
+ fun getImageCaptureSurface_returnsNonRepeatingSurface() {
+ assertThat(getUseCaseSurface(ImageCapture.Builder().build())).isNotNull()
+ }
+
+ @Test
+ fun getChildSurface_returnsRepeatingSurface() {
+ // Arrange.
+ val surfaceTexture = SurfaceTexture(0)
+ val surface = Surface(surfaceTexture)
+ val preview = Preview.Builder().build().apply {
+ this.setSurfaceProvider {
+ it.provideSurface(surface, directExecutor()) {
+ surfaceTexture.release()
+ surface.release()
+ }
+ }
+ }
+ // Act & Assert.
+ assertThat(getUseCaseSurface(preview)).isNotNull()
+ // Cleanup.
+ preview.unbindFromCamera(parentCamera)
+ surfaceTexture.release()
+ surface.release()
+ }
+
+ private fun getUseCaseSurface(useCase: UseCase): DeferrableSurface? {
+ useCase.bindToCamera(
+ parentCamera,
+ null,
+ useCase.getDefaultConfig(true, useCaseConfigFactory)
+ )
+ useCase.updateSuggestedStreamSpec(StreamSpec.builder(INPUT_SIZE).build())
+ return VirtualCameraAdapter.getChildSurface(useCase)
+ }
+
+ @Test
+ fun setUseCaseActiveAndInactive_surfaceConnectsAndDisconnects() {
+ // Arrange.
+ adapter.bindChildren()
+ adapter.setChildrenEdges(childrenEdges)
+ child1.updateSessionConfigForTesting(SESSION_CONFIG_WITH_SURFACE)
+ // Assert: edge open by default.
+ verifyEdge(child1, OPEN, NO_PROVIDER)
+ // Set UseCase to active, verify it has provider.
+ child1.notifyActiveForTesting()
+ verifyEdge(child1, OPEN, HAS_PROVIDER)
+ // Set UseCase to inactive, verify it's closed.
+ child1.notifyInactiveForTesting()
+ verifyEdge(child1, CLOSED, HAS_PROVIDER)
+ // Set UseCase to active, verify it becomes open again.
+ child1.notifyActiveForTesting()
+ verifyEdge(child1, OPEN, HAS_PROVIDER)
+ }
+
+ @Test
+ fun resetWithClosedChildSurface_invokesErrorListener() {
+ // Arrange.
+ adapter.bindChildren()
+ adapter.setChildrenEdges(childrenEdges)
+ child1.updateSessionConfigForTesting(SESSION_CONFIG_WITH_SURFACE)
+ child1.notifyActiveForTesting()
+
+ // Act: close the child surface.
+ SESSION_CONFIG_WITH_SURFACE.surfaces[0].close()
+ adapter.onUseCaseReset(child1)
+ shadowOf(getMainLooper()).idle()
+
+ // Assert: error listener is invoked.
+ assertThat(receivedSessionConfigError)
+ .isEqualTo(SessionConfig.SessionError.SESSION_ERROR_SURFACE_NEEDS_RESET)
+ }
+
+ @Test
+ fun resetUseCase_edgeInvalidated() {
+ // Arrange: setup and get the old DeferrableSurface.
+ adapter.bindChildren()
+ adapter.setChildrenEdges(childrenEdges)
+ child1.updateSessionConfigForTesting(SESSION_CONFIG_WITH_SURFACE)
+ child1.notifyActiveForTesting()
+ val oldSurface = childrenEdges[child1]!!.deferrableSurfaceForTesting
+ // Act: notify reset.
+ child1.notifyResetForTesting()
+ // Assert: DeferrableSurface is recreated. The old one is closed.
+ assertThat(oldSurface.isClosed).isTrue()
+ assertThat(childrenEdges[child1]!!.deferrableSurfaceForTesting)
+ .isNotSameInstanceAs(oldSurface)
+ verifyEdge(child1, OPEN, HAS_PROVIDER)
+ }
+
+ @Test
+ fun updateUseCaseWithAndWithoutSurface_surfaceConnectsAndDisconnects() {
+ // Arrange
+ adapter.bindChildren()
+ adapter.setChildrenEdges(childrenEdges)
+ child1.notifyActiveForTesting()
+ verifyEdge(child1, OPEN, NO_PROVIDER)
+
+ // Act: set Surface and update
+ child1.updateSessionConfigForTesting(SESSION_CONFIG_WITH_SURFACE)
+ child1.notifyUpdatedForTesting()
+ // Assert: edge is connected.
+ verifyEdge(child1, OPEN, HAS_PROVIDER)
+ // Act: remove Surface and update.
+ child1.updateSessionConfigForTesting(defaultEmptySessionConfig())
+ child1.notifyUpdatedForTesting()
+ // Assert: edge is disconnected.
+ verifyEdge(child1, CLOSED, HAS_PROVIDER)
+ // Act: set Surface and update.
+ child1.updateSessionConfigForTesting(SESSION_CONFIG_WITH_SURFACE)
+ child1.notifyUpdatedForTesting()
+ // Assert: edge is connected again.
+ verifyEdge(child1, OPEN, HAS_PROVIDER)
+ }
+
+ @Test
+ fun getChildrenOutConfigs() {
+ // Arrange.
+ val cropRect = Rect(10, 10, 410, 310)
+ val preview = Preview.Builder().setTargetRotation(Surface.ROTATION_90).build()
+ val imageCapture = ImageCapture.Builder().setTargetRotation(Surface.ROTATION_0).build()
+ adapter = VirtualCameraAdapter(
+ parentCamera, setOf(preview, child2, imageCapture), useCaseConfigFactory
+ ) { _, _ ->
+ Futures.immediateFuture(null)
+ }
+
+ // Act.
+ val outConfigs = adapter.getChildrenOutConfigs(
+ createSurfaceEdge(cropRect = cropRect, rotationDegrees = 90),
+ Surface.ROTATION_90
+ )
+
+ // Assert: preview config
+ val previewOutConfig = outConfigs[preview]!!
+ assertThat(previewOutConfig.format).isEqualTo(INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE)
+ assertThat(previewOutConfig.targets).isEqualTo(PREVIEW)
+ assertThat(previewOutConfig.cropRect).isEqualTo(cropRect)
+ // Preview's target rotation matches the parent's, so it only applies the 90° rotation.
+ assertThat(previewOutConfig.size).isEqualTo(Size(300, 400))
+ assertThat(previewOutConfig.rotationDegrees).isEqualTo(90)
+ assertThat(previewOutConfig.mirroring).isFalse()
+ // Assert: ImageCapture config
+ val imageOutConfig = outConfigs[imageCapture]!!
+ assertThat(imageOutConfig.format).isEqualTo(ImageFormat.JPEG)
+ assertThat(imageOutConfig.targets).isEqualTo(IMAGE_CAPTURE)
+ // ImageCapture's target rotation does not match the parent's, so it applies the delta on
+ // top of the 90° rotation.
+ assertThat(imageOutConfig.size).isEqualTo(Size(400, 300))
+ assertThat(imageOutConfig.rotationDegrees).isEqualTo(180)
+ // Assert: child2
+ val outConfig2 = outConfigs[child2]!!
+ assertThat(outConfig2.format).isEqualTo(INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE)
+ assertThat(outConfig2.targets).isEqualTo(VIDEO_CAPTURE)
+ assertThat(outConfig2.cropRect).isEqualTo(cropRect)
+ assertThat(outConfig2.mirroring).isTrue()
+ }
+
+ @Test
+ fun updateChildrenSpec_updateAndNotifyChildren() {
+ // Act: update children with the map.
+ adapter.setChildrenEdges(childrenEdges)
+ // Assert: surface size, crop rect and transformation propagated to children
+ assertThat(child1.attachedStreamSpec!!.resolution).isEqualTo(INPUT_SIZE)
+ assertThat(child2.attachedStreamSpec!!.resolution).isEqualTo(INPUT_SIZE)
+ assertThat(child1.viewPortCropRect).isEqualTo(CROP_RECT)
+ assertThat(child2.viewPortCropRect).isEqualTo(CROP_RECT)
+ assertThat(child1.sensorToBufferTransformMatrix).isEqualTo(SENSOR_TO_BUFFER)
+ assertThat(child2.sensorToBufferTransformMatrix).isEqualTo(SENSOR_TO_BUFFER)
+ }
+
+ private fun createSurfaceEdge(
+ target: Int = PREVIEW,
+ format: Int = INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE,
+ streamSpec: StreamSpec = StreamSpec.builder(INPUT_SIZE).build(),
+ matrix: Matrix = SENSOR_TO_BUFFER,
+ hasCameraTransform: Boolean = true,
+ cropRect: Rect = CROP_RECT,
+ rotationDegrees: Int = 0,
+ mirroring: Boolean = false
+ ): SurfaceEdge {
+ return SurfaceEdge(
+ target,
+ format,
+ streamSpec,
+ matrix,
+ hasCameraTransform,
+ cropRect,
+ rotationDegrees,
+ ROTATION_NOT_SPECIFIED,
+ mirroring
+ ).also { surfaceEdgesToClose.add(it) }
+ }
+
+ private fun verifyEdge(child: UseCase, isClosed: Boolean, hasProvider: Boolean) {
+ assertThat(childrenEdges[child]!!.deferrableSurfaceForTesting.isClosed).isEqualTo(isClosed)
+ assertThat(childrenEdges[child]!!.hasProvider()).isEqualTo(hasProvider)
+ }
+}
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/VirtualCameraTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/VirtualCameraTest.kt
index 4681fbb..65446d4 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/VirtualCameraTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/VirtualCameraTest.kt
@@ -16,45 +16,17 @@
package androidx.camera.core.streamsharing
-import android.graphics.ImageFormat
-import android.graphics.Matrix
-import android.graphics.Rect
-import android.graphics.SurfaceTexture
import android.os.Build
-import android.os.Looper.getMainLooper
-import android.util.Size
import android.view.Surface
-import androidx.camera.core.CameraEffect.IMAGE_CAPTURE
-import androidx.camera.core.CameraEffect.PREVIEW
-import androidx.camera.core.CameraEffect.VIDEO_CAPTURE
-import androidx.camera.core.ImageCapture
-import androidx.camera.core.ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY
-import androidx.camera.core.ImageCapture.FLASH_MODE_AUTO
-import androidx.camera.core.MirrorMode.MIRROR_MODE_ON
-import androidx.camera.core.Preview
+import androidx.camera.core.CameraSelector
import androidx.camera.core.UseCase
-import androidx.camera.core.impl.CameraControlInternal
-import androidx.camera.core.impl.CaptureConfig
-import androidx.camera.core.impl.DeferrableSurface
-import androidx.camera.core.impl.ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE
-import androidx.camera.core.impl.ImageOutputConfig.ROTATION_NOT_SPECIFIED
-import androidx.camera.core.impl.SessionConfig
-import androidx.camera.core.impl.SessionConfig.defaultEmptySessionConfig
-import androidx.camera.core.impl.StreamSpec
-import androidx.camera.core.impl.utils.executor.CameraXExecutors.directExecutor
import androidx.camera.core.impl.utils.futures.Futures
-import androidx.camera.core.processing.SurfaceEdge
import androidx.camera.testing.fakes.FakeCamera
-import androidx.camera.testing.impl.fakes.FakeDeferrableSurface
-import androidx.camera.testing.impl.fakes.FakeUseCaseConfig
-import androidx.camera.testing.impl.fakes.FakeUseCaseConfigFactory
+import androidx.camera.testing.fakes.FakeCameraInfoInternal
import com.google.common.truth.Truth.assertThat
-import org.junit.After
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
-import org.robolectric.Shadows.shadowOf
import org.robolectric.annotation.Config
import org.robolectric.annotation.internal.DoNotInstrument
@@ -66,55 +38,32 @@
@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
class VirtualCameraTest {
- companion object {
- private const val CLOSED = true
- private const val OPEN = false
- private const val HAS_PROVIDER = true
- private const val NO_PROVIDER = false
- private val INPUT_SIZE = Size(800, 600)
- private val CROP_RECT = Rect(0, 0, 800, 600)
+ private val cameraInfo = FakeCameraInfoInternal(90, CameraSelector.LENS_FACING_BACK)
- // Arbitrary transform to test that the transform is propagated.
- private val SENSOR_TO_BUFFER = Matrix().apply { setScale(1f, -1f) }
- private var receivedSessionConfigError: SessionConfig.SessionError? = null
- private val SESSION_CONFIG_WITH_SURFACE = SessionConfig.Builder()
- .addSurface(FakeDeferrableSurface(INPUT_SIZE, ImageFormat.PRIVATE))
- .addErrorListener { _, error ->
- receivedSessionConfigError = error
- }.build()
- }
+ private val parentCamera = FakeCamera(null, cameraInfo)
- private val surfaceEdgesToClose = mutableListOf<SurfaceEdge>()
- private val parentCamera = FakeCamera()
- private val child1 = FakeUseCaseConfig.Builder().setTargetRotation(Surface.ROTATION_0).build()
- private val child2 = FakeUseCaseConfig.Builder()
- .setMirrorMode(MIRROR_MODE_ON)
- .build()
- private val childrenEdges = mapOf(
- Pair(child1 as UseCase, createSurfaceEdge()),
- Pair(child2 as UseCase, createSurfaceEdge())
- )
- private val useCaseConfigFactory = FakeUseCaseConfigFactory()
- private lateinit var virtualCamera: VirtualCamera
- private var snapshotTriggered = false
+ private val useCaseStateCallback = object : UseCase.StateChangeCallback {
- @Before
- fun setUp() {
- virtualCamera = VirtualCamera(
- parentCamera, setOf(child1, child2), useCaseConfigFactory
- ) { _, _ ->
- snapshotTriggered = true
- Futures.immediateFuture(null)
+ override fun onUseCaseActive(useCase: UseCase) {
+ }
+
+ override fun onUseCaseInactive(useCase: UseCase) {
+ }
+
+ override fun onUseCaseUpdated(useCase: UseCase) {
+ }
+
+ override fun onUseCaseReset(useCase: UseCase) {
}
}
- @After
- fun tearDown() {
- for (surfaceEdge in surfaceEdgesToClose) {
- surfaceEdge.close()
- }
+ private val streamSharingControl = StreamSharing.Control { _, _ ->
+ Futures.immediateFuture(null)
}
+ private val virtualCamera =
+ VirtualCamera(parentCamera, useCaseStateCallback, streamSharingControl)
+
@Test
fun getCameraId_returnsVirtualCameraId() {
assertThat(virtualCamera.cameraInfoInternal.cameraId)
@@ -122,219 +71,16 @@
}
@Test
- fun submitStillCaptureRequests_triggersSnapshot() {
- // Arrange.
- virtualCamera.bindChildren()
-
- // Act: submit a still capture request from a child.
- val cameraControl = child1.camera!!.cameraControl as CameraControlInternal
- cameraControl.submitStillCaptureRequests(
- listOf(CaptureConfig.Builder().build()),
- CAPTURE_MODE_MINIMIZE_LATENCY,
- FLASH_MODE_AUTO
- )
- shadowOf(getMainLooper()).idle()
-
- // The StreamSharing.Control is called to take a snapshot.
- assertThat(snapshotTriggered).isTrue()
- }
-
- @Test
- fun getImageCaptureSurface_returnsNonRepeatingSurface() {
- assertThat(getUseCaseSurface(ImageCapture.Builder().build())).isNotNull()
- }
-
- @Test
- fun getChildSurface_returnsRepeatingSurface() {
- // Arrange.
- val surfaceTexture = SurfaceTexture(0)
- val surface = Surface(surfaceTexture)
- val preview = Preview.Builder().build().apply {
- this.setSurfaceProvider {
- it.provideSurface(surface, directExecutor()) {
- surfaceTexture.release()
- surface.release()
- }
- }
- }
- // Act & Assert.
- assertThat(getUseCaseSurface(preview)).isNotNull()
- // Cleanup.
- preview.unbindFromCamera(parentCamera)
- }
-
- private fun getUseCaseSurface(useCase: UseCase): DeferrableSurface? {
- useCase.bindToCamera(
- parentCamera,
- null,
- useCase.getDefaultConfig(true, useCaseConfigFactory)
- )
- useCase.updateSuggestedStreamSpec(StreamSpec.builder(INPUT_SIZE).build())
- return VirtualCamera.getChildSurface(useCase)
- }
-
- @Test
- fun setUseCaseActiveAndInactive_surfaceConnectsAndDisconnects() {
- // Arrange.
- virtualCamera.bindChildren()
- virtualCamera.setChildrenEdges(childrenEdges)
- child1.updateSessionConfigForTesting(SESSION_CONFIG_WITH_SURFACE)
- // Assert: edge open by default.
- verifyEdge(child1, OPEN, NO_PROVIDER)
- // Set UseCase to active, verify it has provider.
- child1.notifyActiveForTesting()
- verifyEdge(child1, OPEN, HAS_PROVIDER)
- // Set UseCase to inactive, verify it's closed.
- child1.notifyInactiveForTesting()
- verifyEdge(child1, CLOSED, HAS_PROVIDER)
- // Set UseCase to active, verify it becomes open again.
- child1.notifyActiveForTesting()
- verifyEdge(child1, OPEN, HAS_PROVIDER)
- }
-
- @Test
- fun resetWithClosedChildSurface_invokesErrorListener() {
- // Arrange.
- virtualCamera.bindChildren()
- virtualCamera.setChildrenEdges(childrenEdges)
- child1.updateSessionConfigForTesting(SESSION_CONFIG_WITH_SURFACE)
- child1.notifyActiveForTesting()
-
- // Act: close the child surface.
- SESSION_CONFIG_WITH_SURFACE.surfaces[0].close()
- virtualCamera.onUseCaseReset(child1)
- shadowOf(getMainLooper()).idle()
-
- // Assert: error listener is invoked.
- assertThat(receivedSessionConfigError)
- .isEqualTo(SessionConfig.SessionError.SESSION_ERROR_SURFACE_NEEDS_RESET)
- }
-
- @Test
- fun resetUseCase_edgeInvalidated() {
- // Arrange: setup and get the old DeferrableSurface.
- virtualCamera.bindChildren()
- virtualCamera.setChildrenEdges(childrenEdges)
- child1.updateSessionConfigForTesting(SESSION_CONFIG_WITH_SURFACE)
- child1.notifyActiveForTesting()
- val oldSurface = childrenEdges[child1]!!.deferrableSurfaceForTesting
- // Act: notify reset.
- child1.notifyResetForTesting()
- // Assert: DeferrableSurface is recreated. The old one is closed.
- assertThat(oldSurface.isClosed).isTrue()
- assertThat(childrenEdges[child1]!!.deferrableSurfaceForTesting)
- .isNotSameInstanceAs(oldSurface)
- verifyEdge(child1, OPEN, HAS_PROVIDER)
- }
-
- @Test
- fun updateUseCaseWithAndWithoutSurface_surfaceConnectsAndDisconnects() {
- // Arrange
- virtualCamera.bindChildren()
- virtualCamera.setChildrenEdges(childrenEdges)
- child1.notifyActiveForTesting()
- verifyEdge(child1, OPEN, NO_PROVIDER)
-
- // Act: set Surface and update
- child1.updateSessionConfigForTesting(SESSION_CONFIG_WITH_SURFACE)
- child1.notifyUpdatedForTesting()
- // Assert: edge is connected.
- verifyEdge(child1, OPEN, HAS_PROVIDER)
- // Act: remove Surface and update.
- child1.updateSessionConfigForTesting(defaultEmptySessionConfig())
- child1.notifyUpdatedForTesting()
- // Assert: edge is disconnected.
- verifyEdge(child1, CLOSED, HAS_PROVIDER)
- // Act: set Surface and update.
- child1.updateSessionConfigForTesting(SESSION_CONFIG_WITH_SURFACE)
- child1.notifyUpdatedForTesting()
- // Assert: edge is connected again.
- verifyEdge(child1, OPEN, HAS_PROVIDER)
- }
-
- @Test
- fun virtualCameraInheritsParentProperties() {
+ fun getCameraState_returnsParentState() {
assertThat(virtualCamera.cameraState).isEqualTo(parentCamera.cameraState)
- assertThat(virtualCamera.cameraInfoInternal.implementation)
- .isEqualTo(virtualCamera.cameraInfoInternal.implementation)
}
@Test
- fun getChildrenOutConfigs() {
- // Arrange.
- val cropRect = Rect(10, 10, 410, 310)
- val preview = Preview.Builder().setTargetRotation(Surface.ROTATION_90).build()
- val imageCapture = ImageCapture.Builder().build()
- virtualCamera = VirtualCamera(
- parentCamera, setOf(preview, child2, imageCapture), useCaseConfigFactory
- ) { _, _ ->
- Futures.immediateFuture(null)
- }
-
- // Act.
- val outConfigs = virtualCamera.getChildrenOutConfigs(
- createSurfaceEdge(cropRect = cropRect)
- )
-
- // Assert: preview config
- val previewOutConfig = outConfigs[preview]!!
- assertThat(previewOutConfig.format).isEqualTo(INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE)
- assertThat(previewOutConfig.targets).isEqualTo(PREVIEW)
- assertThat(previewOutConfig.cropRect).isEqualTo(cropRect)
- assertThat(previewOutConfig.size).isEqualTo(Size(300, 400))
- assertThat(previewOutConfig.rotationDegrees).isEqualTo(270)
- assertThat(previewOutConfig.mirroring).isFalse()
- // Assert: ImageCapture config
- val imageOutConfig = outConfigs[imageCapture]!!
- assertThat(imageOutConfig.format).isEqualTo(ImageFormat.JPEG)
- assertThat(imageOutConfig.targets).isEqualTo(IMAGE_CAPTURE)
- // Assert: child2
- val outConfig2 = outConfigs[child2]!!
- assertThat(outConfig2.format).isEqualTo(INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE)
- assertThat(outConfig2.targets).isEqualTo(VIDEO_CAPTURE)
- assertThat(outConfig2.cropRect).isEqualTo(cropRect)
- assertThat(outConfig2.size).isEqualTo(Size(400, 300))
- assertThat(outConfig2.mirroring).isTrue()
- }
-
- @Test
- fun updateChildrenSpec_updateAndNotifyChildren() {
- // Act: update children with the map.
- virtualCamera.setChildrenEdges(childrenEdges)
- // Assert: surface size, crop rect and transformation propagated to children
- assertThat(child1.attachedStreamSpec!!.resolution).isEqualTo(INPUT_SIZE)
- assertThat(child2.attachedStreamSpec!!.resolution).isEqualTo(INPUT_SIZE)
- assertThat(child1.viewPortCropRect).isEqualTo(CROP_RECT)
- assertThat(child2.viewPortCropRect).isEqualTo(CROP_RECT)
- assertThat(child1.sensorToBufferTransformMatrix).isEqualTo(SENSOR_TO_BUFFER)
- assertThat(child2.sensorToBufferTransformMatrix).isEqualTo(SENSOR_TO_BUFFER)
- }
-
- private fun createSurfaceEdge(
- target: Int = PREVIEW,
- format: Int = INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE,
- streamSpec: StreamSpec = StreamSpec.builder(INPUT_SIZE).build(),
- matrix: Matrix = SENSOR_TO_BUFFER,
- hasCameraTransform: Boolean = true,
- cropRect: Rect = CROP_RECT,
- rotationDegrees: Int = 0,
- mirroring: Boolean = false
- ): SurfaceEdge {
- return SurfaceEdge(
- target,
- format,
- streamSpec,
- matrix,
- hasCameraTransform,
- cropRect,
- rotationDegrees,
- ROTATION_NOT_SPECIFIED,
- mirroring
- ).also { surfaceEdgesToClose.add(it) }
- }
-
- private fun verifyEdge(child: UseCase, isClosed: Boolean, hasProvider: Boolean) {
- assertThat(childrenEdges[child]!!.deferrableSurfaceForTesting.isClosed).isEqualTo(isClosed)
- assertThat(childrenEdges[child]!!.hasProvider()).isEqualTo(hasProvider)
+ fun setRotationDegrees_offsetsParentRotationDegrees() {
+ assertThat(parentCamera.cameraInfoInternal.getSensorRotationDegrees(Surface.ROTATION_0))
+ .isEqualTo(90)
+ virtualCamera.setRotationDegrees(180)
+ assertThat(virtualCamera.cameraInfoInternal.getSensorRotationDegrees(Surface.ROTATION_0))
+ .isEqualTo(270)
}
}
diff --git a/camera/camera-effects/api/current.txt b/camera/camera-effects/api/current.txt
index e6f50d0..0fa6f1a 100644
--- a/camera/camera-effects/api/current.txt
+++ b/camera/camera-effects/api/current.txt
@@ -1 +1,30 @@
// Signature format: 4.0
+package androidx.camera.effects {
+
+ @RequiresApi(21) @com.google.auto.value.AutoValue public abstract class Frame {
+ ctor public Frame();
+ method public abstract android.graphics.Rect getCropRect();
+ method public abstract boolean getMirroring();
+ method public android.graphics.Canvas getOverlayCanvas();
+ method public abstract int getRotationDegrees();
+ method public abstract android.graphics.Matrix getSensorToBufferTransform();
+ method public abstract android.util.Size getSize();
+ method public abstract long getTimestampNanos();
+ }
+
+ @RequiresApi(21) public class OverlayEffect extends androidx.camera.core.CameraEffect implements java.lang.AutoCloseable {
+ ctor public OverlayEffect(int, int, android.os.Handler, androidx.core.util.Consumer<java.lang.Throwable!>);
+ method public void clearOnDrawListener();
+ method public void close();
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Integer!> drawFrameAsync(long);
+ method public android.os.Handler getHandler();
+ method public int getQueueDepth();
+ method public void setOnDrawListener(androidx.arch.core.util.Function<androidx.camera.effects.Frame!,java.lang.Boolean!>);
+ field public static final int RESULT_CANCELLED_BY_CALLER = 4; // 0x4
+ field public static final int RESULT_FRAME_NOT_FOUND = 2; // 0x2
+ field public static final int RESULT_INVALID_SURFACE = 3; // 0x3
+ field public static final int RESULT_SUCCESS = 1; // 0x1
+ }
+
+}
+
diff --git a/camera/camera-effects/api/restricted_current.txt b/camera/camera-effects/api/restricted_current.txt
index e6f50d0..0fa6f1a 100644
--- a/camera/camera-effects/api/restricted_current.txt
+++ b/camera/camera-effects/api/restricted_current.txt
@@ -1 +1,30 @@
// Signature format: 4.0
+package androidx.camera.effects {
+
+ @RequiresApi(21) @com.google.auto.value.AutoValue public abstract class Frame {
+ ctor public Frame();
+ method public abstract android.graphics.Rect getCropRect();
+ method public abstract boolean getMirroring();
+ method public android.graphics.Canvas getOverlayCanvas();
+ method public abstract int getRotationDegrees();
+ method public abstract android.graphics.Matrix getSensorToBufferTransform();
+ method public abstract android.util.Size getSize();
+ method public abstract long getTimestampNanos();
+ }
+
+ @RequiresApi(21) public class OverlayEffect extends androidx.camera.core.CameraEffect implements java.lang.AutoCloseable {
+ ctor public OverlayEffect(int, int, android.os.Handler, androidx.core.util.Consumer<java.lang.Throwable!>);
+ method public void clearOnDrawListener();
+ method public void close();
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Integer!> drawFrameAsync(long);
+ method public android.os.Handler getHandler();
+ method public int getQueueDepth();
+ method public void setOnDrawListener(androidx.arch.core.util.Function<androidx.camera.effects.Frame!,java.lang.Boolean!>);
+ field public static final int RESULT_CANCELLED_BY_CALLER = 4; // 0x4
+ field public static final int RESULT_FRAME_NOT_FOUND = 2; // 0x2
+ field public static final int RESULT_INVALID_SURFACE = 3; // 0x3
+ field public static final int RESULT_SUCCESS = 1; // 0x1
+ }
+
+}
+
diff --git a/camera/camera-effects/build.gradle b/camera/camera-effects/build.gradle
index cedb467..a806e1a 100644
--- a/camera/camera-effects/build.gradle
+++ b/camera/camera-effects/build.gradle
@@ -58,11 +58,10 @@
}
androidx {
name = "Camera Effects"
- publish = Publish.NONE
- inceptionYear = "2022"
+ publish = Publish.SNAPSHOT_AND_RELEASE
+ inceptionYear = "2023"
runApiTasks = new RunApiTasks.Yes()
description = "Camera effects components for the Jetpack Camera Library, a library providing " +
- "camera post-processing features such as portrait mode that can be used with the " +
- "CameraX library."
+ "camera post-processing features such as drawing overlay with the CameraX library."
metalavaK2UastEnabled = true
}
diff --git a/camera/camera-effects/src/androidTest/java/androidx/camera/effects/internal/SurfaceProcessorImplDeviceTest.kt b/camera/camera-effects/src/androidTest/java/androidx/camera/effects/internal/SurfaceProcessorImplDeviceTest.kt
index 8378175..2eca7e1 100644
--- a/camera/camera-effects/src/androidTest/java/androidx/camera/effects/internal/SurfaceProcessorImplDeviceTest.kt
+++ b/camera/camera-effects/src/androidTest/java/androidx/camera/effects/internal/SurfaceProcessorImplDeviceTest.kt
@@ -242,7 +242,7 @@
val cachedFrame = processor.buffer.frames.single()
// Act: draw the cached frame.
- val drawFuture = processor.drawFrame(cachedFrame.timestampNs)
+ val drawFuture = processor.drawFrameAsync(cachedFrame.timestampNanos)
// Assert: the future completes with RESULT_SUCCESS and the output receives the frame.
assertThat(drawFuture.get()).isEqualTo(OverlayEffect.RESULT_SUCCESS)
@@ -256,7 +256,7 @@
val frame = processor.buffer.frames.single()
// Act: draw the frame with a wrong timestamp.
- val drawFuture = processor.drawFrame(frame.timestampNs - 1)
+ val drawFuture = processor.drawFrameAsync(frame.timestampNanos - 1)
// Assert: the future completes with RESULT_FRAME_NOT_FOUND and the output does not receive
// the frame.
@@ -275,7 +275,7 @@
val frame = processor.buffer.frames.single()
// Act: draw the frame.
- val drawFuture = processor.drawFrame(frame.timestampNs)
+ val drawFuture = processor.drawFrameAsync(frame.timestampNanos)
// Assert: the future completes with RESULT_CANCELLED_BY_CALLER and the output does not
// receive the frame.
@@ -303,7 +303,7 @@
}
// Act: draw the buffered frame.
- val drawFuture = processor.drawFrame(frame.timestampNs)
+ val drawFuture = processor.drawFrameAsync(frame.timestampNanos)
// Assert: the future completes with RESULT_INVALID_SURFACE and the output does not
// receive the frame.
@@ -318,7 +318,7 @@
processor.release()
// Act: release the processor and draw a frame.
- val drawFuture = processor.drawFrame(0)
+ val drawFuture = processor.drawFrameAsync(0)
// Assert: the future completes with an exception.
try {
diff --git a/camera/camera-effects/src/main/java/androidx/camera/effects/Frame.java b/camera/camera-effects/src/main/java/androidx/camera/effects/Frame.java
index 47c353b..102a961 100644
--- a/camera/camera-effects/src/main/java/androidx/camera/effects/Frame.java
+++ b/camera/camera-effects/src/main/java/androidx/camera/effects/Frame.java
@@ -22,7 +22,6 @@
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
-import android.hardware.camera2.CameraCharacteristics;
import android.util.Size;
import android.view.Surface;
@@ -30,21 +29,20 @@
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
+import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageInfo;
+import androidx.camera.core.Preview;
import androidx.camera.core.SurfaceRequest;
import com.google.auto.value.AutoValue;
/**
- * Represents a frame that will be rendered next.
+ * Represents a frame that is about to be rendered.
*
- * <p>This class can be used to overlay graphics or data on camera output. It contains
- * information for drawing an overlay, including sensor-to-buffer transform, size, crop rect,
- * rotation, mirroring, and timestamp. It also provides a {@link Canvas} for the drawing.
- *
- * TODO(b/297509601): Make it public API in 1.4.
+ * <p>Use this class to draw overlay on camera output. It contains a {@link Canvas} for the
+ * drawing. It also provides metadata for positioning the overlay correctly, including
+ * sensor-to-buffer transform, size, crop rect, rotation, mirroring, and timestamp.
*/
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@RequiresApi(21)
@AutoValue
public abstract class Frame {
@@ -61,12 +59,12 @@
@NonNull
public static Frame of(
@NonNull Surface overlaySurface,
- long timestampNs,
+ long timestampNanos,
@NonNull Size size,
@NonNull SurfaceRequest.TransformationInfo transformationInfo) {
Frame frame = new AutoValue_Frame(transformationInfo.getSensorToBufferTransform(), size,
transformationInfo.getCropRect(), transformationInfo.getRotationDegrees(),
- transformationInfo.getMirroring(), timestampNs);
+ transformationInfo.getMirroring(), timestampNanos);
frame.mOverlaySurface = overlaySurface;
return frame;
}
@@ -75,8 +73,8 @@
* Returns the sensor to image buffer transform matrix.
*
* <p>The value is a mapping from sensor coordinates to buffer coordinates, which is,
- * from the rect of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE} to the
- * rect defined by {@code (0, 0, #getSize()#getWidth(), #getSize()#getHeight())}.
+ * from the rect of the camera sensor to the rect defined by {@code (0, 0, #getSize()
+ * #getWidth(), #getSize()#getHeight())}.
*
* <p>The value can be set on the {@link Canvas} using {@link Canvas#setMatrix} API. This
* transforms the {@link Canvas} to the sensor coordinate system.
@@ -89,18 +87,20 @@
/**
* Returns the resolution of the frame.
*
+ * <p>This is the size of the input {@link SurfaceTexture} created by the effect.
+ *
* @see SurfaceRequest#getResolution()
*/
@NonNull
public abstract Size getSize();
/**
- * Returns the crop rect rectangle.
+ * Returns the crop rect.
*
- * <p>The value represents how the frame will be cropped by the CameraX pipeline. The crop
- * rectangle specifies the region of valid pixels in the frame, using coordinates from (0, 0)
- * to the (width, height) of {@link #getSize()}. Only the overlay drawn within the bound of
- * the crop rect will be visible to the end users.
+ * <p>The value represents how CameraX intends to crop the input frame. The crop rect specifies
+ * the region of valid pixels in the frame, using coordinates from (0, 0) to the (width,
+ * height) of {@link #getSize()}. Only the overlay drawn within the bound of the crop rect
+ * will be visible to the end users.
*
* <p>The crop rect is applied before the rotating and mirroring. The order of the operations
* is as follows: 1) cropping, 2) rotating and 3) mirroring.
@@ -114,9 +114,10 @@
* Returns the rotation degrees of the frame.
*
* <p>This is a clockwise rotation in degrees that needs to be applied to the frame. The
- * rotation will be determined by {@link CameraCharacteristics} and UseCase configuration.
- * The app must draw the overlay according to the rotation degrees to ensure it is
- * displayed correctly to the end users.
+ * rotation will be determined by camera sensor orientation and UseCase configuration
+ * such as {@link Preview#setTargetRotation}. The app must draw the overlay according to the
+ * rotation degrees to ensure it is displayed correctly to the end users. For example, to
+ * overlay a text, make sure the text's orientation is aligned with the rotation degrees.
*
* <p>The rotation is applied after the cropping but before the mirroring. The order of the
* operations is as follows: 1) cropping, 2) rotating and 3) mirroring.
@@ -128,7 +129,7 @@
/**
* Returns whether the buffer will be mirrored.
*
- * <p>This flag indicates whether the buffer will be mirrored by the pipeline vertically. For
+ * <p>This flag indicates whether the buffer will be mirrored vertically by the pipeline. For
* example, for front camera preview, the buffer is usually mirrored before displayed to end
* users.
*
@@ -142,21 +143,26 @@
/**
* Returns the timestamp of the frame in nanoseconds.
*
+ * <p>This value will match the frames from other streams. For example, for a
+ * {@link ImageAnalysis} output that is originated from the same frame, this value will match
+ * the value of {@link ImageInfo#getTimestamp()}.
+ *
* @see SurfaceTexture#getTimestamp()
* @see ImageInfo#getTimestamp()
*/
- public abstract long getTimestampNs();
+ public abstract long getTimestampNanos();
/**
* Get the canvas for drawing the overlay.
*
* <p>Call this method to get the {@link Canvas} for drawing an overlay on top of the frame.
- * The {@link Canvas} is backed by a {@link SurfaceTexture} with the sizes equals
+ * The {@link Canvas} is backed by a {@link SurfaceTexture} with a size equal to
* {@link #getSize()}. To draw object in camera sensor coordinates, apply
* {@link #getSensorToBufferTransform()} via {@link Canvas#setMatrix(Matrix)} before drawing.
*
- * <p>The caller should only invoke this method when there's a requirement to overlay on the
- * frame. Using this method introduce wait times to synchronize frame updates.
+ * <p>Using this method introduces wait times to synchronize frame updates. The caller should
+ * only invoke this method when it needs to draw overlay. For example, when an object is
+ * detected in the frame.
*/
@NonNull
public Canvas getOverlayCanvas() {
@@ -166,7 +172,6 @@
return mOverlayCanvas;
}
-
/**
* Internal API to check whether the overlay canvas has been drawn into.
*/
diff --git a/camera/camera-effects/src/main/java/androidx/camera/effects/OverlayEffect.java b/camera/camera-effects/src/main/java/androidx/camera/effects/OverlayEffect.java
index 642f8e6..f274630 100644
--- a/camera/camera-effects/src/main/java/androidx/camera/effects/OverlayEffect.java
+++ b/camera/camera-effects/src/main/java/androidx/camera/effects/OverlayEffect.java
@@ -16,29 +16,65 @@
package androidx.camera.effects;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.SurfaceTexture;
+import android.os.Handler;
+
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.arch.core.util.Function;
import androidx.camera.core.CameraEffect;
+import androidx.camera.core.ImageAnalysis;
+import androidx.camera.core.ImageInfo;
+import androidx.camera.core.ProcessingException;
+import androidx.camera.core.SurfaceProcessor;
import androidx.camera.core.UseCase;
+import androidx.camera.effects.internal.SurfaceProcessorImpl;
+import androidx.core.util.Consumer;
import com.google.common.util.concurrent.ListenableFuture;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+import java.util.concurrent.Executor;
/**
* A {@link CameraEffect} for drawing overlay on top of the camera frames.
- * TODO(b/297509601): Make it public API in 1.4.
+ *
+ * <p>This class manages and processes camera frames with OpenGL. Upon arrival, frames are
+ * enqueued into an array of GL textures for deferred rendering. Calling
+ * {@link #drawFrameAsync(long)} dequeues frames and renders them to the output. Additionally, when
+ * the texture queue reaches its capacity, the oldest frame is automatically dequeued and
+ * rendered. The size of the texture queue can be defined in the constructor.
+ *
+ * <p>The queuing mechanism provides the flexibility to postpone frame rendering until analysis
+ * results are available. For instance, to highlight on a QR code in a preview, one can apply a
+ * QR code detection algorithm using {@link ImageAnalysis}. Once the frame's analysis result
+ * is ready, invoke {@link #drawFrameAsync(long)} and pass in the
+ * {@link ImageInfo#getTimestamp()} to release the frame and draw overlay. If the app
+ * doesn't render real-time analysis results, set the queue depth to 0 to avoid unnecessary
+ * buffer copies. For example, when laying over a static watermark.
+ *
+ * <p>Prior to rendering a frame, the {@link OverlayEffect} invokes the listener set in
+ * {@link #setOnDrawListener(Function)}. This listener provides a {@link Frame} object, which
+ * contains both a {@link Canvas} object for drawing the overlay and the metadata like crop rect,
+ * rotation degrees, etc to calculate how the overlay should be positioned. Once the listener
+ * returns, {@link OverlayEffect} updates the {@link SurfaceTexture} behind the {@link Canvas}
+ * and blends it with the camera frame before rendering to the output.
+ *
+ * <p>This class is thread-safe. The methods can be invoked on any thread. The app provides a
+ * {@link Handler} object in the constructor which is used for listening for Surface updates,
+ * performing OpenGL operations and invoking app provided listeners.
*/
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@RequiresApi(21)
-public class OverlayEffect {
+public class OverlayEffect extends CameraEffect implements AutoCloseable {
/**
- * {@link #drawFrame(long)} result code
+ * {@link #drawFrameAsync(long)} result code.
*/
@Retention(RetentionPolicy.SOURCE)
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@@ -51,21 +87,20 @@
}
/**
- * The {@link #drawFrame(long)} call was successful. The frame with the exact timestamp was
+ * The {@link #drawFrameAsync(long)} call was successful. The frame with the exact timestamp was
* drawn to the output surface.
*/
public static final int RESULT_SUCCESS = 1;
/**
- * The {@link #drawFrame(long)} call failed because the frame with the exact timestamp was
+ * The {@link #drawFrameAsync(long)} call failed because the frame with the exact timestamp was
* not found in the queue. It could be one of the following reasons:
*
* <ul>
- * <li>the timestamp was incorrect, or
- * <li>the frame was not yet available, or
- * <li>the frame was removed because {@link #drawFrame} had been called with a newer
+ * <li>the timestamp provided was incorrect, or
+ * <li>the frame was removed because {@link #drawFrameAsync} had been called with a newer
* timestamp, or
- * <li>the frame was removed due to the queue is full.
+ * <li>the frame was removed due to the queue being full.
* </ul>
*
* If it's the last case, the caller may avoid this issue by increasing the queue depth.
@@ -73,30 +108,137 @@
public static final int RESULT_FRAME_NOT_FOUND = 2;
/**
- * The {@link #drawFrame(long)} call failed because the output surface is missing, or the
- * output surface no longer matches the frame. It could be because the {@link UseCase}
- * was unbound, causing the original surface to be replaced or disabled.
+ * The {@link #drawFrameAsync(long)} call failed because the output surface is missing, or the
+ * output surface no longer matches the frame. It can happen when the output Surface is
+ * replaced or disabled. For example, when the {@link UseCase} was unbound.
*/
public static final int RESULT_INVALID_SURFACE = 3;
/**
- * The {@link #drawFrame(long)} call failed because the caller cancelled the drawing. This
- * happens when the listener provided via {@link #setOnDrawListener(Function)} returned false.
+ * The {@link #drawFrameAsync(long)} call failed because the caller cancelled the drawing. This
+ * happens when the listener in {@link #setOnDrawListener(Function)} returned false.
*/
public static final int RESULT_CANCELLED_BY_CALLER = 4;
/**
- * TODO(b/297509601): add JavaDoc
+ * Creates an {@link OverlayEffect}.
+ *
+ * @param targets The targets the effect applies to. For example,
+ * {@link CameraEffect#PREVIEW} | {@link CameraEffect#VIDEO_CAPTURE}. See
+ * {@link UseCaseGroup.Builder#addEffect} for supported targets
+ * combinations.
+ * @param queueDepth The depth of the queue. This value indicates how many frames can be
+ * queued before the oldest frame being automatically released.
+ * {@link OverlayEffect} allocates an array of OpenGL 2D textures that
+ * matches this size. The maximum value of the queueDepth depends on the
+ * size of the image and the device capabilities. Set a larger value if
+ * an ImageAnalysis processing takes a long time to produce a result to
+ * be used for overlay, so the frame is not auto-released before the
+ * result is ready. If the queue depth is 0, the input frames are
+ * rendered immediately without queuing.
+ * @param handler The Handler for listening for the input Surface updates and for
+ * performing OpenGL operations.
+ * @param errorListener invoked if the effect runs into unrecoverable errors. The
+ * {@link Throwable} will be the error thrown by this
+ * {@link CameraEffect}. For example, {@link ProcessingException}.
+ * This is invoked on the provided {@param Handler}.
*/
- @NonNull
- public ListenableFuture<Integer> drawFrame(long timestampNs) {
- throw new UnsupportedOperationException("Not implemented yet");
+ public OverlayEffect(int targets, int queueDepth, @NonNull Handler handler,
+ @NonNull Consumer<Throwable> errorListener) {
+ this(targets, new SurfaceProcessorImpl(queueDepth, handler), errorListener);
+ }
+
+ private OverlayEffect(int targets, @NonNull SurfaceProcessorImpl surfaceProcessor,
+ @NonNull Consumer<Throwable> errorListener) {
+ this(targets, surfaceProcessor.getGlExecutor(), surfaceProcessor,
+ errorListener);
+ }
+
+ private OverlayEffect(int targets, @NonNull Executor executor,
+ @NonNull SurfaceProcessor surfaceProcessor,
+ @NonNull Consumer<Throwable> errorListener) {
+ super(targets, executor, surfaceProcessor, errorListener);
}
/**
- * TODO(b/297509601): add JavaDoc
+ * Draws the queued frame with the given timestamp.
+ *
+ * <p>Once invoked, {@link OverlayEffect} retrieves the queued frame with the given timestamp
+ * and draws it to the output Surface. If the frame is successfully drawn,
+ * {@link ListenableFuture} completes with {@link #RESULT_SUCCESS}. Otherwise, it completes
+ * with one of the following results: {@link #RESULT_FRAME_NOT_FOUND},
+ * {@link #RESULT_INVALID_SURFACE} or {@link #RESULT_CANCELLED_BY_CALLER}. If this method is
+ * called after the {@link OverlayEffect} is released, the {@link ListenableFuture} completes
+ * with an {@link IllegalStateException}.
+ *
+ * <p>This method is thread safe. When calling from the {@link #getHandler()} thread, it's
+ * executed right away; otherwise, it posts the execution on the {@link #getHandler()}. It's
+ * recommended to call this method from the {@link #getHandler()} thread to avoid thread
+ * hopping.
+ */
+ @NonNull
+ public ListenableFuture<Integer> drawFrameAsync(long timestampNs) {
+ return getSurfaceProcessorImpl().drawFrameAsync(timestampNs);
+ }
+
+ /**
+ * Sets the listener for drawing overlay.
+ *
+ * <p>Each time before {@link OverlayEffect} draws a frame to the output, the listener
+ * receives a {@link Frame} object, which contains the necessary APIs for drawing overlay.
+ *
+ * <p>To draw an overlay, first call {@link Frame#getOverlayCanvas()} ()} to get a
+ * {@link Canvas} object. The {@link Canvas} object is backed by a {@link SurfaceTexture}
+ * with the size of {@link Frame#getSize()}. {@link Frame#getSensorToBufferTransform()}
+ * represents the mapping from camera sensor coordinates to the frame's coordinates. To draw
+ * objects in the sensor coordinates, call {@link Canvas#setMatrix(Matrix)} with the value of
+ * {@link Frame#getSensorToBufferTransform()}.
+ *
+ * <p>Once the drawing is done, the listener should return true for the {@link OverlayEffect}
+ * to draw it to the output Surface. If it returns false, the frame will be dropped.
+ *
+ * <p>{@link OverlayEffect} invokes the listener on the {@link #getHandler()} thread.
+ *
+ * @see Frame
*/
public void setOnDrawListener(@NonNull Function<Frame, Boolean> onDrawListener) {
- throw new UnsupportedOperationException("Not implemented yet");
+ getSurfaceProcessorImpl().setOnDrawListener(onDrawListener);
+ }
+
+ /**
+ * Clears the listener set in {@link #setOnDrawListener(Function)}.
+ */
+ public void clearOnDrawListener() {
+ getSurfaceProcessorImpl().setOnDrawListener(null);
+ }
+
+ /**
+ * Closes the {@link OverlayEffect}.
+ *
+ * <p>Once closed, the {@link OverlayEffect} can no longer be used.
+ */
+ @Override
+ public void close() {
+ getSurfaceProcessorImpl().release();
+ }
+
+ /**
+ * Gets the depth of the queue set in the constructor.
+ */
+ public int getQueueDepth() {
+ return getSurfaceProcessorImpl().getQueueDepth();
+ }
+
+ /**
+ * Gets the {@link Handler} set in the constructor.
+ */
+ @NonNull
+ public Handler getHandler() {
+ return getSurfaceProcessorImpl().getGlHandler();
+ }
+
+ @NonNull
+ private SurfaceProcessorImpl getSurfaceProcessorImpl() {
+ return (SurfaceProcessorImpl) Objects.requireNonNull(getSurfaceProcessor());
}
}
diff --git a/camera/camera-effects/src/main/java/androidx/camera/effects/internal/SurfaceProcessorImpl.java b/camera/camera-effects/src/main/java/androidx/camera/effects/internal/SurfaceProcessorImpl.java
index b85c79f..6422c8f 100644
--- a/camera/camera-effects/src/main/java/androidx/camera/effects/internal/SurfaceProcessorImpl.java
+++ b/camera/camera-effects/src/main/java/androidx/camera/effects/internal/SurfaceProcessorImpl.java
@@ -96,11 +96,14 @@
private boolean mIsReleased = false;
+ private final int mQueueDepth;
+
// Thread and handler for receiving overlay texture updates.
private final HandlerThread mOverlayHandlerThread;
private final Handler mOverlayHandler;
public SurfaceProcessorImpl(int queueDepth, @NonNull Handler glHandler) {
+ mQueueDepth = queueDepth;
mGlHandler = glHandler;
mGlExecutor = CameraXExecutors.newHandlerExecutor(mGlHandler);
mGlRenderer = new GlRenderer(queueDepth);
@@ -267,7 +270,7 @@
* exception.
*/
@NonNull
- public ListenableFuture<Integer> drawFrame(long timestampNs) {
+ public ListenableFuture<Integer> drawFrameAsync(long timestampNs) {
return CallbackToFutureAdapter.getFuture(completer -> {
runOnGlThread(() -> {
if (mIsReleased) {
@@ -286,6 +289,21 @@
});
}
+ /**
+ * Gets the depth of the buffer.
+ */
+ public int getQueueDepth() {
+ return mQueueDepth;
+ }
+
+ /**
+ * Gets the GL handler.
+ */
+ @NonNull
+ public Handler getGlHandler() {
+ return mGlHandler;
+ }
+
// *** Private methods ***
private void runOnGlThread(@NonNull Runnable runnable) {
@@ -331,10 +349,10 @@
return OverlayEffect.RESULT_INVALID_SURFACE;
}
// Only draw if frame is associated with the current output surface.
- if (drawOverlay(frame.getTimestampNs())) {
+ if (drawOverlay(frame.getTimestampNanos())) {
mGlRenderer.renderQueueTextureToSurface(
frame.getTextureId(),
- frame.getTimestampNs(),
+ frame.getTimestampNanos(),
frame.getTransform(),
frame.getSurface());
return OverlayEffect.RESULT_SUCCESS;
diff --git a/camera/camera-effects/src/main/java/androidx/camera/effects/internal/TextureFrame.java b/camera/camera-effects/src/main/java/androidx/camera/effects/internal/TextureFrame.java
index d284439..6a1a542 100644
--- a/camera/camera-effects/src/main/java/androidx/camera/effects/internal/TextureFrame.java
+++ b/camera/camera-effects/src/main/java/androidx/camera/effects/internal/TextureFrame.java
@@ -40,7 +40,7 @@
private final int mTextureId;
- private long mTimestampNs = NO_VALUE;
+ private long mTimestampNanos = NO_VALUE;
@Nullable
private Surface mSurface;
@@ -61,7 +61,7 @@
* with new content.
*/
boolean isEmpty() {
- return mTimestampNs == NO_VALUE;
+ return mTimestampNanos == NO_VALUE;
}
/**
@@ -71,7 +71,7 @@
*/
void markEmpty() {
checkState(!isEmpty(), "Frame is already empty");
- mTimestampNs = NO_VALUE;
+ mTimestampNanos = NO_VALUE;
mSurface = null;
}
@@ -88,7 +88,7 @@
*/
void markFilled(long timestampNs, @NonNull float[] transform, @NonNull Surface surface) {
checkState(isEmpty(), "Frame is already filled");
- mTimestampNs = timestampNs;
+ mTimestampNanos = timestampNs;
System.arraycopy(transform, 0, mTransform, 0, transform.length);
mSurface = surface;
}
@@ -98,8 +98,8 @@
*
* <p>This value is used in {@link GlRenderer#renderQueueTextureToSurface}.
*/
- long getTimestampNs() {
- return mTimestampNs;
+ long getTimestampNanos() {
+ return mTimestampNanos;
}
/**
diff --git a/camera/camera-effects/src/main/java/androidx/camera/effects/internal/TextureFrameBuffer.java b/camera/camera-effects/src/main/java/androidx/camera/effects/internal/TextureFrameBuffer.java
index e75b292..8c5b854 100644
--- a/camera/camera-effects/src/main/java/androidx/camera/effects/internal/TextureFrameBuffer.java
+++ b/camera/camera-effects/src/main/java/androidx/camera/effects/internal/TextureFrameBuffer.java
@@ -73,9 +73,9 @@
if (frame.isEmpty()) {
continue;
}
- if (frame.getTimestampNs() == timestampNs) {
+ if (frame.getTimestampNanos() == timestampNs) {
frameToReturn = frame;
- } else if (frame.getTimestampNs() < timestampNs) {
+ } else if (frame.getTimestampNanos() < timestampNs) {
frame.markEmpty();
}
}
@@ -95,8 +95,8 @@
for (TextureFrame frame : mFrames) {
if (frame.isEmpty()) {
return frame;
- } else if (frame.getTimestampNs() < minTimestampNs) {
- minTimestampNs = frame.getTimestampNs();
+ } else if (frame.getTimestampNanos() < minTimestampNs) {
+ minTimestampNs = frame.getTimestampNanos();
oldestFrame = frame;
}
}
diff --git a/camera/camera-effects/src/main/java/androidx/camera/effects/opengl/GlRenderer.java b/camera/camera-effects/src/main/java/androidx/camera/effects/opengl/GlRenderer.java
index 9158e9a..c2aeac5 100644
--- a/camera/camera-effects/src/main/java/androidx/camera/effects/opengl/GlRenderer.java
+++ b/camera/camera-effects/src/main/java/androidx/camera/effects/opengl/GlRenderer.java
@@ -43,7 +43,7 @@
* <li>Rendering a texture in the queue to the output Surface.
* </ul>
*
- * <p>It also allows the caller to upload a bitmap and overlay it when rendering to Surface.
+ * <p>It also allows the caller to overlay a texture when rendering to Surface.
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@RestrictTo(RestrictTo.Scope.LIBRARY)
diff --git a/camera/camera-effects/src/test/java/androidx/camera/effects/internal/TextureFrameBufferTest.kt b/camera/camera-effects/src/test/java/androidx/camera/effects/internal/TextureFrameBufferTest.kt
index 757373c..5f7edda 100644
--- a/camera/camera-effects/src/test/java/androidx/camera/effects/internal/TextureFrameBufferTest.kt
+++ b/camera/camera-effects/src/test/java/androidx/camera/effects/internal/TextureFrameBufferTest.kt
@@ -92,7 +92,7 @@
// Assert: the frame has the correct values.
assertThat(frame.textureId).isEqualTo(1)
- assertThat(frame.timestampNs).isEqualTo(TIMESTAMP_1)
+ assertThat(frame.timestampNanos).isEqualTo(TIMESTAMP_1)
assertThat(frame.transform.contentEquals(transform1)).isTrue()
assertThat(frame.transform).isNotSameInstanceAs(transform1)
assertThat(frame.surface).isSameInstanceAs(surface1)
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionsManagerTest.kt b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionsManagerTest.kt
index 926cad2..5dc613d 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionsManagerTest.kt
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionsManagerTest.kt
@@ -27,6 +27,7 @@
import androidx.camera.core.SurfaceRequest
import androidx.camera.core.impl.CameraInfoInternal
import androidx.camera.core.impl.MutableStateObservable
+import androidx.camera.extensions.impl.ExtensionsTestlibControl
import androidx.camera.extensions.internal.ClientVersion
import androidx.camera.extensions.internal.ExtensionVersion
import androidx.camera.extensions.internal.VendorExtender
@@ -60,6 +61,7 @@
@RunWith(Parameterized::class)
@SdkSuppress(minSdkVersion = 21)
class ExtensionsManagerTest(
+ private val implType: ExtensionsTestlibControl.ImplementationType,
@field:ExtensionMode.Mode @param:ExtensionMode.Mode private val extensionMode: Int,
@field:CameraSelector.LensFacing @param:CameraSelector.LensFacing private val lensFacing: Int
) {
@@ -92,6 +94,7 @@
)
baseCameraSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build()
+ ExtensionsTestlibControl.getInstance().setImplementationType(implType)
}
@After
@@ -107,9 +110,9 @@
companion object {
@JvmStatic
- @get:Parameterized.Parameters(name = "extension = {0}, facing = {1}")
+ @get:Parameterized.Parameters(name = "implType = {0}, mode = {1}, facing = {2}")
val parameters: Collection<Array<Any>>
- get() = ExtensionsTestUtil.getAllExtensionsLensFacingCombinations()
+ get() = ExtensionsTestUtil.getAllImplExtensionsLensFacingCombinations()
}
@Test
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ImageAnalysisTest.kt b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ImageAnalysisTest.kt
index 2fb9866..935c0e1 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ImageAnalysisTest.kt
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ImageAnalysisTest.kt
@@ -30,6 +30,7 @@
import androidx.camera.core.Preview
import androidx.camera.core.impl.ImageFormatConstants
import androidx.camera.core.impl.utils.executor.CameraXExecutors
+import androidx.camera.extensions.impl.ExtensionsTestlibControl
import androidx.camera.extensions.internal.VendorExtender
import androidx.camera.extensions.util.ExtensionsTestUtil
import androidx.camera.lifecycle.ProcessCameraProvider
@@ -58,14 +59,15 @@
@RunWith(Parameterized::class)
@SdkSuppress(minSdkVersion = 21)
class ImageAnalysisTest(
+ private val implType: ExtensionsTestlibControl.ImplementationType,
@ExtensionMode.Mode private val extensionMode: Int,
@CameraSelector.LensFacing private val lensFacing: Int
) {
companion object {
@JvmStatic
- @get:Parameterized.Parameters(name = "extension = {0}, facing = {1}")
+ @get:Parameterized.Parameters(name = "implType = {0}, mode = {1}, facing = {2}")
val parameters: Collection<Array<Any>>
- get() = ExtensionsTestUtil.getAllExtensionsLensFacingCombinations()
+ get() = ExtensionsTestUtil.getAllImplExtensionsLensFacingCombinations()
}
@get:Rule
@@ -91,6 +93,7 @@
)
cameraProvider = ProcessCameraProvider.getInstance(context)[10000, TimeUnit.MILLISECONDS]
+ ExtensionsTestlibControl.getInstance().setImplementationType(implType)
baseCameraSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build()
extensionsManager = ExtensionsManager.getInstanceAsync(
context,
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ImageCaptureTest.kt b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ImageCaptureTest.kt
index 0328edf..96616ad 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ImageCaptureTest.kt
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ImageCaptureTest.kt
@@ -31,6 +31,7 @@
import androidx.camera.core.Preview
import androidx.camera.core.impl.utils.executor.CameraXExecutors
import androidx.camera.core.internal.compat.workaround.ExifRotationAvailability
+import androidx.camera.extensions.impl.ExtensionsTestlibControl
import androidx.camera.extensions.util.ExtensionsTestUtil
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.testing.impl.CameraUtil
@@ -66,6 +67,7 @@
@RunWith(Parameterized::class)
@SdkSuppress(minSdkVersion = 21)
class ImageCaptureTest(
+ private val implType: ExtensionsTestlibControl.ImplementationType,
@field:ExtensionMode.Mode @param:ExtensionMode.Mode private val extensionMode: Int,
@field:CameraSelector.LensFacing @param:CameraSelector.LensFacing private val lensFacing: Int
) {
@@ -102,6 +104,7 @@
cameraProvider = ProcessCameraProvider.getInstance(context)[10000, TimeUnit.MILLISECONDS]
baseCameraSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build()
+ ExtensionsTestlibControl.getInstance().setImplementationType(implType)
extensionsManager = ExtensionsManager.getInstanceAsync(
context,
cameraProvider
@@ -132,9 +135,9 @@
companion object {
@JvmStatic
- @get:Parameterized.Parameters(name = "extension = {0}, facing = {1}")
+ @get:Parameterized.Parameters(name = "impl= {0}, mode = {1}, facing = {2}")
val parameters: Collection<Array<Any>>
- get() = ExtensionsTestUtil.getAllExtensionsLensFacingCombinations()
+ get() = ExtensionsTestUtil.getAllImplExtensionsLensFacingCombinations()
}
@Test
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/PreviewTest.kt b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/PreviewTest.kt
index 7ba9407..ef828d0 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/PreviewTest.kt
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/PreviewTest.kt
@@ -24,6 +24,7 @@
import androidx.camera.camera2.Camera2Config
import androidx.camera.core.CameraSelector
import androidx.camera.core.Preview
+import androidx.camera.extensions.impl.ExtensionsTestlibControl
import androidx.camera.extensions.util.ExtensionsTestUtil
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.testing.impl.CameraUtil
@@ -53,6 +54,7 @@
@RunWith(Parameterized::class)
@SdkSuppress(minSdkVersion = 21)
class PreviewTest(
+ private val implType: ExtensionsTestlibControl.ImplementationType,
@field:ExtensionMode.Mode @param:ExtensionMode.Mode private val extensionMode: Int,
@field:CameraSelector.LensFacing @param:CameraSelector.LensFacing private val lensFacing: Int
) {
@@ -119,6 +121,7 @@
)
cameraProvider = ProcessCameraProvider.getInstance(context)[10000, TimeUnit.MILLISECONDS]
+ ExtensionsTestlibControl.getInstance().setImplementationType(implType)
baseCameraSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build()
extensionsManager = ExtensionsManager.getInstanceAsync(
context,
@@ -150,9 +153,9 @@
companion object {
@JvmStatic
- @get:Parameterized.Parameters(name = "extension = {0}, facing = {1}")
+ @get:Parameterized.Parameters(name = "implType = {0}, mode = {1}, facing = {2}")
val parameters: Collection<Array<Any>>
- get() = ExtensionsTestUtil.getAllExtensionsLensFacingCombinations()
+ get() = ExtensionsTestUtil.getAllImplExtensionsLensFacingCombinations()
}
@UiThreadTest
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/VideoCaptureTest.kt b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/VideoCaptureTest.kt
index 8348eeb..69bcb78 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/VideoCaptureTest.kt
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/VideoCaptureTest.kt
@@ -29,6 +29,7 @@
import androidx.camera.core.Preview
import androidx.camera.core.Preview.SurfaceProvider
import androidx.camera.core.impl.utils.executor.CameraXExecutors
+import androidx.camera.extensions.impl.ExtensionsTestlibControl
import androidx.camera.extensions.util.ExtensionsTestUtil
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.testing.impl.AndroidUtil.skipVideoRecordingTestIfNotSupportedByEmulator
@@ -66,6 +67,7 @@
@RunWith(Parameterized::class)
@SdkSuppress(minSdkVersion = 21)
class VideoCaptureTest(
+ private val implType: ExtensionsTestlibControl.ImplementationType,
@field:ExtensionMode.Mode @param:ExtensionMode.Mode private val extensionMode: Int,
@field:CameraSelector.LensFacing @param:CameraSelector.LensFacing private val lensFacing: Int
) {
@@ -130,6 +132,7 @@
skipVideoRecordingTestIfNotSupportedByEmulator()
cameraProvider = ProcessCameraProvider.getInstance(context)[10000, TimeUnit.MILLISECONDS]
+ ExtensionsTestlibControl.getInstance().setImplementationType(implType)
baseCameraSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build()
extensionsManager = ExtensionsManager.getInstanceAsync(
context,
@@ -280,8 +283,8 @@
private const val TAG = "VideoCaptureTest"
@JvmStatic
- @get:Parameterized.Parameters(name = "extension = {0}, facing = {1}")
+ @get:Parameterized.Parameters(name = "implType = {0}, mode = {1}, facing = {2}")
val parameters: Collection<Array<Any>>
- get() = ExtensionsTestUtil.getAllExtensionsLensFacingCombinations()
+ get() = ExtensionsTestUtil.getAllImplExtensionsLensFacingCombinations()
}
}
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/util/ExtensionsTestUtil.java b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/util/ExtensionsTestUtil.java
index a9f652d..8f92a27 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/util/ExtensionsTestUtil.java
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/util/ExtensionsTestUtil.java
@@ -21,6 +21,9 @@
import static androidx.camera.extensions.ExtensionMode.FACE_RETOUCH;
import static androidx.camera.extensions.ExtensionMode.HDR;
import static androidx.camera.extensions.ExtensionMode.NIGHT;
+import static androidx.camera.extensions.impl.ExtensionsTestlibControl.ImplementationType.OEM_IMPL;
+import static androidx.camera.extensions.impl.ExtensionsTestlibControl.ImplementationType.TESTLIB_ADVANCED;
+import static androidx.camera.extensions.impl.ExtensionsTestlibControl.ImplementationType.TESTLIB_BASIC;
import android.hardware.camera2.CameraCharacteristics;
import android.os.Build;
@@ -29,6 +32,7 @@
import androidx.annotation.RequiresApi;
import androidx.camera.core.CameraSelector;
import androidx.camera.extensions.ExtensionMode;
+import androidx.camera.extensions.impl.ExtensionsTestlibControl;
import androidx.camera.extensions.internal.AdvancedVendorExtender;
import androidx.camera.extensions.internal.BasicVendorExtender;
import androidx.camera.extensions.internal.ExtensionVersion;
@@ -37,28 +41,65 @@
import androidx.camera.extensions.internal.compat.workaround.ExtensionDisabledValidator;
import androidx.camera.testing.impl.CameraUtil;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.List;
/**
* Extension test util functions.
*/
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
public class ExtensionsTestUtil {
+
+ /**
+ * Returns the parameters which contains the combination of implementationType, extensions
+ * mode and lens facing.
+ */
@NonNull
- public static Collection<Object[]> getAllExtensionsLensFacingCombinations() {
- return Arrays.asList(new Object[][]{
- {BOKEH, CameraSelector.LENS_FACING_FRONT},
- {BOKEH, CameraSelector.LENS_FACING_BACK},
- {HDR, CameraSelector.LENS_FACING_FRONT},
- {HDR, CameraSelector.LENS_FACING_BACK},
- {FACE_RETOUCH, CameraSelector.LENS_FACING_FRONT},
- {FACE_RETOUCH, CameraSelector.LENS_FACING_BACK},
- {NIGHT, CameraSelector.LENS_FACING_FRONT},
- {NIGHT, CameraSelector.LENS_FACING_BACK},
- {AUTO, CameraSelector.LENS_FACING_FRONT},
- {AUTO, CameraSelector.LENS_FACING_BACK}
+ public static Collection<Object[]> getAllImplExtensionsLensFacingCombinations() {
+ ExtensionsTestlibControl.ImplementationType implType =
+ ExtensionsTestlibControl.getInstance().getImplementationType();
+
+ if (implType == TESTLIB_ADVANCED) {
+ ExtensionsTestlibControl.getInstance().setImplementationType(TESTLIB_BASIC);
+ implType = TESTLIB_BASIC;
+ }
+
+ List<Object[]> basicOrOemImplList = Arrays.asList(new Object[][]{
+ {implType, BOKEH, CameraSelector.LENS_FACING_FRONT},
+ {implType, BOKEH, CameraSelector.LENS_FACING_BACK},
+ {implType, HDR, CameraSelector.LENS_FACING_FRONT},
+ {implType, HDR, CameraSelector.LENS_FACING_BACK},
+ {implType, FACE_RETOUCH, CameraSelector.LENS_FACING_FRONT},
+ {implType, FACE_RETOUCH, CameraSelector.LENS_FACING_BACK},
+ {implType, NIGHT, CameraSelector.LENS_FACING_FRONT},
+ {implType, NIGHT, CameraSelector.LENS_FACING_BACK},
+ {implType, AUTO, CameraSelector.LENS_FACING_FRONT},
+ {implType, AUTO, CameraSelector.LENS_FACING_BACK}
});
+
+ if (implType == OEM_IMPL) {
+ return basicOrOemImplList;
+ }
+
+ List<Object[]> advancedList = Arrays.asList(new Object[][]{
+ {TESTLIB_ADVANCED, BOKEH, CameraSelector.LENS_FACING_FRONT},
+ {TESTLIB_ADVANCED, BOKEH, CameraSelector.LENS_FACING_BACK},
+ {TESTLIB_ADVANCED, HDR, CameraSelector.LENS_FACING_FRONT},
+ {TESTLIB_ADVANCED, HDR, CameraSelector.LENS_FACING_BACK},
+ {TESTLIB_ADVANCED, FACE_RETOUCH, CameraSelector.LENS_FACING_FRONT},
+ {TESTLIB_ADVANCED, FACE_RETOUCH, CameraSelector.LENS_FACING_BACK},
+ {TESTLIB_ADVANCED, NIGHT, CameraSelector.LENS_FACING_FRONT},
+ {TESTLIB_ADVANCED, NIGHT, CameraSelector.LENS_FACING_BACK},
+ {TESTLIB_ADVANCED, AUTO, CameraSelector.LENS_FACING_FRONT},
+ {TESTLIB_ADVANCED, AUTO, CameraSelector.LENS_FACING_BACK}
+ });
+
+ List<Object[]> allList = new ArrayList<>();
+ allList.addAll(basicOrOemImplList);
+ allList.addAll(advancedList);
+ return allList;
}
/**
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraInfoInternal.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraInfoInternal.java
index 68a27ed..5048cbb 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraInfoInternal.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraInfoInternal.java
@@ -26,6 +26,7 @@
import androidx.annotation.FloatRange;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.CameraState;
import androidx.camera.core.DynamicRange;
@@ -35,6 +36,7 @@
import androidx.camera.core.ZoomState;
import androidx.camera.core.impl.CameraCaptureCallback;
import androidx.camera.core.impl.CameraInfoInternal;
+import androidx.camera.core.impl.DynamicRanges;
import androidx.camera.core.impl.EncoderProfilesProvider;
import androidx.camera.core.impl.ImageOutputConfig.RotationValue;
import androidx.camera.core.impl.Quirk;
@@ -260,6 +262,30 @@
return mSupportedDynamicRanges;
}
+ /**
+ * Returns the supported dynamic ranges of this camera from a set of candidate dynamic ranges.
+ *
+ * <p>The dynamic ranges which represent what the camera supports will come from the dynamic
+ * ranges set on {@link #setSupportedDynamicRanges(Set)}, or will consist of {@code {SDR}} if
+ * {@code setSupportedDynamicRanges(Set)} has not been called. In order to stay compliant
+ * with the API contract of
+ * {@link androidx.camera.core.CameraInfo#querySupportedDynamicRanges(Set)}, it is
+ * required that the {@link Set} provided to {@code setSupportedDynamicRanges(Set)} should
+ * always contain {@link DynamicRange#SDR} and should never contain under-specified dynamic
+ * ranges, such as {@link DynamicRange#UNSPECIFIED} and
+ * {@link DynamicRange#HDR_UNSPECIFIED_10_BIT}.
+ *
+ * @see androidx.camera.core.CameraInfo#querySupportedDynamicRanges(Set)
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @NonNull
+ @Override
+ public Set<DynamicRange> querySupportedDynamicRanges(
+ @NonNull Set<DynamicRange> candidateDynamicRanges) {
+ return DynamicRanges.findAllPossibleMatches(
+ candidateDynamicRanges, getSupportedDynamicRanges());
+ }
+
@Override
public void addSessionCaptureCallback(@NonNull Executor executor,
@NonNull CameraCaptureCallback callback) {
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/impl/fakes/FakeSurfaceEffect.java b/camera/camera-testing/src/main/java/androidx/camera/testing/impl/fakes/FakeSurfaceEffect.java
index 5166d0c..26925b4 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/impl/fakes/FakeSurfaceEffect.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/impl/fakes/FakeSurfaceEffect.java
@@ -58,6 +58,21 @@
* <p> This is helpful when we want to make sure the {@link SurfaceProcessorInternal} is
* released properly.
*/
+ public FakeSurfaceEffect(@Targets int targets, @Transformations int transformation,
+ @NonNull SurfaceProcessorInternal surfaceProcessorInternal) {
+ super(targets, transformation, mainThreadExecutor(), surfaceProcessorInternal,
+ throwable -> {
+ });
+ mSurfaceProcessorInternal = surfaceProcessorInternal;
+ }
+
+ /**
+ * Create a fake {@link CameraEffect} the {@link #createSurfaceProcessorInternal} value
+ * overridden.
+ *
+ * <p> This is helpful when we want to make sure the {@link SurfaceProcessorInternal} is
+ * released properly.
+ */
public FakeSurfaceEffect(@Targets int targets,
@NonNull SurfaceProcessorInternal surfaceProcessorInternal) {
super(targets, mainThreadExecutor(), surfaceProcessorInternal, throwable -> {
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/impl/fakes/FakeSurfaceProcessor.java b/camera/camera-testing/src/main/java/androidx/camera/testing/impl/fakes/FakeSurfaceProcessor.java
index c0aed34..d97e4fe 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/impl/fakes/FakeSurfaceProcessor.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/impl/fakes/FakeSurfaceProcessor.java
@@ -43,7 +43,6 @@
private final Executor mExecutor;
private final boolean mAutoCloseSurfaceOutput;
-
@Nullable
private SurfaceRequest mSurfaceRequest;
@NonNull
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
index 5235e59..7df0fe49 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
@@ -87,6 +87,15 @@
* @since 1.2
*/
public boolean isAdvancedExtenderImplemented() {
- return false;
+ return ExtensionsTestlibControl.getInstance().getImplementationType()
+ == ExtensionsTestlibControl.ImplementationType.TESTLIB_ADVANCED;
+ }
+
+ /**
+ * This method is used to check if test lib is running. If OEM implementation exists, invoking
+ * this method will throw {@link NoSuchMethodError}. This can be used to determine if OEM
+ * implementation is used or not.
+ */
+ public void checkTestlibRunning() {
}
}
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/ExtensionsTestlibControl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/ExtensionsTestlibControl.java
index 6cf35b5..344d9ac 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/ExtensionsTestlibControl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/ExtensionsTestlibControl.java
@@ -21,19 +21,25 @@
/**
* An internal utility class that allows tests to specify whether to enable basic extender or
- * advanced extender of this testlib.
+ * advanced extender of this testlib. If OEM implementation exists on the device, the
+ * implementation type is always {@link ImplementationType#OEM_IMPL} and can't be changed to
+ * other types.
*/
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
public class ExtensionsTestlibControl {
public enum ImplementationType {
- ADVANCED_EXTENDER,
- BASIC_EXTENDER
+ OEM_IMPL,
+ TESTLIB_ADVANCED,
+ TESTLIB_BASIC
}
private static ExtensionsTestlibControl sInstance;
private static Object sLock = new Object();
+ private volatile ImplementationType mImplementationType = ImplementationType.TESTLIB_BASIC;
private ExtensionsTestlibControl() {
+ mImplementationType = doesOEMImplementationExist()
+ ? ImplementationType.OEM_IMPL : ImplementationType.TESTLIB_BASIC;
}
/**
@@ -49,15 +55,43 @@
}
}
- private ImplementationType mImplementationType = ImplementationType.BASIC_EXTENDER;
-
/**
* Set the implementation type.
+ *
+ * <p>When OEM implementation exists on the device, the only possible type is
+ * {@link ImplementationType#OEM_IMPL}. Setting the implementation type to
+ * {@link ImplementationType#TESTLIB_BASIC} or {@link ImplementationType#TESTLIB_ADVANCED}
+ * when OEM implementation exist will throw an {@link IllegalArgumentException}.
+ *
+ * <p>When OEM implementation doesn't exist on the device, it is allowed to set it to
+ * {@link ImplementationType#TESTLIB_BASIC} or {@link ImplementationType#TESTLIB_ADVANCED}.
+ * Setting it to {@link ImplementationType#OEM_IMPL} in this case will throw an
+ * {@link IllegalArgumentException}.
*/
public void setImplementationType(@NonNull ImplementationType type) {
+ if (mImplementationType != ImplementationType.OEM_IMPL) { // OEM impl doesn't exist
+ if (type == ImplementationType.OEM_IMPL) {
+ throw new IllegalArgumentException("OEM_IMPL is not supported on this device.");
+ }
+ } else { // OEM impl exists
+ if (type != ImplementationType.OEM_IMPL) {
+ throw new IllegalArgumentException("Can't change the implementation type because "
+ + "OEM implementation exists on the device");
+ }
+ }
+
mImplementationType = type;
}
+ private boolean doesOEMImplementationExist() {
+ try {
+ new ExtensionVersionImpl().checkTestlibRunning();
+ return false;
+ } catch (NoSuchMethodError e) { // checkTestlibRunning doesn't exist in OEM implementation.
+ return true;
+ }
+ }
+
/**
* Gets the implementation type;
*/
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
index ac5fdce..0c0cf09 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
@@ -19,7 +19,6 @@
import android.annotation.SuppressLint;
import android.content.Context;
-import android.graphics.ImageFormat;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
@@ -40,7 +39,7 @@
import java.nio.ByteBuffer;
import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
@@ -385,8 +384,7 @@
@Nullable
@Override
public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(@NonNull Size captureSize) {
- Pair<Integer, Size[]> pair = new Pair<>(ImageFormat.JPEG, new Size[] {captureSize});
- return Arrays.asList(pair);
+ return Collections.emptyList();
}
@Override
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
index 093d409..0de93ff 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
@@ -179,11 +179,11 @@
@NonNull
@Override
public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
- List<CaptureRequest.Key> keys = Arrays.asList(
+ List<CaptureRequest.Key> keys = new ArrayList<>(Arrays.asList(
CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_TRIGGER,
CaptureRequest.CONTROL_AF_REGIONS,
- CaptureRequest.CONTROL_AE_REGIONS);
+ CaptureRequest.CONTROL_AE_REGIONS));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
keys.add(CaptureRequest.CONTROL_ZOOM_RATIO);
} else {
@@ -195,12 +195,12 @@
@NonNull
@Override
public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
- List<CaptureResult.Key> keys = Arrays.asList(
+ List<CaptureResult.Key> keys = new ArrayList<>(Arrays.asList(
CaptureResult.CONTROL_AF_MODE,
CaptureResult.CONTROL_AE_REGIONS,
CaptureResult.CONTROL_AF_REGIONS,
CaptureResult.CONTROL_AE_STATE,
- CaptureResult.CONTROL_AF_STATE);
+ CaptureResult.CONTROL_AF_STATE));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
keys.add(CaptureResult.CONTROL_ZOOM_RATIO);
} else {
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java
index 9f567ba..520ea90 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java
@@ -42,13 +42,12 @@
@Override
public boolean isExtensionAvailable(@NonNull String cameraId,
@NonNull Map<String, CameraCharacteristics> characteristicsMap) {
- throw new RuntimeException("Stub, replace with implementation.");
+ return false;
}
@Override
public void init(@NonNull String cameraId,
@NonNull Map<String, CameraCharacteristics> characteristicsMap) {
- throw new RuntimeException("Stub, replace with implementation.");
}
@Override
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java
index 40bbb93..d99e44c 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java
@@ -42,13 +42,12 @@
@Override
public boolean isExtensionAvailable(@NonNull String cameraId,
@NonNull Map<String, CameraCharacteristics> characteristicsMap) {
- throw new RuntimeException("Stub, replace with implementation.");
+ return false;
}
@Override
public void init(@NonNull String cameraId,
@NonNull Map<String, CameraCharacteristics> characteristicsMap) {
- throw new RuntimeException("Stub, replace with implementation.");
}
@Override
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java
index 4093211..743b8d9 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java
@@ -42,13 +42,12 @@
@Override
public boolean isExtensionAvailable(@NonNull String cameraId,
@NonNull Map<String, CameraCharacteristics> characteristicsMap) {
- throw new RuntimeException("Stub, replace with implementation.");
+ return false;
}
@Override
public void init(@NonNull String cameraId,
@NonNull Map<String, CameraCharacteristics> characteristicsMap) {
- throw new RuntimeException("Stub, replace with implementation.");
}
@Override
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/DefaultRequestProcessorImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/DefaultRequestProcessorImpl.java
new file mode 100644
index 0000000..c6c58a3
--- /dev/null
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/DefaultRequestProcessorImpl.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2023 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.camera.extensions.impl.advanced;
+
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+
+import androidx.annotation.NonNull;
+
+public class DefaultRequestProcessorImpl implements RequestProcessorImpl.Callback {
+ @Override
+ public void onCaptureStarted(@NonNull RequestProcessorImpl.Request request, long frameNumber,
+ long timestamp) {
+
+ }
+
+ @Override
+ public void onCaptureProgressed(@NonNull RequestProcessorImpl.Request request,
+ @NonNull CaptureResult partialResult) {
+
+ }
+
+ @Override
+ public void onCaptureCompleted(@NonNull RequestProcessorImpl.Request request,
+ @NonNull TotalCaptureResult totalCaptureResult) {
+
+ }
+
+ @Override
+ public void onCaptureFailed(@NonNull RequestProcessorImpl.Request request,
+ @NonNull CaptureFailure captureFailure) {
+
+ }
+
+ @Override
+ public void onCaptureBufferLost(@NonNull RequestProcessorImpl.Request request, long frameNumber,
+ int outputStreamId) {
+
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(int sequenceId, long frameNumber) {
+
+ }
+
+ @Override
+ public void onCaptureSequenceAborted(int sequenceId) {
+
+ }
+}
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java
index 3d682ec..e4b038c 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java
@@ -16,101 +16,19 @@
package androidx.camera.extensions.impl.advanced;
-import android.hardware.camera2.CameraCharacteristics;
-import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.CaptureResult;
-import android.util.Range;
-import android.util.Size;
+import android.graphics.ImageFormat;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import java.util.List;
-import java.util.Map;
+import androidx.annotation.RequiresApi;
/**
- * Stub advanced extender implementation for hdr.
- *
- * <p>This class should be implemented by OEM and deployed to the target devices.
+ * A sample HDR implementation for testing long processing capture. It is capable of outputting
+ * the postview(JPEG format) and the process progress event. ImageAnalysis is not supported.
*
* @since 1.2
*/
-public class HdrAdvancedExtenderImpl implements AdvancedExtenderImpl {
+@RequiresApi(21)
+public class HdrAdvancedExtenderImpl extends LongCaptureAdvancedExtenderImpl {
public HdrAdvancedExtenderImpl() {
- }
-
- @Override
- public boolean isExtensionAvailable(@NonNull String cameraId,
- @NonNull Map<String, CameraCharacteristics> characteristicsMap) {
- throw new RuntimeException("Stub, replace with implementation.");
- }
-
- @Override
- public void init(@NonNull String cameraId,
- @NonNull Map<String, CameraCharacteristics> characteristicsMap) {
- throw new RuntimeException("Stub, replace with implementation.");
- }
-
- @Override
- @Nullable
- public Range<Long> getEstimatedCaptureLatencyRange(
- @NonNull String cameraId, @Nullable Size size, int imageFormat) {
- throw new RuntimeException("Stub, replace with implementation.");
- }
-
- @Override
- @NonNull
- public Map<Integer, List<Size>> getSupportedPreviewOutputResolutions(
- @NonNull String cameraId) {
- throw new RuntimeException("Stub, replace with implementation.");
- }
-
-
- @Override
- @NonNull
- public Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(
- @NonNull String cameraId) {
- throw new RuntimeException("Stub, replace with implementation.");
- }
-
- @Override
- @NonNull
- public Map<Integer, List<Size>> getSupportedPostviewResolutions(
- @NonNull Size captureSize) {
- throw new RuntimeException("Stub, replace with implementation.");
- }
-
- @Override
- @Nullable
- public List<Size> getSupportedYuvAnalysisResolutions(@NonNull String cameraId) {
- throw new RuntimeException("Stub, replace with implementation.");
- }
-
- @Override
- @NonNull
- public SessionProcessorImpl createSessionProcessor() {
- throw new RuntimeException("Stub, replace with implementation.");
- }
-
- @Override
- @NonNull
- public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
- throw new RuntimeException("Stub, replace with implementation.");
- }
-
- @Override
- @NonNull
- public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
- throw new RuntimeException("Stub, replace with implementation.");
- }
-
- @Override
- public boolean isCaptureProcessProgressAvailable() {
- throw new RuntimeException("Stub, replace with implementation.");
- }
-
- @Override
- public boolean isPostviewAvailable() {
- throw new RuntimeException("Stub, replace with implementation.");
+ super(/* postviewFormat */ ImageFormat.JPEG);
}
}
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/LongCaptureAdvancedExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/LongCaptureAdvancedExtenderImpl.java
new file mode 100644
index 0000000..d28067c
--- /dev/null
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/LongCaptureAdvancedExtenderImpl.java
@@ -0,0 +1,593 @@
+/*
+ * Copyright 2023 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.camera.extensions.impl.advanced;
+
+import android.content.Context;
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.os.Build;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Size;
+import android.view.Surface;
+
+import androidx.annotation.GuardedBy;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.camera.core.ImageProcessingUtil;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * An {@link AdvancedExtenderImpl} implementation that have long processing time for capture and
+ * is capable of outputting the postview and the process progress event.
+ */
+@RequiresApi(21)
+public class LongCaptureAdvancedExtenderImpl implements AdvancedExtenderImpl {
+ private static final int EV_INDEX = 10;
+
+ private CameraCharacteristics mCameraCharacteristics;
+ private final int mPostviewFormat;
+
+ public LongCaptureAdvancedExtenderImpl(int postviewFormat) {
+ mPostviewFormat = postviewFormat;
+ }
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId,
+ @NonNull Map<String, CameraCharacteristics> characteristicsMap) {
+ return true;
+ }
+
+ @Override
+ public void init(@NonNull String cameraId,
+ @NonNull Map<String, CameraCharacteristics> characteristicsMap) {
+ mCameraCharacteristics = characteristicsMap.get(cameraId);
+ }
+
+ @Override
+ @Nullable
+ public Range<Long> getEstimatedCaptureLatencyRange(
+ @NonNull String cameraId, @Nullable Size size, int imageFormat) {
+ return new Range<>(1000L, 4000L);
+ }
+
+ @Override
+ @NonNull
+ public Map<Integer, List<Size>> getSupportedPreviewOutputResolutions(
+ @NonNull String cameraId) {
+ HashMap<Integer, List<Size>> map = new HashMap<>();
+ map.put(ImageFormat.PRIVATE, getOutputSizes(ImageFormat.PRIVATE));
+ return map;
+ }
+
+ private List<Size> getOutputSizes(int imageFormat) {
+ StreamConfigurationMap map = mCameraCharacteristics
+ .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+
+ return Arrays.asList(map.getOutputSizes(imageFormat));
+ }
+
+ @Override
+ @NonNull
+ public Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(
+ @NonNull String cameraId) {
+ HashMap<Integer, List<Size>> map = new HashMap<>();
+ map.put(ImageFormat.JPEG, getOutputSizes(ImageFormat.JPEG));
+ return map;
+ }
+
+ @Override
+ @NonNull
+ public Map<Integer, List<Size>> getSupportedPostviewResolutions(
+ @NonNull Size captureSize) {
+ HashMap<Integer, List<Size>> map = new HashMap<>();
+ // Here it intentionally contains JPEG or YUV instead of both so that we can test
+ // the different path.
+ if (mPostviewFormat == ImageFormat.YUV_420_888) {
+ map.put(ImageFormat.YUV_420_888, getCompatibleYuvSizes(captureSize));
+ } else if (mPostviewFormat == ImageFormat.JPEG) {
+ // it will configure YUV stream and convert it to JPEG.
+ map.put(ImageFormat.JPEG, getCompatibleYuvSizes(captureSize));
+ }
+ return map;
+ }
+
+ private List<Size> getCompatibleYuvSizes(Size captureSize) {
+ List<Size> yuvSizes = getOutputSizes(ImageFormat.YUV_420_888);
+ List<Size> results = new ArrayList<>();
+
+ for (Size yuvSize : yuvSizes) {
+ int area = yuvSize.getWidth() * yuvSize.getHeight();
+ if (area <= captureSize.getWidth() * captureSize.getHeight()
+ && area <= 1920 * 1080 /* 1080P */) {
+ results.add(yuvSize);
+ }
+ }
+ return results;
+ }
+
+ @Override
+ @Nullable
+ public List<Size> getSupportedYuvAnalysisResolutions(
+ @NonNull String cameraId) {
+ return Collections.emptyList();
+ }
+
+ private LongCaptureSessionProcessor mNightSessionProcessor = new LongCaptureSessionProcessor();
+ @Override
+ @NonNull
+ public SessionProcessorImpl createSessionProcessor() {
+ return mNightSessionProcessor;
+ }
+
+ @Override
+ @NonNull
+ public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
+ List<CaptureRequest.Key> keys = new ArrayList<>(Arrays.asList(
+ CaptureRequest.CONTROL_AF_MODE,
+ CaptureRequest.CONTROL_AF_TRIGGER,
+ CaptureRequest.CONTROL_AF_REGIONS,
+ CaptureRequest.CONTROL_AE_REGIONS)
+ );
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ keys.add(CaptureRequest.CONTROL_ZOOM_RATIO);
+ } else {
+ keys.add(CaptureRequest.SCALER_CROP_REGION);
+ }
+ return Collections.unmodifiableList(keys);
+ }
+
+ @Override
+ @NonNull
+ public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
+ List<CaptureResult.Key> keys = new ArrayList<>(Arrays.asList(
+ CaptureResult.CONTROL_AF_MODE,
+ CaptureResult.CONTROL_AE_REGIONS,
+ CaptureResult.CONTROL_AF_REGIONS,
+ CaptureResult.CONTROL_AE_STATE,
+ CaptureResult.CONTROL_AF_STATE));
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ keys.add(CaptureResult.CONTROL_ZOOM_RATIO);
+ } else {
+ keys.add(CaptureResult.SCALER_CROP_REGION);
+ }
+ return Collections.unmodifiableList(keys);
+ }
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ return true;
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ return true;
+ }
+
+ private class LongCaptureSessionProcessor implements SessionProcessorImpl {
+ private HandlerThread mHandlerThread;
+ private Handler mBackgroundHandler;
+
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ private Map<CaptureRequest.Key<?>, Object> mParameters = new LinkedHashMap<>();
+
+ private Camera2OutputConfigImpl mPreviewOutputConfig;
+ private Camera2OutputConfigImpl mCaptureOutputConfig;
+ private Camera2OutputConfigImpl mPostviewOutputConfig;
+
+ private Surface mPostviewJpegOutputSurface;
+
+ private RequestProcessorImpl mRequestProcessor;
+ private AtomicInteger mNextCaptureSequenceId = new AtomicInteger(1);
+
+ @NonNull
+ @Override
+ public Camera2SessionConfigImpl initSession(@NonNull String cameraId,
+ @NonNull Map<String, CameraCharacteristics> cameraCharacteristicsMap,
+ @NonNull Context context, @NonNull OutputSurfaceConfigurationImpl surfaceConfigs) {
+ return initSessionInternal(
+ surfaceConfigs.getPreviewOutputSurface(),
+ surfaceConfigs.getImageCaptureOutputSurface(),
+ surfaceConfigs.getPostviewOutputSurface());
+ }
+
+ @NonNull
+ @Override
+ public Camera2SessionConfigImpl initSession(@NonNull String cameraId,
+ @NonNull Map<String, CameraCharacteristics> cameraCharacteristicsMap,
+ @NonNull Context context, @NonNull OutputSurfaceImpl previewSurfaceConfig,
+ @NonNull OutputSurfaceImpl imageCaptureSurfaceConfig,
+ @Nullable OutputSurfaceImpl imageAnalysisSurfaceConfig) {
+ return initSessionInternal(previewSurfaceConfig,
+ imageCaptureSurfaceConfig,
+ null);
+ }
+
+ private Camera2SessionConfigImpl initSessionInternal(
+ @NonNull OutputSurfaceImpl previewSurfaceConfig,
+ @NonNull OutputSurfaceImpl imageCaptureSurfaceConfig,
+ @Nullable OutputSurfaceImpl postviewSurfaceConfig) {
+
+ mHandlerThread = new HandlerThread("LongCapture advanced extender impl");
+ mHandlerThread.start();
+ mBackgroundHandler = new Handler(mHandlerThread.getLooper());
+ Camera2SessionConfigImplBuilder builder =
+ new Camera2SessionConfigImplBuilder()
+ .setSessionTemplateId(CameraDevice.TEMPLATE_PREVIEW);
+
+ // Preview
+ if (previewSurfaceConfig.getSurface() != null) {
+ mPreviewOutputConfig = Camera2OutputConfigImplBuilder
+ .newSurfaceConfig(previewSurfaceConfig.getSurface()).build();
+
+ builder.addOutputConfig(mPreviewOutputConfig);
+ }
+
+ // Image Capture
+ if (imageCaptureSurfaceConfig.getSurface() != null) {
+ mCaptureOutputConfig = Camera2OutputConfigImplBuilder.newSurfaceConfig(
+ imageCaptureSurfaceConfig.getSurface()).build();
+ builder.addOutputConfig(mCaptureOutputConfig);
+ }
+
+ // postview
+ if (postviewSurfaceConfig != null) {
+ if (postviewSurfaceConfig.getImageFormat() == ImageFormat.YUV_420_888) {
+ // For YUV format postview, it just configures the YUV surface into the camera.
+ mPostviewOutputConfig = Camera2OutputConfigImplBuilder.newSurfaceConfig(
+ postviewSurfaceConfig.getSurface()).build();
+ } else if (postviewSurfaceConfig.getImageFormat() == ImageFormat.JPEG) {
+ // For JPEG format postview, because we can't configure two JPEG streams on
+ // most devices, alternatively, we configure a YUV stream and convert it to
+ // JPEG to the postview output surface.
+ mPostviewOutputConfig = Camera2OutputConfigImplBuilder.newImageReaderConfig(
+ postviewSurfaceConfig.getSize(), ImageFormat.YUV_420_888, 2
+ ).build();
+ mPostviewJpegOutputSurface = postviewSurfaceConfig.getSurface();
+ }
+
+ builder.addOutputConfig(mPostviewOutputConfig);
+ }
+
+ return builder.build();
+ }
+
+ @Override
+ public void deInitSession() {
+ mHandlerThread.quitSafely();
+ }
+
+ @Override
+ public void setParameters(@NonNull Map<CaptureRequest.Key<?>, Object> parameters) {
+ synchronized (mLock) {
+ for (CaptureRequest.Key<?> key : parameters.keySet()) {
+ Object value = parameters.get(key);
+ if (value != null) {
+ mParameters.put(key, value);
+ }
+ }
+ }
+ }
+
+ private void applyParameters(@NonNull RequestBuilder requestBuilder) {
+ synchronized (mLock) {
+ for (CaptureRequest.Key<?> key : mParameters.keySet()) {
+ requestBuilder.setParameters(key, mParameters.get(key));
+ }
+ }
+ }
+
+ @Override
+ public int startTrigger(@NonNull Map<CaptureRequest.Key<?>, Object> triggers,
+ @NonNull CaptureCallback captureCallback) {
+ RequestBuilder builder = new RequestBuilder(mPreviewOutputConfig.getId(),
+ CameraDevice.TEMPLATE_PREVIEW);
+ applyParameters(builder);
+ builder.setParameters(
+ CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, EV_INDEX);
+
+ List<CaptureRequest.Key> availableKeys = getAvailableCaptureRequestKeys();
+ for (CaptureRequest.Key<?> key : triggers.keySet()) {
+ if (availableKeys.contains(key)) {
+ builder.setParameters(key, triggers.get(key));
+ }
+ }
+
+ int seqId = mNextCaptureSequenceId.getAndIncrement();
+
+ RequestProcessorImpl.Callback callback = new RequestProcessorImpl.Callback() {
+ @Override
+ public void onCaptureStarted(@NonNull RequestProcessorImpl.Request request,
+ long frameNumber,
+ long timestamp) {
+ captureCallback.onCaptureStarted(seqId, timestamp);
+ }
+
+ @Override
+ public void onCaptureProgressed(@NonNull RequestProcessorImpl.Request request,
+ @NonNull CaptureResult partialResult) {
+
+ }
+
+ @Override
+ public void onCaptureCompleted(@NonNull RequestProcessorImpl.Request request,
+ @NonNull TotalCaptureResult totalCaptureResult) {
+ captureCallback.onCaptureProcessStarted(seqId);
+ }
+
+ @Override
+ public void onCaptureFailed(@NonNull RequestProcessorImpl.Request request,
+ @NonNull CaptureFailure captureFailure) {
+ captureCallback.onCaptureFailed(seqId);
+ }
+
+ @Override
+ public void onCaptureBufferLost(@NonNull RequestProcessorImpl.Request request,
+ long frameNumber, int outputStreamId) {
+ captureCallback.onCaptureFailed(seqId);
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(int sequenceId, long frameNumber) {
+ captureCallback.onCaptureSequenceCompleted(seqId);
+ }
+
+ @Override
+ public void onCaptureSequenceAborted(int sequenceId) {
+ captureCallback.onCaptureSequenceAborted(seqId);
+ }
+ };
+
+ mRequestProcessor.submit(builder.build(), callback);
+ return seqId;
+ }
+
+ private int getJpegOrientation() {
+ synchronized (mLock) {
+ if (mParameters.get(CaptureRequest.JPEG_ORIENTATION) != null) {
+ return (int) mParameters.get(CaptureRequest.JPEG_ORIENTATION);
+ }
+ }
+ return 0;
+ }
+
+ @RequiresApi(21)
+ @Override
+ public void onCaptureSessionStart(@NonNull RequestProcessorImpl requestProcessor) {
+ mRequestProcessor = requestProcessor;
+
+ if (mPostviewFormat == ImageFormat.JPEG && mPostviewJpegOutputSurface != null) {
+ requestProcessor.setImageProcessor(mPostviewOutputConfig.getId(),
+ new ImageProcessorImpl() {
+ @Override
+ public void onNextImageAvailable(int outputConfigId, long timestampNs,
+ ImageReferenceImpl imageReference, String physicalCameraId) {
+ ImageProcessingUtil.convertYuvToJpegBytesIntoSurface(
+ imageReference.get(),
+ 90,
+ getJpegOrientation(),
+ mPostviewJpegOutputSurface
+ );
+
+ imageReference.decrement();
+ }
+ }
+ );
+ }
+ }
+
+ @Override
+ public void onCaptureSessionEnd() {
+
+ }
+
+ @Override
+ public int startRepeating(@NonNull CaptureCallback captureCallback) {
+ RequestBuilder builder = new RequestBuilder(mPreviewOutputConfig.getId(),
+ CameraDevice.TEMPLATE_PREVIEW);
+ applyParameters(builder);
+ builder.setParameters(
+ CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, EV_INDEX);
+ final int seqId = mNextCaptureSequenceId.getAndIncrement();
+
+ RequestProcessorImpl.Callback callback = new RequestProcessorImpl.Callback() {
+ @Override
+ public void onCaptureStarted(@NonNull RequestProcessorImpl.Request request,
+ long frameNumber,
+ long timestamp) {
+ captureCallback.onCaptureStarted(seqId, timestamp);
+ }
+
+ @Override
+ public void onCaptureProgressed(@NonNull RequestProcessorImpl.Request request,
+ @NonNull CaptureResult partialResult) {
+
+ }
+
+ @Override
+ public void onCaptureCompleted(@NonNull RequestProcessorImpl.Request request,
+ @NonNull TotalCaptureResult totalCaptureResult) {
+ captureCallback.onCaptureProcessStarted(seqId);
+ }
+
+ @Override
+ public void onCaptureFailed(@NonNull RequestProcessorImpl.Request request,
+ @NonNull CaptureFailure captureFailure) {
+ captureCallback.onCaptureFailed(seqId);
+ }
+
+ @Override
+ public void onCaptureBufferLost(@NonNull RequestProcessorImpl.Request request,
+ long frameNumber, int outputStreamId) {
+ captureCallback.onCaptureFailed(seqId);
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(int sequenceId, long frameNumber) {
+ captureCallback.onCaptureSequenceCompleted(seqId);
+ }
+
+ @Override
+ public void onCaptureSequenceAborted(int sequenceId) {
+ captureCallback.onCaptureSequenceAborted(seqId);
+ }
+ };
+
+ mRequestProcessor.setRepeating(builder.build(), callback);
+
+ return seqId;
+ }
+
+ @Override
+ public void stopRepeating() {
+ mRequestProcessor.stopRepeating();
+ }
+
+ @Override
+ public int startCapture(@NonNull CaptureCallback callback) {
+ return startCaptureInternal(false, callback);
+ }
+
+ @Override
+ public int startCaptureWithPostview(@NonNull CaptureCallback callback) {
+ return startCaptureInternal(true, callback);
+ }
+
+ private int startCaptureInternal(boolean enablePostivew,
+ @NonNull CaptureCallback captureCallback) {
+
+ // Send postview request
+ if (enablePostivew) {
+ RequestBuilder builderPostview = new RequestBuilder(mPostviewOutputConfig.getId(),
+ CameraDevice.TEMPLATE_PREVIEW);
+ applyParameters(builderPostview);
+ RequestProcessorImpl.Request postviewRequest = builderPostview.build();
+
+ mRequestProcessor.submit(postviewRequest, new DefaultRequestProcessorImpl());
+ }
+
+ captureCallback.onCaptureProcessProgressed(10);
+
+ // send still capture request
+ final int seqId = mNextCaptureSequenceId.getAndIncrement();
+ updateProcessProgressDelayed(captureCallback, 40, 1000);
+ updateProcessProgressDelayed(captureCallback, 70, 2000);
+ updateProcessProgressDelayed(captureCallback, 100, 3000);
+
+ mBackgroundHandler.postDelayed(() -> {
+ submitStillCapture(seqId, captureCallback);
+ }, 3000);
+ return seqId;
+ }
+
+ private void updateProcessProgressDelayed(CaptureCallback callback,
+ int progress, long delayInMs) {
+ mBackgroundHandler.postDelayed(() -> {
+ callback.onCaptureProcessProgressed(progress);
+ }, delayInMs);
+ }
+
+ private int submitStillCapture(int seqId, @NonNull CaptureCallback captureCallback) {
+ if (mRequestProcessor == null) {
+ return -1;
+ }
+ RequestBuilder builderStillCapture = new RequestBuilder(mCaptureOutputConfig.getId(),
+ CameraDevice.TEMPLATE_STILL_CAPTURE);
+ applyParameters(builderStillCapture);
+ RequestProcessorImpl.Request stillcaptureRequest = builderStillCapture.build();
+
+ RequestProcessorImpl.Callback callback = new RequestProcessorImpl.Callback() {
+ private boolean mOnCaptureStartedInvokded = false;
+
+ @Override
+ public void onCaptureStarted(@NonNull RequestProcessorImpl.Request request,
+ long frameNumber, long timestamp) {
+ if (!mOnCaptureStartedInvokded) {
+ mOnCaptureStartedInvokded = true;
+ captureCallback.onCaptureStarted(seqId, timestamp);
+ }
+ }
+
+ @Override
+ public void onCaptureProgressed(@NonNull RequestProcessorImpl.Request request,
+ @NonNull CaptureResult partialResult) {
+
+ }
+
+ @Override
+ public void onCaptureCompleted(@NonNull RequestProcessorImpl.Request request,
+ @NonNull TotalCaptureResult totalCaptureResult) {
+ }
+
+ @Override
+ public void onCaptureFailed(@NonNull RequestProcessorImpl.Request request,
+ @NonNull CaptureFailure captureFailure) {
+ captureCallback.onCaptureFailed(seqId);
+ }
+
+ @Override
+ public void onCaptureBufferLost(@NonNull RequestProcessorImpl.Request request,
+ long frameNumber, int outputStreamId) {
+ captureCallback.onCaptureFailed(seqId);
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(int sequenceId, long frameNumber) {
+ captureCallback.onCaptureSequenceCompleted(seqId);
+ }
+
+ @Override
+ public void onCaptureSequenceAborted(int sequenceId) {
+ captureCallback.onCaptureSequenceAborted(seqId);
+ }
+ };
+
+ mRequestProcessor.submit(stillcaptureRequest, callback);
+
+ return seqId;
+ }
+ @Override
+ public void abortCapture(int captureSequenceId) {
+
+ }
+
+ @Nullable
+ @Override
+ public Pair<Long, Long> getRealtimeCaptureLatency() {
+ return null;
+ }
+ }
+}
+
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java
index 5c32de8..415a8c5 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java
@@ -16,101 +16,19 @@
package androidx.camera.extensions.impl.advanced;
-import android.hardware.camera2.CameraCharacteristics;
-import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.CaptureResult;
-import android.util.Range;
-import android.util.Size;
+import android.graphics.ImageFormat;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import java.util.List;
-import java.util.Map;
+import androidx.annotation.RequiresApi;
/**
- * Stub advanced extender implementation for night.
- *
- * <p>This class should be implemented by OEM and deployed to the target devices.
+ * A sample night implementation for testing long processing capture. It is capable of outputting
+ * the postview(YUV format) and the process progress event. ImageAnalysis is not supported.
*
* @since 1.2
*/
-public class NightAdvancedExtenderImpl implements AdvancedExtenderImpl {
+@RequiresApi(21)
+public class NightAdvancedExtenderImpl extends LongCaptureAdvancedExtenderImpl {
public NightAdvancedExtenderImpl() {
- }
-
- @Override
- public boolean isExtensionAvailable(@NonNull String cameraId,
- @NonNull Map<String, CameraCharacteristics> characteristicsMap) {
- throw new RuntimeException("Stub, replace with implementation.");
- }
-
- @Override
- public void init(@NonNull String cameraId,
- @NonNull Map<String, CameraCharacteristics> characteristicsMap) {
- throw new RuntimeException("Stub, replace with implementation.");
- }
-
- @Override
- @Nullable
- public Range<Long> getEstimatedCaptureLatencyRange(
- @NonNull String cameraId, @Nullable Size size, int imageFormat) {
- throw new RuntimeException("Stub, replace with implementation.");
- }
-
- @Override
- @NonNull
- public Map<Integer, List<Size>> getSupportedPreviewOutputResolutions(
- @NonNull String cameraId) {
- throw new RuntimeException("Stub, replace with implementation.");
- }
-
- @Override
- @NonNull
- public Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(
- @NonNull String cameraId) {
- throw new RuntimeException("Stub, replace with implementation.");
- }
-
- @Override
- @NonNull
- public Map<Integer, List<Size>> getSupportedPostviewResolutions(
- @NonNull Size captureSize) {
- throw new RuntimeException("Stub, replace with implementation.");
- }
-
- @Override
- @Nullable
- public List<Size> getSupportedYuvAnalysisResolutions(
- @NonNull String cameraId) {
- throw new RuntimeException("Stub, replace with implementation.");
- }
-
- @Override
- @NonNull
- public SessionProcessorImpl createSessionProcessor() {
- throw new RuntimeException("Stub, replace with implementation.");
- }
-
- @Override
- @NonNull
- public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
- throw new RuntimeException("Stub, replace with implementation.");
- }
-
- @Override
- @NonNull
- public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
- throw new RuntimeException("Stub, replace with implementation.");
- }
-
- @Override
- public boolean isCaptureProcessProgressAvailable() {
- throw new RuntimeException("Stub, replace with implementation.");
- }
-
- @Override
- public boolean isPostviewAvailable() {
- throw new RuntimeException("Stub, replace with implementation.");
+ super(/* postviewFormat */ ImageFormat.YUV_420_888);
}
}
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/RequestBuilder.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/RequestBuilder.java
new file mode 100644
index 0000000..b83328b
--- /dev/null
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/advanced/RequestBuilder.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2023 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.camera.extensions.impl.advanced;
+
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+
+import androidx.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A builder to build the {@link RequestProcessorImpl.Request} instance.
+ */
+public class RequestBuilder {
+ List<Integer> mTargetOutputConfigIds = new ArrayList<>();
+ Map<CaptureRequest.Key<?>, Object> mParameters = new HashMap<>();
+ int mTemplateId = CameraDevice.TEMPLATE_PREVIEW;
+
+ /**
+ * Construct the builder with default settings.
+ */
+ public RequestBuilder() {
+ }
+
+ /**
+ * Construct the builder.
+ */
+ public RequestBuilder(int targetOutputConfigId, int templateId) {
+ addTargetOutputConfigIds(targetOutputConfigId);
+ setTemplateId(templateId);
+ }
+
+
+ /**
+ * Adds the target outputconfig ids.
+ */
+ @NonNull
+ public RequestBuilder addTargetOutputConfigIds(int targetOutputConfigId) {
+ mTargetOutputConfigIds.add(targetOutputConfigId);
+ return this;
+ }
+
+ /**
+ * Sets the parameters
+ */
+ @NonNull
+ public RequestBuilder setParameters(@NonNull CaptureRequest.Key<?> key,
+ @NonNull Object value) {
+ mParameters.put(key, value);
+ return this;
+ }
+
+ /**
+ * Sets the template id.
+ */
+ @NonNull
+ public RequestBuilder setTemplateId(int templateId) {
+ mTemplateId = templateId;
+ return this;
+ }
+
+ /**
+ * construct {@link RequestProcessorImpl.Request} instance.
+ */
+ @NonNull
+ public RequestProcessorImpl.Request build() {
+ return new RequestProcessorRequest(
+ mTargetOutputConfigIds, mParameters, mTemplateId);
+ }
+
+ static class RequestProcessorRequest implements RequestProcessorImpl.Request {
+ final List<Integer> mTargetOutputConfigIds;
+ final Map<CaptureRequest.Key<?>, Object> mParameters;
+ final int mTemplateId;
+
+ RequestProcessorRequest(List<Integer> targetOutputConfigIds,
+ Map<CaptureRequest.Key<?>, Object> parameters,
+ int templateId) {
+ mTargetOutputConfigIds = targetOutputConfigIds;
+ mParameters = parameters;
+ mTemplateId = templateId;
+ }
+
+ @Override
+ @NonNull
+ public List<Integer> getTargetOutputConfigIds() {
+ return mTargetOutputConfigIds;
+ }
+
+ @Override
+ @NonNull
+ public Map<CaptureRequest.Key<?>, Object> getParameters() {
+ return mParameters;
+ }
+
+ @Override
+ @NonNull
+ public Integer getTemplateId() {
+ return mTemplateId;
+ }
+ }
+}
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/RecorderVideoCapabilities.java b/camera/camera-video/src/main/java/androidx/camera/video/RecorderVideoCapabilities.java
index 561cf39..9d2eb01 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/RecorderVideoCapabilities.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/RecorderVideoCapabilities.java
@@ -16,11 +16,7 @@
package androidx.camera.video;
-import static androidx.camera.core.DynamicRange.BIT_DEPTH_UNSPECIFIED;
-import static androidx.camera.core.DynamicRange.ENCODING_HDR_UNSPECIFIED;
import static androidx.camera.core.DynamicRange.ENCODING_HLG;
-import static androidx.camera.core.DynamicRange.ENCODING_SDR;
-import static androidx.camera.core.DynamicRange.ENCODING_UNSPECIFIED;
import static androidx.camera.core.DynamicRange.SDR;
import static androidx.camera.core.impl.ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE;
import static androidx.camera.video.Quality.getSortedQualities;
@@ -40,6 +36,7 @@
import androidx.camera.core.CameraInfo;
import androidx.camera.core.DynamicRange;
import androidx.camera.core.impl.CameraInfoInternal;
+import androidx.camera.core.impl.DynamicRanges;
import androidx.camera.core.impl.EncoderProfilesProvider;
import androidx.camera.core.impl.EncoderProfilesProxy;
import androidx.camera.core.impl.EncoderProfilesProxy.VideoProfileProxy;
@@ -54,7 +51,6 @@
import androidx.camera.video.internal.encoder.VideoEncoderInfo;
import androidx.camera.video.internal.workaround.QualityResolutionModifiedEncoderProfilesProvider;
import androidx.camera.video.internal.workaround.QualityValidatedEncoderProfilesProvider;
-import androidx.core.util.Preconditions;
import java.util.ArrayList;
import java.util.HashMap;
@@ -241,7 +237,7 @@
@Nullable
private CapabilitiesByQuality generateCapabilitiesForNonFullySpecifiedDynamicRange(
@NonNull DynamicRange dynamicRange) {
- if (!canResolve(dynamicRange, getSupportedDynamicRanges())) {
+ if (!DynamicRanges.canResolve(dynamicRange, getSupportedDynamicRanges())) {
return null;
}
@@ -251,56 +247,4 @@
new DynamicRangeMatchedEncoderProfilesProvider(mProfilesProvider, dynamicRange);
return new CapabilitiesByQuality(constrainedProvider);
}
-
- /**
- * Returns {@code true} if the test dynamic range can resolve to the fully specified dynamic
- * range set.
- *
- * <p>A range can resolve if test fields are unspecified and appropriately match the fields
- * of the fully specified dynamic range, or the test fields exactly match the fields of
- * the fully specified dynamic range.
- */
- private static boolean canResolve(@NonNull DynamicRange dynamicRangeToTest,
- @NonNull Set<DynamicRange> fullySpecifiedDynamicRanges) {
- if (dynamicRangeToTest.isFullySpecified()) {
- return fullySpecifiedDynamicRanges.contains(dynamicRangeToTest);
- } else {
- for (DynamicRange fullySpecifiedDynamicRange : fullySpecifiedDynamicRanges) {
- if (canMatchBitDepth(dynamicRangeToTest, fullySpecifiedDynamicRange)
- && canMatchEncoding(dynamicRangeToTest, fullySpecifiedDynamicRange)) {
- return true;
- }
- }
-
- return false;
- }
- }
-
- private static boolean canMatchBitDepth(@NonNull DynamicRange dynamicRangeToTest,
- @NonNull DynamicRange fullySpecifiedDynamicRange) {
- Preconditions.checkState(fullySpecifiedDynamicRange.isFullySpecified(), "Fully specified "
- + "range is not actually fully specified.");
- if (dynamicRangeToTest.getBitDepth() == BIT_DEPTH_UNSPECIFIED) {
- return true;
- }
-
- return dynamicRangeToTest.getBitDepth() == fullySpecifiedDynamicRange.getBitDepth();
- }
-
- private static boolean canMatchEncoding(@NonNull DynamicRange dynamicRangeToTest,
- @NonNull DynamicRange fullySpecifiedDynamicRange) {
- Preconditions.checkState(fullySpecifiedDynamicRange.isFullySpecified(), "Fully specified "
- + "range is not actually fully specified.");
- int encodingToTest = dynamicRangeToTest.getEncoding();
- if (encodingToTest == ENCODING_UNSPECIFIED) {
- return true;
- }
-
- int fullySpecifiedEncoding = fullySpecifiedDynamicRange.getEncoding();
- if (encodingToTest == ENCODING_HDR_UNSPECIFIED && fullySpecifiedEncoding != ENCODING_SDR) {
- return true;
- }
-
- return encodingToTest == fullySpecifiedEncoding;
- }
}
diff --git a/camera/camera-viewfinder-core/api/current.txt b/camera/camera-viewfinder-core/api/current.txt
index e6f50d0..c56eefc 100644
--- a/camera/camera-viewfinder-core/api/current.txt
+++ b/camera/camera-viewfinder-core/api/current.txt
@@ -1 +1,68 @@
// Signature format: 4.0
+package @RequiresApi(21) androidx.camera.viewfinder.surface {
+
+ public enum ImplementationMode {
+ method public static androidx.camera.viewfinder.surface.ImplementationMode valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.camera.viewfinder.surface.ImplementationMode[] values();
+ enum_constant public static final androidx.camera.viewfinder.surface.ImplementationMode COMPATIBLE;
+ enum_constant public static final androidx.camera.viewfinder.surface.ImplementationMode PERFORMANCE;
+ field public static final androidx.camera.viewfinder.surface.ImplementationMode.Companion Companion;
+ }
+
+ public static final class ImplementationMode.Companion {
+ }
+
+ public interface ViewfinderSurfaceProvider {
+ method public void onSurfaceRequested(androidx.camera.viewfinder.surface.ViewfinderSurfaceRequest request);
+ }
+
+ public final class ViewfinderSurfaceRequest {
+ method public androidx.camera.viewfinder.surface.ImplementationMode? getImplementationMode();
+ method public int getLensFacing();
+ method public android.util.Size getResolution();
+ method public int getSensorOrientation();
+ method public void markSurfaceSafeToRelease();
+ method public void provideSurface(android.view.Surface surface, java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.camera.viewfinder.surface.ViewfinderSurfaceRequest.Result> resultListener);
+ method public boolean willNotProvideSurface();
+ property public final androidx.camera.viewfinder.surface.ImplementationMode? implementationMode;
+ property public final int lensFacing;
+ property public final android.util.Size resolution;
+ property public final int sensorOrientation;
+ field public static final androidx.camera.viewfinder.surface.ViewfinderSurfaceRequest.Companion Companion;
+ }
+
+ public static final class ViewfinderSurfaceRequest.Builder {
+ ctor public ViewfinderSurfaceRequest.Builder(android.util.Size resolution);
+ ctor public ViewfinderSurfaceRequest.Builder(androidx.camera.viewfinder.surface.ViewfinderSurfaceRequest surfaceRequest);
+ ctor public ViewfinderSurfaceRequest.Builder(androidx.camera.viewfinder.surface.ViewfinderSurfaceRequest.Builder builder);
+ method public androidx.camera.viewfinder.surface.ViewfinderSurfaceRequest build();
+ method public androidx.camera.viewfinder.surface.ViewfinderSurfaceRequest.Builder setImplementationMode(androidx.camera.viewfinder.surface.ImplementationMode? implementationMode);
+ method public androidx.camera.viewfinder.surface.ViewfinderSurfaceRequest.Builder setLensFacing(int lensFacing);
+ method public androidx.camera.viewfinder.surface.ViewfinderSurfaceRequest.Builder setSensorOrientation(int sensorOrientation);
+ }
+
+ public static final class ViewfinderSurfaceRequest.Companion {
+ }
+
+ @com.google.auto.value.AutoValue public static final class ViewfinderSurfaceRequest.Result {
+ ctor public ViewfinderSurfaceRequest.Result(int code, android.view.Surface surface);
+ method public int component1();
+ method public android.view.Surface component2();
+ method public androidx.camera.viewfinder.surface.ViewfinderSurfaceRequest.Result copy(int code, android.view.Surface surface);
+ method public int getCode();
+ method public android.view.Surface getSurface();
+ property public final int code;
+ property public final android.view.Surface surface;
+ field public static final androidx.camera.viewfinder.surface.ViewfinderSurfaceRequest.Result.Companion Companion;
+ field public static final int RESULT_INVALID_SURFACE = 2; // 0x2
+ field public static final int RESULT_REQUEST_CANCELLED = 1; // 0x1
+ field public static final int RESULT_SURFACE_ALREADY_PROVIDED = 3; // 0x3
+ field public static final int RESULT_SURFACE_USED_SUCCESSFULLY = 0; // 0x0
+ field public static final int RESULT_WILL_NOT_PROVIDE_SURFACE = 4; // 0x4
+ }
+
+ public static final class ViewfinderSurfaceRequest.Result.Companion {
+ }
+
+}
+
diff --git a/camera/camera-viewfinder-core/api/restricted_current.txt b/camera/camera-viewfinder-core/api/restricted_current.txt
index e6f50d0..c56eefc 100644
--- a/camera/camera-viewfinder-core/api/restricted_current.txt
+++ b/camera/camera-viewfinder-core/api/restricted_current.txt
@@ -1 +1,68 @@
// Signature format: 4.0
+package @RequiresApi(21) androidx.camera.viewfinder.surface {
+
+ public enum ImplementationMode {
+ method public static androidx.camera.viewfinder.surface.ImplementationMode valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.camera.viewfinder.surface.ImplementationMode[] values();
+ enum_constant public static final androidx.camera.viewfinder.surface.ImplementationMode COMPATIBLE;
+ enum_constant public static final androidx.camera.viewfinder.surface.ImplementationMode PERFORMANCE;
+ field public static final androidx.camera.viewfinder.surface.ImplementationMode.Companion Companion;
+ }
+
+ public static final class ImplementationMode.Companion {
+ }
+
+ public interface ViewfinderSurfaceProvider {
+ method public void onSurfaceRequested(androidx.camera.viewfinder.surface.ViewfinderSurfaceRequest request);
+ }
+
+ public final class ViewfinderSurfaceRequest {
+ method public androidx.camera.viewfinder.surface.ImplementationMode? getImplementationMode();
+ method public int getLensFacing();
+ method public android.util.Size getResolution();
+ method public int getSensorOrientation();
+ method public void markSurfaceSafeToRelease();
+ method public void provideSurface(android.view.Surface surface, java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.camera.viewfinder.surface.ViewfinderSurfaceRequest.Result> resultListener);
+ method public boolean willNotProvideSurface();
+ property public final androidx.camera.viewfinder.surface.ImplementationMode? implementationMode;
+ property public final int lensFacing;
+ property public final android.util.Size resolution;
+ property public final int sensorOrientation;
+ field public static final androidx.camera.viewfinder.surface.ViewfinderSurfaceRequest.Companion Companion;
+ }
+
+ public static final class ViewfinderSurfaceRequest.Builder {
+ ctor public ViewfinderSurfaceRequest.Builder(android.util.Size resolution);
+ ctor public ViewfinderSurfaceRequest.Builder(androidx.camera.viewfinder.surface.ViewfinderSurfaceRequest surfaceRequest);
+ ctor public ViewfinderSurfaceRequest.Builder(androidx.camera.viewfinder.surface.ViewfinderSurfaceRequest.Builder builder);
+ method public androidx.camera.viewfinder.surface.ViewfinderSurfaceRequest build();
+ method public androidx.camera.viewfinder.surface.ViewfinderSurfaceRequest.Builder setImplementationMode(androidx.camera.viewfinder.surface.ImplementationMode? implementationMode);
+ method public androidx.camera.viewfinder.surface.ViewfinderSurfaceRequest.Builder setLensFacing(int lensFacing);
+ method public androidx.camera.viewfinder.surface.ViewfinderSurfaceRequest.Builder setSensorOrientation(int sensorOrientation);
+ }
+
+ public static final class ViewfinderSurfaceRequest.Companion {
+ }
+
+ @com.google.auto.value.AutoValue public static final class ViewfinderSurfaceRequest.Result {
+ ctor public ViewfinderSurfaceRequest.Result(int code, android.view.Surface surface);
+ method public int component1();
+ method public android.view.Surface component2();
+ method public androidx.camera.viewfinder.surface.ViewfinderSurfaceRequest.Result copy(int code, android.view.Surface surface);
+ method public int getCode();
+ method public android.view.Surface getSurface();
+ property public final int code;
+ property public final android.view.Surface surface;
+ field public static final androidx.camera.viewfinder.surface.ViewfinderSurfaceRequest.Result.Companion Companion;
+ field public static final int RESULT_INVALID_SURFACE = 2; // 0x2
+ field public static final int RESULT_REQUEST_CANCELLED = 1; // 0x1
+ field public static final int RESULT_SURFACE_ALREADY_PROVIDED = 3; // 0x3
+ field public static final int RESULT_SURFACE_USED_SUCCESSFULLY = 0; // 0x0
+ field public static final int RESULT_WILL_NOT_PROVIDE_SURFACE = 4; // 0x4
+ }
+
+ public static final class ViewfinderSurfaceRequest.Result.Companion {
+ }
+
+}
+
diff --git a/camera/camera-viewfinder-core/src/main/java/androidx/camera/viewfinder/impl/package-info.java b/camera/camera-viewfinder-core/src/main/java/androidx/camera/viewfinder/impl/package-info.java
new file mode 100644
index 0000000..7b9fae3
--- /dev/null
+++ b/camera/camera-viewfinder-core/src/main/java/androidx/camera/viewfinder/impl/package-info.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2023 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.
+ */
+
+/**
+ *
+ */
+@RequiresApi(21)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+package androidx.camera.viewfinder.impl;
+
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
diff --git a/camera/camera-viewfinder-core/src/main/java/androidx/camera/viewfinder/impl/surface/DeferredSurface.kt b/camera/camera-viewfinder-core/src/main/java/androidx/camera/viewfinder/impl/surface/DeferredSurface.kt
new file mode 100644
index 0000000..6b27dd9
--- /dev/null
+++ b/camera/camera-viewfinder-core/src/main/java/androidx/camera/viewfinder/impl/surface/DeferredSurface.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2023 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.camera.viewfinder.impl.surface
+
+import android.view.Surface
+import androidx.annotation.GuardedBy
+import androidx.camera.impl.utils.Logger
+import androidx.camera.impl.utils.futures.Futures.nonCancellationPropagating
+import androidx.concurrent.futures.CallbackToFutureAdapter
+import com.google.common.util.concurrent.ListenableFuture
+
+/**
+ * A class for creating and tracking use of a [Surface] in an asynchronous manner.
+ */
+abstract class DeferredSurface : AutoCloseable {
+ private val lock = Any()
+ private val terminationFuture: ListenableFuture<Void?>
+
+ @GuardedBy("mLock")
+ private var closed = false
+
+ @GuardedBy("mLock")
+ private var terminationCompleterInternal: CallbackToFutureAdapter.Completer<Void?>? = null
+
+ init {
+ terminationFuture =
+ CallbackToFutureAdapter.getFuture {
+ synchronized(lock) {
+ terminationCompleterInternal = it
+ }
+ "ViewfinderSurface-termination(" + this@DeferredSurface + ")"
+ }
+ }
+
+ fun getSurfaceAsync(): ListenableFuture<Surface> {
+ return provideSurfaceAsync()
+ }
+
+ fun getTerminationFutureAsync(): ListenableFuture<Void?> {
+ return nonCancellationPropagating(terminationFuture)
+ }
+
+ /**
+ * Close the surface.
+ *
+ *
+ * After closing, the underlying surface resources can be safely released by
+ * [SurfaceView] or [TextureView] implementation.
+ */
+ override fun close() {
+ var terminationCompleter: CallbackToFutureAdapter.Completer<Void?>? = null
+ synchronized(lock) {
+ if (!closed) {
+ closed = true
+ terminationCompleter = terminationCompleterInternal
+ terminationCompleterInternal = null
+ Logger.d(
+ TAG,
+ "surface closed, closed=true $this"
+ )
+ }
+ }
+ if (terminationCompleter != null) {
+ terminationCompleter!!.set(null)
+ }
+ }
+
+ protected abstract fun provideSurfaceAsync(): ListenableFuture<Surface>
+
+ /**
+ * The exception that is returned by the ListenableFuture of [getSurfaceAsync] if the
+ * deferrable surface is unable to produce a [Surface].
+ */
+ class SurfaceUnavailableException(message: String) : Exception(message)
+ companion object {
+ private const val TAG = "DeferredSurface"
+ }
+}
diff --git a/camera/camera-viewfinder-core/src/main/java/androidx/camera/viewfinder/surface/ImplementationMode.kt b/camera/camera-viewfinder-core/src/main/java/androidx/camera/viewfinder/surface/ImplementationMode.kt
new file mode 100644
index 0000000..6afd5e6
--- /dev/null
+++ b/camera/camera-viewfinder-core/src/main/java/androidx/camera/viewfinder/surface/ImplementationMode.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2023 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.camera.viewfinder.surface
+
+import android.view.SurfaceView
+import android.view.TextureView
+import androidx.annotation.RestrictTo
+
+/**
+ * The implementation mode of a viewfinder.
+ *
+ *
+ * User preference on how the viewfinder should render the viewfinder.
+ * The viewfinder is displayed with either a [SurfaceView] or a
+ * [TextureView]. A [SurfaceView] is generally better than a [TextureView]
+ * when it comes to certain key metrics, including power and latency. On the other hand,
+ * [TextureView] is better supported by a wider range of devices. The option is used to decide what
+ * is the best internal implementation given the device capabilities and user configurations.
+ */
+enum class ImplementationMode(private val id: Int) {
+ /**
+ * Use a [SurfaceView] for the viewfinder when possible. A SurfaceView has somewhat
+ * lower latency and less performance and power overhead than a TextureView. [SurfaceView]
+ * offers more control on a single drawing board, but does not support certain animations.
+ */
+ PERFORMANCE(0),
+
+ /**
+ * Use a [TextureView] for the viewfinder.
+ */
+ COMPATIBLE(1);
+
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ fun getId(): Int {
+ return id
+ }
+
+ companion object {
+ /**
+ * Convert an Int id to ImplementationMode
+ * @throws IllegalArgumentException if id doesn't below to any ImplementationMode
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @JvmStatic
+ fun fromId(id: Int): ImplementationMode {
+ for (implementationMode in ImplementationMode.values()) {
+ if (implementationMode.id == id) {
+ return implementationMode
+ }
+ }
+ throw IllegalArgumentException("Unknown implementation mode id $id")
+ }
+ }
+}
diff --git a/camera/camera-viewfinder-core/src/main/java/androidx/camera/viewfinder/surface/ViewfinderSurfaceProvider.kt b/camera/camera-viewfinder-core/src/main/java/androidx/camera/viewfinder/surface/ViewfinderSurfaceProvider.kt
new file mode 100644
index 0000000..c98d532
--- /dev/null
+++ b/camera/camera-viewfinder-core/src/main/java/androidx/camera/viewfinder/surface/ViewfinderSurfaceProvider.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 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.camera.viewfinder.surface
+
+import android.view.Surface
+
+/**
+ * A interface implemented by the application to provide a [Surface] for viewfinder.
+ *
+ * This interface is implemented by the application to provide a [Surface]. This
+ * will be called by application when it needs a Surface for viewfinder. It also signals when the
+ * Surface is no longer in use.
+ */
+interface ViewfinderSurfaceProvider {
+ /**
+ * Called when a new [Surface] has been requested by the camera.
+ *
+ *
+ * This is called every time a new surface is required to keep the viewfinder running.
+ * The camera may repeatedly request surfaces, but only a single request will be active at a
+ * time.
+ *
+ * @param request the request for a surface which contains the requirements of the
+ * surface and methods for completing the request.
+ */
+ fun onSurfaceRequested(request: ViewfinderSurfaceRequest)
+}
diff --git a/camera/camera-viewfinder-core/src/main/java/androidx/camera/viewfinder/surface/ViewfinderSurfaceRequest.kt b/camera/camera-viewfinder-core/src/main/java/androidx/camera/viewfinder/surface/ViewfinderSurfaceRequest.kt
new file mode 100644
index 0000000..456280db
--- /dev/null
+++ b/camera/camera-viewfinder-core/src/main/java/androidx/camera/viewfinder/surface/ViewfinderSurfaceRequest.kt
@@ -0,0 +1,631 @@
+/*
+ * Copyright 2023 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.camera.viewfinder.surface
+
+import android.annotation.SuppressLint
+import android.hardware.camera2.CameraMetadata
+import android.util.Size
+import android.view.Surface
+import androidx.annotation.IntDef
+import androidx.annotation.RestrictTo
+import androidx.camera.impl.utils.Logger
+import androidx.camera.impl.utils.executor.CameraExecutors
+import androidx.camera.impl.utils.futures.FutureCallback
+import androidx.camera.impl.utils.futures.Futures
+import androidx.camera.viewfinder.impl.surface.DeferredSurface
+import androidx.concurrent.futures.CallbackToFutureAdapter
+import androidx.core.util.Consumer
+import androidx.core.util.Preconditions
+import com.google.auto.value.AutoValue
+import com.google.common.util.concurrent.ListenableFuture
+import java.util.concurrent.CancellationException
+import java.util.concurrent.ExecutionException
+import java.util.concurrent.Executor
+import java.util.concurrent.atomic.AtomicReference
+
+/**
+ * The request to get a [Surface] to display camera feed.
+ *
+ *
+ * This request contains requirements for the surface resolution and camera
+ * device information from [CameraCharacteristics].
+ *
+ * Calling [ViewfinderSurfaceRequest.markSurfaceSafeToRelease] will notify the
+ * surface provider that the surface is not needed and related resources can be released.
+ *
+ * Creates a new surface request with surface resolution, camera device, lens facing and
+ * sensor orientation information.
+ *
+ * @param resolution The requested surface resolution. It is the output surface size
+ * the camera is configured with, instead of {@link CameraViewfinder}
+ * view size.
+ * @param lensFacing The camera lens facing.
+ * @param sensorOrientation THe camera sensor orientation.
+ * @param implementationMode The {@link ImplementationMode} to apply to the viewfinder.
+ */
+class ViewfinderSurfaceRequest internal constructor(
+ val resolution: Size,
+ @LensFacingValue val lensFacing: Int,
+ @SensorOrientationDegreesValue val sensorOrientation: Int,
+ val implementationMode: ImplementationMode?
+) {
+ private val mInternalDeferredSurface: DeferredSurface
+ private val cancellationCompleter: CallbackToFutureAdapter.Completer<Void?>
+ private val sessionStatusFuture: ListenableFuture<Void?>
+ private val surfaceCompleter: CallbackToFutureAdapter.Completer<Surface>
+
+ private val surfaceFutureAsync: ListenableFuture<Surface>
+
+ init {
+ // To ensure concurrency and ordering, operations are chained. Completion can only be
+ // triggered externally by the top-level completer (mSurfaceCompleter). The other future
+ // completers are only completed by callbacks set up within the constructor of this class
+ // to ensure correct ordering of events.
+
+ // Cancellation listener must be called last to ensure the result can be retrieved from
+ // the session listener.
+ val surfaceRequestString =
+ "SurfaceRequest[size: " + resolution + ", id: " + this.hashCode() + "]"
+ val cancellationCompleterRef =
+ AtomicReference<CallbackToFutureAdapter.Completer<Void?>?>(null)
+ val requestCancellationFuture =
+ CallbackToFutureAdapter.getFuture {
+ cancellationCompleterRef.set(it)
+ "$surfaceRequestString-cancellation"
+ }
+ val requestCancellationCompleter =
+ Preconditions.checkNotNull(cancellationCompleterRef.get())
+ cancellationCompleter = requestCancellationCompleter
+
+ // Surface session status future completes and is responsible for finishing the
+ // cancellation listener.
+ val sessionStatusCompleterRef =
+ AtomicReference<CallbackToFutureAdapter.Completer<Void?>?>(null)
+ sessionStatusFuture =
+ CallbackToFutureAdapter.getFuture<Void?> {
+ sessionStatusCompleterRef.set(it)
+ "$surfaceRequestString-status"
+ }
+ Futures.addCallback<Void?>(sessionStatusFuture, object : FutureCallback<Void?> {
+ override fun onSuccess(result: Void?) {
+ // Cancellation didn't occur, so complete the cancellation future. There
+ // shouldn't ever be any standard listeners on this future, so nothing should be
+ // invoked.
+ Preconditions.checkState(requestCancellationCompleter.set(null))
+ }
+
+ override fun onFailure(t: Throwable) {
+ if (t is RequestCancelledException) {
+ // Cancellation occurred. Notify listeners.
+ Preconditions.checkState(
+ requestCancellationFuture.cancel(false)
+ )
+ } else {
+ // Cancellation didn't occur, complete the future so cancellation listeners
+ // are not invoked.
+ Preconditions.checkState(requestCancellationCompleter.set(null))
+ }
+ }
+ }, CameraExecutors.directExecutor())
+
+ // Create the surface future/completer. This will be used to complete the rest of the
+ // future chain and can be set externally via SurfaceRequest methods.
+ val sessionStatusCompleter = Preconditions.checkNotNull(sessionStatusCompleterRef.get())
+ val surfaceCompleterRef =
+ AtomicReference<CallbackToFutureAdapter.Completer<Surface>?>(null)
+ surfaceFutureAsync =
+ CallbackToFutureAdapter.getFuture {
+ surfaceCompleterRef.set(it)
+ "$surfaceRequestString-Surface"
+ }
+ surfaceCompleter = Preconditions.checkNotNull(surfaceCompleterRef.get())
+
+ // Create the viewfinder surface which will be used for communicating when the
+ // camera and consumer are done using the surface. Note this anonymous inner class holds
+ // an implicit reference to the ViewfinderSurfaceRequest. This is by design, and ensures the
+ // ViewfinderSurfaceRequest and all contained future completers will not be garbage
+ // collected as long as the ViewfinderSurface is referenced externally (via
+ // getViewfinderSurface()).
+ mInternalDeferredSurface =
+ object : DeferredSurface() {
+ override fun provideSurfaceAsync(): ListenableFuture<Surface> {
+ Logger.d(
+ TAG,
+ "mInternalViewfinderSurface + $this provideSurface"
+ )
+ return surfaceFutureAsync
+ }
+ }
+ val terminationFuture: ListenableFuture<Void?> =
+ mInternalDeferredSurface.getTerminationFutureAsync()
+
+ // Propagate surface completion to the session future.
+ Futures.addCallback<Surface>(surfaceFutureAsync, object : FutureCallback<Surface?> {
+ override fun onSuccess(result: Surface?) {
+ // On successful setting of a surface, defer completion of the session future to
+ // the ViewfinderSurface termination future. Once that future completes, then it
+ // is safe to release the Surface and associated resources.
+ Futures.propagate(terminationFuture, sessionStatusCompleter)
+ }
+
+ override fun onFailure(t: Throwable) {
+ // Translate cancellation into a SurfaceRequestCancelledException. Other
+ // exceptions mean either the request was completed via willNotProvideSurface() or a
+ // programming error occurred. In either case, the user will never see the
+ // session future (an immediate future will be returned instead), so complete the
+ // future so cancellation listeners are never called.
+ if (t is CancellationException) {
+ Preconditions.checkState(
+ sessionStatusCompleter.setException(
+ RequestCancelledException(
+ "$surfaceRequestString cancelled.", t
+ )
+ )
+ )
+ } else {
+ sessionStatusCompleter.set(null)
+ }
+ }
+ }, CameraExecutors.directExecutor())
+
+ // If the viewfinder surface is terminated, there are two cases:
+ // 1. The surface has not yet been provided to the camera (or marked as 'will not
+ // complete'). Treat this as if the surface request has been cancelled.
+ // 2. The surface was already provided to the camera. In this case the camera is now
+ // finished with the surface, so cancelling the surface future below will be a no-op.
+ terminationFuture.addListener({
+ Logger.d(
+ TAG,
+ ("mInternalViewfinderSurface + " + mInternalDeferredSurface + " " +
+ "terminateFuture triggered")
+ )
+ surfaceFutureAsync.cancel(true)
+ }, CameraExecutors.directExecutor())
+ }
+
+ /**
+ * Closes the viewfinder surface to mark it as safe to release.
+ *
+ *
+ * This method should be called by the user when the requested surface is not needed and
+ * related resources can be released.
+ */
+ fun markSurfaceSafeToRelease() {
+ mInternalDeferredSurface.close()
+ }
+
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ fun getSurface(): DeferredSurface {
+ return mInternalDeferredSurface
+ }
+
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @SuppressLint("PairedRegistration")
+ fun addRequestCancellationListener(
+ executor: Executor,
+ listener: Runnable
+ ) {
+ cancellationCompleter.addCancellationListener(listener, executor)
+ }
+
+ /**
+ * Completes the request for a [Surface] if it has not already been
+ * completed or cancelled.
+ *
+ *
+ * Once the camera no longer needs the provided surface, the `resultListener` will be
+ * invoked with a [Result] containing [Result.RESULT_SURFACE_USED_SUCCESSFULLY].
+ * At this point it is safe to release the surface and any underlying resources. Releasing
+ * the surface before receiving this signal may cause undesired behavior on lower API levels.
+ *
+ *
+ * If the request is cancelled by the camera before successfully attaching the
+ * provided surface to the camera, then the `resultListener` will be invoked with a
+ * [Result] containing [Result.RESULT_REQUEST_CANCELLED].
+ *
+ *
+ * If the request was previously completed via [.willNotProvideSurface], then
+ * `resultListener` will be invoked with a [Result] containing
+ * [Result.RESULT_WILL_NOT_PROVIDE_SURFACE].
+ *
+ *
+ * Upon returning from this method, the surface request is guaranteed to be complete.
+ * However, only the `resultListener` provided to the first invocation of this method
+ * should be used to track when the provided [Surface] is no longer in use by the
+ * camera, as subsequent invocations will always invoke the `resultListener` with a
+ * [Result] containing [Result.RESULT_SURFACE_ALREADY_PROVIDED].
+ *
+ * @param surface The surface which will complete the request.
+ * @param executor Executor used to execute the `resultListener`.
+ * @param resultListener Listener used to track how the surface is used by the camera in
+ * response to being provided by this method.
+ */
+ fun provideSurface(
+ surface: Surface,
+ executor: Executor,
+ resultListener: Consumer<Result?>
+ ) {
+ if (surfaceCompleter.set(surface) || surfaceFutureAsync.isCancelled) {
+ // Session will be pending completion (or surface request was cancelled). Return the
+ // session future.
+ Futures.addCallback(sessionStatusFuture, object : FutureCallback<Void?> {
+ override fun onSuccess(result: Void?) {
+ resultListener.accept(
+ Result(
+ Result.RESULT_SURFACE_USED_SUCCESSFULLY,
+ surface
+ )
+ )
+ }
+
+ override fun onFailure(t: Throwable) {
+ Preconditions.checkState(
+ t is RequestCancelledException, ("Camera " +
+ "surface session should only fail with request " +
+ "cancellation. Instead failed due to:\n" + t)
+ )
+ resultListener.accept(Result(Result.RESULT_REQUEST_CANCELLED, surface))
+ }
+ }, executor)
+ } else {
+ // Surface request is already complete
+ Preconditions.checkState(surfaceFutureAsync.isDone)
+ try {
+ surfaceFutureAsync.get()
+ // Getting this far means the surface was already provided.
+ executor.execute {
+ resultListener.accept(
+ Result(
+ Result.RESULT_SURFACE_ALREADY_PROVIDED,
+ surface
+ )
+ )
+ }
+ } catch (e: InterruptedException) {
+ executor.execute {
+ resultListener.accept(
+ Result(
+ Result.RESULT_WILL_NOT_PROVIDE_SURFACE,
+ surface
+ )
+ )
+ }
+ } catch (e: ExecutionException) {
+ executor.execute {
+ resultListener.accept(
+ Result(
+ Result.RESULT_WILL_NOT_PROVIDE_SURFACE,
+ surface
+ )
+ )
+ }
+ }
+ }
+ }
+
+ /**
+ * Signals that the request will never be fulfilled.
+ *
+ *
+ * This may be called in the case where the application may be shutting down and a
+ * surface will never be produced to fulfill the request.
+ *
+ *
+ * This will be called by CameraViewfinder as soon as it is known that the request will not
+ * be fulfilled. Failure to complete the SurfaceRequest via `willNotProvideSurface()`
+ * or [.provideSurface] may cause long delays in shutting
+ * down the camera.
+ *
+ *
+ * Upon returning from this method, the request is guaranteed to be complete, regardless
+ * of the return value. If the request was previously successfully completed by
+ * [.provideSurface], invoking this method will return
+ * `false`, and will have no effect on how the surface is used by the camera.
+ *
+ * @return `true` if this call to `willNotProvideSurface()` successfully
+ * completes the request, i.e., the request has not already been completed via
+ * [.provideSurface] or by a previous call to
+ * `willNotProvideSurface()` and has not already been cancelled by the camera.
+ */
+ fun willNotProvideSurface(): Boolean {
+ return surfaceCompleter.setException(
+ DeferredSurface.SurfaceUnavailableException(
+ ("Surface request will not complete.")
+ )
+ )
+ }
+
+ /**
+ * Builder for [ViewfinderSurfaceRequest].
+ */
+ class Builder {
+ private val resolution: Size
+
+ @LensFacingValue
+ private var lensFacing = CameraMetadata.LENS_FACING_BACK
+
+ @SensorOrientationDegreesValue
+ private var sensorOrientation = 0
+ private var implementationMode: ImplementationMode? = null
+
+ /**
+ * Constructor for [Builder].
+ *
+ *
+ * Creates a builder with viewfinder resolution.
+ *
+ * @param resolution viewfinder resolution.
+ */
+ constructor(resolution: Size) {
+ this.resolution = resolution
+ }
+
+ /**
+ * Constructor for [Builder].
+ *
+ *
+ * Creates a builder with other builder instance. The returned builder will be
+ * pre-populated with the state of the provided builder.
+ *
+ * @param builder [Builder] instance.
+ */
+ constructor(builder: Builder) {
+ resolution = builder.resolution
+ implementationMode = builder.implementationMode
+ lensFacing = builder.lensFacing
+ sensorOrientation = builder.sensorOrientation
+ }
+
+ /**
+ * Constructor for [Builder].
+ *
+ *
+ * Creates a builder with other [ViewfinderSurfaceRequest] instance. The
+ * returned builder will be pre-populated with the state of the provided
+ * [ViewfinderSurfaceRequest] instance.
+ *
+ * @param surfaceRequest [ViewfinderSurfaceRequest] instance.
+ */
+ constructor(surfaceRequest: ViewfinderSurfaceRequest) {
+ resolution = surfaceRequest.resolution
+ implementationMode = surfaceRequest.implementationMode
+ lensFacing = surfaceRequest.lensFacing
+ sensorOrientation = surfaceRequest.sensorOrientation
+ }
+
+ /**
+ * Sets the [ImplementationMode].
+ *
+ *
+ * **Possible values:**
+ *
+ * * [PERFORMANCE][ImplementationMode.PERFORMANCE]
+ * * [COMPATIBLE][ImplementationMode.COMPATIBLE]
+ *
+ * @param implementationMode The [ImplementationMode].
+ * @return This builder.
+ */
+ fun setImplementationMode(implementationMode: ImplementationMode?): Builder {
+ this.implementationMode = implementationMode
+ return this
+ }
+
+ /**
+ * Sets the lens facing.
+ *
+ *
+ * **Possible values:**
+ *
+ * * [FRONT][CameraMetadata.LENS_FACING_FRONT]
+ * * [BACK][CameraMetadata.LENS_FACING_BACK]
+ * * [EXTERNAL][CameraMetadata.LENS_FACING_EXTERNAL]
+ *
+ *
+ *
+ * The value can be retrieved from [CameraCharacteristics] by key
+ * [CameraCharacteristics.LENS_FACING]. If not set,
+ * [CameraMetadata.LENS_FACING_BACK] will be used by default.
+ *
+ * @param lensFacing The lens facing.
+ * @return This builder.
+ */
+ fun setLensFacing(@LensFacingValue lensFacing: Int): Builder {
+ this.lensFacing = lensFacing
+ return this
+ }
+
+ /**
+ * Sets the sensor orientation.
+ *
+ *
+ * **Range of valid values:**<br></br>
+ * 0, 90, 180, 270
+ *
+ *
+ * The value can be retrieved from [CameraCharacteristics] by key
+ * [CameraCharacteristics.SENSOR_ORIENTATION]. If it is not
+ * set, 0 will be used by default.
+ *
+ * @param sensorOrientation
+ * @return this builder.
+ */
+ fun setSensorOrientation(@SensorOrientationDegreesValue sensorOrientation: Int): Builder {
+ this.sensorOrientation = sensorOrientation
+ return this
+ }
+
+ /**
+ * Builds the [ViewfinderSurfaceRequest].
+ * @return the instance of [ViewfinderSurfaceRequest].
+ *
+ * @throws IllegalArgumentException
+ */
+ fun build(): ViewfinderSurfaceRequest {
+ if ((lensFacing != CameraMetadata.LENS_FACING_FRONT
+ ) && (lensFacing != CameraMetadata.LENS_FACING_BACK
+ ) && (lensFacing != CameraMetadata.LENS_FACING_EXTERNAL)
+ ) {
+ throw IllegalArgumentException(
+ ("Lens facing value: $lensFacing is invalid")
+ )
+ }
+ if ((sensorOrientation != 0
+ ) && (sensorOrientation != 90
+ ) && (sensorOrientation != 180
+ ) && (sensorOrientation != 270)
+ ) {
+ throw IllegalArgumentException(
+ ("Sensor orientation value: $sensorOrientation is invalid")
+ )
+ }
+ return ViewfinderSurfaceRequest(
+ resolution,
+ lensFacing,
+ sensorOrientation,
+ implementationMode
+ )
+ }
+ }
+
+ internal class RequestCancelledException(message: String, cause: Throwable) :
+ RuntimeException(message, cause)
+
+ /**
+ * Result of providing a surface to a [ViewfinderSurfaceRequest] via
+ * [.provideSurface].
+ *
+ * Can be used to compare to results returned to `resultListener` in
+ * [.provideSurface].
+ *
+ * @param code One of [.RESULT_SURFACE_USED_SUCCESSFULLY],
+ * [.RESULT_REQUEST_CANCELLED], [.RESULT_INVALID_SURFACE],
+ * [.RESULT_SURFACE_ALREADY_PROVIDED], or
+ * [.RESULT_WILL_NOT_PROVIDE_SURFACE].
+ * @param surface The [Surface] used to complete the [ViewfinderSurfaceRequest].
+ */
+ @AutoValue
+ data class Result(@ResultCode val code: Int, val surface: Surface) {
+ /**
+ * Possible result codes.
+ *
+ */
+ @IntDef(
+ RESULT_SURFACE_USED_SUCCESSFULLY,
+ RESULT_REQUEST_CANCELLED,
+ RESULT_INVALID_SURFACE,
+ RESULT_SURFACE_ALREADY_PROVIDED,
+ RESULT_WILL_NOT_PROVIDE_SURFACE
+ )
+ @Retention(
+ AnnotationRetention.SOURCE
+ )
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ annotation class ResultCode()
+ companion object {
+ /**
+ * Provided surface was successfully used by the camera and eventually detached once no
+ * longer needed by the camera.
+ *
+ *
+ * This result denotes that it is safe to release the [Surface] and any underlying
+ * resources.
+ *
+ *
+ * For compatibility reasons, the [Surface] object should not be reused by
+ * future [SurfaceRequests][ViewfinderSurfaceRequest], and a new surface should be
+ * created instead.
+ */
+ const val RESULT_SURFACE_USED_SUCCESSFULLY = 0
+
+ /**
+ * Provided surface was never attached to the camera due to the
+ * [ViewfinderSurfaceRequest] being cancelled by the camera.
+ *
+ *
+ * It is safe to release or reuse [Surface], assuming it was not previously
+ * attached to a camera via [.provideSurface]. If
+ * reusing the surface for a future surface request, it should be verified that the
+ * surface still matches the resolution specified by
+ * [ViewfinderSurfaceRequest.resolution].
+ */
+ const val RESULT_REQUEST_CANCELLED = 1
+
+ /**
+ * Provided surface could not be used by the camera.
+ *
+ *
+ * This is likely due to the [Surface] being closed prematurely or the resolution
+ * of the surface not matching the resolution specified by
+ * [ViewfinderSurfaceRequest.resolution].
+ */
+ const val RESULT_INVALID_SURFACE = 2
+
+ /**
+ * Surface was not attached to the camera through this invocation of
+ * [.provideSurface] due to the
+ * [ViewfinderSurfaceRequest] already being complete with a surface.
+ *
+ *
+ * The [ViewfinderSurfaceRequest] has already been completed by a previous
+ * invocation of [.provideSurface].
+ *
+ *
+ * It is safe to release or reuse the [Surface], assuming it was not previously
+ * attached to a camera via [.provideSurface].
+ */
+ const val RESULT_SURFACE_ALREADY_PROVIDED = 3
+
+ /**
+ * Surface was not attached to the camera through this invocation of
+ * [.provideSurface] due to the
+ * [ViewfinderSurfaceRequest] already being marked as "will not provide surface".
+ *
+ *
+ * The [ViewfinderSurfaceRequest] has already been marked as 'will not provide
+ * surface' by a previous invocation of [.willNotProvideSurface].
+ *
+ *
+ * It is safe to release or reuse the [Surface], assuming it was not previously
+ * attached to a camera via [.provideSurface].
+ */
+ const val RESULT_WILL_NOT_PROVIDE_SURFACE = 4
+ }
+ }
+
+ /**
+ * Valid integer sensor orientation degrees values.
+ */
+ @IntDef(0, 90, 180, 270)
+ @Retention(AnnotationRetention.SOURCE)
+ internal annotation class SensorOrientationDegreesValue()
+
+ /**
+ * Valid integer sensor orientation degrees values.
+ */
+ @IntDef(
+ CameraMetadata.LENS_FACING_FRONT,
+ CameraMetadata.LENS_FACING_BACK,
+ CameraMetadata.LENS_FACING_EXTERNAL
+ )
+ @Retention(
+ AnnotationRetention.SOURCE
+ )
+ internal annotation class LensFacingValue()
+ companion object {
+ private const val TAG = "SurfaceRequest"
+ }
+}
diff --git a/camera/camera-viewfinder-core/src/main/java/androidx/camera/viewfinder/surface/package-info.java b/camera/camera-viewfinder-core/src/main/java/androidx/camera/viewfinder/surface/package-info.java
new file mode 100644
index 0000000..e8f0a15
--- /dev/null
+++ b/camera/camera-viewfinder-core/src/main/java/androidx/camera/viewfinder/surface/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2023 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.
+ */
+
+/**
+ *
+ */
+@RequiresApi(21)
+package androidx.camera.viewfinder.surface;
+
+import androidx.annotation.RequiresApi;
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/CameraInfoDeviceTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/CameraInfoDeviceTest.kt
new file mode 100644
index 0000000..e73da7a
--- /dev/null
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/CameraInfoDeviceTest.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2023 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.camera.integration.core
+
+import android.content.Context
+import androidx.camera.camera2.Camera2Config
+import androidx.camera.camera2.pipe.integration.CameraPipeConfig
+import androidx.camera.core.CameraXConfig
+import androidx.camera.core.DynamicRange
+import androidx.camera.lifecycle.ProcessCameraProvider
+import androidx.camera.testing.impl.CameraPipeConfigTestRule
+import androidx.camera.testing.impl.CameraUtil
+import androidx.camera.testing.impl.CoreAppTestUtil
+import androidx.concurrent.futures.await
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.filters.LargeTest
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import java.util.concurrent.TimeUnit
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withTimeout
+import org.junit.After
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@LargeTest
+@RunWith(Parameterized::class)
+class CameraInfoDeviceTest(
+ private val implName: String,
+ private val cameraXConfig: CameraXConfig
+) {
+ @get:Rule
+ val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+ CameraUtil.PreTestCameraIdList(
+ if (implName == Camera2Config::class.simpleName) {
+ Camera2Config.defaultConfig()
+ } else {
+ CameraPipeConfig.defaultConfig()
+ }
+ )
+ )
+
+ @get:Rule
+ val cameraPipeConfigTestRule = CameraPipeConfigTestRule(
+ active = implName == CameraPipeConfig::class.simpleName,
+ )
+
+ private val context = ApplicationProvider.getApplicationContext<Context>()
+ private lateinit var cameraProvider: ProcessCameraProvider
+
+ companion object {
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun data() = listOf(
+ arrayOf(Camera2Config::class.simpleName, Camera2Config.defaultConfig()),
+ arrayOf(CameraPipeConfig::class.simpleName, CameraPipeConfig.defaultConfig())
+ )
+ }
+
+ @Before
+ fun setUp() = runBlocking {
+ assumeTrue(CameraUtil.deviceHasCamera())
+ CoreAppTestUtil.assumeCompatibleDevice()
+
+ withTimeout(10000) {
+ ProcessCameraProvider.configureInstance(cameraXConfig)
+ cameraProvider = ProcessCameraProvider.getInstance(context).await()
+ }
+ }
+
+ @After
+ fun tearDown() {
+ if (::cameraProvider.isInitialized) {
+ cameraProvider.shutdownAsync()[10, TimeUnit.SECONDS]
+ }
+ }
+
+ @Test
+ fun allCamerasAdvertiseSdr() {
+ cameraProvider.availableCameraInfos.forEach { cameraInfo ->
+ assertThat(cameraInfo.querySupportedDynamicRanges(setOf(DynamicRange.UNSPECIFIED)))
+ .contains(DynamicRange.SDR)
+ }
+ }
+
+ @Test
+ fun underSpecifiedDynamicRange_neverReturnedFromQuery() {
+ cameraProvider.availableCameraInfos.forEach { cameraInfo ->
+ cameraInfo.querySupportedDynamicRanges(setOf(DynamicRange.UNSPECIFIED)).forEach {
+ assertWithMessage(
+ "$cameraInfo advertises under-specified dynamic range: $it"
+ ).that(
+ it.isFullySpecified
+ ).isTrue()
+ }
+ }
+ }
+}
diff --git a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
index e89bff2..0bde846 100644
--- a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
+++ b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
@@ -345,8 +345,10 @@
private OpenGLRenderer mPreviewRenderer;
private DisplayManager.DisplayListener mDisplayListener;
private RecordUi mRecordUi;
+ private DynamicRangeUi mDynamicRangeUi;
private Quality mVideoQuality;
private DynamicRange mDynamicRange = DynamicRange.SDR;
+ private Set<DynamicRange> mDisplaySupportedHighDynamicRanges = Collections.emptySet();
private final Set<DynamicRange> mSelectableDynamicRanges = new HashSet<>();
private int mVideoMirrorMode = MIRROR_MODE_ON_FRONT_ONLY;
private boolean mIsPreviewStabilizationOn = false;
@@ -716,42 +718,6 @@
});
// Final reference to this record UI
- mRecordUi.getButtonDynamicRange().setText(getDynamicRangeIconName(mDynamicRange));
- mRecordUi.getButtonDynamicRange().setOnClickListener(view -> {
- PopupMenu popup = new PopupMenu(this, view);
- Menu menu = popup.getMenu();
-
- final int groupId = Menu.NONE;
- for (DynamicRange dynamicRange : mSelectableDynamicRanges) {
- int itemId = dynamicRangeToItemId(dynamicRange);
- menu.add(groupId, itemId, itemId, getDynamicRangeMenuItemName(dynamicRange));
- if (Objects.equals(dynamicRange, mDynamicRange)) {
- // Apply the checked item for the selected dynamic range to the menu.
- menu.findItem(itemId).setChecked(true);
- }
- }
-
- // Make menu single checkable
- menu.setGroupCheckable(groupId, true, true);
-
- popup.setOnMenuItemClickListener(item -> {
- DynamicRange dynamicRange = itemIdToDynamicRange(item.getItemId());
- if (!Objects.equals(dynamicRange, mDynamicRange)) {
- mDynamicRange = dynamicRange;
- if (Build.VERSION.SDK_INT >= 26) {
- updateWindowColorMode();
- }
- mRecordUi.getButtonDynamicRange()
- .setText(getDynamicRangeIconName(mDynamicRange));
- // Dynamic range changed, rebind UseCases
- tryBindUseCases();
- }
- return true;
- });
-
- popup.show();
- });
-
mRecordUi.getButtonQuality().setText(getQualityIconName(mVideoQuality));
mRecordUi.getButtonQuality().setOnClickListener(view -> {
PopupMenu popup = new PopupMenu(this, view);
@@ -799,6 +765,47 @@
});
}
+ private void setUpDynamicRangeButton() {
+ mDynamicRangeUi.setDisplayedDynamicRange(mDynamicRange);
+ mDynamicRangeUi.getButton().setOnClickListener(view -> {
+ PopupMenu popup = new PopupMenu(this, view);
+ Menu menu = popup.getMenu();
+
+ final int groupId = Menu.NONE;
+ for (DynamicRange dynamicRange : mSelectableDynamicRanges) {
+ int itemId = dynamicRangeToItemId(dynamicRange);
+ menu.add(groupId, itemId, itemId, getDynamicRangeMenuItemName(dynamicRange));
+ if (Objects.equals(dynamicRange, mDynamicRange)) {
+ // Apply the checked item for the selected dynamic range to the menu.
+ menu.findItem(itemId).setChecked(true);
+ }
+ }
+
+ // Make menu single checkable
+ menu.setGroupCheckable(groupId, true, true);
+
+ popup.setOnMenuItemClickListener(item -> {
+ DynamicRange dynamicRange = itemIdToDynamicRange(item.getItemId());
+ if (!Objects.equals(dynamicRange, mDynamicRange)) {
+ setSelectedDynamicRange(dynamicRange);
+ // Dynamic range changed, rebind UseCases
+ tryBindUseCases();
+ }
+ return true;
+ });
+
+ popup.show();
+ });
+ }
+
+ private void setSelectedDynamicRange(@NonNull DynamicRange dynamicRange) {
+ mDynamicRange = dynamicRange;
+ if (Build.VERSION.SDK_INT >= 26) {
+ updateWindowColorMode();
+ }
+ mDynamicRangeUi.setDisplayedDynamicRange(mDynamicRange);
+ }
+
@RequiresApi(26)
private void updateWindowColorMode() {
int colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
@@ -1155,6 +1162,7 @@
mPhotoToggle.setVisibility(View.GONE);
mPreviewToggle.setVisibility(View.GONE);
mAnalysisToggle.setVisibility(View.GONE);
+ mDynamicRangeUi.getButton().setVisibility(View.GONE);
mRecordUi.hideUi();
if (!testCase.equals(SWITCH_TEST_CASE)) {
mCameraDirectionButton.setVisibility(View.GONE);
@@ -1190,10 +1198,30 @@
}
}
+ private void updateDynamicRangeUiState() {
+ // Only show dynamic range if video or preview are enabled
+ boolean visible = (mVideoToggle.isChecked() || mPreviewToggle.isChecked());
+ // Dynamic range is configurable if it's visible, there's more than 1 choice, and there
+ // isn't a recording in progress
+ boolean configurable = visible
+ && mSelectableDynamicRanges.size() > 1
+ && mRecordUi.getState() != RecordUi.State.RECORDING;
+
+ if (configurable) {
+ mDynamicRangeUi.setState(DynamicRangeUi.State.CONFIGURABLE);
+ } else if (visible) {
+ mDynamicRangeUi.setState(DynamicRangeUi.State.VISIBLE);
+ } else {
+ mDynamicRangeUi.setState(DynamicRangeUi.State.HIDDEN);
+ }
+ }
+
@SuppressLint({"NullAnnotationGroup", "RestrictedApiAndroidX"})
@OptIn(markerClass = androidx.camera.core.ExperimentalZeroShutterLag.class)
private void updateButtonsUi() {
mRecordUi.setEnabled(mVideoToggle.isChecked());
+ updateDynamicRangeUiState();
+
mTakePicture.setEnabled(mPhotoToggle.isChecked());
mCaptureQualityToggle.setEnabled(mPhotoToggle.isChecked());
mZslToggle.setVisibility(getCameraInfo() != null
@@ -1276,6 +1304,7 @@
mPreviewToggle.setOnCheckedChangeListener(mOnCheckedChangeListener);
setUpRecordButton();
+ setUpDynamicRangeButton();
setUpFlashButton();
setUpTakePictureButton();
setUpCameraDirectionButton();
@@ -1352,12 +1381,14 @@
setContentView(R.layout.activity_camera_xmain);
mImageCaptureExecutorService = Executors.newSingleThreadExecutor();
- Display display = null;
+ mDisplaySupportedHighDynamicRanges = Collections.emptySet();
if (Build.VERSION.SDK_INT >= 30) {
- display = OpenGLActivity.Api30Impl.getDisplay(this);
+ Display display = OpenGLActivity.Api30Impl.getDisplay(this);
+ mDisplaySupportedHighDynamicRanges =
+ OpenGLActivity.getHighDynamicRangesSupportedByDisplay(display);
}
OpenGLRenderer previewRenderer = mPreviewRenderer =
- new OpenGLRenderer(OpenGLActivity.getHdrEncodingsSupportedByDisplay(display));
+ new OpenGLRenderer(mDisplaySupportedHighDynamicRanges);
ViewStub viewFinderStub = findViewById(R.id.viewFinderStub);
updatePreviewRatioAndScaleTypeByIntent(viewFinderStub);
updateVideoMirrorModeByIntent(getIntent());
@@ -1391,13 +1422,14 @@
mZoomResetToggle = findViewById(R.id.zoom_reset_toggle);
mTextView = findViewById(R.id.textView);
+ mDynamicRangeUi = new DynamicRangeUi(findViewById(R.id.dynamic_range));
mRecordUi = new RecordUi(
findViewById(R.id.Video),
findViewById(R.id.video_pause),
findViewById(R.id.video_stats),
findViewById(R.id.video_quality),
findViewById(R.id.video_persistent),
- findViewById(R.id.video_dynamic_range)
+ (newState) -> updateDynamicRangeUiState()
);
setUpButtonEvents();
@@ -1631,8 +1663,7 @@
// Reset video quality to avoid always fail by quality too large.
mRecordUi.getButtonQuality().setText(getQualityIconName(mVideoQuality = QUALITY_AUTO));
// Reset video dynamic range to avoid failure
- mRecordUi.getButtonDynamicRange().setText(
- getDynamicRangeIconName(mDynamicRange = DynamicRange.SDR));
+ setSelectedDynamicRange(DynamicRange.SDR);
reduceUseCaseToFindSupportedCombination();
@@ -1694,11 +1725,18 @@
@SuppressLint("RestrictedApiAndroidX")
private List<UseCase> buildUseCases() {
List<UseCase> useCases = new ArrayList<>();
+ if (mVideoToggle.isChecked() || mPreviewToggle.isChecked()) {
+ // Update possible dynamic ranges for current camera
+ updateDynamicRangeConfiguration();
+ }
+
if (mPreviewToggle.isChecked()) {
Preview preview = new Preview.Builder()
.setTargetName("Preview")
.setTargetAspectRatio(mTargetAspectRatio)
.setPreviewStabilizationEnabled(mIsPreviewStabilizationOn)
+ .setDynamicRange(
+ mVideoToggle.isChecked() ? DynamicRange.UNSPECIFIED : mDynamicRange)
.build();
resetViewIdlingResource();
// Use the listener of the future to make sure the Preview setup the new surface.
@@ -1732,9 +1770,6 @@
}
if (mVideoToggle.isChecked()) {
- // Update possible dynamic ranges for current camera
- updateDynamicRangeConfiguration();
-
// Recreate the Recorder except there's a running persistent recording, existing
// Recorder. We may later consider reuse the Recorder everytime if the quality didn't
// change.
@@ -1756,29 +1791,43 @@
return useCases;
}
+ @SuppressLint("RestrictedApiAndroidX")
private void updateDynamicRangeConfiguration() {
mSelectableDynamicRanges.clear();
- // Get the list of available dynamic ranges for the current quality
- VideoCapabilities videoCapabilities = Recorder.getVideoCapabilities(
- mCamera.getCameraInfo());
- Set<DynamicRange> supportedDynamicRanges =
- videoCapabilities.getSupportedDynamicRanges();
+ Set<DynamicRange> supportedDynamicRanges = Collections.singleton(DynamicRange.SDR);
+ // ImageCapture and ImageAnalysis currently only support SDR, so only update supported
+ // ranges if they're not enabled
+ if (!mAnalysisToggle.isChecked() && !mPhotoToggle.isChecked()) {
+ if (mVideoToggle.isChecked()) {
+ // Get the list of available dynamic ranges for the current quality
+ VideoCapabilities videoCapabilities = Recorder.getVideoCapabilities(
+ mCamera.getCameraInfo());
+ supportedDynamicRanges = videoCapabilities.getSupportedDynamicRanges();
+ } else if (mPreviewToggle.isChecked()) {
+ supportedDynamicRanges = new HashSet<>();
+ // Add SDR as its always available
+ supportedDynamicRanges.add(DynamicRange.SDR);
+
+ // Add all HDR dynamic ranges supported by the display
+ Set<DynamicRange> queryResult = mCamera.getCameraInfo()
+ .querySupportedDynamicRanges(
+ Collections.singleton(DynamicRange.UNSPECIFIED));
+ supportedDynamicRanges.addAll(queryResult);
+ }
+ }
if (supportedDynamicRanges.size() > 1) {
- mRecordUi.setDynamicRangeConfigurable(true);
if (hasTenBitDynamicRange(supportedDynamicRanges)) {
mSelectableDynamicRanges.add(DynamicRange.HDR_UNSPECIFIED_10_BIT);
}
- } else {
- mRecordUi.setDynamicRangeConfigurable(false);
}
mSelectableDynamicRanges.addAll(supportedDynamicRanges);
// In case the previous dynamic range held in mDynamicRange isn't supported, reset
// to SDR.
if (!mSelectableDynamicRanges.contains(mDynamicRange)) {
- mDynamicRange = DynamicRange.SDR;
+ setSelectedDynamicRange(DynamicRange.SDR);
}
}
@@ -2064,6 +2113,65 @@
}
}
+ private static class DynamicRangeUi {
+
+ enum State {
+ // Button can be selected to choose dynamic range
+ CONFIGURABLE,
+ // Button is visible, but cannot be selected
+ VISIBLE,
+ // Button is not visible, cannot be selected
+ HIDDEN
+ }
+
+ private State mState = State.HIDDEN;
+
+ private final Button mButtonDynamicRange;
+
+ DynamicRangeUi(@NonNull Button buttonDynamicRange) {
+ mButtonDynamicRange = buttonDynamicRange;
+ }
+
+ void setState(@NonNull State newState) {
+ if (newState != mState) {
+ mState = newState;
+ switch (newState) {
+ case HIDDEN: {
+ mButtonDynamicRange.setEnabled(false);
+ mButtonDynamicRange.setVisibility(View.INVISIBLE);
+ break;
+ }
+ case VISIBLE: {
+ mButtonDynamicRange.setEnabled(false);
+ mButtonDynamicRange.setVisibility(View.VISIBLE);
+ break;
+ }
+ case CONFIGURABLE: {
+ mButtonDynamicRange.setEnabled(true);
+ mButtonDynamicRange.setVisibility(View.VISIBLE);
+ break;
+ }
+ }
+ }
+ }
+
+ @NonNull
+ Button getButton() {
+ return mButtonDynamicRange;
+ }
+
+ void setDisplayedDynamicRange(@NonNull DynamicRange dynamicRange) {
+ int resId = R.string.toggle_video_dyn_rng_unknown;
+ for (DynamicRangeUiData uiData : DYNAMIC_RANGE_UI_DATA) {
+ if (Objects.equals(dynamicRange, uiData.mDynamicRange)) {
+ resId = uiData.mToggleLabelRes;
+ break;
+ }
+ }
+ mButtonDynamicRange.setText(resId);
+ }
+ }
+
@UiThread
private static class RecordUi {
@@ -2076,22 +2184,20 @@
private final TextView mTextStats;
private final Button mButtonQuality;
private final ToggleButton mButtonPersistent;
- private final Button mButtonDynamicRange;
- private boolean mDynamicRangeConfigurable = false;
-
private boolean mEnabled = false;
private State mState = State.IDLE;
+ private final Consumer<State> mNewStateConsumer;
RecordUi(@NonNull Button buttonRecord, @NonNull Button buttonPause,
@NonNull TextView textStats, @NonNull Button buttonQuality,
@NonNull ToggleButton buttonPersistent,
- @NonNull Button buttonDynamicRange) {
+ @NonNull Consumer<State> onNewState) {
mButtonRecord = buttonRecord;
mButtonPause = buttonPause;
mTextStats = textStats;
mButtonQuality = buttonQuality;
mButtonPersistent = buttonPersistent;
- mButtonDynamicRange = buttonDynamicRange;
+ mNewStateConsumer = onNewState;
}
void setEnabled(boolean enabled) {
@@ -2101,22 +2207,23 @@
mTextStats.setVisibility(View.VISIBLE);
mButtonQuality.setVisibility(View.VISIBLE);
mButtonPersistent.setVisibility(View.VISIBLE);
- mButtonDynamicRange.setVisibility(View.VISIBLE);
updateUi();
} else {
mButtonRecord.setText("Record");
mButtonRecord.setEnabled(false);
mButtonPause.setVisibility(View.INVISIBLE);
mButtonQuality.setVisibility(View.INVISIBLE);
- mButtonDynamicRange.setVisibility(View.INVISIBLE);
mTextStats.setVisibility(View.GONE);
mButtonPersistent.setVisibility(View.INVISIBLE);
}
}
void setState(@NonNull State state) {
- mState = state;
- updateUi();
+ if (state != mState) {
+ mState = state;
+ updateUi();
+ mNewStateConsumer.accept(state);
+ }
}
@NonNull
@@ -2131,14 +2238,6 @@
mButtonPersistent.setVisibility(View.GONE);
}
- private void setDynamicRangeConfigurable(boolean configurable) {
- if (configurable != mDynamicRangeConfigurable) {
- mDynamicRangeConfigurable = configurable;
- boolean buttonEnabled = mButtonDynamicRange.isEnabled();
- mButtonDynamicRange.setEnabled(buttonEnabled && mDynamicRangeConfigurable);
- }
- }
-
private void updateUi() {
if (!mEnabled) {
return;
@@ -2151,7 +2250,6 @@
mButtonPause.setVisibility(View.INVISIBLE);
mButtonPersistent.setEnabled(true);
mButtonQuality.setEnabled(true);
- mButtonDynamicRange.setEnabled(mDynamicRangeConfigurable);
break;
case RECORDING:
mButtonRecord.setText("Stop");
@@ -2160,7 +2258,6 @@
mButtonPause.setVisibility(View.VISIBLE);
mButtonPersistent.setEnabled(false);
mButtonQuality.setEnabled(false);
- mButtonDynamicRange.setEnabled(false);
break;
case STOPPING:
mButtonRecord.setText("Saving");
@@ -2169,7 +2266,6 @@
mButtonPause.setVisibility(View.INVISIBLE);
mButtonPersistent.setEnabled(false);
mButtonQuality.setEnabled(true);
- mButtonDynamicRange.setEnabled(mDynamicRangeConfigurable);
break;
case PAUSED:
mButtonRecord.setText("Stop");
@@ -2178,7 +2274,6 @@
mButtonPause.setVisibility(View.VISIBLE);
mButtonPersistent.setEnabled(false);
mButtonQuality.setEnabled(true);
- mButtonDynamicRange.setEnabled(mDynamicRangeConfigurable);
break;
}
}
@@ -2203,10 +2298,6 @@
ToggleButton getButtonPersistent() {
return mButtonPersistent;
}
- @NonNull
- Button getButtonDynamicRange() {
- return mButtonDynamicRange;
- }
}
Preview getPreview() {
@@ -2351,19 +2442,6 @@
}
@NonNull
- private String getDynamicRangeIconName(@NonNull DynamicRange dynamicRange) {
- int resId = R.string.toggle_video_dyn_rng_unknown;
- for (DynamicRangeUiData uiData : DYNAMIC_RANGE_UI_DATA) {
- if (Objects.equals(dynamicRange, uiData.mDynamicRange)) {
- resId = uiData.mToggleLabelRes;
- break;
- }
- }
-
- return getString(resId);
- }
-
- @NonNull
private static String getDynamicRangeMenuItemName(@NonNull DynamicRange dynamicRange) {
String menuItemName = dynamicRange.toString();
for (DynamicRangeUiData uiData : DYNAMIC_RANGE_UI_DATA) {
diff --git a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/OpenGLActivity.java b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/OpenGLActivity.java
index 4faa7a9..00a0313 100644
--- a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/OpenGLActivity.java
+++ b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/OpenGLActivity.java
@@ -59,10 +59,11 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
-import java.util.List;
+import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import java.util.stream.Collectors;
/** Activity which runs the camera preview with opengl processing */
@@ -136,7 +137,7 @@
display = Api30Impl.getDisplay(this);
}
OpenGLRenderer renderer = mRenderer = new OpenGLRenderer(
- getHdrEncodingsSupportedByDisplay(display));
+ getHighDynamicRangesSupportedByDisplay(display));
ViewStub viewFinderStub = findViewById(R.id.viewFinderStub);
View viewFinder = OpenGLActivity.chooseViewFinder(getIntent().getExtras(), viewFinderStub,
renderer);
@@ -267,20 +268,20 @@
}
/**
- * Returns a list of HDR encodings supported by the display.
+ * Returns a list of HDR dynamic ranges supported by the display.
*
- * <p>The returned HDR encodings are the encodings from the {@link DynamicRange} class, such
- * as {@link DynamicRange#ENCODING_HLG}. The returned list will never contain
- * {@link DynamicRange#ENCODING_SDR}.
+ * <p>The returned HDR dynamic ranges are constants defined by the {@code DynamicRange} class.
+ * The returned list will never contain {@link DynamicRange#SDR}.
*
* <p>The list may be empty if the display does not support HDR, such as on pre-API 24 devices.
*/
@NonNull
- public static List<Integer> getHdrEncodingsSupportedByDisplay(@Nullable Display display) {
+ public static Set<DynamicRange> getHighDynamicRangesSupportedByDisplay(
+ @Nullable Display display) {
if (display != null && Build.VERSION.SDK_INT >= 24) {
- return Api24Impl.getHdrEncodingsSupportedByDisplay(display);
+ return Api24Impl.getHighDynamicRangesSupportedByDisplay(display);
} else {
- return Collections.emptyList();
+ return Collections.emptySet();
}
}
@@ -334,17 +335,19 @@
@RequiresApi(24)
static class Api24Impl {
- private static final Map<Integer, Integer> DISPLAY_HDR_TYPE_TO_DYNAMIC_RANGE_ENCODING =
+ private static final Map<Integer, Set<DynamicRange>> DISPLAY_HDR_TYPE_TO_DYNAMIC_RANGE =
new HashMap<>();
static {
- DISPLAY_HDR_TYPE_TO_DYNAMIC_RANGE_ENCODING.put(HDR_TYPE_HLG, DynamicRange.ENCODING_HLG);
- DISPLAY_HDR_TYPE_TO_DYNAMIC_RANGE_ENCODING.put(HDR_TYPE_HDR10,
- DynamicRange.ENCODING_HDR10);
- DISPLAY_HDR_TYPE_TO_DYNAMIC_RANGE_ENCODING.put(HDR_TYPE_HDR10_PLUS,
- DynamicRange.ENCODING_HDR10_PLUS);
- DISPLAY_HDR_TYPE_TO_DYNAMIC_RANGE_ENCODING.put(HDR_TYPE_DOLBY_VISION,
- DynamicRange.ENCODING_DOLBY_VISION);
+ DISPLAY_HDR_TYPE_TO_DYNAMIC_RANGE.put(HDR_TYPE_HLG,
+ Collections.singleton(DynamicRange.HLG_10_BIT));
+ DISPLAY_HDR_TYPE_TO_DYNAMIC_RANGE.put(HDR_TYPE_HDR10,
+ Collections.singleton(DynamicRange.HDR10_10_BIT));
+ DISPLAY_HDR_TYPE_TO_DYNAMIC_RANGE.put(HDR_TYPE_HDR10_PLUS,
+ Collections.singleton(DynamicRange.HDR10_PLUS_10_BIT));
+ DISPLAY_HDR_TYPE_TO_DYNAMIC_RANGE.put(HDR_TYPE_DOLBY_VISION,
+ new HashSet<>(Arrays.asList(
+ DynamicRange.DOLBY_VISION_8_BIT, DynamicRange.DOLBY_VISION_10_BIT)));
}
private Api24Impl() {
@@ -352,12 +355,14 @@
}
@DoNotInline
- static List<Integer> getHdrEncodingsSupportedByDisplay(@NonNull Display display) {
+ static Set<DynamicRange> getHighDynamicRangesSupportedByDisplay(
+ @NonNull Display display) {
return Arrays.stream(display.getHdrCapabilities().getSupportedHdrTypes())
.boxed()
- .map(DISPLAY_HDR_TYPE_TO_DYNAMIC_RANGE_ENCODING::get)
+ .map(DISPLAY_HDR_TYPE_TO_DYNAMIC_RANGE::get)
+ .flatMap(set -> Objects.requireNonNull(set).stream())
.filter(Objects::nonNull)
- .collect(Collectors.toList());
+ .collect(Collectors.toSet());
}
}
diff --git a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/OpenGLRenderer.java b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/OpenGLRenderer.java
index 60dafae..fe1c9b8 100644
--- a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/OpenGLRenderer.java
+++ b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/OpenGLRenderer.java
@@ -42,9 +42,9 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.List;
import java.util.Locale;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
@@ -120,10 +120,10 @@
private Pair<Executor, Consumer<Long>> mFrameUpdateListener;
- private final List<Integer> mHdrEncodingsSupportedByOutput;
+ private final Set<DynamicRange> mHighDynamicRangesSupportedByOutput;
- OpenGLRenderer(@NonNull List<Integer> hdrEncodingsSupportedByOutput) {
- mHdrEncodingsSupportedByOutput = hdrEncodingsSupportedByOutput;
+ OpenGLRenderer(@NonNull Set<DynamicRange> highDynamicRangesSupportedByOutput) {
+ mHighDynamicRangesSupportedByOutput = highDynamicRangesSupportedByOutput;
// Initialize the GL context on the GL thread
mExecutor.execute(() -> mNativeContext = initContext());
}
@@ -218,7 +218,7 @@
private boolean outputSupportsDynamicRange(DynamicRange newDynamicRange) {
if (!Objects.equals(newDynamicRange, DynamicRange.SDR)) {
- return mHdrEncodingsSupportedByOutput.contains(newDynamicRange.getEncoding());
+ return mHighDynamicRangesSupportedByOutput.contains(newDynamicRange);
}
// SDR is always supported
return true;
diff --git a/camera/integration-tests/coretestapp/src/main/res/layout/activity_camera_xmain.xml b/camera/integration-tests/coretestapp/src/main/res/layout/activity_camera_xmain.xml
index 81eb97a..27bbfa0 100644
--- a/camera/integration-tests/coretestapp/src/main/res/layout/activity_camera_xmain.xml
+++ b/camera/integration-tests/coretestapp/src/main/res/layout/activity_camera_xmain.xml
@@ -323,7 +323,7 @@
app:layout_constraintTop_toBottomOf="@id/direction_toggle" />
<Button
- android:id="@+id/video_quality"
+ android:id="@+id/dynamic_range"
android:layout_width="46dp"
android:layout_height="wrap_content"
android:layout_marginTop="1dp"
@@ -338,7 +338,7 @@
/>
<Button
- android:id="@+id/video_dynamic_range"
+ android:id="@+id/video_quality"
android:layout_width="46dp"
android:layout_height="wrap_content"
android:layout_marginTop="1dp"
@@ -348,7 +348,7 @@
android:textColor="#EEEEEE"
android:textSize="14dp"
android:visibility="invisible"
- app:layout_constraintTop_toBottomOf="@id/video_persistent"
+ app:layout_constraintTop_toBottomOf="@id/dynamic_range"
app:layout_constraintRight_toRightOf="parent"
/>
diff --git a/camera/integration-tests/extensionstestapp/src/main/java/androidx/camera/integration/extensions/CameraExtensionsActivity.java b/camera/integration-tests/extensionstestapp/src/main/java/androidx/camera/integration/extensions/CameraExtensionsActivity.java
index c06e615..859569e 100644
--- a/camera/integration-tests/extensionstestapp/src/main/java/androidx/camera/integration/extensions/CameraExtensionsActivity.java
+++ b/camera/integration-tests/extensionstestapp/src/main/java/androidx/camera/integration/extensions/CameraExtensionsActivity.java
@@ -665,20 +665,20 @@
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
- switch (item.getItemId()) {
- case R.id.menu_camera2_extensions:
- if (Build.VERSION.SDK_INT >= 31) {
- mCameraProvider.unbindAll();
- intent.setClassName(this, Camera2ExtensionsActivity.class.getName());
- startActivity(intent);
- finish();
- }
- return true;
- case R.id.menu_validation_tool:
- intent.setClassName(this, CameraValidationResultActivity.class.getName());
+ int itemId = item.getItemId();
+ if (itemId == R.id.menu_camera2_extensions) {
+ if (Build.VERSION.SDK_INT >= 31) {
+ mCameraProvider.unbindAll();
+ intent.setClassName(this, Camera2ExtensionsActivity.class.getName());
startActivity(intent);
finish();
- return true;
+ }
+ return true;
+ } else if (itemId == R.id.menu_validation_tool) {
+ intent.setClassName(this, CameraValidationResultActivity.class.getName());
+ startActivity(intent);
+ finish();
+ return true;
}
return super.onOptionsItemSelected(item);
diff --git a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/EffectsFragment.kt b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/EffectsFragment.kt
index 1d811a0..ca25ba9 100644
--- a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/EffectsFragment.kt
+++ b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/EffectsFragment.kt
@@ -217,6 +217,7 @@
private fun stopRecording() {
record.text = "Record"
recording?.stop()
+ recording = null
}
private fun getNewVideoOutputMediaStoreOptions(): MediaStoreOutputOptions {
diff --git a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/MainActivity.java b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/MainActivity.java
index 35c9e82..3e94241 100644
--- a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/MainActivity.java
+++ b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/MainActivity.java
@@ -169,25 +169,19 @@
@SuppressLint("NonConstantResourceId")
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
- switch (item.getItemId()) {
- case R.id.preview_view:
- mFragmentType = FragmentType.PREVIEW_VIEW;
- break;
- case R.id.camera_controller:
- mFragmentType = FragmentType.CAMERA_CONTROLLER;
- break;
- case R.id.transform:
- mFragmentType = FragmentType.TRANSFORM;
- break;
- case R.id.compose_ui:
- mFragmentType = FragmentType.COMPOSE_UI;
- break;
- case R.id.mlkit:
- mFragmentType = FragmentType.MLKIT;
- break;
- case R.id.effects:
- mFragmentType = FragmentType.EFFECTS;
- break;
+ int itemId = item.getItemId();
+ if (itemId == R.id.preview_view) {
+ mFragmentType = FragmentType.PREVIEW_VIEW;
+ } else if (itemId == R.id.camera_controller) {
+ mFragmentType = FragmentType.CAMERA_CONTROLLER;
+ } else if (itemId == R.id.transform) {
+ mFragmentType = FragmentType.TRANSFORM;
+ } else if (itemId == R.id.compose_ui) {
+ mFragmentType = FragmentType.COMPOSE_UI;
+ } else if (itemId == R.id.mlkit) {
+ mFragmentType = FragmentType.MLKIT;
+ } else if (itemId == R.id.effects) {
+ mFragmentType = FragmentType.EFFECTS;
}
startFragment();
return true;
diff --git a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/ToneMappingSurfaceEffect.kt b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/ToneMappingSurfaceEffect.kt
index 4f5c8ae7..44af50ca 100644
--- a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/ToneMappingSurfaceEffect.kt
+++ b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/ToneMappingSurfaceEffect.kt
@@ -16,17 +16,23 @@
package androidx.camera.integration.view
+import android.annotation.SuppressLint
import androidx.camera.core.CameraEffect
/**
* A tone mapping effect for Preview/VideoCapture UseCase.
*/
+@SuppressLint("RestrictedApiAndroidX")
internal class ToneMappingSurfaceEffect(
targets: Int = PREVIEW or VIDEO_CAPTURE,
private val processor: ToneMappingSurfaceProcessor = ToneMappingSurfaceProcessor()
) :
CameraEffect(
- targets, processor.getGlExecutor(), processor, {}
+ targets,
+ TRANSFORMATION_CAMERA_AND_SURFACE_ROTATION,
+ processor.getGlExecutor(),
+ processor,
+ {}
) {
fun release() {
diff --git a/camera/integration-tests/viewtestapp/src/main/res/layout-land/effects_view.xml b/camera/integration-tests/viewtestapp/src/main/res/layout-land/effects_view.xml
index cbf1b36..dbdca03 100644
--- a/camera/integration-tests/viewtestapp/src/main/res/layout-land/effects_view.xml
+++ b/camera/integration-tests/viewtestapp/src/main/res/layout-land/effects_view.xml
@@ -1,12 +1,9 @@
<?xml version="1.0" encoding="utf-8"?><!--
Copyright 2023 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.
@@ -14,13 +11,12 @@
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
- android:layout_width="match_parent"
+ android:layout_width="0dp"
android:layout_weight="1"
- android:layout_height="0dp">
+ android:layout_height="match_parent">
<androidx.camera.view.PreviewView
android:id="@+id/preview_view"
android:layout_width="match_parent"
@@ -51,14 +47,15 @@
</LinearLayout>
</RelativeLayout>
<LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
android:layout_margin="20dp">
<LinearLayout
android:orientation="vertical"
- android:layout_width="0dp"
+ android:layout_width="match_parent"
android:layout_weight="1"
- android:layout_height="match_parent">
+ android:layout_height="0dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -84,9 +81,9 @@
</LinearLayout>
<LinearLayout
android:orientation="vertical"
- android:layout_width="0dp"
+ android:layout_width="match_parent"
android:layout_weight="1"
- android:layout_height="match_parent">
+ android:layout_height="0dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/cardview/cardview/src/main/java/androidx/cardview/widget/CardView.java b/cardview/cardview/src/main/java/androidx/cardview/widget/CardView.java
index 08b5580..b940212 100644
--- a/cardview/cardview/src/main/java/androidx/cardview/widget/CardView.java
+++ b/cardview/cardview/src/main/java/androidx/cardview/widget/CardView.java
@@ -86,8 +86,6 @@
static {
if (Build.VERSION.SDK_INT >= 21) {
IMPL = new CardViewApi21Impl();
- } else if (Build.VERSION.SDK_INT >= 17) {
- IMPL = new CardViewApi17Impl();
} else {
IMPL = new CardViewBaseImpl();
}
diff --git a/cardview/cardview/src/main/java/androidx/cardview/widget/CardViewApi17Impl.java b/cardview/cardview/src/main/java/androidx/cardview/widget/CardViewApi17Impl.java
deleted file mode 100644
index 49387fd..0000000
--- a/cardview/cardview/src/main/java/androidx/cardview/widget/CardViewApi17Impl.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.cardview.widget;
-
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.RectF;
-
-import androidx.annotation.RequiresApi;
-
-@RequiresApi(17)
-class CardViewApi17Impl extends CardViewBaseImpl {
-
- @Override
- public void initStatic() {
- RoundRectDrawableWithShadow.sRoundRectHelper =
- new RoundRectDrawableWithShadow.RoundRectHelper() {
- @Override
- public void drawRoundRect(Canvas canvas, RectF bounds, float cornerRadius,
- Paint paint) {
- canvas.drawRoundRect(bounds, cornerRadius, cornerRadius, paint);
- }
- };
- }
-}
diff --git a/cardview/cardview/src/main/java/androidx/cardview/widget/CardViewBaseImpl.java b/cardview/cardview/src/main/java/androidx/cardview/widget/CardViewBaseImpl.java
index bc6cd5d..c5a8dec 100644
--- a/cardview/cardview/src/main/java/androidx/cardview/widget/CardViewBaseImpl.java
+++ b/cardview/cardview/src/main/java/androidx/cardview/widget/CardViewBaseImpl.java
@@ -17,64 +17,17 @@
import android.content.Context;
import android.content.res.ColorStateList;
-import android.graphics.Canvas;
-import android.graphics.Paint;
import android.graphics.Rect;
-import android.graphics.RectF;
import androidx.annotation.Nullable;
class CardViewBaseImpl implements CardViewImpl {
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- final RectF mCornerRect = new RectF();
-
@Override
public void initStatic() {
- // Draws a round rect using 7 draw operations. This is faster than using
- // canvas.drawRoundRect before JBMR1 because API 11-16 used alpha mask textures to draw
- // shapes.
RoundRectDrawableWithShadow.sRoundRectHelper =
- new RoundRectDrawableWithShadow.RoundRectHelper() {
- @Override
- public void drawRoundRect(Canvas canvas, RectF bounds, float cornerRadius,
- Paint paint) {
- final float twoRadius = cornerRadius * 2;
- final float innerWidth = bounds.width() - twoRadius - 1;
- final float innerHeight = bounds.height() - twoRadius - 1;
- if (cornerRadius >= 1f) {
- // increment corner radius to account for half pixels.
- float roundedCornerRadius = cornerRadius + .5f;
- mCornerRect.set(-roundedCornerRadius, -roundedCornerRadius, roundedCornerRadius,
- roundedCornerRadius);
- int saved = canvas.save();
- canvas.translate(bounds.left + roundedCornerRadius,
- bounds.top + roundedCornerRadius);
- canvas.drawArc(mCornerRect, 180, 90, true, paint);
- canvas.translate(innerWidth, 0);
- canvas.rotate(90);
- canvas.drawArc(mCornerRect, 180, 90, true, paint);
- canvas.translate(innerHeight, 0);
- canvas.rotate(90);
- canvas.drawArc(mCornerRect, 180, 90, true, paint);
- canvas.translate(innerWidth, 0);
- canvas.rotate(90);
- canvas.drawArc(mCornerRect, 180, 90, true, paint);
- canvas.restoreToCount(saved);
- //draw top and bottom pieces
- canvas.drawRect(bounds.left + roundedCornerRadius - 1f, bounds.top,
- bounds.right - roundedCornerRadius + 1f,
- bounds.top + roundedCornerRadius, paint);
-
- canvas.drawRect(bounds.left + roundedCornerRadius - 1f,
- bounds.bottom - roundedCornerRadius,
- bounds.right - roundedCornerRadius + 1f, bounds.bottom, paint);
- }
- // center
- canvas.drawRect(bounds.left, bounds.top + cornerRadius,
- bounds.right, bounds.bottom - cornerRadius , paint);
- }
- };
+ (canvas, bounds, cornerRadius, paint) ->
+ canvas.drawRoundRect(bounds, cornerRadius, cornerRadius, paint);
}
@Override
diff --git a/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/EasingTest.kt b/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/EasingTest.kt
index cbc7126..1b9ff11 100644
--- a/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/EasingTest.kt
+++ b/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/EasingTest.kt
@@ -16,8 +16,10 @@
package androidx.compose.animation.core
+import androidx.compose.ui.util.floatFromBits
import com.google.common.truth.Truth.assertThat
import junit.framework.TestCase.assertEquals
+import junit.framework.TestCase.assertTrue
import org.junit.Assert.assertNotEquals
import org.junit.Test
import org.junit.runner.RunWith
@@ -61,4 +63,29 @@
assertNotEquals(curve1.hashCode(), curve5.hashCode())
assertNotEquals(curve1.hashCode(), curve6.hashCode())
}
+
+ @Test
+ fun canSolveCubicForSmallFractions() {
+ val curve = CubicBezierEasing(0.3f, 0.0f, 0.7f, 1.0f)
+
+ val testValues = intArrayOf(
+ 0x3e800000, // 0.25f
+ 0x3e000000, // 0.125f
+ 0x3d800000, // 0.0625f
+ 0x3a800000, // 0.0009765625f
+ 0x36000000, // 0.0000019073486328125f
+ 0x34800000, // 2.384185791015625e-7f
+ // Values from here are below the epsilon we use in our computations
+ 0x34000000, // 1.1920928955078125e-7f
+ 0x34210fb0, // 1.50000005305628292263e-7f
+ 0x33800000, // 5.9604644775390625e-8f
+ 0x33000000, // 2.98023223876953125e-8f
+ 0x00000000, // 0.0f
+ )
+
+ for (i in testValues) {
+ val t = curve.transform(floatFromBits(i))
+ assertTrue(t in 0.0f..1.0f)
+ }
+ }
}
diff --git a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Bezier.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Bezier.kt
index 5569c6b..f949c726 100644
--- a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Bezier.kt
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Bezier.kt
@@ -28,8 +28,8 @@
import kotlin.math.sqrt
private const val Tau = Math.PI * 2.0
-private const val Epsilon = 1e-7
-private const val FloatEpsilon = 1e-7f
+private const val Epsilon = 1.5e-7
+private const val FloatEpsilon = 1.5e-7f
/**
* Evaluate the specified [segment] at position [t] and returns the X
diff --git a/compose/animation/animation/api/current.txt b/compose/animation/animation/api/current.txt
index 2e7140c..f8817a9 100644
--- a/compose/animation/animation/api/current.txt
+++ b/compose/animation/animation/api/current.txt
@@ -19,8 +19,6 @@
public sealed interface AnimatedContentTransitionScope<S> extends androidx.compose.animation.core.Transition.Segment<S> {
method public androidx.compose.ui.Alignment getContentAlignment();
method public default androidx.compose.animation.ExitTransition getKeepUntilTransitionsFinished(androidx.compose.animation.ExitTransition.Companion);
- method @SuppressCompatibility @androidx.compose.animation.ExperimentalAnimationApi public androidx.compose.animation.EnterTransition scaleInToFitContainer(optional androidx.compose.ui.Alignment alignment, optional androidx.compose.ui.layout.ContentScale contentScale);
- method @SuppressCompatibility @androidx.compose.animation.ExperimentalAnimationApi public androidx.compose.animation.ExitTransition scaleOutToFitContainer(optional androidx.compose.ui.Alignment alignment, optional androidx.compose.ui.layout.ContentScale contentScale);
method public androidx.compose.animation.EnterTransition slideIntoContainer(int towards, optional androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntOffset> animationSpec, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,java.lang.Integer> initialOffset);
method public androidx.compose.animation.ExitTransition slideOutOfContainer(int towards, optional androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntOffset> animationSpec, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,java.lang.Integer> targetOffset);
method public infix androidx.compose.animation.ContentTransform using(androidx.compose.animation.ContentTransform, androidx.compose.animation.SizeTransform? sizeTransform);
diff --git a/compose/animation/animation/api/restricted_current.txt b/compose/animation/animation/api/restricted_current.txt
index 2e7140c..f8817a9 100644
--- a/compose/animation/animation/api/restricted_current.txt
+++ b/compose/animation/animation/api/restricted_current.txt
@@ -19,8 +19,6 @@
public sealed interface AnimatedContentTransitionScope<S> extends androidx.compose.animation.core.Transition.Segment<S> {
method public androidx.compose.ui.Alignment getContentAlignment();
method public default androidx.compose.animation.ExitTransition getKeepUntilTransitionsFinished(androidx.compose.animation.ExitTransition.Companion);
- method @SuppressCompatibility @androidx.compose.animation.ExperimentalAnimationApi public androidx.compose.animation.EnterTransition scaleInToFitContainer(optional androidx.compose.ui.Alignment alignment, optional androidx.compose.ui.layout.ContentScale contentScale);
- method @SuppressCompatibility @androidx.compose.animation.ExperimentalAnimationApi public androidx.compose.animation.ExitTransition scaleOutToFitContainer(optional androidx.compose.ui.Alignment alignment, optional androidx.compose.ui.layout.ContentScale contentScale);
method public androidx.compose.animation.EnterTransition slideIntoContainer(int towards, optional androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntOffset> animationSpec, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,java.lang.Integer> initialOffset);
method public androidx.compose.animation.ExitTransition slideOutOfContainer(int towards, optional androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntOffset> animationSpec, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,java.lang.Integer> targetOffset);
method public infix androidx.compose.animation.ContentTransform using(androidx.compose.animation.ContentTransform, androidx.compose.animation.SizeTransform? sizeTransform);
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/layoutanimation/ContainerTransform.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/layoutanimation/ContainerTransform.kt
deleted file mode 100644
index cf03291..0000000
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/layoutanimation/ContainerTransform.kt
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.animation.demos.layoutanimation
-
-import androidx.compose.animation.AnimatedContent
-import androidx.compose.animation.ExperimentalAnimationApi
-import androidx.compose.animation.core.animateDpAsState
-import androidx.compose.animation.core.animateIntAsState
-import androidx.compose.animation.core.tween
-import androidx.compose.animation.fadeIn
-import androidx.compose.animation.fadeOut
-import androidx.compose.animation.togetherWith
-import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.Icon
-import androidx.compose.material.MaterialTheme
-import androidx.compose.material.RadioButton
-import androidx.compose.material.Text
-import androidx.compose.material.TextField
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.automirrored.filled.ArrowBack
-import androidx.compose.material.icons.filled.AccountCircle
-import androidx.compose.material.icons.filled.Add
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.vector.rememberVectorPainter
-import androidx.compose.ui.layout.ContentScale
-import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
-
-@OptIn(ExperimentalAnimationApi::class)
-@Preview
-@Composable
-fun LocalContainerTransformDemo() {
- Box(Modifier.fillMaxSize()) {
- LazyColumn {
- items(20) {
- Box(
- Modifier
- .fillMaxWidth()
- .height(150.dp)
- .padding(15.dp)
- .background(MaterialTheme.colors.primary)
- )
- }
- }
- }
- var selectedAlignment by remember { mutableStateOf(Alignment.Center) }
- var contentScale by remember { mutableStateOf(ContentScale.FillWidth) }
- Column(
- Modifier.padding(top = 100.dp)
- ) {
- Column(
- Modifier
- .background(Color.LightGray, RoundedCornerShape(10.dp)),
- ) {
- Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
- RadioButton(
- selected = selectedAlignment == Alignment.TopStart,
- onClick = { selectedAlignment = Alignment.TopStart }
- )
- Text("TopStart", Modifier.padding(5.dp))
- RadioButton(
- selected = selectedAlignment == Alignment.TopCenter,
- onClick = { selectedAlignment = Alignment.TopCenter }
- )
- Text("TopCenter", Modifier.padding(5.dp))
- RadioButton(
- selected = selectedAlignment == Alignment.TopEnd,
- onClick = { selectedAlignment = Alignment.TopEnd }
- )
- Text("TopEnd", Modifier.padding(5.dp))
- }
- Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
- RadioButton(
- selected = selectedAlignment == Alignment.CenterStart,
- onClick = { selectedAlignment = Alignment.CenterStart }
- )
- Text("CenterStart", Modifier.padding(5.dp))
- RadioButton(
- selected = selectedAlignment == Alignment.Center,
- onClick = { selectedAlignment = Alignment.Center }
- )
- Text("Center", Modifier.padding(5.dp))
- RadioButton(
- selected = selectedAlignment == Alignment.CenterEnd,
- onClick = { selectedAlignment = Alignment.CenterEnd }
- )
- Text("CenterEnd", Modifier.padding(5.dp))
- }
- Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
- RadioButton(
- selected = selectedAlignment == Alignment.BottomStart,
- onClick = { selectedAlignment = Alignment.BottomStart }
- )
- Text("BottomStart", Modifier.padding(5.dp))
- RadioButton(
- selected = selectedAlignment == Alignment.BottomCenter,
- onClick = { selectedAlignment = Alignment.BottomCenter }
- )
- Text("BottomCenter", Modifier.padding(5.dp))
- RadioButton(
- selected = selectedAlignment == Alignment.BottomEnd,
- onClick = { selectedAlignment = Alignment.BottomEnd }
- )
- Text("BottomEnd", Modifier.padding(5.dp))
- }
- }
- Column(
- Modifier
- .background(Color.Gray, RoundedCornerShape(10.dp)),
- ) {
- Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
- RadioButton(
- selected = contentScale == ContentScale.FillWidth,
- onClick = { contentScale = ContentScale.FillWidth }
- )
- Text("FillWidth", Modifier.padding(5.dp))
- RadioButton(
- selected = contentScale == ContentScale.FillHeight,
- onClick = { contentScale = ContentScale.FillHeight }
- )
- Text("FillHeight", Modifier.padding(5.dp))
- RadioButton(
- selected = contentScale == ContentScale.FillBounds,
- onClick = { contentScale = ContentScale.FillBounds }
- )
- Text("FillBounds", Modifier.padding(5.dp))
- }
- Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
- RadioButton(
- selected = contentScale == ContentScale.Crop,
- onClick = { contentScale = ContentScale.Crop }
- )
- Text("Crop", Modifier.padding(5.dp))
- RadioButton(
- selected = contentScale == ContentScale.Fit,
- onClick = { contentScale = ContentScale.Fit }
- )
- Text("Fit", Modifier.padding(5.dp))
- RadioButton(
- selected = contentScale == ContentScale.Inside,
- onClick = { contentScale = ContentScale.Inside }
- )
- Text("Inside", Modifier.padding(5.dp))
- }
- }
- }
- Box(Modifier.fillMaxSize()) {
- var target by remember { mutableStateOf(ContainerState.FAB) }
- // Corner radius
- val cr by animateIntAsState(if (target == ContainerState.FAB) 50 else 0)
- val padding by animateDpAsState(if (target == ContainerState.FAB) 10.dp else 0.dp)
- AnimatedContent(
- target,
- label = "",
- transitionSpec = {
- fadeIn(tween(200, delayMillis = 100)) +
- scaleInToFitContainer(selectedAlignment, contentScale) togetherWith
- fadeOut(tween(100)) + scaleOutToFitContainer(selectedAlignment, contentScale)
- },
- modifier = Modifier
- .align(Alignment.BottomEnd)
- .padding(padding)
- .clip(RoundedCornerShape(cr))
- .background(Color.White)
- ) {
- if (it == ContainerState.FAB) {
- Icon(
- rememberVectorPainter(image = Icons.Default.Add),
- null,
- modifier = Modifier
- .clickable {
- target = ContainerState.FullScreen
- }
- .padding(20.dp))
- } else {
- Column(Modifier.fillMaxSize()) {
- Icon(
- rememberVectorPainter(image = Icons.AutoMirrored.Filled.ArrowBack),
- null,
- modifier = Modifier
- .clickable {
- target = ContainerState.FAB
- }
- .padding(20.dp))
- Spacer(Modifier.height(60.dp))
- Text("Page Title", fontSize = 20.sp, modifier = Modifier.padding(20.dp))
- Spacer(
- Modifier
- .fillMaxWidth()
- .height(2.dp)
- .background(Color.LightGray)
- )
- Row(
- Modifier
- .fillMaxWidth()
- .padding(20.dp)
- ) {
- Icon(rememberVectorPainter(image = Icons.Default.AccountCircle), null)
- Spacer(Modifier.width(20.dp))
- TextField(value = "Account Name", onValueChange = {})
- }
- }
- }
- }
- }
-}
-
-private enum class ContainerState {
- FAB,
- FullScreen
-}
diff --git a/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedContentSamples.kt b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedContentSamples.kt
index c9c4f15..b9eeaff 100644
--- a/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedContentSamples.kt
+++ b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedContentSamples.kt
@@ -22,7 +22,6 @@
import androidx.compose.animation.AnimatedContentTransitionScope.SlideDirection
import androidx.compose.animation.ContentTransform
import androidx.compose.animation.ExitTransition
-import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.SizeTransform
import androidx.compose.animation.core.animateDp
import androidx.compose.animation.core.keyframes
@@ -55,7 +54,6 @@
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -309,30 +307,6 @@
}
}
-@OptIn(ExperimentalAnimationApi::class)
-@Suppress("UNUSED_VARIABLE")
-@Sampled
-@Composable
-fun ScaleInToFitContainerSample() {
- // enum class CartState { Expanded, Collapsed }
- // This is an example of scaling both the incoming content and outgoing content to fit in the
- // animating container size while animating alpha.
- val transitionSpec: AnimatedContentTransitionScope<CartState>.() -> ContentTransform = {
- // Fade in while scaling the content.
- fadeIn() + scaleInToFitContainer() togetherWith
- // Fade out outgoing content while scaling it. It is important
- // to combine `scaleOutToFitContainer` with another ExitTransition that defines
- // a timeframe for the exit (such as fade/shrink/slide/Hold).
- fadeOut() + scaleOutToFitContainer(
- // Default alignment is the content alignment defined in AnimatedContent
- Alignment.Center,
- // Content will be scaled based on the height of the content. Default content
- // scale is ContentScale.FillWidth.
- ContentScale.FillHeight
- )
- }
-}
-
private enum class CartState {
Expanded,
Collapsed
diff --git a/compose/animation/animation/src/androidInstrumentedTest/kotlin/androidx/compose/animation/AnimatedContentTest.kt b/compose/animation/animation/src/androidInstrumentedTest/kotlin/androidx/compose/animation/AnimatedContentTest.kt
index 0568edf..56d0163 100644
--- a/compose/animation/animation/src/androidInstrumentedTest/kotlin/androidx/compose/animation/AnimatedContentTest.kt
+++ b/compose/animation/animation/src/androidInstrumentedTest/kotlin/androidx/compose/animation/AnimatedContentTest.kt
@@ -51,19 +51,13 @@
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.LayoutCoordinates
import androidx.compose.ui.layout.LookaheadScope
import androidx.compose.ui.layout.SubcomposeLayout
-import androidx.compose.ui.layout.boundsInRoot
-import androidx.compose.ui.layout.layout
import androidx.compose.ui.layout.onGloballyPositioned
-import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.layout.positionInRoot
import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
@@ -72,7 +66,6 @@
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.round
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import com.google.common.truth.Truth.assertThat
@@ -789,334 +782,6 @@
}
@Test
- fun testScaleToFitDefault() {
- var target by mutableStateOf(1)
- var box1Coords: LayoutCoordinates? = null
- var box2Coords: LayoutCoordinates? = null
- var box1Disposed = true
- var box2Disposed = true
- rule.setContent {
- CompositionLocalProvider(LocalDensity provides Density(1f)) {
- AnimatedContent(
- targetState = target,
- transitionSpec = {
- if (1 isTransitioningTo 2) {
- fadeIn(tween(300)) + scaleInToFitContainer() togetherWith
- scaleOutToFitContainer()
- } else {
- fadeIn() + scaleInToFitContainer() togetherWith
- fadeOut(tween(150))
- } using SizeTransform { initialSize, targetSize ->
- keyframes {
- durationMillis = 300
- initialSize at 100 using LinearEasing
- targetSize at 200 using LinearEasing
- }
- }
- }) {
- if (it == 1) {
- Box(
- Modifier
- .onPlaced {
- box1Coords = it
- }
- .size(200.dp, 400.dp)) {
- DisposableEffect(key1 = Unit) {
- box1Disposed = false
- onDispose {
- box1Disposed = true
- }
- }
- }
- } else {
- Box(
- Modifier
- .onPlaced { box2Coords = it }
- .size(100.dp, 50.dp)) {
-
- DisposableEffect(key1 = Unit) {
- box2Disposed = false
- onDispose {
- box2Disposed = true
- }
- }
- }
- }
- }
- }
- }
-
- rule.waitForIdle()
- rule.mainClock.autoAdvance = false
- assertEquals(IntSize(200, 400), box1Coords?.size)
- assertNull(box2Coords)
-
- assertFalse(box1Disposed)
- assertTrue(box2Disposed)
-
- rule.runOnIdle {
- // Start transition from 1 -> 2, size 200,400 -> 100,50
- target = 2
- }
- rule.mainClock.advanceTimeByFrame()
- rule.waitForIdle()
-
- // Box1 doesn't have any other ExitTransition than scale, so it'll be disposed
- // after a couple of frames
- assertFalse(box1Disposed)
- assertFalse(box2Disposed)
-
- repeat(20) {
- rule.mainClock.advanceTimeByFrame()
-
- val playTime = 16 * it
- val bounds2 = box2Coords?.boundsInRoot()
- if (playTime <= 100) {
- assertEquals(Rect(0f, 0f, 200f, 100f), bounds2)
- } else if (playTime <= 200) {
- val fraction = (playTime - 100) / 100f
- val width = 200 * (1 - fraction) + 100 * fraction
- // Since we are testing default behavior, the scaling is based on width.
- val height = width / 100f * 50
- assertEquals(Offset.Zero, bounds2?.topLeft)
- assertEquals(width, bounds2?.width)
- assertEquals(height, bounds2?.height)
- } else {
- assertEquals(Rect(0f, 0f, 100f, 50f), bounds2)
- }
- }
-
- rule.runOnIdle {
- // Start transition from false -> true, size 100, 50 -> 200,400
- target = 1
- }
- rule.mainClock.advanceTimeByFrame()
- rule.waitForIdle()
-
- assertFalse(box1Disposed)
- assertFalse(box2Disposed)
-
- repeat(20) {
- rule.mainClock.advanceTimeByFrame()
- val playTime = 16 * it
- val bounds = box1Coords?.boundsInRoot()
- if (playTime <= 100) {
- assertEquals(100f, bounds?.width)
- assertFalse(box2Disposed)
- } else if (playTime <= 150) {
- val fraction = (playTime - 100) / 100f
- val width = 100 * (1 - fraction) + 200 * fraction
- // Since we are testing default behavior, the scaling is based on width.
- assertEquals(Offset.Zero, bounds?.topLeft)
- assertEquals(width, bounds?.width)
- } else {
- rule.waitForIdle()
- assertThat(box2Disposed)
- }
- }
- }
-
- @Test
- fun testScaleToFitCenterAlignment() {
- var target by mutableStateOf(true)
- var box1Coords: LayoutCoordinates? = null
- var box2Coords: LayoutCoordinates? = null
- var layoutDirection: LayoutDirection? = null
- rule.setContent {
- CompositionLocalProvider(LocalDensity provides Density(1f)) {
- layoutDirection = LocalLayoutDirection.current
- AnimatedContent(
- targetState = target,
- transitionSpec = {
- fadeIn() + scaleInToFitContainer(Alignment.Center) togetherWith
- fadeOut(tween(100)) using
- SizeTransform { _, _ ->
- tween(100, easing = LinearEasing)
- }
- }) {
- if (target) {
- Box(
- Modifier
- .onPlaced {
- box1Coords = it
- }
- .size(200.dp, 400.dp))
- } else {
- Box(
- Modifier
- .onPlaced { box2Coords = it }
- .size(100.dp, 50.dp))
- }
- }
- }
- }
-
- rule.waitForIdle()
- assertEquals(IntSize(200, 400), box1Coords?.size)
- assertNull(box2Coords)
-
- rule.runOnIdle {
- // Start transition from true -> false, size 200,400 -> 100,50
- target = false
- }
- rule.mainClock.advanceTimeByFrame()
- repeat(10) {
- rule.mainClock.advanceTimeByFrame()
- val playTime = 16 * it
- val bounds = box2Coords?.boundsInRoot()
- assertNotNull(bounds)
- val fraction = (playTime / 100f).coerceAtMost(1f)
- val width = 200 * (1 - fraction) + 100 * fraction
- val containerHeight = 400 * (1 - fraction) + 50 * fraction
- // Since we are testing default behavior, the scaling is based on width.
- val height = width / 100f * 50
- assertEquals(width, bounds!!.width, 0.01f)
- assertEquals(height, bounds.height, 0.01f)
- val offset = Alignment.Center.align(
- IntSize(width.roundToInt(), height.roundToInt()),
- IntSize(width.roundToInt(), containerHeight.roundToInt()), layoutDirection!!
- )
- assertEquals(offset, bounds.topLeft.round())
- }
- }
-
- @Test
- fun testScaleToFitBottomCenterAlignment() {
- var target by mutableStateOf(true)
- var box1Coords: LayoutCoordinates? = null
- var box2Coords: LayoutCoordinates? = null
- var layoutDirection: LayoutDirection? = null
- rule.setContent {
- CompositionLocalProvider(LocalDensity provides Density(1f)) {
- layoutDirection = LocalLayoutDirection.current
- AnimatedContent(
- targetState = target,
- transitionSpec = {
- fadeIn() + scaleInToFitContainer(
- Alignment.BottomCenter
- ) togetherWith
- fadeOut(tween(100)) using
- SizeTransform { _, _ ->
- tween(100, easing = LinearEasing)
- }
- }) {
- if (target) {
- Box(
- Modifier
- .onPlaced {
- box1Coords = it
- }
- .size(200.dp, 400.dp))
- } else {
- Box(
- Modifier
- .onPlaced { box2Coords = it }
- .size(100.dp, 50.dp))
- }
- }
- }
- }
-
- rule.waitForIdle()
- rule.mainClock.autoAdvance = false
- assertEquals(IntSize(200, 400), box1Coords?.size)
- assertNull(box2Coords)
-
- rule.runOnIdle {
- // Start transition from true -> false, size 200,400 -> 100,50
- target = false
- }
- rule.mainClock.advanceTimeByFrame()
- repeat(10) {
- rule.mainClock.advanceTimeByFrame()
- val playTime = 16 * it
- val bounds = box2Coords?.boundsInRoot()
- assertNotNull(bounds)
- val fraction = (playTime / 100f).coerceAtMost(1f)
- val width = 200 * (1 - fraction) + 100 * fraction
- val containerHeight = 400 * (1 - fraction) + 50 * fraction
- // Since we are testing default behavior, the scaling is based on width.
- val height = width / 100f * 50
- assertEquals(width, bounds!!.width, 0.01f)
- assertEquals(height, bounds.height, 0.01f)
- val offset = Alignment.BottomCenter.align(
- IntSize(width.roundToInt(), height.roundToInt()),
- IntSize(width.roundToInt(), containerHeight.roundToInt()), layoutDirection!!
- )
- assertEquals(offset, bounds.topLeft.round())
- }
- }
-
- @Test
- fun testScaleToFitInsideBottomEndAlignment() {
- var target by mutableStateOf(true)
- var box1Coords: LayoutCoordinates? = null
- var box2Coords: LayoutCoordinates? = null
- var layoutDirection: LayoutDirection? = null
- rule.setContent {
- CompositionLocalProvider(LocalDensity provides Density(1f)) {
- layoutDirection = LocalLayoutDirection.current
- AnimatedContent(
- targetState = target,
- transitionSpec = {
- fadeIn() + scaleInToFitContainer(
- Alignment.BottomEnd, ContentScale.Inside
- ) togetherWith
- fadeOut(tween(100)) using
- SizeTransform { _, _ ->
- tween(100, easing = LinearEasing)
- }
- }) {
- if (target) {
- Box(
- Modifier
- .onPlaced {
- box1Coords = it
- }
- .size(200.dp, 400.dp))
- } else {
- Box(
- Modifier
- .onPlaced { box2Coords = it }
- .size(100.dp, 50.dp))
- }
- }
- }
- }
-
- rule.waitForIdle()
- rule.mainClock.autoAdvance = false
- assertEquals(IntSize(200, 400), box1Coords?.size)
- assertNull(box2Coords)
-
- rule.runOnIdle {
- // Start transition from true -> false, size 200,400 -> 100,50
- target = false
- }
- rule.mainClock.advanceTimeByFrame()
- repeat(10) {
- rule.mainClock.advanceTimeByFrame()
- val playTime = 16 * it
- val bounds = box2Coords?.boundsInRoot()
- assertNotNull(bounds)
- val fraction = (playTime / 100f).coerceAtMost(1f)
- val width = 100f
- val containerWidth = 200 * (1 - fraction) + 100 * fraction
- val containerHeight = 400 * (1 - fraction) + 50 * fraction
- // Since we are testing default behavior, the scaling is based on width.
- val height = 50f
- assertEquals(width, bounds!!.width, 0.01f)
- assertEquals(height, bounds.height, 0.01f)
- val offset = Alignment.BottomEnd.align(
- IntSize(width.roundToInt(), height.roundToInt()),
- IntSize(containerWidth.roundToInt(), containerHeight.roundToInt()),
- layoutDirection!!
- )
- assertEquals(offset, bounds.topLeft.round())
- }
- }
-
- @Test
fun testRightEnterExitTransitionIsChosenDuringInterruption() {
var flag by mutableStateOf(false)
var fixedPosition: Offset? = null
@@ -1187,72 +852,6 @@
rule.waitForIdle()
}
- @Test
- fun testScaleToFitWithFitHeight() {
- var target by mutableStateOf(true)
- var box1Coords: LayoutCoordinates? = null
- var box2Coords: LayoutCoordinates? = null
- var layoutDirection: LayoutDirection? = null
- rule.setContent {
- CompositionLocalProvider(LocalDensity provides Density(1f)) {
- layoutDirection = LocalLayoutDirection.current
- AnimatedContent(
- targetState = target,
- transitionSpec = {
- fadeIn() + scaleInToFitContainer(
- Alignment.Center, ContentScale.FillHeight
- ) togetherWith fadeOut(tween(100)) using
- SizeTransform { _, _ ->
- tween(100, easing = LinearEasing)
- }
- }) {
- if (target) {
- Box(
- Modifier
- .onPlaced {
- box1Coords = it
- }
- .size(200.dp, 400.dp))
- } else {
- Box(
- Modifier
- .onPlaced { box2Coords = it }
- .size(100.dp, 250.dp))
- }
- }
- }
- }
-
- rule.waitForIdle()
- rule.mainClock.autoAdvance = false
- assertEquals(IntSize(200, 400), box1Coords?.size)
- assertNull(box2Coords)
-
- rule.runOnIdle {
- // Start transition from true -> false, size 200,400 -> 100,250
- target = false
- }
- rule.mainClock.advanceTimeByFrame()
- repeat(10) {
- rule.mainClock.advanceTimeByFrame()
- val playTime = 16 * it
- val bounds = box2Coords?.boundsInRoot()
- assertNotNull(bounds)
- val fraction = (playTime / 100f).coerceAtMost(1f)
- val height = 400 * (1 - fraction) + 250 * fraction
- val containerWidth = 200 * (1 - fraction) + 100 * fraction
- // Since we are testing default behavior, the scaling is based on width.
- val width = height / 250f * 100
- assertEquals(width, bounds!!.width, 0.01f)
- assertEquals(height, bounds.height, 0.01f)
- val offset = Alignment.Center.align(
- IntSize(width.roundToInt(), height.roundToInt()),
- IntSize(containerWidth.roundToInt(), height.roundToInt()), layoutDirection!!
- )
- assertEquals(offset, bounds.topLeft.round())
- }
- }
-
@OptIn(ExperimentalAnimationApi::class)
@Test
fun testExitHoldDefersUntilAllFinished() {
@@ -1327,51 +926,6 @@
assertTrue(box2EnterFinished)
}
- /**
- * This test checks that scaleInToFitContainer and scaleOutToFitContainer handle empty
- * content correctly.
- */
- @Test
- fun testAnimateToEmptyComposable() {
- var isEmpty by mutableStateOf(false)
- var targetSize: IntSize? = null
- rule.setContent {
- CompositionLocalProvider(LocalDensity provides Density(1f)) {
- AnimatedContent(targetState = isEmpty,
- transitionSpec = {
- scaleInToFitContainer() togetherWith scaleOutToFitContainer()
- },
- modifier = Modifier.layout { measurable, constraints ->
- measurable.measure(constraints).run {
- if (isLookingAhead) {
- targetSize = IntSize(width, height)
- }
- layout(width, height) {
- place(0, 0)
- }
- }
- }
- ) {
- if (!it) {
- Box(Modifier.size(200.dp))
- }
- }
- }
- }
- rule.runOnIdle {
- assertEquals(IntSize(200, 200), targetSize)
- isEmpty = true
- }
-
- rule.runOnIdle {
- assertEquals(IntSize.Zero, targetSize)
- isEmpty = !isEmpty
- }
- rule.runOnIdle {
- assertEquals(IntSize(200, 200), targetSize)
- }
- }
-
@OptIn(InternalAnimationApi::class)
private val Transition<*>.playTimeMillis get() = (playTimeNanos / 1_000_000L).toInt()
}
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedContent.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedContent.kt
index 24ce9d9..896308a 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedContent.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedContent.kt
@@ -1,3 +1,4 @@
+
/*
* Copyright 2021 The Android Open Source Project
*
@@ -13,10 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@file:OptIn(InternalAnimationApi::class, ExperimentalAnimationApi::class)
-
+@file:OptIn(InternalAnimationApi::class)
package androidx.compose.animation
-
import androidx.compose.animation.AnimatedContentTransitionScope.SlideDirection.Companion.Down
import androidx.compose.animation.AnimatedContentTransitionScope.SlideDirection.Companion.End
import androidx.compose.animation.AnimatedContentTransitionScope.SlideDirection.Companion.Left
@@ -37,7 +36,6 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.Immutable
-import androidx.compose.runtime.MutableState
import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
@@ -45,44 +43,30 @@
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
-import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue
-import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clipToBounds
-import androidx.compose.ui.graphics.TransformOrigin
-import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.IntrinsicMeasurable
import androidx.compose.ui.layout.IntrinsicMeasureScope
import androidx.compose.ui.layout.Layout
-import androidx.compose.ui.layout.LayoutCoordinates
-import androidx.compose.ui.layout.LookaheadScope
import androidx.compose.ui.layout.Measurable
import androidx.compose.ui.layout.MeasurePolicy
import androidx.compose.ui.layout.MeasureResult
import androidx.compose.ui.layout.MeasureScope
import androidx.compose.ui.layout.ParentDataModifier
import androidx.compose.ui.layout.Placeable
-import androidx.compose.ui.layout.ScaleFactor
import androidx.compose.ui.layout.layout
-import androidx.compose.ui.node.LayoutModifierNode
-import androidx.compose.ui.node.ModifierNodeElement
-import androidx.compose.ui.platform.InspectorInfo
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.LayoutDirection
-import androidx.compose.ui.unit.toSize
import androidx.compose.ui.util.fastForEach
import androidx.compose.ui.util.fastForEachIndexed
import androidx.compose.ui.util.fastMaxOfOrNull
-import androidx.compose.ui.util.fastRoundToInt
-import kotlinx.coroutines.CoroutineScope
-
/**
* [AnimatedContent] is a container that automatically animates its content when [targetState]
* changes. Its [content] for different target states is defined in a mapping between a target
@@ -161,7 +145,6 @@
content = content
)
}
-
/**
* [ContentTransform] defines how the target content (i.e. content associated with target state)
* enters [AnimatedContent] and how the initial content disappears.
@@ -212,7 +195,6 @@
* content with the same index, the target content will be placed on top.
*/
var targetContentZIndex by mutableFloatStateOf(targetContentZIndex)
-
/**
* [sizeTransform] manages the expanding and shrinking of the container if there is any size
* change as new content enters the [AnimatedContent] and old content leaves.
@@ -223,7 +205,6 @@
var sizeTransform: SizeTransform? = sizeTransform
internal set
}
-
/**
* This creates a [SizeTransform] with the provided [clip] and [sizeAnimationSpec]. By default,
* [clip] will be true. This means during the size animation, the content will be clipped to the
@@ -241,7 +222,6 @@
)
}
): SizeTransform = SizeTransformImpl(clip, sizeAnimationSpec)
-
/**
* [SizeTransform] defines how to transform from one size to another when the size of the content
* changes. When [clip] is true, the content will be clipped to the animation size.
@@ -255,14 +235,12 @@
* Whether the content should be clipped using the animated size.
*/
val clip: Boolean
-
/**
* This allows [FiniteAnimationSpec] to be defined based on the [initialSize] before the size
* animation and the [targetSize] of the animation.
*/
fun createAnimationSpec(initialSize: IntSize, targetSize: IntSize): FiniteAnimationSpec<IntSize>
}
-
/**
* Private implementation of SizeTransform interface.
*/
@@ -276,7 +254,6 @@
targetSize: IntSize
): FiniteAnimationSpec<IntSize> = sizeAnimationSpec(initialSize, targetSize)
}
-
/**
* This creates a [ContentTransform] using the provided [EnterTransition] and [exit], where the
* enter and exit transition will be running simultaneously.
@@ -285,14 +262,12 @@
* @sample androidx.compose.animation.samples.AnimatedContentTransitionSpecSample
*/
infix fun EnterTransition.togetherWith(exit: ExitTransition) = ContentTransform(this, exit)
-
@ExperimentalAnimationApi
@Deprecated(
"Infix fun EnterTransition.with(ExitTransition) has been renamed to" +
" togetherWith", ReplaceWith("togetherWith(exit)")
)
infix fun EnterTransition.with(exit: ExitTransition) = ContentTransform(this, exit)
-
/**
* [AnimatedContentTransitionScope] provides functions that are convenient and only applicable in the
* context of [AnimatedContent], such as [slideIntoContainer] and [slideOutOfContainer].
@@ -304,7 +279,6 @@
* @sample androidx.compose.animation.samples.AnimatedContentTransitionSpecSample
*/
infix fun ContentTransform.using(sizeTransform: SizeTransform?): ContentTransform
-
/**
* [SlideDirection] defines the direction of the slide in/out for [slideIntoContainer] and
* [slideOutOfContainer]. The supported directions are: [Left], [Right], [Up] and [Down].
@@ -320,7 +294,6 @@
val Start = SlideDirection(4)
val End = SlideDirection(5)
}
-
override fun toString(): String {
return when (this) {
Left -> "Left"
@@ -333,7 +306,6 @@
}
}
}
-
/**
* This defines a horizontal/vertical slide-in that is specific to [AnimatedContent] from the
* edge of the container. The offset amount is dynamically calculated based on the current
@@ -363,7 +335,6 @@
),
initialOffset: (offsetForFullSlide: Int) -> Int = { it }
): EnterTransition
-
/**
* This defines a horizontal/vertical exit transition to completely slide out of the
* [AnimatedContent] container. The offset amount is dynamically calculated based on the current
@@ -392,7 +363,6 @@
),
targetOffset: (offsetForFullSlide: Int) -> Int = { it }
): ExitTransition
-
/**
* [KeepUntilTransitionsFinished] defers the disposal of the exiting content till both enter and
* exit transitions have finished. It can be combined with other [ExitTransition]s using
@@ -408,81 +378,28 @@
*/
val ExitTransition.Companion.KeepUntilTransitionsFinished: ExitTransition
get() = KeepUntilTransitionsFinished
-
/**
* This returns the [Alignment] specified on [AnimatedContent].
*/
val contentAlignment: Alignment
-
- /**
- * [scaleInToFitContainer] defines an [EnterTransition] that scales the incoming content
- * based on the (potentially animating) container (i.e. [AnimatedContent]) size. [contentScale]
- * defines the scaling function. By default, the incoming content will be scaled based on its
- * width (i.e. [ContentScale.FillWidth]), so that the content fills the container's width.
- * [alignment] can be used to specify the alignment of the scaled content
- * within the container of AnimatedContent.
- *
- * [scaleInToFitContainer] will measure the content using the final (i.e. lookahead)
- * constraints, in order to obtain the final layout and apply scaling to that final layout
- * while the container is resizing.
- *
- * @sample androidx.compose.animation.samples.ScaleInToFitContainerSample
- */
- @ExperimentalAnimationApi
- fun scaleInToFitContainer(
- alignment: Alignment = contentAlignment,
- contentScale: ContentScale = ContentScale.FillWidth
- ): EnterTransition
-
- /**
- * [scaleOutToFitContainer] defines an [ExitTransition] that scales the outgoing content
- * based on the (potentially animating) container (i.e. [AnimatedContent]) size.
- * [contentScale] defines the scaling function. By default, the outgoing content will be scaled
- * using [ContentScale.FillWidth], so that it fits the container's width.
- * [alignment] can be used to specify the alignment of the scaled content
- * within the container of AnimatedContent.
- *
- * [scaleOutToFitContainer] will measure the content using the constraints cached
- * at the beginning of the exit animation so that the content does not get re-laid out during
- * the exit animation, and instead only scaling will be applied as the container resizes.
- *
- * **IMPORTANT**: [scaleOutToFitContainer] does NOT keep the exiting content from being
- * disposed. Therefore it relies on other ExitTransitions such as [fadeOut] to define a
- * timeframe for when should be active.
- *
- * @sample androidx.compose.animation.samples.ScaleInToFitContainerSample
- */
- @ExperimentalAnimationApi
- fun scaleOutToFitContainer(
- alignment: Alignment = contentAlignment,
- contentScale: ContentScale = ContentScale.FillWidth,
- ): ExitTransition
}
-
-internal class AnimatedContentRootScope<S> internal constructor(
+internal class AnimatedContentTransitionScopeImpl<S> internal constructor(
internal val transition: Transition<S>,
- lookaheadScope: LookaheadScope,
- internal val coroutineScope: CoroutineScope,
override var contentAlignment: Alignment,
internal var layoutDirection: LayoutDirection
-) : AnimatedContentTransitionScope<S>, LookaheadScope by lookaheadScope {
- lateinit var rootCoords: LayoutCoordinates
- lateinit var rootLookaheadCoords: LayoutCoordinates
-
+) : AnimatedContentTransitionScope<S> {
/**
* Initial state of a Transition Segment. This is the state that transition starts from.
*/
override val initialState: S
@Suppress("UnknownNullness")
get() = transition.segment.initialState
-
/**
* Target state of a Transition Segment. This is the state that transition will end on.
*/
override val targetState: S
@Suppress("UnknownNullness")
get() = transition.segment.targetState
-
/**
* Customizes the [SizeTransform] of a given [ContentTransform]. For example:
*
@@ -491,7 +408,6 @@
override infix fun ContentTransform.using(sizeTransform: SizeTransform?) = this.apply {
this.sizeTransform = sizeTransform
}
-
/**
* This defines a horizontal/vertical slide-in that is specific to [AnimatedContent] from the
* edge of the container. The offset amount is dynamically calculated based on the current
@@ -528,24 +444,19 @@
currentSize.width - calculateOffset(IntSize(it, it), currentSize).x
)
}
-
towards.isRight -> slideInHorizontally(animationSpec) {
initialOffset.invoke(-calculateOffset(IntSize(it, it), currentSize).x - it)
}
-
towards == Up -> slideInVertically(animationSpec) {
initialOffset.invoke(
currentSize.height - calculateOffset(IntSize(it, it), currentSize).y
)
}
-
towards == Down -> slideInVertically(animationSpec) {
initialOffset.invoke(-calculateOffset(IntSize(it, it), currentSize).y - it)
}
-
else -> EnterTransition.None
}
-
private val AnimatedContentTransitionScope.SlideDirection.isLeft: Boolean
get() {
return this == Left || this == Start && layoutDirection == LayoutDirection.Ltr ||
@@ -556,11 +467,9 @@
return this == Right || this == Start && layoutDirection == LayoutDirection.Rtl ||
this == End && layoutDirection == LayoutDirection.Ltr
}
-
private fun calculateOffset(fullSize: IntSize, currentSize: IntSize): IntOffset {
return contentAlignment.align(fullSize, currentSize, LayoutDirection.Ltr)
}
-
/**
* This defines a horizontal/vertical exit transition to completely slide out of the
* [AnimatedContent] container. The offset amount is dynamically calculated based on the current
@@ -596,69 +505,32 @@
val targetSize = targetSizeMap[transition.targetState]?.value ?: IntSize.Zero
targetOffset.invoke(-calculateOffset(IntSize(it, it), targetSize).x - it)
}
-
towards.isRight -> slideOutHorizontally(animationSpec) {
val targetSize = targetSizeMap[transition.targetState]?.value ?: IntSize.Zero
targetOffset.invoke(
-calculateOffset(IntSize(it, it), targetSize).x + targetSize.width
)
}
-
towards == Up -> slideOutVertically(animationSpec) {
val targetSize = targetSizeMap[transition.targetState]?.value ?: IntSize.Zero
targetOffset.invoke(-calculateOffset(IntSize(it, it), targetSize).y - it)
}
-
towards == Down -> slideOutVertically(animationSpec) {
val targetSize = targetSizeMap[transition.targetState]?.value ?: IntSize.Zero
targetOffset.invoke(
-calculateOffset(IntSize(it, it), targetSize).y + targetSize.height
)
}
-
else -> ExitTransition.None
}
}
-
- @ExperimentalAnimationApi
- override fun scaleInToFitContainer(
- alignment: Alignment,
- contentScale: ContentScale
- ): EnterTransition = EnterTransition(
- ScaleToFitTransitionKey, ScaleToFitInLookaheadElement(
- this@AnimatedContentRootScope,
- contentScale,
- alignment
- )
- )
-
- @ExperimentalAnimationApi
- override fun scaleOutToFitContainer(
- alignment: Alignment,
- contentScale: ContentScale
- ): ExitTransition = ExitTransition(
- ScaleToFitTransitionKey,
- ScaleToFitInLookaheadElement(
- this@AnimatedContentRootScope,
- contentScale,
- alignment
- )
- )
-
internal var measuredSize: IntSize by mutableStateOf(IntSize.Zero)
- internal val targetSizeMap = mutableMapOf<S, MutableState<IntSize>>()
+ internal val targetSizeMap = mutableMapOf<S, State<IntSize>>()
internal var animatedSize: State<IntSize>? = null
-
// Current size of the container. If there's any size animation, the current size will be
// read from the animation value, otherwise we'll use the current
- internal val currentSize: IntSize
+ private val currentSize: IntSize
get() = animatedSize?.value ?: measuredSize
-
- internal val targetSize: IntSize
- get() = requireNotNull(targetSizeMap[targetState]) {
- "Error: Target size for AnimatedContent has not been set."
- }.value
-
@Suppress("ComposableModifierFactory", "ModifierFactoryExtensionFunction")
@Composable
internal fun createSizeAnimationModifier(
@@ -668,47 +540,67 @@
val sizeTransform = rememberUpdatedState(contentTransform.sizeTransform)
if (transition.currentState == transition.targetState) {
shouldAnimateSize = false
- } else if (sizeTransform.value != null) {
- shouldAnimateSize = true
+ } else {
+ // TODO: CurrentSize is only relevant to enter/exit transition, not so much for sizeAnim
+ if (sizeTransform.value != null) {
+ shouldAnimateSize = true
+ }
}
-
return if (shouldAnimateSize) {
- val sizeAnimation =
- transition.createDeferredAnimation(IntSize.VectorConverter, "sizeTransform")
+ val sizeAnimation = transition.createDeferredAnimation(IntSize.VectorConverter)
remember(sizeAnimation) {
(if (sizeTransform.value?.clip == false) Modifier else Modifier.clipToBounds())
- .then(
- SizeModifierInLookaheadElement(
- this, sizeAnimation, sizeTransform
- )
- )
+ .then(SizeModifier(sizeAnimation, sizeTransform))
}
} else {
animatedSize = null
Modifier
}
}
-
// This helps track the target measurable without affecting the placement order. Target
// measurable needs to be measured first but placed last.
- internal data class ChildData<T>(var targetState: T) : ParentDataModifier {
+ internal data class ChildData(var isTarget: Boolean) : ParentDataModifier {
override fun Density.modifyParentData(parentData: Any?): Any {
return this@ChildData
}
}
+ private inner class SizeModifier(
+ val sizeAnimation: Transition<S>.DeferredAnimation<IntSize, AnimationVector2D>,
+ val sizeTransform: State<SizeTransform?>,
+ ) : LayoutModifierWithPassThroughIntrinsics() {
+ override fun MeasureScope.measure(
+ measurable: Measurable,
+ constraints: Constraints
+ ): MeasureResult {
+ val placeable = measurable.measure(constraints)
+ val size = sizeAnimation.animate(
+ transitionSpec = {
+ val initial = targetSizeMap[initialState]?.value ?: IntSize.Zero
+ val target = targetSizeMap[targetState]?.value ?: IntSize.Zero
+ sizeTransform.value?.createAnimationSpec(initial, target) ?: spring()
+ }
+ ) {
+ targetSizeMap[it]?.value ?: IntSize.Zero
+ }
+ animatedSize = size
+ val offset = contentAlignment.align(
+ IntSize(placeable.width, placeable.height), size.value, LayoutDirection.Ltr
+ )
+ return layout(size.value.width, size.value.height) {
+ placeable.place(offset)
+ }
+ }
+ }
}
-
/**
* Receiver scope for content lambda for AnimatedContent. In this scope,
* [transition][AnimatedVisibilityScope.transition] can be used to observe the state of the
* transition, or to add more enter/exit transition for the content.
*/
sealed interface AnimatedContentScope : AnimatedVisibilityScope
-
private class AnimatedContentScopeImpl internal constructor(
animatedVisibilityScope: AnimatedVisibilityScope
) : AnimatedContentScope, AnimatedVisibilityScope by animatedVisibilityScope
-
/**
* [AnimatedContent] is a container that automatically animates its content when
* [Transition.targetState] changes. Its [content] for different target states is defined in a
@@ -772,268 +664,145 @@
content: @Composable() AnimatedContentScope.(targetState: S) -> Unit
) {
val layoutDirection = LocalLayoutDirection.current
- val coroutineScope = rememberCoroutineScope()
- LookaheadScope {
- val rootScope = remember(this@AnimatedContent) {
- AnimatedContentRootScope(
- this@AnimatedContent, this@LookaheadScope,
- coroutineScope, contentAlignment, layoutDirection
- )
- }
- val currentlyVisible = remember(this) { mutableStateListOf(currentState) }
- val contentMap = remember(this) { mutableMapOf<S, @Composable() () -> Unit>() }
- val constraintsMap = remember { mutableMapOf<S, Constraints>() }
-
- // This is needed for tooling because it could change currentState directly,
- // as opposed to changing target only. When that happens we need to clear all the
- // visible content and only display the content for the new current state and target state.
- if (!currentlyVisible.contains(currentState)) {
+ val rootScope = remember(this) {
+ AnimatedContentTransitionScopeImpl(this, contentAlignment, layoutDirection)
+ }
+ // TODO: remove screen as soon as they are animated out
+ val currentlyVisible = remember(this) { mutableStateListOf(currentState) }
+ val contentMap = remember(this) { mutableMapOf<S, @Composable() () -> Unit>() }
+ // This is needed for tooling because it could change currentState directly,
+ // as opposed to changing target only. When that happens we need to clear all the
+ // visible content and only display the content for the new current state and target state.
+ if (!currentlyVisible.contains(currentState)) {
+ currentlyVisible.clear()
+ currentlyVisible.add(currentState)
+ }
+ if (currentState == targetState) {
+ if (currentlyVisible.size != 1 || currentlyVisible[0] != currentState) {
currentlyVisible.clear()
currentlyVisible.add(currentState)
}
-
- if (currentState == targetState) {
- if (currentlyVisible.size != 1 || currentlyVisible[0] != currentState) {
- currentlyVisible.clear()
- currentlyVisible.add(currentState)
- }
- if (contentMap.size != 1 || contentMap.containsKey(currentState)) {
- contentMap.clear()
- }
- val targetConstraints = constraintsMap[targetState]
- constraintsMap.clear()
- targetConstraints?.let { constraintsMap[targetState] = it }
- // TODO: Do we want to support changing contentAlignment amid animation?
- rootScope.contentAlignment = contentAlignment
- rootScope.layoutDirection = layoutDirection
- } else if (!currentlyVisible.contains(targetState)) {
- // Currently visible list always keeps the targetState at the end of the list, unless
- // it's already in the list in the case of interruption. This makes the composable
- // associated with the targetState get placed last, so the target composable will be
- // displayed on top of content associated with other states, unless zIndex is specified.
- // Replace the target with the same key if any.
- val id = currentlyVisible.indexOfFirst { contentKey(it) == contentKey(targetState) }
- if (id == -1) {
- currentlyVisible.add(targetState)
- } else {
- currentlyVisible[id] = targetState
- }
- }
- if (!contentMap.containsKey(targetState) || !contentMap.containsKey(currentState)) {
+ if (contentMap.size != 1 || contentMap.containsKey(currentState)) {
contentMap.clear()
- currentlyVisible.fastForEach { stateForContent ->
- contentMap[stateForContent] = {
- // Only update content transform when enter/exit _direction_ changes.
- val contentTransform = remember(stateForContent == targetState) {
- rootScope.transitionSpec()
- }
- PopulateContentFor(
- stateForContent, rootScope, contentTransform, currentlyVisible, content
- )
- }
- }
}
- val contentTransform = remember(rootScope, segment) { transitionSpec(rootScope) }
- val sizeModifier = rootScope.createSizeAnimationModifier(contentTransform)
- Layout(
- modifier = modifier
- .layout { measurable, constraints ->
- val placeable = measurable.measure(constraints)
- layout(placeable.width, placeable.height) {
- coordinates?.let {
- if (isLookingAhead) {
- rootScope.rootLookaheadCoords = it
- } else {
- rootScope.rootCoords = it
+ // TODO: Do we want to support changing contentAlignment amid animation?
+ rootScope.contentAlignment = contentAlignment
+ rootScope.layoutDirection = layoutDirection
+ }
+ // Currently visible list always keeps the targetState at the end of the list, unless it's
+ // already in the list in the case of interruption. This makes the composable associated with
+ // the targetState get placed last, so the target composable will be displayed on top of
+ // content associated with other states, unless zIndex is specified.
+ if (currentState != targetState && !currentlyVisible.contains(targetState)) {
+ // Replace the target with the same key if any
+ val id = currentlyVisible.indexOfFirst { contentKey(it) == contentKey(targetState) }
+ if (id == -1) {
+ currentlyVisible.add(targetState)
+ } else {
+ currentlyVisible[id] = targetState
+ }
+ }
+ if (!contentMap.containsKey(targetState) || !contentMap.containsKey(currentState)) {
+ contentMap.clear()
+ currentlyVisible.fastForEach { stateForContent ->
+ contentMap[stateForContent] = {
+ val specOnEnter = remember { transitionSpec(rootScope) }
+ // NOTE: enter and exit for this AnimatedVisibility will be using different spec,
+ // naturally.
+ val exit =
+ remember(segment.targetState == stateForContent) {
+ if (segment.targetState == stateForContent) {
+ ExitTransition.None
+ } else {
+ rootScope.transitionSpec().initialContentExit
+ }
+ }
+ val childData = remember {
+ AnimatedContentTransitionScopeImpl.ChildData(stateForContent == targetState)
+ }
+ // TODO: Will need a custom impl of this to: 1) get the signal for when
+ // the animation is finished, 2) get the target size properly
+ AnimatedEnterExitImpl(
+ this,
+ { it == stateForContent },
+ enter = specOnEnter.targetContentEnter,
+ exit = exit,
+ modifier = Modifier
+ .layout { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
+ layout(placeable.width, placeable.height) {
+ placeable.place(0, 0, zIndex = specOnEnter.targetContentZIndex)
}
}
- placeable.place(0, 0)
+ .then(childData.apply { isTarget = stateForContent == targetState }),
+ shouldDisposeBlock = { currentState, targetState ->
+ currentState == EnterExitState.PostExit &&
+ targetState == EnterExitState.PostExit &&
+ !exit.data.hold
+ }
+ ) {
+ // TODO: Should Transition.AnimatedVisibility have an end listener?
+ DisposableEffect(this) {
+ onDispose {
+ currentlyVisible.remove(stateForContent)
+ rootScope.targetSizeMap.remove(stateForContent)
+ }
+ }
+ rootScope.targetSizeMap[stateForContent] =
+ (this as AnimatedVisibilityScopeImpl).targetSize
+ with(remember { AnimatedContentScopeImpl(this) }) {
+ content(stateForContent)
}
}
- .then(sizeModifier),
- content = {
- currentlyVisible.fastForEach {
- key(contentKey(it)) { contentMap[it]?.invoke() }
- }
- },
- measurePolicy = remember {
- AnimatedContentMeasurePolicy(
- rootScope, constraintsMap
- )
}
- )
- }
-}
-
-/**
- * Creates content for a specific state based on the current Transition, enter/exit and the content
- * lookup lambda.
- */
-@Composable
-private inline fun <S> Transition<S>.PopulateContentFor(
- stateForContent: S,
- rootScope: AnimatedContentRootScope<S>,
- contentTransform: ContentTransform,
- currentlyVisible: SnapshotStateList<S>,
- crossinline content: @Composable() AnimatedContentScope.(targetState: S) -> Unit
-) {
- var activeEnter by remember { mutableStateOf(contentTransform.targetContentEnter) }
- var activeExit by remember { mutableStateOf(ExitTransition.None) }
- val targetZIndex = remember { contentTransform.targetContentZIndex }
-
- val isEntering = targetState == stateForContent
- if (targetState == currentState) {
- // Transition finished, reset active enter & exit.
- activeEnter = EnterTransition.None
- activeExit = ExitTransition.None
- } else if (isEntering) {
- // If the previous enter transition never finishes when multiple
- // interruptions happen, avoid adding new enter transitions for simplicity.
- if (activeEnter == EnterTransition.None)
- activeEnter += contentTransform.targetContentEnter
- } else {
- // If the previous exit transition never finishes when multiple
- // interruptions happen, avoid adding new enter transitions for simplicity.
- if (activeExit == ExitTransition.None) {
- activeExit += contentTransform.initialContentExit
}
}
-
- val childData = remember { AnimatedContentRootScope.ChildData(stateForContent) }
- AnimatedEnterExitImpl(
- this,
- { it == stateForContent },
- enter = activeEnter,
- exit = activeExit,
- modifier = Modifier
- .layout { measurable, constraints ->
- val placeable = measurable.measure(constraints)
- layout(placeable.width, placeable.height) {
- placeable.place(0, 0, zIndex = targetZIndex)
+ val contentTransform = remember(rootScope, segment) { transitionSpec(rootScope) }
+ val sizeModifier = rootScope.createSizeAnimationModifier(contentTransform)
+ Layout(
+ modifier = modifier.then(sizeModifier),
+ content = {
+ currentlyVisible.fastForEach {
+ key(contentKey(it)) {
+ contentMap[it]?.invoke()
}
}
- .then(childData)
- .then(
- if (isEntering) {
- activeEnter[ScaleToFitTransitionKey]
- ?: activeExit[ScaleToFitTransitionKey] ?: Modifier
- } else {
- activeExit[ScaleToFitTransitionKey]
- ?: activeEnter[ScaleToFitTransitionKey] ?: Modifier
- }
- ),
- shouldDisposeBlock = { currentState, targetState ->
- currentState == EnterExitState.PostExit &&
- targetState == EnterExitState.PostExit && !activeExit.data.hold
},
- onLookaheadMeasured = {
- if (isEntering) rootScope.targetSizeMap.getOrPut(targetState) {
- mutableStateOf(it)
- }.value = it
- }
- ) {
- // TODO: Should Transition.AnimatedVisibility have an end listener?
- DisposableEffect(this) {
- onDispose {
- currentlyVisible.remove(stateForContent)
- rootScope.targetSizeMap.remove(stateForContent)
- }
- }
- with(remember { AnimatedContentScopeImpl(this) }) {
- content(stateForContent)
- }
- }
+ measurePolicy = remember { AnimatedContentMeasurePolicy(rootScope) }
+ )
}
-
-/**
- * This measure policy returns the target content size in the lookahead pass, and the max width
- * and height needed for all contents to fit during the main measure pass.
- *
- * The measure policy will measure all children with lookahead constraints. For outgoing content,
- * we will use the constraints recorded before the content started to exit. This enables the
- * outgoing content to not change constraints on its way out.
- */
-@Suppress("UNCHECKED_CAST")
-private class AnimatedContentMeasurePolicy<S>(
- val rootScope: AnimatedContentRootScope<S>,
- val constraintsMap: MutableMap<S, Constraints>
-) : MeasurePolicy {
+private class AnimatedContentMeasurePolicy(val rootScope: AnimatedContentTransitionScopeImpl<*>) :
+ MeasurePolicy {
override fun MeasureScope.measure(
measurables: List<Measurable>,
constraints: Constraints
): MeasureResult {
val placeables = arrayOfNulls<Placeable>(measurables.size)
// Measure the target composable first (but place it on top unless zIndex is specified)
- val targetState = rootScope.targetState
measurables.fastForEachIndexed { index, measurable ->
- if ((measurable.parentData as? AnimatedContentRootScope.ChildData<*>)
- ?.targetState == targetState
+ if ((measurable.parentData as? AnimatedContentTransitionScopeImpl.ChildData)
+ ?.isTarget == true
) {
- // Record lookahead constraints and always use it to measure target content.
- val lookaheadConstraints = if (isLookingAhead) {
- constraintsMap[targetState] = constraints
- constraints
- } else {
- requireNotNull(constraintsMap[targetState]) {
- "Lookahead pass was never done for target content."
- }
- }
- placeables[index] = measurable.measure(lookaheadConstraints)
+ placeables[index] = measurable.measure(constraints)
}
}
- // If no content is defined for target state, set the target size to zero
- rootScope.targetSizeMap.getOrPut(targetState) { mutableStateOf(IntSize.Zero) }
-
- val initialState = rootScope.initialState
// Measure the non-target composables after target, since these have no impact on
// container size in the size animation.
measurables.fastForEachIndexed { index, measurable ->
- val stateForContent =
- (measurable.parentData as? AnimatedContentRootScope.ChildData<*>)
- ?.targetState
if (placeables[index] == null) {
- val lookaheadConstraints =
- constraintsMap[stateForContent] ?: if (isLookingAhead) {
- constraintsMap[stateForContent as S] = constraints
- constraints
- } else {
- requireNotNull(constraintsMap[stateForContent as S]) {
- "Error: Lookahead pass never happened for state: $stateForContent"
- }
- }
- placeables[index] = measurable.measure(lookaheadConstraints).also {
- // If the initial state size isn't in the map, add it. This could be possible
- // when the initial state is specified to be different than target state upon
- // entering composition.
- if (stateForContent == initialState &&
- isLookingAhead &&
- !rootScope.targetSizeMap.containsKey(initialState)
- ) {
- rootScope.targetSizeMap[initialState] =
- mutableStateOf(IntSize(it.width, it.height))
- }
- }
+ placeables[index] = measurable.measure(constraints)
}
}
- val lookaheadSize = rootScope.targetSizeMap[targetState]!!.value
- val measuredWidth = if (isLookingAhead) {
- lookaheadSize.width
- } else {
- placeables.maxByOrNull { it?.width ?: 0 }?.width ?: 0
- }
- val measuredHeight = if (isLookingAhead) {
- lookaheadSize.height
- } else {
- placeables.maxByOrNull { it?.height ?: 0 }?.height ?: 0
- }
- rootScope.measuredSize = IntSize(measuredWidth, measuredHeight)
+ val maxWidth: Int = placeables.maxByOrNull { it?.width ?: 0 }?.width ?: 0
+ val maxHeight = placeables.maxByOrNull { it?.height ?: 0 }?.height ?: 0
+ rootScope.measuredSize = IntSize(maxWidth, maxHeight)
// Position the children.
- return layout(measuredWidth, measuredHeight) {
+ return layout(maxWidth, maxHeight) {
placeables.forEach { placeable ->
placeable?.let {
val offset = rootScope.contentAlignment.align(
IntSize(it.width, it.height),
- IntSize(measuredWidth, measuredHeight),
+ IntSize(maxWidth, maxHeight),
LayoutDirection.Ltr
)
it.place(offset.x, offset.y)
@@ -1041,178 +810,20 @@
}
}
}
-
override fun IntrinsicMeasureScope.minIntrinsicWidth(
measurables: List<IntrinsicMeasurable>,
height: Int
) = measurables.fastMaxOfOrNull { it.minIntrinsicWidth(height) } ?: 0
-
override fun IntrinsicMeasureScope.minIntrinsicHeight(
measurables: List<IntrinsicMeasurable>,
width: Int
) = measurables.fastMaxOfOrNull { it.minIntrinsicHeight(width) } ?: 0
-
override fun IntrinsicMeasureScope.maxIntrinsicWidth(
measurables: List<IntrinsicMeasurable>,
height: Int
) = measurables.fastMaxOfOrNull { it.maxIntrinsicWidth(height) } ?: 0
-
override fun IntrinsicMeasureScope.maxIntrinsicHeight(
measurables: List<IntrinsicMeasurable>,
width: Int
) = measurables.fastMaxOfOrNull { it.maxIntrinsicHeight(width) } ?: 0
}
-
-private class SizeModifierInLookaheadNode<S>(
- var rootScope: AnimatedContentRootScope<S>,
- var sizeAnimation: Transition<S>.DeferredAnimation<IntSize, AnimationVector2D>,
- var sizeTransform: State<SizeTransform?>,
-) : LayoutModifierNodeWithPassThroughIntrinsics() {
-
- override fun MeasureScope.measure(
- measurable: Measurable,
- constraints: Constraints,
- ): MeasureResult {
- val placeable = measurable.measure(constraints)
- val size = if (isLookingAhead) {
- val targetSize = IntSize(placeable.width, placeable.height)
- // lookahead pass
- rootScope.animatedSize = sizeAnimation.animate(
- transitionSpec = {
- val initial = rootScope.targetSizeMap[initialState]?.value ?: IntSize.Zero
- val target = rootScope.targetSizeMap[targetState]?.value ?: IntSize.Zero
- sizeTransform.value?.createAnimationSpec(initial, target) ?: spring()
- }
- ) {
- rootScope.targetSizeMap[it]?.value ?: IntSize.Zero
- }
- targetSize
- } else {
- rootScope.animatedSize!!.value
- }
- val offset = rootScope.contentAlignment.align(
- IntSize(placeable.width, placeable.height), size, LayoutDirection.Ltr
- )
- return layout(size.width, size.height) {
- placeable.place(offset)
- }
- }
-}
-
-private data class SizeModifierInLookaheadElement<S>(
- val rootScope: AnimatedContentRootScope<S>,
- val sizeAnimation: Transition<S>.DeferredAnimation<IntSize, AnimationVector2D>,
- val sizeTransform: State<SizeTransform?>,
-) : ModifierNodeElement<SizeModifierInLookaheadNode<S>>() {
- override fun create(): SizeModifierInLookaheadNode<S> {
- return SizeModifierInLookaheadNode(rootScope, sizeAnimation, sizeTransform)
- }
-
- override fun update(node: SizeModifierInLookaheadNode<S>) {
- node.rootScope = rootScope
- node.sizeTransform = sizeTransform
- node.sizeAnimation = sizeAnimation
- }
-
- override fun InspectorInfo.inspectableProperties() {
- name = "sizeTransform"
- properties["sizeTransform"] = sizeTransform
- properties["sizeAnimation"] = sizeAnimation
- }
-}
-
-private data class ScaleToFitInLookaheadElement(
- val rootScope: AnimatedContentRootScope<*>,
- val contentScale: ContentScale,
- val alignment: Alignment
-) : ModifierNodeElement<ScaleToFitInLookaheadNode>() {
- override fun create(): ScaleToFitInLookaheadNode =
- ScaleToFitInLookaheadNode(rootScope, contentScale, alignment)
-
- override fun update(node: ScaleToFitInLookaheadNode) {
- node.rootScope = rootScope
- node.contentScale = contentScale
- node.alignment = alignment
- }
-
- override fun InspectorInfo.inspectableProperties() {
- name = "scaleToFit"
- properties["rootScope"] = rootScope
- properties["scale"] = contentScale
- properties["alignment"] = alignment
- }
-}
-
-/**
- * Creates a Modifier Node to: 1) measure the layout with lookahead constraints, 2) scale the
- * resulting (potentially unfitting) layout based on the resizing container using the given
- * [contentScale] lambda.
- *
- * This node is designed to work in a lookahead scope, therefore it anticipates lookahead pass
- * before actual measure pass.
- */
-private class ScaleToFitInLookaheadNode(
- var rootScope: AnimatedContentRootScope<*>,
- var contentScale: ContentScale,
- var alignment: Alignment
-) : Modifier.Node(), LayoutModifierNode {
- private var lookaheadConstraints: Constraints = Constraints()
- set(value) {
- lookaheadPassOccurred = true
- field = value
- }
- get() {
- require(lookaheadPassOccurred) {
- "Error: Attempting to read lookahead constraints before lookahead pass."
- }
- return field
- }
- private var lookaheadPassOccurred = false
-
- override fun onDetach() {
- super.onDetach()
- lookaheadPassOccurred = false
- }
-
- override fun MeasureScope.measure(
- measurable: Measurable,
- constraints: Constraints
- ): MeasureResult {
- if (isLookingAhead) lookaheadConstraints = constraints
- // Measure with lookahead constraints.
- val placeable = measurable.measure(lookaheadConstraints)
- val contentSize = IntSize(placeable.width, placeable.height)
- val sizeToReport = if (isLookingAhead) {
- // report size of the target content, as that's what the content will be scaled to.
- rootScope.targetSize
- } else {
- // report current animated size && scale based on that and full size
- rootScope.currentSize
- }
- val resolvedScale =
- if (contentSize.width == 0 || contentSize.height == 0) {
- ScaleFactor(1f, 1f)
- } else
- contentScale.computeScaleFactor(contentSize.toSize(), sizeToReport.toSize())
- return layout(sizeToReport.width, sizeToReport.height) {
- val (x, y) = alignment.align(
- IntSize(
- (contentSize.width * resolvedScale.scaleX).fastRoundToInt(),
- (contentSize.height * resolvedScale.scaleY).fastRoundToInt()
- ),
- sizeToReport,
- layoutDirection
- )
- placeable.placeWithLayer(x, y) {
- scaleX = resolvedScale.scaleX
- scaleY = resolvedScale.scaleY
- transformOrigin = TransformOrigin(0f, 0f)
- }
- }
- }
-}
-
-/**
- * Fixed key to read customization out of EnterTransition and ExitTransition.
- */
-private val ScaleToFitTransitionKey = Any()
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/androidUnitTest/kotlin/androidx/compose/compiler/plugins/kotlin/ComposerParamSignatureTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/androidUnitTest/kotlin/androidx/compose/compiler/plugins/kotlin/ComposerParamSignatureTests.kt
index 190bd74..bbb3dc3 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/androidUnitTest/kotlin/androidx/compose/compiler/plugins/kotlin/ComposerParamSignatureTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/androidUnitTest/kotlin/androidx/compose/compiler/plugins/kotlin/ComposerParamSignatureTests.kt
@@ -1814,4 +1814,35 @@
) {
assertFalse(it.contains("INVOKESTATIC kotlin/jvm/internal/Reflection.property0 (Lkotlin/jvm/internal/PropertyReference0;)Lkotlin/reflect/KProperty0;"))
}
+
+ @Test
+ fun testComposableAdaptedFunctionReference() = validateBytecode(
+ """
+ class ScrollState {
+ fun test(index: Int, default: Int = 0): Int = 0
+ fun testExact(index: Int): Int = 0
+ }
+ fun scrollState(): ScrollState = TODO()
+
+ @Composable fun rememberFooInline() = fooInline(scrollState()::test)
+ @Composable fun rememberFoo() = foo(scrollState()::test)
+ @Composable fun rememberFooExactInline() = fooInline(scrollState()::testExact)
+ @Composable fun rememberFooExact() = foo(scrollState()::testExact)
+
+ @Composable
+ inline fun fooInline(block: (Int) -> Int) = block(0)
+
+ @Composable
+ fun foo(block: (Int) -> Int) = block(0)
+ """,
+ validate = {
+ // Validate that function references in inline calls are actually getting inlined
+ assertFalse(
+ it.contains("""INVOKESPECIAL Test_0Kt${'$'}rememberFooInline$1$1.<init> (Ljava/lang/Object;)V""")
+ )
+ assertFalse(
+ it.contains("""INVOKESPECIAL Test_0Kt${'$'}rememberFooExactInline$1$1.<init> (Ljava/lang/Object;)V""")
+ )
+ }
+ )
}
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/jvmTest/kotlin/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/jvmTest/kotlin/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTests.kt
index 3c11d14..31468ef 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/jvmTest/kotlin/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/jvmTest/kotlin/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTests.kt
@@ -2376,4 +2376,37 @@
}
""".trimIndent()
)
+
+ @Test
+ fun testGroupsInLoops() = verifyGoldenComposeIrTransform(
+ """
+ import androidx.compose.runtime.*
+
+ @Composable
+ private fun KeyContent1(items: List<Int>) {
+ items.forEach { item ->
+ if (item > -1) {
+ key(item) {
+ remember {
+ item
+ }
+ }
+ }
+ }
+ }
+
+ @Composable
+ private fun KeyContent2(items: List<Int>) {
+ for (item in items) {
+ if (item > -1) {
+ key(item) {
+ remember {
+ item
+ }
+ }
+ }
+ }
+ }
+ """
+ )
}
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/jvmTest/kotlin/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/jvmTest/kotlin/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTransformTests.kt
index b8dceda..4164c6d 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/jvmTest/kotlin/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/jvmTest/kotlin/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTransformTests.kt
@@ -652,4 +652,28 @@
}
"""
)
+
+ @Test
+ fun testAdaptedFunctionRef() = verifyGoldenComposeIrTransform(
+ """
+ import androidx.compose.runtime.Composable
+
+ class ScrollState {
+ fun test(index: Int, default: Int = 0): Int = 0
+ fun testExact(index: Int): Int = 0
+ }
+ fun scrollState(): ScrollState = TODO()
+
+ @Composable fun rememberFooInline() = fooInline(scrollState()::test)
+ @Composable fun rememberFoo() = foo(scrollState()::test)
+ @Composable fun rememberFooExactInline() = fooInline(scrollState()::testExact)
+ @Composable fun rememberFooExact() = foo(scrollState()::testExact)
+
+ @Composable
+ inline fun fooInline(block: (Int) -> Int) = block(0)
+
+ @Composable
+ fun foo(block: (Int) -> Int) = block(0)
+ """,
+ )
}
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/jvmTest/kotlin/androidx/compose/compiler/plugins/kotlin/analysis/ComposableCheckerTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/jvmTest/kotlin/androidx/compose/compiler/plugins/kotlin/analysis/ComposableCheckerTests.kt
index 44c3e39..f4a354e 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/jvmTest/kotlin/androidx/compose/compiler/plugins/kotlin/analysis/ComposableCheckerTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/jvmTest/kotlin/androidx/compose/compiler/plugins/kotlin/analysis/ComposableCheckerTests.kt
@@ -1576,4 +1576,42 @@
"""
)
}
+
+ @Test
+ fun testErrorInAnonymousFunctionPropertyInitializer() {
+ assumeTrue(!useFir)
+ check(
+ """
+ import androidx.compose.runtime.Composable
+ @Composable fun ComposableFunction() {}
+ fun getMyClass(): Any {
+ class MyClass {
+ val property = <!COMPOSABLE_EXPECTED!>fun() {
+ <!COMPOSABLE_INVOCATION!>ComposableFunction<!>() // invocation
+ }<!>
+ }
+ return MyClass()
+ }
+ """
+ )
+ }
+
+ @Test
+ fun testErrorInAnonymousFunctionPropertyInitializerForK2() {
+ assumeTrue(useFir)
+ check(
+ """
+ import androidx.compose.runtime.Composable
+ @Composable fun ComposableFunction() {}
+ fun getMyClass(): Any {
+ class MyClass {
+ val property = <!COMPOSABLE_EXPECTED!>fun()<!> {
+ <!COMPOSABLE_INVOCATION!>ComposableFunction<!>() // invocation
+ }
+ }
+ return MyClass()
+ }
+ """
+ )
+ }
}
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/jvmTest/kotlin/androidx/compose/compiler/plugins/kotlin/facade/K2CompilerFacade.kt b/compose/compiler/compiler-hosted/integration-tests/src/jvmTest/kotlin/androidx/compose/compiler/plugins/kotlin/facade/K2CompilerFacade.kt
index 6c095ec..ff32894 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/jvmTest/kotlin/androidx/compose/compiler/plugins/kotlin/facade/K2CompilerFacade.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/jvmTest/kotlin/androidx/compose/compiler/plugins/kotlin/facade/K2CompilerFacade.kt
@@ -216,6 +216,7 @@
configuration.getBoolean(JVMConfigurationKeys.LINK_VIA_SIGNATURES),
EvaluatedConstTracker.create(),
configuration[CommonConfigurationKeys.INLINE_CONST_TRACKER],
+ configuration[CommonConfigurationKeys.EXPECT_ACTUAL_TRACKER],
allowNonCachedDeclarations = false
),
IrGenerationExtension.getInstances(project),
diff --git "a/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.ContextReceiversTransformTests/testContextReceiversNestedWith\133useFir = false\135.txt" "b/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.ContextReceiversTransformTests/testContextReceiversNestedWith\133useFir = false\135.txt"
index f8c822e..65f9106 100644
--- "a/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.ContextReceiversTransformTests/testContextReceiversNestedWith\133useFir = false\135.txt"
+++ "b/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.ContextReceiversTransformTests/testContextReceiversNestedWith\133useFir = false\135.txt"
@@ -22,7 +22,7 @@
@Composable
fun Test(foo: Foo, %composer: Composer?, %changed: Int) {
%composer = %composer.startRestartGroup(<>)
- sourceInformation(%composer, "C(Test)*<A()>,<B()>:Test.kt")
+ sourceInformation(%composer, "C(Test)*<A()>:Test.kt")
val %dirty = %changed
if (%changed and 0b1110 == 0) {
%dirty = %dirty or if (%composer.changed(foo)) 0b0100 else 0b0010
@@ -33,9 +33,12 @@
}
with(foo) {
A(%this%with, %composer, 0)
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "*<B()>")
with(Bar()) {
B(%this%with, %this%with, %composer, 0)
}
+ %composer.endReplaceableGroup()
}
if (isTraceInProgress()) {
traceEventEnd()
diff --git "a/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.ContextReceiversTransformTests/testContextReceiversNestedWith\133useFir = true\135.txt" "b/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.ContextReceiversTransformTests/testContextReceiversNestedWith\133useFir = true\135.txt"
index f8c822e..65f9106 100644
--- "a/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.ContextReceiversTransformTests/testContextReceiversNestedWith\133useFir = true\135.txt"
+++ "b/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.ContextReceiversTransformTests/testContextReceiversNestedWith\133useFir = true\135.txt"
@@ -22,7 +22,7 @@
@Composable
fun Test(foo: Foo, %composer: Composer?, %changed: Int) {
%composer = %composer.startRestartGroup(<>)
- sourceInformation(%composer, "C(Test)*<A()>,<B()>:Test.kt")
+ sourceInformation(%composer, "C(Test)*<A()>:Test.kt")
val %dirty = %changed
if (%changed and 0b1110 == 0) {
%dirty = %dirty or if (%composer.changed(foo)) 0b0100 else 0b0010
@@ -33,9 +33,12 @@
}
with(foo) {
A(%this%with, %composer, 0)
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "*<B()>")
with(Bar()) {
B(%this%with, %this%with, %composer, 0)
}
+ %composer.endReplaceableGroup()
}
if (isTraceInProgress()) {
traceEventEnd()
diff --git "a/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.ControlFlowTransformTests/testGroupsInLoops\133useFir = false\135.txt" "b/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.ControlFlowTransformTests/testGroupsInLoops\133useFir = false\135.txt"
new file mode 100644
index 0000000..c4bbba2
--- /dev/null
+++ "b/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.ControlFlowTransformTests/testGroupsInLoops\133useFir = false\135.txt"
@@ -0,0 +1,122 @@
+//
+// Source
+// ------------------------------------------
+
+import androidx.compose.runtime.*
+
+@Composable
+private fun KeyContent1(items: List<Int>) {
+ items.forEach { item ->
+ if (item > -1) {
+ key(item) {
+ remember {
+ item
+ }
+ }
+ }
+ }
+}
+
+@Composable
+private fun KeyContent2(items: List<Int>) {
+ for (item in items) {
+ if (item > -1) {
+ key(item) {
+ remember {
+ item
+ }
+ }
+ }
+ }
+}
+
+//
+// Transformed IR
+// ------------------------------------------
+
+@Composable
+private fun KeyContent1(items: List<Int>, %composer: Composer?, %changed: Int) {
+ %composer = %composer.startRestartGroup(<>)
+ sourceInformation(%composer, "C(KeyContent1):Test.kt")
+ val %dirty = %changed
+ if (%changed and 0b0110 == 0) {
+ %dirty = %dirty or if (%composer.changedInstance(items)) 0b0100 else 0b0010
+ }
+ if (%dirty and 0b0011 != 0b0010 || !%composer.skipping) {
+ if (isTraceInProgress()) {
+ traceEventStart(<>, %dirty, -1, <>)
+ }
+ items.forEach { item: Int ->
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "")
+ if (item > -1) {
+ %composer.startMovableGroup(<>, item)
+ sourceInformation(%composer, "<rememb...>")
+ val tmp0 = <block>{
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "CC(remember):Test.kt#9igjgp")
+ val tmp1_group = %composer.cache(false) {
+ item
+ }
+ %composer.endReplaceableGroup()
+ tmp1_group
+ }
+ %composer.endMovableGroup()
+ tmp0
+ }
+ %composer.endReplaceableGroup()
+ }
+ if (isTraceInProgress()) {
+ traceEventEnd()
+ }
+ } else {
+ %composer.skipToGroupEnd()
+ }
+ %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
+ KeyContent1(items, %composer, updateChangedFlags(%changed or 0b0001))
+ }
+}
+@Composable
+private fun KeyContent2(items: List<Int>, %composer: Composer?, %changed: Int) {
+ %composer = %composer.startRestartGroup(<>)
+ sourceInformation(%composer, "C(KeyContent2):Test.kt")
+ val %dirty = %changed
+ if (%changed and 0b0110 == 0) {
+ %dirty = %dirty or if (%composer.changedInstance(items)) 0b0100 else 0b0010
+ }
+ if (%dirty and 0b0011 != 0b0010 || !%composer.skipping) {
+ if (isTraceInProgress()) {
+ traceEventStart(<>, %dirty, -1, <>)
+ }
+ val <iterator> = items.iterator()
+ while (<iterator>.hasNext()) {
+ val item = <iterator>.next()
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "")
+ if (item > -1) {
+ %composer.startMovableGroup(<>, item)
+ sourceInformation(%composer, "<rememb...>")
+ val tmp0 = <block>{
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "CC(remember):Test.kt#9igjgp")
+ val tmp1_group = %composer.cache(false) {
+ item
+ }
+ %composer.endReplaceableGroup()
+ tmp1_group
+ }
+ %composer.endMovableGroup()
+ tmp0
+ }
+ %composer.endReplaceableGroup()
+ }
+ if (isTraceInProgress()) {
+ traceEventEnd()
+ }
+ } else {
+ %composer.skipToGroupEnd()
+ }
+ %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
+ KeyContent2(items, %composer, updateChangedFlags(%changed or 0b0001))
+ }
+}
diff --git "a/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.ControlFlowTransformTests/testGroupsInLoops\133useFir = true\135.txt" "b/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.ControlFlowTransformTests/testGroupsInLoops\133useFir = true\135.txt"
new file mode 100644
index 0000000..b19edaf
--- /dev/null
+++ "b/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.ControlFlowTransformTests/testGroupsInLoops\133useFir = true\135.txt"
@@ -0,0 +1,118 @@
+//
+// Source
+// ------------------------------------------
+
+import androidx.compose.runtime.*
+
+@Composable
+private fun KeyContent1(items: List<Int>) {
+ items.forEach { item ->
+ if (item > -1) {
+ key(item) {
+ remember {
+ item
+ }
+ }
+ }
+ }
+}
+
+@Composable
+private fun KeyContent2(items: List<Int>) {
+ for (item in items) {
+ if (item > -1) {
+ key(item) {
+ remember {
+ item
+ }
+ }
+ }
+ }
+}
+
+//
+// Transformed IR
+// ------------------------------------------
+
+@Composable
+private fun KeyContent1(items: List<Int>, %composer: Composer?, %changed: Int) {
+ %composer = %composer.startRestartGroup(<>)
+ sourceInformation(%composer, "C(KeyContent1):Test.kt")
+ val %dirty = %changed
+ if (%changed and 0b0110 == 0) {
+ %dirty = %dirty or if (%composer.changedInstance(items)) 0b0100 else 0b0010
+ }
+ if (%dirty and 0b0011 != 0b0010 || !%composer.skipping) {
+ if (isTraceInProgress()) {
+ traceEventStart(<>, %dirty, -1, <>)
+ }
+ items.forEach { item: Int ->
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "")
+ if (item > -1) {
+ %composer.startMovableGroup(<>, item)
+ sourceInformation(%composer, "<rememb...>")
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "CC(remember):Test.kt#9igjgp")
+ %composer.cache(false) {
+ item
+ }
+ %composer.endReplaceableGroup()
+ %composer.endMovableGroup()
+ }
+ %composer.endReplaceableGroup()
+ }
+ if (isTraceInProgress()) {
+ traceEventEnd()
+ }
+ } else {
+ %composer.skipToGroupEnd()
+ }
+ %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
+ KeyContent1(items, %composer, updateChangedFlags(%changed or 0b0001))
+ }
+}
+@Composable
+private fun KeyContent2(items: List<Int>, %composer: Composer?, %changed: Int) {
+ %composer = %composer.startRestartGroup(<>)
+ sourceInformation(%composer, "C(KeyContent2):Test.kt")
+ val %dirty = %changed
+ if (%changed and 0b0110 == 0) {
+ %dirty = %dirty or if (%composer.changedInstance(items)) 0b0100 else 0b0010
+ }
+ if (%dirty and 0b0011 != 0b0010 || !%composer.skipping) {
+ if (isTraceInProgress()) {
+ traceEventStart(<>, %dirty, -1, <>)
+ }
+ val <iterator> = items.iterator()
+ while (<iterator>.hasNext()) {
+ val item = <iterator>.next()
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "")
+ if (item > -1) {
+ %composer.startMovableGroup(<>, item)
+ sourceInformation(%composer, "<rememb...>")
+ val tmp0 = <block>{
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "CC(remember):Test.kt#9igjgp")
+ val tmp1_group = %composer.cache(false) {
+ item
+ }
+ %composer.endReplaceableGroup()
+ tmp1_group
+ }
+ %composer.endMovableGroup()
+ tmp0
+ }
+ %composer.endReplaceableGroup()
+ }
+ if (isTraceInProgress()) {
+ traceEventEnd()
+ }
+ } else {
+ %composer.skipToGroupEnd()
+ }
+ %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
+ KeyContent2(items, %composer, updateChangedFlags(%changed or 0b0001))
+ }
+}
diff --git "a/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.ControlFlowTransformTests/testInlineLambdaBeforeACall\133useFir = false\135.txt" "b/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.ControlFlowTransformTests/testInlineLambdaBeforeACall\133useFir = false\135.txt"
index 212e96e..f603a80 100644
--- "a/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.ControlFlowTransformTests/testInlineLambdaBeforeACall\133useFir = false\135.txt"
+++ "b/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.ControlFlowTransformTests/testInlineLambdaBeforeACall\133useFir = false\135.txt"
@@ -26,11 +26,14 @@
traceEventStart(<>, %changed, -1, <>)
}
%composer.startReplaceableGroup(<>)
- sourceInformation(%composer, "*<Test("...>")
+ sourceInformation(%composer, "")
InlineNonComposable {
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "*<Test("...>")
repeat(10) { it: Int ->
Test("InsideInline", %composer, 0b0110)
}
+ %composer.endReplaceableGroup()
}
%composer.endReplaceableGroup()
val tmp0 = Test("AfterInline", %composer, 0b0110)
diff --git "a/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.ControlFlowTransformTests/testInlineLambdaBeforeACall\133useFir = true\135.txt" "b/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.ControlFlowTransformTests/testInlineLambdaBeforeACall\133useFir = true\135.txt"
index 212e96e..f603a80 100644
--- "a/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.ControlFlowTransformTests/testInlineLambdaBeforeACall\133useFir = true\135.txt"
+++ "b/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.ControlFlowTransformTests/testInlineLambdaBeforeACall\133useFir = true\135.txt"
@@ -26,11 +26,14 @@
traceEventStart(<>, %changed, -1, <>)
}
%composer.startReplaceableGroup(<>)
- sourceInformation(%composer, "*<Test("...>")
+ sourceInformation(%composer, "")
InlineNonComposable {
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "*<Test("...>")
repeat(10) { it: Int ->
Test("InsideInline", %composer, 0b0110)
}
+ %composer.endReplaceableGroup()
}
%composer.endReplaceableGroup()
val tmp0 = Test("AfterInline", %composer, 0b0110)
diff --git "a/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.LambdaMemoizationTransformTests/testAdaptedFunctionRef\133useFir = false\135.txt" "b/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.LambdaMemoizationTransformTests/testAdaptedFunctionRef\133useFir = false\135.txt"
new file mode 100644
index 0000000..5785249
--- /dev/null
+++ "b/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.LambdaMemoizationTransformTests/testAdaptedFunctionRef\133useFir = false\135.txt"
@@ -0,0 +1,149 @@
+//
+// Source
+// ------------------------------------------
+
+import androidx.compose.runtime.Composable
+
+class ScrollState {
+ fun test(index: Int, default: Int = 0): Int = 0
+ fun testExact(index: Int): Int = 0
+}
+fun scrollState(): ScrollState = TODO()
+
+@Composable fun rememberFooInline() = fooInline(scrollState()::test)
+@Composable fun rememberFoo() = foo(scrollState()::test)
+@Composable fun rememberFooExactInline() = fooInline(scrollState()::testExact)
+@Composable fun rememberFooExact() = foo(scrollState()::testExact)
+
+@Composable
+inline fun fooInline(block: (Int) -> Int) = block(0)
+
+@Composable
+fun foo(block: (Int) -> Int) = block(0)
+
+//
+// Transformed IR
+// ------------------------------------------
+
+@StabilityInferred(parameters = 1)
+class ScrollState {
+ fun test(index: Int, default: Int = 0): Int {
+ return 0
+ }
+ fun testExact(index: Int): Int {
+ return 0
+ }
+ static val %stable: Int = 0
+}
+fun scrollState(): ScrollState {
+ return TODO()
+}
+@Composable
+fun rememberFooInline(%composer: Composer?, %changed: Int): Int {
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "C(rememberFooInline)<fooInl...>:Test.kt")
+ if (isTraceInProgress()) {
+ traceEventStart(<>, %changed, -1, <>)
+ }
+ val tmp0 = fooInline(<block>{
+ fun ScrollState.test(p0: Int): Int {
+ val tmp0_return = receiver.test(
+ index = p0
+ )
+ tmp0_return
+ }
+ scrollState()::test
+ }, %composer, 0)
+ if (isTraceInProgress()) {
+ traceEventEnd()
+ }
+ %composer.endReplaceableGroup()
+ return tmp0
+}
+@Composable
+fun rememberFoo(%composer: Composer?, %changed: Int): Int {
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "C(rememberFoo)<scroll...>,<foo(sc...>:Test.kt")
+ if (isTraceInProgress()) {
+ traceEventStart(<>, %changed, -1, <>)
+ }
+ val tmp0 = foo(<block>{
+ val tmp0 = scrollState()
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "CC(remember):Test.kt#9igjgp")
+ val tmp1_group = %composer.cache(%composer.changed(tmp0)) {
+ fun ScrollState.test(p0: Int): Int {
+ receiver.test(
+ index = p0
+ )
+ }
+ tmp0::test
+ }
+ %composer.endReplaceableGroup()
+ tmp1_group
+ }, %composer, 0)
+ if (isTraceInProgress()) {
+ traceEventEnd()
+ }
+ %composer.endReplaceableGroup()
+ return tmp0
+}
+@Composable
+fun rememberFooExactInline(%composer: Composer?, %changed: Int): Int {
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "C(rememberFooExactInline)<fooInl...>:Test.kt")
+ if (isTraceInProgress()) {
+ traceEventStart(<>, %changed, -1, <>)
+ }
+ val tmp0 = fooInline(scrollState()::testExact, %composer, 0)
+ if (isTraceInProgress()) {
+ traceEventEnd()
+ }
+ %composer.endReplaceableGroup()
+ return tmp0
+}
+@Composable
+fun rememberFooExact(%composer: Composer?, %changed: Int): Int {
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "C(rememberFooExact)<scroll...>,<foo(sc...>:Test.kt")
+ if (isTraceInProgress()) {
+ traceEventStart(<>, %changed, -1, <>)
+ }
+ val tmp0 = foo(<block>{
+ val tmp0 = scrollState()
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "CC(remember):Test.kt#9igjgp")
+ val tmp1_group = %composer.cache(%composer.changed(tmp0)) {
+ tmp0::testExact
+ }
+ %composer.endReplaceableGroup()
+ tmp1_group
+ }, %composer, 0)
+ if (isTraceInProgress()) {
+ traceEventEnd()
+ }
+ %composer.endReplaceableGroup()
+ return tmp0
+}
+@Composable
+fun fooInline(block: Function1<Int, Int>, %composer: Composer?, %changed: Int): Int {
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "CC(fooInline):Test.kt")
+ val tmp0 = block(0)
+ %composer.endReplaceableGroup()
+ return tmp0
+}
+@Composable
+fun foo(block: Function1<Int, Int>, %composer: Composer?, %changed: Int): Int {
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "C(foo):Test.kt")
+ if (isTraceInProgress()) {
+ traceEventStart(<>, %changed, -1, <>)
+ }
+ val tmp0 = block(0)
+ if (isTraceInProgress()) {
+ traceEventEnd()
+ }
+ %composer.endReplaceableGroup()
+ return tmp0
+}
diff --git "a/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.LambdaMemoizationTransformTests/testAdaptedFunctionRef\133useFir = true\135.txt" "b/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.LambdaMemoizationTransformTests/testAdaptedFunctionRef\133useFir = true\135.txt"
new file mode 100644
index 0000000..ab1b9ff
--- /dev/null
+++ "b/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.LambdaMemoizationTransformTests/testAdaptedFunctionRef\133useFir = true\135.txt"
@@ -0,0 +1,149 @@
+//
+// Source
+// ------------------------------------------
+
+import androidx.compose.runtime.Composable
+
+class ScrollState {
+ fun test(index: Int, default: Int = 0): Int = 0
+ fun testExact(index: Int): Int = 0
+}
+fun scrollState(): ScrollState = TODO()
+
+@Composable fun rememberFooInline() = fooInline(scrollState()::test)
+@Composable fun rememberFoo() = foo(scrollState()::test)
+@Composable fun rememberFooExactInline() = fooInline(scrollState()::testExact)
+@Composable fun rememberFooExact() = foo(scrollState()::testExact)
+
+@Composable
+inline fun fooInline(block: (Int) -> Int) = block(0)
+
+@Composable
+fun foo(block: (Int) -> Int) = block(0)
+
+//
+// Transformed IR
+// ------------------------------------------
+
+@StabilityInferred(parameters = 1)
+class ScrollState {
+ fun test(index: Int, default: Int = 0): Int {
+ return 0
+ }
+ fun testExact(index: Int): Int {
+ return 0
+ }
+ static val %stable: Int = 0
+}
+fun scrollState(): ScrollState {
+ return TODO()
+}
+@Composable
+fun rememberFooInline(%composer: Composer?, %changed: Int): Int {
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "C(rememberFooInline)<fooInl...>:Test.kt")
+ if (isTraceInProgress()) {
+ traceEventStart(<>, %changed, -1, <>)
+ }
+ val tmp0 = fooInline(<block>{
+ fun ScrollState.test(p0: Int): Int {
+ val tmp0_return = receiver.test(
+ index = p0
+ )
+ tmp0_return
+ }
+ scrollState()::test
+ }, %composer, 0)
+ if (isTraceInProgress()) {
+ traceEventEnd()
+ }
+ %composer.endReplaceableGroup()
+ return tmp0
+}
+@Composable
+fun rememberFoo(%composer: Composer?, %changed: Int): Int {
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "C(rememberFoo)<test>,<foo(sc...>:Test.kt")
+ if (isTraceInProgress()) {
+ traceEventStart(<>, %changed, -1, <>)
+ }
+ val tmp0 = foo(<block>{
+ val tmp0 = scrollState()
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "CC(remember):Test.kt#9igjgp")
+ val tmp1_group = %composer.cache(%composer.changed(tmp0)) {
+ fun ScrollState.test(p0: Int): Int {
+ receiver.test(
+ index = p0
+ )
+ }
+ tmp0::test
+ }
+ %composer.endReplaceableGroup()
+ tmp1_group
+ }, %composer, 0)
+ if (isTraceInProgress()) {
+ traceEventEnd()
+ }
+ %composer.endReplaceableGroup()
+ return tmp0
+}
+@Composable
+fun rememberFooExactInline(%composer: Composer?, %changed: Int): Int {
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "C(rememberFooExactInline)<fooInl...>:Test.kt")
+ if (isTraceInProgress()) {
+ traceEventStart(<>, %changed, -1, <>)
+ }
+ val tmp0 = fooInline(scrollState()::testExact, %composer, 0)
+ if (isTraceInProgress()) {
+ traceEventEnd()
+ }
+ %composer.endReplaceableGroup()
+ return tmp0
+}
+@Composable
+fun rememberFooExact(%composer: Composer?, %changed: Int): Int {
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "C(rememberFooExact)<testEx...>,<foo(sc...>:Test.kt")
+ if (isTraceInProgress()) {
+ traceEventStart(<>, %changed, -1, <>)
+ }
+ val tmp0 = foo(<block>{
+ val tmp0 = scrollState()
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "CC(remember):Test.kt#9igjgp")
+ val tmp1_group = %composer.cache(%composer.changed(tmp0)) {
+ tmp0::testExact
+ }
+ %composer.endReplaceableGroup()
+ tmp1_group
+ }, %composer, 0)
+ if (isTraceInProgress()) {
+ traceEventEnd()
+ }
+ %composer.endReplaceableGroup()
+ return tmp0
+}
+@Composable
+fun fooInline(block: Function1<Int, Int>, %composer: Composer?, %changed: Int): Int {
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "CC(fooInline):Test.kt")
+ val tmp0 = block(0)
+ %composer.endReplaceableGroup()
+ return tmp0
+}
+@Composable
+fun foo(block: Function1<Int, Int>, %composer: Composer?, %changed: Int): Int {
+ %composer.startReplaceableGroup(<>)
+ sourceInformation(%composer, "C(foo):Test.kt")
+ if (isTraceInProgress()) {
+ traceEventStart(<>, %changed, -1, <>)
+ }
+ val tmp0 = block(0)
+ if (isTraceInProgress()) {
+ traceEventEnd()
+ }
+ %composer.endReplaceableGroup()
+ return tmp0
+}
diff --git "a/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.RememberIntrinsicTransformTests/testRememberAdaptedFunctionReference\133useFir = false\135.txt" "b/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.RememberIntrinsicTransformTests/testRememberAdaptedFunctionReference\133useFir = false\135.txt"
index 05ba6c9..e276214 100644
--- "a/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.RememberIntrinsicTransformTests/testRememberAdaptedFunctionReference\133useFir = false\135.txt"
+++ "b/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.RememberIntrinsicTransformTests/testRememberAdaptedFunctionReference\133useFir = false\135.txt"
@@ -30,9 +30,12 @@
used(<block>{
%composer.startReplaceableGroup(<>)
sourceInformation(%composer, "CC(remember):Test.kt#9igjgp")
- val tmp0_group = %composer.cache(%dirty and 0b1110 == 0b0100) {
- effect()
- }
+ val tmp0_group = %composer.cache(%dirty and 0b1110 == 0b0100, <block>{
+ fun effect(): Int {
+ effect()
+ }
+ ::effect
+ })
%composer.endReplaceableGroup()
tmp0_group
})
diff --git "a/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.RememberIntrinsicTransformTests/testRememberAdaptedFunctionReference\133useFir = true\135.txt" "b/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.RememberIntrinsicTransformTests/testRememberAdaptedFunctionReference\133useFir = true\135.txt"
index 05ba6c9..e276214 100644
--- "a/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.RememberIntrinsicTransformTests/testRememberAdaptedFunctionReference\133useFir = true\135.txt"
+++ "b/compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.RememberIntrinsicTransformTests/testRememberAdaptedFunctionReference\133useFir = true\135.txt"
@@ -30,9 +30,12 @@
used(<block>{
%composer.startReplaceableGroup(<>)
sourceInformation(%composer, "CC(remember):Test.kt#9igjgp")
- val tmp0_group = %composer.cache(%dirty and 0b1110 == 0b0100) {
- effect()
- }
+ val tmp0_group = %composer.cache(%dirty and 0b1110 == 0b0100, <block>{
+ fun effect(): Int {
+ effect()
+ }
+ ::effect
+ })
%composer.endReplaceableGroup()
tmp0_group
})
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt
index df1ebf9..db3c96d 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt
@@ -266,7 +266,7 @@
companion object {
fun checkCompilerVersion(configuration: CompilerConfiguration): Boolean {
try {
- val KOTLIN_VERSION_EXPECTATION = "1.9.20"
+ val KOTLIN_VERSION_EXPECTATION = "1.9.21"
KotlinCompilerVersion.getVersion()?.let { version ->
val msgCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
val suppressKotlinVersionCheck = configuration.get(
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt
index 569b3da..9e42502 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt
@@ -142,7 +142,7 @@
* The maven version string of this compiler. This string should be updated before/after every
* release.
*/
- const val compilerVersion: String = "1.5.5"
+ const val compilerVersion: String = "1.5.6"
private val minimumRuntimeVersion: String
get() = runtimeVersionToMavenVersionTable[minimumRuntimeVersionInt] ?: "unknown"
}
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/k2/ComposableCallChecker.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/k2/ComposableCallChecker.kt
index 46a822b..4465723 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/k2/ComposableCallChecker.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/k2/ComposableCallChecker.kt
@@ -16,6 +16,7 @@
package androidx.compose.compiler.plugins.kotlin.k2
+import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.FirElement
@@ -41,12 +42,16 @@
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirTryExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedArgumentList
+import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol
import org.jetbrains.kotlin.fir.references.toResolvedValueParameterSymbol
import org.jetbrains.kotlin.fir.resolve.isInvoke
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.functionTypeKind
+import org.jetbrains.kotlin.psi.KtFunction
+import org.jetbrains.kotlin.psi.KtFunctionLiteral
+import org.jetbrains.kotlin.psi.KtLambdaExpression
object ComposablePropertyAccessExpressionChecker : FirPropertyAccessExpressionChecker() {
override fun check(
@@ -119,49 +124,44 @@
visitAnonymousFunction = { function ->
if (function.typeRef.coneType.functionTypeKind(context.session) === ComposableFunction)
return
+ val functionPsi = function.psi
+ if (functionPsi is KtFunctionLiteral || functionPsi is KtLambdaExpression ||
+ functionPsi !is KtFunction
+ ) {
+ return@visitCurrentScope
+ }
+ val nonReadOnlyCalleeReference =
+ if (!calleeFunction.isReadOnlyComposable(context.session)) {
+ expression.calleeReference.source
+ } else {
+ null
+ }
+ if (checkComposableFunction(
+ function,
+ nonReadOnlyCalleeReference,
+ context,
+ reporter,
+ ) == ComposableCheckForScopeStatus.STOP
+ ) {
+ return
+ }
},
visitFunction = { function ->
- if (function.hasComposableAnnotation(context.session)) {
- if (
- function.hasReadOnlyComposableAnnotation(context.session) &&
- !calleeFunction.isReadOnlyComposable(context.session)
- ) {
- reporter.reportOn(
- expression.calleeReference.source,
- ComposeErrors.NONREADONLY_CALL_IN_READONLY_COMPOSABLE,
- context
- )
+ val nonReadOnlyCalleeReference =
+ if (!calleeFunction.isReadOnlyComposable(context.session)) {
+ expression.calleeReference.source
+ } else {
+ null
}
+ if (checkComposableFunction(
+ function,
+ nonReadOnlyCalleeReference,
+ context,
+ reporter,
+ ) == ComposableCheckForScopeStatus.STOP
+ ) {
return
}
- // We allow composable calls in local delegated properties.
- // The only call this could be is a getValue/setValue in the synthesized getter/setter.
- if (function is FirPropertyAccessor && function.propertySymbol.hasDelegate) {
- if (function.propertySymbol.isVar) {
- reporter.reportOn(
- function.source,
- ComposeErrors.COMPOSE_INVALID_DELEGATE,
- context
- )
- }
- // Only local variables can be implicitly composable, for top-level or class-level
- // declarations we require an explicit annotation.
- if (!function.propertySymbol.isLocal) {
- reporter.reportOn(
- function.propertySymbol.source,
- ComposeErrors.COMPOSABLE_EXPECTED,
- context
- )
- }
- return
- }
- // We've found a non-composable function which contains a composable call.
- val source = if (function is FirPropertyAccessor) {
- function.propertySymbol.source
- } else {
- function.source
- }
- reporter.reportOn(source, ComposeErrors.COMPOSABLE_EXPECTED, context)
},
visitTryExpression = { tryExpression, container ->
// Only report an error if the composable call happens inside of the `try`
@@ -182,6 +182,69 @@
)
}
+private enum class ComposableCheckForScopeStatus {
+ STOP,
+ CONTINUE,
+}
+
+/**
+ * This function will be called by [visitCurrentScope], and this function determines
+ * whether it will continue the composable element check for the scope or not
+ * by returning [ComposableCheckForScopeStatus].
+ */
+private fun checkComposableFunction(
+ function: FirFunction,
+ nonReadOnlyCallInsideFunction: KtSourceElement?,
+ context: CheckerContext,
+ reporter: DiagnosticReporter,
+): ComposableCheckForScopeStatus {
+ // [function] is a function with "read-only" composable annotation, but it has a call
+ // without "read-only" composable annotation.
+ // -> report NONREADONLY_CALL_IN_READONLY_COMPOSABLE.
+ if (function.hasComposableAnnotation(context.session)) {
+ if (
+ function.hasReadOnlyComposableAnnotation(context.session) &&
+ nonReadOnlyCallInsideFunction != null
+ ) {
+ reporter.reportOn(
+ nonReadOnlyCallInsideFunction,
+ ComposeErrors.NONREADONLY_CALL_IN_READONLY_COMPOSABLE,
+ context
+ )
+ }
+ return ComposableCheckForScopeStatus.STOP
+ }
+ // We allow composable calls in local delegated properties.
+ // The only call this could be is a getValue/setValue in the synthesized getter/setter.
+ if (function is FirPropertyAccessor && function.propertySymbol.hasDelegate) {
+ if (function.propertySymbol.isVar) {
+ reporter.reportOn(
+ function.source,
+ ComposeErrors.COMPOSE_INVALID_DELEGATE,
+ context
+ )
+ }
+ // Only local variables can be implicitly composable, for top-level or class-level
+ // declarations we require an explicit annotation.
+ if (!function.propertySymbol.isLocal) {
+ reporter.reportOn(
+ function.propertySymbol.source,
+ ComposeErrors.COMPOSABLE_EXPECTED,
+ context
+ )
+ }
+ return ComposableCheckForScopeStatus.STOP
+ }
+ // We've found a non-composable function which contains a composable call.
+ val source = if (function is FirPropertyAccessor) {
+ function.propertySymbol.source
+ } else {
+ function.source
+ }
+ reporter.reportOn(source, ComposeErrors.COMPOSABLE_EXPECTED, context)
+ return ComposableCheckForScopeStatus.CONTINUE
+}
+
/**
* Reports an error if we are invoking a lambda parameter of an inline function in a context
* where composable calls are not allowed, unless the lambda parameter is itself annotated
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
index 409e4ac..9f7db48 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
@@ -2781,6 +2781,9 @@
expression.transformChildrenVoid()
}
return if (captureScope.hasCapturedComposableCall) {
+ // if the inlined lambda has composable calls, realize its coalescable groups
+ // in the body to ensure that repeated invocations are not colliding.
+ captureScope.realizeAllDirectChildren()
expression.asCoalescableGroup(captureScope)
} else {
expression
@@ -2809,7 +2812,7 @@
visitNormalComposableCall(expression)
}
}
- ComposeFqNames.key -> visitKeyCall(expression)
+ ComposeFqNames.key,
DecoyFqNames.key -> visitKeyCall(expression)
else -> visitNormalComposableCall(expression)
}
@@ -3586,7 +3589,7 @@
// If a loop contains composable calls but not a otherwise need a group per iteration
// group, none of the children can be coalesced and must be realized as the second
// iteration as composable calls at the end might end of overlapping slots with the
- // start of the loop. See b/205590513 for details.
+ // start of the loop. See b/232007227 for details.
loopScope.realizeAllDirectChildren()
loop.asCoalescableGroup(loopScope)
} else {
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt
index ff49298..90acac0 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt
@@ -62,7 +62,7 @@
import org.jetbrains.kotlin.ir.declarations.IrValueDeclaration
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.declarations.IrVariable
-import org.jetbrains.kotlin.ir.declarations.copyAttributes
+import org.jetbrains.kotlin.ir.expressions.IrBlock
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
@@ -74,7 +74,6 @@
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
import org.jetbrains.kotlin.ir.expressions.IrValueAccessExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
-import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
@@ -458,17 +457,64 @@
return super.visitValueAccess(expression)
}
+ override fun visitBlock(expression: IrBlock): IrExpression {
+ val result = super.visitBlock(expression)
+
+ if (result is IrBlock && result.origin == IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE) {
+ if (inlineLambdaInfo.isInlineFunctionExpression(expression)) {
+ // Do not memoize function references for inline lambdas
+ return result
+ }
+
+ val functionReference = result.statements.last()
+ if (functionReference !is IrFunctionReference) {
+ // Do not memoize if the expected shape doesn't match.
+ return result
+ }
+
+ return rememberFunctionReference(functionReference, expression)
+ }
+
+ return result
+ }
+
// Memoize the instance created by using the :: operator
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
+ val result = super.visitFunctionReference(expression)
+
+ if (
+ inlineLambdaInfo.isInlineFunctionExpression(expression) ||
+ inlineLambdaInfo.isInlineLambda(expression.symbol.owner)
+ ) {
+ // Do not memoize function references used in inline parameters.
+ return result
+ }
+
+ if (expression.symbol.owner.origin == IrDeclarationOrigin.ADAPTER_FOR_CALLABLE_REFERENCE) {
+ // Adapted function reference (inexact function signature match) is handled in block
+ return result
+ }
+
+ if (result !is IrFunctionReference) {
+ // Do not memoize if the shape doesn't match
+ return result
+ }
+
+ return rememberFunctionReference(result, result)
+ }
+
+ private fun rememberFunctionReference(
+ reference: IrFunctionReference,
+ expression: IrExpression
+ ): IrExpression {
// Get the local captures for local function ref, to make sure we invalidate memoized
// reference if its capture is different.
- val localCaptures = if (expression.symbol.owner.isLocal) {
- declarationContextStack.recordLocalCapture(expression.symbol.owner)
+ val localCaptures = if (reference.symbol.owner.isLocal) {
+ declarationContextStack.recordLocalCapture(reference.symbol.owner)
} else {
null
}
- val result = super.visitFunctionReference(expression)
- val functionContext = currentFunctionContext ?: return result
+ val functionContext = currentFunctionContext ?: return expression
// The syntax <expr>::<method>(<params>) and ::<function>(<params>) is reserved for
// future use. Revisit implementation if this syntax is as a curry syntax in the future.
@@ -476,27 +522,27 @@
// receivers are treated below.
// Do not attempt memoization if the referenced function has context receivers.
- if (expression.symbol.owner.contextReceiverParametersCount > 0) {
- return result
+ if (reference.symbol.owner.contextReceiverParametersCount > 0) {
+ return expression
}
// Do not attempt memoization if value parameters are not null. This is to guard against
// unexpected IR shapes.
- for (i in 0 until expression.valueArgumentsCount) {
- if (expression.getValueArgument(i) != null) {
- return result
+ for (i in 0 until reference.valueArgumentsCount) {
+ if (reference.getValueArgument(i) != null) {
+ return expression
}
}
if (functionContext.canRemember) {
// Memoize the reference for <expr>::<method>
- val dispatchReceiver = expression.dispatchReceiver
- val extensionReceiver = expression.extensionReceiver
+ val dispatchReceiver = reference.dispatchReceiver
+ val extensionReceiver = reference.extensionReceiver
val hasReceiver = dispatchReceiver != null || extensionReceiver != null
val receiverIsStable =
dispatchReceiver.isNullOrStable() &&
- extensionReceiver.isNullOrStable()
+ extensionReceiver.isNullOrStable()
val captures = mutableListOf<IrValueDeclaration>()
if (localCaptures != null) {
@@ -526,28 +572,22 @@
tmp
}
+ // Patch reference receiver in place
+ reference.dispatchReceiver = tempDispatchReceiver?.let { irGet(it) }
+ reference.extensionReceiver = tempExtensionReceiver?.let { irGet(it) }
+
+rememberExpression(
functionContext,
- IrFunctionReferenceImpl(
- startOffset,
- endOffset,
- expression.type,
- expression.symbol,
- expression.typeArgumentsCount,
- expression.valueArgumentsCount,
- expression.reflectionTarget
- ).copyAttributes(expression).apply {
- this.dispatchReceiver = tempDispatchReceiver?.let { irGet(it) }
- this.extensionReceiver = tempExtensionReceiver?.let { irGet(it) }
- },
+ expression,
captures
)
}
} else if (dispatchReceiver == null && extensionReceiver == null) {
- return rememberExpression(functionContext, result, captures)
+ return rememberExpression(functionContext, expression, captures)
}
}
- return result
+
+ return expression
}
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression {
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrInlineReferenceLocator.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrInlineReferenceLocator.kt
index 852ae18..8c72dac 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrInlineReferenceLocator.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrInlineReferenceLocator.kt
@@ -46,10 +46,14 @@
class ComposeInlineLambdaLocator(private val context: IrPluginContext) {
private val inlineLambdaToParameter = mutableMapOf<IrFunctionSymbol, IrValueParameter>()
+ private val inlineFunctionExpressions = mutableSetOf<IrExpression>()
fun isInlineLambda(irFunction: IrFunction): Boolean =
irFunction.symbol in inlineLambdaToParameter.keys
+ fun isInlineFunctionExpression(expression: IrExpression): Boolean =
+ expression in inlineFunctionExpressions
+
fun preservesComposableScope(irFunction: IrFunction): Boolean =
inlineLambdaToParameter[irFunction.symbol]?.let {
!it.isCrossinline && !it.type.hasAnnotation(ComposeFqNames.DisallowComposableCalls)
@@ -66,7 +70,7 @@
declaration.acceptChildrenVoid(this)
val parent = declaration.parent as? IrFunction
if (parent?.isInlineFunctionCall(context) == true &&
- declaration.isInlineParameter()) {
+ declaration.isInlinedFunction()) {
declaration.defaultValue?.expression?.unwrapLambda()?.let {
inlineLambdaToParameter[it] = declaration
}
@@ -78,8 +82,9 @@
val function = expression.symbol.owner
if (function.isInlineFunctionCall(context)) {
for (parameter in function.valueParameters) {
- if (parameter.isInlineParameter()) {
+ if (parameter.isInlinedFunction()) {
expression.getValueArgument(parameter.index)
+ ?.also { inlineFunctionExpressions += it }
?.unwrapLambda()
?.let { inlineLambdaToParameter[it] = parameter }
}
@@ -119,7 +124,7 @@
// This is copied from JvmIrInlineUtils.kt in the Kotlin compiler, since we
// need to check for synthetic composable functions.
-private fun IrValueParameter.isInlineParameter(): Boolean =
+private fun IrValueParameter.isInlinedFunction(): Boolean =
index >= 0 && !isNoinline && (type.isFunction() || type.isSuspendFunction() ||
type.isSyntheticComposableFunction()) &&
// Parameters with default values are always nullable, so check the expression too.
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
index 9980397..0b0f561 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
@@ -522,8 +522,7 @@
val param = symbol.owner.valueParameters[i]
val isLambda = arg is IrFunctionExpression ||
(arg is IrBlock &&
- (arg.origin == IrStatementOrigin.LAMBDA ||
- arg.origin == IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE))
+ (arg.origin == IrStatementOrigin.LAMBDA))
if (isLambda) {
arg.unwrapLambda()?.let {
returnTargetToCall[it] = this
@@ -881,7 +880,7 @@
lhs.print()
print("--")
}
- IrStatementOrigin.LAMBDA, IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE -> {
+ IrStatementOrigin.LAMBDA -> {
val function = expression.statements[0] as IrFunction
function.printAsLambda()
}
diff --git a/compose/foundation/foundation/api/current.txt b/compose/foundation/foundation/api/current.txt
index 972e769..8633904 100644
--- a/compose/foundation/foundation/api/current.txt
+++ b/compose/foundation/foundation/api/current.txt
@@ -31,16 +31,16 @@
}
public final class BasicMarqueeKt {
- method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.MarqueeSpacing MarqueeSpacing(float spacing);
- method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public static androidx.compose.ui.Modifier basicMarquee(androidx.compose.ui.Modifier, optional int iterations, optional int animationMode, optional int delayMillis, optional int initialDelayMillis, optional androidx.compose.foundation.MarqueeSpacing spacing, optional float velocity);
- method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public static int getDefaultMarqueeDelayMillis();
- method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public static int getDefaultMarqueeIterations();
- method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.MarqueeSpacing getDefaultMarqueeSpacing();
- method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public static float getDefaultMarqueeVelocity();
- property @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public static final int DefaultMarqueeDelayMillis;
- property @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public static final int DefaultMarqueeIterations;
- property @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public static final androidx.compose.foundation.MarqueeSpacing DefaultMarqueeSpacing;
- property @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public static final float DefaultMarqueeVelocity;
+ method public static androidx.compose.foundation.MarqueeSpacing MarqueeSpacing(float spacing);
+ method @androidx.compose.runtime.Stable public static androidx.compose.ui.Modifier basicMarquee(androidx.compose.ui.Modifier, optional int iterations, optional int animationMode, optional int delayMillis, optional int initialDelayMillis, optional androidx.compose.foundation.MarqueeSpacing spacing, optional float velocity);
+ method public static int getDefaultMarqueeDelayMillis();
+ method public static int getDefaultMarqueeIterations();
+ method public static androidx.compose.foundation.MarqueeSpacing getDefaultMarqueeSpacing();
+ method public static float getDefaultMarqueeVelocity();
+ property public static final int DefaultMarqueeDelayMillis;
+ property public static final int DefaultMarqueeIterations;
+ property public static final androidx.compose.foundation.MarqueeSpacing DefaultMarqueeSpacing;
+ property public static final float DefaultMarqueeVelocity;
}
@SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public final class BasicTooltipDefaults {
@@ -173,24 +173,24 @@
method public static androidx.compose.ui.Modifier magnifier(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.unit.Density,androidx.compose.ui.geometry.Offset> sourceCenter, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.unit.Density,androidx.compose.ui.geometry.Offset>? magnifierCenter, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.unit.DpSize,kotlin.Unit>? onSizeChanged, optional float zoom, optional long size, optional float cornerRadius, optional float elevation, optional boolean clip);
}
- @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi @kotlin.jvm.JvmInline public final value class MarqueeAnimationMode {
+ @kotlin.jvm.JvmInline public final value class MarqueeAnimationMode {
field public static final androidx.compose.foundation.MarqueeAnimationMode.Companion Companion;
}
public static final class MarqueeAnimationMode.Companion {
- method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public int getImmediately();
- method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public int getWhileFocused();
- property @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public final int Immediately;
- property @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public final int WhileFocused;
+ method public int getImmediately();
+ method public int getWhileFocused();
+ property public final int Immediately;
+ property public final int WhileFocused;
}
- @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public fun interface MarqueeSpacing {
- method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public int calculateSpacing(androidx.compose.ui.unit.Density, int contentWidth, int containerWidth);
+ @androidx.compose.runtime.Stable public fun interface MarqueeSpacing {
+ method public int calculateSpacing(androidx.compose.ui.unit.Density, int contentWidth, int containerWidth);
field public static final androidx.compose.foundation.MarqueeSpacing.Companion Companion;
}
public static final class MarqueeSpacing.Companion {
- method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public androidx.compose.foundation.MarqueeSpacing fractionOfContainer(float fraction);
+ method public androidx.compose.foundation.MarqueeSpacing fractionOfContainer(float fraction);
}
public enum MutatePriority {
diff --git a/compose/foundation/foundation/api/restricted_current.txt b/compose/foundation/foundation/api/restricted_current.txt
index e802b3d..3f5571d 100644
--- a/compose/foundation/foundation/api/restricted_current.txt
+++ b/compose/foundation/foundation/api/restricted_current.txt
@@ -31,16 +31,16 @@
}
public final class BasicMarqueeKt {
- method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.MarqueeSpacing MarqueeSpacing(float spacing);
- method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public static androidx.compose.ui.Modifier basicMarquee(androidx.compose.ui.Modifier, optional int iterations, optional int animationMode, optional int delayMillis, optional int initialDelayMillis, optional androidx.compose.foundation.MarqueeSpacing spacing, optional float velocity);
- method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public static int getDefaultMarqueeDelayMillis();
- method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public static int getDefaultMarqueeIterations();
- method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.MarqueeSpacing getDefaultMarqueeSpacing();
- method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public static float getDefaultMarqueeVelocity();
- property @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public static final int DefaultMarqueeDelayMillis;
- property @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public static final int DefaultMarqueeIterations;
- property @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public static final androidx.compose.foundation.MarqueeSpacing DefaultMarqueeSpacing;
- property @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public static final float DefaultMarqueeVelocity;
+ method public static androidx.compose.foundation.MarqueeSpacing MarqueeSpacing(float spacing);
+ method @androidx.compose.runtime.Stable public static androidx.compose.ui.Modifier basicMarquee(androidx.compose.ui.Modifier, optional int iterations, optional int animationMode, optional int delayMillis, optional int initialDelayMillis, optional androidx.compose.foundation.MarqueeSpacing spacing, optional float velocity);
+ method public static int getDefaultMarqueeDelayMillis();
+ method public static int getDefaultMarqueeIterations();
+ method public static androidx.compose.foundation.MarqueeSpacing getDefaultMarqueeSpacing();
+ method public static float getDefaultMarqueeVelocity();
+ property public static final int DefaultMarqueeDelayMillis;
+ property public static final int DefaultMarqueeIterations;
+ property public static final androidx.compose.foundation.MarqueeSpacing DefaultMarqueeSpacing;
+ property public static final float DefaultMarqueeVelocity;
}
@SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public final class BasicTooltipDefaults {
@@ -173,24 +173,24 @@
method public static androidx.compose.ui.Modifier magnifier(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.unit.Density,androidx.compose.ui.geometry.Offset> sourceCenter, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.unit.Density,androidx.compose.ui.geometry.Offset>? magnifierCenter, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.unit.DpSize,kotlin.Unit>? onSizeChanged, optional float zoom, optional long size, optional float cornerRadius, optional float elevation, optional boolean clip);
}
- @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi @kotlin.jvm.JvmInline public final value class MarqueeAnimationMode {
+ @kotlin.jvm.JvmInline public final value class MarqueeAnimationMode {
field public static final androidx.compose.foundation.MarqueeAnimationMode.Companion Companion;
}
public static final class MarqueeAnimationMode.Companion {
- method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public int getImmediately();
- method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public int getWhileFocused();
- property @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public final int Immediately;
- property @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public final int WhileFocused;
+ method public int getImmediately();
+ method public int getWhileFocused();
+ property public final int Immediately;
+ property public final int WhileFocused;
}
- @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public fun interface MarqueeSpacing {
- method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public int calculateSpacing(androidx.compose.ui.unit.Density, int contentWidth, int containerWidth);
+ @androidx.compose.runtime.Stable public fun interface MarqueeSpacing {
+ method public int calculateSpacing(androidx.compose.ui.unit.Density, int contentWidth, int containerWidth);
field public static final androidx.compose.foundation.MarqueeSpacing.Companion Companion;
}
public static final class MarqueeSpacing.Companion {
- method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public androidx.compose.foundation.MarqueeSpacing fractionOfContainer(float fraction);
+ method public androidx.compose.foundation.MarqueeSpacing fractionOfContainer(float fraction);
}
public enum MutatePriority {
diff --git a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/BasicMarqueeTest.kt b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/BasicMarqueeTest.kt
index ed67719..9cc7e7a 100644
--- a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/BasicMarqueeTest.kt
+++ b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/BasicMarqueeTest.kt
@@ -922,6 +922,7 @@
focusManager = LocalFocusManager.current
TestMarqueeContent(
Modifier
+ .focusable() // extra focusable for initial focus.
.basicMarqueeWithTestParams(animationMode = WhileFocused)
.focusRequester(focusRequester)
.focusable()
diff --git a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/ClickableTest.kt b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/ClickableTest.kt
index 56d0bec..4c72289 100644
--- a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/ClickableTest.kt
+++ b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/ClickableTest.kt
@@ -81,7 +81,9 @@
import androidx.test.filters.LargeTest
import androidx.test.filters.MediumTest
import androidx.test.platform.app.InstrumentationRegistry
+import com.google.common.truth.Correspondence
import com.google.common.truth.Truth.assertThat
+import kotlin.reflect.KClass
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import org.junit.After
@@ -97,6 +99,11 @@
@get:Rule
val rule = createComposeRule()
+ private val InstanceOf = Correspondence.from<Any, KClass<*>>(
+ { obj, clazz -> clazz?.isInstance(obj) ?: false },
+ "is an instance of"
+ )
+
@Before
fun before() {
isDebugInspectorInfoEnabled = true
@@ -1054,22 +1061,19 @@
val focusRequester = FocusRequester()
lateinit var focusManager: FocusManager
lateinit var inputModeManager: InputModeManager
- rule.setContent {
+ rule.setFocusableContent {
scope = rememberCoroutineScope()
focusManager = LocalFocusManager.current
inputModeManager = LocalInputModeManager.current
- Box {
- BasicText(
- "ClickableText",
- modifier = Modifier
- .testTag("myClickable")
- .focusRequester(focusRequester)
- .clickable(
- interactionSource = interactionSource,
- indication = null
- ) {}
- )
- }
+ Box {
+ BasicText(
+ "ClickableText",
+ modifier = Modifier
+ .testTag("myClickable")
+ .focusRequester(focusRequester)
+ .clickable(interactionSource = interactionSource, indication = null) {}
+ )
+ }
}
rule.runOnIdle {
@OptIn(ExperimentalComposeUiApi::class)
@@ -1092,8 +1096,9 @@
// Keyboard mode, so we should now be focused and see an interaction
rule.runOnIdle {
- assertThat(interactions).hasSize(1)
- assertThat(interactions.first()).isInstanceOf(FocusInteraction.Focus::class.java)
+ assertThat(interactions)
+ .comparingElementsUsing(InstanceOf)
+ .containsExactly(FocusInteraction.Focus::class)
}
rule.runOnIdle {
@@ -1101,12 +1106,12 @@
}
rule.runOnIdle {
- assertThat(interactions).hasSize(2)
- assertThat(interactions.first()).isInstanceOf(FocusInteraction.Focus::class.java)
- assertThat(interactions[1])
- .isInstanceOf(FocusInteraction.Unfocus::class.java)
- assertThat((interactions[1] as FocusInteraction.Unfocus).focus)
- .isEqualTo(interactions[0])
+ // TODO(b/308811852): Simplify the other assertions in FocusableTest, ClickableTest and
+ // CombinedClickable by using InstanceOf (like we do here).
+ assertThat(interactions)
+ .comparingElementsUsing(InstanceOf)
+ .containsExactly(FocusInteraction.Focus::class, FocusInteraction.Unfocus::class)
+ .inOrder()
}
}
diff --git a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/CombinedClickableTest.kt b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/CombinedClickableTest.kt
index 3c6d481..0defe94 100644
--- a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/CombinedClickableTest.kt
+++ b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/CombinedClickableTest.kt
@@ -1298,7 +1298,7 @@
val focusRequester = FocusRequester()
lateinit var focusManager: FocusManager
lateinit var inputModeManager: InputModeManager
- rule.setContent {
+ rule.setFocusableContent {
scope = rememberCoroutineScope()
focusManager = LocalFocusManager.current
inputModeManager = LocalInputModeManager.current
diff --git a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/FocusableTest.kt b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/FocusableTest.kt
index 46b4931..80b1504 100644
--- a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/FocusableTest.kt
+++ b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/FocusableTest.kt
@@ -97,7 +97,7 @@
@Test
fun focusable_defaultSemantics() {
- rule.setContent {
+ rule.setFocusableContent {
Box {
BasicText(
"focusableText",
@@ -115,7 +115,7 @@
@Test
fun focusable_disabledSemantics() {
- rule.setContent {
+ rule.setFocusableContent {
Box {
BasicText(
"focusableText",
@@ -133,7 +133,7 @@
@Test
fun focusable_focusAcquire() {
val (focusRequester, otherFocusRequester) = FocusRequester.createRefs()
- rule.setContent {
+ rule.setFocusableContent {
Box {
BasicText(
"focusableText",
@@ -176,7 +176,7 @@
lateinit var scope: CoroutineScope
- rule.setContent {
+ rule.setFocusableContent {
scope = rememberCoroutineScope()
Box {
BasicText(
@@ -236,7 +236,7 @@
lateinit var scope: CoroutineScope
- rule.setContent {
+ rule.setFocusableContent {
scope = rememberCoroutineScope()
Box {
if (emitFocusableText) {
@@ -284,7 +284,6 @@
}
}
- @OptIn(ExperimentalFoundationApi::class)
@Test
fun focusable_pins_whenItIsFocused() {
// Arrange.
@@ -296,7 +295,7 @@
return PinnedHandle {}
}
}
- rule.setContent {
+ rule.setFocusableContent {
CompositionLocalProvider(LocalPinnableContainer provides pinnableContainer) {
Box(
Modifier
@@ -318,7 +317,6 @@
}
}
- @OptIn(ExperimentalFoundationApi::class)
@Test
fun focusable_unpins_whenItIsUnfocused() {
// Arrange.
@@ -330,7 +328,7 @@
return PinnedHandle { onUnpinInvoked = true }
}
}
- rule.setContent {
+ rule.setFocusableContent {
CompositionLocalProvider(LocalPinnableContainer provides pinnableContainer) {
Box(
Modifier
@@ -386,7 +384,7 @@
}
val focusRequester = FocusRequester()
- rule.setContent {
+ rule.setFocusableContent {
with(rule.density) {
Box(
Modifier
@@ -422,7 +420,7 @@
lateinit var state: LazyListState
lateinit var coroutineScope: CoroutineScope
var items by mutableStateOf((1..20).toList())
- rule.setContent {
+ rule.setFocusableContent {
state = rememberLazyListState()
coroutineScope = rememberCoroutineScope()
LazyRow(
@@ -457,7 +455,7 @@
// Arrange.
var hasFocus = false
var itemVisible by mutableStateOf(true)
- rule.setContent {
+ rule.setFocusableContent {
SubcomposeLayout(
modifier = Modifier
.requiredSize(100.dp)
@@ -490,7 +488,6 @@
}
}
- @OptIn(ExperimentalFoundationApi::class)
@Test
fun focusable_updatePinnableContainer_staysPinned() {
// Arrange.
@@ -510,7 +507,7 @@
}
}
var pinnableContainer by mutableStateOf<PinnableContainer>(pinnableContainer1)
- rule.setContent {
+ rule.setFocusableContent {
CompositionLocalProvider(LocalPinnableContainer provides pinnableContainer) {
Box(
Modifier
@@ -544,7 +541,7 @@
val focusRequester = FocusRequester()
lateinit var state: FocusState
var key by mutableStateOf(0)
- rule.setContent {
+ rule.setFocusableContent {
ReusableContent(key) {
BasicText(
"focusableText",
@@ -594,7 +591,7 @@
)
}
- rule.setContent {
+ rule.setFocusableContent {
scope = rememberCoroutineScope()
if (moveContent) {
Box(Modifier.size(5.dp)) {
diff --git a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/FoundationTestUtils.kt b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/FoundationTestUtils.kt
new file mode 100644
index 0000000..990aaec
--- /dev/null
+++ b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/FoundationTestUtils.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.requiredSize
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.test.junit4.ComposeContentTestRule
+import androidx.compose.ui.unit.dp
+
+/**
+ * This function adds a parent composable which has size.
+ * [View.requestFocus()][android.view.View.requestFocus] will not take focus if the view has no
+ * size.
+ *
+ * @param extraItemForInitialFocus Includes an extra item that takes focus initially. This is
+ * useful in cases where we need tests that could be affected by initial focus. Eg. When there is
+ * only one focusable item and we clear focus, that item could end up being focused on again by the
+ * initial focus logic.
+ */
+internal fun ComposeContentTestRule.setFocusableContent(
+ extraItemForInitialFocus: Boolean = true,
+ content: @Composable () -> Unit
+) {
+ setContent {
+ if (extraItemForInitialFocus) {
+ Row {
+ Box(modifier = Modifier.requiredSize(10.dp, 10.dp).focusable())
+ Box { content() }
+ }
+ } else {
+ Box(modifier = Modifier.requiredSize(100.dp, 100.dp)) { content() }
+ }
+ }
+}
diff --git a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/ScrollableTest.kt b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/ScrollableTest.kt
index e05e7d7..e51bd1f 100644
--- a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/ScrollableTest.kt
+++ b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/ScrollableTest.kt
@@ -252,6 +252,29 @@
}
}
+ @OptIn(ExperimentalTestApi::class)
+ @Test
+ fun scrollable_horizontalScroll_mouseWheel_badMotionEvent() {
+ var total = 0f
+ val controller = ScrollableState(
+ consumeScrollDelta = {
+ total += it
+ it
+ }
+ )
+ setScrollableContent {
+ Modifier.scrollable(
+ state = controller,
+ orientation = Orientation.Horizontal
+ )
+ }
+ rule.onNodeWithTag(scrollableBoxTag).performMouseInput {
+ this.scroll(Float.NaN, ScrollWheel.Horizontal)
+ }
+
+ assertThat(total).isEqualTo(0)
+ }
+
/*
* Note: For keyboard scrolling to work (that is, scrolling based on the page up/down keys),
* at least one child within the scrollable must be focusable. (This matches the behavior in
@@ -513,6 +536,29 @@
}
}
+ @OptIn(ExperimentalTestApi::class)
+ @Test
+ fun scrollable_verticalScroll_mouseWheel_badMotionEvent() {
+ var total = 0f
+ val controller = ScrollableState(
+ consumeScrollDelta = {
+ total += it
+ it
+ }
+ )
+ setScrollableContent {
+ Modifier.scrollable(
+ state = controller,
+ orientation = Orientation.Vertical
+ )
+ }
+ rule.onNodeWithTag(scrollableBoxTag).performMouseInput {
+ this.scroll(Float.NaN, ScrollWheel.Vertical)
+ }
+
+ assertThat(total).isEqualTo(0)
+ }
+
/*
* Note: For keyboard scrolling to work (that is, scrolling based on the page up/down keys),
* at least one child within the scrollable must be focusable. (This matches the behavior in
diff --git a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/lazy/grid/LazyScrollTest.kt b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/lazy/grid/LazyScrollTest.kt
index fc52c37e..7a9fa96 100644
--- a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/lazy/grid/LazyScrollTest.kt
+++ b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/lazy/grid/LazyScrollTest.kt
@@ -19,7 +19,9 @@
import androidx.compose.animation.core.FloatSpringSpec
import androidx.compose.foundation.AutoTestFrameClock
import androidx.compose.foundation.gestures.animateScrollBy
+import androidx.compose.foundation.gestures.scrollBy
import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
@@ -68,11 +70,18 @@
}
}
- private fun testScroll(spacingPx: Int = 0, assertBlock: suspend () -> Unit) {
+ private fun testScroll(
+ spacingPx: Int = 0,
+ containerSizePx: Int = itemSizePx * 3,
+ afterContentPaddingPx: Int = 0,
+ assertBlock: suspend () -> Unit
+ ) {
rule.setContent {
state = rememberLazyGridState()
scope = rememberCoroutineScope()
- TestContent(with(rule.density) { spacingPx.toDp() })
+ with(rule.density) {
+ TestContent(spacingPx.toDp(), containerSizePx.toDp(), afterContentPaddingPx.toDp())
+ }
}
runBlocking {
assertBlock()
@@ -297,6 +306,85 @@
}
@Test
+ fun canScrollForwardAndBackward_afterSmallScrollFromStart() = testScroll(
+ containerSizePx = (itemSizePx * 1.5f).roundToInt()
+ ) {
+ val delta = (itemSizePx / 3f).roundToInt()
+ withContext(Dispatchers.Main + AutoTestFrameClock()) {
+ // small enough scroll to not cause any new items to be composed or old ones disposed.
+ state.scrollBy(delta.toFloat())
+ }
+ rule.runOnIdle {
+ assertThat(state.firstVisibleItemScrollOffset).isEqualTo(delta)
+ assertThat(state.canScrollForward).isTrue()
+ assertThat(state.canScrollBackward).isTrue()
+ }
+ // and scroll back to start
+ withContext(Dispatchers.Main + AutoTestFrameClock()) {
+ state.scrollBy(-delta.toFloat())
+ }
+ rule.runOnIdle {
+ assertThat(state.canScrollForward).isTrue()
+ assertThat(state.canScrollBackward).isFalse()
+ }
+ }
+
+ @Test
+ fun canScrollForwardAndBackward_afterSmallScrollFromEnd() = testScroll(
+ containerSizePx = (itemSizePx * 1.5f).roundToInt()
+ ) {
+ val delta = -(itemSizePx / 3f).roundToInt()
+ withContext(Dispatchers.Main + AutoTestFrameClock()) {
+ // scroll to the end of the list.
+ state.scrollToItem(itemsCount)
+ // small enough scroll to not cause any new items to be composed or old ones disposed.
+ state.scrollBy(delta.toFloat())
+ }
+ rule.runOnIdle {
+ assertThat(state.canScrollForward).isTrue()
+ assertThat(state.canScrollBackward).isTrue()
+ }
+ // and scroll back to the end
+ withContext(Dispatchers.Main + AutoTestFrameClock()) {
+ state.scrollBy(-delta.toFloat())
+ }
+ rule.runOnIdle {
+ assertThat(state.canScrollForward).isFalse()
+ assertThat(state.canScrollBackward).isTrue()
+ }
+ }
+
+ @Test
+ fun canScrollForwardAndBackward_afterSmallScrollFromEnd_withContentPadding() = testScroll(
+ containerSizePx = (itemSizePx * 1.5f).roundToInt(),
+ afterContentPaddingPx = 2,
+ ) {
+ val delta = -(itemSizePx / 3f).roundToInt()
+ withContext(Dispatchers.Main + AutoTestFrameClock()) {
+ // scroll to the end of the list.
+ state.scrollToItem(itemsCount)
+
+ assertThat(state.canScrollForward).isFalse()
+ assertThat(state.canScrollBackward).isTrue()
+
+ // small enough scroll to not cause any new items to be composed or old ones disposed.
+ state.scrollBy(delta.toFloat())
+ }
+ rule.runOnIdle {
+ assertThat(state.canScrollForward).isTrue()
+ assertThat(state.canScrollBackward).isTrue()
+ }
+ // and scroll back to the end
+ withContext(Dispatchers.Main + AutoTestFrameClock()) {
+ state.scrollBy(-delta.toFloat())
+ }
+ rule.runOnIdle {
+ assertThat(state.canScrollForward).isFalse()
+ assertThat(state.canScrollBackward).isTrue()
+ }
+ }
+
+ @Test
fun animatePerFrameForwardWithSpacing() = testScroll(spacingPx = 10) {
assertSpringAnimation(toIndex = 16, spacingPx = 10)
}
@@ -375,12 +463,13 @@
}
@Composable
- private fun TestContent(spacingDp: Dp) {
+ private fun TestContent(spacingDp: Dp, containerSizeDp: Dp, afterContentPaddingDp: Dp) {
if (vertical) {
LazyVerticalGrid(
GridCells.Fixed(2),
Modifier.height(containerSizeDp),
state,
+ contentPadding = PaddingValues(bottom = afterContentPaddingDp),
verticalArrangement = Arrangement.spacedBy(spacingDp)
) {
items(itemsCount) {
diff --git a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/selection/SelectableTest.kt b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/selection/SelectableTest.kt
index 5b384af..74078e3 100644
--- a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/selection/SelectableTest.kt
+++ b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/selection/SelectableTest.kt
@@ -26,6 +26,7 @@
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.setFocusableContent
import androidx.compose.foundation.text.BasicText
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.getValue
@@ -548,7 +549,7 @@
lateinit var focusManager: FocusManager
lateinit var inputModeManager: InputModeManager
- rule.setContent {
+ rule.setFocusableContent {
scope = rememberCoroutineScope()
focusManager = LocalFocusManager.current
inputModeManager = LocalInputModeManager.current
diff --git a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/selection/ToggleableTest.kt b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/selection/ToggleableTest.kt
index 4174820..312e6b5 100644
--- a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/selection/ToggleableTest.kt
+++ b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/selection/ToggleableTest.kt
@@ -29,6 +29,7 @@
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.setFocusableContent
import androidx.compose.foundation.text.BasicText
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.getValue
@@ -640,7 +641,7 @@
lateinit var focusManager: FocusManager
lateinit var inputModeManager: InputModeManager
- rule.setContent {
+ rule.setFocusableContent {
scope = rememberCoroutineScope()
focusManager = LocalFocusManager.current
inputModeManager = LocalInputModeManager.current
diff --git a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text/CoreTextFieldInputServiceIntegrationTest.kt b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text/CoreTextFieldInputServiceIntegrationTest.kt
index 6860c1a..489b3e2 100644
--- a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text/CoreTextFieldInputServiceIntegrationTest.kt
+++ b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text/CoreTextFieldInputServiceIntegrationTest.kt
@@ -19,6 +19,7 @@
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.offset
+import androidx.compose.foundation.setFocusableContent
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
@@ -370,7 +371,7 @@
lateinit var textLayoutResult: TextLayoutResult
val focusRequester = FocusRequester()
- setContent {
+ setContent(extraItemForInitialFocus = false) {
CoreTextField(
value = value,
modifier = Modifier.focusRequester(focusRequester),
@@ -400,7 +401,7 @@
lateinit var textLayoutResult: TextLayoutResult
val focusRequester = FocusRequester()
- setContent {
+ setContent(extraItemForInitialFocus = false) {
Box(Modifier.offset { offset }) {
CoreTextField(
value = value,
@@ -440,7 +441,7 @@
var value by mutableStateOf(TextFieldValue(""))
lateinit var textLayoutResult: TextLayoutResult
- setContent {
+ setContent(extraItemForInitialFocus = false) {
CoreTextField(
value = value,
modifier = Modifier.testTag(tag),
@@ -494,7 +495,7 @@
val focusRequester = FocusRequester()
val matrix = Matrix()
- setContent {
+ setContent(extraItemForInitialFocus = false) {
Box(Modifier.offset { offset }) {
CoreTextField(value = value,
modifier = Modifier.focusRequester(focusRequester),
@@ -539,8 +540,11 @@
}
}
- private fun setContent(content: @Composable () -> Unit) {
- rule.setContent {
+ private fun setContent(
+ extraItemForInitialFocus: Boolean = true,
+ content: @Composable () -> Unit
+ ) {
+ rule.setFocusableContent(extraItemForInitialFocus) {
focusManager = LocalFocusManager.current
CompositionLocalProvider(
LocalTextInputService provides textInputService,
diff --git a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text2/BasicTextField2ImmIntegrationTest.kt b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text2/BasicTextField2ImmIntegrationTest.kt
index ce06e74..d6aedab 100644
--- a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text2/BasicTextField2ImmIntegrationTest.kt
+++ b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text2/BasicTextField2ImmIntegrationTest.kt
@@ -17,6 +17,10 @@
package androidx.compose.foundation.text2
import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.focusable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.size
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text2.input.InputTransformation
import androidx.compose.foundation.text2.input.TextFieldBuffer
@@ -44,6 +48,7 @@
import androidx.compose.ui.test.requestFocus
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.unit.dp
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.FlakyTest
import androidx.test.filters.SmallTest
@@ -95,14 +100,14 @@
@Test
fun stopsBeingTextEditor_whenFocusLost() {
val state = TextFieldState()
- var focusManager: FocusManager? = null
+ lateinit var focusManager: FocusManager
inputMethodInterceptor.setTextFieldTestContent {
focusManager = LocalFocusManager.current
BasicTextField2(state, Modifier.testTag(Tag))
}
requestFocus(Tag)
rule.runOnIdle {
- focusManager!!.clearFocus()
+ focusManager.clearFocus()
}
inputMethodInterceptor.assertNoSessionActive()
}
@@ -215,6 +220,7 @@
commitText("hello", 1)
+ @Suppress("SpellCheckingInspection")
assertThat(state.text.toString()).isEqualTo("helloworld")
}
@@ -408,6 +414,12 @@
override val isWindowFocused = true
}
this.setContent {
- CompositionLocalProvider(LocalWindowInfo provides windowInfo, content)
+ CompositionLocalProvider(LocalWindowInfo provides windowInfo) {
+ Row {
+ // Extra focusable that takes initial focus when focus is cleared.
+ Box(Modifier.size(10.dp).focusable())
+ Box { content() }
+ }
+ }
}
}
diff --git a/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/text/KeyboardOptionsTest.kt b/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/text/KeyboardOptionsTest.kt
index 766c37e..f83f030 100644
--- a/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/text/KeyboardOptionsTest.kt
+++ b/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/text/KeyboardOptionsTest.kt
@@ -16,11 +16,11 @@
package androidx.compose.foundation.text
-import androidx.compose.ui.text.input.AndroidImeOptions
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.ImeOptions
import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.text.input.PlatformImeOptions
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
@@ -31,7 +31,7 @@
@Test
fun test_toImeOption() {
- val platformImeOptions = AndroidImeOptions("privateImeOptions")
+ val platformImeOptions = PlatformImeOptions("privateImeOptions")
val keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number,
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/BasicMarquee.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/BasicMarquee.kt
index 4b3e83b..03f9dbe 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/BasicMarquee.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/BasicMarquee.kt
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-@file:OptIn(ExperimentalFoundationApi::class)
-
package androidx.compose.foundation
import androidx.compose.animation.core.Animatable
@@ -71,27 +69,17 @@
import kotlinx.coroutines.withContext
// From https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/widget/TextView.java;l=736;drc=6d97d6d7215fef247d1a90e05545cac3676f9212
-@Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
-@ExperimentalFoundationApi
-@get:ExperimentalFoundationApi
+@Suppress("MayBeConstant")
val DefaultMarqueeIterations: Int = 3
// From https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/widget/TextView.java;l=13979;drc=6d97d6d7215fef247d1a90e05545cac3676f9212
-@Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
-@ExperimentalFoundationApi
-@get:ExperimentalFoundationApi
+@Suppress("MayBeConstant")
val DefaultMarqueeDelayMillis: Int = 1_200
// From https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/widget/TextView.java;l=14088;drc=6d97d6d7215fef247d1a90e05545cac3676f9212
-@Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
-@ExperimentalFoundationApi
-@get:ExperimentalFoundationApi
val DefaultMarqueeSpacing: MarqueeSpacing = MarqueeSpacing.fractionOfContainer(1f / 3f)
// From https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/widget/TextView.java;l=13980;drc=6d97d6d7215fef247d1a90e05545cac3676f9212
-@Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
-@ExperimentalFoundationApi
-@get:ExperimentalFoundationApi
val DefaultMarqueeVelocity: Dp = 30.dp
/**
@@ -132,12 +120,8 @@
* @param spacing A [MarqueeSpacing] that specifies how much space to leave at the end of the
* content before showing the beginning again.
* @param velocity The speed of the animation in dps / second.
- *
- * Note: this modifier and corresponding APIs are experimental pending some refinements in the API
- * surface, mostly related to customisation params.
*/
@Stable
-@ExperimentalFoundationApi
fun Modifier.basicMarquee(
iterations: Int = DefaultMarqueeIterations,
animationMode: MarqueeAnimationMode = Immediately,
@@ -433,7 +417,6 @@
}
/** Specifies when the [basicMarquee] animation runs. */
-@ExperimentalFoundationApi
@JvmInline
value class MarqueeAnimationMode private constructor(private val value: Int) {
@@ -448,17 +431,11 @@
* Starts animating immediately (accounting for any initial delay), irrespective of focus
* state.
*/
- @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
- @ExperimentalFoundationApi
- @get:ExperimentalFoundationApi
val Immediately = MarqueeAnimationMode(0)
/**
* Only animates while the marquee has focus or a node in the marquee's content has focus.
*/
- @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
- @ExperimentalFoundationApi
- @get:ExperimentalFoundationApi
val WhileFocused = MarqueeAnimationMode(1)
}
}
@@ -466,14 +443,12 @@
/**
* A [MarqueeSpacing] with a fixed size.
*/
-@ExperimentalFoundationApi
fun MarqueeSpacing(spacing: Dp): MarqueeSpacing = MarqueeSpacing { _, _ -> spacing.roundToPx() }
/**
* Defines a [calculateSpacing] method that determines the space after the end of [basicMarquee]
* content before drawing the content again.
*/
-@ExperimentalFoundationApi
@Stable
fun interface MarqueeSpacing {
/**
@@ -490,7 +465,6 @@
* @return The space in pixels between the end of the content and the beginning of the content
* when wrapping.
*/
- @ExperimentalFoundationApi
fun Density.calculateSpacing(
contentWidth: Int,
containerWidth: Int
@@ -500,7 +474,6 @@
/**
* A [MarqueeSpacing] that is a fraction of the container's width.
*/
- @ExperimentalFoundationApi
fun fractionOfContainer(fraction: Float): MarqueeSpacing = MarqueeSpacing { _, width ->
(fraction * width).roundToInt()
}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGrid.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGrid.kt
index 26f0514..daf2c45 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGrid.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGrid.kt
@@ -359,6 +359,7 @@
spanLayoutProvider = spanLayoutProvider,
pinnedItems = pinnedItems,
coroutineScope = coroutineScope,
+ placementScopeInvalidator = state.placementScopeInvalidator,
layout = { width, height, placement ->
layout(
containerConstraints.constrainWidth(width + totalHorizontalPadding),
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridItemPlacementAnimator.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridItemPlacementAnimator.kt
index 19d1f00..0d50108 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridItemPlacementAnimator.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridItemPlacementAnimator.kt
@@ -16,6 +16,7 @@
package androidx.compose.foundation.lazy.grid
+import androidx.collection.mutableScatterMapOf
import androidx.compose.foundation.lazy.layout.LazyLayoutAnimation
import androidx.compose.foundation.lazy.layout.LazyLayoutAnimationSpecsNode
import androidx.compose.foundation.lazy.layout.LazyLayoutKeyIndexMap
@@ -33,7 +34,7 @@
*/
internal class LazyGridItemPlacementAnimator {
// state containing relevant info for active items.
- private val keyToItemInfoMap = mutableMapOf<Any, ItemInfo>()
+ private val keyToItemInfoMap = mutableScatterMapOf<Any, ItemInfo>()
// snapshot of the key to index map used for the last measuring.
private var keyIndexMap: LazyLayoutKeyIndexMap = LazyLayoutKeyIndexMap.Empty
@@ -84,7 +85,7 @@
}
// first add all items we had in the previous run
- movingAwayKeys.addAll(keyToItemInfoMap.keys)
+ keyToItemInfoMap.forEachKey { movingAwayKeys.add(it) }
// iterate through the items which are visible (without animated offsets)
positionedItems.fastForEach { item ->
// remove items we have in the current one as they are still visible.
@@ -167,7 +168,7 @@
movingAwayKeys.forEach { key ->
// found an item which was in our map previously but is not a part of the
// positionedItems now
- val itemInfo = keyToItemInfoMap.getValue(key)
+ val itemInfo = keyToItemInfoMap[key]!!
val newIndex = keyIndexMap.getIndex(key)
if (newIndex == -1) {
@@ -181,6 +182,7 @@
Constraints.fixedHeight(itemInfo.crossAxisSize)
}
)
+ item.nonScrollableItem = true
// check if we have any active placement animation on the item
val inProgress =
itemInfo.animations.any { it?.isPlacementAnimationInProgress == true }
@@ -211,7 +213,7 @@
}
val mainAxisOffset = 0 - accumulatedOffset - item.mainAxisSize
- val itemInfo = keyToItemInfoMap.getValue(item.key)
+ val itemInfo = keyToItemInfoMap[item.key]!!
item.position(
mainAxisOffset = mainAxisOffset,
@@ -237,7 +239,7 @@
}
val mainAxisOffset = mainAxisLayoutSize + accumulatedOffset
- val itemInfo = keyToItemInfoMap.getValue(item.key)
+ val itemInfo = keyToItemInfoMap[item.key]!!
item.position(
mainAxisOffset = mainAxisOffset,
crossAxisOffset = itemInfo.crossAxisOffset,
@@ -269,7 +271,7 @@
private fun initializeAnimation(
item: LazyGridMeasuredItem,
mainAxisOffset: Int,
- itemInfo: ItemInfo = keyToItemInfoMap.getValue(item.key)
+ itemInfo: ItemInfo = keyToItemInfoMap[item.key]!!
) {
val firstPlaceableOffset = item.offset
@@ -290,7 +292,7 @@
}
private fun startAnimationsIfNeeded(item: LazyGridMeasuredItem) {
- val itemInfo = keyToItemInfoMap.getValue(item.key)
+ val itemInfo = keyToItemInfoMap[item.key]!!
itemInfo.animations.forEach { animation ->
if (animation != null) {
val newTarget = item.offset
@@ -305,8 +307,13 @@
}
}
- fun getAnimation(key: Any, placeableIndex: Int): LazyLayoutAnimation? =
- keyToItemInfoMap[key]?.animations?.get(placeableIndex)
+ fun getAnimation(key: Any, placeableIndex: Int): LazyLayoutAnimation? {
+ return if (keyToItemInfoMap.isEmpty()) {
+ null
+ } else {
+ keyToItemInfoMap[key]?.animations?.get(placeableIndex)
+ }
+ }
private val LazyGridMeasuredItem.hasAnimations: Boolean
get() {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasure.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasure.kt
index 2130384..9e08bf66 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasure.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasure.kt
@@ -19,6 +19,7 @@
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.lazy.layout.ObservableScopeInvalidator
import androidx.compose.ui.layout.MeasureResult
import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.unit.Constraints
@@ -62,6 +63,7 @@
spanLayoutProvider: LazyGridSpanLayoutProvider,
pinnedItems: List<Int>,
coroutineScope: CoroutineScope,
+ placementScopeInvalidator: ObservableScopeInvalidator,
layout: (Int, Int, Placeable.PlacementScope.() -> Unit) -> MeasureResult
): LazyGridMeasureResult {
require(beforeContentPadding >= 0) { "negative beforeContentPadding" }
@@ -81,7 +83,8 @@
reverseLayout = reverseLayout,
orientation = if (isVertical) Orientation.Vertical else Orientation.Horizontal,
afterContentPadding = afterContentPadding,
- mainAxisItemSpacing = spaceBetweenLines
+ mainAxisItemSpacing = spaceBetweenLines,
+ remeasureNeeded = false
)
} else {
var currentFirstLineIndex = firstVisibleLineIndex
@@ -137,10 +140,23 @@
val maxMainAxis = (maxOffset + afterContentPadding).coerceAtLeast(0)
var currentMainAxisOffset = -currentFirstLineScrollOffset
+ // will be set to true if we composed some items only to know their size and apply scroll,
+ // while in the end this item will not end up in the visible viewport. we will need an
+ // extra remeasure in order to dispose such items.
+ var remeasureNeeded = false
+
// first we need to skip lines we already composed while composing backward
- visibleLines.fastForEach {
- index++
- currentMainAxisOffset += it.mainAxisSizeWithSpacings
+ var indexInVisibleLines = 0
+ while (indexInVisibleLines < visibleLines.size) {
+ if (currentMainAxisOffset >= maxMainAxis) {
+ // this item is out of the bounds and will not be visible.
+ visibleLines.removeAt(indexInVisibleLines)
+ remeasureNeeded = true
+ } else {
+ index++
+ currentMainAxisOffset += visibleLines[indexInVisibleLines].mainAxisSizeWithSpacings
+ indexInVisibleLines++
+ }
}
// then composing visible lines forward until we fill the whole viewport.
@@ -159,9 +175,10 @@
currentMainAxisOffset += measuredLine.mainAxisSizeWithSpacings
if (currentMainAxisOffset <= minOffset &&
measuredLine.items.last().index != itemsCount - 1) {
- // this line is offscreen and will not be placed. advance firstVisibleLineIndex
+ // this line is offscreen and will not be visible. advance firstVisibleLineIndex
currentFirstLineIndex = index + 1
currentFirstLineScrollOffset -= measuredLine.mainAxisSizeWithSpacings
+ remeasureNeeded = true
} else {
visibleLines.add(measuredLine)
}
@@ -285,6 +302,8 @@
consumedScroll = consumedScroll,
measureResult = layout(layoutWidth, layoutHeight) {
positionedItems.fastForEach { it.place(this) }
+ // we attach it during the placement so LazyGridState can trigger re-placement
+ placementScopeInvalidator.attachToScope()
},
viewportStartOffset = -beforeContentPadding,
viewportEndOffset = mainAxisAvailableSize + afterContentPadding,
@@ -299,7 +318,8 @@
reverseLayout = reverseLayout,
orientation = if (isVertical) Orientation.Vertical else Orientation.Horizontal,
afterContentPadding = afterContentPadding,
- mainAxisItemSpacing = spaceBetweenLines
+ mainAxisItemSpacing = spaceBetweenLines,
+ remeasureNeeded = remeasureNeeded
)
}
}
@@ -390,7 +410,7 @@
} else {
absoluteOffset
}
- positionedItems.addAll(
+ positionedItems.addAllFromArray(
line.position(relativeOffset, layoutWidth, layoutHeight)
)
}
@@ -405,7 +425,7 @@
currentMainAxis = firstLineScrollOffset
lines.fastForEach {
- positionedItems.addAll(it.position(currentMainAxis, layoutWidth, layoutHeight))
+ positionedItems.addAllFromArray(it.position(currentMainAxis, layoutWidth, layoutHeight))
currentMainAxis += it.mainAxisSizeWithSpacings
}
@@ -417,3 +437,10 @@
}
return positionedItems
}
+
+// Faster version of addAll that does not create a list for each array
+private fun <T> MutableList<T>.addAllFromArray(arr: Array<T>) {
+ for (item in arr) {
+ add(item)
+ }
+}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasureResult.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasureResult.kt
index 00dfd71..49a5139 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasureResult.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasureResult.kt
@@ -16,30 +16,32 @@
package androidx.compose.foundation.lazy.grid
-import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.gestures.snapping.offsetOnMainAxis
import androidx.compose.ui.layout.MeasureResult
import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.util.fastForEach
/**
* The result of the measure pass for lazy list layout.
*/
-@OptIn(ExperimentalFoundationApi::class)
internal class LazyGridMeasureResult(
// properties defining the scroll position:
/** The new first visible line of items.*/
val firstVisibleLine: LazyGridMeasuredLine?,
/** The new value for [LazyGridState.firstVisibleItemScrollOffset].*/
- val firstVisibleLineScrollOffset: Int,
+ var firstVisibleLineScrollOffset: Int,
/** True if there is some space available to continue scrolling in the forward direction.*/
- val canScrollForward: Boolean,
+ var canScrollForward: Boolean,
/** The amount of scroll consumed during the measure pass.*/
- val consumedScroll: Float,
+ var consumedScroll: Float,
/** MeasureResult defining the layout.*/
measureResult: MeasureResult,
+ /** True when extra remeasure is required. */
+ val remeasureNeeded: Boolean,
// properties representing the info needed for LazyListLayoutInfo:
/** see [LazyGridLayoutInfo.visibleItemsInfo] */
- override val visibleItemsInfo: List<LazyGridItemInfo>,
+ override val visibleItemsInfo: List<LazyGridMeasuredItem>,
/** see [LazyGridLayoutInfo.viewportStartOffset] */
override val viewportStartOffset: Int,
/** see [LazyGridLayoutInfo.viewportEndOffset] */
@@ -55,7 +57,67 @@
/** see [LazyGridLayoutInfo.mainAxisItemSpacing] */
override val mainAxisItemSpacing: Int
) : LazyGridLayoutInfo, MeasureResult by measureResult {
+
+ val canScrollBackward
+ get() = (firstVisibleLine?.index ?: 0) != 0 || firstVisibleLineScrollOffset != 0
+
override val viewportSize: IntSize
get() = IntSize(width, height)
override val beforeContentPadding: Int get() = -viewportStartOffset
+
+ /**
+ * Tries to apply a scroll [delta] for this layout info. In some cases we can apply small
+ * scroll deltas by just changing the offsets for each [visibleItemsInfo].
+ * But we can only do so if after applying the delta we would not need to compose a new item
+ * or dispose an item which is currently visible. In this case this function will not apply
+ * the [delta] and return false.
+ *
+ * @return true if we can safely apply a passed scroll [delta] to this layout info.
+ * If true is returned, only the placement phase is needed to apply new offsets.
+ * If false is returned, it means we have to rerun the full measure phase to apply the [delta].
+ */
+ fun tryToApplyScrollWithoutRemeasure(delta: Int): Boolean {
+ if (remeasureNeeded || visibleItemsInfo.isEmpty() || firstVisibleLine == null ||
+ // applying this delta will change firstVisibleLineScrollOffset
+ (firstVisibleLineScrollOffset - delta) !in
+ 0 until firstVisibleLine.mainAxisSizeWithSpacings
+ ) {
+ return false
+ }
+ val first = visibleItemsInfo.first()
+ val last = visibleItemsInfo.last()
+ if (first.nonScrollableItem || last.nonScrollableItem) {
+ // non scrollable items require special handling.
+ return false
+ }
+ val canApply = if (delta < 0) {
+ // scrolling forward
+ val deltaToFirstItemChange = first.offsetOnMainAxis(orientation) +
+ first.mainAxisSizeWithSpacings - viewportStartOffset
+ val deltaToLastItemChange = last.offsetOnMainAxis(orientation) +
+ last.mainAxisSizeWithSpacings - viewportEndOffset
+ minOf(deltaToFirstItemChange, deltaToLastItemChange) > -delta
+ } else {
+ // scrolling backward
+ val deltaToFirstItemChange =
+ viewportStartOffset - first.offsetOnMainAxis(orientation)
+ val deltaToLastItemChange =
+ viewportEndOffset - last.offsetOnMainAxis(orientation)
+ minOf(deltaToFirstItemChange, deltaToLastItemChange) > delta
+ }
+ return if (canApply) {
+ firstVisibleLineScrollOffset -= delta
+ visibleItemsInfo.fastForEach {
+ it.applyScrollDelta(delta)
+ }
+ consumedScroll = delta.toFloat()
+ if (!canScrollForward && delta > 0) {
+ // we scrolled backward, so now we can scroll forward
+ canScrollForward = true
+ }
+ true
+ } else {
+ false
+ }
+ }
}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasuredItem.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasuredItem.kt
index 961341b..d7f4dd5 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasuredItem.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasuredItem.kt
@@ -90,6 +90,12 @@
private set
/**
+ * True when this item is not supposed to react on scroll delta. for example items being
+ * animated away out of the bounds are non scrollable.
+ */
+ var nonScrollableItem: Boolean = false
+
+ /**
* Calculates positions for the inner placeables at [mainAxisOffset], [crossAxisOffset].
* [layoutWidth] and [layoutHeight] should be provided to not place placeables which are ended
* up outside of the viewport (for example one item consist of 2 placeables, and the first one
@@ -123,6 +129,19 @@
maxMainAxisOffset = mainAxisLayoutSize + afterContentPadding
}
+ fun applyScrollDelta(delta: Int) {
+ if (nonScrollableItem) {
+ return
+ }
+ offset = offset.copy { it + delta }
+ repeat(placeablesCount) { index ->
+ val animation = animator.getAnimation(key, index)
+ if (animation != null) {
+ animation.rawOffset = animation.rawOffset.copy { mainAxis -> mainAxis + delta }
+ }
+ }
+ }
+
fun place(
scope: Placeable.PlacementScope,
) = with(scope) {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridScrollPosition.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridScrollPosition.kt
index 7ec7f70..30b61cc 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridScrollPosition.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridScrollPosition.kt
@@ -67,6 +67,11 @@
}
}
+ fun updateScrollOffset(scrollOffset: Int) {
+ check(scrollOffset >= 0f) { "scrollOffset should be non-negative ($scrollOffset)" }
+ this.scrollOffset = scrollOffset
+ }
+
/**
* Updates the scroll position - the passed values will be used as a start position for
* composing the items during the next measure pass and will be updated by the real
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridState.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridState.kt
index e76d3de..913d241 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridState.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridState.kt
@@ -28,6 +28,7 @@
import androidx.compose.foundation.lazy.layout.LazyLayoutBeyondBoundsInfo
import androidx.compose.foundation.lazy.layout.LazyLayoutPinnedItemList
import androidx.compose.foundation.lazy.layout.LazyLayoutPrefetchState
+import androidx.compose.foundation.lazy.layout.ObservableScopeInvalidator
import androidx.compose.foundation.lazy.layout.animateScrollToItem
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
@@ -35,17 +36,20 @@
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.neverEqualPolicy
import androidx.compose.runtime.saveable.Saver
import androidx.compose.runtime.saveable.listSaver
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
+import androidx.compose.ui.layout.AlignmentLine
+import androidx.compose.ui.layout.MeasureResult
import androidx.compose.ui.layout.Remeasurement
import androidx.compose.ui.layout.RemeasurementModifier
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Density
-import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.util.fastForEach
import kotlin.math.abs
+import kotlin.math.roundToInt
/**
* Creates a [LazyGridState] that is remembered across compositions.
@@ -115,7 +119,10 @@
val firstVisibleItemScrollOffset: Int get() = scrollPosition.scrollOffset
/** Backing state for [layoutInfo] */
- private val layoutInfoState = mutableStateOf<LazyGridLayoutInfo>(EmptyLazyGridLayoutInfo)
+ private val layoutInfoState = mutableStateOf(
+ EmptyLazyGridLayoutInfo,
+ neverEqualPolicy()
+ )
/**
* The object of [LazyGridLayoutInfo] calculated during the last layout pass. For example,
@@ -239,6 +246,8 @@
internal val nearestRange: IntRange by scrollPosition.nearestRangeState
+ internal val placementScopeInvalidator = ObservableScopeInvalidator()
+
/**
* Instantly brings the item at [index] to the top of the viewport, offset by [scrollOffset]
* pixels.
@@ -308,9 +317,21 @@
// inside measuring we do scrollToBeConsumed.roundToInt() so there will be no scroll if
// we have less than 0.5 pixels
if (abs(scrollToBeConsumed) > 0.5f) {
+ val layoutInfo = layoutInfoState.value
val preScrollToBeConsumed = scrollToBeConsumed
- remeasurement?.forceRemeasure()
- if (prefetchingEnabled) {
+ val intDelta = scrollToBeConsumed.roundToInt()
+ if (layoutInfo.tryToApplyScrollWithoutRemeasure(intDelta)) {
+ applyMeasureResult(
+ result = layoutInfo,
+ visibleItemsStayedTheSame = true
+ )
+ // we don't need to remeasure, so we only trigger re-placement:
+ placementScopeInvalidator.invalidateScope()
+
+ notifyPrefetch(preScrollToBeConsumed - scrollToBeConsumed, layoutInfo)
+ } else {
+ remeasurement?.forceRemeasure()
+
notifyPrefetch(preScrollToBeConsumed - scrollToBeConsumed)
}
}
@@ -329,7 +350,10 @@
}
}
- private fun notifyPrefetch(delta: Float) {
+ private fun notifyPrefetch(
+ delta: Float,
+ layoutInfo: LazyGridLayoutInfo = layoutInfoState.value
+ ) {
val prefetchState = prefetchState
if (!prefetchingEnabled) {
return
@@ -414,18 +438,23 @@
/**
* Updates the state with the new calculated scroll position and consumed scroll.
*/
- internal fun applyMeasureResult(result: LazyGridMeasureResult) {
- scrollPosition.updateFromMeasureResult(result)
+ internal fun applyMeasureResult(
+ result: LazyGridMeasureResult,
+ visibleItemsStayedTheSame: Boolean = false
+ ) {
scrollToBeConsumed -= result.consumedScroll
layoutInfoState.value = result
+ if (visibleItemsStayedTheSame) {
+ scrollPosition.updateScrollOffset(result.firstVisibleLineScrollOffset)
+ } else {
+ scrollPosition.updateFromMeasureResult(result)
+ cancelPrefetchIfVisibleItemsChanged(result)
+ }
+ canScrollBackward = result.canScrollBackward
canScrollForward = result.canScrollForward
- canScrollBackward = (result.firstVisibleLine?.index ?: 0) != 0 ||
- result.firstVisibleLineScrollOffset != 0
numMeasurePasses++
-
- cancelPrefetchIfVisibleItemsChanged(result)
}
/**
@@ -454,16 +483,25 @@
}
}
-@OptIn(ExperimentalFoundationApi::class)
-private object EmptyLazyGridLayoutInfo : LazyGridLayoutInfo {
- override val visibleItemsInfo = emptyList<LazyGridItemInfo>()
- override val viewportStartOffset = 0
- override val viewportEndOffset = 0
- override val totalItemsCount = 0
- override val viewportSize = IntSize.Zero
- override val orientation = Orientation.Vertical
- override val reverseLayout = false
- override val beforeContentPadding: Int = 0
- override val afterContentPadding: Int = 0
- override val mainAxisItemSpacing = 0
-}
+private val EmptyLazyGridLayoutInfo = LazyGridMeasureResult(
+ firstVisibleLine = null,
+ firstVisibleLineScrollOffset = 0,
+ canScrollForward = false,
+ consumedScroll = 0f,
+ measureResult = object : MeasureResult {
+ override val width: Int = 0
+ override val height: Int = 0
+ @Suppress("PrimitiveInCollection")
+ override val alignmentLines: Map<AlignmentLine, Int> = emptyMap()
+ override fun placeChildren() {}
+ },
+ visibleItemsInfo = emptyList(),
+ viewportStartOffset = 0,
+ viewportEndOffset = 0,
+ totalItemsCount = 0,
+ reverseLayout = false,
+ orientation = Orientation.Vertical,
+ afterContentPadding = 0,
+ mainAxisItemSpacing = 0,
+ remeasureNeeded = false
+)
diff --git a/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupPerfettoSdkBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupPerfettoSdkBenchmark.kt
index eb9ab43..32e2f34 100644
--- a/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupPerfettoSdkBenchmark.kt
+++ b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupPerfettoSdkBenchmark.kt
@@ -23,6 +23,7 @@
import androidx.benchmark.macro.TraceSectionMetric
import androidx.benchmark.macro.junit4.MacrobenchmarkRule
import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
import androidx.testutils.measureStartup
import org.hamcrest.CoreMatchers.`is`
import org.hamcrest.MatcherAssert.assertThat
@@ -33,6 +34,7 @@
@OptIn(ExperimentalMetricApi::class)
@LargeTest
+@SdkSuppress(minSdkVersion = 30) // required for perfetto sdk capture
@RunWith(Parameterized::class)
class TrivialStartupPerfettoSdkBenchmark(
private val startupMode: StartupMode,
diff --git a/compose/material3/material3-window-size-class/api/1.2.0-beta01.txt b/compose/material3/material3-window-size-class/api/1.2.0-beta01.txt
new file mode 100644
index 0000000..7da9b6a
--- /dev/null
+++ b/compose/material3/material3-window-size-class/api/1.2.0-beta01.txt
@@ -0,0 +1,60 @@
+// Signature format: 4.0
+package androidx.compose.material3.windowsizeclass {
+
+ public final class AndroidWindowSizeClass_androidKt {
+ method @SuppressCompatibility @androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi @androidx.compose.runtime.Composable public static androidx.compose.material3.windowsizeclass.WindowSizeClass calculateWindowSizeClass(android.app.Activity activity);
+ }
+
+ @SuppressCompatibility @kotlin.RequiresOptIn(message="This material3-window-size-class API is experimental and is likely to change or to " + "be removed in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalMaterial3WindowSizeClassApi {
+ }
+
+ @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class WindowHeightSizeClass implements java.lang.Comparable<androidx.compose.material3.windowsizeclass.WindowHeightSizeClass> {
+ method public operator int compareTo(int other);
+ field public static final androidx.compose.material3.windowsizeclass.WindowHeightSizeClass.Companion Companion;
+ }
+
+ public static final class WindowHeightSizeClass.Companion {
+ method public java.util.Set<androidx.compose.material3.windowsizeclass.WindowHeightSizeClass> getAllSizeClasses();
+ method public int getCompact();
+ method public java.util.Set<androidx.compose.material3.windowsizeclass.WindowHeightSizeClass> getDefaultSizeClasses();
+ method public int getExpanded();
+ method public int getMedium();
+ property public final java.util.Set<androidx.compose.material3.windowsizeclass.WindowHeightSizeClass> AllSizeClasses;
+ property public final int Compact;
+ property public final java.util.Set<androidx.compose.material3.windowsizeclass.WindowHeightSizeClass> DefaultSizeClasses;
+ property public final int Expanded;
+ property public final int Medium;
+ }
+
+ @androidx.compose.runtime.Immutable public final class WindowSizeClass {
+ method public int getHeightSizeClass();
+ method public int getWidthSizeClass();
+ property public final int heightSizeClass;
+ property public final int widthSizeClass;
+ field public static final androidx.compose.material3.windowsizeclass.WindowSizeClass.Companion Companion;
+ }
+
+ public static final class WindowSizeClass.Companion {
+ method @SuppressCompatibility @androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi public androidx.compose.material3.windowsizeclass.WindowSizeClass calculateFromSize(long size, optional java.util.Set<androidx.compose.material3.windowsizeclass.WindowWidthSizeClass> supportedWidthSizeClasses, optional java.util.Set<androidx.compose.material3.windowsizeclass.WindowHeightSizeClass> supportedHeightSizeClasses);
+ }
+
+ @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class WindowWidthSizeClass implements java.lang.Comparable<androidx.compose.material3.windowsizeclass.WindowWidthSizeClass> {
+ method public operator int compareTo(int other);
+ field public static final androidx.compose.material3.windowsizeclass.WindowWidthSizeClass.Companion Companion;
+ }
+
+ public static final class WindowWidthSizeClass.Companion {
+ method public java.util.Set<androidx.compose.material3.windowsizeclass.WindowWidthSizeClass> getAllSizeClasses();
+ method public int getCompact();
+ method public java.util.Set<androidx.compose.material3.windowsizeclass.WindowWidthSizeClass> getDefaultSizeClasses();
+ method public int getExpanded();
+ method public int getMedium();
+ property public final java.util.Set<androidx.compose.material3.windowsizeclass.WindowWidthSizeClass> AllSizeClasses;
+ property public final int Compact;
+ property public final java.util.Set<androidx.compose.material3.windowsizeclass.WindowWidthSizeClass> DefaultSizeClasses;
+ property public final int Expanded;
+ property public final int Medium;
+ }
+
+}
+
diff --git a/compose/material3/material3-window-size-class/api/res-1.2.0-beta01.txt b/compose/material3/material3-window-size-class/api/res-1.2.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/compose/material3/material3-window-size-class/api/res-1.2.0-beta01.txt
diff --git a/compose/material3/material3-window-size-class/api/restricted_1.2.0-beta01.txt b/compose/material3/material3-window-size-class/api/restricted_1.2.0-beta01.txt
new file mode 100644
index 0000000..7da9b6a
--- /dev/null
+++ b/compose/material3/material3-window-size-class/api/restricted_1.2.0-beta01.txt
@@ -0,0 +1,60 @@
+// Signature format: 4.0
+package androidx.compose.material3.windowsizeclass {
+
+ public final class AndroidWindowSizeClass_androidKt {
+ method @SuppressCompatibility @androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi @androidx.compose.runtime.Composable public static androidx.compose.material3.windowsizeclass.WindowSizeClass calculateWindowSizeClass(android.app.Activity activity);
+ }
+
+ @SuppressCompatibility @kotlin.RequiresOptIn(message="This material3-window-size-class API is experimental and is likely to change or to " + "be removed in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalMaterial3WindowSizeClassApi {
+ }
+
+ @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class WindowHeightSizeClass implements java.lang.Comparable<androidx.compose.material3.windowsizeclass.WindowHeightSizeClass> {
+ method public operator int compareTo(int other);
+ field public static final androidx.compose.material3.windowsizeclass.WindowHeightSizeClass.Companion Companion;
+ }
+
+ public static final class WindowHeightSizeClass.Companion {
+ method public java.util.Set<androidx.compose.material3.windowsizeclass.WindowHeightSizeClass> getAllSizeClasses();
+ method public int getCompact();
+ method public java.util.Set<androidx.compose.material3.windowsizeclass.WindowHeightSizeClass> getDefaultSizeClasses();
+ method public int getExpanded();
+ method public int getMedium();
+ property public final java.util.Set<androidx.compose.material3.windowsizeclass.WindowHeightSizeClass> AllSizeClasses;
+ property public final int Compact;
+ property public final java.util.Set<androidx.compose.material3.windowsizeclass.WindowHeightSizeClass> DefaultSizeClasses;
+ property public final int Expanded;
+ property public final int Medium;
+ }
+
+ @androidx.compose.runtime.Immutable public final class WindowSizeClass {
+ method public int getHeightSizeClass();
+ method public int getWidthSizeClass();
+ property public final int heightSizeClass;
+ property public final int widthSizeClass;
+ field public static final androidx.compose.material3.windowsizeclass.WindowSizeClass.Companion Companion;
+ }
+
+ public static final class WindowSizeClass.Companion {
+ method @SuppressCompatibility @androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi public androidx.compose.material3.windowsizeclass.WindowSizeClass calculateFromSize(long size, optional java.util.Set<androidx.compose.material3.windowsizeclass.WindowWidthSizeClass> supportedWidthSizeClasses, optional java.util.Set<androidx.compose.material3.windowsizeclass.WindowHeightSizeClass> supportedHeightSizeClasses);
+ }
+
+ @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class WindowWidthSizeClass implements java.lang.Comparable<androidx.compose.material3.windowsizeclass.WindowWidthSizeClass> {
+ method public operator int compareTo(int other);
+ field public static final androidx.compose.material3.windowsizeclass.WindowWidthSizeClass.Companion Companion;
+ }
+
+ public static final class WindowWidthSizeClass.Companion {
+ method public java.util.Set<androidx.compose.material3.windowsizeclass.WindowWidthSizeClass> getAllSizeClasses();
+ method public int getCompact();
+ method public java.util.Set<androidx.compose.material3.windowsizeclass.WindowWidthSizeClass> getDefaultSizeClasses();
+ method public int getExpanded();
+ method public int getMedium();
+ property public final java.util.Set<androidx.compose.material3.windowsizeclass.WindowWidthSizeClass> AllSizeClasses;
+ property public final int Compact;
+ property public final java.util.Set<androidx.compose.material3.windowsizeclass.WindowWidthSizeClass> DefaultSizeClasses;
+ property public final int Expanded;
+ property public final int Medium;
+ }
+
+}
+
diff --git a/compose/material3/material3/api/1.2.0-beta01.txt b/compose/material3/material3/api/1.2.0-beta01.txt
new file mode 100644
index 0000000..7ca2ade
--- /dev/null
+++ b/compose/material3/material3/api/1.2.0-beta01.txt
@@ -0,0 +1,2073 @@
+// Signature format: 4.0
+package androidx.compose.material3 {
+
+ public final class AlertDialogDefaults {
+ method @androidx.compose.runtime.Composable public long getContainerColor();
+ method @androidx.compose.runtime.Composable public long getIconContentColor();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ method @androidx.compose.runtime.Composable public long getTextContentColor();
+ method @androidx.compose.runtime.Composable public long getTitleContentColor();
+ method public float getTonalElevation();
+ property public final float TonalElevation;
+ property @androidx.compose.runtime.Composable public final long containerColor;
+ property @androidx.compose.runtime.Composable public final long iconContentColor;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ property @androidx.compose.runtime.Composable public final long textContentColor;
+ property @androidx.compose.runtime.Composable public final long titleContentColor;
+ field public static final androidx.compose.material3.AlertDialogDefaults INSTANCE;
+ }
+
+ public final class AndroidAlertDialog_androidKt {
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void AlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.window.DialogProperties properties, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void AlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, kotlin.jvm.functions.Function0<kotlin.Unit> confirmButton, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dismissButton, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long iconContentColor, optional long titleContentColor, optional long textContentColor, optional float tonalElevation, optional androidx.compose.ui.window.DialogProperties properties);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void BasicAlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.window.DialogProperties properties, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ }
+
+ public final class AndroidMenu_androidKt {
+ method @androidx.compose.runtime.Composable public static void DropdownMenu(boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional long offset, optional androidx.compose.foundation.ScrollState scrollState, optional androidx.compose.ui.window.PopupProperties properties, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @Deprecated @androidx.compose.runtime.Composable public static void DropdownMenu(boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional long offset, optional androidx.compose.ui.window.PopupProperties properties, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void DropdownMenuItem(kotlin.jvm.functions.Function0<kotlin.Unit> text, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional boolean enabled, optional androidx.compose.material3.MenuItemColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ }
+
+ public final class AppBarKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void BottomAppBar(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.BottomAppBarScrollBehavior? scrollBehavior, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void BottomAppBar(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void BottomAppBar(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? floatingActionButton, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void BottomAppBar(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? floatingActionButton, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.BottomAppBarScrollBehavior? scrollBehavior);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static androidx.compose.material3.BottomAppBarState BottomAppBarState(float initialHeightOffsetLimit, float initialHeightOffset, float initialContentOffset);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void CenterAlignedTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void LargeTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void MediumTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SmallTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.BottomAppBarState rememberBottomAppBarState(optional float initialHeightOffsetLimit, optional float initialHeightOffset, optional float initialContentOffset);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.TopAppBarState rememberTopAppBarState(optional float initialHeightOffsetLimit, optional float initialHeightOffset, optional float initialContentOffset);
+ }
+
+ public final class AssistChipDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke assistChipBorder(boolean enabled, optional long borderColor, optional long disabledBorderColor, optional float borderWidth);
+ method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.ChipBorder assistChipBorder(optional long borderColor, optional long disabledBorderColor, optional float borderWidth);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors assistChipColors(optional long containerColor, optional long labelColor, optional long leadingIconContentColor, optional long trailingIconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconContentColor, optional long disabledTrailingIconContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation assistChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors elevatedAssistChipColors(optional long containerColor, optional long labelColor, optional long leadingIconContentColor, optional long trailingIconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconContentColor, optional long disabledTrailingIconContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation elevatedAssistChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+ method public float getHeight();
+ method public float getIconSize();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ property public final float Height;
+ property public final float IconSize;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ field public static final androidx.compose.material3.AssistChipDefaults INSTANCE;
+ }
+
+ public final class BadgeDefaults {
+ method @androidx.compose.runtime.Composable public long getContainerColor();
+ property @androidx.compose.runtime.Composable public final long containerColor;
+ field public static final androidx.compose.material3.BadgeDefaults INSTANCE;
+ }
+
+ public final class BadgeKt {
+ method @androidx.compose.runtime.Composable public static void Badge(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit>? content);
+ method @androidx.compose.runtime.Composable public static void BadgedBox(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> badge, optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public interface BasicTooltipState {
+ method public void dismiss();
+ method public boolean isPersistent();
+ method public boolean isVisible();
+ method public void onDispose();
+ method public suspend Object? show(optional androidx.compose.foundation.MutatePriority mutatePriority, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ property public abstract boolean isPersistent;
+ property public abstract boolean isVisible;
+ }
+
+ public final class BottomAppBarDefaults {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.BottomAppBarScrollBehavior exitAlwaysScrollBehavior(optional androidx.compose.material3.BottomAppBarState state, optional kotlin.jvm.functions.Function0<java.lang.Boolean> canScroll, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float>? snapAnimationSpec, optional androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float>? flingAnimationSpec);
+ method @androidx.compose.runtime.Composable public long getBottomAppBarFabColor();
+ method @androidx.compose.runtime.Composable public long getContainerColor();
+ method public float getContainerElevation();
+ method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+ property public final float ContainerElevation;
+ property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
+ property @androidx.compose.runtime.Composable public final long bottomAppBarFabColor;
+ property @androidx.compose.runtime.Composable public final long containerColor;
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+ field public static final androidx.compose.material3.BottomAppBarDefaults INSTANCE;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public interface BottomAppBarScrollBehavior {
+ method public androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float>? getFlingAnimationSpec();
+ method public androidx.compose.ui.input.nestedscroll.NestedScrollConnection getNestedScrollConnection();
+ method public androidx.compose.animation.core.AnimationSpec<java.lang.Float>? getSnapAnimationSpec();
+ method public androidx.compose.material3.BottomAppBarState getState();
+ method public boolean isPinned();
+ property public abstract androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float>? flingAnimationSpec;
+ property public abstract boolean isPinned;
+ property public abstract androidx.compose.ui.input.nestedscroll.NestedScrollConnection nestedScrollConnection;
+ property public abstract androidx.compose.animation.core.AnimationSpec<java.lang.Float>? snapAnimationSpec;
+ property public abstract androidx.compose.material3.BottomAppBarState state;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public interface BottomAppBarState {
+ method public float getCollapsedFraction();
+ method public float getContentOffset();
+ method public float getHeightOffset();
+ method public float getHeightOffsetLimit();
+ method public void setContentOffset(float);
+ method public void setHeightOffset(float);
+ method public void setHeightOffsetLimit(float);
+ property public abstract float collapsedFraction;
+ property public abstract float contentOffset;
+ property public abstract float heightOffset;
+ property public abstract float heightOffsetLimit;
+ field public static final androidx.compose.material3.BottomAppBarState.Companion Companion;
+ }
+
+ public static final class BottomAppBarState.Companion {
+ method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.BottomAppBarState,?> getSaver();
+ property public final androidx.compose.runtime.saveable.Saver<androidx.compose.material3.BottomAppBarState,?> Saver;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class BottomSheetDefaults {
+ method @androidx.compose.runtime.Composable public void DragHandle(optional androidx.compose.ui.Modifier modifier, optional float width, optional float height, optional androidx.compose.ui.graphics.Shape shape, optional long color);
+ method @androidx.compose.runtime.Composable public long getContainerColor();
+ method public float getElevation();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getExpandedShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getHiddenShape();
+ method @androidx.compose.runtime.Composable public long getScrimColor();
+ method public float getSheetMaxWidth();
+ method public float getSheetPeekHeight();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+ property @androidx.compose.runtime.Composable public final long ContainerColor;
+ property public final float Elevation;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape ExpandedShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape HiddenShape;
+ property @androidx.compose.runtime.Composable public final long ScrimColor;
+ property public final float SheetMaxWidth;
+ property public final float SheetPeekHeight;
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+ field public static final androidx.compose.material3.BottomSheetDefaults INSTANCE;
+ }
+
+ public final class BottomSheetScaffoldKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void BottomSheetScaffold(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> sheetContent, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.BottomSheetScaffoldState scaffoldState, optional float sheetPeekHeight, optional float sheetMaxWidth, optional androidx.compose.ui.graphics.Shape sheetShape, optional long sheetContainerColor, optional long sheetContentColor, optional float sheetTonalElevation, optional float sheetShadowElevation, optional kotlin.jvm.functions.Function0<kotlin.Unit>? sheetDragHandle, optional boolean sheetSwipeEnabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? topBar, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SnackbarHostState,kotlin.Unit> snackbarHost, optional long containerColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.BottomSheetScaffoldState rememberBottomSheetScaffoldState(optional androidx.compose.material3.SheetState bottomSheetState, optional androidx.compose.material3.SnackbarHostState snackbarHostState);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.SheetState rememberStandardBottomSheetState(optional androidx.compose.material3.SheetValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange, optional boolean skipHiddenState);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class BottomSheetScaffoldState {
+ ctor public BottomSheetScaffoldState(androidx.compose.material3.SheetState bottomSheetState, androidx.compose.material3.SnackbarHostState snackbarHostState);
+ method public androidx.compose.material3.SheetState getBottomSheetState();
+ method public androidx.compose.material3.SnackbarHostState getSnackbarHostState();
+ property public final androidx.compose.material3.SheetState bottomSheetState;
+ property public final androidx.compose.material3.SnackbarHostState snackbarHostState;
+ }
+
+ @androidx.compose.runtime.Immutable public final class ButtonColors {
+ ctor public ButtonColors(long containerColor, long contentColor, long disabledContainerColor, long disabledContentColor);
+ method public long getContainerColor();
+ method public long getContentColor();
+ method public long getDisabledContainerColor();
+ method public long getDisabledContentColor();
+ property public final long containerColor;
+ property public final long contentColor;
+ property public final long disabledContainerColor;
+ property public final long disabledContentColor;
+ }
+
+ public final class ButtonDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors buttonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonElevation buttonElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float disabledElevation);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors elevatedButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonElevation elevatedButtonElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float disabledElevation);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors filledTonalButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonElevation filledTonalButtonElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float disabledElevation);
+ method public androidx.compose.foundation.layout.PaddingValues getButtonWithIconContentPadding();
+ method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getElevatedShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFilledTonalShape();
+ method public float getIconSize();
+ method public float getIconSpacing();
+ method public float getMinHeight();
+ method public float getMinWidth();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke getOutlinedButtonBorder();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getOutlinedShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ method public androidx.compose.foundation.layout.PaddingValues getTextButtonContentPadding();
+ method public androidx.compose.foundation.layout.PaddingValues getTextButtonWithIconContentPadding();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getTextShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors outlinedButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors textButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+ property public final androidx.compose.foundation.layout.PaddingValues ButtonWithIconContentPadding;
+ property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
+ property public final float IconSize;
+ property public final float IconSpacing;
+ property public final float MinHeight;
+ property public final float MinWidth;
+ property public final androidx.compose.foundation.layout.PaddingValues TextButtonContentPadding;
+ property public final androidx.compose.foundation.layout.PaddingValues TextButtonWithIconContentPadding;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape elevatedShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape filledTonalShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.BorderStroke outlinedButtonBorder;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape outlinedShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape textShape;
+ field public static final androidx.compose.material3.ButtonDefaults INSTANCE;
+ }
+
+ @androidx.compose.runtime.Stable public final class ButtonElevation {
+ }
+
+ public final class ButtonKt {
+ method @androidx.compose.runtime.Composable public static void Button(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void ElevatedButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void FilledTonalButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void OutlinedButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void TextButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ }
+
+ public final class CalendarModelKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static String formatWithSkeleton(long utcTimeMillis, String skeleton, java.util.Locale locale, java.util.Map<java.lang.String,java.lang.Object> cache);
+ }
+
+ public final class CalendarModel_androidKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static String formatWithSkeleton(long utcTimeMillis, String skeleton, java.util.Locale locale, java.util.Map<java.lang.String,java.lang.Object> cache);
+ }
+
+ @androidx.compose.runtime.Immutable public final class CardColors {
+ ctor public CardColors(long containerColor, long contentColor, long disabledContainerColor, long disabledContentColor);
+ method public long getContainerColor();
+ method public long getContentColor();
+ method public long getDisabledContainerColor();
+ method public long getDisabledContentColor();
+ property public final long containerColor;
+ property public final long contentColor;
+ property public final long disabledContainerColor;
+ property public final long disabledContentColor;
+ }
+
+ public final class CardDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.CardColors cardColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.CardElevation cardElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.CardColors elevatedCardColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.CardElevation elevatedCardElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getElevatedShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getOutlinedShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke outlinedCardBorder(optional boolean enabled);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.CardColors outlinedCardColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.CardElevation outlinedCardElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape elevatedShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape outlinedShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ field public static final androidx.compose.material3.CardDefaults INSTANCE;
+ }
+
+ @androidx.compose.runtime.Immutable public final class CardElevation {
+ }
+
+ public final class CardKt {
+ method @androidx.compose.runtime.Composable public static void Card(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.CardColors colors, optional androidx.compose.material3.CardElevation elevation, optional androidx.compose.foundation.BorderStroke? border, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void Card(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.CardColors colors, optional androidx.compose.material3.CardElevation elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void ElevatedCard(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.CardColors colors, optional androidx.compose.material3.CardElevation elevation, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void ElevatedCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.CardColors colors, optional androidx.compose.material3.CardElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void OutlinedCard(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.CardColors colors, optional androidx.compose.material3.CardElevation elevation, optional androidx.compose.foundation.BorderStroke border, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void OutlinedCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.CardColors colors, optional androidx.compose.material3.CardElevation elevation, optional androidx.compose.foundation.BorderStroke border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ }
+
+ @androidx.compose.runtime.Immutable public final class CheckboxColors {
+ ctor public CheckboxColors(long checkedCheckmarkColor, long uncheckedCheckmarkColor, long checkedBoxColor, long uncheckedBoxColor, long disabledCheckedBoxColor, long disabledUncheckedBoxColor, long disabledIndeterminateBoxColor, long checkedBorderColor, long uncheckedBorderColor, long disabledBorderColor, long disabledUncheckedBorderColor, long disabledIndeterminateBorderColor);
+ method public long getCheckedBorderColor();
+ method public long getCheckedBoxColor();
+ method public long getCheckedCheckmarkColor();
+ method public long getDisabledBorderColor();
+ method public long getDisabledCheckedBoxColor();
+ method public long getDisabledIndeterminateBorderColor();
+ method public long getDisabledIndeterminateBoxColor();
+ method public long getDisabledUncheckedBorderColor();
+ method public long getDisabledUncheckedBoxColor();
+ method public long getUncheckedBorderColor();
+ method public long getUncheckedBoxColor();
+ method public long getUncheckedCheckmarkColor();
+ property public final long checkedBorderColor;
+ property public final long checkedBoxColor;
+ property public final long checkedCheckmarkColor;
+ property public final long disabledBorderColor;
+ property public final long disabledCheckedBoxColor;
+ property public final long disabledIndeterminateBorderColor;
+ property public final long disabledIndeterminateBoxColor;
+ property public final long disabledUncheckedBorderColor;
+ property public final long disabledUncheckedBoxColor;
+ property public final long uncheckedBorderColor;
+ property public final long uncheckedBoxColor;
+ property public final long uncheckedCheckmarkColor;
+ }
+
+ public final class CheckboxDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.CheckboxColors colors(optional long checkedColor, optional long uncheckedColor, optional long checkmarkColor, optional long disabledCheckedColor, optional long disabledUncheckedColor, optional long disabledIndeterminateColor);
+ field public static final androidx.compose.material3.CheckboxDefaults INSTANCE;
+ }
+
+ public final class CheckboxKt {
+ method @androidx.compose.runtime.Composable public static void Checkbox(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit>? onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable public static void TriStateCheckbox(androidx.compose.ui.state.ToggleableState state, kotlin.jvm.functions.Function0<kotlin.Unit>? onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ }
+
+ @Deprecated @androidx.compose.runtime.Immutable public final class ChipBorder {
+ }
+
+ @androidx.compose.runtime.Immutable public final class ChipColors {
+ ctor public ChipColors(long containerColor, long labelColor, long leadingIconContentColor, long trailingIconContentColor, long disabledContainerColor, long disabledLabelColor, long disabledLeadingIconContentColor, long disabledTrailingIconContentColor);
+ method public long getContainerColor();
+ method public long getDisabledContainerColor();
+ method public long getDisabledLabelColor();
+ method public long getDisabledLeadingIconContentColor();
+ method public long getDisabledTrailingIconContentColor();
+ method public long getLabelColor();
+ method public long getLeadingIconContentColor();
+ method public long getTrailingIconContentColor();
+ property public final long containerColor;
+ property public final long disabledContainerColor;
+ property public final long disabledLabelColor;
+ property public final long disabledLeadingIconContentColor;
+ property public final long disabledTrailingIconContentColor;
+ property public final long labelColor;
+ property public final long leadingIconContentColor;
+ property public final long trailingIconContentColor;
+ }
+
+ @androidx.compose.runtime.Immutable public final class ChipElevation {
+ ctor public ChipElevation(float elevation, float pressedElevation, float focusedElevation, float hoveredElevation, float draggedElevation, float disabledElevation);
+ method public float getDisabledElevation();
+ method public float getDraggedElevation();
+ method public float getElevation();
+ method public float getFocusedElevation();
+ method public float getHoveredElevation();
+ method public float getPressedElevation();
+ property public final float disabledElevation;
+ property public final float draggedElevation;
+ property public final float elevation;
+ property public final float focusedElevation;
+ property public final float hoveredElevation;
+ property public final float pressedElevation;
+ }
+
+ public final class ChipKt {
+ method @androidx.compose.runtime.Composable public static void AssistChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @Deprecated @androidx.compose.runtime.Composable public static void AssistChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable public static void ElevatedAssistChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @Deprecated @androidx.compose.runtime.Composable public static void ElevatedAssistChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable public static void ElevatedFilterChip(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SelectableChipColors colors, optional androidx.compose.material3.SelectableChipElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable public static void ElevatedSuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @Deprecated @androidx.compose.runtime.Composable public static void ElevatedSuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable public static void FilterChip(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SelectableChipColors colors, optional androidx.compose.material3.SelectableChipElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable public static void InputChip(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? avatar, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SelectableChipColors colors, optional androidx.compose.material3.SelectableChipElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable public static void SuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @Deprecated @androidx.compose.runtime.Composable public static void SuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ }
+
+ @androidx.compose.runtime.Immutable public final class ColorScheme {
+ ctor public ColorScheme(long primary, long onPrimary, long primaryContainer, long onPrimaryContainer, long inversePrimary, long secondary, long onSecondary, long secondaryContainer, long onSecondaryContainer, long tertiary, long onTertiary, long tertiaryContainer, long onTertiaryContainer, long background, long onBackground, long surface, long onSurface, long surfaceVariant, long onSurfaceVariant, long surfaceTint, long inverseSurface, long inverseOnSurface, long error, long onError, long errorContainer, long onErrorContainer, long outline, long outlineVariant, long scrim);
+ ctor public ColorScheme(long primary, long onPrimary, long primaryContainer, long onPrimaryContainer, long inversePrimary, long secondary, long onSecondary, long secondaryContainer, long onSecondaryContainer, long tertiary, long onTertiary, long tertiaryContainer, long onTertiaryContainer, long background, long onBackground, long surface, long onSurface, long surfaceVariant, long onSurfaceVariant, long surfaceTint, long inverseSurface, long inverseOnSurface, long error, long onError, long errorContainer, long onErrorContainer, long outline, long outlineVariant, long scrim, long surfaceBright, long surfaceDim, long surfaceContainer, long surfaceContainerHigh, long surfaceContainerHighest, long surfaceContainerLow, long surfaceContainerLowest);
+ method @Deprecated public androidx.compose.material3.ColorScheme copy(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+ method public androidx.compose.material3.ColorScheme copy(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim, optional long surfaceBright, optional long surfaceDim, optional long surfaceContainer, optional long surfaceContainerHigh, optional long surfaceContainerHighest, optional long surfaceContainerLow, optional long surfaceContainerLowest);
+ method public long getBackground();
+ method public long getError();
+ method public long getErrorContainer();
+ method public long getInverseOnSurface();
+ method public long getInversePrimary();
+ method public long getInverseSurface();
+ method public long getOnBackground();
+ method public long getOnError();
+ method public long getOnErrorContainer();
+ method public long getOnPrimary();
+ method public long getOnPrimaryContainer();
+ method public long getOnSecondary();
+ method public long getOnSecondaryContainer();
+ method public long getOnSurface();
+ method public long getOnSurfaceVariant();
+ method public long getOnTertiary();
+ method public long getOnTertiaryContainer();
+ method public long getOutline();
+ method public long getOutlineVariant();
+ method public long getPrimary();
+ method public long getPrimaryContainer();
+ method public long getScrim();
+ method public long getSecondary();
+ method public long getSecondaryContainer();
+ method public long getSurface();
+ method public long getSurfaceBright();
+ method public long getSurfaceContainer();
+ method public long getSurfaceContainerHigh();
+ method public long getSurfaceContainerHighest();
+ method public long getSurfaceContainerLow();
+ method public long getSurfaceContainerLowest();
+ method public long getSurfaceDim();
+ method public long getSurfaceTint();
+ method public long getSurfaceVariant();
+ method public long getTertiary();
+ method public long getTertiaryContainer();
+ property public final long background;
+ property public final long error;
+ property public final long errorContainer;
+ property public final long inverseOnSurface;
+ property public final long inversePrimary;
+ property public final long inverseSurface;
+ property public final long onBackground;
+ property public final long onError;
+ property public final long onErrorContainer;
+ property public final long onPrimary;
+ property public final long onPrimaryContainer;
+ property public final long onSecondary;
+ property public final long onSecondaryContainer;
+ property public final long onSurface;
+ property public final long onSurfaceVariant;
+ property public final long onTertiary;
+ property public final long onTertiaryContainer;
+ property public final long outline;
+ property public final long outlineVariant;
+ property public final long primary;
+ property public final long primaryContainer;
+ property public final long scrim;
+ property public final long secondary;
+ property public final long secondaryContainer;
+ property public final long surface;
+ property public final long surfaceBright;
+ property public final long surfaceContainer;
+ property public final long surfaceContainerHigh;
+ property public final long surfaceContainerHighest;
+ property public final long surfaceContainerLow;
+ property public final long surfaceContainerLowest;
+ property public final long surfaceDim;
+ property public final long surfaceTint;
+ property public final long surfaceVariant;
+ property public final long tertiary;
+ property public final long tertiaryContainer;
+ }
+
+ public final class ColorSchemeKt {
+ method @androidx.compose.runtime.Stable public static long contentColorFor(androidx.compose.material3.ColorScheme, long backgroundColor);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static long contentColorFor(long backgroundColor);
+ method @Deprecated public static androidx.compose.material3.ColorScheme darkColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+ method public static androidx.compose.material3.ColorScheme darkColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim, optional long surfaceBright, optional long surfaceContainer, optional long surfaceContainerHigh, optional long surfaceContainerHighest, optional long surfaceContainerLow, optional long surfaceContainerLowest, optional long surfaceDim);
+ method public static androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> getLocalTonalElevationEnabled();
+ method @Deprecated public static androidx.compose.material3.ColorScheme lightColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+ method public static androidx.compose.material3.ColorScheme lightColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim, optional long surfaceBright, optional long surfaceContainer, optional long surfaceContainerHigh, optional long surfaceContainerHighest, optional long surfaceContainerLow, optional long surfaceContainerLowest, optional long surfaceDim);
+ method @androidx.compose.runtime.Stable public static long surfaceColorAtElevation(androidx.compose.material3.ColorScheme, float elevation);
+ property public static final androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> LocalTonalElevationEnabled;
+ }
+
+ public final class ContentColorKt {
+ method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.graphics.Color> getLocalContentColor();
+ property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.graphics.Color> LocalContentColor;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class DatePickerColors {
+ ctor public DatePickerColors(long containerColor, long titleContentColor, long headlineContentColor, long weekdayContentColor, long subheadContentColor, long navigationContentColor, long yearContentColor, long disabledYearContentColor, long currentYearContentColor, long selectedYearContentColor, long disabledSelectedYearContentColor, long selectedYearContainerColor, long disabledSelectedYearContainerColor, long dayContentColor, long disabledDayContentColor, long selectedDayContentColor, long disabledSelectedDayContentColor, long selectedDayContainerColor, long disabledSelectedDayContainerColor, long todayContentColor, long todayDateBorderColor, long dayInSelectionRangeContainerColor, long dayInSelectionRangeContentColor, long dividerColor, androidx.compose.material3.TextFieldColors dateTextFieldColors);
+ method public long getContainerColor();
+ method public long getCurrentYearContentColor();
+ method public androidx.compose.material3.TextFieldColors getDateTextFieldColors();
+ method public long getDayContentColor();
+ method public long getDayInSelectionRangeContainerColor();
+ method public long getDayInSelectionRangeContentColor();
+ method public long getDisabledDayContentColor();
+ method public long getDisabledSelectedDayContainerColor();
+ method public long getDisabledSelectedDayContentColor();
+ method public long getDisabledSelectedYearContainerColor();
+ method public long getDisabledSelectedYearContentColor();
+ method public long getDisabledYearContentColor();
+ method public long getDividerColor();
+ method public long getHeadlineContentColor();
+ method public long getNavigationContentColor();
+ method public long getSelectedDayContainerColor();
+ method public long getSelectedDayContentColor();
+ method public long getSelectedYearContainerColor();
+ method public long getSelectedYearContentColor();
+ method public long getSubheadContentColor();
+ method public long getTitleContentColor();
+ method public long getTodayContentColor();
+ method public long getTodayDateBorderColor();
+ method public long getWeekdayContentColor();
+ method public long getYearContentColor();
+ property public final long containerColor;
+ property public final long currentYearContentColor;
+ property public final androidx.compose.material3.TextFieldColors dateTextFieldColors;
+ property public final long dayContentColor;
+ property public final long dayInSelectionRangeContainerColor;
+ property public final long dayInSelectionRangeContentColor;
+ property public final long disabledDayContentColor;
+ property public final long disabledSelectedDayContainerColor;
+ property public final long disabledSelectedDayContentColor;
+ property public final long disabledSelectedYearContainerColor;
+ property public final long disabledSelectedYearContentColor;
+ property public final long disabledYearContentColor;
+ property public final long dividerColor;
+ property public final long headlineContentColor;
+ property public final long navigationContentColor;
+ property public final long selectedDayContainerColor;
+ property public final long selectedDayContentColor;
+ property public final long selectedYearContainerColor;
+ property public final long selectedYearContentColor;
+ property public final long subheadContentColor;
+ property public final long titleContentColor;
+ property public final long todayContentColor;
+ property public final long todayDateBorderColor;
+ property public final long weekdayContentColor;
+ property public final long yearContentColor;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class DatePickerDefaults {
+ method @androidx.compose.runtime.Composable public void DatePickerHeadline(Long? selectedDateMillis, int displayMode, androidx.compose.material3.DatePickerFormatter dateFormatter, optional androidx.compose.ui.Modifier modifier);
+ method @androidx.compose.runtime.Composable public void DatePickerTitle(int displayMode, optional androidx.compose.ui.Modifier modifier);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.DatePickerColors colors(optional long containerColor, optional long titleContentColor, optional long headlineContentColor, optional long weekdayContentColor, optional long subheadContentColor, optional long navigationContentColor, optional long yearContentColor, optional long disabledYearContentColor, optional long currentYearContentColor, optional long selectedYearContentColor, optional long disabledSelectedYearContentColor, optional long selectedYearContainerColor, optional long disabledSelectedYearContainerColor, optional long dayContentColor, optional long disabledDayContentColor, optional long selectedDayContentColor, optional long disabledSelectedDayContentColor, optional long selectedDayContainerColor, optional long disabledSelectedDayContainerColor, optional long todayContentColor, optional long todayDateBorderColor, optional long dayInSelectionRangeContentColor, optional long dayInSelectionRangeContainerColor, optional long dividerColor, optional androidx.compose.material3.TextFieldColors dateTextFieldColors);
+ method public androidx.compose.material3.DatePickerFormatter dateFormatter(optional String yearSelectionSkeleton, optional String selectedDateSkeleton, optional String selectedDateDescriptionSkeleton);
+ method public androidx.compose.material3.SelectableDates getAllDates();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ method public float getTonalElevation();
+ method public kotlin.ranges.IntRange getYearRange();
+ property public final androidx.compose.material3.SelectableDates AllDates;
+ property public final float TonalElevation;
+ property public final kotlin.ranges.IntRange YearRange;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ field public static final androidx.compose.material3.DatePickerDefaults INSTANCE;
+ field public static final String YearAbbrMonthDaySkeleton = "yMMMd";
+ field public static final String YearMonthSkeleton = "yMMMM";
+ field public static final String YearMonthWeekdayDaySkeleton = "yMMMMEEEEd";
+ }
+
+ public final class DatePickerDialog_androidKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void DatePickerDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, kotlin.jvm.functions.Function0<kotlin.Unit> confirmButton, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dismissButton, optional androidx.compose.ui.graphics.Shape shape, optional float tonalElevation, optional androidx.compose.material3.DatePickerColors colors, optional androidx.compose.ui.window.DialogProperties properties, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public interface DatePickerFormatter {
+ method public String? formatDate(Long? dateMillis, java.util.Locale locale, optional boolean forContentDescription);
+ method public String? formatMonthYear(Long? monthMillis, java.util.Locale locale);
+ }
+
+ public final class DatePickerKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void DatePicker(androidx.compose.material3.DatePickerState state, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.DatePickerFormatter dateFormatter, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? headline, optional boolean showModeToggle, optional androidx.compose.material3.DatePickerColors colors);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static androidx.compose.material3.DatePickerState DatePickerState(java.util.Locale locale, optional Long? initialSelectedDateMillis, optional Long? initialDisplayedMonthMillis, optional kotlin.ranges.IntRange yearRange, optional int initialDisplayMode, optional androidx.compose.material3.SelectableDates selectableDates);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.DatePickerState rememberDatePickerState(optional Long? initialSelectedDateMillis, optional Long? initialDisplayedMonthMillis, optional kotlin.ranges.IntRange yearRange, optional int initialDisplayMode, optional androidx.compose.material3.SelectableDates selectableDates);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public interface DatePickerState {
+ method public int getDisplayMode();
+ method public long getDisplayedMonthMillis();
+ method public androidx.compose.material3.SelectableDates getSelectableDates();
+ method public Long? getSelectedDateMillis();
+ method public kotlin.ranges.IntRange getYearRange();
+ method public void setDisplayMode(int);
+ method public void setDisplayedMonthMillis(long);
+ method public void setSelectedDateMillis(Long?);
+ property public abstract int displayMode;
+ property public abstract long displayedMonthMillis;
+ property public abstract androidx.compose.material3.SelectableDates selectableDates;
+ property public abstract Long? selectedDateMillis;
+ property public abstract kotlin.ranges.IntRange yearRange;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class DateRangePickerDefaults {
+ method @androidx.compose.runtime.Composable public void DateRangePickerHeadline(Long? selectedStartDateMillis, Long? selectedEndDateMillis, int displayMode, androidx.compose.material3.DatePickerFormatter dateFormatter, optional androidx.compose.ui.Modifier modifier);
+ method @androidx.compose.runtime.Composable public void DateRangePickerTitle(int displayMode, optional androidx.compose.ui.Modifier modifier);
+ field public static final androidx.compose.material3.DateRangePickerDefaults INSTANCE;
+ }
+
+ public final class DateRangePickerKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void DateRangePicker(androidx.compose.material3.DateRangePickerState state, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.DatePickerFormatter dateFormatter, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? headline, optional boolean showModeToggle, optional androidx.compose.material3.DatePickerColors colors);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static androidx.compose.material3.DateRangePickerState DateRangePickerState(java.util.Locale locale, optional Long? initialSelectedStartDateMillis, optional Long? initialSelectedEndDateMillis, optional Long? initialDisplayedMonthMillis, optional kotlin.ranges.IntRange yearRange, optional int initialDisplayMode, optional androidx.compose.material3.SelectableDates selectableDates);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.DateRangePickerState rememberDateRangePickerState(optional Long? initialSelectedStartDateMillis, optional Long? initialSelectedEndDateMillis, optional Long? initialDisplayedMonthMillis, optional kotlin.ranges.IntRange yearRange, optional int initialDisplayMode, optional androidx.compose.material3.SelectableDates selectableDates);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public interface DateRangePickerState {
+ method public int getDisplayMode();
+ method public long getDisplayedMonthMillis();
+ method public androidx.compose.material3.SelectableDates getSelectableDates();
+ method public Long? getSelectedEndDateMillis();
+ method public Long? getSelectedStartDateMillis();
+ method public kotlin.ranges.IntRange getYearRange();
+ method public void setDisplayMode(int);
+ method public void setDisplayedMonthMillis(long);
+ method public void setSelection(Long? startDateMillis, Long? endDateMillis);
+ property public abstract int displayMode;
+ property public abstract long displayedMonthMillis;
+ property public abstract androidx.compose.material3.SelectableDates selectableDates;
+ property public abstract Long? selectedEndDateMillis;
+ property public abstract Long? selectedStartDateMillis;
+ property public abstract kotlin.ranges.IntRange yearRange;
+ }
+
+ @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum DismissDirection {
+ method @Deprecated public static androidx.compose.material3.DismissDirection valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method @Deprecated public static androidx.compose.material3.DismissDirection[] values();
+ enum_constant @Deprecated public static final androidx.compose.material3.DismissDirection EndToStart;
+ enum_constant @Deprecated public static final androidx.compose.material3.DismissDirection StartToEnd;
+ }
+
+ @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum DismissValue {
+ method @Deprecated public static androidx.compose.material3.DismissValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method @Deprecated public static androidx.compose.material3.DismissValue[] values();
+ enum_constant @Deprecated public static final androidx.compose.material3.DismissValue Default;
+ enum_constant @Deprecated public static final androidx.compose.material3.DismissValue DismissedToEnd;
+ enum_constant @Deprecated public static final androidx.compose.material3.DismissValue DismissedToStart;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class DisplayMode {
+ field public static final androidx.compose.material3.DisplayMode.Companion Companion;
+ }
+
+ public static final class DisplayMode.Companion {
+ method public int getInput();
+ method public int getPicker();
+ property public final int Input;
+ property public final int Picker;
+ }
+
+ public final class DividerDefaults {
+ method @androidx.compose.runtime.Composable public long getColor();
+ method public float getThickness();
+ property public final float Thickness;
+ property @androidx.compose.runtime.Composable public final long color;
+ field public static final androidx.compose.material3.DividerDefaults INSTANCE;
+ }
+
+ public final class DividerKt {
+ method @Deprecated @androidx.compose.runtime.Composable public static void Divider(optional androidx.compose.ui.Modifier modifier, optional float thickness, optional long color);
+ method @androidx.compose.runtime.Composable public static void HorizontalDivider(optional androidx.compose.ui.Modifier modifier, optional float thickness, optional long color);
+ method @androidx.compose.runtime.Composable public static void VerticalDivider(optional androidx.compose.ui.Modifier modifier, optional float thickness, optional long color);
+ }
+
+ public final class DrawerDefaults {
+ method @androidx.compose.runtime.Composable public long getContainerColor();
+ method public float getDismissibleDrawerElevation();
+ method public float getMaximumDrawerWidth();
+ method public float getModalDrawerElevation();
+ method public float getPermanentDrawerElevation();
+ method @androidx.compose.runtime.Composable public long getScrimColor();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+ property public final float DismissibleDrawerElevation;
+ property public final float MaximumDrawerWidth;
+ property public final float ModalDrawerElevation;
+ property public final float PermanentDrawerElevation;
+ property @androidx.compose.runtime.Composable public final long containerColor;
+ property @androidx.compose.runtime.Composable public final long scrimColor;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+ field public static final androidx.compose.material3.DrawerDefaults INSTANCE;
+ }
+
+ @androidx.compose.runtime.Stable public final class DrawerState {
+ ctor public DrawerState(androidx.compose.material3.DrawerValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.DrawerValue,java.lang.Boolean> confirmStateChange);
+ method @Deprecated public suspend Object? animateTo(androidx.compose.material3.DrawerValue targetValue, androidx.compose.animation.core.AnimationSpec<java.lang.Float> anim, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public suspend Object? close(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public float getCurrentOffset();
+ method public androidx.compose.material3.DrawerValue getCurrentValue();
+ method @Deprecated public androidx.compose.runtime.State<java.lang.Float> getOffset();
+ method public androidx.compose.material3.DrawerValue getTargetValue();
+ method public boolean isAnimationRunning();
+ method public boolean isClosed();
+ method public boolean isOpen();
+ method public suspend Object? open(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public suspend Object? snapTo(androidx.compose.material3.DrawerValue targetValue, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ property public final float currentOffset;
+ property public final androidx.compose.material3.DrawerValue currentValue;
+ property public final boolean isAnimationRunning;
+ property public final boolean isClosed;
+ property public final boolean isOpen;
+ property @Deprecated public final androidx.compose.runtime.State<java.lang.Float> offset;
+ property public final androidx.compose.material3.DrawerValue targetValue;
+ field public static final androidx.compose.material3.DrawerState.Companion Companion;
+ }
+
+ public static final class DrawerState.Companion {
+ method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.DrawerState,androidx.compose.material3.DrawerValue> Saver(kotlin.jvm.functions.Function1<? super androidx.compose.material3.DrawerValue,java.lang.Boolean> confirmStateChange);
+ }
+
+ public enum DrawerValue {
+ method public static androidx.compose.material3.DrawerValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.compose.material3.DrawerValue[] values();
+ enum_constant public static final androidx.compose.material3.DrawerValue Closed;
+ enum_constant public static final androidx.compose.material3.DrawerValue Open;
+ }
+
+ public final class DynamicTonalPaletteKt {
+ method @RequiresApi(android.os.Build.VERSION_CODES.S) public static androidx.compose.material3.ColorScheme dynamicDarkColorScheme(android.content.Context context);
+ method @RequiresApi(android.os.Build.VERSION_CODES.S) public static androidx.compose.material3.ColorScheme dynamicLightColorScheme(android.content.Context context);
+ }
+
+ @SuppressCompatibility @kotlin.RequiresOptIn(message="This material API is experimental and is likely to change or to be removed in" + " the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalMaterial3Api {
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public interface ExposedDropdownMenuBoxScope {
+ method @androidx.compose.runtime.Composable public default void ExposedDropdownMenu(boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.ScrollState scrollState, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method public androidx.compose.ui.Modifier exposedDropdownSize(androidx.compose.ui.Modifier, optional boolean matchTextFieldWidth);
+ method public androidx.compose.ui.Modifier menuAnchor(androidx.compose.ui.Modifier);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class ExposedDropdownMenuDefaults {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void TrailingIcon(boolean expanded);
+ method public androidx.compose.foundation.layout.PaddingValues getItemContentPadding();
+ method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor);
+ method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long containerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long focusedContainerColor, optional long unfocusedContainerColor, optional long disabledContainerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+ method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor);
+ method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long containerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long focusedContainerColor, optional long unfocusedContainerColor, optional long disabledContainerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+ property public final androidx.compose.foundation.layout.PaddingValues ItemContentPadding;
+ field public static final androidx.compose.material3.ExposedDropdownMenuDefaults INSTANCE;
+ }
+
+ public final class ExposedDropdownMenu_androidKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void ExposedDropdownMenuBox(boolean expanded, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onExpandedChange, optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function1<? super androidx.compose.material3.ExposedDropdownMenuBoxScope,kotlin.Unit> content);
+ }
+
+ @kotlin.jvm.JvmInline public final value class FabPosition {
+ field public static final androidx.compose.material3.FabPosition.Companion Companion;
+ }
+
+ public static final class FabPosition.Companion {
+ method public int getCenter();
+ method public int getEnd();
+ method public int getEndOverlay();
+ method public int getStart();
+ property public final int Center;
+ property public final int End;
+ property public final int EndOverlay;
+ property public final int Start;
+ }
+
+ public final class FilterChipDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipColors elevatedFilterChipColors(optional long containerColor, optional long labelColor, optional long iconColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconColor, optional long disabledTrailingIconColor, optional long selectedContainerColor, optional long disabledSelectedContainerColor, optional long selectedLabelColor, optional long selectedLeadingIconColor, optional long selectedTrailingIconColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipElevation elevatedFilterChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke filterChipBorder(boolean enabled, boolean selected, optional long borderColor, optional long selectedBorderColor, optional long disabledBorderColor, optional long disabledSelectedBorderColor, optional float borderWidth, optional float selectedBorderWidth);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipColors filterChipColors(optional long containerColor, optional long labelColor, optional long iconColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconColor, optional long disabledTrailingIconColor, optional long selectedContainerColor, optional long disabledSelectedContainerColor, optional long selectedLabelColor, optional long selectedLeadingIconColor, optional long selectedTrailingIconColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipElevation filterChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+ method public float getHeight();
+ method public float getIconSize();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ property public final float Height;
+ property public final float IconSize;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ field public static final androidx.compose.material3.FilterChipDefaults INSTANCE;
+ }
+
+ public final class FloatingActionButtonDefaults {
+ method public androidx.compose.material3.FloatingActionButtonElevation bottomAppBarFabElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.FloatingActionButtonElevation elevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation);
+ method @androidx.compose.runtime.Composable public long getContainerColor();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getExtendedFabShape();
+ method public float getLargeIconSize();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getLargeShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getSmallShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.FloatingActionButtonElevation loweredElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation);
+ property public final float LargeIconSize;
+ property @androidx.compose.runtime.Composable public final long containerColor;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape extendedFabShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape largeShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape smallShape;
+ field public static final androidx.compose.material3.FloatingActionButtonDefaults INSTANCE;
+ }
+
+ @androidx.compose.runtime.Stable public class FloatingActionButtonElevation {
+ }
+
+ public final class FloatingActionButtonKt {
+ method @androidx.compose.runtime.Composable public static void ExtendedFloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void ExtendedFloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> text, kotlin.jvm.functions.Function0<kotlin.Unit> icon, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean expanded, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable public static void FloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void LargeFloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void SmallFloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ }
+
+ @androidx.compose.runtime.Immutable public final class IconButtonColors {
+ ctor public IconButtonColors(long containerColor, long contentColor, long disabledContainerColor, long disabledContentColor);
+ method public long getContainerColor();
+ method public long getContentColor();
+ method public long getDisabledContainerColor();
+ method public long getDisabledContentColor();
+ property public final long containerColor;
+ property public final long contentColor;
+ property public final long disabledContainerColor;
+ property public final long disabledContentColor;
+ }
+
+ public final class IconButtonDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors filledIconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors filledIconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors filledTonalIconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors filledTonalIconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFilledShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getOutlinedShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors iconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors iconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke outlinedIconButtonBorder(boolean enabled);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors outlinedIconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke? outlinedIconToggleButtonBorder(boolean enabled, boolean checked);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors outlinedIconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape filledShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape outlinedShape;
+ field public static final androidx.compose.material3.IconButtonDefaults INSTANCE;
+ }
+
+ public final class IconButtonKt {
+ method @androidx.compose.runtime.Composable public static void FilledIconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.IconButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void FilledIconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.IconToggleButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void FilledTonalIconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.IconButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void FilledTonalIconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.IconToggleButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.IconButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.IconToggleButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void OutlinedIconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.IconButtonColors colors, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void OutlinedIconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.IconToggleButtonColors colors, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ }
+
+ public final class IconKt {
+ method @androidx.compose.runtime.Composable public static void Icon(androidx.compose.ui.graphics.ImageBitmap bitmap, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional long tint);
+ method @androidx.compose.runtime.Composable public static void Icon(androidx.compose.ui.graphics.painter.Painter painter, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional long tint);
+ method @androidx.compose.runtime.Composable public static void Icon(androidx.compose.ui.graphics.vector.ImageVector imageVector, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional long tint);
+ }
+
+ @androidx.compose.runtime.Immutable public final class IconToggleButtonColors {
+ ctor public IconToggleButtonColors(long containerColor, long contentColor, long disabledContainerColor, long disabledContentColor, long checkedContainerColor, long checkedContentColor);
+ method public long getCheckedContainerColor();
+ method public long getCheckedContentColor();
+ method public long getContainerColor();
+ method public long getContentColor();
+ method public long getDisabledContainerColor();
+ method public long getDisabledContentColor();
+ property public final long checkedContainerColor;
+ property public final long checkedContentColor;
+ property public final long containerColor;
+ property public final long contentColor;
+ property public final long disabledContainerColor;
+ property public final long disabledContentColor;
+ }
+
+ public final class InputChipDefaults {
+ method public float getAvatarSize();
+ method public float getHeight();
+ method public float getIconSize();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke inputChipBorder(boolean enabled, boolean selected, optional long borderColor, optional long selectedBorderColor, optional long disabledBorderColor, optional long disabledSelectedBorderColor, optional float borderWidth, optional float selectedBorderWidth);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipColors inputChipColors(optional long containerColor, optional long labelColor, optional long leadingIconColor, optional long trailingIconColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconColor, optional long disabledTrailingIconColor, optional long selectedContainerColor, optional long disabledSelectedContainerColor, optional long selectedLabelColor, optional long selectedLeadingIconColor, optional long selectedTrailingIconColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipElevation inputChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+ property public final float AvatarSize;
+ property public final float Height;
+ property public final float IconSize;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ field public static final androidx.compose.material3.InputChipDefaults INSTANCE;
+ }
+
+ public final class InteractiveComponentSizeKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> getLocalMinimumInteractiveComponentEnforcement();
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> getLocalMinimumTouchTargetEnforcement();
+ method @androidx.compose.runtime.Stable public static androidx.compose.ui.Modifier minimumInteractiveComponentSize(androidx.compose.ui.Modifier);
+ property @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static final androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> LocalMinimumInteractiveComponentEnforcement;
+ property @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static final androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> LocalMinimumTouchTargetEnforcement;
+ }
+
+ public final class LabelKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void Label(kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional boolean isPersistent, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ }
+
+ @androidx.compose.runtime.Immutable public final class ListItemColors {
+ ctor public ListItemColors(long containerColor, long headlineColor, long leadingIconColor, long overlineColor, long supportingTextColor, long trailingIconColor, long disabledHeadlineColor, long disabledLeadingIconColor, long disabledTrailingIconColor);
+ method public long getContainerColor();
+ method public long getDisabledHeadlineColor();
+ method public long getDisabledLeadingIconColor();
+ method public long getDisabledTrailingIconColor();
+ method public long getHeadlineColor();
+ method public long getLeadingIconColor();
+ method public long getOverlineColor();
+ method public long getSupportingTextColor();
+ method public long getTrailingIconColor();
+ property public final long containerColor;
+ property public final long disabledHeadlineColor;
+ property public final long disabledLeadingIconColor;
+ property public final long disabledTrailingIconColor;
+ property public final long headlineColor;
+ property public final long leadingIconColor;
+ property public final long overlineColor;
+ property public final long supportingTextColor;
+ property public final long trailingIconColor;
+ }
+
+ public final class ListItemDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ListItemColors colors(optional long containerColor, optional long headlineColor, optional long leadingIconColor, optional long overlineColor, optional long supportingColor, optional long trailingIconColor, optional long disabledHeadlineColor, optional long disabledLeadingIconColor, optional long disabledTrailingIconColor);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public long getContainerColor();
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public long getContentColor();
+ method public float getElevation();
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.ui.graphics.Shape getShape();
+ property public final float Elevation;
+ property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final long containerColor;
+ property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final long contentColor;
+ property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.ui.graphics.Shape shape;
+ field public static final androidx.compose.material3.ListItemDefaults INSTANCE;
+ }
+
+ public final class ListItemKt {
+ method @androidx.compose.runtime.Composable public static void ListItem(kotlin.jvm.functions.Function0<kotlin.Unit> headlineContent, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? overlineContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingContent, optional androidx.compose.material3.ListItemColors colors, optional float tonalElevation, optional float shadowElevation);
+ }
+
+ public final class MaterialTheme {
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.material3.ColorScheme getColorScheme();
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.material3.Shapes getShapes();
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.material3.Typography getTypography();
+ property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.material3.ColorScheme colorScheme;
+ property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.material3.Shapes shapes;
+ property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.material3.Typography typography;
+ field public static final androidx.compose.material3.MaterialTheme INSTANCE;
+ }
+
+ public final class MaterialThemeKt {
+ method @androidx.compose.runtime.Composable public static void MaterialTheme(optional androidx.compose.material3.ColorScheme colorScheme, optional androidx.compose.material3.Shapes shapes, optional androidx.compose.material3.Typography typography, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ }
+
+ public final class MenuDefaults {
+ method public androidx.compose.foundation.layout.PaddingValues getDropdownMenuItemContentPadding();
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.MenuItemColors itemColors(optional long textColor, optional long leadingIconColor, optional long trailingIconColor, optional long disabledTextColor, optional long disabledLeadingIconColor, optional long disabledTrailingIconColor);
+ property public final androidx.compose.foundation.layout.PaddingValues DropdownMenuItemContentPadding;
+ field public static final androidx.compose.material3.MenuDefaults INSTANCE;
+ }
+
+ @androidx.compose.runtime.Immutable public final class MenuItemColors {
+ ctor public MenuItemColors(long textColor, long leadingIconColor, long trailingIconColor, long disabledTextColor, long disabledLeadingIconColor, long disabledTrailingIconColor);
+ method public long getDisabledLeadingIconColor();
+ method public long getDisabledTextColor();
+ method public long getDisabledTrailingIconColor();
+ method public long getLeadingIconColor();
+ method public long getTextColor();
+ method public long getTrailingIconColor();
+ property public final long disabledLeadingIconColor;
+ property public final long disabledTextColor;
+ property public final long disabledTrailingIconColor;
+ property public final long leadingIconColor;
+ property public final long textColor;
+ property public final long trailingIconColor;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class ModalBottomSheetDefaults {
+ method public androidx.compose.material3.ModalBottomSheetProperties properties(optional androidx.compose.ui.window.SecureFlagPolicy securePolicy, optional boolean isFocusable, optional boolean shouldDismissOnBackPress);
+ field public static final androidx.compose.material3.ModalBottomSheetDefaults INSTANCE;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class ModalBottomSheetProperties {
+ ctor public ModalBottomSheetProperties(androidx.compose.ui.window.SecureFlagPolicy securePolicy, boolean isFocusable, boolean shouldDismissOnBackPress);
+ method public androidx.compose.ui.window.SecureFlagPolicy getSecurePolicy();
+ method public boolean getShouldDismissOnBackPress();
+ method public boolean isFocusable();
+ property public final boolean isFocusable;
+ property public final androidx.compose.ui.window.SecureFlagPolicy securePolicy;
+ property public final boolean shouldDismissOnBackPress;
+ }
+
+ public final class ModalBottomSheet_androidKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void ModalBottomSheet(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SheetState sheetState, optional float sheetMaxWidth, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional float tonalElevation, optional long scrimColor, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dragHandle, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.ModalBottomSheetProperties properties, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.SheetState rememberModalBottomSheetState(optional boolean skipPartiallyExpanded, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public interface MultiChoiceSegmentedButtonRowScope extends androidx.compose.foundation.layout.RowScope {
+ }
+
+ public final class NavigationBarDefaults {
+ method @androidx.compose.runtime.Composable public long getContainerColor();
+ method public float getElevation();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+ property public final float Elevation;
+ property @androidx.compose.runtime.Composable public final long containerColor;
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+ field public static final androidx.compose.material3.NavigationBarDefaults INSTANCE;
+ }
+
+ @androidx.compose.runtime.Stable public final class NavigationBarItemColors {
+ ctor public NavigationBarItemColors(long selectedIconColor, long selectedTextColor, long selectedIndicatorColor, long unselectedIconColor, long unselectedTextColor, long disabledIconColor, long disabledTextColor);
+ method public long getDisabledIconColor();
+ method public long getDisabledTextColor();
+ method public long getSelectedIconColor();
+ method public long getSelectedIndicatorColor();
+ method public long getSelectedTextColor();
+ method public long getUnselectedIconColor();
+ method public long getUnselectedTextColor();
+ property public final long disabledIconColor;
+ property public final long disabledTextColor;
+ property public final long selectedIconColor;
+ property public final long selectedIndicatorColor;
+ property public final long selectedTextColor;
+ property public final long unselectedIconColor;
+ property public final long unselectedTextColor;
+ }
+
+ public final class NavigationBarItemDefaults {
+ method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationBarItemColors colors(optional long selectedIconColor, optional long selectedTextColor, optional long indicatorColor, optional long unselectedIconColor, optional long unselectedTextColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationBarItemColors colors(optional long selectedIconColor, optional long selectedTextColor, optional long indicatorColor, optional long unselectedIconColor, optional long unselectedTextColor, optional long disabledIconColor, optional long disabledTextColor);
+ field public static final androidx.compose.material3.NavigationBarItemDefaults INSTANCE;
+ }
+
+ public final class NavigationBarKt {
+ method @androidx.compose.runtime.Composable public static void NavigationBar(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void NavigationBarItem(androidx.compose.foundation.layout.RowScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional boolean alwaysShowLabel, optional androidx.compose.material3.NavigationBarItemColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ }
+
+ @androidx.compose.runtime.Stable public interface NavigationDrawerItemColors {
+ method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> badgeColor(boolean selected);
+ method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> containerColor(boolean selected);
+ method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> iconColor(boolean selected);
+ method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> textColor(boolean selected);
+ }
+
+ public final class NavigationDrawerItemDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationDrawerItemColors colors(optional long selectedContainerColor, optional long unselectedContainerColor, optional long selectedIconColor, optional long unselectedIconColor, optional long selectedTextColor, optional long unselectedTextColor, optional long selectedBadgeColor, optional long unselectedBadgeColor);
+ method public androidx.compose.foundation.layout.PaddingValues getItemPadding();
+ property public final androidx.compose.foundation.layout.PaddingValues ItemPadding;
+ field public static final androidx.compose.material3.NavigationDrawerItemDefaults INSTANCE;
+ }
+
+ public final class NavigationDrawerKt {
+ method @androidx.compose.runtime.Composable public static void DismissibleDrawerSheet(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape drawerShape, optional long drawerContainerColor, optional long drawerContentColor, optional float drawerTonalElevation, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void DismissibleNavigationDrawer(kotlin.jvm.functions.Function0<kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.DrawerState drawerState, optional boolean gesturesEnabled, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void ModalDrawerSheet(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape drawerShape, optional long drawerContainerColor, optional long drawerContentColor, optional float drawerTonalElevation, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void ModalNavigationDrawer(kotlin.jvm.functions.Function0<kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.DrawerState drawerState, optional boolean gesturesEnabled, optional long scrimColor, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void NavigationDrawerItem(kotlin.jvm.functions.Function0<kotlin.Unit> label, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? badge, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.NavigationDrawerItemColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable public static void PermanentDrawerSheet(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape drawerShape, optional long drawerContainerColor, optional long drawerContentColor, optional float drawerTonalElevation, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void PermanentNavigationDrawer(kotlin.jvm.functions.Function0<kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static androidx.compose.material3.DrawerState rememberDrawerState(androidx.compose.material3.DrawerValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.DrawerValue,java.lang.Boolean> confirmStateChange);
+ }
+
+ public final class NavigationRailDefaults {
+ method @androidx.compose.runtime.Composable public long getContainerColor();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+ property @androidx.compose.runtime.Composable public final long ContainerColor;
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+ field public static final androidx.compose.material3.NavigationRailDefaults INSTANCE;
+ }
+
+ @androidx.compose.runtime.Stable public final class NavigationRailItemColors {
+ ctor public NavigationRailItemColors(long selectedIconColor, long selectedTextColor, long selectedIndicatorColor, long unselectedIconColor, long unselectedTextColor, long disabledIconColor, long disabledTextColor);
+ method public long getDisabledIconColor();
+ method public long getDisabledTextColor();
+ method public long getSelectedIconColor();
+ method public long getSelectedIndicatorColor();
+ method public long getSelectedTextColor();
+ method public long getUnselectedIconColor();
+ method public long getUnselectedTextColor();
+ property public final long disabledIconColor;
+ property public final long disabledTextColor;
+ property public final long selectedIconColor;
+ property public final long selectedIndicatorColor;
+ property public final long selectedTextColor;
+ property public final long unselectedIconColor;
+ property public final long unselectedTextColor;
+ }
+
+ public final class NavigationRailItemDefaults {
+ method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationRailItemColors colors(optional long selectedIconColor, optional long selectedTextColor, optional long indicatorColor, optional long unselectedIconColor, optional long unselectedTextColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationRailItemColors colors(optional long selectedIconColor, optional long selectedTextColor, optional long indicatorColor, optional long unselectedIconColor, optional long unselectedTextColor, optional long disabledIconColor, optional long disabledTextColor);
+ field public static final androidx.compose.material3.NavigationRailItemDefaults INSTANCE;
+ }
+
+ public final class NavigationRailKt {
+ method @androidx.compose.runtime.Composable public static void NavigationRail(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? header, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void NavigationRailItem(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional boolean alwaysShowLabel, optional androidx.compose.material3.NavigationRailItemColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ }
+
+ @androidx.compose.runtime.Immutable public final class OutlinedTextFieldDefaults {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void ContainerBox(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional androidx.compose.ui.graphics.Shape shape, optional float focusedBorderThickness, optional float unfocusedBorderThickness);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void DecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors colors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long focusedContainerColor, optional long unfocusedContainerColor, optional long disabledContainerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+ method public androidx.compose.foundation.layout.PaddingValues contentPadding(optional float start, optional float top, optional float end, optional float bottom);
+ method public float getFocusedBorderThickness();
+ method public float getMinHeight();
+ method public float getMinWidth();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ method public float getUnfocusedBorderThickness();
+ property public final float FocusedBorderThickness;
+ property public final float MinHeight;
+ property public final float MinWidth;
+ property public final float UnfocusedBorderThickness;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ field public static final androidx.compose.material3.OutlinedTextFieldDefaults INSTANCE;
+ }
+
+ public final class OutlinedTextFieldKt {
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void OutlinedTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+ method @androidx.compose.runtime.Composable public static void OutlinedTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void OutlinedTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+ method @androidx.compose.runtime.Composable public static void OutlinedTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+ }
+
+ @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public interface PlainTooltipState extends androidx.compose.material3.BasicTooltipState {
+ }
+
+ public final class ProgressIndicatorDefaults {
+ method @androidx.compose.runtime.Composable public long getCircularColor();
+ method public int getCircularDeterminateStrokeCap();
+ method public int getCircularIndeterminateStrokeCap();
+ method public float getCircularStrokeWidth();
+ method @androidx.compose.runtime.Composable public long getCircularTrackColor();
+ method @androidx.compose.runtime.Composable public long getLinearColor();
+ method public int getLinearStrokeCap();
+ method @androidx.compose.runtime.Composable public long getLinearTrackColor();
+ method public androidx.compose.animation.core.SpringSpec<java.lang.Float> getProgressAnimationSpec();
+ property public final int CircularDeterminateStrokeCap;
+ property public final int CircularIndeterminateStrokeCap;
+ property public final float CircularStrokeWidth;
+ property public final int LinearStrokeCap;
+ property public final androidx.compose.animation.core.SpringSpec<java.lang.Float> ProgressAnimationSpec;
+ property @androidx.compose.runtime.Composable public final long circularColor;
+ property @androidx.compose.runtime.Composable public final long circularTrackColor;
+ property @androidx.compose.runtime.Composable public final long linearColor;
+ property @androidx.compose.runtime.Composable public final long linearTrackColor;
+ field public static final androidx.compose.material3.ProgressIndicatorDefaults INSTANCE;
+ }
+
+ public final class ProgressIndicatorKt {
+ method @Deprecated @androidx.compose.runtime.Composable public static void CircularProgressIndicator(optional androidx.compose.ui.Modifier modifier, optional long color, optional float strokeWidth);
+ method @androidx.compose.runtime.Composable public static void CircularProgressIndicator(optional androidx.compose.ui.Modifier modifier, optional long color, optional float strokeWidth, optional long trackColor, optional int strokeCap);
+ method @Deprecated @androidx.compose.runtime.Composable public static void CircularProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional float strokeWidth);
+ method @Deprecated @androidx.compose.runtime.Composable public static void CircularProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional float strokeWidth, optional long trackColor, optional int strokeCap);
+ method @androidx.compose.runtime.Composable public static void CircularProgressIndicator(kotlin.jvm.functions.Function0<java.lang.Float> progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional float strokeWidth, optional long trackColor, optional int strokeCap);
+ method @Deprecated @androidx.compose.runtime.Composable public static void LinearProgressIndicator(optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor);
+ method @androidx.compose.runtime.Composable public static void LinearProgressIndicator(optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor, optional int strokeCap);
+ method @Deprecated @androidx.compose.runtime.Composable public static void LinearProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor);
+ method @Deprecated @androidx.compose.runtime.Composable public static void LinearProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor, optional int strokeCap);
+ method @androidx.compose.runtime.Composable public static void LinearProgressIndicator(kotlin.jvm.functions.Function0<java.lang.Float> progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor, optional int strokeCap);
+ }
+
+ @androidx.compose.runtime.Immutable public final class RadioButtonColors {
+ ctor public RadioButtonColors(long selectedColor, long unselectedColor, long disabledSelectedColor, long disabledUnselectedColor);
+ method public long getDisabledSelectedColor();
+ method public long getDisabledUnselectedColor();
+ method public long getSelectedColor();
+ method public long getUnselectedColor();
+ property public final long disabledSelectedColor;
+ property public final long disabledUnselectedColor;
+ property public final long selectedColor;
+ property public final long unselectedColor;
+ }
+
+ public final class RadioButtonDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.RadioButtonColors colors(optional long selectedColor, optional long unselectedColor, optional long disabledSelectedColor, optional long disabledUnselectedColor);
+ field public static final androidx.compose.material3.RadioButtonDefaults INSTANCE;
+ }
+
+ public final class RadioButtonKt {
+ method @androidx.compose.runtime.Composable public static void RadioButton(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit>? onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.RadioButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class RangeSliderState {
+ ctor public RangeSliderState(optional float activeRangeStart, optional float activeRangeEnd, optional @IntRange(from=0L) int steps, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange);
+ method public float getActiveRangeEnd();
+ method public float getActiveRangeStart();
+ method public kotlin.jvm.functions.Function0<kotlin.Unit>? getOnValueChangeFinished();
+ method public int getSteps();
+ method public kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> getValueRange();
+ method public void setActiveRangeEnd(float);
+ method public void setActiveRangeStart(float);
+ property public final float activeRangeEnd;
+ property public final float activeRangeStart;
+ property public final kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished;
+ property public final int steps;
+ property public final kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable @androidx.compose.runtime.Stable public final class RichTooltipColors {
+ ctor public RichTooltipColors(long containerColor, long contentColor, long titleContentColor, long actionContentColor);
+ method public long getActionContentColor();
+ method public long getContainerColor();
+ method public long getContentColor();
+ method public long getTitleContentColor();
+ property public final long actionContentColor;
+ property public final long containerColor;
+ property public final long contentColor;
+ property public final long titleContentColor;
+ }
+
+ @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public interface RichTooltipState extends androidx.compose.material3.BasicTooltipState {
+ }
+
+ public final class ScaffoldDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getContentWindowInsets();
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets contentWindowInsets;
+ field public static final androidx.compose.material3.ScaffoldDefaults INSTANCE;
+ }
+
+ public final class ScaffoldKt {
+ method @androidx.compose.runtime.Composable public static void Scaffold(optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> topBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> bottomBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit> floatingActionButton, optional int floatingActionButtonPosition, optional long containerColor, optional long contentColor, optional androidx.compose.foundation.layout.WindowInsets contentWindowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static boolean getScaffoldSubcomposeInMeasureFix();
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static void setScaffoldSubcomposeInMeasureFix(boolean);
+ property @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static final boolean ScaffoldSubcomposeInMeasureFix;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class SearchBarColors {
+ method public long getContainerColor();
+ method public long getDividerColor();
+ method public androidx.compose.material3.TextFieldColors getInputFieldColors();
+ property public final long containerColor;
+ property public final long dividerColor;
+ property public final androidx.compose.material3.TextFieldColors inputFieldColors;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class SearchBarDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.SearchBarColors colors(optional long containerColor, optional long dividerColor, optional androidx.compose.material3.TextFieldColors inputFieldColors);
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getDockedShape();
+ method @Deprecated public float getElevation();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFullScreenShape();
+ method public float getInputFieldHeight();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getInputFieldShape();
+ method public float getShadowElevation();
+ method public float getTonalElevation();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+ method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors inputFieldColors(optional long textColor, optional long disabledTextColor, optional long cursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long placeholderColor, optional long disabledPlaceholderColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors inputFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long cursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor);
+ property @Deprecated public final float Elevation;
+ property public final float InputFieldHeight;
+ property public final float ShadowElevation;
+ property public final float TonalElevation;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape dockedShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape fullScreenShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape inputFieldShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+ field public static final androidx.compose.material3.SearchBarDefaults INSTANCE;
+ }
+
+ public final class SearchBar_androidKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void DockedSearchBar(String query, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onQueryChange, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onSearch, boolean active, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onActiveChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SearchBarColors colors, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SearchBar(String query, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onQueryChange, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onSearch, boolean active, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onActiveChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SearchBarColors colors, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class SegmentedButtonColors {
+ ctor public SegmentedButtonColors(long activeContainerColor, long activeContentColor, long activeBorderColor, long inactiveContainerColor, long inactiveContentColor, long inactiveBorderColor, long disabledActiveContainerColor, long disabledActiveContentColor, long disabledActiveBorderColor, long disabledInactiveContainerColor, long disabledInactiveContentColor, long disabledInactiveBorderColor);
+ method public long getActiveBorderColor();
+ method public long getActiveContainerColor();
+ method public long getActiveContentColor();
+ method public long getDisabledActiveBorderColor();
+ method public long getDisabledActiveContainerColor();
+ method public long getDisabledActiveContentColor();
+ method public long getDisabledInactiveBorderColor();
+ method public long getDisabledInactiveContainerColor();
+ method public long getDisabledInactiveContentColor();
+ method public long getInactiveBorderColor();
+ method public long getInactiveContainerColor();
+ method public long getInactiveContentColor();
+ property public final long activeBorderColor;
+ property public final long activeContainerColor;
+ property public final long activeContentColor;
+ property public final long disabledActiveBorderColor;
+ property public final long disabledActiveContainerColor;
+ property public final long disabledActiveContentColor;
+ property public final long disabledInactiveBorderColor;
+ property public final long disabledInactiveContainerColor;
+ property public final long disabledInactiveContentColor;
+ property public final long inactiveBorderColor;
+ property public final long inactiveContainerColor;
+ property public final long inactiveContentColor;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class SegmentedButtonDefaults {
+ method @androidx.compose.runtime.Composable public void ActiveIcon();
+ method @androidx.compose.runtime.Composable public void Icon(boolean active, optional kotlin.jvm.functions.Function0<kotlin.Unit> activeContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? inactiveContent);
+ method public androidx.compose.foundation.BorderStroke borderStroke(long color, optional float width);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.SegmentedButtonColors colors(optional long activeContainerColor, optional long activeContentColor, optional long activeBorderColor, optional long inactiveContainerColor, optional long inactiveContentColor, optional long inactiveBorderColor, optional long disabledActiveContainerColor, optional long disabledActiveContentColor, optional long disabledActiveBorderColor, optional long disabledInactiveContainerColor, optional long disabledInactiveContentColor, optional long disabledInactiveBorderColor);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.foundation.shape.CornerBasedShape getBaseShape();
+ method public float getBorderWidth();
+ method public float getIconSize();
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.ui.graphics.Shape itemShape(int index, int count, optional androidx.compose.foundation.shape.CornerBasedShape baseShape);
+ property public final float BorderWidth;
+ property public final float IconSize;
+ property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.foundation.shape.CornerBasedShape baseShape;
+ field public static final androidx.compose.material3.SegmentedButtonDefaults INSTANCE;
+ }
+
+ public final class SegmentedButtonKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void MultiChoiceSegmentedButtonRow(optional androidx.compose.ui.Modifier modifier, optional float space, kotlin.jvm.functions.Function1<? super androidx.compose.material3.MultiChoiceSegmentedButtonRowScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SegmentedButton(androidx.compose.material3.MultiChoiceSegmentedButtonRowScope, boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SegmentedButtonColors colors, optional androidx.compose.foundation.BorderStroke border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> icon, kotlin.jvm.functions.Function0<kotlin.Unit> label);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SegmentedButton(androidx.compose.material3.SingleChoiceSegmentedButtonRowScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SegmentedButtonColors colors, optional androidx.compose.foundation.BorderStroke border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> icon, kotlin.jvm.functions.Function0<kotlin.Unit> label);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SingleChoiceSegmentedButtonRow(optional androidx.compose.ui.Modifier modifier, optional float space, kotlin.jvm.functions.Function1<? super androidx.compose.material3.SingleChoiceSegmentedButtonRowScope,kotlin.Unit> content);
+ }
+
+ @androidx.compose.runtime.Immutable public final class SelectableChipColors {
+ ctor public SelectableChipColors(long containerColor, long labelColor, long leadingIconColor, long trailingIconColor, long disabledContainerColor, long disabledLabelColor, long disabledLeadingIconColor, long disabledTrailingIconColor, long selectedContainerColor, long disabledSelectedContainerColor, long selectedLabelColor, long selectedLeadingIconColor, long selectedTrailingIconColor);
+ }
+
+ @androidx.compose.runtime.Immutable public final class SelectableChipElevation {
+ ctor public SelectableChipElevation(float elevation, float pressedElevation, float focusedElevation, float hoveredElevation, float draggedElevation, float disabledElevation);
+ method public float getDisabledElevation();
+ method public float getDraggedElevation();
+ method public float getElevation();
+ method public float getFocusedElevation();
+ method public float getHoveredElevation();
+ method public float getPressedElevation();
+ property public final float disabledElevation;
+ property public final float draggedElevation;
+ property public final float elevation;
+ property public final float focusedElevation;
+ property public final float hoveredElevation;
+ property public final float pressedElevation;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public interface SelectableDates {
+ method public default boolean isSelectableDate(long utcTimeMillis);
+ method public default boolean isSelectableYear(int year);
+ }
+
+ public final class ShapeDefaults {
+ method public androidx.compose.foundation.shape.CornerBasedShape getExtraLarge();
+ method public androidx.compose.foundation.shape.CornerBasedShape getExtraSmall();
+ method public androidx.compose.foundation.shape.CornerBasedShape getLarge();
+ method public androidx.compose.foundation.shape.CornerBasedShape getMedium();
+ method public androidx.compose.foundation.shape.CornerBasedShape getSmall();
+ property public final androidx.compose.foundation.shape.CornerBasedShape ExtraLarge;
+ property public final androidx.compose.foundation.shape.CornerBasedShape ExtraSmall;
+ property public final androidx.compose.foundation.shape.CornerBasedShape Large;
+ property public final androidx.compose.foundation.shape.CornerBasedShape Medium;
+ property public final androidx.compose.foundation.shape.CornerBasedShape Small;
+ field public static final androidx.compose.material3.ShapeDefaults INSTANCE;
+ }
+
+ @androidx.compose.runtime.Immutable public final class Shapes {
+ ctor public Shapes(optional androidx.compose.foundation.shape.CornerBasedShape extraSmall, optional androidx.compose.foundation.shape.CornerBasedShape small, optional androidx.compose.foundation.shape.CornerBasedShape medium, optional androidx.compose.foundation.shape.CornerBasedShape large, optional androidx.compose.foundation.shape.CornerBasedShape extraLarge);
+ method public androidx.compose.material3.Shapes copy(optional androidx.compose.foundation.shape.CornerBasedShape extraSmall, optional androidx.compose.foundation.shape.CornerBasedShape small, optional androidx.compose.foundation.shape.CornerBasedShape medium, optional androidx.compose.foundation.shape.CornerBasedShape large, optional androidx.compose.foundation.shape.CornerBasedShape extraLarge);
+ method public androidx.compose.foundation.shape.CornerBasedShape getExtraLarge();
+ method public androidx.compose.foundation.shape.CornerBasedShape getExtraSmall();
+ method public androidx.compose.foundation.shape.CornerBasedShape getLarge();
+ method public androidx.compose.foundation.shape.CornerBasedShape getMedium();
+ method public androidx.compose.foundation.shape.CornerBasedShape getSmall();
+ property public final androidx.compose.foundation.shape.CornerBasedShape extraLarge;
+ property public final androidx.compose.foundation.shape.CornerBasedShape extraSmall;
+ property public final androidx.compose.foundation.shape.CornerBasedShape large;
+ property public final androidx.compose.foundation.shape.CornerBasedShape medium;
+ property public final androidx.compose.foundation.shape.CornerBasedShape small;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class SheetState {
+ ctor @Deprecated public SheetState(boolean skipPartiallyExpanded, optional androidx.compose.material3.SheetValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange, optional boolean skipHiddenState);
+ ctor @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public SheetState(boolean skipPartiallyExpanded, androidx.compose.ui.unit.Density density, optional androidx.compose.material3.SheetValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange, optional boolean skipHiddenState);
+ method public suspend Object? expand(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public androidx.compose.material3.SheetValue getCurrentValue();
+ method public boolean getHasExpandedState();
+ method public boolean getHasPartiallyExpandedState();
+ method public androidx.compose.material3.SheetValue getTargetValue();
+ method public suspend Object? hide(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public boolean isVisible();
+ method public suspend Object? partialExpand(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public float requireOffset();
+ method public suspend Object? show(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ property public final androidx.compose.material3.SheetValue currentValue;
+ property public final boolean hasExpandedState;
+ property public final boolean hasPartiallyExpandedState;
+ property public final boolean isVisible;
+ property public final androidx.compose.material3.SheetValue targetValue;
+ field public static final androidx.compose.material3.SheetState.Companion Companion;
+ }
+
+ public static final class SheetState.Companion {
+ method @Deprecated public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.SheetState,androidx.compose.material3.SheetValue> Saver(boolean skipPartiallyExpanded, kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange);
+ method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.SheetState,androidx.compose.material3.SheetValue> Saver(boolean skipPartiallyExpanded, kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange, androidx.compose.ui.unit.Density density);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum SheetValue {
+ method public static androidx.compose.material3.SheetValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.compose.material3.SheetValue[] values();
+ enum_constant public static final androidx.compose.material3.SheetValue Expanded;
+ enum_constant public static final androidx.compose.material3.SheetValue Hidden;
+ enum_constant public static final androidx.compose.material3.SheetValue PartiallyExpanded;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public interface SingleChoiceSegmentedButtonRowScope extends androidx.compose.foundation.layout.RowScope {
+ }
+
+ @androidx.compose.runtime.Immutable public final class SliderColors {
+ ctor public SliderColors(long thumbColor, long activeTrackColor, long activeTickColor, long inactiveTrackColor, long inactiveTickColor, long disabledThumbColor, long disabledActiveTrackColor, long disabledActiveTickColor, long disabledInactiveTrackColor, long disabledInactiveTickColor);
+ method public long getActiveTickColor();
+ method public long getActiveTrackColor();
+ method public long getDisabledActiveTickColor();
+ method public long getDisabledActiveTrackColor();
+ method public long getDisabledInactiveTickColor();
+ method public long getDisabledInactiveTrackColor();
+ method public long getDisabledThumbColor();
+ method public long getInactiveTickColor();
+ method public long getInactiveTrackColor();
+ method public long getThumbColor();
+ property public final long activeTickColor;
+ property public final long activeTrackColor;
+ property public final long disabledActiveTickColor;
+ property public final long disabledActiveTrackColor;
+ property public final long disabledInactiveTickColor;
+ property public final long disabledInactiveTrackColor;
+ property public final long disabledThumbColor;
+ property public final long inactiveTickColor;
+ property public final long inactiveTrackColor;
+ property public final long thumbColor;
+ }
+
+ @androidx.compose.runtime.Stable public final class SliderDefaults {
+ method @androidx.compose.runtime.Composable public void Thumb(androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SliderColors colors, optional boolean enabled, optional long thumbSize);
+ method @androidx.compose.runtime.Composable public void Track(androidx.compose.material3.RangeSliderState rangeSliderState, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SliderColors colors, optional boolean enabled);
+ method @Deprecated @androidx.compose.runtime.Composable public void Track(androidx.compose.material3.SliderPositions sliderPositions, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SliderColors colors, optional boolean enabled);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void Track(androidx.compose.material3.SliderState sliderState, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SliderColors colors, optional boolean enabled);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.SliderColors colors(optional long thumbColor, optional long activeTrackColor, optional long activeTickColor, optional long inactiveTrackColor, optional long inactiveTickColor, optional long disabledThumbColor, optional long disabledActiveTrackColor, optional long disabledActiveTickColor, optional long disabledInactiveTrackColor, optional long disabledInactiveTickColor);
+ field public static final androidx.compose.material3.SliderDefaults INSTANCE;
+ }
+
+ public final class SliderKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void RangeSlider(androidx.compose.material3.RangeSliderState state, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SliderColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource startInteractionSource, optional androidx.compose.foundation.interaction.MutableInteractionSource endInteractionSource, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.RangeSliderState,kotlin.Unit> startThumb, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.RangeSliderState,kotlin.Unit> endThumb, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.RangeSliderState,kotlin.Unit> track);
+ method @androidx.compose.runtime.Composable public static void RangeSlider(kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> value, kotlin.jvm.functions.Function1<? super kotlin.ranges.ClosedFloatingPointRange<java.lang.Float>,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional @IntRange(from=0L) int steps, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.material3.SliderColors colors);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void RangeSlider(kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> value, kotlin.jvm.functions.Function1<? super kotlin.ranges.ClosedFloatingPointRange<java.lang.Float>,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.material3.SliderColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource startInteractionSource, optional androidx.compose.foundation.interaction.MutableInteractionSource endInteractionSource, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.RangeSliderState,kotlin.Unit> startThumb, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.RangeSliderState,kotlin.Unit> endThumb, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.RangeSliderState,kotlin.Unit> track, optional @IntRange(from=0L) int steps);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void Slider(androidx.compose.material3.SliderState state, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SliderColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SliderState,kotlin.Unit> thumb, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SliderState,kotlin.Unit> track);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void Slider(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.material3.SliderColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional @IntRange(from=0L) int steps, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SliderState,kotlin.Unit> thumb, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SliderState,kotlin.Unit> track, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange);
+ method @androidx.compose.runtime.Composable public static void Slider(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional @IntRange(from=0L) int steps, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.material3.SliderColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ }
+
+ @Deprecated @androidx.compose.runtime.Stable public final class SliderPositions {
+ ctor @Deprecated public SliderPositions(optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> initialActiveRange, optional float[] initialTickFractions);
+ method @Deprecated public kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> getActiveRange();
+ method @Deprecated public float[] getTickFractions();
+ property @Deprecated public final kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> activeRange;
+ property @Deprecated public final float[] tickFractions;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class SliderState implements androidx.compose.foundation.gestures.DraggableState {
+ ctor public SliderState(optional float value, optional @IntRange(from=0L) int steps, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange);
+ method public void dispatchRawDelta(float delta);
+ method public suspend Object? drag(androidx.compose.foundation.MutatePriority dragPriority, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.gestures.DragScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public kotlin.jvm.functions.Function0<kotlin.Unit>? getOnValueChangeFinished();
+ method public int getSteps();
+ method public float getValue();
+ method public kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> getValueRange();
+ method public void setValue(float);
+ property public final kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished;
+ property public final int steps;
+ property public final float value;
+ property public final kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange;
+ }
+
+ @androidx.compose.runtime.Stable public interface SnackbarData {
+ method public void dismiss();
+ method public androidx.compose.material3.SnackbarVisuals getVisuals();
+ method public void performAction();
+ property public abstract androidx.compose.material3.SnackbarVisuals visuals;
+ }
+
+ public final class SnackbarDefaults {
+ method @androidx.compose.runtime.Composable public long getActionColor();
+ method @androidx.compose.runtime.Composable public long getActionContentColor();
+ method @androidx.compose.runtime.Composable public long getColor();
+ method @androidx.compose.runtime.Composable public long getContentColor();
+ method @androidx.compose.runtime.Composable public long getDismissActionContentColor();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ property @androidx.compose.runtime.Composable public final long actionColor;
+ property @androidx.compose.runtime.Composable public final long actionContentColor;
+ property @androidx.compose.runtime.Composable public final long color;
+ property @androidx.compose.runtime.Composable public final long contentColor;
+ property @androidx.compose.runtime.Composable public final long dismissActionContentColor;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ field public static final androidx.compose.material3.SnackbarDefaults INSTANCE;
+ }
+
+ public enum SnackbarDuration {
+ method public static androidx.compose.material3.SnackbarDuration valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.compose.material3.SnackbarDuration[] values();
+ enum_constant public static final androidx.compose.material3.SnackbarDuration Indefinite;
+ enum_constant public static final androidx.compose.material3.SnackbarDuration Long;
+ enum_constant public static final androidx.compose.material3.SnackbarDuration Short;
+ }
+
+ public final class SnackbarHostKt {
+ method @androidx.compose.runtime.Composable public static void SnackbarHost(androidx.compose.material3.SnackbarHostState hostState, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SnackbarData,kotlin.Unit> snackbar);
+ }
+
+ @androidx.compose.runtime.Stable public final class SnackbarHostState {
+ ctor public SnackbarHostState();
+ method public androidx.compose.material3.SnackbarData? getCurrentSnackbarData();
+ method public suspend Object? showSnackbar(androidx.compose.material3.SnackbarVisuals visuals, kotlin.coroutines.Continuation<? super androidx.compose.material3.SnackbarResult>);
+ method public suspend Object? showSnackbar(String message, optional String? actionLabel, optional boolean withDismissAction, optional androidx.compose.material3.SnackbarDuration duration, kotlin.coroutines.Continuation<? super androidx.compose.material3.SnackbarResult>);
+ property public final androidx.compose.material3.SnackbarData? currentSnackbarData;
+ }
+
+ public final class SnackbarKt {
+ method @androidx.compose.runtime.Composable public static void Snackbar(androidx.compose.material3.SnackbarData snackbarData, optional androidx.compose.ui.Modifier modifier, optional boolean actionOnNewLine, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional long actionColor, optional long actionContentColor, optional long dismissActionContentColor);
+ method @androidx.compose.runtime.Composable public static void Snackbar(optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? action, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dismissAction, optional boolean actionOnNewLine, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional long actionContentColor, optional long dismissActionContentColor, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ }
+
+ public enum SnackbarResult {
+ method public static androidx.compose.material3.SnackbarResult valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.compose.material3.SnackbarResult[] values();
+ enum_constant public static final androidx.compose.material3.SnackbarResult ActionPerformed;
+ enum_constant public static final androidx.compose.material3.SnackbarResult Dismissed;
+ }
+
+ @androidx.compose.runtime.Stable public interface SnackbarVisuals {
+ method public String? getActionLabel();
+ method public androidx.compose.material3.SnackbarDuration getDuration();
+ method public String getMessage();
+ method public boolean getWithDismissAction();
+ property public abstract String? actionLabel;
+ property public abstract androidx.compose.material3.SnackbarDuration duration;
+ property public abstract String message;
+ property public abstract boolean withDismissAction;
+ }
+
+ public final class SuggestionChipDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors elevatedSuggestionChipColors(optional long containerColor, optional long labelColor, optional long iconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledIconContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation elevatedSuggestionChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+ method public float getHeight();
+ method public float getIconSize();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke suggestionChipBorder(boolean enabled, optional long borderColor, optional long disabledBorderColor, optional float borderWidth);
+ method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.ChipBorder suggestionChipBorder(optional long borderColor, optional long disabledBorderColor, optional float borderWidth);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors suggestionChipColors(optional long containerColor, optional long labelColor, optional long iconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledIconContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation suggestionChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+ property public final float Height;
+ property public final float IconSize;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ field public static final androidx.compose.material3.SuggestionChipDefaults INSTANCE;
+ }
+
+ public final class SurfaceKt {
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long color, optional long contentColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional long color, optional long contentColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional long color, optional long contentColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional long color, optional long contentColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.unit.Dp> getLocalAbsoluteTonalElevation();
+ property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.unit.Dp> LocalAbsoluteTonalElevation;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class SwipeToDismissBoxDefaults {
+ method @androidx.compose.runtime.Composable public kotlin.jvm.functions.Function1<java.lang.Float,java.lang.Float> getPositionalThreshold();
+ property @androidx.compose.runtime.Composable public final kotlin.jvm.functions.Function1<java.lang.Float,java.lang.Float> positionalThreshold;
+ field public static final androidx.compose.material3.SwipeToDismissBoxDefaults INSTANCE;
+ }
+
+ public final class SwipeToDismissBoxKt {
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismiss(androidx.compose.material3.SwipeToDismissState state, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> background, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> dismissContent, optional androidx.compose.ui.Modifier modifier, optional java.util.Set<? extends androidx.compose.material3.SwipeToDismissValue> directions);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismissBox(androidx.compose.material3.SwipeToDismissState state, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> backgroundContent, optional androidx.compose.ui.Modifier modifier, optional boolean enableDismissFromStartToEnd, optional boolean enableDismissFromEndToStart, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.SwipeToDismissState rememberSwipeToDismissState(optional androidx.compose.material3.SwipeToDismissValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SwipeToDismissValue,java.lang.Boolean> confirmValueChange, optional kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class SwipeToDismissState {
+ ctor public SwipeToDismissState(androidx.compose.material3.SwipeToDismissValue initialValue, androidx.compose.ui.unit.Density density, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SwipeToDismissValue,java.lang.Boolean> confirmValueChange, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold);
+ method public suspend Object? dismiss(androidx.compose.material3.SwipeToDismissValue direction, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public androidx.compose.material3.SwipeToDismissValue getCurrentValue();
+ method public androidx.compose.material3.SwipeToDismissValue getDismissDirection();
+ method @FloatRange(from=0.0, to=1.0) public float getProgress();
+ method public androidx.compose.material3.SwipeToDismissValue getTargetValue();
+ method @Deprecated public boolean isDismissed(androidx.compose.material3.DismissDirection direction);
+ method public float requireOffset();
+ method public suspend Object? reset(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public suspend Object? snapTo(androidx.compose.material3.SwipeToDismissValue targetValue, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ property public final androidx.compose.material3.SwipeToDismissValue currentValue;
+ property public final androidx.compose.material3.SwipeToDismissValue dismissDirection;
+ property @FloatRange(from=0.0, to=1.0) public final float progress;
+ property public final androidx.compose.material3.SwipeToDismissValue targetValue;
+ field public static final androidx.compose.material3.SwipeToDismissState.Companion Companion;
+ }
+
+ public static final class SwipeToDismissState.Companion {
+ method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.SwipeToDismissState,androidx.compose.material3.SwipeToDismissValue> Saver(kotlin.jvm.functions.Function1<? super androidx.compose.material3.SwipeToDismissValue,java.lang.Boolean> confirmValueChange, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold, androidx.compose.ui.unit.Density density);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum SwipeToDismissValue {
+ method public static androidx.compose.material3.SwipeToDismissValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.compose.material3.SwipeToDismissValue[] values();
+ enum_constant public static final androidx.compose.material3.SwipeToDismissValue EndToStart;
+ enum_constant public static final androidx.compose.material3.SwipeToDismissValue Settled;
+ enum_constant public static final androidx.compose.material3.SwipeToDismissValue StartToEnd;
+ }
+
+ @androidx.compose.runtime.Immutable public final class SwitchColors {
+ ctor public SwitchColors(long checkedThumbColor, long checkedTrackColor, long checkedBorderColor, long checkedIconColor, long uncheckedThumbColor, long uncheckedTrackColor, long uncheckedBorderColor, long uncheckedIconColor, long disabledCheckedThumbColor, long disabledCheckedTrackColor, long disabledCheckedBorderColor, long disabledCheckedIconColor, long disabledUncheckedThumbColor, long disabledUncheckedTrackColor, long disabledUncheckedBorderColor, long disabledUncheckedIconColor);
+ method public long getCheckedBorderColor();
+ method public long getCheckedIconColor();
+ method public long getCheckedThumbColor();
+ method public long getCheckedTrackColor();
+ method public long getDisabledCheckedBorderColor();
+ method public long getDisabledCheckedIconColor();
+ method public long getDisabledCheckedThumbColor();
+ method public long getDisabledCheckedTrackColor();
+ method public long getDisabledUncheckedBorderColor();
+ method public long getDisabledUncheckedIconColor();
+ method public long getDisabledUncheckedThumbColor();
+ method public long getDisabledUncheckedTrackColor();
+ method public long getUncheckedBorderColor();
+ method public long getUncheckedIconColor();
+ method public long getUncheckedThumbColor();
+ method public long getUncheckedTrackColor();
+ property public final long checkedBorderColor;
+ property public final long checkedIconColor;
+ property public final long checkedThumbColor;
+ property public final long checkedTrackColor;
+ property public final long disabledCheckedBorderColor;
+ property public final long disabledCheckedIconColor;
+ property public final long disabledCheckedThumbColor;
+ property public final long disabledCheckedTrackColor;
+ property public final long disabledUncheckedBorderColor;
+ property public final long disabledUncheckedIconColor;
+ property public final long disabledUncheckedThumbColor;
+ property public final long disabledUncheckedTrackColor;
+ property public final long uncheckedBorderColor;
+ property public final long uncheckedIconColor;
+ property public final long uncheckedThumbColor;
+ property public final long uncheckedTrackColor;
+ }
+
+ public final class SwitchDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.SwitchColors colors(optional long checkedThumbColor, optional long checkedTrackColor, optional long checkedBorderColor, optional long checkedIconColor, optional long uncheckedThumbColor, optional long uncheckedTrackColor, optional long uncheckedBorderColor, optional long uncheckedIconColor, optional long disabledCheckedThumbColor, optional long disabledCheckedTrackColor, optional long disabledCheckedBorderColor, optional long disabledCheckedIconColor, optional long disabledUncheckedThumbColor, optional long disabledUncheckedTrackColor, optional long disabledUncheckedBorderColor, optional long disabledUncheckedIconColor);
+ method public float getIconSize();
+ property public final float IconSize;
+ field public static final androidx.compose.material3.SwitchDefaults INSTANCE;
+ }
+
+ public final class SwitchKt {
+ method @androidx.compose.runtime.Composable public static void Switch(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit>? onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? thumbContent, optional boolean enabled, optional androidx.compose.material3.SwitchColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ }
+
+ public interface TabIndicatorScope {
+ method public androidx.compose.ui.Modifier tabIndicatorLayout(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function4<? super androidx.compose.ui.layout.MeasureScope,? super androidx.compose.ui.layout.Measurable,? super androidx.compose.ui.unit.Constraints,? super java.util.List<androidx.compose.material3.TabPosition>,? extends androidx.compose.ui.layout.MeasureResult> measure);
+ method public androidx.compose.ui.Modifier tabIndicatorOffset(androidx.compose.ui.Modifier, int selectedTabIndex, optional boolean matchContentSize);
+ }
+
+ public final class TabKt {
+ method @androidx.compose.runtime.Composable public static void LeadingIconTab(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> text, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional long selectedContentColor, optional long unselectedContentColor, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable public static void Tab(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional long selectedContentColor, optional long unselectedContentColor, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable public static void Tab(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional long selectedContentColor, optional long unselectedContentColor, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ }
+
+ @androidx.compose.runtime.Immutable public final class TabPosition {
+ method public float getContentWidth();
+ method public float getLeft();
+ method public float getRight();
+ method public float getWidth();
+ property public final float contentWidth;
+ property public final float left;
+ property public final float right;
+ property public final float width;
+ }
+
+ public final class TabRowDefaults {
+ method @Deprecated @androidx.compose.runtime.Composable public void Indicator(optional androidx.compose.ui.Modifier modifier, optional float height, optional long color);
+ method @androidx.compose.runtime.Composable public void PrimaryIndicator(optional androidx.compose.ui.Modifier modifier, optional float width, optional float height, optional long color, optional androidx.compose.ui.graphics.Shape shape);
+ method @androidx.compose.runtime.Composable public void SecondaryIndicator(optional androidx.compose.ui.Modifier modifier, optional float height, optional long color);
+ method @Deprecated @androidx.compose.runtime.Composable public long getContainerColor();
+ method @Deprecated @androidx.compose.runtime.Composable public long getContentColor();
+ method @androidx.compose.runtime.Composable public long getPrimaryContainerColor();
+ method @androidx.compose.runtime.Composable public long getPrimaryContentColor();
+ method public float getScrollableTabRowEdgeStartPadding();
+ method @androidx.compose.runtime.Composable public long getSecondaryContainerColor();
+ method @androidx.compose.runtime.Composable public long getSecondaryContentColor();
+ method public androidx.compose.ui.Modifier tabIndicatorOffset(androidx.compose.ui.Modifier, androidx.compose.material3.TabPosition currentTabPosition);
+ property public final float ScrollableTabRowEdgeStartPadding;
+ property @Deprecated @androidx.compose.runtime.Composable public final long containerColor;
+ property @Deprecated @androidx.compose.runtime.Composable public final long contentColor;
+ property @androidx.compose.runtime.Composable public final long primaryContainerColor;
+ property @androidx.compose.runtime.Composable public final long primaryContentColor;
+ property @androidx.compose.runtime.Composable public final long secondaryContainerColor;
+ property @androidx.compose.runtime.Composable public final long secondaryContentColor;
+ field public static final androidx.compose.material3.TabRowDefaults INSTANCE;
+ }
+
+ public final class TabRowKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void PrimaryScrollableTabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.ScrollState scrollState, optional long containerColor, optional long contentColor, optional float edgePadding, optional kotlin.jvm.functions.Function1<? super java.util.List<androidx.compose.material3.TabPosition>,kotlin.Unit> indicator, optional kotlin.jvm.functions.Function0<kotlin.Unit> divider, kotlin.jvm.functions.Function0<kotlin.Unit> tabs);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void PrimaryTabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.TabIndicatorScope,kotlin.Unit> indicator, optional kotlin.jvm.functions.Function0<kotlin.Unit> divider, kotlin.jvm.functions.Function0<kotlin.Unit> tabs);
+ method @androidx.compose.runtime.Composable public static void ScrollableTabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional float edgePadding, optional kotlin.jvm.functions.Function1<? super java.util.List<androidx.compose.material3.TabPosition>,kotlin.Unit> indicator, optional kotlin.jvm.functions.Function0<kotlin.Unit> divider, kotlin.jvm.functions.Function0<kotlin.Unit> tabs);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SecondaryScrollableTabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.ScrollState scrollState, optional long containerColor, optional long contentColor, optional float edgePadding, optional kotlin.jvm.functions.Function1<? super java.util.List<androidx.compose.material3.TabPosition>,kotlin.Unit> indicator, optional kotlin.jvm.functions.Function0<kotlin.Unit> divider, kotlin.jvm.functions.Function0<kotlin.Unit> tabs);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SecondaryTabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.TabIndicatorScope,kotlin.Unit> indicator, optional kotlin.jvm.functions.Function0<kotlin.Unit> divider, kotlin.jvm.functions.Function0<kotlin.Unit> tabs);
+ method @androidx.compose.runtime.Composable public static void TabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function1<? super java.util.List<androidx.compose.material3.TabPosition>,kotlin.Unit> indicator, optional kotlin.jvm.functions.Function0<kotlin.Unit> divider, kotlin.jvm.functions.Function0<kotlin.Unit> tabs);
+ }
+
+ @androidx.compose.runtime.Immutable public final class TextFieldColors {
+ ctor public TextFieldColors(long focusedTextColor, long unfocusedTextColor, long disabledTextColor, long errorTextColor, long focusedContainerColor, long unfocusedContainerColor, long disabledContainerColor, long errorContainerColor, long cursorColor, long errorCursorColor, androidx.compose.foundation.text.selection.TextSelectionColors textSelectionColors, long focusedIndicatorColor, long unfocusedIndicatorColor, long disabledIndicatorColor, long errorIndicatorColor, long focusedLeadingIconColor, long unfocusedLeadingIconColor, long disabledLeadingIconColor, long errorLeadingIconColor, long focusedTrailingIconColor, long unfocusedTrailingIconColor, long disabledTrailingIconColor, long errorTrailingIconColor, long focusedLabelColor, long unfocusedLabelColor, long disabledLabelColor, long errorLabelColor, long focusedPlaceholderColor, long unfocusedPlaceholderColor, long disabledPlaceholderColor, long errorPlaceholderColor, long focusedSupportingTextColor, long unfocusedSupportingTextColor, long disabledSupportingTextColor, long errorSupportingTextColor, long focusedPrefixColor, long unfocusedPrefixColor, long disabledPrefixColor, long errorPrefixColor, long focusedSuffixColor, long unfocusedSuffixColor, long disabledSuffixColor, long errorSuffixColor);
+ method public long getCursorColor();
+ method public long getDisabledContainerColor();
+ method public long getDisabledIndicatorColor();
+ method public long getDisabledLabelColor();
+ method public long getDisabledLeadingIconColor();
+ method public long getDisabledPlaceholderColor();
+ method public long getDisabledPrefixColor();
+ method public long getDisabledSuffixColor();
+ method public long getDisabledSupportingTextColor();
+ method public long getDisabledTextColor();
+ method public long getDisabledTrailingIconColor();
+ method public long getErrorContainerColor();
+ method public long getErrorCursorColor();
+ method public long getErrorIndicatorColor();
+ method public long getErrorLabelColor();
+ method public long getErrorLeadingIconColor();
+ method public long getErrorPlaceholderColor();
+ method public long getErrorPrefixColor();
+ method public long getErrorSuffixColor();
+ method public long getErrorSupportingTextColor();
+ method public long getErrorTextColor();
+ method public long getErrorTrailingIconColor();
+ method public long getFocusedContainerColor();
+ method public long getFocusedIndicatorColor();
+ method public long getFocusedLabelColor();
+ method public long getFocusedLeadingIconColor();
+ method public long getFocusedPlaceholderColor();
+ method public long getFocusedPrefixColor();
+ method public long getFocusedSuffixColor();
+ method public long getFocusedSupportingTextColor();
+ method public long getFocusedTextColor();
+ method public long getFocusedTrailingIconColor();
+ method public androidx.compose.foundation.text.selection.TextSelectionColors getTextSelectionColors();
+ method public long getUnfocusedContainerColor();
+ method public long getUnfocusedIndicatorColor();
+ method public long getUnfocusedLabelColor();
+ method public long getUnfocusedLeadingIconColor();
+ method public long getUnfocusedPlaceholderColor();
+ method public long getUnfocusedPrefixColor();
+ method public long getUnfocusedSuffixColor();
+ method public long getUnfocusedSupportingTextColor();
+ method public long getUnfocusedTextColor();
+ method public long getUnfocusedTrailingIconColor();
+ property public final long cursorColor;
+ property public final long disabledContainerColor;
+ property public final long disabledIndicatorColor;
+ property public final long disabledLabelColor;
+ property public final long disabledLeadingIconColor;
+ property public final long disabledPlaceholderColor;
+ property public final long disabledPrefixColor;
+ property public final long disabledSuffixColor;
+ property public final long disabledSupportingTextColor;
+ property public final long disabledTextColor;
+ property public final long disabledTrailingIconColor;
+ property public final long errorContainerColor;
+ property public final long errorCursorColor;
+ property public final long errorIndicatorColor;
+ property public final long errorLabelColor;
+ property public final long errorLeadingIconColor;
+ property public final long errorPlaceholderColor;
+ property public final long errorPrefixColor;
+ property public final long errorSuffixColor;
+ property public final long errorSupportingTextColor;
+ property public final long errorTextColor;
+ property public final long errorTrailingIconColor;
+ property public final long focusedContainerColor;
+ property public final long focusedIndicatorColor;
+ property public final long focusedLabelColor;
+ property public final long focusedLeadingIconColor;
+ property public final long focusedPlaceholderColor;
+ property public final long focusedPrefixColor;
+ property public final long focusedSuffixColor;
+ property public final long focusedSupportingTextColor;
+ property public final long focusedTextColor;
+ property public final long focusedTrailingIconColor;
+ property public final androidx.compose.foundation.text.selection.TextSelectionColors textSelectionColors;
+ property public final long unfocusedContainerColor;
+ property public final long unfocusedIndicatorColor;
+ property public final long unfocusedLabelColor;
+ property public final long unfocusedLeadingIconColor;
+ property public final long unfocusedPlaceholderColor;
+ property public final long unfocusedPrefixColor;
+ property public final long unfocusedSuffixColor;
+ property public final long unfocusedSupportingTextColor;
+ property public final long unfocusedTextColor;
+ property public final long unfocusedTrailingIconColor;
+ }
+
+ @androidx.compose.runtime.Immutable public final class TextFieldDefaults {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void ContainerBox(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional androidx.compose.ui.graphics.Shape shape);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void DecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void FilledContainerBox(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional androidx.compose.ui.graphics.Shape shape);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void OutlinedBorderContainerBox(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional androidx.compose.ui.graphics.Shape shape, optional float focusedBorderThickness, optional float unfocusedBorderThickness);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void OutlinedTextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void OutlinedTextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void TextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void TextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors colors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long focusedContainerColor, optional long unfocusedContainerColor, optional long disabledContainerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+ method public androidx.compose.foundation.layout.PaddingValues contentPaddingWithLabel(optional float start, optional float end, optional float top, optional float bottom);
+ method public androidx.compose.foundation.layout.PaddingValues contentPaddingWithoutLabel(optional float start, optional float top, optional float end, optional float bottom);
+ method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFilledShape();
+ method @Deprecated public float getFocusedBorderThickness();
+ method public float getFocusedIndicatorThickness();
+ method public float getMinHeight();
+ method public float getMinWidth();
+ method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getOutlinedShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ method @Deprecated public float getUnfocusedBorderThickness();
+ method public float getUnfocusedIndicatorThickness();
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public androidx.compose.ui.Modifier indicatorLine(androidx.compose.ui.Modifier, boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional float focusedIndicatorLineThickness, optional float unfocusedIndicatorLineThickness);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long containerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+ method @Deprecated public androidx.compose.foundation.layout.PaddingValues outlinedTextFieldPadding(optional float start, optional float top, optional float end, optional float bottom);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long containerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+ method @Deprecated public androidx.compose.foundation.layout.PaddingValues textFieldWithLabelPadding(optional float start, optional float end, optional float top, optional float bottom);
+ method @Deprecated public androidx.compose.foundation.layout.PaddingValues textFieldWithoutLabelPadding(optional float start, optional float top, optional float end, optional float bottom);
+ property @Deprecated public final float FocusedBorderThickness;
+ property public final float FocusedIndicatorThickness;
+ property public final float MinHeight;
+ property public final float MinWidth;
+ property @Deprecated public final float UnfocusedBorderThickness;
+ property public final float UnfocusedIndicatorThickness;
+ property @Deprecated @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape filledShape;
+ property @Deprecated @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape outlinedShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ field public static final androidx.compose.material3.TextFieldDefaults INSTANCE;
+ }
+
+ public final class TextFieldKt {
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+ method @androidx.compose.runtime.Composable public static void TextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+ method @androidx.compose.runtime.Composable public static void TextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+ }
+
+ public final class TextKt {
+ method @androidx.compose.runtime.Composable public static void ProvideTextStyle(androidx.compose.ui.text.TextStyle value, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void Text(androidx.compose.ui.text.AnnotatedString text, optional androidx.compose.ui.Modifier modifier, optional long color, optional long fontSize, optional androidx.compose.ui.text.font.FontStyle? fontStyle, optional androidx.compose.ui.text.font.FontWeight? fontWeight, optional androidx.compose.ui.text.font.FontFamily? fontFamily, optional long letterSpacing, optional androidx.compose.ui.text.style.TextDecoration? textDecoration, optional androidx.compose.ui.text.style.TextAlign? textAlign, optional long lineHeight, optional int overflow, optional boolean softWrap, optional int maxLines, optional int minLines, optional java.util.Map<java.lang.String,androidx.compose.foundation.text.InlineTextContent> inlineContent, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.ui.text.TextStyle style);
+ method @Deprecated @androidx.compose.runtime.Composable public static void Text(androidx.compose.ui.text.AnnotatedString text, optional androidx.compose.ui.Modifier modifier, optional long color, optional long fontSize, optional androidx.compose.ui.text.font.FontStyle? fontStyle, optional androidx.compose.ui.text.font.FontWeight? fontWeight, optional androidx.compose.ui.text.font.FontFamily? fontFamily, optional long letterSpacing, optional androidx.compose.ui.text.style.TextDecoration? textDecoration, optional androidx.compose.ui.text.style.TextAlign? textAlign, optional long lineHeight, optional int overflow, optional boolean softWrap, optional int maxLines, optional java.util.Map<java.lang.String,androidx.compose.foundation.text.InlineTextContent> inlineContent, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.ui.text.TextStyle style);
+ method @androidx.compose.runtime.Composable public static void Text(String text, optional androidx.compose.ui.Modifier modifier, optional long color, optional long fontSize, optional androidx.compose.ui.text.font.FontStyle? fontStyle, optional androidx.compose.ui.text.font.FontWeight? fontWeight, optional androidx.compose.ui.text.font.FontFamily? fontFamily, optional long letterSpacing, optional androidx.compose.ui.text.style.TextDecoration? textDecoration, optional androidx.compose.ui.text.style.TextAlign? textAlign, optional long lineHeight, optional int overflow, optional boolean softWrap, optional int maxLines, optional int minLines, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit>? onTextLayout, optional androidx.compose.ui.text.TextStyle style);
+ method @Deprecated @androidx.compose.runtime.Composable public static void Text(String text, optional androidx.compose.ui.Modifier modifier, optional long color, optional long fontSize, optional androidx.compose.ui.text.font.FontStyle? fontStyle, optional androidx.compose.ui.text.font.FontWeight? fontWeight, optional androidx.compose.ui.text.font.FontFamily? fontFamily, optional long letterSpacing, optional androidx.compose.ui.text.style.TextDecoration? textDecoration, optional androidx.compose.ui.text.style.TextAlign? textAlign, optional long lineHeight, optional int overflow, optional boolean softWrap, optional int maxLines, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.ui.text.TextStyle style);
+ method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.TextStyle> getLocalTextStyle();
+ property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.TextStyle> LocalTextStyle;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class TimePickerColors {
+ ctor public TimePickerColors(long clockDialColor, long selectorColor, long containerColor, long periodSelectorBorderColor, long clockDialSelectedContentColor, long clockDialUnselectedContentColor, long periodSelectorSelectedContainerColor, long periodSelectorUnselectedContainerColor, long periodSelectorSelectedContentColor, long periodSelectorUnselectedContentColor, long timeSelectorSelectedContainerColor, long timeSelectorUnselectedContainerColor, long timeSelectorSelectedContentColor, long timeSelectorUnselectedContentColor);
+ method public long getClockDialColor();
+ method public long getClockDialSelectedContentColor();
+ method public long getClockDialUnselectedContentColor();
+ method public long getContainerColor();
+ method public long getPeriodSelectorBorderColor();
+ method public long getPeriodSelectorSelectedContainerColor();
+ method public long getPeriodSelectorSelectedContentColor();
+ method public long getPeriodSelectorUnselectedContainerColor();
+ method public long getPeriodSelectorUnselectedContentColor();
+ method public long getSelectorColor();
+ method public long getTimeSelectorSelectedContainerColor();
+ method public long getTimeSelectorSelectedContentColor();
+ method public long getTimeSelectorUnselectedContainerColor();
+ method public long getTimeSelectorUnselectedContentColor();
+ property public final long clockDialColor;
+ property public final long clockDialSelectedContentColor;
+ property public final long clockDialUnselectedContentColor;
+ property public final long containerColor;
+ property public final long periodSelectorBorderColor;
+ property public final long periodSelectorSelectedContainerColor;
+ property public final long periodSelectorSelectedContentColor;
+ property public final long periodSelectorUnselectedContainerColor;
+ property public final long periodSelectorUnselectedContentColor;
+ property public final long selectorColor;
+ property public final long timeSelectorSelectedContainerColor;
+ property public final long timeSelectorSelectedContentColor;
+ property public final long timeSelectorUnselectedContainerColor;
+ property public final long timeSelectorUnselectedContentColor;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class TimePickerDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.TimePickerColors colors(optional long clockDialColor, optional long clockDialSelectedContentColor, optional long clockDialUnselectedContentColor, optional long selectorColor, optional long containerColor, optional long periodSelectorBorderColor, optional long periodSelectorSelectedContainerColor, optional long periodSelectorUnselectedContainerColor, optional long periodSelectorSelectedContentColor, optional long periodSelectorUnselectedContentColor, optional long timeSelectorSelectedContainerColor, optional long timeSelectorUnselectedContainerColor, optional long timeSelectorSelectedContentColor, optional long timeSelectorUnselectedContentColor);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public int layoutType();
+ field public static final androidx.compose.material3.TimePickerDefaults INSTANCE;
+ }
+
+ public final class TimePickerKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TimeInput(androidx.compose.material3.TimePickerState state, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.TimePickerColors colors);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TimePicker(androidx.compose.material3.TimePickerState state, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.TimePickerColors colors, optional int layoutType);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.TimePickerState rememberTimePickerState(optional int initialHour, optional int initialMinute, optional boolean is24Hour);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class TimePickerLayoutType {
+ field public static final androidx.compose.material3.TimePickerLayoutType.Companion Companion;
+ }
+
+ public static final class TimePickerLayoutType.Companion {
+ method public int getHorizontal();
+ method public int getVertical();
+ property public final int Horizontal;
+ property public final int Vertical;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class TimePickerState {
+ ctor public TimePickerState(int initialHour, int initialMinute, boolean is24Hour);
+ method public int getHour();
+ method public int getMinute();
+ method public boolean is24hour();
+ method public suspend Object? settle(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ property public final int hour;
+ property public final boolean is24hour;
+ property public final int minute;
+ field public static final androidx.compose.material3.TimePickerState.Companion Companion;
+ }
+
+ public static final class TimePickerState.Companion {
+ method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.TimePickerState,?> Saver();
+ }
+
+ @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public interface TooltipBoxScope {
+ method @Deprecated public androidx.compose.ui.Modifier tooltipTrigger(androidx.compose.ui.Modifier);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class TooltipDefaults {
+ method @androidx.compose.runtime.Composable public long getPlainTooltipContainerColor();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getPlainTooltipContainerShape();
+ method @androidx.compose.runtime.Composable public long getPlainTooltipContentColor();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getRichTooltipContainerShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.window.PopupPositionProvider rememberPlainTooltipPositionProvider(optional float spacingBetweenTooltipAndAnchor);
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.window.PopupPositionProvider rememberRichTooltipPositionProvider(optional float spacingBetweenTooltipAndAnchor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.RichTooltipColors richTooltipColors(optional long containerColor, optional long contentColor, optional long titleContentColor, optional long actionContentColor);
+ property @androidx.compose.runtime.Composable public final long plainTooltipContainerColor;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape plainTooltipContainerShape;
+ property @androidx.compose.runtime.Composable public final long plainTooltipContentColor;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape richTooltipContainerShape;
+ field public static final androidx.compose.material3.TooltipDefaults INSTANCE;
+ }
+
+ public final class TooltipKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void PlainTooltip(optional androidx.compose.ui.Modifier modifier, optional long contentColor, optional long containerColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.ui.graphics.Shape shape, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void PlainTooltipBox(kotlin.jvm.functions.Function0<kotlin.Unit> tooltip, optional androidx.compose.ui.Modifier modifier, optional boolean focusable, optional androidx.compose.material3.PlainTooltipState tooltipState, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional float tonalElevation, optional float shadowElevation, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.material3.TooltipBoxScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void RichTooltip(optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? action, optional androidx.compose.material3.RichTooltipColors colors, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.ui.graphics.Shape shape, kotlin.jvm.functions.Function0<kotlin.Unit> text);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void RichTooltipBox(kotlin.jvm.functions.Function0<kotlin.Unit> text, optional androidx.compose.ui.Modifier modifier, optional boolean focusable, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? action, optional androidx.compose.material3.RichTooltipState tooltipState, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.RichTooltipColors colors, optional float tonalElevation, optional float shadowElevation, kotlin.jvm.functions.Function1<? super androidx.compose.material3.TooltipBoxScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TooltipBox(androidx.compose.ui.window.PopupPositionProvider positionProvider, kotlin.jvm.functions.Function0<kotlin.Unit> tooltip, androidx.compose.material3.TooltipState state, optional androidx.compose.ui.Modifier modifier, optional boolean focusable, optional boolean enableUserInput, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static androidx.compose.material3.TooltipState TooltipState(optional boolean initialIsVisible, optional boolean isPersistent, optional androidx.compose.foundation.MutatorMutex mutatorMutex);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.PlainTooltipState rememberPlainTooltipState(optional androidx.compose.foundation.MutatorMutex mutatorMutex);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.RichTooltipState rememberRichTooltipState(boolean isPersistent, optional androidx.compose.foundation.MutatorMutex mutatorMutex);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.TooltipState rememberTooltipState(optional boolean initialIsVisible, optional boolean isPersistent, optional androidx.compose.foundation.MutatorMutex mutatorMutex);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public interface TooltipState extends androidx.compose.material3.BasicTooltipState {
+ method public androidx.compose.animation.core.MutableTransitionState<java.lang.Boolean> getTransition();
+ property public abstract androidx.compose.animation.core.MutableTransitionState<java.lang.Boolean> transition;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class TopAppBarColors {
+ ctor public TopAppBarColors(long containerColor, long scrolledContainerColor, long navigationIconContentColor, long titleContentColor, long actionIconContentColor);
+ method public long getActionIconContentColor();
+ method public long getContainerColor();
+ method public long getNavigationIconContentColor();
+ method public long getScrolledContainerColor();
+ method public long getTitleContentColor();
+ property public final long actionIconContentColor;
+ property public final long containerColor;
+ property public final long navigationIconContentColor;
+ property public final long scrolledContainerColor;
+ property public final long titleContentColor;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class TopAppBarDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.TopAppBarColors centerAlignedTopAppBarColors(optional long containerColor, optional long scrolledContainerColor, optional long navigationIconContentColor, optional long titleContentColor, optional long actionIconContentColor);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TopAppBarScrollBehavior enterAlwaysScrollBehavior(optional androidx.compose.material3.TopAppBarState state, optional kotlin.jvm.functions.Function0<java.lang.Boolean> canScroll, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float>? snapAnimationSpec, optional androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float>? flingAnimationSpec);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TopAppBarScrollBehavior exitUntilCollapsedScrollBehavior(optional androidx.compose.material3.TopAppBarState state, optional kotlin.jvm.functions.Function0<java.lang.Boolean> canScroll, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float>? snapAnimationSpec, optional androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float>? flingAnimationSpec);
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.TopAppBarColors largeTopAppBarColors(optional long containerColor, optional long scrolledContainerColor, optional long navigationIconContentColor, optional long titleContentColor, optional long actionIconContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.TopAppBarColors mediumTopAppBarColors(optional long containerColor, optional long scrolledContainerColor, optional long navigationIconContentColor, optional long titleContentColor, optional long actionIconContentColor);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TopAppBarScrollBehavior pinnedScrollBehavior(optional androidx.compose.material3.TopAppBarState state, optional kotlin.jvm.functions.Function0<java.lang.Boolean> canScroll);
+ method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.TopAppBarColors smallTopAppBarColors(optional long containerColor, optional long scrolledContainerColor, optional long navigationIconContentColor, optional long titleContentColor, optional long actionIconContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.TopAppBarColors topAppBarColors(optional long containerColor, optional long scrolledContainerColor, optional long navigationIconContentColor, optional long titleContentColor, optional long actionIconContentColor);
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+ field public static final androidx.compose.material3.TopAppBarDefaults INSTANCE;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public interface TopAppBarScrollBehavior {
+ method public androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float>? getFlingAnimationSpec();
+ method public androidx.compose.ui.input.nestedscroll.NestedScrollConnection getNestedScrollConnection();
+ method public androidx.compose.animation.core.AnimationSpec<java.lang.Float>? getSnapAnimationSpec();
+ method public androidx.compose.material3.TopAppBarState getState();
+ method public boolean isPinned();
+ property public abstract androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float>? flingAnimationSpec;
+ property public abstract boolean isPinned;
+ property public abstract androidx.compose.ui.input.nestedscroll.NestedScrollConnection nestedScrollConnection;
+ property public abstract androidx.compose.animation.core.AnimationSpec<java.lang.Float>? snapAnimationSpec;
+ property public abstract androidx.compose.material3.TopAppBarState state;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class TopAppBarState {
+ ctor public TopAppBarState(float initialHeightOffsetLimit, float initialHeightOffset, float initialContentOffset);
+ method public float getCollapsedFraction();
+ method public float getContentOffset();
+ method public float getHeightOffset();
+ method public float getHeightOffsetLimit();
+ method public float getOverlappedFraction();
+ method public void setContentOffset(float);
+ method public void setHeightOffset(float);
+ method public void setHeightOffsetLimit(float);
+ property public final float collapsedFraction;
+ property public final float contentOffset;
+ property public final float heightOffset;
+ property public final float heightOffsetLimit;
+ property public final float overlappedFraction;
+ field public static final androidx.compose.material3.TopAppBarState.Companion Companion;
+ }
+
+ public static final class TopAppBarState.Companion {
+ method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.TopAppBarState,?> getSaver();
+ property public final androidx.compose.runtime.saveable.Saver<androidx.compose.material3.TopAppBarState,?> Saver;
+ }
+
+ @androidx.compose.runtime.Immutable public final class Typography {
+ ctor public Typography(optional androidx.compose.ui.text.TextStyle displayLarge, optional androidx.compose.ui.text.TextStyle displayMedium, optional androidx.compose.ui.text.TextStyle displaySmall, optional androidx.compose.ui.text.TextStyle headlineLarge, optional androidx.compose.ui.text.TextStyle headlineMedium, optional androidx.compose.ui.text.TextStyle headlineSmall, optional androidx.compose.ui.text.TextStyle titleLarge, optional androidx.compose.ui.text.TextStyle titleMedium, optional androidx.compose.ui.text.TextStyle titleSmall, optional androidx.compose.ui.text.TextStyle bodyLarge, optional androidx.compose.ui.text.TextStyle bodyMedium, optional androidx.compose.ui.text.TextStyle bodySmall, optional androidx.compose.ui.text.TextStyle labelLarge, optional androidx.compose.ui.text.TextStyle labelMedium, optional androidx.compose.ui.text.TextStyle labelSmall);
+ method public androidx.compose.material3.Typography copy(optional androidx.compose.ui.text.TextStyle displayLarge, optional androidx.compose.ui.text.TextStyle displayMedium, optional androidx.compose.ui.text.TextStyle displaySmall, optional androidx.compose.ui.text.TextStyle headlineLarge, optional androidx.compose.ui.text.TextStyle headlineMedium, optional androidx.compose.ui.text.TextStyle headlineSmall, optional androidx.compose.ui.text.TextStyle titleLarge, optional androidx.compose.ui.text.TextStyle titleMedium, optional androidx.compose.ui.text.TextStyle titleSmall, optional androidx.compose.ui.text.TextStyle bodyLarge, optional androidx.compose.ui.text.TextStyle bodyMedium, optional androidx.compose.ui.text.TextStyle bodySmall, optional androidx.compose.ui.text.TextStyle labelLarge, optional androidx.compose.ui.text.TextStyle labelMedium, optional androidx.compose.ui.text.TextStyle labelSmall);
+ method public androidx.compose.ui.text.TextStyle getBodyLarge();
+ method public androidx.compose.ui.text.TextStyle getBodyMedium();
+ method public androidx.compose.ui.text.TextStyle getBodySmall();
+ method public androidx.compose.ui.text.TextStyle getDisplayLarge();
+ method public androidx.compose.ui.text.TextStyle getDisplayMedium();
+ method public androidx.compose.ui.text.TextStyle getDisplaySmall();
+ method public androidx.compose.ui.text.TextStyle getHeadlineLarge();
+ method public androidx.compose.ui.text.TextStyle getHeadlineMedium();
+ method public androidx.compose.ui.text.TextStyle getHeadlineSmall();
+ method public androidx.compose.ui.text.TextStyle getLabelLarge();
+ method public androidx.compose.ui.text.TextStyle getLabelMedium();
+ method public androidx.compose.ui.text.TextStyle getLabelSmall();
+ method public androidx.compose.ui.text.TextStyle getTitleLarge();
+ method public androidx.compose.ui.text.TextStyle getTitleMedium();
+ method public androidx.compose.ui.text.TextStyle getTitleSmall();
+ property public final androidx.compose.ui.text.TextStyle bodyLarge;
+ property public final androidx.compose.ui.text.TextStyle bodyMedium;
+ property public final androidx.compose.ui.text.TextStyle bodySmall;
+ property public final androidx.compose.ui.text.TextStyle displayLarge;
+ property public final androidx.compose.ui.text.TextStyle displayMedium;
+ property public final androidx.compose.ui.text.TextStyle displaySmall;
+ property public final androidx.compose.ui.text.TextStyle headlineLarge;
+ property public final androidx.compose.ui.text.TextStyle headlineMedium;
+ property public final androidx.compose.ui.text.TextStyle headlineSmall;
+ property public final androidx.compose.ui.text.TextStyle labelLarge;
+ property public final androidx.compose.ui.text.TextStyle labelMedium;
+ property public final androidx.compose.ui.text.TextStyle labelSmall;
+ property public final androidx.compose.ui.text.TextStyle titleLarge;
+ property public final androidx.compose.ui.text.TextStyle titleMedium;
+ property public final androidx.compose.ui.text.TextStyle titleSmall;
+ }
+
+}
+
+package androidx.compose.material3.pulltorefresh {
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class PullToRefreshDefaults {
+ method @androidx.compose.runtime.Composable public void Indicator(androidx.compose.material3.pulltorefresh.PullToRefreshState state, optional androidx.compose.ui.Modifier modifier, optional long color);
+ method @androidx.compose.runtime.Composable public long getContainerColor();
+ method @androidx.compose.runtime.Composable public long getContentColor();
+ method public float getPositionalThreshold();
+ method public androidx.compose.ui.graphics.Shape getShape();
+ property public final float PositionalThreshold;
+ property @androidx.compose.runtime.Composable public final long containerColor;
+ property @androidx.compose.runtime.Composable public final long contentColor;
+ property public final androidx.compose.ui.graphics.Shape shape;
+ field public static final androidx.compose.material3.pulltorefresh.PullToRefreshDefaults INSTANCE;
+ }
+
+ public final class PullToRefreshKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void PullToRefreshContainer(androidx.compose.material3.pulltorefresh.PullToRefreshState state, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.pulltorefresh.PullToRefreshState,kotlin.Unit> indicator, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static androidx.compose.material3.pulltorefresh.PullToRefreshState PullToRefreshState(float positionalThresholdPx, optional boolean initialRefreshing, optional kotlin.jvm.functions.Function0<java.lang.Boolean> enabled);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.pulltorefresh.PullToRefreshState rememberPullToRefreshState(optional float positionalThreshold, optional kotlin.jvm.functions.Function0<java.lang.Boolean> enabled);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public interface PullToRefreshState {
+ method public void endRefresh();
+ method public androidx.compose.ui.input.nestedscroll.NestedScrollConnection getNestedScrollConnection();
+ method public float getPositionalThreshold();
+ method @FloatRange(from=0.0) public float getProgress();
+ method @FloatRange(from=0.0) public float getVerticalOffset();
+ method public boolean isRefreshing();
+ method public void setNestedScrollConnection(androidx.compose.ui.input.nestedscroll.NestedScrollConnection);
+ method public void startRefresh();
+ property public abstract boolean isRefreshing;
+ property public abstract androidx.compose.ui.input.nestedscroll.NestedScrollConnection nestedScrollConnection;
+ property public abstract float positionalThreshold;
+ property @FloatRange(from=0.0) public abstract float progress;
+ property @FloatRange(from=0.0) public abstract float verticalOffset;
+ }
+
+}
+
diff --git a/compose/material3/material3/api/current.txt b/compose/material3/material3/api/current.txt
index c4701d4..7ca2ade 100644
--- a/compose/material3/material3/api/current.txt
+++ b/compose/material3/material3/api/current.txt
@@ -597,43 +597,19 @@
property public abstract kotlin.ranges.IntRange yearRange;
}
- @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum DismissDirection {
- method public static androidx.compose.material3.DismissDirection valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
- method public static androidx.compose.material3.DismissDirection[] values();
- enum_constant public static final androidx.compose.material3.DismissDirection EndToStart;
- enum_constant public static final androidx.compose.material3.DismissDirection StartToEnd;
+ @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum DismissDirection {
+ method @Deprecated public static androidx.compose.material3.DismissDirection valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method @Deprecated public static androidx.compose.material3.DismissDirection[] values();
+ enum_constant @Deprecated public static final androidx.compose.material3.DismissDirection EndToStart;
+ enum_constant @Deprecated public static final androidx.compose.material3.DismissDirection StartToEnd;
}
- public final class DismissState {
- ctor public DismissState(androidx.compose.material3.DismissValue initialValue, androidx.compose.ui.unit.Density density, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.DismissValue,java.lang.Boolean> confirmValueChange, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold);
- ctor @Deprecated public DismissState(androidx.compose.material3.DismissValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.DismissValue,java.lang.Boolean> confirmValueChange, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold);
- method public suspend Object? dismiss(androidx.compose.material3.DismissDirection direction, kotlin.coroutines.Continuation<? super kotlin.Unit>);
- method public androidx.compose.material3.DismissValue getCurrentValue();
- method public androidx.compose.material3.DismissDirection? getDismissDirection();
- method public float getProgress();
- method public androidx.compose.material3.DismissValue getTargetValue();
- method public boolean isDismissed(androidx.compose.material3.DismissDirection direction);
- method public float requireOffset();
- method public suspend Object? reset(kotlin.coroutines.Continuation<? super kotlin.Unit>);
- method public suspend Object? snapTo(androidx.compose.material3.DismissValue targetValue, kotlin.coroutines.Continuation<? super kotlin.Unit>);
- property public final androidx.compose.material3.DismissValue currentValue;
- property public final androidx.compose.material3.DismissDirection? dismissDirection;
- property public final float progress;
- property public final androidx.compose.material3.DismissValue targetValue;
- field public static final androidx.compose.material3.DismissState.Companion Companion;
- }
-
- public static final class DismissState.Companion {
- method @Deprecated public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.DismissState,androidx.compose.material3.DismissValue> Saver(kotlin.jvm.functions.Function1<? super androidx.compose.material3.DismissValue,java.lang.Boolean> confirmValueChange, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold);
- method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.DismissState,androidx.compose.material3.DismissValue> Saver(kotlin.jvm.functions.Function1<? super androidx.compose.material3.DismissValue,java.lang.Boolean> confirmValueChange, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold, androidx.compose.ui.unit.Density density);
- }
-
- @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum DismissValue {
- method public static androidx.compose.material3.DismissValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
- method public static androidx.compose.material3.DismissValue[] values();
- enum_constant public static final androidx.compose.material3.DismissValue Default;
- enum_constant public static final androidx.compose.material3.DismissValue DismissedToEnd;
- enum_constant public static final androidx.compose.material3.DismissValue DismissedToStart;
+ @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum DismissValue {
+ method @Deprecated public static androidx.compose.material3.DismissValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method @Deprecated public static androidx.compose.material3.DismissValue[] values();
+ enum_constant @Deprecated public static final androidx.compose.material3.DismissValue Default;
+ enum_constant @Deprecated public static final androidx.compose.material3.DismissValue DismissedToEnd;
+ enum_constant @Deprecated public static final androidx.compose.material3.DismissValue DismissedToStart;
}
@SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class DisplayMode {
@@ -1559,15 +1535,45 @@
}
@SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class SwipeToDismissBoxDefaults {
- method @androidx.compose.runtime.Composable public kotlin.jvm.functions.Function1<java.lang.Float,java.lang.Float> getFixedPositionalThreshold();
- property @androidx.compose.runtime.Composable public final kotlin.jvm.functions.Function1<java.lang.Float,java.lang.Float> fixedPositionalThreshold;
+ method @androidx.compose.runtime.Composable public kotlin.jvm.functions.Function1<java.lang.Float,java.lang.Float> getPositionalThreshold();
+ property @androidx.compose.runtime.Composable public final kotlin.jvm.functions.Function1<java.lang.Float,java.lang.Float> positionalThreshold;
field public static final androidx.compose.material3.SwipeToDismissBoxDefaults INSTANCE;
}
public final class SwipeToDismissBoxKt {
- method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismiss(androidx.compose.material3.DismissState state, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> background, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> dismissContent, optional androidx.compose.ui.Modifier modifier, optional java.util.Set<? extends androidx.compose.material3.DismissDirection> directions);
- method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismissBox(androidx.compose.material3.DismissState state, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> backgroundContent, optional androidx.compose.ui.Modifier modifier, optional java.util.Set<? extends androidx.compose.material3.DismissDirection> directions, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
- method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.DismissState rememberDismissState(optional androidx.compose.material3.DismissValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.DismissValue,java.lang.Boolean> confirmValueChange, optional kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismiss(androidx.compose.material3.SwipeToDismissState state, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> background, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> dismissContent, optional androidx.compose.ui.Modifier modifier, optional java.util.Set<? extends androidx.compose.material3.SwipeToDismissValue> directions);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismissBox(androidx.compose.material3.SwipeToDismissState state, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> backgroundContent, optional androidx.compose.ui.Modifier modifier, optional boolean enableDismissFromStartToEnd, optional boolean enableDismissFromEndToStart, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.SwipeToDismissState rememberSwipeToDismissState(optional androidx.compose.material3.SwipeToDismissValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SwipeToDismissValue,java.lang.Boolean> confirmValueChange, optional kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class SwipeToDismissState {
+ ctor public SwipeToDismissState(androidx.compose.material3.SwipeToDismissValue initialValue, androidx.compose.ui.unit.Density density, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SwipeToDismissValue,java.lang.Boolean> confirmValueChange, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold);
+ method public suspend Object? dismiss(androidx.compose.material3.SwipeToDismissValue direction, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public androidx.compose.material3.SwipeToDismissValue getCurrentValue();
+ method public androidx.compose.material3.SwipeToDismissValue getDismissDirection();
+ method @FloatRange(from=0.0, to=1.0) public float getProgress();
+ method public androidx.compose.material3.SwipeToDismissValue getTargetValue();
+ method @Deprecated public boolean isDismissed(androidx.compose.material3.DismissDirection direction);
+ method public float requireOffset();
+ method public suspend Object? reset(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public suspend Object? snapTo(androidx.compose.material3.SwipeToDismissValue targetValue, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ property public final androidx.compose.material3.SwipeToDismissValue currentValue;
+ property public final androidx.compose.material3.SwipeToDismissValue dismissDirection;
+ property @FloatRange(from=0.0, to=1.0) public final float progress;
+ property public final androidx.compose.material3.SwipeToDismissValue targetValue;
+ field public static final androidx.compose.material3.SwipeToDismissState.Companion Companion;
+ }
+
+ public static final class SwipeToDismissState.Companion {
+ method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.SwipeToDismissState,androidx.compose.material3.SwipeToDismissValue> Saver(kotlin.jvm.functions.Function1<? super androidx.compose.material3.SwipeToDismissValue,java.lang.Boolean> confirmValueChange, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold, androidx.compose.ui.unit.Density density);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum SwipeToDismissValue {
+ method public static androidx.compose.material3.SwipeToDismissValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.compose.material3.SwipeToDismissValue[] values();
+ enum_constant public static final androidx.compose.material3.SwipeToDismissValue EndToStart;
+ enum_constant public static final androidx.compose.material3.SwipeToDismissValue Settled;
+ enum_constant public static final androidx.compose.material3.SwipeToDismissValue StartToEnd;
}
@androidx.compose.runtime.Immutable public final class SwitchColors {
diff --git a/compose/material3/material3/api/res-1.2.0-beta01.txt b/compose/material3/material3/api/res-1.2.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/compose/material3/material3/api/res-1.2.0-beta01.txt
diff --git a/compose/material3/material3/api/restricted_1.2.0-beta01.txt b/compose/material3/material3/api/restricted_1.2.0-beta01.txt
new file mode 100644
index 0000000..7ca2ade
--- /dev/null
+++ b/compose/material3/material3/api/restricted_1.2.0-beta01.txt
@@ -0,0 +1,2073 @@
+// Signature format: 4.0
+package androidx.compose.material3 {
+
+ public final class AlertDialogDefaults {
+ method @androidx.compose.runtime.Composable public long getContainerColor();
+ method @androidx.compose.runtime.Composable public long getIconContentColor();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ method @androidx.compose.runtime.Composable public long getTextContentColor();
+ method @androidx.compose.runtime.Composable public long getTitleContentColor();
+ method public float getTonalElevation();
+ property public final float TonalElevation;
+ property @androidx.compose.runtime.Composable public final long containerColor;
+ property @androidx.compose.runtime.Composable public final long iconContentColor;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ property @androidx.compose.runtime.Composable public final long textContentColor;
+ property @androidx.compose.runtime.Composable public final long titleContentColor;
+ field public static final androidx.compose.material3.AlertDialogDefaults INSTANCE;
+ }
+
+ public final class AndroidAlertDialog_androidKt {
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void AlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.window.DialogProperties properties, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void AlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, kotlin.jvm.functions.Function0<kotlin.Unit> confirmButton, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dismissButton, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long iconContentColor, optional long titleContentColor, optional long textContentColor, optional float tonalElevation, optional androidx.compose.ui.window.DialogProperties properties);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void BasicAlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.window.DialogProperties properties, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ }
+
+ public final class AndroidMenu_androidKt {
+ method @androidx.compose.runtime.Composable public static void DropdownMenu(boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional long offset, optional androidx.compose.foundation.ScrollState scrollState, optional androidx.compose.ui.window.PopupProperties properties, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @Deprecated @androidx.compose.runtime.Composable public static void DropdownMenu(boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional long offset, optional androidx.compose.ui.window.PopupProperties properties, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void DropdownMenuItem(kotlin.jvm.functions.Function0<kotlin.Unit> text, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional boolean enabled, optional androidx.compose.material3.MenuItemColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ }
+
+ public final class AppBarKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void BottomAppBar(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.BottomAppBarScrollBehavior? scrollBehavior, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void BottomAppBar(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void BottomAppBar(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? floatingActionButton, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void BottomAppBar(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? floatingActionButton, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.BottomAppBarScrollBehavior? scrollBehavior);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static androidx.compose.material3.BottomAppBarState BottomAppBarState(float initialHeightOffsetLimit, float initialHeightOffset, float initialContentOffset);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void CenterAlignedTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void LargeTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void MediumTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SmallTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.BottomAppBarState rememberBottomAppBarState(optional float initialHeightOffsetLimit, optional float initialHeightOffset, optional float initialContentOffset);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.TopAppBarState rememberTopAppBarState(optional float initialHeightOffsetLimit, optional float initialHeightOffset, optional float initialContentOffset);
+ }
+
+ public final class AssistChipDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke assistChipBorder(boolean enabled, optional long borderColor, optional long disabledBorderColor, optional float borderWidth);
+ method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.ChipBorder assistChipBorder(optional long borderColor, optional long disabledBorderColor, optional float borderWidth);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors assistChipColors(optional long containerColor, optional long labelColor, optional long leadingIconContentColor, optional long trailingIconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconContentColor, optional long disabledTrailingIconContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation assistChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors elevatedAssistChipColors(optional long containerColor, optional long labelColor, optional long leadingIconContentColor, optional long trailingIconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconContentColor, optional long disabledTrailingIconContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation elevatedAssistChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+ method public float getHeight();
+ method public float getIconSize();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ property public final float Height;
+ property public final float IconSize;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ field public static final androidx.compose.material3.AssistChipDefaults INSTANCE;
+ }
+
+ public final class BadgeDefaults {
+ method @androidx.compose.runtime.Composable public long getContainerColor();
+ property @androidx.compose.runtime.Composable public final long containerColor;
+ field public static final androidx.compose.material3.BadgeDefaults INSTANCE;
+ }
+
+ public final class BadgeKt {
+ method @androidx.compose.runtime.Composable public static void Badge(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit>? content);
+ method @androidx.compose.runtime.Composable public static void BadgedBox(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> badge, optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public interface BasicTooltipState {
+ method public void dismiss();
+ method public boolean isPersistent();
+ method public boolean isVisible();
+ method public void onDispose();
+ method public suspend Object? show(optional androidx.compose.foundation.MutatePriority mutatePriority, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ property public abstract boolean isPersistent;
+ property public abstract boolean isVisible;
+ }
+
+ public final class BottomAppBarDefaults {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.BottomAppBarScrollBehavior exitAlwaysScrollBehavior(optional androidx.compose.material3.BottomAppBarState state, optional kotlin.jvm.functions.Function0<java.lang.Boolean> canScroll, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float>? snapAnimationSpec, optional androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float>? flingAnimationSpec);
+ method @androidx.compose.runtime.Composable public long getBottomAppBarFabColor();
+ method @androidx.compose.runtime.Composable public long getContainerColor();
+ method public float getContainerElevation();
+ method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+ property public final float ContainerElevation;
+ property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
+ property @androidx.compose.runtime.Composable public final long bottomAppBarFabColor;
+ property @androidx.compose.runtime.Composable public final long containerColor;
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+ field public static final androidx.compose.material3.BottomAppBarDefaults INSTANCE;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public interface BottomAppBarScrollBehavior {
+ method public androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float>? getFlingAnimationSpec();
+ method public androidx.compose.ui.input.nestedscroll.NestedScrollConnection getNestedScrollConnection();
+ method public androidx.compose.animation.core.AnimationSpec<java.lang.Float>? getSnapAnimationSpec();
+ method public androidx.compose.material3.BottomAppBarState getState();
+ method public boolean isPinned();
+ property public abstract androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float>? flingAnimationSpec;
+ property public abstract boolean isPinned;
+ property public abstract androidx.compose.ui.input.nestedscroll.NestedScrollConnection nestedScrollConnection;
+ property public abstract androidx.compose.animation.core.AnimationSpec<java.lang.Float>? snapAnimationSpec;
+ property public abstract androidx.compose.material3.BottomAppBarState state;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public interface BottomAppBarState {
+ method public float getCollapsedFraction();
+ method public float getContentOffset();
+ method public float getHeightOffset();
+ method public float getHeightOffsetLimit();
+ method public void setContentOffset(float);
+ method public void setHeightOffset(float);
+ method public void setHeightOffsetLimit(float);
+ property public abstract float collapsedFraction;
+ property public abstract float contentOffset;
+ property public abstract float heightOffset;
+ property public abstract float heightOffsetLimit;
+ field public static final androidx.compose.material3.BottomAppBarState.Companion Companion;
+ }
+
+ public static final class BottomAppBarState.Companion {
+ method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.BottomAppBarState,?> getSaver();
+ property public final androidx.compose.runtime.saveable.Saver<androidx.compose.material3.BottomAppBarState,?> Saver;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class BottomSheetDefaults {
+ method @androidx.compose.runtime.Composable public void DragHandle(optional androidx.compose.ui.Modifier modifier, optional float width, optional float height, optional androidx.compose.ui.graphics.Shape shape, optional long color);
+ method @androidx.compose.runtime.Composable public long getContainerColor();
+ method public float getElevation();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getExpandedShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getHiddenShape();
+ method @androidx.compose.runtime.Composable public long getScrimColor();
+ method public float getSheetMaxWidth();
+ method public float getSheetPeekHeight();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+ property @androidx.compose.runtime.Composable public final long ContainerColor;
+ property public final float Elevation;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape ExpandedShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape HiddenShape;
+ property @androidx.compose.runtime.Composable public final long ScrimColor;
+ property public final float SheetMaxWidth;
+ property public final float SheetPeekHeight;
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+ field public static final androidx.compose.material3.BottomSheetDefaults INSTANCE;
+ }
+
+ public final class BottomSheetScaffoldKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void BottomSheetScaffold(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> sheetContent, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.BottomSheetScaffoldState scaffoldState, optional float sheetPeekHeight, optional float sheetMaxWidth, optional androidx.compose.ui.graphics.Shape sheetShape, optional long sheetContainerColor, optional long sheetContentColor, optional float sheetTonalElevation, optional float sheetShadowElevation, optional kotlin.jvm.functions.Function0<kotlin.Unit>? sheetDragHandle, optional boolean sheetSwipeEnabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? topBar, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SnackbarHostState,kotlin.Unit> snackbarHost, optional long containerColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.BottomSheetScaffoldState rememberBottomSheetScaffoldState(optional androidx.compose.material3.SheetState bottomSheetState, optional androidx.compose.material3.SnackbarHostState snackbarHostState);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.SheetState rememberStandardBottomSheetState(optional androidx.compose.material3.SheetValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange, optional boolean skipHiddenState);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class BottomSheetScaffoldState {
+ ctor public BottomSheetScaffoldState(androidx.compose.material3.SheetState bottomSheetState, androidx.compose.material3.SnackbarHostState snackbarHostState);
+ method public androidx.compose.material3.SheetState getBottomSheetState();
+ method public androidx.compose.material3.SnackbarHostState getSnackbarHostState();
+ property public final androidx.compose.material3.SheetState bottomSheetState;
+ property public final androidx.compose.material3.SnackbarHostState snackbarHostState;
+ }
+
+ @androidx.compose.runtime.Immutable public final class ButtonColors {
+ ctor public ButtonColors(long containerColor, long contentColor, long disabledContainerColor, long disabledContentColor);
+ method public long getContainerColor();
+ method public long getContentColor();
+ method public long getDisabledContainerColor();
+ method public long getDisabledContentColor();
+ property public final long containerColor;
+ property public final long contentColor;
+ property public final long disabledContainerColor;
+ property public final long disabledContentColor;
+ }
+
+ public final class ButtonDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors buttonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonElevation buttonElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float disabledElevation);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors elevatedButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonElevation elevatedButtonElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float disabledElevation);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors filledTonalButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonElevation filledTonalButtonElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float disabledElevation);
+ method public androidx.compose.foundation.layout.PaddingValues getButtonWithIconContentPadding();
+ method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getElevatedShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFilledTonalShape();
+ method public float getIconSize();
+ method public float getIconSpacing();
+ method public float getMinHeight();
+ method public float getMinWidth();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke getOutlinedButtonBorder();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getOutlinedShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ method public androidx.compose.foundation.layout.PaddingValues getTextButtonContentPadding();
+ method public androidx.compose.foundation.layout.PaddingValues getTextButtonWithIconContentPadding();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getTextShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors outlinedButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors textButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+ property public final androidx.compose.foundation.layout.PaddingValues ButtonWithIconContentPadding;
+ property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
+ property public final float IconSize;
+ property public final float IconSpacing;
+ property public final float MinHeight;
+ property public final float MinWidth;
+ property public final androidx.compose.foundation.layout.PaddingValues TextButtonContentPadding;
+ property public final androidx.compose.foundation.layout.PaddingValues TextButtonWithIconContentPadding;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape elevatedShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape filledTonalShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.BorderStroke outlinedButtonBorder;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape outlinedShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape textShape;
+ field public static final androidx.compose.material3.ButtonDefaults INSTANCE;
+ }
+
+ @androidx.compose.runtime.Stable public final class ButtonElevation {
+ }
+
+ public final class ButtonKt {
+ method @androidx.compose.runtime.Composable public static void Button(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void ElevatedButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void FilledTonalButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void OutlinedButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void TextButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ }
+
+ public final class CalendarModelKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static String formatWithSkeleton(long utcTimeMillis, String skeleton, java.util.Locale locale, java.util.Map<java.lang.String,java.lang.Object> cache);
+ }
+
+ public final class CalendarModel_androidKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static String formatWithSkeleton(long utcTimeMillis, String skeleton, java.util.Locale locale, java.util.Map<java.lang.String,java.lang.Object> cache);
+ }
+
+ @androidx.compose.runtime.Immutable public final class CardColors {
+ ctor public CardColors(long containerColor, long contentColor, long disabledContainerColor, long disabledContentColor);
+ method public long getContainerColor();
+ method public long getContentColor();
+ method public long getDisabledContainerColor();
+ method public long getDisabledContentColor();
+ property public final long containerColor;
+ property public final long contentColor;
+ property public final long disabledContainerColor;
+ property public final long disabledContentColor;
+ }
+
+ public final class CardDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.CardColors cardColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.CardElevation cardElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.CardColors elevatedCardColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.CardElevation elevatedCardElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getElevatedShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getOutlinedShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke outlinedCardBorder(optional boolean enabled);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.CardColors outlinedCardColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.CardElevation outlinedCardElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape elevatedShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape outlinedShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ field public static final androidx.compose.material3.CardDefaults INSTANCE;
+ }
+
+ @androidx.compose.runtime.Immutable public final class CardElevation {
+ }
+
+ public final class CardKt {
+ method @androidx.compose.runtime.Composable public static void Card(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.CardColors colors, optional androidx.compose.material3.CardElevation elevation, optional androidx.compose.foundation.BorderStroke? border, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void Card(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.CardColors colors, optional androidx.compose.material3.CardElevation elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void ElevatedCard(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.CardColors colors, optional androidx.compose.material3.CardElevation elevation, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void ElevatedCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.CardColors colors, optional androidx.compose.material3.CardElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void OutlinedCard(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.CardColors colors, optional androidx.compose.material3.CardElevation elevation, optional androidx.compose.foundation.BorderStroke border, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void OutlinedCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.CardColors colors, optional androidx.compose.material3.CardElevation elevation, optional androidx.compose.foundation.BorderStroke border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ }
+
+ @androidx.compose.runtime.Immutable public final class CheckboxColors {
+ ctor public CheckboxColors(long checkedCheckmarkColor, long uncheckedCheckmarkColor, long checkedBoxColor, long uncheckedBoxColor, long disabledCheckedBoxColor, long disabledUncheckedBoxColor, long disabledIndeterminateBoxColor, long checkedBorderColor, long uncheckedBorderColor, long disabledBorderColor, long disabledUncheckedBorderColor, long disabledIndeterminateBorderColor);
+ method public long getCheckedBorderColor();
+ method public long getCheckedBoxColor();
+ method public long getCheckedCheckmarkColor();
+ method public long getDisabledBorderColor();
+ method public long getDisabledCheckedBoxColor();
+ method public long getDisabledIndeterminateBorderColor();
+ method public long getDisabledIndeterminateBoxColor();
+ method public long getDisabledUncheckedBorderColor();
+ method public long getDisabledUncheckedBoxColor();
+ method public long getUncheckedBorderColor();
+ method public long getUncheckedBoxColor();
+ method public long getUncheckedCheckmarkColor();
+ property public final long checkedBorderColor;
+ property public final long checkedBoxColor;
+ property public final long checkedCheckmarkColor;
+ property public final long disabledBorderColor;
+ property public final long disabledCheckedBoxColor;
+ property public final long disabledIndeterminateBorderColor;
+ property public final long disabledIndeterminateBoxColor;
+ property public final long disabledUncheckedBorderColor;
+ property public final long disabledUncheckedBoxColor;
+ property public final long uncheckedBorderColor;
+ property public final long uncheckedBoxColor;
+ property public final long uncheckedCheckmarkColor;
+ }
+
+ public final class CheckboxDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.CheckboxColors colors(optional long checkedColor, optional long uncheckedColor, optional long checkmarkColor, optional long disabledCheckedColor, optional long disabledUncheckedColor, optional long disabledIndeterminateColor);
+ field public static final androidx.compose.material3.CheckboxDefaults INSTANCE;
+ }
+
+ public final class CheckboxKt {
+ method @androidx.compose.runtime.Composable public static void Checkbox(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit>? onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable public static void TriStateCheckbox(androidx.compose.ui.state.ToggleableState state, kotlin.jvm.functions.Function0<kotlin.Unit>? onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ }
+
+ @Deprecated @androidx.compose.runtime.Immutable public final class ChipBorder {
+ }
+
+ @androidx.compose.runtime.Immutable public final class ChipColors {
+ ctor public ChipColors(long containerColor, long labelColor, long leadingIconContentColor, long trailingIconContentColor, long disabledContainerColor, long disabledLabelColor, long disabledLeadingIconContentColor, long disabledTrailingIconContentColor);
+ method public long getContainerColor();
+ method public long getDisabledContainerColor();
+ method public long getDisabledLabelColor();
+ method public long getDisabledLeadingIconContentColor();
+ method public long getDisabledTrailingIconContentColor();
+ method public long getLabelColor();
+ method public long getLeadingIconContentColor();
+ method public long getTrailingIconContentColor();
+ property public final long containerColor;
+ property public final long disabledContainerColor;
+ property public final long disabledLabelColor;
+ property public final long disabledLeadingIconContentColor;
+ property public final long disabledTrailingIconContentColor;
+ property public final long labelColor;
+ property public final long leadingIconContentColor;
+ property public final long trailingIconContentColor;
+ }
+
+ @androidx.compose.runtime.Immutable public final class ChipElevation {
+ ctor public ChipElevation(float elevation, float pressedElevation, float focusedElevation, float hoveredElevation, float draggedElevation, float disabledElevation);
+ method public float getDisabledElevation();
+ method public float getDraggedElevation();
+ method public float getElevation();
+ method public float getFocusedElevation();
+ method public float getHoveredElevation();
+ method public float getPressedElevation();
+ property public final float disabledElevation;
+ property public final float draggedElevation;
+ property public final float elevation;
+ property public final float focusedElevation;
+ property public final float hoveredElevation;
+ property public final float pressedElevation;
+ }
+
+ public final class ChipKt {
+ method @androidx.compose.runtime.Composable public static void AssistChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @Deprecated @androidx.compose.runtime.Composable public static void AssistChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable public static void ElevatedAssistChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @Deprecated @androidx.compose.runtime.Composable public static void ElevatedAssistChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable public static void ElevatedFilterChip(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SelectableChipColors colors, optional androidx.compose.material3.SelectableChipElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable public static void ElevatedSuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @Deprecated @androidx.compose.runtime.Composable public static void ElevatedSuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable public static void FilterChip(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SelectableChipColors colors, optional androidx.compose.material3.SelectableChipElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable public static void InputChip(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? avatar, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SelectableChipColors colors, optional androidx.compose.material3.SelectableChipElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable public static void SuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @Deprecated @androidx.compose.runtime.Composable public static void SuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ }
+
+ @androidx.compose.runtime.Immutable public final class ColorScheme {
+ ctor public ColorScheme(long primary, long onPrimary, long primaryContainer, long onPrimaryContainer, long inversePrimary, long secondary, long onSecondary, long secondaryContainer, long onSecondaryContainer, long tertiary, long onTertiary, long tertiaryContainer, long onTertiaryContainer, long background, long onBackground, long surface, long onSurface, long surfaceVariant, long onSurfaceVariant, long surfaceTint, long inverseSurface, long inverseOnSurface, long error, long onError, long errorContainer, long onErrorContainer, long outline, long outlineVariant, long scrim);
+ ctor public ColorScheme(long primary, long onPrimary, long primaryContainer, long onPrimaryContainer, long inversePrimary, long secondary, long onSecondary, long secondaryContainer, long onSecondaryContainer, long tertiary, long onTertiary, long tertiaryContainer, long onTertiaryContainer, long background, long onBackground, long surface, long onSurface, long surfaceVariant, long onSurfaceVariant, long surfaceTint, long inverseSurface, long inverseOnSurface, long error, long onError, long errorContainer, long onErrorContainer, long outline, long outlineVariant, long scrim, long surfaceBright, long surfaceDim, long surfaceContainer, long surfaceContainerHigh, long surfaceContainerHighest, long surfaceContainerLow, long surfaceContainerLowest);
+ method @Deprecated public androidx.compose.material3.ColorScheme copy(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+ method public androidx.compose.material3.ColorScheme copy(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim, optional long surfaceBright, optional long surfaceDim, optional long surfaceContainer, optional long surfaceContainerHigh, optional long surfaceContainerHighest, optional long surfaceContainerLow, optional long surfaceContainerLowest);
+ method public long getBackground();
+ method public long getError();
+ method public long getErrorContainer();
+ method public long getInverseOnSurface();
+ method public long getInversePrimary();
+ method public long getInverseSurface();
+ method public long getOnBackground();
+ method public long getOnError();
+ method public long getOnErrorContainer();
+ method public long getOnPrimary();
+ method public long getOnPrimaryContainer();
+ method public long getOnSecondary();
+ method public long getOnSecondaryContainer();
+ method public long getOnSurface();
+ method public long getOnSurfaceVariant();
+ method public long getOnTertiary();
+ method public long getOnTertiaryContainer();
+ method public long getOutline();
+ method public long getOutlineVariant();
+ method public long getPrimary();
+ method public long getPrimaryContainer();
+ method public long getScrim();
+ method public long getSecondary();
+ method public long getSecondaryContainer();
+ method public long getSurface();
+ method public long getSurfaceBright();
+ method public long getSurfaceContainer();
+ method public long getSurfaceContainerHigh();
+ method public long getSurfaceContainerHighest();
+ method public long getSurfaceContainerLow();
+ method public long getSurfaceContainerLowest();
+ method public long getSurfaceDim();
+ method public long getSurfaceTint();
+ method public long getSurfaceVariant();
+ method public long getTertiary();
+ method public long getTertiaryContainer();
+ property public final long background;
+ property public final long error;
+ property public final long errorContainer;
+ property public final long inverseOnSurface;
+ property public final long inversePrimary;
+ property public final long inverseSurface;
+ property public final long onBackground;
+ property public final long onError;
+ property public final long onErrorContainer;
+ property public final long onPrimary;
+ property public final long onPrimaryContainer;
+ property public final long onSecondary;
+ property public final long onSecondaryContainer;
+ property public final long onSurface;
+ property public final long onSurfaceVariant;
+ property public final long onTertiary;
+ property public final long onTertiaryContainer;
+ property public final long outline;
+ property public final long outlineVariant;
+ property public final long primary;
+ property public final long primaryContainer;
+ property public final long scrim;
+ property public final long secondary;
+ property public final long secondaryContainer;
+ property public final long surface;
+ property public final long surfaceBright;
+ property public final long surfaceContainer;
+ property public final long surfaceContainerHigh;
+ property public final long surfaceContainerHighest;
+ property public final long surfaceContainerLow;
+ property public final long surfaceContainerLowest;
+ property public final long surfaceDim;
+ property public final long surfaceTint;
+ property public final long surfaceVariant;
+ property public final long tertiary;
+ property public final long tertiaryContainer;
+ }
+
+ public final class ColorSchemeKt {
+ method @androidx.compose.runtime.Stable public static long contentColorFor(androidx.compose.material3.ColorScheme, long backgroundColor);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static long contentColorFor(long backgroundColor);
+ method @Deprecated public static androidx.compose.material3.ColorScheme darkColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+ method public static androidx.compose.material3.ColorScheme darkColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim, optional long surfaceBright, optional long surfaceContainer, optional long surfaceContainerHigh, optional long surfaceContainerHighest, optional long surfaceContainerLow, optional long surfaceContainerLowest, optional long surfaceDim);
+ method public static androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> getLocalTonalElevationEnabled();
+ method @Deprecated public static androidx.compose.material3.ColorScheme lightColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+ method public static androidx.compose.material3.ColorScheme lightColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim, optional long surfaceBright, optional long surfaceContainer, optional long surfaceContainerHigh, optional long surfaceContainerHighest, optional long surfaceContainerLow, optional long surfaceContainerLowest, optional long surfaceDim);
+ method @androidx.compose.runtime.Stable public static long surfaceColorAtElevation(androidx.compose.material3.ColorScheme, float elevation);
+ property public static final androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> LocalTonalElevationEnabled;
+ }
+
+ public final class ContentColorKt {
+ method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.graphics.Color> getLocalContentColor();
+ property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.graphics.Color> LocalContentColor;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class DatePickerColors {
+ ctor public DatePickerColors(long containerColor, long titleContentColor, long headlineContentColor, long weekdayContentColor, long subheadContentColor, long navigationContentColor, long yearContentColor, long disabledYearContentColor, long currentYearContentColor, long selectedYearContentColor, long disabledSelectedYearContentColor, long selectedYearContainerColor, long disabledSelectedYearContainerColor, long dayContentColor, long disabledDayContentColor, long selectedDayContentColor, long disabledSelectedDayContentColor, long selectedDayContainerColor, long disabledSelectedDayContainerColor, long todayContentColor, long todayDateBorderColor, long dayInSelectionRangeContainerColor, long dayInSelectionRangeContentColor, long dividerColor, androidx.compose.material3.TextFieldColors dateTextFieldColors);
+ method public long getContainerColor();
+ method public long getCurrentYearContentColor();
+ method public androidx.compose.material3.TextFieldColors getDateTextFieldColors();
+ method public long getDayContentColor();
+ method public long getDayInSelectionRangeContainerColor();
+ method public long getDayInSelectionRangeContentColor();
+ method public long getDisabledDayContentColor();
+ method public long getDisabledSelectedDayContainerColor();
+ method public long getDisabledSelectedDayContentColor();
+ method public long getDisabledSelectedYearContainerColor();
+ method public long getDisabledSelectedYearContentColor();
+ method public long getDisabledYearContentColor();
+ method public long getDividerColor();
+ method public long getHeadlineContentColor();
+ method public long getNavigationContentColor();
+ method public long getSelectedDayContainerColor();
+ method public long getSelectedDayContentColor();
+ method public long getSelectedYearContainerColor();
+ method public long getSelectedYearContentColor();
+ method public long getSubheadContentColor();
+ method public long getTitleContentColor();
+ method public long getTodayContentColor();
+ method public long getTodayDateBorderColor();
+ method public long getWeekdayContentColor();
+ method public long getYearContentColor();
+ property public final long containerColor;
+ property public final long currentYearContentColor;
+ property public final androidx.compose.material3.TextFieldColors dateTextFieldColors;
+ property public final long dayContentColor;
+ property public final long dayInSelectionRangeContainerColor;
+ property public final long dayInSelectionRangeContentColor;
+ property public final long disabledDayContentColor;
+ property public final long disabledSelectedDayContainerColor;
+ property public final long disabledSelectedDayContentColor;
+ property public final long disabledSelectedYearContainerColor;
+ property public final long disabledSelectedYearContentColor;
+ property public final long disabledYearContentColor;
+ property public final long dividerColor;
+ property public final long headlineContentColor;
+ property public final long navigationContentColor;
+ property public final long selectedDayContainerColor;
+ property public final long selectedDayContentColor;
+ property public final long selectedYearContainerColor;
+ property public final long selectedYearContentColor;
+ property public final long subheadContentColor;
+ property public final long titleContentColor;
+ property public final long todayContentColor;
+ property public final long todayDateBorderColor;
+ property public final long weekdayContentColor;
+ property public final long yearContentColor;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class DatePickerDefaults {
+ method @androidx.compose.runtime.Composable public void DatePickerHeadline(Long? selectedDateMillis, int displayMode, androidx.compose.material3.DatePickerFormatter dateFormatter, optional androidx.compose.ui.Modifier modifier);
+ method @androidx.compose.runtime.Composable public void DatePickerTitle(int displayMode, optional androidx.compose.ui.Modifier modifier);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.DatePickerColors colors(optional long containerColor, optional long titleContentColor, optional long headlineContentColor, optional long weekdayContentColor, optional long subheadContentColor, optional long navigationContentColor, optional long yearContentColor, optional long disabledYearContentColor, optional long currentYearContentColor, optional long selectedYearContentColor, optional long disabledSelectedYearContentColor, optional long selectedYearContainerColor, optional long disabledSelectedYearContainerColor, optional long dayContentColor, optional long disabledDayContentColor, optional long selectedDayContentColor, optional long disabledSelectedDayContentColor, optional long selectedDayContainerColor, optional long disabledSelectedDayContainerColor, optional long todayContentColor, optional long todayDateBorderColor, optional long dayInSelectionRangeContentColor, optional long dayInSelectionRangeContainerColor, optional long dividerColor, optional androidx.compose.material3.TextFieldColors dateTextFieldColors);
+ method public androidx.compose.material3.DatePickerFormatter dateFormatter(optional String yearSelectionSkeleton, optional String selectedDateSkeleton, optional String selectedDateDescriptionSkeleton);
+ method public androidx.compose.material3.SelectableDates getAllDates();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ method public float getTonalElevation();
+ method public kotlin.ranges.IntRange getYearRange();
+ property public final androidx.compose.material3.SelectableDates AllDates;
+ property public final float TonalElevation;
+ property public final kotlin.ranges.IntRange YearRange;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ field public static final androidx.compose.material3.DatePickerDefaults INSTANCE;
+ field public static final String YearAbbrMonthDaySkeleton = "yMMMd";
+ field public static final String YearMonthSkeleton = "yMMMM";
+ field public static final String YearMonthWeekdayDaySkeleton = "yMMMMEEEEd";
+ }
+
+ public final class DatePickerDialog_androidKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void DatePickerDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, kotlin.jvm.functions.Function0<kotlin.Unit> confirmButton, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dismissButton, optional androidx.compose.ui.graphics.Shape shape, optional float tonalElevation, optional androidx.compose.material3.DatePickerColors colors, optional androidx.compose.ui.window.DialogProperties properties, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public interface DatePickerFormatter {
+ method public String? formatDate(Long? dateMillis, java.util.Locale locale, optional boolean forContentDescription);
+ method public String? formatMonthYear(Long? monthMillis, java.util.Locale locale);
+ }
+
+ public final class DatePickerKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void DatePicker(androidx.compose.material3.DatePickerState state, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.DatePickerFormatter dateFormatter, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? headline, optional boolean showModeToggle, optional androidx.compose.material3.DatePickerColors colors);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static androidx.compose.material3.DatePickerState DatePickerState(java.util.Locale locale, optional Long? initialSelectedDateMillis, optional Long? initialDisplayedMonthMillis, optional kotlin.ranges.IntRange yearRange, optional int initialDisplayMode, optional androidx.compose.material3.SelectableDates selectableDates);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.DatePickerState rememberDatePickerState(optional Long? initialSelectedDateMillis, optional Long? initialDisplayedMonthMillis, optional kotlin.ranges.IntRange yearRange, optional int initialDisplayMode, optional androidx.compose.material3.SelectableDates selectableDates);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public interface DatePickerState {
+ method public int getDisplayMode();
+ method public long getDisplayedMonthMillis();
+ method public androidx.compose.material3.SelectableDates getSelectableDates();
+ method public Long? getSelectedDateMillis();
+ method public kotlin.ranges.IntRange getYearRange();
+ method public void setDisplayMode(int);
+ method public void setDisplayedMonthMillis(long);
+ method public void setSelectedDateMillis(Long?);
+ property public abstract int displayMode;
+ property public abstract long displayedMonthMillis;
+ property public abstract androidx.compose.material3.SelectableDates selectableDates;
+ property public abstract Long? selectedDateMillis;
+ property public abstract kotlin.ranges.IntRange yearRange;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class DateRangePickerDefaults {
+ method @androidx.compose.runtime.Composable public void DateRangePickerHeadline(Long? selectedStartDateMillis, Long? selectedEndDateMillis, int displayMode, androidx.compose.material3.DatePickerFormatter dateFormatter, optional androidx.compose.ui.Modifier modifier);
+ method @androidx.compose.runtime.Composable public void DateRangePickerTitle(int displayMode, optional androidx.compose.ui.Modifier modifier);
+ field public static final androidx.compose.material3.DateRangePickerDefaults INSTANCE;
+ }
+
+ public final class DateRangePickerKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void DateRangePicker(androidx.compose.material3.DateRangePickerState state, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.DatePickerFormatter dateFormatter, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? headline, optional boolean showModeToggle, optional androidx.compose.material3.DatePickerColors colors);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static androidx.compose.material3.DateRangePickerState DateRangePickerState(java.util.Locale locale, optional Long? initialSelectedStartDateMillis, optional Long? initialSelectedEndDateMillis, optional Long? initialDisplayedMonthMillis, optional kotlin.ranges.IntRange yearRange, optional int initialDisplayMode, optional androidx.compose.material3.SelectableDates selectableDates);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.DateRangePickerState rememberDateRangePickerState(optional Long? initialSelectedStartDateMillis, optional Long? initialSelectedEndDateMillis, optional Long? initialDisplayedMonthMillis, optional kotlin.ranges.IntRange yearRange, optional int initialDisplayMode, optional androidx.compose.material3.SelectableDates selectableDates);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public interface DateRangePickerState {
+ method public int getDisplayMode();
+ method public long getDisplayedMonthMillis();
+ method public androidx.compose.material3.SelectableDates getSelectableDates();
+ method public Long? getSelectedEndDateMillis();
+ method public Long? getSelectedStartDateMillis();
+ method public kotlin.ranges.IntRange getYearRange();
+ method public void setDisplayMode(int);
+ method public void setDisplayedMonthMillis(long);
+ method public void setSelection(Long? startDateMillis, Long? endDateMillis);
+ property public abstract int displayMode;
+ property public abstract long displayedMonthMillis;
+ property public abstract androidx.compose.material3.SelectableDates selectableDates;
+ property public abstract Long? selectedEndDateMillis;
+ property public abstract Long? selectedStartDateMillis;
+ property public abstract kotlin.ranges.IntRange yearRange;
+ }
+
+ @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum DismissDirection {
+ method @Deprecated public static androidx.compose.material3.DismissDirection valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method @Deprecated public static androidx.compose.material3.DismissDirection[] values();
+ enum_constant @Deprecated public static final androidx.compose.material3.DismissDirection EndToStart;
+ enum_constant @Deprecated public static final androidx.compose.material3.DismissDirection StartToEnd;
+ }
+
+ @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum DismissValue {
+ method @Deprecated public static androidx.compose.material3.DismissValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method @Deprecated public static androidx.compose.material3.DismissValue[] values();
+ enum_constant @Deprecated public static final androidx.compose.material3.DismissValue Default;
+ enum_constant @Deprecated public static final androidx.compose.material3.DismissValue DismissedToEnd;
+ enum_constant @Deprecated public static final androidx.compose.material3.DismissValue DismissedToStart;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class DisplayMode {
+ field public static final androidx.compose.material3.DisplayMode.Companion Companion;
+ }
+
+ public static final class DisplayMode.Companion {
+ method public int getInput();
+ method public int getPicker();
+ property public final int Input;
+ property public final int Picker;
+ }
+
+ public final class DividerDefaults {
+ method @androidx.compose.runtime.Composable public long getColor();
+ method public float getThickness();
+ property public final float Thickness;
+ property @androidx.compose.runtime.Composable public final long color;
+ field public static final androidx.compose.material3.DividerDefaults INSTANCE;
+ }
+
+ public final class DividerKt {
+ method @Deprecated @androidx.compose.runtime.Composable public static void Divider(optional androidx.compose.ui.Modifier modifier, optional float thickness, optional long color);
+ method @androidx.compose.runtime.Composable public static void HorizontalDivider(optional androidx.compose.ui.Modifier modifier, optional float thickness, optional long color);
+ method @androidx.compose.runtime.Composable public static void VerticalDivider(optional androidx.compose.ui.Modifier modifier, optional float thickness, optional long color);
+ }
+
+ public final class DrawerDefaults {
+ method @androidx.compose.runtime.Composable public long getContainerColor();
+ method public float getDismissibleDrawerElevation();
+ method public float getMaximumDrawerWidth();
+ method public float getModalDrawerElevation();
+ method public float getPermanentDrawerElevation();
+ method @androidx.compose.runtime.Composable public long getScrimColor();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+ property public final float DismissibleDrawerElevation;
+ property public final float MaximumDrawerWidth;
+ property public final float ModalDrawerElevation;
+ property public final float PermanentDrawerElevation;
+ property @androidx.compose.runtime.Composable public final long containerColor;
+ property @androidx.compose.runtime.Composable public final long scrimColor;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+ field public static final androidx.compose.material3.DrawerDefaults INSTANCE;
+ }
+
+ @androidx.compose.runtime.Stable public final class DrawerState {
+ ctor public DrawerState(androidx.compose.material3.DrawerValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.DrawerValue,java.lang.Boolean> confirmStateChange);
+ method @Deprecated public suspend Object? animateTo(androidx.compose.material3.DrawerValue targetValue, androidx.compose.animation.core.AnimationSpec<java.lang.Float> anim, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public suspend Object? close(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public float getCurrentOffset();
+ method public androidx.compose.material3.DrawerValue getCurrentValue();
+ method @Deprecated public androidx.compose.runtime.State<java.lang.Float> getOffset();
+ method public androidx.compose.material3.DrawerValue getTargetValue();
+ method public boolean isAnimationRunning();
+ method public boolean isClosed();
+ method public boolean isOpen();
+ method public suspend Object? open(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public suspend Object? snapTo(androidx.compose.material3.DrawerValue targetValue, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ property public final float currentOffset;
+ property public final androidx.compose.material3.DrawerValue currentValue;
+ property public final boolean isAnimationRunning;
+ property public final boolean isClosed;
+ property public final boolean isOpen;
+ property @Deprecated public final androidx.compose.runtime.State<java.lang.Float> offset;
+ property public final androidx.compose.material3.DrawerValue targetValue;
+ field public static final androidx.compose.material3.DrawerState.Companion Companion;
+ }
+
+ public static final class DrawerState.Companion {
+ method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.DrawerState,androidx.compose.material3.DrawerValue> Saver(kotlin.jvm.functions.Function1<? super androidx.compose.material3.DrawerValue,java.lang.Boolean> confirmStateChange);
+ }
+
+ public enum DrawerValue {
+ method public static androidx.compose.material3.DrawerValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.compose.material3.DrawerValue[] values();
+ enum_constant public static final androidx.compose.material3.DrawerValue Closed;
+ enum_constant public static final androidx.compose.material3.DrawerValue Open;
+ }
+
+ public final class DynamicTonalPaletteKt {
+ method @RequiresApi(android.os.Build.VERSION_CODES.S) public static androidx.compose.material3.ColorScheme dynamicDarkColorScheme(android.content.Context context);
+ method @RequiresApi(android.os.Build.VERSION_CODES.S) public static androidx.compose.material3.ColorScheme dynamicLightColorScheme(android.content.Context context);
+ }
+
+ @SuppressCompatibility @kotlin.RequiresOptIn(message="This material API is experimental and is likely to change or to be removed in" + " the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalMaterial3Api {
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public interface ExposedDropdownMenuBoxScope {
+ method @androidx.compose.runtime.Composable public default void ExposedDropdownMenu(boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.ScrollState scrollState, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method public androidx.compose.ui.Modifier exposedDropdownSize(androidx.compose.ui.Modifier, optional boolean matchTextFieldWidth);
+ method public androidx.compose.ui.Modifier menuAnchor(androidx.compose.ui.Modifier);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class ExposedDropdownMenuDefaults {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void TrailingIcon(boolean expanded);
+ method public androidx.compose.foundation.layout.PaddingValues getItemContentPadding();
+ method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor);
+ method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long containerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long focusedContainerColor, optional long unfocusedContainerColor, optional long disabledContainerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+ method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor);
+ method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long containerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long focusedContainerColor, optional long unfocusedContainerColor, optional long disabledContainerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+ property public final androidx.compose.foundation.layout.PaddingValues ItemContentPadding;
+ field public static final androidx.compose.material3.ExposedDropdownMenuDefaults INSTANCE;
+ }
+
+ public final class ExposedDropdownMenu_androidKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void ExposedDropdownMenuBox(boolean expanded, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onExpandedChange, optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function1<? super androidx.compose.material3.ExposedDropdownMenuBoxScope,kotlin.Unit> content);
+ }
+
+ @kotlin.jvm.JvmInline public final value class FabPosition {
+ field public static final androidx.compose.material3.FabPosition.Companion Companion;
+ }
+
+ public static final class FabPosition.Companion {
+ method public int getCenter();
+ method public int getEnd();
+ method public int getEndOverlay();
+ method public int getStart();
+ property public final int Center;
+ property public final int End;
+ property public final int EndOverlay;
+ property public final int Start;
+ }
+
+ public final class FilterChipDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipColors elevatedFilterChipColors(optional long containerColor, optional long labelColor, optional long iconColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconColor, optional long disabledTrailingIconColor, optional long selectedContainerColor, optional long disabledSelectedContainerColor, optional long selectedLabelColor, optional long selectedLeadingIconColor, optional long selectedTrailingIconColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipElevation elevatedFilterChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke filterChipBorder(boolean enabled, boolean selected, optional long borderColor, optional long selectedBorderColor, optional long disabledBorderColor, optional long disabledSelectedBorderColor, optional float borderWidth, optional float selectedBorderWidth);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipColors filterChipColors(optional long containerColor, optional long labelColor, optional long iconColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconColor, optional long disabledTrailingIconColor, optional long selectedContainerColor, optional long disabledSelectedContainerColor, optional long selectedLabelColor, optional long selectedLeadingIconColor, optional long selectedTrailingIconColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipElevation filterChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+ method public float getHeight();
+ method public float getIconSize();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ property public final float Height;
+ property public final float IconSize;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ field public static final androidx.compose.material3.FilterChipDefaults INSTANCE;
+ }
+
+ public final class FloatingActionButtonDefaults {
+ method public androidx.compose.material3.FloatingActionButtonElevation bottomAppBarFabElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.FloatingActionButtonElevation elevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation);
+ method @androidx.compose.runtime.Composable public long getContainerColor();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getExtendedFabShape();
+ method public float getLargeIconSize();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getLargeShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getSmallShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.FloatingActionButtonElevation loweredElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation);
+ property public final float LargeIconSize;
+ property @androidx.compose.runtime.Composable public final long containerColor;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape extendedFabShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape largeShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape smallShape;
+ field public static final androidx.compose.material3.FloatingActionButtonDefaults INSTANCE;
+ }
+
+ @androidx.compose.runtime.Stable public class FloatingActionButtonElevation {
+ }
+
+ public final class FloatingActionButtonKt {
+ method @androidx.compose.runtime.Composable public static void ExtendedFloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void ExtendedFloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> text, kotlin.jvm.functions.Function0<kotlin.Unit> icon, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean expanded, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable public static void FloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void LargeFloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void SmallFloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ }
+
+ @androidx.compose.runtime.Immutable public final class IconButtonColors {
+ ctor public IconButtonColors(long containerColor, long contentColor, long disabledContainerColor, long disabledContentColor);
+ method public long getContainerColor();
+ method public long getContentColor();
+ method public long getDisabledContainerColor();
+ method public long getDisabledContentColor();
+ property public final long containerColor;
+ property public final long contentColor;
+ property public final long disabledContainerColor;
+ property public final long disabledContentColor;
+ }
+
+ public final class IconButtonDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors filledIconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors filledIconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors filledTonalIconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors filledTonalIconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFilledShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getOutlinedShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors iconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors iconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke outlinedIconButtonBorder(boolean enabled);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors outlinedIconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke? outlinedIconToggleButtonBorder(boolean enabled, boolean checked);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors outlinedIconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape filledShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape outlinedShape;
+ field public static final androidx.compose.material3.IconButtonDefaults INSTANCE;
+ }
+
+ public final class IconButtonKt {
+ method @androidx.compose.runtime.Composable public static void FilledIconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.IconButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void FilledIconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.IconToggleButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void FilledTonalIconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.IconButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void FilledTonalIconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.IconToggleButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.IconButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.IconToggleButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void OutlinedIconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.IconButtonColors colors, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void OutlinedIconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.IconToggleButtonColors colors, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ }
+
+ public final class IconKt {
+ method @androidx.compose.runtime.Composable public static void Icon(androidx.compose.ui.graphics.ImageBitmap bitmap, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional long tint);
+ method @androidx.compose.runtime.Composable public static void Icon(androidx.compose.ui.graphics.painter.Painter painter, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional long tint);
+ method @androidx.compose.runtime.Composable public static void Icon(androidx.compose.ui.graphics.vector.ImageVector imageVector, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional long tint);
+ }
+
+ @androidx.compose.runtime.Immutable public final class IconToggleButtonColors {
+ ctor public IconToggleButtonColors(long containerColor, long contentColor, long disabledContainerColor, long disabledContentColor, long checkedContainerColor, long checkedContentColor);
+ method public long getCheckedContainerColor();
+ method public long getCheckedContentColor();
+ method public long getContainerColor();
+ method public long getContentColor();
+ method public long getDisabledContainerColor();
+ method public long getDisabledContentColor();
+ property public final long checkedContainerColor;
+ property public final long checkedContentColor;
+ property public final long containerColor;
+ property public final long contentColor;
+ property public final long disabledContainerColor;
+ property public final long disabledContentColor;
+ }
+
+ public final class InputChipDefaults {
+ method public float getAvatarSize();
+ method public float getHeight();
+ method public float getIconSize();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke inputChipBorder(boolean enabled, boolean selected, optional long borderColor, optional long selectedBorderColor, optional long disabledBorderColor, optional long disabledSelectedBorderColor, optional float borderWidth, optional float selectedBorderWidth);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipColors inputChipColors(optional long containerColor, optional long labelColor, optional long leadingIconColor, optional long trailingIconColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconColor, optional long disabledTrailingIconColor, optional long selectedContainerColor, optional long disabledSelectedContainerColor, optional long selectedLabelColor, optional long selectedLeadingIconColor, optional long selectedTrailingIconColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipElevation inputChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+ property public final float AvatarSize;
+ property public final float Height;
+ property public final float IconSize;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ field public static final androidx.compose.material3.InputChipDefaults INSTANCE;
+ }
+
+ public final class InteractiveComponentSizeKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> getLocalMinimumInteractiveComponentEnforcement();
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> getLocalMinimumTouchTargetEnforcement();
+ method @androidx.compose.runtime.Stable public static androidx.compose.ui.Modifier minimumInteractiveComponentSize(androidx.compose.ui.Modifier);
+ property @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static final androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> LocalMinimumInteractiveComponentEnforcement;
+ property @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static final androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> LocalMinimumTouchTargetEnforcement;
+ }
+
+ public final class LabelKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void Label(kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional boolean isPersistent, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ }
+
+ @androidx.compose.runtime.Immutable public final class ListItemColors {
+ ctor public ListItemColors(long containerColor, long headlineColor, long leadingIconColor, long overlineColor, long supportingTextColor, long trailingIconColor, long disabledHeadlineColor, long disabledLeadingIconColor, long disabledTrailingIconColor);
+ method public long getContainerColor();
+ method public long getDisabledHeadlineColor();
+ method public long getDisabledLeadingIconColor();
+ method public long getDisabledTrailingIconColor();
+ method public long getHeadlineColor();
+ method public long getLeadingIconColor();
+ method public long getOverlineColor();
+ method public long getSupportingTextColor();
+ method public long getTrailingIconColor();
+ property public final long containerColor;
+ property public final long disabledHeadlineColor;
+ property public final long disabledLeadingIconColor;
+ property public final long disabledTrailingIconColor;
+ property public final long headlineColor;
+ property public final long leadingIconColor;
+ property public final long overlineColor;
+ property public final long supportingTextColor;
+ property public final long trailingIconColor;
+ }
+
+ public final class ListItemDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ListItemColors colors(optional long containerColor, optional long headlineColor, optional long leadingIconColor, optional long overlineColor, optional long supportingColor, optional long trailingIconColor, optional long disabledHeadlineColor, optional long disabledLeadingIconColor, optional long disabledTrailingIconColor);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public long getContainerColor();
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public long getContentColor();
+ method public float getElevation();
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.ui.graphics.Shape getShape();
+ property public final float Elevation;
+ property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final long containerColor;
+ property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final long contentColor;
+ property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.ui.graphics.Shape shape;
+ field public static final androidx.compose.material3.ListItemDefaults INSTANCE;
+ }
+
+ public final class ListItemKt {
+ method @androidx.compose.runtime.Composable public static void ListItem(kotlin.jvm.functions.Function0<kotlin.Unit> headlineContent, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? overlineContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingContent, optional androidx.compose.material3.ListItemColors colors, optional float tonalElevation, optional float shadowElevation);
+ }
+
+ public final class MaterialTheme {
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.material3.ColorScheme getColorScheme();
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.material3.Shapes getShapes();
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.material3.Typography getTypography();
+ property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.material3.ColorScheme colorScheme;
+ property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.material3.Shapes shapes;
+ property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.material3.Typography typography;
+ field public static final androidx.compose.material3.MaterialTheme INSTANCE;
+ }
+
+ public final class MaterialThemeKt {
+ method @androidx.compose.runtime.Composable public static void MaterialTheme(optional androidx.compose.material3.ColorScheme colorScheme, optional androidx.compose.material3.Shapes shapes, optional androidx.compose.material3.Typography typography, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ }
+
+ public final class MenuDefaults {
+ method public androidx.compose.foundation.layout.PaddingValues getDropdownMenuItemContentPadding();
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.MenuItemColors itemColors(optional long textColor, optional long leadingIconColor, optional long trailingIconColor, optional long disabledTextColor, optional long disabledLeadingIconColor, optional long disabledTrailingIconColor);
+ property public final androidx.compose.foundation.layout.PaddingValues DropdownMenuItemContentPadding;
+ field public static final androidx.compose.material3.MenuDefaults INSTANCE;
+ }
+
+ @androidx.compose.runtime.Immutable public final class MenuItemColors {
+ ctor public MenuItemColors(long textColor, long leadingIconColor, long trailingIconColor, long disabledTextColor, long disabledLeadingIconColor, long disabledTrailingIconColor);
+ method public long getDisabledLeadingIconColor();
+ method public long getDisabledTextColor();
+ method public long getDisabledTrailingIconColor();
+ method public long getLeadingIconColor();
+ method public long getTextColor();
+ method public long getTrailingIconColor();
+ property public final long disabledLeadingIconColor;
+ property public final long disabledTextColor;
+ property public final long disabledTrailingIconColor;
+ property public final long leadingIconColor;
+ property public final long textColor;
+ property public final long trailingIconColor;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class ModalBottomSheetDefaults {
+ method public androidx.compose.material3.ModalBottomSheetProperties properties(optional androidx.compose.ui.window.SecureFlagPolicy securePolicy, optional boolean isFocusable, optional boolean shouldDismissOnBackPress);
+ field public static final androidx.compose.material3.ModalBottomSheetDefaults INSTANCE;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class ModalBottomSheetProperties {
+ ctor public ModalBottomSheetProperties(androidx.compose.ui.window.SecureFlagPolicy securePolicy, boolean isFocusable, boolean shouldDismissOnBackPress);
+ method public androidx.compose.ui.window.SecureFlagPolicy getSecurePolicy();
+ method public boolean getShouldDismissOnBackPress();
+ method public boolean isFocusable();
+ property public final boolean isFocusable;
+ property public final androidx.compose.ui.window.SecureFlagPolicy securePolicy;
+ property public final boolean shouldDismissOnBackPress;
+ }
+
+ public final class ModalBottomSheet_androidKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void ModalBottomSheet(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SheetState sheetState, optional float sheetMaxWidth, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional float tonalElevation, optional long scrimColor, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dragHandle, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.ModalBottomSheetProperties properties, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.SheetState rememberModalBottomSheetState(optional boolean skipPartiallyExpanded, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public interface MultiChoiceSegmentedButtonRowScope extends androidx.compose.foundation.layout.RowScope {
+ }
+
+ public final class NavigationBarDefaults {
+ method @androidx.compose.runtime.Composable public long getContainerColor();
+ method public float getElevation();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+ property public final float Elevation;
+ property @androidx.compose.runtime.Composable public final long containerColor;
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+ field public static final androidx.compose.material3.NavigationBarDefaults INSTANCE;
+ }
+
+ @androidx.compose.runtime.Stable public final class NavigationBarItemColors {
+ ctor public NavigationBarItemColors(long selectedIconColor, long selectedTextColor, long selectedIndicatorColor, long unselectedIconColor, long unselectedTextColor, long disabledIconColor, long disabledTextColor);
+ method public long getDisabledIconColor();
+ method public long getDisabledTextColor();
+ method public long getSelectedIconColor();
+ method public long getSelectedIndicatorColor();
+ method public long getSelectedTextColor();
+ method public long getUnselectedIconColor();
+ method public long getUnselectedTextColor();
+ property public final long disabledIconColor;
+ property public final long disabledTextColor;
+ property public final long selectedIconColor;
+ property public final long selectedIndicatorColor;
+ property public final long selectedTextColor;
+ property public final long unselectedIconColor;
+ property public final long unselectedTextColor;
+ }
+
+ public final class NavigationBarItemDefaults {
+ method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationBarItemColors colors(optional long selectedIconColor, optional long selectedTextColor, optional long indicatorColor, optional long unselectedIconColor, optional long unselectedTextColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationBarItemColors colors(optional long selectedIconColor, optional long selectedTextColor, optional long indicatorColor, optional long unselectedIconColor, optional long unselectedTextColor, optional long disabledIconColor, optional long disabledTextColor);
+ field public static final androidx.compose.material3.NavigationBarItemDefaults INSTANCE;
+ }
+
+ public final class NavigationBarKt {
+ method @androidx.compose.runtime.Composable public static void NavigationBar(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void NavigationBarItem(androidx.compose.foundation.layout.RowScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional boolean alwaysShowLabel, optional androidx.compose.material3.NavigationBarItemColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ }
+
+ @androidx.compose.runtime.Stable public interface NavigationDrawerItemColors {
+ method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> badgeColor(boolean selected);
+ method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> containerColor(boolean selected);
+ method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> iconColor(boolean selected);
+ method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> textColor(boolean selected);
+ }
+
+ public final class NavigationDrawerItemDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationDrawerItemColors colors(optional long selectedContainerColor, optional long unselectedContainerColor, optional long selectedIconColor, optional long unselectedIconColor, optional long selectedTextColor, optional long unselectedTextColor, optional long selectedBadgeColor, optional long unselectedBadgeColor);
+ method public androidx.compose.foundation.layout.PaddingValues getItemPadding();
+ property public final androidx.compose.foundation.layout.PaddingValues ItemPadding;
+ field public static final androidx.compose.material3.NavigationDrawerItemDefaults INSTANCE;
+ }
+
+ public final class NavigationDrawerKt {
+ method @androidx.compose.runtime.Composable public static void DismissibleDrawerSheet(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape drawerShape, optional long drawerContainerColor, optional long drawerContentColor, optional float drawerTonalElevation, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void DismissibleNavigationDrawer(kotlin.jvm.functions.Function0<kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.DrawerState drawerState, optional boolean gesturesEnabled, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void ModalDrawerSheet(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape drawerShape, optional long drawerContainerColor, optional long drawerContentColor, optional float drawerTonalElevation, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void ModalNavigationDrawer(kotlin.jvm.functions.Function0<kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.DrawerState drawerState, optional boolean gesturesEnabled, optional long scrimColor, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void NavigationDrawerItem(kotlin.jvm.functions.Function0<kotlin.Unit> label, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? badge, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.NavigationDrawerItemColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable public static void PermanentDrawerSheet(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape drawerShape, optional long drawerContainerColor, optional long drawerContentColor, optional float drawerTonalElevation, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void PermanentNavigationDrawer(kotlin.jvm.functions.Function0<kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static androidx.compose.material3.DrawerState rememberDrawerState(androidx.compose.material3.DrawerValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.DrawerValue,java.lang.Boolean> confirmStateChange);
+ }
+
+ public final class NavigationRailDefaults {
+ method @androidx.compose.runtime.Composable public long getContainerColor();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+ property @androidx.compose.runtime.Composable public final long ContainerColor;
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+ field public static final androidx.compose.material3.NavigationRailDefaults INSTANCE;
+ }
+
+ @androidx.compose.runtime.Stable public final class NavigationRailItemColors {
+ ctor public NavigationRailItemColors(long selectedIconColor, long selectedTextColor, long selectedIndicatorColor, long unselectedIconColor, long unselectedTextColor, long disabledIconColor, long disabledTextColor);
+ method public long getDisabledIconColor();
+ method public long getDisabledTextColor();
+ method public long getSelectedIconColor();
+ method public long getSelectedIndicatorColor();
+ method public long getSelectedTextColor();
+ method public long getUnselectedIconColor();
+ method public long getUnselectedTextColor();
+ property public final long disabledIconColor;
+ property public final long disabledTextColor;
+ property public final long selectedIconColor;
+ property public final long selectedIndicatorColor;
+ property public final long selectedTextColor;
+ property public final long unselectedIconColor;
+ property public final long unselectedTextColor;
+ }
+
+ public final class NavigationRailItemDefaults {
+ method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationRailItemColors colors(optional long selectedIconColor, optional long selectedTextColor, optional long indicatorColor, optional long unselectedIconColor, optional long unselectedTextColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationRailItemColors colors(optional long selectedIconColor, optional long selectedTextColor, optional long indicatorColor, optional long unselectedIconColor, optional long unselectedTextColor, optional long disabledIconColor, optional long disabledTextColor);
+ field public static final androidx.compose.material3.NavigationRailItemDefaults INSTANCE;
+ }
+
+ public final class NavigationRailKt {
+ method @androidx.compose.runtime.Composable public static void NavigationRail(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? header, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void NavigationRailItem(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional boolean alwaysShowLabel, optional androidx.compose.material3.NavigationRailItemColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ }
+
+ @androidx.compose.runtime.Immutable public final class OutlinedTextFieldDefaults {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void ContainerBox(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional androidx.compose.ui.graphics.Shape shape, optional float focusedBorderThickness, optional float unfocusedBorderThickness);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void DecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors colors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long focusedContainerColor, optional long unfocusedContainerColor, optional long disabledContainerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+ method public androidx.compose.foundation.layout.PaddingValues contentPadding(optional float start, optional float top, optional float end, optional float bottom);
+ method public float getFocusedBorderThickness();
+ method public float getMinHeight();
+ method public float getMinWidth();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ method public float getUnfocusedBorderThickness();
+ property public final float FocusedBorderThickness;
+ property public final float MinHeight;
+ property public final float MinWidth;
+ property public final float UnfocusedBorderThickness;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ field public static final androidx.compose.material3.OutlinedTextFieldDefaults INSTANCE;
+ }
+
+ public final class OutlinedTextFieldKt {
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void OutlinedTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+ method @androidx.compose.runtime.Composable public static void OutlinedTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void OutlinedTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+ method @androidx.compose.runtime.Composable public static void OutlinedTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+ }
+
+ @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public interface PlainTooltipState extends androidx.compose.material3.BasicTooltipState {
+ }
+
+ public final class ProgressIndicatorDefaults {
+ method @androidx.compose.runtime.Composable public long getCircularColor();
+ method public int getCircularDeterminateStrokeCap();
+ method public int getCircularIndeterminateStrokeCap();
+ method public float getCircularStrokeWidth();
+ method @androidx.compose.runtime.Composable public long getCircularTrackColor();
+ method @androidx.compose.runtime.Composable public long getLinearColor();
+ method public int getLinearStrokeCap();
+ method @androidx.compose.runtime.Composable public long getLinearTrackColor();
+ method public androidx.compose.animation.core.SpringSpec<java.lang.Float> getProgressAnimationSpec();
+ property public final int CircularDeterminateStrokeCap;
+ property public final int CircularIndeterminateStrokeCap;
+ property public final float CircularStrokeWidth;
+ property public final int LinearStrokeCap;
+ property public final androidx.compose.animation.core.SpringSpec<java.lang.Float> ProgressAnimationSpec;
+ property @androidx.compose.runtime.Composable public final long circularColor;
+ property @androidx.compose.runtime.Composable public final long circularTrackColor;
+ property @androidx.compose.runtime.Composable public final long linearColor;
+ property @androidx.compose.runtime.Composable public final long linearTrackColor;
+ field public static final androidx.compose.material3.ProgressIndicatorDefaults INSTANCE;
+ }
+
+ public final class ProgressIndicatorKt {
+ method @Deprecated @androidx.compose.runtime.Composable public static void CircularProgressIndicator(optional androidx.compose.ui.Modifier modifier, optional long color, optional float strokeWidth);
+ method @androidx.compose.runtime.Composable public static void CircularProgressIndicator(optional androidx.compose.ui.Modifier modifier, optional long color, optional float strokeWidth, optional long trackColor, optional int strokeCap);
+ method @Deprecated @androidx.compose.runtime.Composable public static void CircularProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional float strokeWidth);
+ method @Deprecated @androidx.compose.runtime.Composable public static void CircularProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional float strokeWidth, optional long trackColor, optional int strokeCap);
+ method @androidx.compose.runtime.Composable public static void CircularProgressIndicator(kotlin.jvm.functions.Function0<java.lang.Float> progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional float strokeWidth, optional long trackColor, optional int strokeCap);
+ method @Deprecated @androidx.compose.runtime.Composable public static void LinearProgressIndicator(optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor);
+ method @androidx.compose.runtime.Composable public static void LinearProgressIndicator(optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor, optional int strokeCap);
+ method @Deprecated @androidx.compose.runtime.Composable public static void LinearProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor);
+ method @Deprecated @androidx.compose.runtime.Composable public static void LinearProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor, optional int strokeCap);
+ method @androidx.compose.runtime.Composable public static void LinearProgressIndicator(kotlin.jvm.functions.Function0<java.lang.Float> progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor, optional int strokeCap);
+ }
+
+ @androidx.compose.runtime.Immutable public final class RadioButtonColors {
+ ctor public RadioButtonColors(long selectedColor, long unselectedColor, long disabledSelectedColor, long disabledUnselectedColor);
+ method public long getDisabledSelectedColor();
+ method public long getDisabledUnselectedColor();
+ method public long getSelectedColor();
+ method public long getUnselectedColor();
+ property public final long disabledSelectedColor;
+ property public final long disabledUnselectedColor;
+ property public final long selectedColor;
+ property public final long unselectedColor;
+ }
+
+ public final class RadioButtonDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.RadioButtonColors colors(optional long selectedColor, optional long unselectedColor, optional long disabledSelectedColor, optional long disabledUnselectedColor);
+ field public static final androidx.compose.material3.RadioButtonDefaults INSTANCE;
+ }
+
+ public final class RadioButtonKt {
+ method @androidx.compose.runtime.Composable public static void RadioButton(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit>? onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.RadioButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class RangeSliderState {
+ ctor public RangeSliderState(optional float activeRangeStart, optional float activeRangeEnd, optional @IntRange(from=0L) int steps, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange);
+ method public float getActiveRangeEnd();
+ method public float getActiveRangeStart();
+ method public kotlin.jvm.functions.Function0<kotlin.Unit>? getOnValueChangeFinished();
+ method public int getSteps();
+ method public kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> getValueRange();
+ method public void setActiveRangeEnd(float);
+ method public void setActiveRangeStart(float);
+ property public final float activeRangeEnd;
+ property public final float activeRangeStart;
+ property public final kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished;
+ property public final int steps;
+ property public final kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable @androidx.compose.runtime.Stable public final class RichTooltipColors {
+ ctor public RichTooltipColors(long containerColor, long contentColor, long titleContentColor, long actionContentColor);
+ method public long getActionContentColor();
+ method public long getContainerColor();
+ method public long getContentColor();
+ method public long getTitleContentColor();
+ property public final long actionContentColor;
+ property public final long containerColor;
+ property public final long contentColor;
+ property public final long titleContentColor;
+ }
+
+ @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public interface RichTooltipState extends androidx.compose.material3.BasicTooltipState {
+ }
+
+ public final class ScaffoldDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getContentWindowInsets();
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets contentWindowInsets;
+ field public static final androidx.compose.material3.ScaffoldDefaults INSTANCE;
+ }
+
+ public final class ScaffoldKt {
+ method @androidx.compose.runtime.Composable public static void Scaffold(optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> topBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> bottomBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit> floatingActionButton, optional int floatingActionButtonPosition, optional long containerColor, optional long contentColor, optional androidx.compose.foundation.layout.WindowInsets contentWindowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static boolean getScaffoldSubcomposeInMeasureFix();
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static void setScaffoldSubcomposeInMeasureFix(boolean);
+ property @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static final boolean ScaffoldSubcomposeInMeasureFix;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class SearchBarColors {
+ method public long getContainerColor();
+ method public long getDividerColor();
+ method public androidx.compose.material3.TextFieldColors getInputFieldColors();
+ property public final long containerColor;
+ property public final long dividerColor;
+ property public final androidx.compose.material3.TextFieldColors inputFieldColors;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class SearchBarDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.SearchBarColors colors(optional long containerColor, optional long dividerColor, optional androidx.compose.material3.TextFieldColors inputFieldColors);
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getDockedShape();
+ method @Deprecated public float getElevation();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFullScreenShape();
+ method public float getInputFieldHeight();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getInputFieldShape();
+ method public float getShadowElevation();
+ method public float getTonalElevation();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+ method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors inputFieldColors(optional long textColor, optional long disabledTextColor, optional long cursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long placeholderColor, optional long disabledPlaceholderColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors inputFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long cursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor);
+ property @Deprecated public final float Elevation;
+ property public final float InputFieldHeight;
+ property public final float ShadowElevation;
+ property public final float TonalElevation;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape dockedShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape fullScreenShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape inputFieldShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+ field public static final androidx.compose.material3.SearchBarDefaults INSTANCE;
+ }
+
+ public final class SearchBar_androidKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void DockedSearchBar(String query, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onQueryChange, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onSearch, boolean active, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onActiveChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SearchBarColors colors, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SearchBar(String query, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onQueryChange, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onSearch, boolean active, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onActiveChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SearchBarColors colors, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class SegmentedButtonColors {
+ ctor public SegmentedButtonColors(long activeContainerColor, long activeContentColor, long activeBorderColor, long inactiveContainerColor, long inactiveContentColor, long inactiveBorderColor, long disabledActiveContainerColor, long disabledActiveContentColor, long disabledActiveBorderColor, long disabledInactiveContainerColor, long disabledInactiveContentColor, long disabledInactiveBorderColor);
+ method public long getActiveBorderColor();
+ method public long getActiveContainerColor();
+ method public long getActiveContentColor();
+ method public long getDisabledActiveBorderColor();
+ method public long getDisabledActiveContainerColor();
+ method public long getDisabledActiveContentColor();
+ method public long getDisabledInactiveBorderColor();
+ method public long getDisabledInactiveContainerColor();
+ method public long getDisabledInactiveContentColor();
+ method public long getInactiveBorderColor();
+ method public long getInactiveContainerColor();
+ method public long getInactiveContentColor();
+ property public final long activeBorderColor;
+ property public final long activeContainerColor;
+ property public final long activeContentColor;
+ property public final long disabledActiveBorderColor;
+ property public final long disabledActiveContainerColor;
+ property public final long disabledActiveContentColor;
+ property public final long disabledInactiveBorderColor;
+ property public final long disabledInactiveContainerColor;
+ property public final long disabledInactiveContentColor;
+ property public final long inactiveBorderColor;
+ property public final long inactiveContainerColor;
+ property public final long inactiveContentColor;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class SegmentedButtonDefaults {
+ method @androidx.compose.runtime.Composable public void ActiveIcon();
+ method @androidx.compose.runtime.Composable public void Icon(boolean active, optional kotlin.jvm.functions.Function0<kotlin.Unit> activeContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? inactiveContent);
+ method public androidx.compose.foundation.BorderStroke borderStroke(long color, optional float width);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.SegmentedButtonColors colors(optional long activeContainerColor, optional long activeContentColor, optional long activeBorderColor, optional long inactiveContainerColor, optional long inactiveContentColor, optional long inactiveBorderColor, optional long disabledActiveContainerColor, optional long disabledActiveContentColor, optional long disabledActiveBorderColor, optional long disabledInactiveContainerColor, optional long disabledInactiveContentColor, optional long disabledInactiveBorderColor);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.foundation.shape.CornerBasedShape getBaseShape();
+ method public float getBorderWidth();
+ method public float getIconSize();
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.ui.graphics.Shape itemShape(int index, int count, optional androidx.compose.foundation.shape.CornerBasedShape baseShape);
+ property public final float BorderWidth;
+ property public final float IconSize;
+ property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.foundation.shape.CornerBasedShape baseShape;
+ field public static final androidx.compose.material3.SegmentedButtonDefaults INSTANCE;
+ }
+
+ public final class SegmentedButtonKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void MultiChoiceSegmentedButtonRow(optional androidx.compose.ui.Modifier modifier, optional float space, kotlin.jvm.functions.Function1<? super androidx.compose.material3.MultiChoiceSegmentedButtonRowScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SegmentedButton(androidx.compose.material3.MultiChoiceSegmentedButtonRowScope, boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SegmentedButtonColors colors, optional androidx.compose.foundation.BorderStroke border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> icon, kotlin.jvm.functions.Function0<kotlin.Unit> label);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SegmentedButton(androidx.compose.material3.SingleChoiceSegmentedButtonRowScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SegmentedButtonColors colors, optional androidx.compose.foundation.BorderStroke border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> icon, kotlin.jvm.functions.Function0<kotlin.Unit> label);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SingleChoiceSegmentedButtonRow(optional androidx.compose.ui.Modifier modifier, optional float space, kotlin.jvm.functions.Function1<? super androidx.compose.material3.SingleChoiceSegmentedButtonRowScope,kotlin.Unit> content);
+ }
+
+ @androidx.compose.runtime.Immutable public final class SelectableChipColors {
+ ctor public SelectableChipColors(long containerColor, long labelColor, long leadingIconColor, long trailingIconColor, long disabledContainerColor, long disabledLabelColor, long disabledLeadingIconColor, long disabledTrailingIconColor, long selectedContainerColor, long disabledSelectedContainerColor, long selectedLabelColor, long selectedLeadingIconColor, long selectedTrailingIconColor);
+ }
+
+ @androidx.compose.runtime.Immutable public final class SelectableChipElevation {
+ ctor public SelectableChipElevation(float elevation, float pressedElevation, float focusedElevation, float hoveredElevation, float draggedElevation, float disabledElevation);
+ method public float getDisabledElevation();
+ method public float getDraggedElevation();
+ method public float getElevation();
+ method public float getFocusedElevation();
+ method public float getHoveredElevation();
+ method public float getPressedElevation();
+ property public final float disabledElevation;
+ property public final float draggedElevation;
+ property public final float elevation;
+ property public final float focusedElevation;
+ property public final float hoveredElevation;
+ property public final float pressedElevation;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public interface SelectableDates {
+ method public default boolean isSelectableDate(long utcTimeMillis);
+ method public default boolean isSelectableYear(int year);
+ }
+
+ public final class ShapeDefaults {
+ method public androidx.compose.foundation.shape.CornerBasedShape getExtraLarge();
+ method public androidx.compose.foundation.shape.CornerBasedShape getExtraSmall();
+ method public androidx.compose.foundation.shape.CornerBasedShape getLarge();
+ method public androidx.compose.foundation.shape.CornerBasedShape getMedium();
+ method public androidx.compose.foundation.shape.CornerBasedShape getSmall();
+ property public final androidx.compose.foundation.shape.CornerBasedShape ExtraLarge;
+ property public final androidx.compose.foundation.shape.CornerBasedShape ExtraSmall;
+ property public final androidx.compose.foundation.shape.CornerBasedShape Large;
+ property public final androidx.compose.foundation.shape.CornerBasedShape Medium;
+ property public final androidx.compose.foundation.shape.CornerBasedShape Small;
+ field public static final androidx.compose.material3.ShapeDefaults INSTANCE;
+ }
+
+ @androidx.compose.runtime.Immutable public final class Shapes {
+ ctor public Shapes(optional androidx.compose.foundation.shape.CornerBasedShape extraSmall, optional androidx.compose.foundation.shape.CornerBasedShape small, optional androidx.compose.foundation.shape.CornerBasedShape medium, optional androidx.compose.foundation.shape.CornerBasedShape large, optional androidx.compose.foundation.shape.CornerBasedShape extraLarge);
+ method public androidx.compose.material3.Shapes copy(optional androidx.compose.foundation.shape.CornerBasedShape extraSmall, optional androidx.compose.foundation.shape.CornerBasedShape small, optional androidx.compose.foundation.shape.CornerBasedShape medium, optional androidx.compose.foundation.shape.CornerBasedShape large, optional androidx.compose.foundation.shape.CornerBasedShape extraLarge);
+ method public androidx.compose.foundation.shape.CornerBasedShape getExtraLarge();
+ method public androidx.compose.foundation.shape.CornerBasedShape getExtraSmall();
+ method public androidx.compose.foundation.shape.CornerBasedShape getLarge();
+ method public androidx.compose.foundation.shape.CornerBasedShape getMedium();
+ method public androidx.compose.foundation.shape.CornerBasedShape getSmall();
+ property public final androidx.compose.foundation.shape.CornerBasedShape extraLarge;
+ property public final androidx.compose.foundation.shape.CornerBasedShape extraSmall;
+ property public final androidx.compose.foundation.shape.CornerBasedShape large;
+ property public final androidx.compose.foundation.shape.CornerBasedShape medium;
+ property public final androidx.compose.foundation.shape.CornerBasedShape small;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class SheetState {
+ ctor @Deprecated public SheetState(boolean skipPartiallyExpanded, optional androidx.compose.material3.SheetValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange, optional boolean skipHiddenState);
+ ctor @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public SheetState(boolean skipPartiallyExpanded, androidx.compose.ui.unit.Density density, optional androidx.compose.material3.SheetValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange, optional boolean skipHiddenState);
+ method public suspend Object? expand(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public androidx.compose.material3.SheetValue getCurrentValue();
+ method public boolean getHasExpandedState();
+ method public boolean getHasPartiallyExpandedState();
+ method public androidx.compose.material3.SheetValue getTargetValue();
+ method public suspend Object? hide(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public boolean isVisible();
+ method public suspend Object? partialExpand(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public float requireOffset();
+ method public suspend Object? show(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ property public final androidx.compose.material3.SheetValue currentValue;
+ property public final boolean hasExpandedState;
+ property public final boolean hasPartiallyExpandedState;
+ property public final boolean isVisible;
+ property public final androidx.compose.material3.SheetValue targetValue;
+ field public static final androidx.compose.material3.SheetState.Companion Companion;
+ }
+
+ public static final class SheetState.Companion {
+ method @Deprecated public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.SheetState,androidx.compose.material3.SheetValue> Saver(boolean skipPartiallyExpanded, kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange);
+ method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.SheetState,androidx.compose.material3.SheetValue> Saver(boolean skipPartiallyExpanded, kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange, androidx.compose.ui.unit.Density density);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum SheetValue {
+ method public static androidx.compose.material3.SheetValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.compose.material3.SheetValue[] values();
+ enum_constant public static final androidx.compose.material3.SheetValue Expanded;
+ enum_constant public static final androidx.compose.material3.SheetValue Hidden;
+ enum_constant public static final androidx.compose.material3.SheetValue PartiallyExpanded;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public interface SingleChoiceSegmentedButtonRowScope extends androidx.compose.foundation.layout.RowScope {
+ }
+
+ @androidx.compose.runtime.Immutable public final class SliderColors {
+ ctor public SliderColors(long thumbColor, long activeTrackColor, long activeTickColor, long inactiveTrackColor, long inactiveTickColor, long disabledThumbColor, long disabledActiveTrackColor, long disabledActiveTickColor, long disabledInactiveTrackColor, long disabledInactiveTickColor);
+ method public long getActiveTickColor();
+ method public long getActiveTrackColor();
+ method public long getDisabledActiveTickColor();
+ method public long getDisabledActiveTrackColor();
+ method public long getDisabledInactiveTickColor();
+ method public long getDisabledInactiveTrackColor();
+ method public long getDisabledThumbColor();
+ method public long getInactiveTickColor();
+ method public long getInactiveTrackColor();
+ method public long getThumbColor();
+ property public final long activeTickColor;
+ property public final long activeTrackColor;
+ property public final long disabledActiveTickColor;
+ property public final long disabledActiveTrackColor;
+ property public final long disabledInactiveTickColor;
+ property public final long disabledInactiveTrackColor;
+ property public final long disabledThumbColor;
+ property public final long inactiveTickColor;
+ property public final long inactiveTrackColor;
+ property public final long thumbColor;
+ }
+
+ @androidx.compose.runtime.Stable public final class SliderDefaults {
+ method @androidx.compose.runtime.Composable public void Thumb(androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SliderColors colors, optional boolean enabled, optional long thumbSize);
+ method @androidx.compose.runtime.Composable public void Track(androidx.compose.material3.RangeSliderState rangeSliderState, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SliderColors colors, optional boolean enabled);
+ method @Deprecated @androidx.compose.runtime.Composable public void Track(androidx.compose.material3.SliderPositions sliderPositions, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SliderColors colors, optional boolean enabled);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void Track(androidx.compose.material3.SliderState sliderState, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SliderColors colors, optional boolean enabled);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.SliderColors colors(optional long thumbColor, optional long activeTrackColor, optional long activeTickColor, optional long inactiveTrackColor, optional long inactiveTickColor, optional long disabledThumbColor, optional long disabledActiveTrackColor, optional long disabledActiveTickColor, optional long disabledInactiveTrackColor, optional long disabledInactiveTickColor);
+ field public static final androidx.compose.material3.SliderDefaults INSTANCE;
+ }
+
+ public final class SliderKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void RangeSlider(androidx.compose.material3.RangeSliderState state, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SliderColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource startInteractionSource, optional androidx.compose.foundation.interaction.MutableInteractionSource endInteractionSource, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.RangeSliderState,kotlin.Unit> startThumb, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.RangeSliderState,kotlin.Unit> endThumb, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.RangeSliderState,kotlin.Unit> track);
+ method @androidx.compose.runtime.Composable public static void RangeSlider(kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> value, kotlin.jvm.functions.Function1<? super kotlin.ranges.ClosedFloatingPointRange<java.lang.Float>,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional @IntRange(from=0L) int steps, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.material3.SliderColors colors);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void RangeSlider(kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> value, kotlin.jvm.functions.Function1<? super kotlin.ranges.ClosedFloatingPointRange<java.lang.Float>,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.material3.SliderColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource startInteractionSource, optional androidx.compose.foundation.interaction.MutableInteractionSource endInteractionSource, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.RangeSliderState,kotlin.Unit> startThumb, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.RangeSliderState,kotlin.Unit> endThumb, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.RangeSliderState,kotlin.Unit> track, optional @IntRange(from=0L) int steps);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void Slider(androidx.compose.material3.SliderState state, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SliderColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SliderState,kotlin.Unit> thumb, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SliderState,kotlin.Unit> track);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void Slider(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.material3.SliderColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional @IntRange(from=0L) int steps, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SliderState,kotlin.Unit> thumb, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SliderState,kotlin.Unit> track, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange);
+ method @androidx.compose.runtime.Composable public static void Slider(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional @IntRange(from=0L) int steps, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.material3.SliderColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ }
+
+ @Deprecated @androidx.compose.runtime.Stable public final class SliderPositions {
+ ctor @Deprecated public SliderPositions(optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> initialActiveRange, optional float[] initialTickFractions);
+ method @Deprecated public kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> getActiveRange();
+ method @Deprecated public float[] getTickFractions();
+ property @Deprecated public final kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> activeRange;
+ property @Deprecated public final float[] tickFractions;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class SliderState implements androidx.compose.foundation.gestures.DraggableState {
+ ctor public SliderState(optional float value, optional @IntRange(from=0L) int steps, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange);
+ method public void dispatchRawDelta(float delta);
+ method public suspend Object? drag(androidx.compose.foundation.MutatePriority dragPriority, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.gestures.DragScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public kotlin.jvm.functions.Function0<kotlin.Unit>? getOnValueChangeFinished();
+ method public int getSteps();
+ method public float getValue();
+ method public kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> getValueRange();
+ method public void setValue(float);
+ property public final kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished;
+ property public final int steps;
+ property public final float value;
+ property public final kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange;
+ }
+
+ @androidx.compose.runtime.Stable public interface SnackbarData {
+ method public void dismiss();
+ method public androidx.compose.material3.SnackbarVisuals getVisuals();
+ method public void performAction();
+ property public abstract androidx.compose.material3.SnackbarVisuals visuals;
+ }
+
+ public final class SnackbarDefaults {
+ method @androidx.compose.runtime.Composable public long getActionColor();
+ method @androidx.compose.runtime.Composable public long getActionContentColor();
+ method @androidx.compose.runtime.Composable public long getColor();
+ method @androidx.compose.runtime.Composable public long getContentColor();
+ method @androidx.compose.runtime.Composable public long getDismissActionContentColor();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ property @androidx.compose.runtime.Composable public final long actionColor;
+ property @androidx.compose.runtime.Composable public final long actionContentColor;
+ property @androidx.compose.runtime.Composable public final long color;
+ property @androidx.compose.runtime.Composable public final long contentColor;
+ property @androidx.compose.runtime.Composable public final long dismissActionContentColor;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ field public static final androidx.compose.material3.SnackbarDefaults INSTANCE;
+ }
+
+ public enum SnackbarDuration {
+ method public static androidx.compose.material3.SnackbarDuration valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.compose.material3.SnackbarDuration[] values();
+ enum_constant public static final androidx.compose.material3.SnackbarDuration Indefinite;
+ enum_constant public static final androidx.compose.material3.SnackbarDuration Long;
+ enum_constant public static final androidx.compose.material3.SnackbarDuration Short;
+ }
+
+ public final class SnackbarHostKt {
+ method @androidx.compose.runtime.Composable public static void SnackbarHost(androidx.compose.material3.SnackbarHostState hostState, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SnackbarData,kotlin.Unit> snackbar);
+ }
+
+ @androidx.compose.runtime.Stable public final class SnackbarHostState {
+ ctor public SnackbarHostState();
+ method public androidx.compose.material3.SnackbarData? getCurrentSnackbarData();
+ method public suspend Object? showSnackbar(androidx.compose.material3.SnackbarVisuals visuals, kotlin.coroutines.Continuation<? super androidx.compose.material3.SnackbarResult>);
+ method public suspend Object? showSnackbar(String message, optional String? actionLabel, optional boolean withDismissAction, optional androidx.compose.material3.SnackbarDuration duration, kotlin.coroutines.Continuation<? super androidx.compose.material3.SnackbarResult>);
+ property public final androidx.compose.material3.SnackbarData? currentSnackbarData;
+ }
+
+ public final class SnackbarKt {
+ method @androidx.compose.runtime.Composable public static void Snackbar(androidx.compose.material3.SnackbarData snackbarData, optional androidx.compose.ui.Modifier modifier, optional boolean actionOnNewLine, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional long actionColor, optional long actionContentColor, optional long dismissActionContentColor);
+ method @androidx.compose.runtime.Composable public static void Snackbar(optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? action, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dismissAction, optional boolean actionOnNewLine, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional long actionContentColor, optional long dismissActionContentColor, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ }
+
+ public enum SnackbarResult {
+ method public static androidx.compose.material3.SnackbarResult valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.compose.material3.SnackbarResult[] values();
+ enum_constant public static final androidx.compose.material3.SnackbarResult ActionPerformed;
+ enum_constant public static final androidx.compose.material3.SnackbarResult Dismissed;
+ }
+
+ @androidx.compose.runtime.Stable public interface SnackbarVisuals {
+ method public String? getActionLabel();
+ method public androidx.compose.material3.SnackbarDuration getDuration();
+ method public String getMessage();
+ method public boolean getWithDismissAction();
+ property public abstract String? actionLabel;
+ property public abstract androidx.compose.material3.SnackbarDuration duration;
+ property public abstract String message;
+ property public abstract boolean withDismissAction;
+ }
+
+ public final class SuggestionChipDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors elevatedSuggestionChipColors(optional long containerColor, optional long labelColor, optional long iconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledIconContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation elevatedSuggestionChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+ method public float getHeight();
+ method public float getIconSize();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke suggestionChipBorder(boolean enabled, optional long borderColor, optional long disabledBorderColor, optional float borderWidth);
+ method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.ChipBorder suggestionChipBorder(optional long borderColor, optional long disabledBorderColor, optional float borderWidth);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors suggestionChipColors(optional long containerColor, optional long labelColor, optional long iconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledIconContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation suggestionChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+ property public final float Height;
+ property public final float IconSize;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ field public static final androidx.compose.material3.SuggestionChipDefaults INSTANCE;
+ }
+
+ public final class SurfaceKt {
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long color, optional long contentColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional long color, optional long contentColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional long color, optional long contentColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional long color, optional long contentColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.unit.Dp> getLocalAbsoluteTonalElevation();
+ property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.unit.Dp> LocalAbsoluteTonalElevation;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class SwipeToDismissBoxDefaults {
+ method @androidx.compose.runtime.Composable public kotlin.jvm.functions.Function1<java.lang.Float,java.lang.Float> getPositionalThreshold();
+ property @androidx.compose.runtime.Composable public final kotlin.jvm.functions.Function1<java.lang.Float,java.lang.Float> positionalThreshold;
+ field public static final androidx.compose.material3.SwipeToDismissBoxDefaults INSTANCE;
+ }
+
+ public final class SwipeToDismissBoxKt {
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismiss(androidx.compose.material3.SwipeToDismissState state, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> background, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> dismissContent, optional androidx.compose.ui.Modifier modifier, optional java.util.Set<? extends androidx.compose.material3.SwipeToDismissValue> directions);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismissBox(androidx.compose.material3.SwipeToDismissState state, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> backgroundContent, optional androidx.compose.ui.Modifier modifier, optional boolean enableDismissFromStartToEnd, optional boolean enableDismissFromEndToStart, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.SwipeToDismissState rememberSwipeToDismissState(optional androidx.compose.material3.SwipeToDismissValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SwipeToDismissValue,java.lang.Boolean> confirmValueChange, optional kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class SwipeToDismissState {
+ ctor public SwipeToDismissState(androidx.compose.material3.SwipeToDismissValue initialValue, androidx.compose.ui.unit.Density density, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SwipeToDismissValue,java.lang.Boolean> confirmValueChange, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold);
+ method public suspend Object? dismiss(androidx.compose.material3.SwipeToDismissValue direction, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public androidx.compose.material3.SwipeToDismissValue getCurrentValue();
+ method public androidx.compose.material3.SwipeToDismissValue getDismissDirection();
+ method @FloatRange(from=0.0, to=1.0) public float getProgress();
+ method public androidx.compose.material3.SwipeToDismissValue getTargetValue();
+ method @Deprecated public boolean isDismissed(androidx.compose.material3.DismissDirection direction);
+ method public float requireOffset();
+ method public suspend Object? reset(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public suspend Object? snapTo(androidx.compose.material3.SwipeToDismissValue targetValue, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ property public final androidx.compose.material3.SwipeToDismissValue currentValue;
+ property public final androidx.compose.material3.SwipeToDismissValue dismissDirection;
+ property @FloatRange(from=0.0, to=1.0) public final float progress;
+ property public final androidx.compose.material3.SwipeToDismissValue targetValue;
+ field public static final androidx.compose.material3.SwipeToDismissState.Companion Companion;
+ }
+
+ public static final class SwipeToDismissState.Companion {
+ method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.SwipeToDismissState,androidx.compose.material3.SwipeToDismissValue> Saver(kotlin.jvm.functions.Function1<? super androidx.compose.material3.SwipeToDismissValue,java.lang.Boolean> confirmValueChange, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold, androidx.compose.ui.unit.Density density);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum SwipeToDismissValue {
+ method public static androidx.compose.material3.SwipeToDismissValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.compose.material3.SwipeToDismissValue[] values();
+ enum_constant public static final androidx.compose.material3.SwipeToDismissValue EndToStart;
+ enum_constant public static final androidx.compose.material3.SwipeToDismissValue Settled;
+ enum_constant public static final androidx.compose.material3.SwipeToDismissValue StartToEnd;
+ }
+
+ @androidx.compose.runtime.Immutable public final class SwitchColors {
+ ctor public SwitchColors(long checkedThumbColor, long checkedTrackColor, long checkedBorderColor, long checkedIconColor, long uncheckedThumbColor, long uncheckedTrackColor, long uncheckedBorderColor, long uncheckedIconColor, long disabledCheckedThumbColor, long disabledCheckedTrackColor, long disabledCheckedBorderColor, long disabledCheckedIconColor, long disabledUncheckedThumbColor, long disabledUncheckedTrackColor, long disabledUncheckedBorderColor, long disabledUncheckedIconColor);
+ method public long getCheckedBorderColor();
+ method public long getCheckedIconColor();
+ method public long getCheckedThumbColor();
+ method public long getCheckedTrackColor();
+ method public long getDisabledCheckedBorderColor();
+ method public long getDisabledCheckedIconColor();
+ method public long getDisabledCheckedThumbColor();
+ method public long getDisabledCheckedTrackColor();
+ method public long getDisabledUncheckedBorderColor();
+ method public long getDisabledUncheckedIconColor();
+ method public long getDisabledUncheckedThumbColor();
+ method public long getDisabledUncheckedTrackColor();
+ method public long getUncheckedBorderColor();
+ method public long getUncheckedIconColor();
+ method public long getUncheckedThumbColor();
+ method public long getUncheckedTrackColor();
+ property public final long checkedBorderColor;
+ property public final long checkedIconColor;
+ property public final long checkedThumbColor;
+ property public final long checkedTrackColor;
+ property public final long disabledCheckedBorderColor;
+ property public final long disabledCheckedIconColor;
+ property public final long disabledCheckedThumbColor;
+ property public final long disabledCheckedTrackColor;
+ property public final long disabledUncheckedBorderColor;
+ property public final long disabledUncheckedIconColor;
+ property public final long disabledUncheckedThumbColor;
+ property public final long disabledUncheckedTrackColor;
+ property public final long uncheckedBorderColor;
+ property public final long uncheckedIconColor;
+ property public final long uncheckedThumbColor;
+ property public final long uncheckedTrackColor;
+ }
+
+ public final class SwitchDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.SwitchColors colors(optional long checkedThumbColor, optional long checkedTrackColor, optional long checkedBorderColor, optional long checkedIconColor, optional long uncheckedThumbColor, optional long uncheckedTrackColor, optional long uncheckedBorderColor, optional long uncheckedIconColor, optional long disabledCheckedThumbColor, optional long disabledCheckedTrackColor, optional long disabledCheckedBorderColor, optional long disabledCheckedIconColor, optional long disabledUncheckedThumbColor, optional long disabledUncheckedTrackColor, optional long disabledUncheckedBorderColor, optional long disabledUncheckedIconColor);
+ method public float getIconSize();
+ property public final float IconSize;
+ field public static final androidx.compose.material3.SwitchDefaults INSTANCE;
+ }
+
+ public final class SwitchKt {
+ method @androidx.compose.runtime.Composable public static void Switch(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit>? onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? thumbContent, optional boolean enabled, optional androidx.compose.material3.SwitchColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ }
+
+ public interface TabIndicatorScope {
+ method public androidx.compose.ui.Modifier tabIndicatorLayout(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function4<? super androidx.compose.ui.layout.MeasureScope,? super androidx.compose.ui.layout.Measurable,? super androidx.compose.ui.unit.Constraints,? super java.util.List<androidx.compose.material3.TabPosition>,? extends androidx.compose.ui.layout.MeasureResult> measure);
+ method public androidx.compose.ui.Modifier tabIndicatorOffset(androidx.compose.ui.Modifier, int selectedTabIndex, optional boolean matchContentSize);
+ }
+
+ public final class TabKt {
+ method @androidx.compose.runtime.Composable public static void LeadingIconTab(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> text, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional long selectedContentColor, optional long unselectedContentColor, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable public static void Tab(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional long selectedContentColor, optional long unselectedContentColor, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @androidx.compose.runtime.Composable public static void Tab(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional long selectedContentColor, optional long unselectedContentColor, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+ }
+
+ @androidx.compose.runtime.Immutable public final class TabPosition {
+ method public float getContentWidth();
+ method public float getLeft();
+ method public float getRight();
+ method public float getWidth();
+ property public final float contentWidth;
+ property public final float left;
+ property public final float right;
+ property public final float width;
+ }
+
+ public final class TabRowDefaults {
+ method @Deprecated @androidx.compose.runtime.Composable public void Indicator(optional androidx.compose.ui.Modifier modifier, optional float height, optional long color);
+ method @androidx.compose.runtime.Composable public void PrimaryIndicator(optional androidx.compose.ui.Modifier modifier, optional float width, optional float height, optional long color, optional androidx.compose.ui.graphics.Shape shape);
+ method @androidx.compose.runtime.Composable public void SecondaryIndicator(optional androidx.compose.ui.Modifier modifier, optional float height, optional long color);
+ method @Deprecated @androidx.compose.runtime.Composable public long getContainerColor();
+ method @Deprecated @androidx.compose.runtime.Composable public long getContentColor();
+ method @androidx.compose.runtime.Composable public long getPrimaryContainerColor();
+ method @androidx.compose.runtime.Composable public long getPrimaryContentColor();
+ method public float getScrollableTabRowEdgeStartPadding();
+ method @androidx.compose.runtime.Composable public long getSecondaryContainerColor();
+ method @androidx.compose.runtime.Composable public long getSecondaryContentColor();
+ method public androidx.compose.ui.Modifier tabIndicatorOffset(androidx.compose.ui.Modifier, androidx.compose.material3.TabPosition currentTabPosition);
+ property public final float ScrollableTabRowEdgeStartPadding;
+ property @Deprecated @androidx.compose.runtime.Composable public final long containerColor;
+ property @Deprecated @androidx.compose.runtime.Composable public final long contentColor;
+ property @androidx.compose.runtime.Composable public final long primaryContainerColor;
+ property @androidx.compose.runtime.Composable public final long primaryContentColor;
+ property @androidx.compose.runtime.Composable public final long secondaryContainerColor;
+ property @androidx.compose.runtime.Composable public final long secondaryContentColor;
+ field public static final androidx.compose.material3.TabRowDefaults INSTANCE;
+ }
+
+ public final class TabRowKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void PrimaryScrollableTabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.ScrollState scrollState, optional long containerColor, optional long contentColor, optional float edgePadding, optional kotlin.jvm.functions.Function1<? super java.util.List<androidx.compose.material3.TabPosition>,kotlin.Unit> indicator, optional kotlin.jvm.functions.Function0<kotlin.Unit> divider, kotlin.jvm.functions.Function0<kotlin.Unit> tabs);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void PrimaryTabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.TabIndicatorScope,kotlin.Unit> indicator, optional kotlin.jvm.functions.Function0<kotlin.Unit> divider, kotlin.jvm.functions.Function0<kotlin.Unit> tabs);
+ method @androidx.compose.runtime.Composable public static void ScrollableTabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional float edgePadding, optional kotlin.jvm.functions.Function1<? super java.util.List<androidx.compose.material3.TabPosition>,kotlin.Unit> indicator, optional kotlin.jvm.functions.Function0<kotlin.Unit> divider, kotlin.jvm.functions.Function0<kotlin.Unit> tabs);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SecondaryScrollableTabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.ScrollState scrollState, optional long containerColor, optional long contentColor, optional float edgePadding, optional kotlin.jvm.functions.Function1<? super java.util.List<androidx.compose.material3.TabPosition>,kotlin.Unit> indicator, optional kotlin.jvm.functions.Function0<kotlin.Unit> divider, kotlin.jvm.functions.Function0<kotlin.Unit> tabs);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SecondaryTabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.TabIndicatorScope,kotlin.Unit> indicator, optional kotlin.jvm.functions.Function0<kotlin.Unit> divider, kotlin.jvm.functions.Function0<kotlin.Unit> tabs);
+ method @androidx.compose.runtime.Composable public static void TabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function1<? super java.util.List<androidx.compose.material3.TabPosition>,kotlin.Unit> indicator, optional kotlin.jvm.functions.Function0<kotlin.Unit> divider, kotlin.jvm.functions.Function0<kotlin.Unit> tabs);
+ }
+
+ @androidx.compose.runtime.Immutable public final class TextFieldColors {
+ ctor public TextFieldColors(long focusedTextColor, long unfocusedTextColor, long disabledTextColor, long errorTextColor, long focusedContainerColor, long unfocusedContainerColor, long disabledContainerColor, long errorContainerColor, long cursorColor, long errorCursorColor, androidx.compose.foundation.text.selection.TextSelectionColors textSelectionColors, long focusedIndicatorColor, long unfocusedIndicatorColor, long disabledIndicatorColor, long errorIndicatorColor, long focusedLeadingIconColor, long unfocusedLeadingIconColor, long disabledLeadingIconColor, long errorLeadingIconColor, long focusedTrailingIconColor, long unfocusedTrailingIconColor, long disabledTrailingIconColor, long errorTrailingIconColor, long focusedLabelColor, long unfocusedLabelColor, long disabledLabelColor, long errorLabelColor, long focusedPlaceholderColor, long unfocusedPlaceholderColor, long disabledPlaceholderColor, long errorPlaceholderColor, long focusedSupportingTextColor, long unfocusedSupportingTextColor, long disabledSupportingTextColor, long errorSupportingTextColor, long focusedPrefixColor, long unfocusedPrefixColor, long disabledPrefixColor, long errorPrefixColor, long focusedSuffixColor, long unfocusedSuffixColor, long disabledSuffixColor, long errorSuffixColor);
+ method public long getCursorColor();
+ method public long getDisabledContainerColor();
+ method public long getDisabledIndicatorColor();
+ method public long getDisabledLabelColor();
+ method public long getDisabledLeadingIconColor();
+ method public long getDisabledPlaceholderColor();
+ method public long getDisabledPrefixColor();
+ method public long getDisabledSuffixColor();
+ method public long getDisabledSupportingTextColor();
+ method public long getDisabledTextColor();
+ method public long getDisabledTrailingIconColor();
+ method public long getErrorContainerColor();
+ method public long getErrorCursorColor();
+ method public long getErrorIndicatorColor();
+ method public long getErrorLabelColor();
+ method public long getErrorLeadingIconColor();
+ method public long getErrorPlaceholderColor();
+ method public long getErrorPrefixColor();
+ method public long getErrorSuffixColor();
+ method public long getErrorSupportingTextColor();
+ method public long getErrorTextColor();
+ method public long getErrorTrailingIconColor();
+ method public long getFocusedContainerColor();
+ method public long getFocusedIndicatorColor();
+ method public long getFocusedLabelColor();
+ method public long getFocusedLeadingIconColor();
+ method public long getFocusedPlaceholderColor();
+ method public long getFocusedPrefixColor();
+ method public long getFocusedSuffixColor();
+ method public long getFocusedSupportingTextColor();
+ method public long getFocusedTextColor();
+ method public long getFocusedTrailingIconColor();
+ method public androidx.compose.foundation.text.selection.TextSelectionColors getTextSelectionColors();
+ method public long getUnfocusedContainerColor();
+ method public long getUnfocusedIndicatorColor();
+ method public long getUnfocusedLabelColor();
+ method public long getUnfocusedLeadingIconColor();
+ method public long getUnfocusedPlaceholderColor();
+ method public long getUnfocusedPrefixColor();
+ method public long getUnfocusedSuffixColor();
+ method public long getUnfocusedSupportingTextColor();
+ method public long getUnfocusedTextColor();
+ method public long getUnfocusedTrailingIconColor();
+ property public final long cursorColor;
+ property public final long disabledContainerColor;
+ property public final long disabledIndicatorColor;
+ property public final long disabledLabelColor;
+ property public final long disabledLeadingIconColor;
+ property public final long disabledPlaceholderColor;
+ property public final long disabledPrefixColor;
+ property public final long disabledSuffixColor;
+ property public final long disabledSupportingTextColor;
+ property public final long disabledTextColor;
+ property public final long disabledTrailingIconColor;
+ property public final long errorContainerColor;
+ property public final long errorCursorColor;
+ property public final long errorIndicatorColor;
+ property public final long errorLabelColor;
+ property public final long errorLeadingIconColor;
+ property public final long errorPlaceholderColor;
+ property public final long errorPrefixColor;
+ property public final long errorSuffixColor;
+ property public final long errorSupportingTextColor;
+ property public final long errorTextColor;
+ property public final long errorTrailingIconColor;
+ property public final long focusedContainerColor;
+ property public final long focusedIndicatorColor;
+ property public final long focusedLabelColor;
+ property public final long focusedLeadingIconColor;
+ property public final long focusedPlaceholderColor;
+ property public final long focusedPrefixColor;
+ property public final long focusedSuffixColor;
+ property public final long focusedSupportingTextColor;
+ property public final long focusedTextColor;
+ property public final long focusedTrailingIconColor;
+ property public final androidx.compose.foundation.text.selection.TextSelectionColors textSelectionColors;
+ property public final long unfocusedContainerColor;
+ property public final long unfocusedIndicatorColor;
+ property public final long unfocusedLabelColor;
+ property public final long unfocusedLeadingIconColor;
+ property public final long unfocusedPlaceholderColor;
+ property public final long unfocusedPrefixColor;
+ property public final long unfocusedSuffixColor;
+ property public final long unfocusedSupportingTextColor;
+ property public final long unfocusedTextColor;
+ property public final long unfocusedTrailingIconColor;
+ }
+
+ @androidx.compose.runtime.Immutable public final class TextFieldDefaults {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void ContainerBox(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional androidx.compose.ui.graphics.Shape shape);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void DecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void FilledContainerBox(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional androidx.compose.ui.graphics.Shape shape);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void OutlinedBorderContainerBox(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional androidx.compose.ui.graphics.Shape shape, optional float focusedBorderThickness, optional float unfocusedBorderThickness);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void OutlinedTextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void OutlinedTextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void TextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void TextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors colors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long focusedContainerColor, optional long unfocusedContainerColor, optional long disabledContainerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+ method public androidx.compose.foundation.layout.PaddingValues contentPaddingWithLabel(optional float start, optional float end, optional float top, optional float bottom);
+ method public androidx.compose.foundation.layout.PaddingValues contentPaddingWithoutLabel(optional float start, optional float top, optional float end, optional float bottom);
+ method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFilledShape();
+ method @Deprecated public float getFocusedBorderThickness();
+ method public float getFocusedIndicatorThickness();
+ method public float getMinHeight();
+ method public float getMinWidth();
+ method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getOutlinedShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+ method @Deprecated public float getUnfocusedBorderThickness();
+ method public float getUnfocusedIndicatorThickness();
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public androidx.compose.ui.Modifier indicatorLine(androidx.compose.ui.Modifier, boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional float focusedIndicatorLineThickness, optional float unfocusedIndicatorLineThickness);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long containerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+ method @Deprecated public androidx.compose.foundation.layout.PaddingValues outlinedTextFieldPadding(optional float start, optional float top, optional float end, optional float bottom);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long containerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+ method @Deprecated public androidx.compose.foundation.layout.PaddingValues textFieldWithLabelPadding(optional float start, optional float end, optional float top, optional float bottom);
+ method @Deprecated public androidx.compose.foundation.layout.PaddingValues textFieldWithoutLabelPadding(optional float start, optional float top, optional float end, optional float bottom);
+ property @Deprecated public final float FocusedBorderThickness;
+ property public final float FocusedIndicatorThickness;
+ property public final float MinHeight;
+ property public final float MinWidth;
+ property @Deprecated public final float UnfocusedBorderThickness;
+ property public final float UnfocusedIndicatorThickness;
+ property @Deprecated @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape filledShape;
+ property @Deprecated @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape outlinedShape;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+ field public static final androidx.compose.material3.TextFieldDefaults INSTANCE;
+ }
+
+ public final class TextFieldKt {
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+ method @androidx.compose.runtime.Composable public static void TextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+ method @androidx.compose.runtime.Composable public static void TextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+ }
+
+ public final class TextKt {
+ method @androidx.compose.runtime.Composable public static void ProvideTextStyle(androidx.compose.ui.text.TextStyle value, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void Text(androidx.compose.ui.text.AnnotatedString text, optional androidx.compose.ui.Modifier modifier, optional long color, optional long fontSize, optional androidx.compose.ui.text.font.FontStyle? fontStyle, optional androidx.compose.ui.text.font.FontWeight? fontWeight, optional androidx.compose.ui.text.font.FontFamily? fontFamily, optional long letterSpacing, optional androidx.compose.ui.text.style.TextDecoration? textDecoration, optional androidx.compose.ui.text.style.TextAlign? textAlign, optional long lineHeight, optional int overflow, optional boolean softWrap, optional int maxLines, optional int minLines, optional java.util.Map<java.lang.String,androidx.compose.foundation.text.InlineTextContent> inlineContent, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.ui.text.TextStyle style);
+ method @Deprecated @androidx.compose.runtime.Composable public static void Text(androidx.compose.ui.text.AnnotatedString text, optional androidx.compose.ui.Modifier modifier, optional long color, optional long fontSize, optional androidx.compose.ui.text.font.FontStyle? fontStyle, optional androidx.compose.ui.text.font.FontWeight? fontWeight, optional androidx.compose.ui.text.font.FontFamily? fontFamily, optional long letterSpacing, optional androidx.compose.ui.text.style.TextDecoration? textDecoration, optional androidx.compose.ui.text.style.TextAlign? textAlign, optional long lineHeight, optional int overflow, optional boolean softWrap, optional int maxLines, optional java.util.Map<java.lang.String,androidx.compose.foundation.text.InlineTextContent> inlineContent, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.ui.text.TextStyle style);
+ method @androidx.compose.runtime.Composable public static void Text(String text, optional androidx.compose.ui.Modifier modifier, optional long color, optional long fontSize, optional androidx.compose.ui.text.font.FontStyle? fontStyle, optional androidx.compose.ui.text.font.FontWeight? fontWeight, optional androidx.compose.ui.text.font.FontFamily? fontFamily, optional long letterSpacing, optional androidx.compose.ui.text.style.TextDecoration? textDecoration, optional androidx.compose.ui.text.style.TextAlign? textAlign, optional long lineHeight, optional int overflow, optional boolean softWrap, optional int maxLines, optional int minLines, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit>? onTextLayout, optional androidx.compose.ui.text.TextStyle style);
+ method @Deprecated @androidx.compose.runtime.Composable public static void Text(String text, optional androidx.compose.ui.Modifier modifier, optional long color, optional long fontSize, optional androidx.compose.ui.text.font.FontStyle? fontStyle, optional androidx.compose.ui.text.font.FontWeight? fontWeight, optional androidx.compose.ui.text.font.FontFamily? fontFamily, optional long letterSpacing, optional androidx.compose.ui.text.style.TextDecoration? textDecoration, optional androidx.compose.ui.text.style.TextAlign? textAlign, optional long lineHeight, optional int overflow, optional boolean softWrap, optional int maxLines, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.ui.text.TextStyle style);
+ method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.TextStyle> getLocalTextStyle();
+ property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.TextStyle> LocalTextStyle;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class TimePickerColors {
+ ctor public TimePickerColors(long clockDialColor, long selectorColor, long containerColor, long periodSelectorBorderColor, long clockDialSelectedContentColor, long clockDialUnselectedContentColor, long periodSelectorSelectedContainerColor, long periodSelectorUnselectedContainerColor, long periodSelectorSelectedContentColor, long periodSelectorUnselectedContentColor, long timeSelectorSelectedContainerColor, long timeSelectorUnselectedContainerColor, long timeSelectorSelectedContentColor, long timeSelectorUnselectedContentColor);
+ method public long getClockDialColor();
+ method public long getClockDialSelectedContentColor();
+ method public long getClockDialUnselectedContentColor();
+ method public long getContainerColor();
+ method public long getPeriodSelectorBorderColor();
+ method public long getPeriodSelectorSelectedContainerColor();
+ method public long getPeriodSelectorSelectedContentColor();
+ method public long getPeriodSelectorUnselectedContainerColor();
+ method public long getPeriodSelectorUnselectedContentColor();
+ method public long getSelectorColor();
+ method public long getTimeSelectorSelectedContainerColor();
+ method public long getTimeSelectorSelectedContentColor();
+ method public long getTimeSelectorUnselectedContainerColor();
+ method public long getTimeSelectorUnselectedContentColor();
+ property public final long clockDialColor;
+ property public final long clockDialSelectedContentColor;
+ property public final long clockDialUnselectedContentColor;
+ property public final long containerColor;
+ property public final long periodSelectorBorderColor;
+ property public final long periodSelectorSelectedContainerColor;
+ property public final long periodSelectorSelectedContentColor;
+ property public final long periodSelectorUnselectedContainerColor;
+ property public final long periodSelectorUnselectedContentColor;
+ property public final long selectorColor;
+ property public final long timeSelectorSelectedContainerColor;
+ property public final long timeSelectorSelectedContentColor;
+ property public final long timeSelectorUnselectedContainerColor;
+ property public final long timeSelectorUnselectedContentColor;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class TimePickerDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.TimePickerColors colors(optional long clockDialColor, optional long clockDialSelectedContentColor, optional long clockDialUnselectedContentColor, optional long selectorColor, optional long containerColor, optional long periodSelectorBorderColor, optional long periodSelectorSelectedContainerColor, optional long periodSelectorUnselectedContainerColor, optional long periodSelectorSelectedContentColor, optional long periodSelectorUnselectedContentColor, optional long timeSelectorSelectedContainerColor, optional long timeSelectorUnselectedContainerColor, optional long timeSelectorSelectedContentColor, optional long timeSelectorUnselectedContentColor);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public int layoutType();
+ field public static final androidx.compose.material3.TimePickerDefaults INSTANCE;
+ }
+
+ public final class TimePickerKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TimeInput(androidx.compose.material3.TimePickerState state, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.TimePickerColors colors);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TimePicker(androidx.compose.material3.TimePickerState state, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.TimePickerColors colors, optional int layoutType);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.TimePickerState rememberTimePickerState(optional int initialHour, optional int initialMinute, optional boolean is24Hour);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class TimePickerLayoutType {
+ field public static final androidx.compose.material3.TimePickerLayoutType.Companion Companion;
+ }
+
+ public static final class TimePickerLayoutType.Companion {
+ method public int getHorizontal();
+ method public int getVertical();
+ property public final int Horizontal;
+ property public final int Vertical;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class TimePickerState {
+ ctor public TimePickerState(int initialHour, int initialMinute, boolean is24Hour);
+ method public int getHour();
+ method public int getMinute();
+ method public boolean is24hour();
+ method public suspend Object? settle(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ property public final int hour;
+ property public final boolean is24hour;
+ property public final int minute;
+ field public static final androidx.compose.material3.TimePickerState.Companion Companion;
+ }
+
+ public static final class TimePickerState.Companion {
+ method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.TimePickerState,?> Saver();
+ }
+
+ @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public interface TooltipBoxScope {
+ method @Deprecated public androidx.compose.ui.Modifier tooltipTrigger(androidx.compose.ui.Modifier);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class TooltipDefaults {
+ method @androidx.compose.runtime.Composable public long getPlainTooltipContainerColor();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getPlainTooltipContainerShape();
+ method @androidx.compose.runtime.Composable public long getPlainTooltipContentColor();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getRichTooltipContainerShape();
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.window.PopupPositionProvider rememberPlainTooltipPositionProvider(optional float spacingBetweenTooltipAndAnchor);
+ method @androidx.compose.runtime.Composable public androidx.compose.ui.window.PopupPositionProvider rememberRichTooltipPositionProvider(optional float spacingBetweenTooltipAndAnchor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.RichTooltipColors richTooltipColors(optional long containerColor, optional long contentColor, optional long titleContentColor, optional long actionContentColor);
+ property @androidx.compose.runtime.Composable public final long plainTooltipContainerColor;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape plainTooltipContainerShape;
+ property @androidx.compose.runtime.Composable public final long plainTooltipContentColor;
+ property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape richTooltipContainerShape;
+ field public static final androidx.compose.material3.TooltipDefaults INSTANCE;
+ }
+
+ public final class TooltipKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void PlainTooltip(optional androidx.compose.ui.Modifier modifier, optional long contentColor, optional long containerColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.ui.graphics.Shape shape, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void PlainTooltipBox(kotlin.jvm.functions.Function0<kotlin.Unit> tooltip, optional androidx.compose.ui.Modifier modifier, optional boolean focusable, optional androidx.compose.material3.PlainTooltipState tooltipState, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional float tonalElevation, optional float shadowElevation, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.material3.TooltipBoxScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void RichTooltip(optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? action, optional androidx.compose.material3.RichTooltipColors colors, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.ui.graphics.Shape shape, kotlin.jvm.functions.Function0<kotlin.Unit> text);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void RichTooltipBox(kotlin.jvm.functions.Function0<kotlin.Unit> text, optional androidx.compose.ui.Modifier modifier, optional boolean focusable, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? action, optional androidx.compose.material3.RichTooltipState tooltipState, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.RichTooltipColors colors, optional float tonalElevation, optional float shadowElevation, kotlin.jvm.functions.Function1<? super androidx.compose.material3.TooltipBoxScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TooltipBox(androidx.compose.ui.window.PopupPositionProvider positionProvider, kotlin.jvm.functions.Function0<kotlin.Unit> tooltip, androidx.compose.material3.TooltipState state, optional androidx.compose.ui.Modifier modifier, optional boolean focusable, optional boolean enableUserInput, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static androidx.compose.material3.TooltipState TooltipState(optional boolean initialIsVisible, optional boolean isPersistent, optional androidx.compose.foundation.MutatorMutex mutatorMutex);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.PlainTooltipState rememberPlainTooltipState(optional androidx.compose.foundation.MutatorMutex mutatorMutex);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.RichTooltipState rememberRichTooltipState(boolean isPersistent, optional androidx.compose.foundation.MutatorMutex mutatorMutex);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.TooltipState rememberTooltipState(optional boolean initialIsVisible, optional boolean isPersistent, optional androidx.compose.foundation.MutatorMutex mutatorMutex);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public interface TooltipState extends androidx.compose.material3.BasicTooltipState {
+ method public androidx.compose.animation.core.MutableTransitionState<java.lang.Boolean> getTransition();
+ property public abstract androidx.compose.animation.core.MutableTransitionState<java.lang.Boolean> transition;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class TopAppBarColors {
+ ctor public TopAppBarColors(long containerColor, long scrolledContainerColor, long navigationIconContentColor, long titleContentColor, long actionIconContentColor);
+ method public long getActionIconContentColor();
+ method public long getContainerColor();
+ method public long getNavigationIconContentColor();
+ method public long getScrolledContainerColor();
+ method public long getTitleContentColor();
+ property public final long actionIconContentColor;
+ property public final long containerColor;
+ property public final long navigationIconContentColor;
+ property public final long scrolledContainerColor;
+ property public final long titleContentColor;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class TopAppBarDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.TopAppBarColors centerAlignedTopAppBarColors(optional long containerColor, optional long scrolledContainerColor, optional long navigationIconContentColor, optional long titleContentColor, optional long actionIconContentColor);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TopAppBarScrollBehavior enterAlwaysScrollBehavior(optional androidx.compose.material3.TopAppBarState state, optional kotlin.jvm.functions.Function0<java.lang.Boolean> canScroll, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float>? snapAnimationSpec, optional androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float>? flingAnimationSpec);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TopAppBarScrollBehavior exitUntilCollapsedScrollBehavior(optional androidx.compose.material3.TopAppBarState state, optional kotlin.jvm.functions.Function0<java.lang.Boolean> canScroll, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float>? snapAnimationSpec, optional androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float>? flingAnimationSpec);
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.TopAppBarColors largeTopAppBarColors(optional long containerColor, optional long scrolledContainerColor, optional long navigationIconContentColor, optional long titleContentColor, optional long actionIconContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.TopAppBarColors mediumTopAppBarColors(optional long containerColor, optional long scrolledContainerColor, optional long navigationIconContentColor, optional long titleContentColor, optional long actionIconContentColor);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TopAppBarScrollBehavior pinnedScrollBehavior(optional androidx.compose.material3.TopAppBarState state, optional kotlin.jvm.functions.Function0<java.lang.Boolean> canScroll);
+ method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.TopAppBarColors smallTopAppBarColors(optional long containerColor, optional long scrolledContainerColor, optional long navigationIconContentColor, optional long titleContentColor, optional long actionIconContentColor);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.TopAppBarColors topAppBarColors(optional long containerColor, optional long scrolledContainerColor, optional long navigationIconContentColor, optional long titleContentColor, optional long actionIconContentColor);
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+ field public static final androidx.compose.material3.TopAppBarDefaults INSTANCE;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public interface TopAppBarScrollBehavior {
+ method public androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float>? getFlingAnimationSpec();
+ method public androidx.compose.ui.input.nestedscroll.NestedScrollConnection getNestedScrollConnection();
+ method public androidx.compose.animation.core.AnimationSpec<java.lang.Float>? getSnapAnimationSpec();
+ method public androidx.compose.material3.TopAppBarState getState();
+ method public boolean isPinned();
+ property public abstract androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float>? flingAnimationSpec;
+ property public abstract boolean isPinned;
+ property public abstract androidx.compose.ui.input.nestedscroll.NestedScrollConnection nestedScrollConnection;
+ property public abstract androidx.compose.animation.core.AnimationSpec<java.lang.Float>? snapAnimationSpec;
+ property public abstract androidx.compose.material3.TopAppBarState state;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class TopAppBarState {
+ ctor public TopAppBarState(float initialHeightOffsetLimit, float initialHeightOffset, float initialContentOffset);
+ method public float getCollapsedFraction();
+ method public float getContentOffset();
+ method public float getHeightOffset();
+ method public float getHeightOffsetLimit();
+ method public float getOverlappedFraction();
+ method public void setContentOffset(float);
+ method public void setHeightOffset(float);
+ method public void setHeightOffsetLimit(float);
+ property public final float collapsedFraction;
+ property public final float contentOffset;
+ property public final float heightOffset;
+ property public final float heightOffsetLimit;
+ property public final float overlappedFraction;
+ field public static final androidx.compose.material3.TopAppBarState.Companion Companion;
+ }
+
+ public static final class TopAppBarState.Companion {
+ method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.TopAppBarState,?> getSaver();
+ property public final androidx.compose.runtime.saveable.Saver<androidx.compose.material3.TopAppBarState,?> Saver;
+ }
+
+ @androidx.compose.runtime.Immutable public final class Typography {
+ ctor public Typography(optional androidx.compose.ui.text.TextStyle displayLarge, optional androidx.compose.ui.text.TextStyle displayMedium, optional androidx.compose.ui.text.TextStyle displaySmall, optional androidx.compose.ui.text.TextStyle headlineLarge, optional androidx.compose.ui.text.TextStyle headlineMedium, optional androidx.compose.ui.text.TextStyle headlineSmall, optional androidx.compose.ui.text.TextStyle titleLarge, optional androidx.compose.ui.text.TextStyle titleMedium, optional androidx.compose.ui.text.TextStyle titleSmall, optional androidx.compose.ui.text.TextStyle bodyLarge, optional androidx.compose.ui.text.TextStyle bodyMedium, optional androidx.compose.ui.text.TextStyle bodySmall, optional androidx.compose.ui.text.TextStyle labelLarge, optional androidx.compose.ui.text.TextStyle labelMedium, optional androidx.compose.ui.text.TextStyle labelSmall);
+ method public androidx.compose.material3.Typography copy(optional androidx.compose.ui.text.TextStyle displayLarge, optional androidx.compose.ui.text.TextStyle displayMedium, optional androidx.compose.ui.text.TextStyle displaySmall, optional androidx.compose.ui.text.TextStyle headlineLarge, optional androidx.compose.ui.text.TextStyle headlineMedium, optional androidx.compose.ui.text.TextStyle headlineSmall, optional androidx.compose.ui.text.TextStyle titleLarge, optional androidx.compose.ui.text.TextStyle titleMedium, optional androidx.compose.ui.text.TextStyle titleSmall, optional androidx.compose.ui.text.TextStyle bodyLarge, optional androidx.compose.ui.text.TextStyle bodyMedium, optional androidx.compose.ui.text.TextStyle bodySmall, optional androidx.compose.ui.text.TextStyle labelLarge, optional androidx.compose.ui.text.TextStyle labelMedium, optional androidx.compose.ui.text.TextStyle labelSmall);
+ method public androidx.compose.ui.text.TextStyle getBodyLarge();
+ method public androidx.compose.ui.text.TextStyle getBodyMedium();
+ method public androidx.compose.ui.text.TextStyle getBodySmall();
+ method public androidx.compose.ui.text.TextStyle getDisplayLarge();
+ method public androidx.compose.ui.text.TextStyle getDisplayMedium();
+ method public androidx.compose.ui.text.TextStyle getDisplaySmall();
+ method public androidx.compose.ui.text.TextStyle getHeadlineLarge();
+ method public androidx.compose.ui.text.TextStyle getHeadlineMedium();
+ method public androidx.compose.ui.text.TextStyle getHeadlineSmall();
+ method public androidx.compose.ui.text.TextStyle getLabelLarge();
+ method public androidx.compose.ui.text.TextStyle getLabelMedium();
+ method public androidx.compose.ui.text.TextStyle getLabelSmall();
+ method public androidx.compose.ui.text.TextStyle getTitleLarge();
+ method public androidx.compose.ui.text.TextStyle getTitleMedium();
+ method public androidx.compose.ui.text.TextStyle getTitleSmall();
+ property public final androidx.compose.ui.text.TextStyle bodyLarge;
+ property public final androidx.compose.ui.text.TextStyle bodyMedium;
+ property public final androidx.compose.ui.text.TextStyle bodySmall;
+ property public final androidx.compose.ui.text.TextStyle displayLarge;
+ property public final androidx.compose.ui.text.TextStyle displayMedium;
+ property public final androidx.compose.ui.text.TextStyle displaySmall;
+ property public final androidx.compose.ui.text.TextStyle headlineLarge;
+ property public final androidx.compose.ui.text.TextStyle headlineMedium;
+ property public final androidx.compose.ui.text.TextStyle headlineSmall;
+ property public final androidx.compose.ui.text.TextStyle labelLarge;
+ property public final androidx.compose.ui.text.TextStyle labelMedium;
+ property public final androidx.compose.ui.text.TextStyle labelSmall;
+ property public final androidx.compose.ui.text.TextStyle titleLarge;
+ property public final androidx.compose.ui.text.TextStyle titleMedium;
+ property public final androidx.compose.ui.text.TextStyle titleSmall;
+ }
+
+}
+
+package androidx.compose.material3.pulltorefresh {
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class PullToRefreshDefaults {
+ method @androidx.compose.runtime.Composable public void Indicator(androidx.compose.material3.pulltorefresh.PullToRefreshState state, optional androidx.compose.ui.Modifier modifier, optional long color);
+ method @androidx.compose.runtime.Composable public long getContainerColor();
+ method @androidx.compose.runtime.Composable public long getContentColor();
+ method public float getPositionalThreshold();
+ method public androidx.compose.ui.graphics.Shape getShape();
+ property public final float PositionalThreshold;
+ property @androidx.compose.runtime.Composable public final long containerColor;
+ property @androidx.compose.runtime.Composable public final long contentColor;
+ property public final androidx.compose.ui.graphics.Shape shape;
+ field public static final androidx.compose.material3.pulltorefresh.PullToRefreshDefaults INSTANCE;
+ }
+
+ public final class PullToRefreshKt {
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void PullToRefreshContainer(androidx.compose.material3.pulltorefresh.PullToRefreshState state, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.pulltorefresh.PullToRefreshState,kotlin.Unit> indicator, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static androidx.compose.material3.pulltorefresh.PullToRefreshState PullToRefreshState(float positionalThresholdPx, optional boolean initialRefreshing, optional kotlin.jvm.functions.Function0<java.lang.Boolean> enabled);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.pulltorefresh.PullToRefreshState rememberPullToRefreshState(optional float positionalThreshold, optional kotlin.jvm.functions.Function0<java.lang.Boolean> enabled);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public interface PullToRefreshState {
+ method public void endRefresh();
+ method public androidx.compose.ui.input.nestedscroll.NestedScrollConnection getNestedScrollConnection();
+ method public float getPositionalThreshold();
+ method @FloatRange(from=0.0) public float getProgress();
+ method @FloatRange(from=0.0) public float getVerticalOffset();
+ method public boolean isRefreshing();
+ method public void setNestedScrollConnection(androidx.compose.ui.input.nestedscroll.NestedScrollConnection);
+ method public void startRefresh();
+ property public abstract boolean isRefreshing;
+ property public abstract androidx.compose.ui.input.nestedscroll.NestedScrollConnection nestedScrollConnection;
+ property public abstract float positionalThreshold;
+ property @FloatRange(from=0.0) public abstract float progress;
+ property @FloatRange(from=0.0) public abstract float verticalOffset;
+ }
+
+}
+
diff --git a/compose/material3/material3/api/restricted_current.txt b/compose/material3/material3/api/restricted_current.txt
index c4701d4..7ca2ade 100644
--- a/compose/material3/material3/api/restricted_current.txt
+++ b/compose/material3/material3/api/restricted_current.txt
@@ -597,43 +597,19 @@
property public abstract kotlin.ranges.IntRange yearRange;
}
- @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum DismissDirection {
- method public static androidx.compose.material3.DismissDirection valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
- method public static androidx.compose.material3.DismissDirection[] values();
- enum_constant public static final androidx.compose.material3.DismissDirection EndToStart;
- enum_constant public static final androidx.compose.material3.DismissDirection StartToEnd;
+ @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum DismissDirection {
+ method @Deprecated public static androidx.compose.material3.DismissDirection valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method @Deprecated public static androidx.compose.material3.DismissDirection[] values();
+ enum_constant @Deprecated public static final androidx.compose.material3.DismissDirection EndToStart;
+ enum_constant @Deprecated public static final androidx.compose.material3.DismissDirection StartToEnd;
}
- public final class DismissState {
- ctor public DismissState(androidx.compose.material3.DismissValue initialValue, androidx.compose.ui.unit.Density density, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.DismissValue,java.lang.Boolean> confirmValueChange, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold);
- ctor @Deprecated public DismissState(androidx.compose.material3.DismissValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.DismissValue,java.lang.Boolean> confirmValueChange, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold);
- method public suspend Object? dismiss(androidx.compose.material3.DismissDirection direction, kotlin.coroutines.Continuation<? super kotlin.Unit>);
- method public androidx.compose.material3.DismissValue getCurrentValue();
- method public androidx.compose.material3.DismissDirection? getDismissDirection();
- method public float getProgress();
- method public androidx.compose.material3.DismissValue getTargetValue();
- method public boolean isDismissed(androidx.compose.material3.DismissDirection direction);
- method public float requireOffset();
- method public suspend Object? reset(kotlin.coroutines.Continuation<? super kotlin.Unit>);
- method public suspend Object? snapTo(androidx.compose.material3.DismissValue targetValue, kotlin.coroutines.Continuation<? super kotlin.Unit>);
- property public final androidx.compose.material3.DismissValue currentValue;
- property public final androidx.compose.material3.DismissDirection? dismissDirection;
- property public final float progress;
- property public final androidx.compose.material3.DismissValue targetValue;
- field public static final androidx.compose.material3.DismissState.Companion Companion;
- }
-
- public static final class DismissState.Companion {
- method @Deprecated public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.DismissState,androidx.compose.material3.DismissValue> Saver(kotlin.jvm.functions.Function1<? super androidx.compose.material3.DismissValue,java.lang.Boolean> confirmValueChange, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold);
- method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.DismissState,androidx.compose.material3.DismissValue> Saver(kotlin.jvm.functions.Function1<? super androidx.compose.material3.DismissValue,java.lang.Boolean> confirmValueChange, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold, androidx.compose.ui.unit.Density density);
- }
-
- @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum DismissValue {
- method public static androidx.compose.material3.DismissValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
- method public static androidx.compose.material3.DismissValue[] values();
- enum_constant public static final androidx.compose.material3.DismissValue Default;
- enum_constant public static final androidx.compose.material3.DismissValue DismissedToEnd;
- enum_constant public static final androidx.compose.material3.DismissValue DismissedToStart;
+ @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum DismissValue {
+ method @Deprecated public static androidx.compose.material3.DismissValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method @Deprecated public static androidx.compose.material3.DismissValue[] values();
+ enum_constant @Deprecated public static final androidx.compose.material3.DismissValue Default;
+ enum_constant @Deprecated public static final androidx.compose.material3.DismissValue DismissedToEnd;
+ enum_constant @Deprecated public static final androidx.compose.material3.DismissValue DismissedToStart;
}
@SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class DisplayMode {
@@ -1559,15 +1535,45 @@
}
@SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class SwipeToDismissBoxDefaults {
- method @androidx.compose.runtime.Composable public kotlin.jvm.functions.Function1<java.lang.Float,java.lang.Float> getFixedPositionalThreshold();
- property @androidx.compose.runtime.Composable public final kotlin.jvm.functions.Function1<java.lang.Float,java.lang.Float> fixedPositionalThreshold;
+ method @androidx.compose.runtime.Composable public kotlin.jvm.functions.Function1<java.lang.Float,java.lang.Float> getPositionalThreshold();
+ property @androidx.compose.runtime.Composable public final kotlin.jvm.functions.Function1<java.lang.Float,java.lang.Float> positionalThreshold;
field public static final androidx.compose.material3.SwipeToDismissBoxDefaults INSTANCE;
}
public final class SwipeToDismissBoxKt {
- method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismiss(androidx.compose.material3.DismissState state, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> background, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> dismissContent, optional androidx.compose.ui.Modifier modifier, optional java.util.Set<? extends androidx.compose.material3.DismissDirection> directions);
- method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismissBox(androidx.compose.material3.DismissState state, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> backgroundContent, optional androidx.compose.ui.Modifier modifier, optional java.util.Set<? extends androidx.compose.material3.DismissDirection> directions, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
- method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.DismissState rememberDismissState(optional androidx.compose.material3.DismissValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.DismissValue,java.lang.Boolean> confirmValueChange, optional kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold);
+ method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismiss(androidx.compose.material3.SwipeToDismissState state, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> background, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> dismissContent, optional androidx.compose.ui.Modifier modifier, optional java.util.Set<? extends androidx.compose.material3.SwipeToDismissValue> directions);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismissBox(androidx.compose.material3.SwipeToDismissState state, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> backgroundContent, optional androidx.compose.ui.Modifier modifier, optional boolean enableDismissFromStartToEnd, optional boolean enableDismissFromEndToStart, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.SwipeToDismissState rememberSwipeToDismissState(optional androidx.compose.material3.SwipeToDismissValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SwipeToDismissValue,java.lang.Boolean> confirmValueChange, optional kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class SwipeToDismissState {
+ ctor public SwipeToDismissState(androidx.compose.material3.SwipeToDismissValue initialValue, androidx.compose.ui.unit.Density density, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SwipeToDismissValue,java.lang.Boolean> confirmValueChange, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold);
+ method public suspend Object? dismiss(androidx.compose.material3.SwipeToDismissValue direction, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public androidx.compose.material3.SwipeToDismissValue getCurrentValue();
+ method public androidx.compose.material3.SwipeToDismissValue getDismissDirection();
+ method @FloatRange(from=0.0, to=1.0) public float getProgress();
+ method public androidx.compose.material3.SwipeToDismissValue getTargetValue();
+ method @Deprecated public boolean isDismissed(androidx.compose.material3.DismissDirection direction);
+ method public float requireOffset();
+ method public suspend Object? reset(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public suspend Object? snapTo(androidx.compose.material3.SwipeToDismissValue targetValue, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ property public final androidx.compose.material3.SwipeToDismissValue currentValue;
+ property public final androidx.compose.material3.SwipeToDismissValue dismissDirection;
+ property @FloatRange(from=0.0, to=1.0) public final float progress;
+ property public final androidx.compose.material3.SwipeToDismissValue targetValue;
+ field public static final androidx.compose.material3.SwipeToDismissState.Companion Companion;
+ }
+
+ public static final class SwipeToDismissState.Companion {
+ method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.SwipeToDismissState,androidx.compose.material3.SwipeToDismissValue> Saver(kotlin.jvm.functions.Function1<? super androidx.compose.material3.SwipeToDismissValue,java.lang.Boolean> confirmValueChange, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold, androidx.compose.ui.unit.Density density);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum SwipeToDismissValue {
+ method public static androidx.compose.material3.SwipeToDismissValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.compose.material3.SwipeToDismissValue[] values();
+ enum_constant public static final androidx.compose.material3.SwipeToDismissValue EndToStart;
+ enum_constant public static final androidx.compose.material3.SwipeToDismissValue Settled;
+ enum_constant public static final androidx.compose.material3.SwipeToDismissValue StartToEnd;
}
@androidx.compose.runtime.Immutable public final class SwitchColors {
diff --git a/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/SwipeToDismissDemo.kt b/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/SwipeToDismissDemo.kt
index 6f691ed..f751e9f 100644
--- a/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/SwipeToDismissDemo.kt
+++ b/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/SwipeToDismissDemo.kt
@@ -16,10 +16,8 @@
package androidx.compose.material3.demos
-import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateFloatAsState
-import androidx.compose.animation.shrinkHorizontally
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
@@ -30,14 +28,13 @@
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Done
import androidx.compose.material3.Card
-import androidx.compose.material3.DismissDirection
-import androidx.compose.material3.DismissValue
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem
import androidx.compose.material3.SwipeToDismissBox
+import androidx.compose.material3.SwipeToDismissValue
import androidx.compose.material3.Text
-import androidx.compose.material3.rememberDismissState
+import androidx.compose.material3.rememberSwipeToDismissState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -86,79 +83,75 @@
var unread by remember { mutableStateOf(false) }
val scope = rememberCoroutineScope()
- val dismissState = rememberDismissState(
+ val dismissState = rememberSwipeToDismissState(
confirmValueChange = {
- if (it == DismissValue.DismissedToEnd) unread = !unread
- it != DismissValue.DismissedToEnd
+ if (it == SwipeToDismissValue.StartToEnd) unread = !unread
+ it != SwipeToDismissValue.StartToEnd
},
positionalThreshold = { distance -> distance * .25f }
)
- val isDismissed = dismissState.isDismissed(DismissDirection.EndToStart)
- AnimatedVisibility(
- visible = !isDismissed,
- exit = shrinkHorizontally(shrinkTowards = Alignment.Start)
- ) {
- SwipeToDismissBox(
- state = dismissState,
- backgroundContent = {
- val direction = dismissState.dismissDirection ?: return@SwipeToDismissBox
- val color by animateColorAsState(
- when (dismissState.targetValue) {
- DismissValue.Default -> Color.LightGray
- DismissValue.DismissedToEnd -> Color.Green
- DismissValue.DismissedToStart -> Color.Red
- }
- )
- val alignment = when (direction) {
- DismissDirection.StartToEnd -> Alignment.CenterStart
- DismissDirection.EndToStart -> Alignment.CenterEnd
+ SwipeToDismissBox(
+ state = dismissState,
+ modifier = Modifier.padding(vertical = 4.dp),
+ backgroundContent = {
+ val direction = dismissState.dismissDirection
+ val color by animateColorAsState(
+ when (dismissState.targetValue) {
+ SwipeToDismissValue.Settled -> Color.LightGray
+ SwipeToDismissValue.StartToEnd -> Color.Green
+ SwipeToDismissValue.EndToStart -> Color.Red
}
- val icon = when (direction) {
- DismissDirection.StartToEnd -> Icons.Default.Done
- DismissDirection.EndToStart -> Icons.Default.Delete
- }
- val scale by animateFloatAsState(
- if (dismissState.targetValue == DismissValue.Default)
- 0.75f else 1f
- )
- Box(
- Modifier
- .fillMaxSize()
- .background(color)
- .padding(horizontal = 20.dp),
- contentAlignment = alignment
- ) {
- Icon(
- icon,
- contentDescription = "Localized description",
- modifier = Modifier.scale(scale)
- )
- }
- },
- modifier = Modifier.padding(vertical = 4.dp)
- ) {
- Card {
- ListItem(
- headlineContent = {
- Text(item, fontWeight = if (unread) FontWeight.Bold else null)
- },
- modifier = Modifier.semantics {
- // Provide accessible alternatives to swipe actions.
- val label = if (unread) "Mark Read" else "Mark Unread"
- customActions = listOf(
- CustomAccessibilityAction(label) { unread = !unread; true },
- CustomAccessibilityAction("Delete") {
- scope.launch {
- dismissState.dismiss(DismissDirection.EndToStart)
- }
- true
- }
- )
- },
- supportingContent = { Text("Swipe me left or right!") },
+ )
+ val alignment = when (direction) {
+ SwipeToDismissValue.StartToEnd,
+ SwipeToDismissValue.Settled -> Alignment.CenterStart
+ SwipeToDismissValue.EndToStart -> Alignment.CenterEnd
+ }
+ val icon = when (direction) {
+ SwipeToDismissValue.StartToEnd,
+ SwipeToDismissValue.Settled -> Icons.Default.Done
+ SwipeToDismissValue.EndToStart -> Icons.Default.Delete
+ }
+ val scale by animateFloatAsState(
+ if (dismissState.targetValue == SwipeToDismissValue.Settled)
+ 0.75f else 1f
+ )
+ Box(
+ Modifier
+ .fillMaxSize()
+ .background(color)
+ .padding(horizontal = 20.dp),
+ contentAlignment = alignment
+ ) {
+ Icon(
+ icon,
+ contentDescription = "Localized description",
+ modifier = Modifier.scale(scale)
)
}
}
+ ) {
+ Card {
+ ListItem(
+ headlineContent = {
+ Text(item, fontWeight = if (unread) FontWeight.Bold else null)
+ },
+ modifier = Modifier.semantics {
+ // Provide accessible alternatives to swipe actions.
+ val label = if (unread) "Mark Read" else "Mark Unread"
+ customActions = listOf(
+ CustomAccessibilityAction(label) { unread = !unread; true },
+ CustomAccessibilityAction("Delete") {
+ scope.launch {
+ dismissState.dismiss(SwipeToDismissValue.EndToStart)
+ }
+ true
+ }
+ )
+ },
+ supportingContent = { Text("Swipe me left or right!") },
+ )
+ }
}
}
}
diff --git a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/SwipeToDismissSamples.kt b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/SwipeToDismissSamples.kt
index 81d3b8e..b883b78 100644
--- a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/SwipeToDismissSamples.kt
+++ b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/SwipeToDismissSamples.kt
@@ -22,15 +22,13 @@
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Card
-import androidx.compose.material3.DismissValue.Default
-import androidx.compose.material3.DismissValue.DismissedToEnd
-import androidx.compose.material3.DismissValue.DismissedToStart
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.ListItem
import androidx.compose.material3.SwipeToDismissBox
+import androidx.compose.material3.SwipeToDismissValue
import androidx.compose.material3.Text
-import androidx.compose.material3.rememberDismissState
+import androidx.compose.material3.rememberSwipeToDismissState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
@@ -42,15 +40,15 @@
@Composable
@ExperimentalMaterial3Api
fun SwipeToDismissListItems() {
- val dismissState = rememberDismissState()
+ val dismissState = rememberSwipeToDismissState()
SwipeToDismissBox(
state = dismissState,
backgroundContent = {
val color by animateColorAsState(
when (dismissState.targetValue) {
- Default -> Color.LightGray
- DismissedToEnd -> Color.Green
- DismissedToStart -> Color.Red
+ SwipeToDismissValue.Settled -> Color.LightGray
+ SwipeToDismissValue.StartToEnd -> Color.Green
+ SwipeToDismissValue.EndToStart -> Color.Red
}
)
Box(Modifier.fillMaxSize().background(color))
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/OutlinedTextFieldTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/OutlinedTextFieldTest.kt
index 5927542..7a5781b 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/OutlinedTextFieldTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/OutlinedTextFieldTest.kt
@@ -631,6 +631,40 @@
}
@Test
+ fun testOutlinedTextField_placeholderColor_whenInputEmptyAndFocused() {
+ var focused = false
+ rule.setMaterialContent(lightColorScheme()) {
+ val text = remember { mutableStateOf("") }
+ OutlinedTextField(
+ modifier = Modifier.testTag(TextFieldTag),
+ value = text.value,
+ onValueChange = { text.value = it },
+ colors = OutlinedTextFieldDefaults.colors(
+ focusedPlaceholderColor = Color.Red,
+ unfocusedPlaceholderColor = Color.Green,
+ ),
+ placeholder = {
+ Text("Placeholder")
+ assertThat(LocalContentColor.current)
+ .isEqualTo(if (focused) Color.Red else Color.Green)
+ },
+ )
+ }
+
+ // click to focus
+ focused = true
+ rule.onNodeWithTag(TextFieldTag).performClick()
+
+ // enter some text (placeholder hidden)
+ rule.onNodeWithTag(TextFieldTag).performTextInput("input")
+ rule.runOnIdle {}
+
+ // delete the text (placeholder shown)
+ rule.onNodeWithTag(TextFieldTag).performTextClearance()
+ rule.runOnIdle {}
+ }
+
+ @Test
fun testOutlinedTextField_labelAndPlaceholderPosition_whenSmallerThanMinimumHeight() {
val labelSize = 10.dp
val labelPosition = Ref<Offset>()
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/SearchBarTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/SearchBarTest.kt
index 89721c6..b025a39 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/SearchBarTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/SearchBarTest.kt
@@ -17,6 +17,7 @@
package androidx.compose.material3
import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
+import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
@@ -70,6 +71,9 @@
val dispatcher = LocalOnBackPressedDispatcherOwner.current!!.onBackPressedDispatcher
var active by remember { mutableStateOf(false) }
+ // Extra item for initial focus.
+ Box(Modifier.size(10.dp).focusable())
+
SearchBar(
modifier = Modifier.testTag(SearchBarTestTag),
query = "Query",
@@ -249,6 +253,9 @@
val dispatcher = LocalOnBackPressedDispatcherOwner.current!!.onBackPressedDispatcher
var active by remember { mutableStateOf(false) }
+ // Extra item for initial focus.
+ Box(Modifier.size(10.dp).focusable())
+
DockedSearchBar(
modifier = Modifier.testTag(SearchBarTestTag),
query = "Query",
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/SwipeToDismissTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/SwipeToDismissTest.kt
index 0ce7603..05a5858 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/SwipeToDismissTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/SwipeToDismissTest.kt
@@ -69,7 +69,7 @@
fun swipeDismiss_testOffset_whenDefault() {
rule.setContent {
SwipeToDismissBox(
- state = rememberDismissState(DismissValue.Default),
+ state = rememberSwipeToDismissState(SwipeToDismissValue.Settled),
backgroundContent = { }
) {
Box(
@@ -87,7 +87,7 @@
fun swipeDismiss_testOffset_whenDismissedToEnd() {
rule.setContent {
SwipeToDismissBox(
- state = rememberDismissState(DismissValue.DismissedToEnd),
+ state = rememberSwipeToDismissState(SwipeToDismissValue.StartToEnd),
backgroundContent = { }
) {
Box(
@@ -106,8 +106,8 @@
fun swipeDismiss_testOffset_whenDismissedToStart() {
rule.setContent {
SwipeToDismissBox(
- state = rememberDismissState(DismissValue.DismissedToStart),
- backgroundContent = { }
+ state = rememberSwipeToDismissState(SwipeToDismissValue.EndToStart),
+ backgroundContent = { },
) {
Box(
Modifier
@@ -125,7 +125,7 @@
fun swipeDismiss_testBackgroundMatchesContentSize() {
rule.setContent {
SwipeToDismissBox(
- state = rememberDismissState(DismissValue.Default),
+ state = rememberSwipeToDismissState(SwipeToDismissValue.Settled),
backgroundContent = {
Box(
Modifier
@@ -142,14 +142,15 @@
@Test
fun swipeDismiss_dismissBySwipe_toEnd() {
- lateinit var dismissState: DismissState
+ lateinit var swipeToDismissState: SwipeToDismissState
rule.setContent {
- dismissState = rememberDismissState(DismissValue.Default)
+ swipeToDismissState = rememberSwipeToDismissState(SwipeToDismissValue.Settled)
SwipeToDismissBox(
- state = dismissState,
- backgroundContent = { },
+ state = swipeToDismissState,
modifier = Modifier.testTag(swipeDismissTag),
- directions = setOf(DismissDirection.StartToEnd)
+ enableDismissFromStartToEnd = true,
+ enableDismissFromEndToStart = false,
+ backgroundContent = { }
) { Box(Modifier.fillMaxSize()) }
}
@@ -158,20 +159,21 @@
advanceClock()
rule.runOnIdle {
- assertThat(dismissState.currentValue).isEqualTo(DismissValue.DismissedToEnd)
+ assertThat(swipeToDismissState.currentValue).isEqualTo(SwipeToDismissValue.StartToEnd)
}
}
@Test
fun swipeDismiss_dismissBySwipe_toStart() {
- lateinit var dismissState: DismissState
+ lateinit var swipeToDismissState: SwipeToDismissState
rule.setContent {
- dismissState = rememberDismissState(DismissValue.Default)
+ swipeToDismissState = rememberSwipeToDismissState(SwipeToDismissValue.Settled)
SwipeToDismissBox(
- state = dismissState,
- backgroundContent = { },
+ state = swipeToDismissState,
modifier = Modifier.testTag(swipeDismissTag),
- directions = setOf(DismissDirection.EndToStart)
+ enableDismissFromStartToEnd = false,
+ enableDismissFromEndToStart = true,
+ backgroundContent = { },
) { Box(Modifier.fillMaxSize()) }
}
@@ -180,21 +182,22 @@
advanceClock()
rule.runOnIdle {
- assertThat(dismissState.currentValue).isEqualTo(DismissValue.DismissedToStart)
+ assertThat(swipeToDismissState.currentValue).isEqualTo(SwipeToDismissValue.EndToStart)
}
}
@Test
fun swipeDismiss_dismissBySwipe_toEnd_rtl() {
- lateinit var dismissState: DismissState
+ lateinit var swipeToDismissState: SwipeToDismissState
rule.setContent {
- dismissState = rememberDismissState(DismissValue.Default)
+ swipeToDismissState = rememberSwipeToDismissState()
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) {
SwipeToDismissBox(
- state = dismissState,
- backgroundContent = { },
+ state = swipeToDismissState,
modifier = Modifier.testTag(swipeDismissTag),
- directions = setOf(DismissDirection.StartToEnd)
+ enableDismissFromStartToEnd = true,
+ enableDismissFromEndToStart = false,
+ backgroundContent = { },
) { Box(Modifier.fillMaxSize()) }
}
}
@@ -204,21 +207,22 @@
advanceClock()
rule.runOnIdle {
- assertThat(dismissState.currentValue).isEqualTo(DismissValue.DismissedToEnd)
+ assertThat(swipeToDismissState.currentValue).isEqualTo(SwipeToDismissValue.StartToEnd)
}
}
@Test
fun swipeDismiss_dismissBySwipe_toStart_rtl() {
- lateinit var dismissState: DismissState
+ lateinit var swipeToDismissState: SwipeToDismissState
rule.setContent {
- dismissState = rememberDismissState(DismissValue.Default)
+ swipeToDismissState = rememberSwipeToDismissState(SwipeToDismissValue.Settled)
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) {
SwipeToDismissBox(
- state = dismissState,
- backgroundContent = { },
+ state = swipeToDismissState,
modifier = Modifier.testTag(swipeDismissTag),
- directions = setOf(DismissDirection.EndToStart)
+ enableDismissFromStartToEnd = false,
+ enableDismissFromEndToStart = true,
+ backgroundContent = { },
) { Box(Modifier.fillMaxSize()) }
}
}
@@ -228,20 +232,21 @@
advanceClock()
rule.runOnIdle {
- assertThat(dismissState.currentValue).isEqualTo(DismissValue.DismissedToStart)
+ assertThat(swipeToDismissState.currentValue).isEqualTo(SwipeToDismissValue.EndToStart)
}
}
@Test
fun swipeDismiss_dismissBySwipe_disabled() {
- lateinit var dismissState: DismissState
+ lateinit var swipeToDismissState: SwipeToDismissState
rule.setContent {
- dismissState = rememberDismissState(DismissValue.Default)
+ swipeToDismissState = rememberSwipeToDismissState(SwipeToDismissValue.Settled)
SwipeToDismissBox(
- state = dismissState,
- backgroundContent = { },
+ state = swipeToDismissState,
modifier = Modifier.testTag(swipeDismissTag),
- directions = setOf()
+ enableDismissFromStartToEnd = false,
+ enableDismissFromEndToStart = false,
+ backgroundContent = { },
) { Box(Modifier.fillMaxSize()) }
}
@@ -250,7 +255,7 @@
advanceClock()
rule.runOnIdle {
- assertThat(dismissState.currentValue).isEqualTo(DismissValue.Default)
+ assertThat(swipeToDismissState.currentValue).isEqualTo(SwipeToDismissValue.Settled)
}
rule.onNodeWithTag(swipeDismissTag).performTouchInput { swipeLeft() }
@@ -258,7 +263,7 @@
advanceClock()
rule.runOnIdle {
- assertThat(dismissState.currentValue).isEqualTo(DismissValue.Default)
+ assertThat(swipeToDismissState.currentValue).isEqualTo(SwipeToDismissValue.Settled)
}
}
@@ -273,7 +278,7 @@
lateinit var lazyState: LazyListState
lateinit var scope: CoroutineScope
val amountOfItems = 100
- val composedItems = mutableMapOf<Int, DismissState>()
+ val composedItems = mutableMapOf<Int, SwipeToDismissState>()
rule.setContent {
scope = rememberCoroutineScope()
@@ -281,9 +286,9 @@
lazyState = rememberLazyListState()
LazyColumn(state = lazyState) {
items(amountOfItems, key = { item -> item }) { index ->
- composedItems[index] = rememberDismissState()
- val isDismissed = composedItems[index]!!
- .isDismissed(DismissDirection.EndToStart)
+ composedItems[index] = rememberSwipeToDismissState()
+ val isDismissed =
+ composedItems[index]!!.currentValue == SwipeToDismissValue.EndToStart
AnimatedVisibility(visible = !isDismissed) {
SwipeToDismissBox(
modifier = Modifier
@@ -320,7 +325,7 @@
// Dismiss an item so that the lazy layout is required to compose a new item
scope.launch {
- composedItems[initiallyVisibleItems - 1]!!.dismiss(DismissDirection.EndToStart)
+ composedItems[initiallyVisibleItems - 1]!!.dismiss(SwipeToDismissValue.EndToStart)
}
rule.waitForIdle()
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/TextFieldTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/TextFieldTest.kt
index 8f1f3a3..0248140 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/TextFieldTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/TextFieldTest.kt
@@ -80,6 +80,7 @@
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performTextClearance
+import androidx.compose.ui.test.performTextInput
import androidx.compose.ui.test.performTouchInput
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.buildAnnotatedString
@@ -590,6 +591,40 @@
}
@Test
+ fun testTextField_placeholderColor_whenInputEmptyAndFocused() {
+ var focused = false
+ rule.setMaterialContent(lightColorScheme()) {
+ val text = remember { mutableStateOf("") }
+ TextField(
+ modifier = Modifier.testTag(TextFieldTag),
+ value = text.value,
+ onValueChange = { text.value = it },
+ colors = TextFieldDefaults.colors(
+ focusedPlaceholderColor = Color.Red,
+ unfocusedPlaceholderColor = Color.Green,
+ ),
+ placeholder = {
+ Text("Placeholder")
+ assertThat(LocalContentColor.current)
+ .isEqualTo(if (focused) Color.Red else Color.Green)
+ },
+ )
+ }
+
+ // click to focus
+ focused = true
+ rule.onNodeWithTag(TextFieldTag).performClick()
+
+ // enter some text (placeholder hidden)
+ rule.onNodeWithTag(TextFieldTag).performTextInput("input")
+ rule.runOnIdle {}
+
+ // delete the text (placeholder shown)
+ rule.onNodeWithTag(TextFieldTag).performTextClearance()
+ rule.runOnIdle {}
+ }
+
+ @Test
fun testTextField_labelAndPlaceholderPosition_whenSmallerThanMinimumHeight() {
val labelSize = 10.dp
val labelPosition = Ref<Offset>()
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Chip.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Chip.kt
index e9d0618..ad8a03e 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Chip.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Chip.kt
@@ -28,13 +28,10 @@
import androidx.compose.foundation.interaction.PressInteraction
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.width
import androidx.compose.material3.tokens.AssistChipTokens
import androidx.compose.material3.tokens.FilterChipTokens
import androidx.compose.material3.tokens.InputChipTokens
@@ -56,12 +53,18 @@
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.layout.Placeable
+import androidx.compose.ui.layout.layoutId
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.role
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.offset
+import androidx.compose.ui.util.fastFirst
+import androidx.compose.ui.util.fastFirstOrNull
/**
* <a href="https://m3.material.io/components/chips/overview" class="external" target="_blank">Material Design assist chip</a>.
@@ -1778,31 +1781,80 @@
LocalContentColor provides labelColor,
LocalTextStyle provides labelTextStyle
) {
- Row(
- Modifier
- .width(IntrinsicSize.Max)
+ Layout(
+ modifier = Modifier
.defaultMinSize(minHeight = minHeight)
.padding(paddingValues),
- horizontalArrangement = Arrangement.Start,
- verticalAlignment = Alignment.CenterVertically
- ) {
- if (avatar != null) {
- avatar()
- } else if (leadingIcon != null) {
- CompositionLocalProvider(
- LocalContentColor provides leadingIconColor, content = leadingIcon
+ content = {
+ if (avatar != null || leadingIcon != null) {
+ Box(
+ modifier = Modifier
+ .layoutId(LeadingIconLayoutId),
+ contentAlignment = Alignment.Center,
+ content = {
+ if (avatar != null) {
+ avatar()
+ } else if (leadingIcon != null) {
+ CompositionLocalProvider(
+ LocalContentColor provides leadingIconColor,
+ content = leadingIcon
+ )
+ }
+ }
+ )
+ }
+ Row(
+ modifier = Modifier
+ .layoutId(LabelLayoutId)
+ .padding(HorizontalElementsPadding, 0.dp),
+ horizontalArrangement = Arrangement.Start,
+ verticalAlignment = Alignment.CenterVertically,
+ content = { label() }
)
+ if (trailingIcon != null) {
+ Box(
+ modifier = Modifier
+ .layoutId(TrailingIconLayoutId),
+ contentAlignment = Alignment.Center,
+ content = {
+ CompositionLocalProvider(
+ LocalContentColor provides trailingIconColor,
+ content = trailingIcon
+ )
+ }
+ )
+ }
}
- Spacer(Modifier.width(HorizontalElementsPadding))
- Row(
- modifier = Modifier.weight(1f),
- horizontalArrangement = Arrangement.Start,
- verticalAlignment = Alignment.CenterVertically
- ) { label() }
- Spacer(Modifier.width(HorizontalElementsPadding))
- if (trailingIcon != null) {
- CompositionLocalProvider(
- LocalContentColor provides trailingIconColor, content = trailingIcon
+ ) { measurables, constraints ->
+ val leadingIconPlaceable: Placeable? =
+ measurables.fastFirstOrNull { it.layoutId == LeadingIconLayoutId }
+ ?.measure(constraints.copy(minWidth = 0, minHeight = 0))
+ val leadingIconWidth = widthOrZero(leadingIconPlaceable)
+ val leadingIconHeight = heightOrZero(leadingIconPlaceable)
+
+ val trailingIconPlaceable: Placeable? =
+ measurables.fastFirstOrNull { it.layoutId == TrailingIconLayoutId }
+ ?.measure(constraints.copy(minWidth = 0, minHeight = 0))
+ val trailingIconWidth = widthOrZero(trailingIconPlaceable)
+ val trailingIconHeight = heightOrZero(trailingIconPlaceable)
+
+ val labelPlaceable = measurables.fastFirst { it.layoutId == LabelLayoutId }
+ .measure(
+ constraints.offset(horizontal = -(leadingIconWidth + trailingIconWidth))
+ )
+
+ val width = leadingIconWidth + labelPlaceable.width + trailingIconWidth
+ val height = maxOf(leadingIconHeight, labelPlaceable.height, trailingIconHeight)
+
+ layout(width, height) {
+ leadingIconPlaceable?.placeRelative(
+ 0,
+ Alignment.CenterVertically.align(leadingIconHeight, height)
+ )
+ labelPlaceable.placeRelative(leadingIconWidth, 0)
+ trailingIconPlaceable?.placeRelative(
+ leadingIconWidth + labelPlaceable.width,
+ Alignment.CenterVertically.align(trailingIconHeight, height)
)
}
}
@@ -2435,3 +2487,7 @@
* Returns the [PaddingValues] for the suggestion chip.
*/
private val SuggestionChipPadding = PaddingValues(horizontal = HorizontalElementsPadding)
+
+private const val LeadingIconLayoutId = "leadingIcon"
+private const val LabelLayoutId = "label"
+private const val TrailingIconLayoutId = "trailingIcon"
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SwipeToDismissBox.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SwipeToDismissBox.kt
index a22cbe7..ebbe7c7 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SwipeToDismissBox.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SwipeToDismissBox.kt
@@ -16,18 +16,13 @@
package androidx.compose.material3
+import androidx.annotation.FloatRange
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
-import androidx.compose.material3.DismissDirection.EndToStart
-import androidx.compose.material3.DismissDirection.StartToEnd
-import androidx.compose.material3.DismissState.Companion.Saver
-import androidx.compose.material3.DismissValue.Default
-import androidx.compose.material3.DismissValue.DismissedToEnd
-import androidx.compose.material3.DismissValue.DismissedToStart
+import androidx.compose.material3.SwipeToDismissState.Companion.Saver
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.Saver
import androidx.compose.runtime.saveable.rememberSaveable
@@ -52,7 +47,7 @@
* The directions in which a [SwipeToDismissBox] can be dismissed.
*/
@ExperimentalMaterial3Api
-enum class DismissDirection {
+enum class SwipeToDismissValue {
/**
* Can be dismissed by swiping in the reading direction.
*/
@@ -61,81 +56,38 @@
/**
* Can be dismissed by swiping in the reverse of the reading direction.
*/
- EndToStart
-}
-
-/**
- * Possible values of [DismissState].
- */
-@ExperimentalMaterial3Api
-enum class DismissValue {
- /**
- * Indicates the component has not been dismissed yet.
- */
- Default,
+ EndToStart,
/**
- * Indicates the component has been dismissed in the reading direction.
+ * Cannot currently be dismissed.
*/
- DismissedToEnd,
-
- /**
- * Indicates the component has been dismissed in the reverse of the reading direction.
- */
- DismissedToStart
+ Settled
}
/**
* State of the [SwipeToDismissBox] composable.
*
* @param initialValue The initial value of the state.
+ * @param density The density that this state can use to convert values to and from dp.
* @param confirmValueChange Optional callback invoked to confirm or veto a pending state change.
* @param positionalThreshold The positional threshold to be used when calculating the target state
* while a swipe is in progress and when settling after the swipe ends. This is the distance from
* the start of a transition. It will be, depending on the direction of the interaction, added or
* subtracted from/to the origin offset. It should always be a positive value.
*/
-@OptIn(ExperimentalMaterial3Api::class)
-class DismissState @Deprecated(
- message = "This constructor is deprecated. " +
- "Please use the constructor that provides a [Density]",
- replaceWith = ReplaceWith(
- "DismissState(" +
- "initialValue, LocalDensity.current, confirmValueChange, positionalThreshold)"
- )
-) constructor(
- initialValue: DismissValue,
- confirmValueChange: (DismissValue) -> Boolean = { true },
+@ExperimentalMaterial3Api
+class SwipeToDismissState(
+ initialValue: SwipeToDismissValue,
+ internal val density: Density,
+ confirmValueChange: (SwipeToDismissValue) -> Boolean = { true },
positionalThreshold: (totalDistance: Float) -> Float
) {
-
- /**
- * State of the [SwipeToDismissBox] composable.
- *
- * @param initialValue The initial value of the state.
- * @param density The density that this state can use to convert values to and from dp.
- * @param confirmValueChange Optional callback invoked to confirm or veto a pending state change.
- * @param positionalThreshold The positional threshold to be used when calculating the target state
- * while a swipe is in progress and when settling after the swipe ends. This is the distance from
- * the start of a transition. It will be, depending on the direction of the interaction, added or
- * subtracted from/to the origin offset. It should always be a positive value.
- */
- @Suppress("Deprecation")
- constructor(
- initialValue: DismissValue,
- density: Density,
- confirmValueChange: (DismissValue) -> Boolean = { true },
- positionalThreshold: (totalDistance: Float) -> Float
- ) : this(initialValue, confirmValueChange, positionalThreshold) {
- this.density = density
- }
-
internal val anchoredDraggableState = AnchoredDraggableState(
initialValue = initialValue,
animationSpec = AnchoredDraggableDefaults.AnimationSpec,
confirmValueChange = confirmValueChange,
positionalThreshold = positionalThreshold,
- velocityThreshold = { with(requireDensity()) { DismissThreshold.toPx() } }
+ velocityThreshold = { with(density) { DismissThreshold.toPx() } }
)
internal val offset: Float get() = anchoredDraggableState.offset
@@ -148,40 +100,53 @@
fun requireOffset(): Float = anchoredDraggableState.requireOffset()
/**
- * The current state value of the [DismissState].
+ * The current state value of the [SwipeToDismissState].
*/
- val currentValue: DismissValue get() = anchoredDraggableState.currentValue
+ val currentValue: SwipeToDismissValue get() = anchoredDraggableState.currentValue
/**
* The target state. This is the closest state to the current offset (taking into account
* positional thresholds). If no interactions like animations or drags are in progress, this
* will be the current state.
*/
- val targetValue: DismissValue get() = anchoredDraggableState.targetValue
+ val targetValue: SwipeToDismissValue get() = anchoredDraggableState.targetValue
/**
* The fraction of the progress going from currentValue to targetValue, within [0f..1f] bounds.
*/
+ @get:FloatRange(from = 0.0, to = 1.0)
val progress: Float get() = anchoredDraggableState.progress
/**
* The direction (if any) in which the composable has been or is being dismissed.
*
- * If the composable is settled at the default state, then this will be null. Use this to
- * change the background of the [SwipeToDismissBox] if you want different actions on each side.
+ * Use this to change the background of the [SwipeToDismissBox] if you want different actions on each
+ * side.
*/
- val dismissDirection: DismissDirection?
+ val dismissDirection: SwipeToDismissValue
get() = if (offset == 0f || offset.isNaN())
- null
- else if (offset > 0f) StartToEnd else EndToStart
+ SwipeToDismissValue.Settled
+ else if (offset > 0f) SwipeToDismissValue.StartToEnd else SwipeToDismissValue.EndToStart
/**
* Whether the component has been dismissed in the given [direction].
*
* @param direction The dismiss direction.
*/
+ @Deprecated(
+ message = "DismissDirection is no longer used by SwipeToDismissState. Please compare " +
+ "currentValue against SwipeToDismissValue instead.",
+ level = DeprecationLevel.HIDDEN
+ )
+ @Suppress("DEPRECATION")
fun isDismissed(direction: DismissDirection): Boolean {
- return currentValue == if (direction == StartToEnd) DismissedToEnd else DismissedToStart
+ return currentValue == (
+ if (direction == DismissDirection.StartToEnd) {
+ SwipeToDismissValue.StartToEnd
+ } else {
+ SwipeToDismissValue.EndToStart
+ }
+ )
}
/**
@@ -189,7 +154,7 @@
*
* @param targetValue The new target value
*/
- suspend fun snapTo(targetValue: DismissValue) {
+ suspend fun snapTo(targetValue: SwipeToDismissValue) {
anchoredDraggableState.snapTo(targetValue)
}
@@ -200,7 +165,9 @@
*
* @return the reason the reset animation ended
*/
- suspend fun reset() = anchoredDraggableState.animateTo(targetValue = Default)
+ suspend fun reset() = anchoredDraggableState.animateTo(
+ targetValue = SwipeToDismissValue.Settled
+ )
/**
* Dismiss the component in the given [direction], with an animation and suspend. This method
@@ -208,64 +175,32 @@
*
* @param direction The dismiss direction.
*/
- suspend fun dismiss(direction: DismissDirection) {
- val targetValue = if (direction == StartToEnd) DismissedToEnd else DismissedToStart
- anchoredDraggableState.animateTo(targetValue = targetValue)
- }
-
- internal var density: Density? = null
- private fun requireDensity() = requireNotNull(density) {
- "DismissState did not have a density attached. Are you using DismissState with " +
- "the SwipeDismiss component?"
+ suspend fun dismiss(direction: SwipeToDismissValue) {
+ anchoredDraggableState.animateTo(targetValue = direction)
}
companion object {
/**
- * The default [Saver] implementation for [DismissState].
+ * The default [Saver] implementation for [SwipeToDismissState].
*/
fun Saver(
- confirmValueChange: (DismissValue) -> Boolean,
+ confirmValueChange: (SwipeToDismissValue) -> Boolean,
positionalThreshold: (totalDistance: Float) -> Float,
density: Density
- ) =
- Saver<DismissState, DismissValue>(
- save = { it.currentValue },
- restore = {
- DismissState(
- it, density, confirmValueChange, positionalThreshold
- )
- }
- )
-
- /**
- * The default [Saver] implementation for [DismissState].
- */
- @Deprecated(
- message = "This function is deprecated. Please use the overload where Density is" +
- " provided.",
- replaceWith = ReplaceWith(
- "Saver(confirmValueChange, positionalThreshold, LocalDensity.current)"
- )
+ ) = Saver<SwipeToDismissState, SwipeToDismissValue>(
+ save = { it.currentValue },
+ restore = {
+ SwipeToDismissState(
+ it, density, confirmValueChange, positionalThreshold
+ )
+ }
)
- @Suppress("Deprecation")
- fun Saver(
- confirmValueChange: (DismissValue) -> Boolean,
- positionalThreshold: (totalDistance: Float) -> Float,
- ) =
- Saver<DismissState, DismissValue>(
- save = { it.currentValue },
- restore = {
- DismissState(
- it, confirmValueChange, positionalThreshold
- )
- }
- )
}
}
/**
- * Create and [remember] a [DismissState].
+ * Create and [remember] a [SwipeToDismissState].
*
* @param initialValue The initial value of the state.
* @param confirmValueChange Optional callback invoked to confirm or veto a pending state change.
@@ -276,12 +211,12 @@
*/
@Composable
@ExperimentalMaterial3Api
-fun rememberDismissState(
- initialValue: DismissValue = Default,
- confirmValueChange: (DismissValue) -> Boolean = { true },
+fun rememberSwipeToDismissState(
+ initialValue: SwipeToDismissValue = SwipeToDismissValue.Settled,
+ confirmValueChange: (SwipeToDismissValue) -> Boolean = { true },
positionalThreshold: (totalDistance: Float) -> Float =
- SwipeToDismissBoxDefaults.fixedPositionalThreshold,
-): DismissState {
+ SwipeToDismissBoxDefaults.positionalThreshold,
+): SwipeToDismissState {
val density = LocalDensity.current
return rememberSaveable(
saver = Saver(
@@ -290,7 +225,7 @@
positionalThreshold = positionalThreshold
)
) {
- DismissState(initialValue, density, confirmValueChange, positionalThreshold)
+ SwipeToDismissState(initialValue, density, confirmValueChange, positionalThreshold)
}
}
@@ -311,16 +246,26 @@
level = DeprecationLevel.WARNING,
message = "Use SwipeToDismissBox instead",
replaceWith =
- ReplaceWith("SwipeToDismissBox(state, background, modifier, directions, dismissContent)")
+ ReplaceWith("SwipeToDismissBox(state, background, modifier, " +
+ "enableDismissFromStartToEnd, enableDismissFromEndToStart, dismissContent)")
)
@ExperimentalMaterial3Api
fun SwipeToDismiss(
- state: DismissState,
+ state: SwipeToDismissState,
background: @Composable RowScope.() -> Unit,
dismissContent: @Composable RowScope.() -> Unit,
modifier: Modifier = Modifier,
- directions: Set<DismissDirection> = setOf(EndToStart, StartToEnd),
-) = SwipeToDismissBox(state, background, modifier, directions, dismissContent)
+ directions: Set<SwipeToDismissValue> = setOf(SwipeToDismissValue.EndToStart,
+ SwipeToDismissValue.StartToEnd
+ ),
+) = SwipeToDismissBox(
+ state = state,
+ backgroundContent = background,
+ modifier = modifier,
+ enableDismissFromStartToEnd = SwipeToDismissValue.StartToEnd in directions,
+ enableDismissFromEndToStart = SwipeToDismissValue.EndToStart in directions,
+ content = dismissContent
+)
/**
* A composable that can be dismissed by swiping left or right.
@@ -328,27 +273,23 @@
* @sample androidx.compose.material3.samples.SwipeToDismissListItems
*
* @param state The state of this component.
- * @param backgroundContent A composable that is stacked behind the content and is exposed when the
+ * @param backgroundContent A composable that is stacked behind the [content] and is exposed when the
* content is swiped. You can/should use the [state] to have different backgrounds on each side.
- * @param content The content that can be dismissed.
* @param modifier Optional [Modifier] for this component.
- * @param directions The set of directions in which the component can be dismissed.
+ * @param enableDismissFromStartToEnd Whether SwipeToDismissBox can be dismissed from start to end.
+ * @param enableDismissFromEndToStart Whether SwipeToDismissBox can be dismissed from end to start.
+ * @param content The content that can be dismissed.
*/
@Composable
@ExperimentalMaterial3Api
fun SwipeToDismissBox(
- state: DismissState,
+ state: SwipeToDismissState,
backgroundContent: @Composable RowScope.() -> Unit,
modifier: Modifier = Modifier,
- directions: Set<DismissDirection> = setOf(EndToStart, StartToEnd),
+ enableDismissFromStartToEnd: Boolean = true,
+ enableDismissFromEndToStart: Boolean = true,
content: @Composable RowScope.() -> Unit,
) {
- // b/278692145 Remove this once deprecated methods without density are removed
- val density = LocalDensity.current
- SideEffect {
- state.density = density
- }
-
val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl
Box(
@@ -356,7 +297,7 @@
.anchoredDraggable(
state = state.anchoredDraggableState,
orientation = Orientation.Horizontal,
- enabled = state.currentValue == Default,
+ enabled = state.currentValue == SwipeToDismissValue.Settled,
reverseDirection = isRtl,
),
propagateMinConstraints = true
@@ -367,66 +308,134 @@
)
Row(
content = content,
- modifier = Modifier.swipeDismissAnchors(state, directions)
+ modifier = Modifier.swipeToDismissAnchors(
+ state,
+ enableDismissFromStartToEnd,
+ enableDismissFromEndToStart
+ )
)
}
}
-/** Contains default values for [SwipeToDismissBox] and [DismissState]. */
+/** Contains default values for [SwipeToDismissBox] and [SwipeToDismissState]. */
@ExperimentalMaterial3Api
object SwipeToDismissBoxDefaults {
- /** Default positional threshold of 56.dp for [DismissState]. */
- val fixedPositionalThreshold: (totalDistance: Float) -> Float
+ /** Default positional threshold of 56.dp for [SwipeToDismissState]. */
+ val positionalThreshold: (totalDistance: Float) -> Float
@Composable get() = with(LocalDensity.current) {
{ 56.dp.toPx() }
}
}
+/**
+ * The directions in which a [SwipeToDismissBox] can be dismissed.
+ */
+@ExperimentalMaterial3Api
+@Deprecated(
+ message = "Dismiss direction is no longer used by SwipeToDismissState. Please use " +
+ "SwipeToDismissValue instead.",
+ level = DeprecationLevel.WARNING
+)
+enum class DismissDirection {
+ /**
+ * Can be dismissed by swiping in the reading direction.
+ */
+ StartToEnd,
+
+ /**
+ * Can be dismissed by swiping in the reverse of the reading direction.
+ */
+ EndToStart,
+}
+
+/**
+ * Possible values of [SwipeToDismissState].
+ */
+@ExperimentalMaterial3Api
+@Deprecated(
+ message = "DismissValue is no longer used by SwipeToDismissState. Please use " +
+ "SwipeToDismissValue instead.",
+ level = DeprecationLevel.WARNING
+)
+enum class DismissValue {
+ /**
+ * Indicates the component has not been dismissed yet.
+ */
+ Default,
+
+ /**
+ * Indicates the component has been dismissed in the reading direction.
+ */
+ DismissedToEnd,
+
+ /**
+ * Indicates the component has been dismissed in the reverse of the reading direction.
+ */
+ DismissedToStart
+}
+
private val DismissThreshold = 125.dp
@OptIn(ExperimentalMaterial3Api::class)
-private fun Modifier.swipeDismissAnchors(state: DismissState, directions: Set<DismissDirection>) =
- this then SwipeDismissAnchorsElement(state, directions)
+private fun Modifier.swipeToDismissAnchors(
+ state: SwipeToDismissState,
+ enableDismissFromStartToEnd: Boolean,
+ enableDismissFromEndToStart: Boolean
+) = this then SwipeToDismissAnchorsElement(
+ state,
+ enableDismissFromStartToEnd,
+ enableDismissFromEndToStart
+)
@OptIn(ExperimentalMaterial3Api::class)
-private class SwipeDismissAnchorsElement(
- private val state: DismissState,
- private val directions: Set<DismissDirection>,
-) : ModifierNodeElement<SwipeDismissAnchorsNode>() {
+private class SwipeToDismissAnchorsElement(
+ private val state: SwipeToDismissState,
+ private val enableDismissFromStartToEnd: Boolean,
+ private val enableDismissFromEndToStart: Boolean,
+) : ModifierNodeElement<SwipeToDismissAnchorsNode>() {
- override fun create() = SwipeDismissAnchorsNode(state, directions)
+ override fun create() = SwipeToDismissAnchorsNode(
+ state,
+ enableDismissFromStartToEnd,
+ enableDismissFromEndToStart,
+ )
- override fun update(node: SwipeDismissAnchorsNode) {
+ override fun update(node: SwipeToDismissAnchorsNode) {
node.state = state
- node.directions = directions
+ node.enableDismissFromStartToEnd = enableDismissFromStartToEnd
+ node.enableDismissFromEndToStart = enableDismissFromEndToStart
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
- other as SwipeDismissAnchorsElement
+ other as SwipeToDismissAnchorsElement
if (state != other.state) return false
- if (directions != other.directions) return false
+ if (enableDismissFromStartToEnd != other.enableDismissFromStartToEnd) return false
+ if (enableDismissFromEndToStart != other.enableDismissFromEndToStart) return false
return true
}
override fun hashCode(): Int {
var result = state.hashCode()
- result = 31 * result + directions.hashCode()
+ result = 31 * result + enableDismissFromStartToEnd.hashCode()
+ result = 31 * result + enableDismissFromEndToStart.hashCode()
return result
}
override fun InspectorInfo.inspectableProperties() {
debugInspectorInfo {
properties["state"] = state
- properties["directions"] = directions
+ properties["enableDismissFromStartToEnd"] = enableDismissFromStartToEnd
+ properties["enableDismissFromEndToStart"] = enableDismissFromEndToStart
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
-private class SwipeDismissAnchorsNode(
- var state: DismissState,
- var directions: Set<DismissDirection>
+private class SwipeToDismissAnchorsNode(
+ var state: SwipeToDismissState,
+ var enableDismissFromStartToEnd: Boolean,
+ var enableDismissFromEndToStart: Boolean,
) : Modifier.Node(), LayoutModifierNode {
private var didLookahead: Boolean = false
@@ -445,12 +454,12 @@
if (isLookingAhead || !didLookahead) {
val width = placeable.width.toFloat()
val newAnchors = DraggableAnchors {
- Default at 0f
- if (StartToEnd in directions) {
- DismissedToEnd at width
+ SwipeToDismissValue.Settled at 0f
+ if (enableDismissFromStartToEnd) {
+ SwipeToDismissValue.StartToEnd at width
}
- if (EndToStart in directions) {
- DismissedToStart at -width
+ if (enableDismissFromEndToStart) {
+ SwipeToDismissValue.EndToStart at -width
}
}
state.anchoredDraggableState.updateAnchors(newAnchors)
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextFieldImpl.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextFieldImpl.kt
index af153c2..8532acf 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextFieldImpl.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextFieldImpl.kt
@@ -129,13 +129,13 @@
// Transparent components interfere with Talkback (b/261061240), so if any components below
// have alpha == 0, we set the component to null instead.
+ val placeholderColor = colors.placeholderColor(enabled, isError, interactionSource).value
val decoratedPlaceholder: @Composable ((Modifier) -> Unit)? =
if (placeholder != null && transformedText.isEmpty() && placeholderAlphaProgress > 0f) {
@Composable { modifier ->
Box(modifier.alpha(placeholderAlphaProgress)) {
Decoration(
- contentColor =
- colors.placeholderColor(enabled, isError, interactionSource).value,
+ contentColor = placeholderColor,
typography = MaterialTheme.typography.bodyLarge,
content = placeholder
)
diff --git a/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/CompositionTests.kt b/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/CompositionTests.kt
index 4b75b67..cce19c1 100644
--- a/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/CompositionTests.kt
+++ b/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/CompositionTests.kt
@@ -62,6 +62,7 @@
import kotlinx.coroutines.channels.consumeEach
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.TestCoroutineScheduler
@@ -3975,6 +3976,46 @@
assertEquals(1, consumer.invokeCount)
}
+ // regression test from b/232007227 with forEach
+ @Test
+ fun slotsAreUsedCorrectly_forEach() = compositionTest {
+ class Car(val model: String)
+ class Person(val name: String, val car: MutableStateFlow<Car>)
+
+ val people = mutableListOf<MutableStateFlow<Person?>>(
+ MutableStateFlow(Person("Ford", MutableStateFlow(Car("Model T")))),
+ MutableStateFlow(Person("Musk", MutableStateFlow(Car("Model 3"))))
+ )
+ compose {
+ people.forEach {
+ val person = it.collectAsState().value
+ Text(person?.name ?: "No person")
+ if (person != null) {
+ val car = person.car.collectAsState().value
+ Text(" ${car.model}")
+ }
+ }
+ }
+
+ validate {
+ people.forEach {
+ val person = it.value
+ Text(person?.name ?: "No person")
+ if (person != null) {
+ val car = person.car.value
+ Text(" ${car.model}")
+ }
+ }
+ }
+
+ advanceTimeBy(16_000L)
+ people[0].value = null
+ advanceTimeBy(16_000L)
+
+ expectChanges()
+ revalidate()
+ }
+
private inline fun CoroutineScope.withGlobalSnapshotManager(block: CoroutineScope.() -> Unit) {
val channel = Channel<Unit>(Channel.CONFLATED)
val job = launch {
diff --git a/compose/ui/ui-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/Offset.kt b/compose/ui/ui-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/Offset.kt
index 6f4df66..9f026f5 100644
--- a/compose/ui/ui-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/Offset.kt
+++ b/compose/ui/ui-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/Offset.kt
@@ -124,15 +124,10 @@
@Stable
fun isValid(): Boolean {
- val x = (packedValue shr 32) and FloatNonFiniteMask
- // Only check y if x didn't fail
- checkPrecondition(
- x <= FloatInfinityBase &&
- (packedValue and FloatNonFiniteMask) <= FloatInfinityBase
- ) {
- "Offset argument contained a NaN value."
- }
- return true
+ val convertX = (packedValue shr 32) and FloatNonFiniteMask
+ val convertY = packedValue and FloatNonFiniteMask
+
+ return (convertX <= FloatInfinityBase) && (convertY <= FloatInfinityBase)
}
/**
diff --git a/compose/ui/ui-graphics/api/restricted_current.txt b/compose/ui/ui-graphics/api/restricted_current.txt
index c4ca8f3..8595a42 100644
--- a/compose/ui/ui-graphics/api/restricted_current.txt
+++ b/compose/ui/ui-graphics/api/restricted_current.txt
@@ -440,6 +440,7 @@
method @androidx.compose.runtime.Stable public static float luminance(long);
method public static inline long takeOrElse(long, kotlin.jvm.functions.Function0<androidx.compose.ui.graphics.Color> block);
method @ColorInt @androidx.compose.runtime.Stable public static int toArgb(long);
+ field @kotlin.PublishedApi internal static final long UnspecifiedColor = 16L; // 0x10L
}
@kotlin.jvm.JvmInline public final value class ColorMatrix {
diff --git a/compose/ui/ui-graphics/benchmark/src/androidTest/java/androidx/compose/ui/graphics/benchmark/ColorBenchmark.kt b/compose/ui/ui-graphics/benchmark/src/androidTest/java/androidx/compose/ui/graphics/benchmark/ColorBenchmark.kt
index 0dad9cd..84a8a27 100644
--- a/compose/ui/ui-graphics/benchmark/src/androidTest/java/androidx/compose/ui/graphics/benchmark/ColorBenchmark.kt
+++ b/compose/ui/ui-graphics/benchmark/src/androidTest/java/androidx/compose/ui/graphics/benchmark/ColorBenchmark.kt
@@ -19,6 +19,7 @@
import androidx.benchmark.junit4.BenchmarkRule
import androidx.benchmark.junit4.measureRepeated
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.colorspace.ColorSpaces
import androidx.compose.ui.graphics.lerp
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
@@ -28,15 +29,26 @@
@LargeTest
@RunWith(AndroidJUnit4::class)
-open class ColorBenchmark {
+class ColorBenchmark {
@get:Rule
val benchmarkRule = BenchmarkRule()
@Test
fun colorLerp() {
benchmarkRule.measureRepeated {
- for (i in 0..1_000) {
- lerp(Color.Red, Color.Green, i / 1_000.0f)
+ for (i in 0..500) {
+ lerp(Color.Red, Color.Green, i / 500.0f)
+ }
+ }
+ }
+
+ @Test
+ fun wideColorLerp() {
+ val start = Color(1.0f, 0.0f, 0.0f, 1.0f, ColorSpaces.DisplayP3)
+ val end = Color(0.0f, 1.0f, 0.0f, 1.0f, ColorSpaces.DisplayP3)
+ benchmarkRule.measureRepeated {
+ for (i in 0..500) {
+ lerp(start, end, i / 500.0f)
}
}
}
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Color.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Color.kt
index 51b9f61e..d65109d 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Color.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Color.kt
@@ -27,6 +27,7 @@
import androidx.compose.ui.graphics.colorspace.ColorSpaces
import androidx.compose.ui.graphics.colorspace.Rgb
import androidx.compose.ui.graphics.colorspace.connect
+import androidx.compose.ui.util.fastCoerceIn
import androidx.compose.ui.util.lerp
import kotlin.math.max
import kotlin.math.min
@@ -162,8 +163,7 @@
return if ((value and 0x3fUL) == 0UL) {
((value shr 48) and 0xffUL).toFloat() / 255.0f
} else {
- Float16(((value shr 48) and 0xffffUL).toShort())
- .toFloat()
+ halfToFloat(((value shr 48) and 0xffffUL).toShort())
}
}
@@ -185,8 +185,7 @@
return if ((value and 0x3fUL) == 0UL) {
((value shr 40) and 0xffUL).toFloat() / 255.0f
} else {
- Float16(((value shr 32) and 0xffffUL).toShort())
- .toFloat()
+ halfToFloat(((value shr 32) and 0xffffUL).toShort())
}
}
@@ -208,8 +207,7 @@
return if ((value and 0x3fUL) == 0UL) {
((value shr 32) and 0xffUL).toFloat() / 255.0f
} else {
- Float16(((value shr 16) and 0xffffUL).toShort())
- .toFloat()
+ halfToFloat(((value shr 16) and 0xffffUL).toShort())
}
}
@@ -393,9 +391,13 @@
}
}
+// Same as Color.Unspecified.packedValue, but avoids a getstatic
+@PublishedApi
+internal const val UnspecifiedColor = 0x10UL
+
/**
* Create a [Color] by passing individual [red], [green], [blue], [alpha], and [colorSpace]
- * components. The default [color space][ColorSpace] is [SRGB][ColorSpaces.Srgb] and
+ * components. The default [color space][ColorSpace] is [sRGB][ColorSpaces.Srgb] and
* the default [alpha] is `1.0` (opaque). [colorSpace] must have a [ColorSpace.componentCount] of
* 3.
*/
@@ -407,7 +409,7 @@
alpha: Float = 1f,
colorSpace: ColorSpace = ColorSpaces.Srgb
): Color {
- require(
+ requirePrecondition(
red in colorSpace.getMinValue(0)..colorSpace.getMaxValue(0) &&
green in colorSpace.getMinValue(1)..colorSpace.getMaxValue(1) &&
blue in colorSpace.getMinValue(2)..colorSpace.getMaxValue(2) &&
@@ -419,41 +421,79 @@
if (colorSpace.isSrgb) {
val argb = (
((alpha * 255.0f + 0.5f).toInt() shl 24) or
- ((red * 255.0f + 0.5f).toInt() shl 16) or
- ((green * 255.0f + 0.5f).toInt() shl 8) or
- (blue * 255.0f + 0.5f).toInt()
- )
- return Color(value = (argb.toULong() and 0xffffffffUL) shl 32)
+ ((red * 255.0f + 0.5f).toInt() shl 16) or
+ ((green * 255.0f + 0.5f).toInt() shl 8) or
+ (blue * 255.0f + 0.5f).toInt()
+ )
+ return Color(argb.toULong() shl 32)
}
- require(colorSpace.componentCount == 3) {
+ requirePrecondition(colorSpace.componentCount == 3) {
"Color only works with ColorSpaces with 3 components"
}
val id = colorSpace.id
- require(id != ColorSpace.MinId) {
+ requirePrecondition(id != ColorSpace.MinId) {
"Unknown color space, please use a color space in ColorSpaces"
}
- val r = Float16(red)
- val g = Float16(green)
- val b = Float16(blue)
+ val r = floatToHalf(red)
+ val g = floatToHalf(green)
+ val b = floatToHalf(blue)
val a = (max(0.0f, min(alpha, 1.0f)) * 1023.0f + 0.5f).toInt()
- // Suppress sign extension
return Color(
- value = (
- ((r.halfValue.toULong() and 0xffffUL) shl 48) or (
- (g.halfValue.toULong() and 0xffffUL) shl 32
- ) or (
- (b.halfValue.toULong() and 0xffffUL) shl 16
- ) or (
- (a.toULong() and 0x3ffUL) shl 6
- ) or (
- id.toULong() and 0x3fUL
- )
- )
+ (
+ ((r.toLong() and 0xffffL) shl 48) or
+ ((g.toLong() and 0xffffL) shl 32) or
+ ((b.toLong() and 0xffffL) shl 16) or
+ ((a.toLong() and 0x03ffL) shl 6) or
+ (id.toLong() and 0x003fL)
+ ).toULong()
+ )
+}
+
+/**
+ * Create a [Color] by passing individual [red], [green], [blue], [alpha], and [colorSpace]
+ * components. This function is equivalent to [Color] but doesn't perform any check/validation
+ * of the parameters. It is meant to be used when the color space and values are known to
+ * be valid by construction, for instance when lerping colors.
+ */
+@Stable
+internal fun UncheckedColor(
+ red: Float,
+ green: Float,
+ blue: Float,
+ alpha: Float = 1f,
+ colorSpace: ColorSpace = ColorSpaces.Srgb
+): Color {
+ if (colorSpace.isSrgb) {
+ val argb = (
+ ((alpha * 255.0f + 0.5f).toInt() shl 24) or
+ ((red * 255.0f + 0.5f).toInt() shl 16) or
+ ((green * 255.0f + 0.5f).toInt() shl 8) or
+ (blue * 255.0f + 0.5f).toInt()
+ )
+ return Color(argb.toULong() shl 32)
+ }
+
+ val r = floatToHalf(red)
+ val g = floatToHalf(green)
+ val b = floatToHalf(blue)
+
+ val a = (max(0.0f, min(alpha, 1.0f)) * 1023.0f + 0.5f).toInt()
+
+ val id = colorSpace.id
+
+ return Color(
+ (
+ ((r.toLong() and 0xffffL) shl 48) or
+ ((g.toLong() and 0xffffL) shl 32) or
+ ((b.toLong() and 0xffffL) shl 16) or
+ ((a.toLong() and 0x03ffL) shl 6) or
+ (id.toLong() and 0x003fL)
+ ).toULong()
)
}
@@ -467,7 +507,7 @@
*/
@Stable
fun Color(@ColorInt color: Int): Color {
- return Color(value = color.toULong() shl 32)
+ return Color(color.toULong() shl 32)
}
/**
@@ -484,7 +524,7 @@
*/
@Stable
fun Color(color: Long): Color {
- return Color(value = (color.toULong() and 0xffffffffUL) shl 32)
+ return Color((color shl 32).toULong())
}
/**
@@ -506,7 +546,8 @@
@IntRange(from = 0, to = 0xFF) blue: Int,
@IntRange(from = 0, to = 0xFF) alpha: Int = 0xFF
): Color {
- val color = ((alpha and 0xFF) shl 24) or
+ val color =
+ ((alpha and 0xFF) shl 24) or
((red and 0xFF) shl 16) or
((green and 0xFF) shl 8) or
(blue and 0xFF)
@@ -535,12 +576,12 @@
val endA = endColor.green
val endB = endColor.blue
- val interpolated = Color(
- alpha = lerp(startAlpha, endAlpha, fraction),
- red = lerp(startL, endL, fraction),
- green = lerp(startA, endA, fraction),
- blue = lerp(startB, endB, fraction),
- colorSpace = colorSpace
+ val interpolated = UncheckedColor(
+ lerp(startL, endL, fraction),
+ lerp(startA, endA, fraction),
+ lerp(startB, endB, fraction),
+ lerp(startAlpha, endAlpha, fraction),
+ colorSpace
)
return interpolated.convert(stop.colorSpace)
}
@@ -568,7 +609,7 @@
val g = compositeComponent(fg.green, background.green, fgA, bgA, a)
val b = compositeComponent(fg.blue, background.blue, fgA, bgA, a)
- return Color(r, g, b, a, background.colorSpace)
+ return UncheckedColor(r, g, b, a, background.colorSpace)
}
/**
@@ -609,7 +650,7 @@
@Stable
fun Color.luminance(): Float {
val colorSpace = colorSpace
- require(colorSpace.model == ColorModel.Rgb) {
+ requirePrecondition(colorSpace.model == ColorModel.Rgb) {
"The specified color must be encoded in an RGB color space. " +
"The supplied color space is ${colorSpace.model}"
}
@@ -619,11 +660,7 @@
val g = eotf(green.toDouble())
val b = eotf(blue.toDouble())
- return saturate(((0.2126 * r) + (0.7152 * g) + (0.0722 * b)).toFloat())
-}
-
-private fun saturate(v: Float): Float {
- return if (v <= 0.0f) 0.0f else (if (v >= 1.0f) 1.0f else v)
+ return (((0.2126 * r) + (0.7152 * g) + (0.0722 * b)).toFloat()).fastCoerceIn(0.0f, 1.0f)
}
/**
@@ -643,13 +680,13 @@
* `false` when this is [Color.Unspecified].
*/
@Stable
-inline val Color.isSpecified: Boolean get() = value != Color.Unspecified.value
+inline val Color.isSpecified: Boolean get() = value != UnspecifiedColor
/**
* `true` when this is [Color.Unspecified].
*/
@Stable
-inline val Color.isUnspecified: Boolean get() = value == Color.Unspecified.value
+inline val Color.isUnspecified: Boolean get() = value == UnspecifiedColor
/**
* If this color [isSpecified] then this is returned, otherwise [block] is executed and its result
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Float16.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Float16.kt
index d48fce3..8aabeca6 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Float16.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Float16.kt
@@ -85,7 +85,7 @@
*
* This table shows that numbers higher than 1024 lose all fractional precision.
*/
[email protected]
+@JvmInline
internal value class Float16(val halfValue: Short) : Comparable<Float16> {
/**
@@ -94,11 +94,7 @@
*
* @param value The value to be represented by the `Float16`
*/
- constructor(value: Float) : this(
- floatToHalf(
- value
- )
- )
+ constructor(value: Float) : this(floatToHalf(value))
/**
* Constructs a newly allocated `Float16` object that
@@ -115,9 +111,7 @@
* @return The half-precision float value represented by this object
* converted to type `Byte`
*/
- fun toByte(): Byte {
- return toFloat().toInt().toByte()
- }
+ fun toByte(): Byte = toFloat().toInt().toByte()
/**
* Returns the value of this `Float16` as a `Short` after
@@ -126,9 +120,7 @@
* @return The half-precision float value represented by this object
* converted to type `Short`
*/
- fun toShort(): Short {
- return toFloat().toInt().toShort()
- }
+ fun toShort(): Short = toFloat().toInt().toShort()
/**
* Returns the value of this `Float16` as a `Int` after
@@ -137,9 +129,7 @@
* @return The half-precision float value represented by this object
* converted to type `Int`
*/
- fun toInt(): Int {
- return toFloat().toInt()
- }
+ fun toInt(): Int = toFloat().toInt()
/**
* Returns the value of this `Float16` as a `Long` after
@@ -148,9 +138,7 @@
* @return The half-precision float value represented by this object
* converted to type `Long`
*/
- fun toLong(): Long {
- return toFloat().toLong()
- }
+ fun toLong(): Long = toFloat().toLong()
/**
* Returns the value of this `Float16` as a `Float` after
@@ -161,9 +149,9 @@
*/
fun toFloat(): Float {
val bits = halfValue.toInt() and 0xffff
- val s = bits and FP16_SIGN_MASK
- val e = bits.ushr(FP16_EXPONENT_SHIFT) and FP16_EXPONENT_MASK
- val m = bits and FP16_SIGNIFICAND_MASK
+ val s = bits and Fp16SignMask
+ val e = bits.ushr(Fp16ExponentShift) and Fp16ExponentMask
+ val m = bits and Fp16SignificandMask
var outE = 0
var outM = 0
@@ -171,8 +159,8 @@
if (e == 0) { // Denormal or 0
if (m != 0) {
// Convert denorm fp16 into normalized fp32
- var o = floatFromBits(FP32_DENORMAL_MAGIC + m)
- o -= FP32_DENORMAL_FLOAT
+ var o = floatFromBits(Fp32DenormalMagic + m)
+ o -= Fp32DenormalFloat
return if (s == 0) o else -o
}
} else {
@@ -180,14 +168,14 @@
if (e == 0x1f) { // Infinite or NaN
outE = 0xff
if (outM != 0) { // SNaNs are quieted
- outM = outM or FP32_QNAN_MASK
+ outM = outM or Fp32QNaNMask
}
} else {
- outE = e - FP16_EXPONENT_BIAS + FP32_EXPONENT_BIAS
+ outE = e - Fp16ExponentBias + Fp32ExponentBias
}
}
- val out = s shl 16 or (outE shl FP32_EXPONENT_SHIFT) or outM
+ val out = s shl 16 or (outE shl Fp32ExponentShift) or outM
return floatFromBits(out)
}
@@ -198,9 +186,7 @@
* @return The half-precision float value represented by this object
* converted to type `Double`
*/
- fun toDouble(): Double {
- return toFloat().toDouble()
- }
+ fun toDouble(): Double = toFloat().toDouble()
/**
* Returns a representation of the half-precision float value
@@ -212,12 +198,10 @@
*
* @return The bits that represent the half-precision float value
*/
- fun toBits(): Int {
- return if (isNaN()) {
- NaN.halfValue.toInt()
- } else {
- halfValue.toInt() and 0xffff
- }
+ fun toBits(): Int = if (isNaN()) {
+ NaN.halfValue.toInt()
+ } else {
+ halfValue.toInt() and 0xffff
}
/**
@@ -226,9 +210,7 @@
*
* @return The bits that represent the half-precision float value
*/
- fun toRawBits(): Int {
- return halfValue.toInt() and 0xffff
- }
+ fun toRawBits(): Int = halfValue.toInt() and 0xffff
/**
* Returns a string representation of the specified half-precision
@@ -236,26 +218,24 @@
*
* @return A string representation of this `Float16` object
*/
- override fun toString(): String {
- return toFloat().toString()
- }
+ override fun toString(): String = toFloat().toString()
/**
* Compares to another half-precision float value. The following
* conditions apply during the comparison:
*
* * [NaN] is considered by this method to be equal to itself and greater
- * than all other half-precision float values (including `#PositiveInfinity`)
+ * than all other half-precision float values (including [PositiveInfinity])
* * [PositiveZero] is considered by this method to be greater than
* [NegativeZero].
*
* @param other The half-precision float value to compare to the half-precision value
* represented by this `Float16` object
*
- * @return The value `0` if `this` is numerically equal to `h`; a
- * value less than `0` if `this` is numerically less than `h`;
+ * @return The value `0` if `this` is numerically equal to [other]; a
+ * value less than `0` if `this` is numerically less than [other];
* and a value greater than `0` if `this` is numerically greater
- * than `h`
+ * than [other]
*/
override operator fun compareTo(other: Float16): Int {
if (isNaN()) {
@@ -263,9 +243,7 @@
} else if (other.isNaN()) {
return -1
}
- return toCompareValue(halfValue).compareTo(
- toCompareValue(other.halfValue)
- )
+ return toCompareValue(halfValue).compareTo(toCompareValue(other.halfValue))
}
/**
@@ -291,9 +269,9 @@
fun withSign(sign: Float16): Float16 =
Float16(
(
- sign.halfValue.toInt() and FP16_SIGN_MASK or
- (halfValue.toInt() and FP16_COMBINED)
- ).toShort()
+ sign.halfValue.toInt() and Fp16SignMask or
+ (halfValue.toInt() and Fp16Combined)
+ ).toShort()
)
/**
@@ -307,7 +285,7 @@
* the result is positive infinity (see [PositiveInfinity])
*/
fun absoluteValue(): Float16 {
- return Float16((halfValue.toInt() and FP16_COMBINED).toShort())
+ return Float16((halfValue.toInt() and Fp16Combined).toShort())
}
/**
@@ -330,7 +308,7 @@
var result = bits
if (e < 0x3c00) {
- result = result and FP16_SIGN_MASK
+ result = result and Fp16SignMask
result = result or (0x3c00 and if (e >= 0x3800) 0xffff else 0x0)
} else if (e < 0x6400) {
e = 25 - (e shr 10)
@@ -362,7 +340,7 @@
var result = bits
if (e < 0x3c00) {
- result = result and FP16_SIGN_MASK
+ result = result and Fp16SignMask
result = result or (0x3c00 and -((bits shr 15).inv() and if (e != 0) 1 else 0))
} else if (e < 0x6400) {
e = 25 - (e shr 10)
@@ -394,7 +372,7 @@
var result = bits
if (e < 0x3c00) {
- result = result and FP16_SIGN_MASK
+ result = result and Fp16SignMask
result = result or (0x3c00 and if (bits > 0x8000) 0xffff else 0x0)
} else if (e < 0x6400) {
e = 25 - (e shr 10)
@@ -425,7 +403,7 @@
var result = bits
if (e < 0x3c00) {
- result = result and FP16_SIGN_MASK
+ result = result and Fp16SignMask
} else if (e < 0x6400) {
e = 25 - (e shr 10)
val mask = (1 shl e) - 1
@@ -443,19 +421,15 @@
* returns [MinExponent] - 1.
*/
val exponent: Int
- get() {
- return (halfValue.toInt().ushr(FP16_EXPONENT_SHIFT) and FP16_EXPONENT_MASK) -
- FP16_EXPONENT_BIAS
- }
+ get() = (halfValue.toInt().ushr(Fp16ExponentShift) and Fp16ExponentMask) -
+ Fp16ExponentBias
/**
* The significand, or mantissa, used in the representation
* of this half-precision float value.
*/
val significand: Int
- get() {
- return halfValue.toInt() and FP16_SIGNIFICAND_MASK
- }
+ get() = halfValue.toInt() and Fp16SignificandMask
/**
* Returns true if this `Float16` value represents a Not-a-Number,
@@ -463,9 +437,7 @@
*
* @return True if the value is a NaN, false otherwise
*/
- fun isNaN(): Boolean {
- return halfValue.toInt() and FP16_COMBINED > FP16_EXPONENT_MAX
- }
+ fun isNaN(): Boolean = halfValue.toInt() and Fp16Combined > Fp16ExponentMax
/**
* Returns true if the half-precision float value represents
@@ -474,9 +446,7 @@
* @return True if the value is positive infinity or negative infinity,
* false otherwise
*/
- fun isInfinite(): Boolean {
- return halfValue.toInt() and FP16_COMBINED == FP16_EXPONENT_MAX
- }
+ fun isInfinite(): Boolean = halfValue.toInt() and Fp16Combined == Fp16ExponentMax
/**
* Returns false if the half-precision float value represents
@@ -485,9 +455,7 @@
* @return False if the value is positive infinity or negative infinity,
* true otherwise
*/
- fun isFinite(): Boolean {
- return halfValue.toInt() and FP16_COMBINED != FP16_EXPONENT_MAX
- }
+ fun isFinite(): Boolean = halfValue.toInt() and Fp16Combined != Fp16ExponentMax
/**
* Returns true if the half-precision float value is normalized
@@ -499,8 +467,8 @@
* @return True if the value is normalized, false otherwise
*/
fun isNormalized(): Boolean {
- return halfValue.toInt() and FP16_EXPONENT_MAX != 0 &&
- halfValue.toInt() and FP16_EXPONENT_MAX != FP16_EXPONENT_MAX
+ return halfValue.toInt() and Fp16ExponentMax != 0 &&
+ halfValue.toInt() and Fp16ExponentMax != Fp16ExponentMax
}
/**
@@ -532,9 +500,9 @@
val o = StringBuilder()
val bits = halfValue.toInt() and 0xffff
- val s = bits.ushr(FP16_SIGN_SHIFT)
- val e = bits.ushr(FP16_EXPONENT_SHIFT) and FP16_EXPONENT_MASK
- val m = bits and FP16_SIGNIFICAND_MASK
+ val s = bits.ushr(Fp16SignShift)
+ val e = bits.ushr(Fp16ExponentShift) and Fp16ExponentMask
+ val m = bits and Fp16SignificandMask
if (e == 0x1f) { // Infinite or NaN
if (m == 0) {
@@ -559,7 +527,7 @@
val significand = m.toString(16)
o.append(significand.replaceFirst("0{2,}$".toRegex(), ""))
o.append('p')
- o.append((e - FP16_EXPONENT_BIAS).toString())
+ o.append((e - Fp16ExponentBias).toString())
}
}
@@ -623,78 +591,118 @@
* Positive 0 of type half-precision float.
*/
val PositiveZero = Float16(0x0000.toShort())
+ }
+}
- private val One = Float16(1f)
- private val NegativeOne = Float16(-1f)
+private val One = Float16(1f)
+private val NegativeOne = Float16(-1f)
- private const val FP16_SIGN_SHIFT = 15
- private const val FP16_SIGN_MASK = 0x8000
- private const val FP16_EXPONENT_SHIFT = 10
- private const val FP16_EXPONENT_MASK = 0x1f
- private const val FP16_SIGNIFICAND_MASK = 0x3ff
- private const val FP16_EXPONENT_BIAS = 15
- private const val FP16_COMBINED = 0x7fff
- private const val FP16_EXPONENT_MAX = 0x7c00
+private const val Fp16SignShift = 15
+private const val Fp16SignMask = 0x8000
+private const val Fp16ExponentShift = 10
+private const val Fp16ExponentMask = 0x1f
+private const val Fp16SignificandMask = 0x3ff
+private const val Fp16ExponentBias = 15
+private const val Fp16Combined = 0x7fff
+private const val Fp16ExponentMax = 0x7c00
- private const val FP32_SIGN_SHIFT = 31
- private const val FP32_EXPONENT_SHIFT = 23
- private const val FP32_EXPONENT_MASK = 0xff
- private const val FP32_SIGNIFICAND_MASK = 0x7fffff
- private const val FP32_EXPONENT_BIAS = 127
- private const val FP32_QNAN_MASK = 0x400000
+private const val Fp32SignShift = 31
+private const val Fp32ExponentShift = 23
+private const val Fp32ExponentMask = 0xff
+private const val Fp32SignificandMask = 0x7fffff
+private const val Fp32ExponentBias = 127
+private const val Fp32QNaNMask = 0x400000
- private const val FP32_DENORMAL_MAGIC = 126 shl 23
- private val FP32_DENORMAL_FLOAT = floatFromBits(FP32_DENORMAL_MAGIC)
+private const val Fp32DenormalMagic = 126 shl 23
+private val Fp32DenormalFloat = floatFromBits(Fp32DenormalMagic)
- private fun toCompareValue(value: Short): Int {
- return if (value.toInt() and FP16_SIGN_MASK != 0) {
- 0x8000 - (value.toInt() and 0xffff)
+@Suppress("NOTHING_TO_INLINE")
+private inline fun toCompareValue(value: Short): Int {
+ return if (value.toInt() and Fp16SignMask != 0) {
+ 0x8000 - (value.toInt() and 0xffff)
+ } else {
+ value.toInt() and 0xffff
+ }
+}
+
+/**
+ * Convert a single-precision float to a half-precision float, stored as
+ * [Short] data type to hold its 16 bits.
+ */
+internal fun floatToHalf(f: Float): Short {
+ val bits = f.toRawBits()
+ val s = bits.ushr(Fp32SignShift)
+ var e = bits.ushr(Fp32ExponentShift) and Fp32ExponentMask
+ var m = bits and Fp32SignificandMask
+
+ var outE = 0
+ var outM = 0
+
+ if (e == 0xff) { // Infinite or NaN
+ outE = 0x1f
+ outM = if (m != 0) 0x200 else 0
+ } else {
+ e = e - Fp32ExponentBias + Fp16ExponentBias
+ if (e >= 0x1f) { // Overflow
+ outE = 0x31
+ } else if (e <= 0) { // Underflow
+ if (e < -10) {
+ // The absolute fp32 value is less than MIN_VALUE, flush to +/-0
} else {
- value.toInt() and 0xffff
+ // The fp32 value is a normalized float less than MIN_NORMAL,
+ // we convert to a denorm fp16
+ m = m or 0x800000 shr 1 - e
+ if (m and 0x1000 != 0) m += 0x2000
+ outM = m shr 13
}
- }
-
- private fun floatToHalf(f: Float): Short {
- val bits = f.toRawBits()
- val s = bits.ushr(FP32_SIGN_SHIFT)
- var e = bits.ushr(FP32_EXPONENT_SHIFT) and FP32_EXPONENT_MASK
- var m = bits and FP32_SIGNIFICAND_MASK
-
- var outE = 0
- var outM = 0
-
- if (e == 0xff) { // Infinite or NaN
- outE = 0x1f
- outM = if (m != 0) 0x200 else 0
- } else {
- e = e - FP32_EXPONENT_BIAS + FP16_EXPONENT_BIAS
- if (e >= 0x1f) { // Overflow
- outE = 0x31
- } else if (e <= 0) { // Underflow
- if (e < -10) {
- // The absolute fp32 value is less than MIN_VALUE, flush to +/-0
- } else {
- // The fp32 value is a normalized float less than MIN_NORMAL,
- // we convert to a denorm fp16
- m = m or 0x800000 shr 1 - e
- if (m and 0x1000 != 0) m += 0x2000
- outM = m shr 13
- }
- } else {
- outE = e
- outM = m shr 13
- if (m and 0x1000 != 0) {
- // Round to nearest "0.5" up
- var out = outE shl FP16_EXPONENT_SHIFT or outM
- out++
- return (out or (s shl FP16_SIGN_SHIFT)).toShort()
- }
- }
+ } else {
+ outE = e
+ outM = m shr 13
+ if (m and 0x1000 != 0) {
+ // Round to nearest "0.5" up
+ var out = outE shl Fp16ExponentShift or outM
+ out++
+ return (out or (s shl Fp16SignShift)).toShort()
}
-
- return (s shl FP16_SIGN_SHIFT or (outE shl FP16_EXPONENT_SHIFT) or outM).toShort()
}
}
+
+ return (s shl Fp16SignShift or (outE shl Fp16ExponentShift) or outM).toShort()
+}
+
+/**
+ * Convert a half-precision float to a single-precision float.
+ */
+internal fun halfToFloat(h: Short): Float {
+ val bits = h.toInt() and 0xffff
+ val s = bits and Fp16SignMask
+ val e = bits.ushr(Fp16ExponentShift) and Fp16ExponentMask
+ val m = bits and Fp16SignificandMask
+
+ var outE = 0
+ var outM = 0
+
+ if (e == 0) { // Denormal or 0
+ if (m != 0) {
+ // Convert denorm fp16 into normalized fp32
+ var o = floatFromBits(Fp32DenormalMagic + m)
+ o -= Fp32DenormalFloat
+ return if (s == 0) o else -o
+ }
+ } else {
+ outM = m shl 13
+ if (e == 0x1f) { // Infinite or NaN
+ outE = 0xff
+ if (outM != 0) { // SNaNs are quieted
+ outM = outM or Fp32QNaNMask
+ }
+ } else {
+ outE = e - Fp16ExponentBias + Fp32ExponentBias
+ }
+ }
+
+ val out = s shl 16 or (outE shl Fp32ExponentShift) or outM
+ return floatFromBits(out)
}
/**
@@ -712,7 +720,6 @@
if (x.isNaN() || y.isNaN()) {
return Float16.NaN
}
-
return if (x <= y) x else y
}
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/InlineClassHelper.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/InlineClassHelper.kt
new file mode 100644
index 0000000..724538e
--- /dev/null
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/InlineClassHelper.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.ui.graphics
+
+import kotlin.contracts.ExperimentalContracts
+import kotlin.contracts.contract
+
+// This function exists so we do *not* inline the throw. It keeps
+// the call site much smaller and since it's the slow path anyway,
+// we don't mind the extra function call
+internal fun throwIllegalArgumentException(message: String) {
+ throw IllegalArgumentException(message)
+}
+
+// Like Kotlin's require() but without the .toString() call
+@Suppress("BanInlineOptIn") // same opt-in as using Kotlin's require()
+@OptIn(ExperimentalContracts::class)
+internal inline fun requirePrecondition(value: Boolean, lazyMessage: () -> String) {
+ contract {
+ returns() implies value
+ }
+ if (!value) {
+ throwIllegalArgumentException(lazyMessage())
+ }
+}
diff --git a/compose/ui/ui-graphics/src/commonTest/kotlin/androidx/compose/ui/graphics/ColorTest.kt b/compose/ui/ui-graphics/src/commonTest/kotlin/androidx/compose/ui/graphics/ColorTest.kt
index 4adb50b..cd9b92d 100644
--- a/compose/ui/ui-graphics/src/commonTest/kotlin/androidx/compose/ui/graphics/ColorTest.kt
+++ b/compose/ui/ui-graphics/src/commonTest/kotlin/androidx/compose/ui/graphics/ColorTest.kt
@@ -568,6 +568,11 @@
assertEquals(50f / 255f, srgbGreen.blue, 0.01f)
}
+ @Test fun unspecifiedConstantValue() {
+ // See comments in Color.kt, we want to make sure Color.Unspecified doesn't change encoding
+ assertEquals(0x10UL, Color.Unspecified.value)
+ }
+
companion object {
fun Int.toHexString() = "0x${toUInt().toString(16).padStart(8, '0')}"
}
diff --git a/compose/ui/ui-test/api/current.txt b/compose/ui/ui-test/api/current.txt
index b1cd79d..666a657 100644
--- a/compose/ui/ui-test/api/current.txt
+++ b/compose/ui/ui-test/api/current.txt
@@ -3,6 +3,8 @@
public final class ActionsKt {
method public static androidx.compose.ui.test.SemanticsNodeInteraction performClick(androidx.compose.ui.test.SemanticsNodeInteraction);
+ method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static androidx.compose.ui.test.SemanticsNodeInteraction performCustomAccessibilityActionLabelled(androidx.compose.ui.test.SemanticsNodeInteraction, String label);
+ method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static androidx.compose.ui.test.SemanticsNodeInteraction performCustomAccessibilityActionWhere(androidx.compose.ui.test.SemanticsNodeInteraction, optional String? predicateDescription, kotlin.jvm.functions.Function1<? super java.lang.String,java.lang.Boolean> labelPredicate);
method @Deprecated public static androidx.compose.ui.test.SemanticsNodeInteraction performGesture(androidx.compose.ui.test.SemanticsNodeInteraction, kotlin.jvm.functions.Function1<? super androidx.compose.ui.test.GestureScope,kotlin.Unit> block);
method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static androidx.compose.ui.test.SemanticsNodeInteraction performKeyInput(androidx.compose.ui.test.SemanticsNodeInteraction, kotlin.jvm.functions.Function1<? super androidx.compose.ui.test.KeyInjectionScope,kotlin.Unit> block);
method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static androidx.compose.ui.test.SemanticsNodeInteraction performMouseInput(androidx.compose.ui.test.SemanticsNodeInteraction, kotlin.jvm.functions.Function1<? super androidx.compose.ui.test.MouseInjectionScope,kotlin.Unit> block);
diff --git a/compose/ui/ui-test/api/restricted_current.txt b/compose/ui/ui-test/api/restricted_current.txt
index 78faf62..b8f4e37 100644
--- a/compose/ui/ui-test/api/restricted_current.txt
+++ b/compose/ui/ui-test/api/restricted_current.txt
@@ -3,6 +3,8 @@
public final class ActionsKt {
method public static androidx.compose.ui.test.SemanticsNodeInteraction performClick(androidx.compose.ui.test.SemanticsNodeInteraction);
+ method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static androidx.compose.ui.test.SemanticsNodeInteraction performCustomAccessibilityActionLabelled(androidx.compose.ui.test.SemanticsNodeInteraction, String label);
+ method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static androidx.compose.ui.test.SemanticsNodeInteraction performCustomAccessibilityActionWhere(androidx.compose.ui.test.SemanticsNodeInteraction, optional String? predicateDescription, kotlin.jvm.functions.Function1<? super java.lang.String,java.lang.Boolean> labelPredicate);
method @Deprecated public static androidx.compose.ui.test.SemanticsNodeInteraction performGesture(androidx.compose.ui.test.SemanticsNodeInteraction, kotlin.jvm.functions.Function1<? super androidx.compose.ui.test.GestureScope,kotlin.Unit> block);
method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static androidx.compose.ui.test.SemanticsNodeInteraction performKeyInput(androidx.compose.ui.test.SemanticsNodeInteraction, kotlin.jvm.functions.Function1<? super androidx.compose.ui.test.KeyInjectionScope,kotlin.Unit> block);
method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static androidx.compose.ui.test.SemanticsNodeInteraction performMouseInput(androidx.compose.ui.test.SemanticsNodeInteraction, kotlin.jvm.functions.Function1<? super androidx.compose.ui.test.MouseInjectionScope,kotlin.Unit> block);
diff --git a/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/actions/CustomAccessibilityActionsTest.kt b/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/actions/CustomAccessibilityActionsTest.kt
new file mode 100644
index 0000000..4bffee2
--- /dev/null
+++ b/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/actions/CustomAccessibilityActionsTest.kt
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.ui.test.actions
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.CustomAccessibilityAction
+import androidx.compose.ui.semantics.customActions
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performCustomAccessibilityActionLabelled
+import androidx.compose.ui.test.performCustomAccessibilityActionWhere
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFailsWith
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalTestApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CustomAccessibilityActionsTest {
+ @get:Rule
+ val rule = createComposeRule()
+
+ private val tag = "tag"
+
+ @Test
+ fun performCustomAccessibilityActionLabelled_failsWhenNoNodeMatches() {
+ rule.setContent {
+ Box(
+ Modifier.semantics {
+ customActions = listOf(CustomAccessibilityAction("action") { true })
+ }
+ )
+ }
+
+ val interaction = rule.onNodeWithTag(tag)
+ val error = assertFailsWith<AssertionError> {
+ interaction.performCustomAccessibilityActionLabelled("action")
+ }
+ assertThat(error).hasMessageThat().contains("could not find any node that satisfies")
+ }
+
+ @Test
+ fun performCustomAccessibilityActionLabelled_failsWhenNoActionMatches() {
+ rule.setContent {
+ Box(
+ Modifier
+ .testTag(tag)
+ .semantics {
+ customActions = listOf(CustomAccessibilityAction("action") { true })
+ }
+ )
+ }
+
+ val error = assertFailsWith<AssertionError> {
+ rule.onNodeWithTag(tag).performCustomAccessibilityActionLabelled("not action")
+ }
+ assertThat(error).hasMessageThat().startsWith(
+ "No custom accessibility actions matched [label is \"not action\"]"
+ )
+ }
+
+ @Test
+ fun performCustomAccessibilityActionLabelled_failsWhenMultipleActionsMatch() {
+ rule.setContent {
+ Box(
+ Modifier
+ .testTag(tag)
+ .semantics {
+ customActions = listOf(
+ CustomAccessibilityAction("action") { true },
+ CustomAccessibilityAction("action") { true },
+ )
+ }
+ )
+ }
+
+ val error = assertFailsWith<AssertionError> {
+ rule.onNodeWithTag(tag).performCustomAccessibilityActionLabelled("action")
+ }
+ assertThat(error).hasMessageThat().startsWith(
+ "Expected exactly one custom accessibility action to match [label is \"action\"], " +
+ "but found 2."
+ )
+ }
+
+ @Test
+ fun performCustomAccessibilityActionLabelled_invokesActionWhenExactlyOneActionMatches() {
+ var fooInvocationCount = 0
+ var barInvocationCount = 0
+ rule.setContent {
+ Box(
+ Modifier
+ .testTag(tag)
+ .semantics {
+ customActions = listOf(
+ CustomAccessibilityAction("foo") { fooInvocationCount++; true },
+ CustomAccessibilityAction("bar") { barInvocationCount++; true },
+ )
+ }
+ )
+ }
+
+ rule.onNodeWithTag(tag).performCustomAccessibilityActionLabelled("foo")
+
+ assertThat(fooInvocationCount).isEqualTo(1)
+ assertThat(barInvocationCount).isEqualTo(0)
+ }
+
+ @Test
+ fun performCustomAccessibilityActionLabelled_doesntFailWhenActionReturnsFalse() {
+ rule.setContent {
+ Box(
+ Modifier
+ .testTag(tag)
+ .semantics {
+ customActions = listOf(
+ CustomAccessibilityAction("action") { false },
+ )
+ }
+ )
+ }
+
+ rule.onNodeWithTag(tag).performCustomAccessibilityActionLabelled("action")
+ }
+
+ @Test
+ fun performCustomAccessibilityActionWhere_failsWhenNoNodeMatches() {
+ rule.setContent {
+ Box(
+ Modifier.semantics {
+ customActions = listOf(CustomAccessibilityAction("action") { true })
+ }
+ )
+ }
+
+ val interaction = rule.onNodeWithTag(tag)
+ val error = assertFailsWith<AssertionError> {
+ interaction.performCustomAccessibilityActionWhere("description") { true }
+ }
+ assertThat(error).hasMessageThat().contains("could not find any node that satisfies")
+ }
+
+ @Test
+ fun performCustomAccessibilityActionWhere_failsWhenNoActionMatches() {
+ rule.setContent {
+ Box(
+ Modifier
+ .testTag(tag)
+ .semantics {
+ customActions = listOf(CustomAccessibilityAction("action") { true })
+ }
+ )
+ }
+
+ val error = assertFailsWith<AssertionError> {
+ rule.onNodeWithTag(tag).performCustomAccessibilityActionWhere("description") { false }
+ }
+ assertThat(error).hasMessageThat().startsWith(
+ "No custom accessibility actions matched [description]"
+ )
+ }
+
+ @Test
+ fun performCustomAccessibilityActionWhere_failsWhenMultipleActionsMatch() {
+ rule.setContent {
+ Box(
+ Modifier
+ .testTag(tag)
+ .semantics {
+ customActions = listOf(
+ CustomAccessibilityAction("action") { true },
+ CustomAccessibilityAction("action") { true },
+ )
+ }
+ )
+ }
+
+ val error = assertFailsWith<AssertionError> {
+ rule.onNodeWithTag(tag).performCustomAccessibilityActionWhere("description") { true }
+ }
+ assertThat(error).hasMessageThat().startsWith(
+ "Expected exactly one custom accessibility action to match [description], " +
+ "but found 2."
+ )
+ }
+
+ @Test
+ fun performCustomAccessibilityActionWhere_invokesActionWhenExactlyOneActionMatches() {
+ var fooInvocationCount = 0
+ var barInvocationCount = 0
+ rule.setContent {
+ Box(
+ Modifier
+ .testTag(tag)
+ .semantics {
+ customActions = listOf(
+ CustomAccessibilityAction("foo") { fooInvocationCount++; true },
+ CustomAccessibilityAction("bar") { barInvocationCount++; true },
+ )
+ }
+ )
+ }
+
+ rule.onNodeWithTag(tag).performCustomAccessibilityActionWhere("description") { it == "foo" }
+
+ assertThat(fooInvocationCount).isEqualTo(1)
+ assertThat(barInvocationCount).isEqualTo(0)
+ }
+
+ @Test
+ fun performCustomAccessibilityActionWhere_doesntFailWhenActionReturnsFalse() {
+ rule.setContent {
+ Box(
+ Modifier
+ .testTag(tag)
+ .semantics {
+ customActions = listOf(
+ CustomAccessibilityAction("action") { false },
+ )
+ }
+ )
+ }
+
+ rule.onNodeWithTag(tag).performCustomAccessibilityActionWhere("description") { true }
+ }
+}
diff --git a/compose/ui/ui-test/src/androidMain/kotlin/androidx/compose/ui/test/AndroidInputDispatcher.android.kt b/compose/ui/ui-test/src/androidMain/kotlin/androidx/compose/ui/test/AndroidInputDispatcher.android.kt
index 9994145..44d6f19 100644
--- a/compose/ui/ui-test/src/androidMain/kotlin/androidx/compose/ui/test/AndroidInputDispatcher.android.kt
+++ b/compose/ui/ui-test/src/androidMain/kotlin/androidx/compose/ui/test/AndroidInputDispatcher.android.kt
@@ -290,8 +290,23 @@
},
/* pointerCoords = */ Array(coordinates.size) { pointerIndex ->
PointerCoords().apply {
- x = positionInScreen.x + coordinates[pointerIndex][0].x
- y = positionInScreen.y + coordinates[pointerIndex][0].y
+
+ val startOffset = coordinates[pointerIndex][0]
+
+ // Allows for non-valid numbers/Offsets to be passed along to Compose to
+ // test if it handles them properly (versus breaking here and we not knowing
+ // if Compose properly handles these values).
+ x = if (startOffset.isValid()) {
+ positionInScreen.x + startOffset.x
+ } else {
+ Float.NaN
+ }
+
+ y = if (startOffset.isValid()) {
+ positionInScreen.y + startOffset.y
+ } else {
+ Float.NaN
+ }
}
},
/* metaState = */ 0,
@@ -311,8 +326,23 @@
/* eventTime = */ eventTimes[timeIndex],
/* pointerCoords = */ Array(coordinates.size) { pointerIndex ->
PointerCoords().apply {
- x = positionInScreen.x + coordinates[pointerIndex][timeIndex].x
- y = positionInScreen.y + coordinates[pointerIndex][timeIndex].y
+ val currentOffset = coordinates[pointerIndex][timeIndex]
+
+ // Allows for non-valid numbers/Offsets to be passed along to
+ // Compose to test if it handles them properly (versus breaking
+ // here and we not knowing if Compose properly handles these
+ // values).
+ x = if (currentOffset.isValid()) {
+ positionInScreen.x + currentOffset.x
+ } else {
+ Float.NaN
+ }
+
+ y = if (currentOffset.isValid()) {
+ positionInScreen.y + currentOffset.y
+ } else {
+ Float.NaN
+ }
}
},
/* metaState = */ 0
diff --git a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/Actions.kt b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/Actions.kt
index 5f9f27e..a646fa88 100644
--- a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/Actions.kt
+++ b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/Actions.kt
@@ -22,8 +22,10 @@
import androidx.compose.ui.layout.boundsInParent
import androidx.compose.ui.layout.positionInRoot
import androidx.compose.ui.semantics.AccessibilityAction
+import androidx.compose.ui.semantics.CustomAccessibilityAction
import androidx.compose.ui.semantics.ScrollAxisRange
import androidx.compose.ui.semantics.SemanticsActions
+import androidx.compose.ui.semantics.SemanticsActions.CustomActions
import androidx.compose.ui.semantics.SemanticsActions.ScrollBy
import androidx.compose.ui.semantics.SemanticsActions.ScrollToIndex
import androidx.compose.ui.semantics.SemanticsNode
@@ -625,6 +627,70 @@
return this
}
+/**
+ * Finds the [CustomAccessibilityAction] in the node's [CustomActions] list whose label is equal
+ * to [label] and then invokes it.
+ *
+ * To use your own logic to find the action to perform instead of matching on the full label, use
+ * [performCustomAccessibilityActionWhere].
+ *
+ * @param label The exact label of the [CustomAccessibilityAction] to perform.
+ *
+ * @throws AssertionError If no [SemanticsNode] is found, or no [CustomAccessibilityAction] has
+ * [label], or more than one [CustomAccessibilityAction] has [label].
+ *
+ * @see performCustomAccessibilityActionWhere
+ */
+@ExperimentalTestApi
+fun SemanticsNodeInteraction.performCustomAccessibilityActionLabelled(
+ label: String
+): SemanticsNodeInteraction =
+ performCustomAccessibilityActionWhere("label is \"$label\"") { it == label }
+
+/**
+ * Finds the [CustomAccessibilityAction] in the node's [CustomActions] list whose label satisfies a
+ * predicate function and then invokes it.
+ *
+ * @param predicateDescription A description of [labelPredicate] that will be included in the error
+ * message if zero or >1 actions match.
+ * @param labelPredicate A predicate function used to select the [CustomAccessibilityAction] to
+ * perform.
+ *
+ * @throws AssertionError If no [SemanticsNode] is found, or no [CustomAccessibilityAction] matches
+ * [labelPredicate], or more than one [CustomAccessibilityAction] matches [labelPredicate].
+ *
+ * @see performCustomAccessibilityActionLabelled
+ */
+@ExperimentalTestApi
+fun SemanticsNodeInteraction.performCustomAccessibilityActionWhere(
+ predicateDescription: String? = null,
+ labelPredicate: (label: String) -> Boolean
+): SemanticsNodeInteraction {
+ val node = fetchSemanticsNode()
+ val actions = node.config[CustomActions]
+ val matchingActions = actions.filter { labelPredicate(it.label) }
+ if (matchingActions.isEmpty()) {
+ throw AssertionError(
+ buildGeneralErrorMessage(
+ "No custom accessibility actions matched [$predicateDescription].",
+ selector,
+ node
+ )
+ )
+ } else if (matchingActions.size > 1) {
+ throw AssertionError(
+ buildGeneralErrorMessage(
+ "Expected exactly one custom accessibility action to match" +
+ " [$predicateDescription], but found ${matchingActions.size}.",
+ selector,
+ node
+ )
+ )
+ }
+ matchingActions[0].action()
+ return this
+}
+
// TODO(200928505): get a more accurate indication if it is a lazy list
private val SemanticsNode.isLazyList: Boolean
get() = ScrollBy in config && ScrollToIndex in config
diff --git a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/MultiModalInjectionScope.kt b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/MultiModalInjectionScope.kt
index 7abc0fc..68fb132 100644
--- a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/MultiModalInjectionScope.kt
+++ b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/MultiModalInjectionScope.kt
@@ -113,11 +113,21 @@
* @return [position] transformed to coordinates relative to the containing root.
*/
internal fun localToRoot(position: Offset): Offset {
- return position + boundsInRoot.topLeft
+ return if (position.isValid()) {
+ position + boundsInRoot.topLeft
+ } else {
+ // Allows invalid position to still pass back through Compose (for testing)
+ position
+ }
}
internal fun rootToLocal(position: Offset): Offset {
- return position - boundsInRoot.topLeft
+ return if (position.isValid()) {
+ position - boundsInRoot.topLeft
+ } else {
+ // Allows invalid position to still pass back through Compose (for testing)
+ position
+ }
}
override val viewConfiguration: ViewConfiguration
diff --git a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/TouchInjectionScope.kt b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/TouchInjectionScope.kt
index d1f5822..e9a98c1 100644
--- a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/TouchInjectionScope.kt
+++ b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/TouchInjectionScope.kt
@@ -210,7 +210,15 @@
*/
fun updatePointerBy(pointerId: Int, delta: Offset) {
// Ignore currentPosition of null here, let updatePointerTo generate the error
- val position = (currentPosition(pointerId) ?: Offset.Zero) + delta
+ val currentPosition = currentPosition(pointerId) ?: Offset.Zero
+
+ val position = if (currentPosition.isValid() && delta.isValid()) {
+ currentPosition + delta
+ } else {
+ // Allows invalid position to still pass back through Compose (for testing)
+ Offset.Unspecified
+ }
+
updatePointerTo(pointerId, position)
}
diff --git a/compose/ui/ui-text/api/current.ignore b/compose/ui/ui-text/api/current.ignore
new file mode 100644
index 0000000..8e2ec26
--- /dev/null
+++ b/compose/ui/ui-text/api/current.ignore
@@ -0,0 +1,7 @@
+// Baseline format: 1.0
+ChangedClass: androidx.compose.ui.text.input.PlatformImeOptions:
+ Class androidx.compose.ui.text.input.PlatformImeOptions changed class/interface declaration
+
+
+RemovedClass: androidx.compose.ui.text.input.AndroidImeOptions:
+ Removed class androidx.compose.ui.text.input.AndroidImeOptions
diff --git a/compose/ui/ui-text/api/current.txt b/compose/ui/ui-text/api/current.txt
index 9f723e7..7abd7ad 100644
--- a/compose/ui/ui-text/api/current.txt
+++ b/compose/ui/ui-text/api/current.txt
@@ -941,12 +941,6 @@
package androidx.compose.ui.text.input {
- public final class AndroidImeOptions implements androidx.compose.ui.text.input.PlatformImeOptions {
- ctor public AndroidImeOptions(optional String? privateImeOptions);
- method public String? getPrivateImeOptions();
- property public final String? privateImeOptions;
- }
-
public final class BackspaceCommand implements androidx.compose.ui.text.input.EditCommand {
ctor public BackspaceCommand();
method public void applyTo(androidx.compose.ui.text.input.EditingBuffer buffer);
@@ -1139,7 +1133,10 @@
property public final char mask;
}
- public sealed interface PlatformImeOptions {
+ @androidx.compose.runtime.Immutable public final class PlatformImeOptions {
+ ctor public PlatformImeOptions(optional String? privateImeOptions);
+ method public String? getPrivateImeOptions();
+ property public final String? privateImeOptions;
}
public interface PlatformTextInputService {
diff --git a/compose/ui/ui-text/api/restricted_current.ignore b/compose/ui/ui-text/api/restricted_current.ignore
index 2c9640b..8e2ec26 100644
--- a/compose/ui/ui-text/api/restricted_current.ignore
+++ b/compose/ui/ui-text/api/restricted_current.ignore
@@ -1,3 +1,7 @@
// Baseline format: 1.0
-AddedClass: androidx.compose.ui.text.platform.Synchronization_jvmKt:
- Added class androidx.compose.ui.text.platform.Synchronization_jvmKt
+ChangedClass: androidx.compose.ui.text.input.PlatformImeOptions:
+ Class androidx.compose.ui.text.input.PlatformImeOptions changed class/interface declaration
+
+
+RemovedClass: androidx.compose.ui.text.input.AndroidImeOptions:
+ Removed class androidx.compose.ui.text.input.AndroidImeOptions
diff --git a/compose/ui/ui-text/api/restricted_current.txt b/compose/ui/ui-text/api/restricted_current.txt
index 707c653..36f0b32 100644
--- a/compose/ui/ui-text/api/restricted_current.txt
+++ b/compose/ui/ui-text/api/restricted_current.txt
@@ -941,12 +941,6 @@
package androidx.compose.ui.text.input {
- public final class AndroidImeOptions implements androidx.compose.ui.text.input.PlatformImeOptions {
- ctor public AndroidImeOptions(optional String? privateImeOptions);
- method public String? getPrivateImeOptions();
- property public final String? privateImeOptions;
- }
-
public final class BackspaceCommand implements androidx.compose.ui.text.input.EditCommand {
ctor public BackspaceCommand();
method public void applyTo(androidx.compose.ui.text.input.EditingBuffer buffer);
@@ -1139,7 +1133,10 @@
property public final char mask;
}
- public sealed interface PlatformImeOptions {
+ @androidx.compose.runtime.Immutable public final class PlatformImeOptions {
+ ctor public PlatformImeOptions(optional String? privateImeOptions);
+ method public String? getPrivateImeOptions();
+ property public final String? privateImeOptions;
}
public interface PlatformTextInputService {
diff --git a/compose/ui/ui-text/lint-baseline.xml b/compose/ui/ui-text/lint-baseline.xml
index 26fe7b7..40b9c16 100644
--- a/compose/ui/ui-text/lint-baseline.xml
+++ b/compose/ui/ui-text/lint-baseline.xml
@@ -1,14 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.3.0-alpha04" type="baseline" client="gradle" dependencies="false" name="AGP (8.3.0-alpha04)" variant="all" version="8.3.0-alpha04">
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 21): `android.graphics.Paint#getBlendMode`"
- errorLine1=" assertThat(paragraph.textPaint.blendMode).isEqualTo(BlendMode.SrcOver)"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/androidInstrumentedTest/kotlin/androidx/compose/ui/text/AndroidParagraphTest.kt"/>
- </issue>
+<issues format="6" by="lint 8.3.0-alpha10" type="baseline" client="gradle" dependencies="false" name="AGP (8.3.0-alpha10)" variant="all" version="8.3.0-alpha10">
<issue
id="NewApi"
@@ -40,10 +31,10 @@
<issue
id="NewApi"
message="Call requires API level 29 (current min is 21): `android.graphics.Paint#getBlendMode`"
- errorLine1=" assertThat(textPaint.blendMode).isEqualTo(BlendMode.SrcOver)"
- errorLine2=" ~~~~~~~~~">
+ errorLine1=" assertThat(paragraph.textPaint.blendMode).isEqualTo(BlendMode.SrcOver)"
+ errorLine2=" ~~~~~~~~~">
<location
- file="src/androidInstrumentedTest/kotlin/androidx/compose/ui/text/platform/AndroidTextPaintTest.kt"/>
+ file="src/androidInstrumentedTest/kotlin/androidx/compose/ui/text/AndroidParagraphTest.kt"/>
</issue>
<issue
@@ -57,6 +48,15 @@
<issue
id="NewApi"
+ message="Call requires API level 29 (current min is 21): `android.graphics.Paint#getBlendMode`"
+ errorLine1=" assertThat(textPaint.blendMode).isEqualTo(BlendMode.SrcOver)"
+ errorLine2=" ~~~~~~~~~">
+ <location
+ file="src/androidInstrumentedTest/kotlin/androidx/compose/ui/text/platform/AndroidTextPaintTest.kt"/>
+ </issue>
+
+ <issue
+ id="NewApi"
message="Call requires API level 29 (current min is 21): `android.graphics.Paint#setBlendMode`"
errorLine1=" textPaint.blendMode = BlendMode.DstOver"
errorLine2=" ~~~~~~~~~">
@@ -66,6 +66,15 @@
<issue
id="NewApi"
+ message="Cast from `BlendMode` to `Comparable` requires API level 29 (current min is 21)"
+ errorLine1=" assertThat(textPaint.blendMode).isEqualTo(BlendMode.DstOver)"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/androidInstrumentedTest/kotlin/androidx/compose/ui/text/platform/AndroidTextPaintTest.kt"/>
+ </issue>
+
+ <issue
+ id="NewApi"
message="Call requires API level 29 (current min is 21): `android.graphics.Paint#getBlendMode`"
errorLine1=" assertThat(textPaint.blendMode).isEqualTo(BlendMode.DstOver)"
errorLine2=" ~~~~~~~~~">
@@ -74,12 +83,93 @@
</issue>
<issue
- id="NewApi"
- message="Cast from `BlendMode` to `Comparable` requires API level 29 (current min is 21)"
- errorLine1=" assertThat(textPaint.blendMode).isEqualTo(BlendMode.DstOver)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ id="PrimitiveInCollection"
+ message="field paragraphEnds with type List<Integer>: replace with IntList"
+ errorLine1=" private val paragraphEnds: List<Int>"
+ errorLine2=" ~~~~~~~~~">
<location
- file="src/androidInstrumentedTest/kotlin/androidx/compose/ui/text/platform/AndroidTextPaintTest.kt"/>
+ file="${:compose:ui:ui-text*debug*MAIN*sourceProvider*0*javaDir*4}/androidx/compose/ui/text/android/LayoutHelper.android.kt"/>
+ </issue>
+
+ <issue
+ id="PrimitiveInCollection"
+ message="variable lineFeeds with type List<Integer>: replace with IntList"
+ errorLine1=" val lineFeeds = mutableListOf<Int>()"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="${:compose:ui:ui-text*debug*MAIN*sourceProvider*0*javaDir*4}/androidx/compose/ui/text/android/LayoutHelper.android.kt"/>
+ </issue>
+
+ <issue
+ id="PrimitiveInCollection"
+ message="return type List<Integer> of breakInWords: replace with IntList"
+ errorLine1=" private fun breakInWords(layoutHelper: LayoutHelper): List<Int> {"
+ errorLine2=" ~~~~~~~~~">
+ <location
+ file="${:compose:ui:ui-text*debug*MAIN*sourceProvider*0*javaDir*4}/androidx/compose/ui/text/android/animation/SegmentBreaker.android.kt"/>
+ </issue>
+
+ <issue
+ id="PrimitiveInCollection"
+ message="variable words with type List<? extends Integer>: replace with IntList"
+ errorLine1=" val words = breakWithBreakIterator(text, BreakIterator.getLineInstance(Locale.getDefault()))"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="${:compose:ui:ui-text*debug*MAIN*sourceProvider*0*javaDir*4}/androidx/compose/ui/text/android/animation/SegmentBreaker.android.kt"/>
+ </issue>
+
+ <issue
+ id="PrimitiveInCollection"
+ message="variable set with type TreeSet<Integer>: replace with IntSet"
+ errorLine1=" val set = TreeSet<Int>().apply {"
+ errorLine2=" ^">
+ <location
+ file="${:compose:ui:ui-text*debug*MAIN*sourceProvider*0*javaDir*4}/androidx/compose/ui/text/android/animation/SegmentBreaker.android.kt"/>
+ </issue>
+
+ <issue
+ id="PrimitiveInCollection"
+ message="return type List<Integer> of breakWithBreakIterator: replace with IntList"
+ errorLine1=" private fun breakWithBreakIterator(text: CharSequence, breaker: BreakIterator): List<Int> {"
+ errorLine2=" ~~~~~~~~~">
+ <location
+ file="${:compose:ui:ui-text*debug*MAIN*sourceProvider*0*javaDir*4}/androidx/compose/ui/text/android/animation/SegmentBreaker.android.kt"/>
+ </issue>
+
+ <issue
+ id="PrimitiveInCollection"
+ message="variable res with type List<Integer>: replace with IntList"
+ errorLine1=" val res = mutableListOf(0)"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="${:compose:ui:ui-text*debug*MAIN*sourceProvider*0*javaDir*4}/androidx/compose/ui/text/android/animation/SegmentBreaker.android.kt"/>
+ </issue>
+
+ <issue
+ id="PrimitiveInCollection"
+ message="return type List<Integer> of breakOffsets: replace with IntList"
+ errorLine1=" fun breakOffsets(layoutHelper: LayoutHelper, segmentType: SegmentType): List<Int> {"
+ errorLine2=" ~~~~~~~~~">
+ <location
+ file="${:compose:ui:ui-text*debug*MAIN*sourceProvider*0*javaDir*4}/androidx/compose/ui/text/android/animation/SegmentBreaker.android.kt"/>
+ </issue>
+
+ <issue
+ id="PrimitiveInCollection"
+ message="variable list with type List<? extends Float>: replace with FloatList"
+ errorLine1=" @Suppress("UNCHECKED_CAST")"
+ errorLine2=" ^">
+ <location
+ file="src/commonMain/kotlin/androidx/compose/ui/text/Savers.kt"/>
+ </issue>
+
+ <issue
+ id="PrimitiveInCollection"
+ message="return type List<FontStyle> of values: replace with IntList"
+ errorLine1=" fun values(): List<FontStyle> = listOf(Normal, Italic)"
+ errorLine2=" ~~~~~~~~~~~~~~~">
+ <location
+ file="src/commonMain/kotlin/androidx/compose/ui/text/font/FontStyle.kt"/>
</issue>
<issue
@@ -93,11 +183,11 @@
<issue
id="PrimitiveInCollection"
- message="return type List<FontStyle> of values: replace with IntList"
- errorLine1=" fun values(): List<FontStyle> = listOf(Normal, Italic)"
+ message="return type List<TextAlign> of values: replace with IntList"
+ errorLine1=" fun values(): List<TextAlign> = listOf(Left, Right, Center, Justify, Start, End)"
errorLine2=" ~~~~~~~~~~~~~~~">
<location
- file="src/commonMain/kotlin/androidx/compose/ui/text/font/FontStyle.kt"/>
+ file="src/commonMain/kotlin/androidx/compose/ui/text/style/TextAlign.kt"/>
</issue>
<issue
@@ -127,94 +217,4 @@
file="src/jvmMain/kotlin/androidx/compose/ui/text/JvmAnnotatedString.jvm.kt"/>
</issue>
- <issue
- id="PrimitiveInCollection"
- message="field paragraphEnds with type List<Integer>: replace with IntList"
- errorLine1=" private val paragraphEnds: List<Int>"
- errorLine2=" ~~~~~~~~~">
- <location
- file="../../../text/text/src/main/java/androidx/compose/ui/text/android/LayoutHelper.kt"/>
- </issue>
-
- <issue
- id="PrimitiveInCollection"
- message="variable lineFeeds with type List<Integer>: replace with IntList"
- errorLine1=" val lineFeeds = mutableListOf<Int>()"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="../../../text/text/src/main/java/androidx/compose/ui/text/android/LayoutHelper.kt"/>
- </issue>
-
- <issue
- id="PrimitiveInCollection"
- message="variable list with type List<? extends Float>: replace with FloatList"
- errorLine1=" @Suppress("UNCHECKED_CAST")"
- errorLine2=" ^">
- <location
- file="src/commonMain/kotlin/androidx/compose/ui/text/Savers.kt"/>
- </issue>
-
- <issue
- id="PrimitiveInCollection"
- message="return type List<Integer> of breakInWords: replace with IntList"
- errorLine1=" private fun breakInWords(layoutHelper: LayoutHelper): List<Int> {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="../../../text/text/src/main/java/androidx/compose/ui/text/android/animation/SegmentBreaker.kt"/>
- </issue>
-
- <issue
- id="PrimitiveInCollection"
- message="variable words with type List<? extends Integer>: replace with IntList"
- errorLine1=" val words = breakWithBreakIterator(text, BreakIterator.getLineInstance(Locale.getDefault()))"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="../../../text/text/src/main/java/androidx/compose/ui/text/android/animation/SegmentBreaker.kt"/>
- </issue>
-
- <issue
- id="PrimitiveInCollection"
- message="variable set with type TreeSet<Integer>: replace with IntSet"
- errorLine1=" val set = TreeSet<Int>().apply {"
- errorLine2=" ^">
- <location
- file="../../../text/text/src/main/java/androidx/compose/ui/text/android/animation/SegmentBreaker.kt"/>
- </issue>
-
- <issue
- id="PrimitiveInCollection"
- message="return type List<Integer> of breakWithBreakIterator: replace with IntList"
- errorLine1=" private fun breakWithBreakIterator(text: CharSequence, breaker: BreakIterator): List<Int> {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="../../../text/text/src/main/java/androidx/compose/ui/text/android/animation/SegmentBreaker.kt"/>
- </issue>
-
- <issue
- id="PrimitiveInCollection"
- message="variable res with type List<Integer>: replace with IntList"
- errorLine1=" val res = mutableListOf(0)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="../../../text/text/src/main/java/androidx/compose/ui/text/android/animation/SegmentBreaker.kt"/>
- </issue>
-
- <issue
- id="PrimitiveInCollection"
- message="return type List<Integer> of breakOffsets: replace with IntList"
- errorLine1=" fun breakOffsets(layoutHelper: LayoutHelper, segmentType: SegmentType): List<Int> {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="../../../text/text/src/main/java/androidx/compose/ui/text/android/animation/SegmentBreaker.kt"/>
- </issue>
-
- <issue
- id="PrimitiveInCollection"
- message="return type List<TextAlign> of values: replace with IntList"
- errorLine1=" fun values(): List<TextAlign> = listOf(Left, Right, Center, Justify, Start, End)"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/commonMain/kotlin/androidx/compose/ui/text/style/TextAlign.kt"/>
- </issue>
-
</issues>
diff --git a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/input/PlatformImeOptions.android.kt b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/input/PlatformImeOptions.android.kt
index e274e69..68ef3fb 100644
--- a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/input/PlatformImeOptions.android.kt
+++ b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/input/PlatformImeOptions.android.kt
@@ -16,10 +16,7 @@
package androidx.compose.ui.text.input
-/**
- * Used to configure the platform specific IME options.
- */
-actual sealed interface PlatformImeOptions
+import androidx.compose.runtime.Immutable
/**
* Used to configure Android platform IME options.
@@ -27,10 +24,13 @@
* @param privateImeOptions defines a [String] for supplying additional information options that
* are private to a particular IME implementation.
*/
-class AndroidImeOptions(val privateImeOptions: String? = null) : PlatformImeOptions {
+@Immutable
+actual class PlatformImeOptions(
+ val privateImeOptions: String? = null,
+) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
- if (other !is AndroidImeOptions) return false
+ if (other !is PlatformImeOptions) return false
if (privateImeOptions != other.privateImeOptions) return false
@@ -42,6 +42,6 @@
}
override fun toString(): String {
- return "AndroidImeOptions(privateImeOptions=$privateImeOptions)"
+ return "PlatformImeOptions(privateImeOptions=$privateImeOptions)"
}
}
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/PlatformImeOptions.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/PlatformImeOptions.kt
index a9ade23..c7be9a2 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/PlatformImeOptions.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/PlatformImeOptions.kt
@@ -16,7 +16,10 @@
package androidx.compose.ui.text.input
+import androidx.compose.runtime.Immutable
+
/**
* Used to configure the platform specific IME options.
*/
-expect sealed interface PlatformImeOptions
+@Immutable
+expect class PlatformImeOptions
diff --git a/compose/ui/ui-text/src/desktopMain/kotlin/androidx/compose/ui/text/input/PlatformImeOptions.desktop.kt b/compose/ui/ui-text/src/desktopMain/kotlin/androidx/compose/ui/text/input/PlatformImeOptions.desktop.kt
index 60607ca..a5bc839 100644
--- a/compose/ui/ui-text/src/desktopMain/kotlin/androidx/compose/ui/text/input/PlatformImeOptions.desktop.kt
+++ b/compose/ui/ui-text/src/desktopMain/kotlin/androidx/compose/ui/text/input/PlatformImeOptions.desktop.kt
@@ -16,7 +16,10 @@
package androidx.compose.ui.text.input
+import androidx.compose.runtime.Immutable
+
/**
* Used to configure the platform specific IME options.
*/
-actual sealed interface PlatformImeOptions
+@Immutable
+actual class PlatformImeOptions
diff --git a/compose/ui/ui-tooling/src/androidInstrumentedTest/kotlin/androidx/compose/ui/tooling/animation/clock/TransitionClockTest.kt b/compose/ui/ui-tooling/src/androidInstrumentedTest/kotlin/androidx/compose/ui/tooling/animation/clock/TransitionClockTest.kt
index bffd5f9..ce1ad15 100644
--- a/compose/ui/ui-tooling/src/androidInstrumentedTest/kotlin/androidx/compose/ui/tooling/animation/clock/TransitionClockTest.kt
+++ b/compose/ui/ui-tooling/src/androidInstrumentedTest/kotlin/androidx/compose/ui/tooling/animation/clock/TransitionClockTest.kt
@@ -599,8 +599,7 @@
clock.setStateParameters(10.dp, 10.dp)
}
rule.runOnIdle {
- // When initial == target state, no animation is active.
- assertEquals(0, clock.getAnimatedProperties().size)
+ assertEquals(2, clock.getAnimatedProperties().size)
clock.setStateParameters(20.dp, 40.dp)
}
rule.runOnIdle {
@@ -620,8 +619,7 @@
rule.runOnIdle {
// Default clock state.
clock.getTransitions(100).let {
- // When initial == target state, no animation is active.
- assertEquals(0, it.size)
+ assertEquals(2, it.size)
}
// Change state
clock.setStateParameters(20.dp, 40.dp)
diff --git a/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/LookaheadScopeSample.kt b/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/LookaheadScopeSample.kt
index a7086c8..a77df1b 100644
--- a/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/LookaheadScopeSample.kt
+++ b/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/LookaheadScopeSample.kt
@@ -127,10 +127,11 @@
// given LookaheadScope, whenever the relative position changes.
fun Modifier.animatePlacementInScope(lookaheadScope: LookaheadScope) = composed {
// Creates an offset animation
- var offsetAnimation: Animatable<IntOffset, AnimationVector2D>? by mutableStateOf(
- null
- )
- var targetOffset: IntOffset? by mutableStateOf(null)
+ var offsetAnimation: Animatable<IntOffset, AnimationVector2D>? by remember {
+ mutableStateOf(
+ null
+ )
+ }
this.intermediateLayout { measurable, constraints ->
val placeable = measurable.measure(constraints)
@@ -142,7 +143,7 @@
val target = with(lookaheadScope) {
lookaheadScopeCoordinates
.localLookaheadPositionOf(coordinates)
- .round().also { targetOffset = it }
+ .round()
}
// Uses the target offset to start an offset animation
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
index 2813b41..ece23e5 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
@@ -2399,12 +2399,17 @@
// Arrange.
val focusRequester = FocusRequester()
setContent {
- Box(
- Modifier
- .testTag(tag)
- .focusRequester(focusRequester)
- .focusable()) {
- BasicText("focusable")
+ Row {
+ // Initially focused item.
+ Box(Modifier.size(10.dp).focusable())
+ Box(
+ Modifier
+ .testTag(tag)
+ .focusRequester(focusRequester)
+ .focusable()
+ ) {
+ BasicText("focusable")
+ }
}
}
rule.runOnIdle { focusRequester.requestFocus() }
@@ -2550,11 +2555,15 @@
fun testTextField_testFocusClearFocusAction() {
// Arrange.
setContent {
- BasicTextField(
- modifier = Modifier.testTag(tag),
- value = "value",
- onValueChange = {}
- )
+ Row {
+ // Initially focused item.
+ Box(Modifier.size(10.dp).focusable())
+ BasicTextField(
+ modifier = Modifier.testTag(tag),
+ value = "value",
+ onValueChange = {}
+ )
+ }
}
val textFieldId = rule.onNodeWithTag(tag)
.assert(expectValue(Focused, false))
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/AndroidComposeViewAccessibilityDelegateCompatTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/AndroidComposeViewAccessibilityDelegateCompatTest.kt
index 5b4c70b..015999c 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/AndroidComposeViewAccessibilityDelegateCompatTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/AndroidComposeViewAccessibilityDelegateCompatTest.kt
@@ -23,43 +23,25 @@
import android.os.Build.VERSION_CODES.P
import android.os.Build.VERSION_CODES.R
import android.text.SpannableString
-import android.util.LongSparseArray
import android.view.View
-import android.view.ViewStructure
import android.view.accessibility.AccessibilityEvent
-import android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE
import android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED
-import android.view.accessibility.AccessibilityEvent.TYPE_VIEW_SCROLLED
import android.view.accessibility.AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED
import android.view.accessibility.AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED
import android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
import android.view.accessibility.AccessibilityNodeInfo
import android.view.accessibility.AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_FLOAT
-import android.view.translation.TranslationRequestValue
-import android.view.translation.TranslationResponseValue
-import android.view.translation.ViewTranslationRequest
-import android.view.translation.ViewTranslationRequest.ID_TEXT
-import android.view.translation.ViewTranslationResponse
-import androidx.annotation.RequiresApi
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.size
-import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
-import androidx.compose.runtime.snapshots.Snapshot
-import androidx.compose.runtime.structuralEqualityPolicy
-import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.platform.AndroidComposeView
import androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalView
-import androidx.compose.ui.platform.coreshims.ContentCaptureSessionCompat
-import androidx.compose.ui.platform.coreshims.ViewStructureCompat
-import androidx.compose.ui.platform.testTag
-import androidx.compose.ui.semantics.CustomAccessibilityAction
import androidx.compose.ui.semantics.LiveRegionMode
import androidx.compose.ui.semantics.ProgressBarRangeInfo
import androidx.compose.ui.semantics.Role
@@ -67,11 +49,9 @@
import androidx.compose.ui.semantics.SemanticsPropertyKey
import androidx.compose.ui.semantics.SemanticsPropertyReceiver
import androidx.compose.ui.semantics.clearAndSetSemantics
-import androidx.compose.ui.semantics.clearTextSubstitution
import androidx.compose.ui.semantics.collapse
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.copyText
-import androidx.compose.ui.semantics.customActions
import androidx.compose.ui.semantics.cutText
import androidx.compose.ui.semantics.disabled
import androidx.compose.ui.semantics.dismiss
@@ -84,7 +64,6 @@
import androidx.compose.ui.semantics.heading
import androidx.compose.ui.semantics.horizontalScrollAxisRange
import androidx.compose.ui.semantics.invisibleToUser
-import androidx.compose.ui.semantics.isShowingTextSubstitution
import androidx.compose.ui.semantics.liveRegion
import androidx.compose.ui.semantics.onClick
import androidx.compose.ui.semantics.onLongClick
@@ -96,55 +75,37 @@
import androidx.compose.ui.semantics.setProgress
import androidx.compose.ui.semantics.setSelection
import androidx.compose.ui.semantics.setText
-import androidx.compose.ui.semantics.setTextSubstitution
-import androidx.compose.ui.semantics.showTextSubstitution
import androidx.compose.ui.semantics.stateDescription
import androidx.compose.ui.semantics.testTag
import androidx.compose.ui.semantics.testTagsAsResourceId
import androidx.compose.ui.semantics.text
import androidx.compose.ui.semantics.textSelectionRange
-import androidx.compose.ui.semantics.textSubstitution
-import androidx.compose.ui.semantics.verticalScrollAxisRange
import androidx.compose.ui.test.SemanticsNodeInteraction
import androidx.compose.ui.test.TestActivity
import androidx.compose.ui.test.junit4.ComposeContentTestRule
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onNodeWithTag
-import androidx.compose.ui.test.performTouchInput
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.core.view.ViewCompat
import androidx.core.view.accessibility.AccessibilityEventCompat.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION
-import androidx.core.view.accessibility.AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUSED
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
-import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_CLICK
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_COLLAPSE
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_DISMISS
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_EXPAND
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_PASTE
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat
-import androidx.core.view.doOnDetach
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import androidx.test.filters.SdkSuppress
import com.google.common.truth.Correspondence
import com.google.common.truth.Truth.assertThat
-import java.util.function.Consumer
-import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.kotlin.any
-import org.mockito.kotlin.argumentCaptor
-import org.mockito.kotlin.clearInvocations
-import org.mockito.kotlin.mock
-import org.mockito.kotlin.times
-import org.mockito.kotlin.verify
-import org.mockito.kotlin.verifyNoMoreInteractions
-import org.mockito.kotlin.whenever
@MediumTest
@RunWith(AndroidJUnit4::class)
@@ -154,11 +115,8 @@
private val tag = "tag"
private lateinit var androidComposeView: AndroidComposeView
- private lateinit var contentCaptureSessionCompat: ContentCaptureSessionCompat
- private lateinit var viewStructureCompat: ViewStructureCompat
private val dispatchedAccessibilityEvents = mutableListOf<AccessibilityEvent>()
private val accessibilityEventLoopIntervalMs = 100L
- private val contentCaptureEventLoopIntervalMs = 100L
@Test
@OptIn(ExperimentalComposeUiApi::class)
@@ -1058,358 +1016,6 @@
}
@Test
- fun sendScrollEvent_byStateObservation_horizontal() {
- // Arrange.
- var scrollValue by mutableStateOf(0f, structuralEqualityPolicy())
- val scrollMaxValue = 100f
- rule.mainClock.autoAdvance = false
- rule.setContentWithAccessibilityEnabled {
- Row(
- Modifier
- .size(20.toDp(), 10.toDp())
- .semantics(mergeDescendants = false) {
- horizontalScrollAxisRange = ScrollAxisRange(
- { scrollValue },
- { scrollMaxValue }
- )
- }
- ) {
- Text("foo", Modifier.size(10.toDp()))
- Text("bar",
- Modifier
- .size(10.toDp())
- .testTag(tag))
- }
- }
- rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
- val virtualViewId = rule.onNodeWithTag(tag).semanticsId
- rule.runOnIdle { dispatchedAccessibilityEvents.clear() }
-
- // Act.
- try {
- androidComposeView.snapshotObserver.startObserving()
- rule.runOnIdle {
- androidComposeView.accessibilityNodeProvider
- .performAction(virtualViewId, ACTION_ACCESSIBILITY_FOCUS, null)
- Snapshot.notifyObjectsInitialized()
- scrollValue = 2f
- Snapshot.sendApplyNotifications()
- }
- } finally {
- androidComposeView.snapshotObserver.stopObserving()
- }
- rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
-
- // Assert.
- rule.runOnIdle {
- val focusedANI = androidComposeView.accessibilityNodeProvider
- .findFocus(AccessibilityNodeInfo.FOCUS_ACCESSIBILITY)
- assertThat(Rect().also { focusedANI?.getBoundsInScreen(it) })
- .isEqualTo(Rect(10, 0, 20, 10))
- assertThat(dispatchedAccessibilityEvents)
- .comparingElementsUsing(AccessibilityEventComparator)
- .containsExactly(
- AccessibilityEvent().apply {
- eventType = TYPE_VIEW_ACCESSIBILITY_FOCUSED
- },
- AccessibilityEvent().apply {
- eventType = TYPE_WINDOW_CONTENT_CHANGED
- contentChangeTypes = CONTENT_CHANGE_TYPE_SUBTREE
- },
- AccessibilityEvent().apply {
- eventType = TYPE_VIEW_SCROLLED
- scrollX = 2
- maxScrollX = 100
- },
- )
- }
- }
-
- @Test
- fun sendScrollEvent_byStateObservation_vertical() {
- // Arrange.
- var scrollValue by mutableStateOf(0f, structuralEqualityPolicy())
- val scrollMaxValue = 100f
- rule.mainClock.autoAdvance = false
- rule.setContentWithAccessibilityEnabled {
- Box(
- Modifier
- .size(10.dp)
- .semantics(mergeDescendants = false) {
- verticalScrollAxisRange = ScrollAxisRange(
- { scrollValue },
- { scrollMaxValue }
- )
- }
- )
- }
-
- // TODO(b/272068594): We receive an extra TYPE_WINDOW_CONTENT_CHANGED event 100ms after
- // setup. So we wait an extra 100ms here so that this test is not affected by that extra
- // event.
- rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
- dispatchedAccessibilityEvents.clear()
-
- // Act.
- try {
- androidComposeView.snapshotObserver.startObserving()
- rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
- rule.runOnIdle {
- Snapshot.notifyObjectsInitialized()
- scrollValue = 2f
- Snapshot.sendApplyNotifications()
- }
- } finally {
- androidComposeView.snapshotObserver.stopObserving()
- }
- rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
-
- // Assert.
- rule.runOnIdle {
- assertThat(dispatchedAccessibilityEvents)
- .comparingElementsUsing(AccessibilityEventComparator)
- .containsExactly(
- AccessibilityEvent().apply {
- eventType = TYPE_WINDOW_CONTENT_CHANGED
- contentChangeTypes = CONTENT_CHANGE_TYPE_SUBTREE
- },
- AccessibilityEvent().apply {
- eventType = TYPE_VIEW_SCROLLED
- scrollY = 2
- maxScrollY = 100
- },
- )
- }
- }
-
- @Test
- fun sendWindowContentChangeUndefinedEventByDefault_whenPropertyAdded() {
- // Arrange.
- var addProperty by mutableStateOf(false)
- rule.mainClock.autoAdvance = false
- rule.setContentWithAccessibilityEnabled {
- Box(
- Modifier
- .size(10.dp)
- .semantics(mergeDescendants = false) {
- if (addProperty) disabled()
- }
- )
- }
-
- // Act.
- rule.runOnIdle { addProperty = true }
- rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
-
- // Assert.
- rule.runOnIdle {
- assertThat(dispatchedAccessibilityEvents)
- .comparingElementsUsing(AccessibilityEventComparator)
- .containsExactly(
- AccessibilityEvent().apply {
- eventType = TYPE_WINDOW_CONTENT_CHANGED
- contentChangeTypes = CONTENT_CHANGE_TYPE_UNDEFINED
- }
- )
- }
- }
-
- @Test
- fun sendWindowContentChangeUndefinedEventByDefault_whenPropertyRemoved() {
- // Arrange.
- var removeProperty by mutableStateOf(false)
- rule.mainClock.autoAdvance = false
- rule.setContentWithAccessibilityEnabled {
- Box(
- Modifier
- .size(10.dp)
- .semantics(mergeDescendants = false) {
- if (!removeProperty) disabled()
- }
- )
- }
-
- // Act.
- rule.runOnIdle { removeProperty = true }
- rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
-
- // Assert.
- rule.runOnIdle {
- assertThat(dispatchedAccessibilityEvents)
- .comparingElementsUsing(AccessibilityEventComparator)
- .containsExactly(
- AccessibilityEvent().apply {
- eventType = TYPE_WINDOW_CONTENT_CHANGED
- contentChangeTypes = CONTENT_CHANGE_TYPE_UNDEFINED
- }
- )
- }
- }
-
- @Test
- @Ignore("b/307823561")
- fun sendWindowContentChangeUndefinedEventByDefault_onlyOnce_whenMultiplePropertiesChange() {
- // Arrange.
- var propertiesChanged by mutableStateOf(false)
- rule.mainClock.autoAdvance = false
- rule.setContentWithAccessibilityEnabled {
- Box(
- Modifier
- .size(10.dp)
- .semantics(mergeDescendants = false) {
- if (!propertiesChanged) {
- disabled()
- } else {
- onClick { true }
- }
- }
- )
- }
-
- // Act.
- rule.runOnIdle { propertiesChanged = true }
- rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
-
- // Assert.
- rule.runOnIdle {
- assertThat(dispatchedAccessibilityEvents)
- .comparingElementsUsing(AccessibilityEventComparator)
- .containsExactly(
- AccessibilityEvent().apply {
- eventType = TYPE_WINDOW_CONTENT_CHANGED
- contentChangeTypes = CONTENT_CHANGE_TYPE_UNDEFINED
- }
- )
- }
- }
-
- @Test
- fun sendWindowContentChangeUndefinedEventByDefault_standardActionWithTheSameLabel() {
- // Arrange.
- var newAction by mutableStateOf(false)
- rule.mainClock.autoAdvance = false
- rule.setContentWithAccessibilityEnabled {
- Box(
- Modifier
- .size(10.dp)
- .semantics(mergeDescendants = false) {
- if (!newAction) {
- onClick(label = "action") { true }
- } else {
- onClick(label = "action") { true }
- }
- }
- )
- }
-
- // Act.
- rule.runOnIdle { newAction = true }
- rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
-
- // Assert.
- rule.runOnIdle { assertThat(dispatchedAccessibilityEvents).isEmpty() }
- }
-
- @Test
- fun sendWindowContentChangeUndefinedEventByDefault_standardActionWithDifferentLabels() {
- // Arrange.
- var newAction by mutableStateOf(false)
- rule.mainClock.autoAdvance = false
- rule.setContentWithAccessibilityEnabled {
- Box(
- Modifier
- .size(10.dp)
- .semantics(mergeDescendants = false) {
- if (!newAction) {
- onClick(label = "action1") { true }
- } else {
- onClick(label = "action2") { true }
- }
- }
- )
- }
-
- // Act.
- rule.runOnIdle { newAction = true }
- rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
-
- // Assert.
- rule.runOnIdle {
- assertThat(dispatchedAccessibilityEvents)
- .comparingElementsUsing(AccessibilityEventComparator)
- .containsExactly(
- AccessibilityEvent().apply {
- eventType = TYPE_WINDOW_CONTENT_CHANGED
- contentChangeTypes = CONTENT_CHANGE_TYPE_UNDEFINED
- }
- )
- }
- }
-
- @Test
- fun sendWindowContentChangeUndefinedEventByDefault_customActionWithTheSameLabel() {
- // Arrange.
- var newAction by mutableStateOf(false)
- rule.mainClock.autoAdvance = false
- rule.setContentWithAccessibilityEnabled {
- Box(
- Modifier
- .size(10.dp)
- .semantics(mergeDescendants = false) {
- customActions = if (!newAction) {
- listOf(CustomAccessibilityAction("action") { true })
- } else {
- listOf(CustomAccessibilityAction("action") { false })
- }
- }
- )
- }
-
- // Act.
- rule.runOnIdle { newAction = true }
- rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
-
- // Assert.
- rule.runOnIdle { assertThat(dispatchedAccessibilityEvents).isEmpty() }
- }
-
- @Test
- fun sendWindowContentChangeUndefinedEventByDefault_customActionWithDifferentLabels() {
- // Arrange.
- var newAction by mutableStateOf(false)
- rule.mainClock.autoAdvance = false
- rule.setContentWithAccessibilityEnabled {
- Box(
- Modifier
- .size(10.dp)
- .semantics(mergeDescendants = false) {
- customActions = if (!newAction) {
- listOf(CustomAccessibilityAction("action1") { true })
- } else {
- listOf(CustomAccessibilityAction("action2") { true })
- }
- }
- )
- }
-
- // Act.
- rule.runOnIdle { newAction = true }
- rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
-
- // Assert.
- rule.runOnIdle {
- assertThat(dispatchedAccessibilityEvents)
- .comparingElementsUsing(AccessibilityEventComparator)
- .containsExactly(
- AccessibilityEvent().apply {
- eventType = TYPE_WINDOW_CONTENT_CHANGED
- contentChangeTypes = CONTENT_CHANGE_TYPE_UNDEFINED
- }
- )
- }
- }
-
- @Test
fun testUncoveredNodes_notPlacedNodes_notIncluded() {
// Arrange.
rule.setContentWithAccessibilityEnabled {
@@ -1489,294 +1095,6 @@
}
}
- @Test
- fun canScroll_returnsFalse_whenPositionInvalid() {
- // Arrange.
- rule.setContentWithAccessibilityEnabled {
- Box(
- Modifier
- .size(100.dp)
- .semantics(mergeDescendants = true) {
- horizontalScrollAxisRange = ScrollAxisRange(
- value = { 0f },
- maxValue = { 1f },
- reverseScrolling = false
- )
- }
- )
- }
-
- // Assert.
- rule.runOnIdle {
- assertThat(androidComposeView.canScrollHorizontally(1)).isFalse()
- assertThat(androidComposeView.canScrollHorizontally(0)).isFalse()
- assertThat(androidComposeView.canScrollHorizontally(-1)).isFalse()
- }
- }
-
- @Test
- fun canScroll_returnsTrue_whenHorizontalScrollableNotAtLimit() {
- // Arrange.
- rule.setContentWithAccessibilityEnabled {
- Box(
- Modifier
- .size(100.toDp())
- .semantics(mergeDescendants = true) {
- testTag = tag
- horizontalScrollAxisRange = ScrollAxisRange(
- value = { 0.5f },
- maxValue = { 1f },
- reverseScrolling = false
- )
- }
- )
- }
-
- // Act.
- rule.onNodeWithTag(tag).performTouchInput { down(Offset(50f, 50f)) }
-
- // Assert.
- rule.runOnIdle {
- // Should be scrollable in both directions.
- assertThat(androidComposeView.canScrollHorizontally(1)).isTrue()
- assertThat(androidComposeView.canScrollHorizontally(0)).isTrue()
- assertThat(androidComposeView.canScrollHorizontally(-1)).isTrue()
- }
- }
-
- @Test
- fun canScroll_returnsTrue_whenVerticalScrollableNotAtLimit() {
- // Arrange.
- rule.setContentWithAccessibilityEnabled {
- Box(
- Modifier
- .size(100.toDp())
- .semantics(mergeDescendants = true) {
- testTag = tag
- verticalScrollAxisRange = ScrollAxisRange(
- value = { 0.5f },
- maxValue = { 1f },
- reverseScrolling = false
- )
- }
- )
- }
-
- // Act.
- rule.onNodeWithTag(tag).performTouchInput { down(Offset(50f, 50f)) }
-
- // Assert.
- rule.runOnIdle {
- // Should be scrollable in both directions.
- assertThat(androidComposeView.canScrollVertically(1)).isTrue()
- assertThat(androidComposeView.canScrollVertically(0)).isTrue()
- assertThat(androidComposeView.canScrollVertically(-1)).isTrue()
- }
- }
-
- @Test
- fun canScroll_returnsFalse_whenHorizontalScrollable_whenScrolledRightAndAtLimit() {
- // Arrange.
- rule.setContentWithAccessibilityEnabled {
- Box(
- Modifier
- .size(100.toDp())
- .semantics(mergeDescendants = true) {
- testTag = tag
- horizontalScrollAxisRange = ScrollAxisRange(
- value = { 1f },
- maxValue = { 1f },
- reverseScrolling = false
- )
- }
- )
- }
-
- // Act.
- rule.onNodeWithTag(tag).performTouchInput { down(Offset(50f, 50f)) }
-
- // Assert.
- rule.runOnIdle {
- assertThat(androidComposeView.canScrollHorizontally(1)).isFalse()
- assertThat(androidComposeView.canScrollHorizontally(0)).isFalse()
- assertThat(androidComposeView.canScrollHorizontally(-1)).isTrue()
- }
- }
-
- @Test
- fun canScroll_returnsFalse_whenHorizontalScrollable_whenScrolledLeftAndAtLimit() {
- // Arrange.
- rule.setContentWithAccessibilityEnabled {
- Box(
- Modifier
- .size(100.toDp())
- .semantics(mergeDescendants = true) {
- testTag = tag
- horizontalScrollAxisRange = ScrollAxisRange(
- value = { 0f },
- maxValue = { 1f },
- reverseScrolling = false
- )
- }
- )
- }
-
- // Act.
- rule.onNodeWithTag(tag).performTouchInput { down(Offset(50f, 50f)) }
-
- // Assert.
- rule.runOnIdle {
- assertThat(androidComposeView.canScrollHorizontally(1)).isTrue()
- assertThat(androidComposeView.canScrollHorizontally(0)).isTrue()
- assertThat(androidComposeView.canScrollHorizontally(-1)).isFalse()
- }
- }
-
- @Test
- fun canScroll_returnsFalse_whenVerticalScrollable_whenScrolledDownAndAtLimit() {
- // Arrange.
- rule.setContentWithAccessibilityEnabled {
- Box(
- Modifier
- .size(100.toDp())
- .semantics(mergeDescendants = true) {
- testTag = tag
- verticalScrollAxisRange = ScrollAxisRange(
- value = { 1f },
- maxValue = { 1f },
- reverseScrolling = false
- )
- }
- )
- }
-
- // Act.
- rule.onNodeWithTag(tag).performTouchInput { down(Offset(50f, 50f)) }
-
- // Assert.
- rule.runOnIdle {
- assertThat(androidComposeView.canScrollVertically(1)).isFalse()
- assertThat(androidComposeView.canScrollVertically(0)).isFalse()
- assertThat(androidComposeView.canScrollVertically(-1)).isTrue()
- }
- }
-
- @Test
- fun canScroll_returnsFalse_whenVerticalScrollable_whenScrolledUpAndAtLimit() {
- // Arrange.
- rule.setContentWithAccessibilityEnabled {
- Box(
- Modifier
- .size(100.toDp())
- .semantics(mergeDescendants = true) {
- testTag = tag
- verticalScrollAxisRange = ScrollAxisRange(
- value = { 0f },
- maxValue = { 1f },
- reverseScrolling = false
- )
- }
- )
- }
-
- // Act.
- rule.onNodeWithTag(tag).performTouchInput { down(Offset(50f, 50f)) }
-
- // Assert.
- rule.runOnIdle {
- assertThat(androidComposeView.canScrollVertically(1)).isTrue()
- assertThat(androidComposeView.canScrollVertically(0)).isTrue()
- assertThat(androidComposeView.canScrollVertically(-1)).isFalse()
- }
- }
-
- @Test
- fun canScroll_respectsReverseDirection() {
- // Arrange.
- rule.setContentWithAccessibilityEnabled {
- Box(
- Modifier
- .size(100.toDp())
- .semantics(mergeDescendants = true) {
- testTag = tag
- horizontalScrollAxisRange = ScrollAxisRange(
- value = { 0f },
- maxValue = { 1f },
- reverseScrolling = true
- )
- }
- )
- }
-
- // Act.
- rule.onNodeWithTag(tag).performTouchInput { down(Offset(50f, 50f)) }
-
- // Assert.
- rule.runOnIdle {
- assertThat(androidComposeView.canScrollHorizontally(1)).isFalse()
- assertThat(androidComposeView.canScrollHorizontally(0)).isFalse()
- assertThat(androidComposeView.canScrollHorizontally(-1)).isTrue()
- }
- }
-
- @Test
- fun canScroll_returnsFalse_forVertical_whenScrollableIsHorizontal() {
- // Arrange.
- rule.setContentWithAccessibilityEnabled {
- Box(
- Modifier
- .size(100.toDp())
- .semantics(mergeDescendants = true) {
- testTag = tag
- horizontalScrollAxisRange = ScrollAxisRange(
- value = { 0.5f },
- maxValue = { 1f },
- reverseScrolling = true
- )
- }
- )
- }
-
- // Act.
- rule.onNodeWithTag(tag).performTouchInput { down(Offset(50f, 50f)) }
-
- // Assert.
- rule.runOnIdle {
- assertThat(androidComposeView.canScrollVertically(1)).isFalse()
- assertThat(androidComposeView.canScrollVertically(0)).isFalse()
- assertThat(androidComposeView.canScrollVertically(-1)).isFalse()
- }
- }
-
- @Test
- fun canScroll_returnsFalse_whenTouchIsOutsideBounds() {
- // Arrange.
- rule.setContentWithAccessibilityEnabled {
- Box(
- Modifier
- .size(50.toDp())
- .semantics(mergeDescendants = true) {
- testTag = tag
- horizontalScrollAxisRange = ScrollAxisRange(
- value = { 0.5f },
- maxValue = { 1f },
- reverseScrolling = true
- )
- }
- )
- }
-
- // Act.
- rule.onNodeWithTag(tag).performTouchInput { down(Offset(100f, 100f)) }
-
- // Assert.
- rule.runOnIdle {
- assertThat(androidComposeView.canScrollHorizontally(1)).isFalse()
- assertThat(androidComposeView.canScrollHorizontally(0)).isFalse()
- assertThat(androidComposeView.canScrollHorizontally(-1)).isFalse()
- }
- }
-
// TODO(b/272068594): Asserting that a list does not contain an element can be an incorrect test
// because this would pass even if the event was present, (For example when isEnabled = false).
// Keeping this here to show parity for code review. This can be removed because the test
@@ -2031,525 +1349,6 @@
}
}
- @Test
- @SdkSuppress(minSdkVersion = 29)
- fun testInitContentCaptureSemanticsStructureChangeEvents_onStart() {
- // Arrange.
- rule.setContentWithContentCaptureEnabled(retainInteractionsDuringInitialization = true) {}
-
- // Act - Wait for initialization that is triggered by onStart().
-
- // Assert = verify the root node appeared.
- rule.runOnIdle {
- verify(contentCaptureSessionCompat).newVirtualViewStructure(any(), any())
- verify(contentCaptureSessionCompat).notifyViewsAppeared(any())
- verify(viewStructureCompat).setDimens(any(), any(), any(), any(), any(), any())
- verify(viewStructureCompat).toViewStructure()
- verifyNoMoreInteractions(contentCaptureSessionCompat)
- verifyNoMoreInteractions(viewStructureCompat)
- }
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 29)
- fun testInitContentCaptureSemanticsStructureChangeEvents_onStop() {
- // Arrange.
- rule.setContentWithContentCaptureEnabled {}
-
- // Act.
- rule.runOnIdle {
- androidComposeView.doOnDetach {
-
- // Assert.
- verify(contentCaptureSessionCompat).notifyViewsDisappeared(any())
- verifyNoMoreInteractions(contentCaptureSessionCompat)
- verifyNoMoreInteractions(viewStructureCompat)
- }
- }
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 29)
- fun testSendContentCaptureSemanticsStructureChangeEvents_appeared() {
- // Arrange.
- var appeared by mutableStateOf(false)
- rule.mainClock.autoAdvance = false
- rule.setContentWithContentCaptureEnabled {
- Row(
- Modifier
- .size(100.dp)
- .semantics {}) {
- if (appeared) {
- Box(
- Modifier
- .size(10.dp)
- .semantics { text = AnnotatedString("foo") })
- Box(
- Modifier
- .size(10.dp)
- .semantics { text = AnnotatedString("bar") })
- }
- }
- }
-
- // Act.
- rule.runOnIdle { appeared = true }
- // TODO(b/272068594): After refactoring this code, ensure that we don't need to wait for two
- // invocations of boundsUpdatesEventLoop.
- repeat(2) {
- rule.mainClock.advanceTimeBy(contentCaptureEventLoopIntervalMs)
- rule.waitForIdle()
- }
-
- // Assert.
- rule.runOnIdle {
- with(argumentCaptor<CharSequence>()) {
- verify(viewStructureCompat, times(2)).setText(capture())
- assertThat(firstValue).isEqualTo("foo")
- assertThat(secondValue).isEqualTo("bar")
- }
- verify(contentCaptureSessionCompat, times(0)).notifyViewsDisappeared(any())
- with(argumentCaptor<List<ViewStructure>>()) {
- verify(contentCaptureSessionCompat, times(1)).notifyViewsAppeared(capture())
- assertThat(firstValue.count()).isEqualTo(2)
- }
- }
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 29)
- fun testSendContentCaptureSemanticsStructureChangeEvents_disappeared() {
- // Arrange.
- var disappeared by mutableStateOf(false)
-
- rule.mainClock.autoAdvance = false
- rule.setContentWithContentCaptureEnabled {
- if (!disappeared) {
- Row(
- Modifier
- .size(100.dp)
- .semantics { }) {
- Box(
- Modifier
- .size(10.dp)
- .semantics { })
- Box(
- Modifier
- .size(10.dp)
- .semantics { })
- }
- }
- }
-
- // Act.
- rule.runOnIdle { disappeared = true }
-
- // TODO(b/272068594): After refactoring this code, ensure that we don't need to wait for two
- // invocations of boundsUpdatesEventLoop.
- repeat(2) {
- rule.mainClock.advanceTimeBy(contentCaptureEventLoopIntervalMs)
- rule.waitForIdle()
- }
-
- // Assert.
- rule.runOnIdle {
- with(argumentCaptor<LongArray>()) {
- verify(contentCaptureSessionCompat, times(1)).notifyViewsDisappeared(capture())
- assertThat(firstValue.count()).isEqualTo(3)
- }
- verify(contentCaptureSessionCompat, times(0)).notifyViewsAppeared(any())
- }
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 29)
- fun testSendContentCaptureSemanticsStructureChangeEvents_appearedAndDisappeared() {
- // Arrange.
- var appeared by mutableStateOf(false)
-
- rule.mainClock.autoAdvance = false
- rule.setContentWithContentCaptureEnabled {
- if (appeared) {
- Row(
- Modifier
- .size(100.dp)
- .semantics { }) {
- Box(
- Modifier
- .size(10.dp)
- .semantics { })
- Box(
- Modifier
- .size(10.dp)
- .semantics { })
- }
- }
- }
-
- // Act.
- rule.runOnIdle { appeared = true }
- // TODO(b/272068594): This test was written to ensure that if the items appeared and
- // disappeared before the 100ms, it would still report the items that were added and the
- // items that were removed The items were (As long as the items had different IDs). However
- // it is not possible for a items with different IDs to disappear as they are not existing.
- // The mocks also limit us to write this test since we can't mock AutofillIDs since
- // AutofillId is a final class, and these tests just use the autofill id of the parent
- // view.
- rule.mainClock.advanceTimeBy(contentCaptureEventLoopIntervalMs)
- rule.runOnIdle { appeared = false }
-
- // TODO(b/272068594): After refactoring this code, ensure that we don't need to wait for
- // two invocations of boundsUpdatesEventLoop.
- repeat(2) {
- rule.mainClock.advanceTimeBy(contentCaptureEventLoopIntervalMs)
- rule.waitForIdle()
- }
-
- // Assert.
- rule.runOnIdle {
- with(argumentCaptor<LongArray>()) {
- verify(contentCaptureSessionCompat, times(1)).notifyViewsDisappeared(capture())
- assertThat(firstValue.count()).isEqualTo(3)
- }
- with(argumentCaptor<List<ViewStructure>>()) {
- verify(contentCaptureSessionCompat, times(1)).notifyViewsAppeared(capture())
- assertThat(firstValue.count()).isEqualTo(3)
- }
- }
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 29)
- fun testSendContentCaptureSemanticsStructureChangeEvents_sameNodeAppearedThenDisappeared() {
- // Arrange.
- var appeared by mutableStateOf(false)
-
- rule.mainClock.autoAdvance = false
- rule.setContentWithContentCaptureEnabled {
- Box(
- Modifier
- .size(10.dp)
- .semantics { }) {
- if (appeared) {
- Box(
- Modifier
- .size(10.dp)
- .semantics { })
- }
- }
- }
-
- // Act.
- rule.runOnIdle { appeared = true }
-
- // TODO(b/272068594): After refactoring this code, ensure that we don't need to wait for two
- // invocations of boundsUpdatesEventLoop.
- repeat(2) {
- rule.mainClock.advanceTimeBy(contentCaptureEventLoopIntervalMs)
- rule.waitForIdle()
- }
-
- // Assert.
- rule.runOnIdle {
- verify(contentCaptureSessionCompat, times(0)).notifyViewsDisappeared(any())
- with(argumentCaptor<List<ViewStructure>>()) {
- verify(contentCaptureSessionCompat, times(1)).notifyViewsAppeared(capture())
- assertThat(firstValue.count()).isEqualTo(1)
- }
- clearInvocations(contentCaptureSessionCompat)
- }
-
- rule.runOnIdle { appeared = false }
-
- // TODO(b/272068594): After refactoring this code, ensure that we don't need to wait for two
- // invocations of boundsUpdatesEventLoop.
- repeat(2) {
- rule.mainClock.advanceTimeBy(contentCaptureEventLoopIntervalMs)
- rule.waitForIdle()
- }
-
- // Assert.
- rule.runOnIdle {
- verify(contentCaptureSessionCompat, times(0)).notifyViewsDisappeared(any())
- verify(contentCaptureSessionCompat, times(0)).notifyViewsAppeared(any())
- }
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 31)
- fun testUpdateTranslationOnAppeared_showOriginal() {
- // Arrange.
- var appeared by mutableStateOf(false)
- var result = true
-
- rule.mainClock.autoAdvance = false
- rule.setContentWithContentCaptureEnabled {
- Box(
- Modifier
- .size(10.dp)
- .semantics { }) {
- if (appeared) {
- Box(
- Modifier
- .size(10.dp)
- .semantics {
- text = AnnotatedString("foo")
- isShowingTextSubstitution = true
- showTextSubstitution {
- result = it
- true
- }
- }
- )
- }
- }
- }
- rule.runOnIdle { androidComposeView.composeAccessibilityDelegate.onHideTranslation() }
-
- // Act.
- rule.runOnIdle { appeared = true }
- rule.mainClock.advanceTimeBy(contentCaptureEventLoopIntervalMs)
-
- // Assert.
- rule.runOnIdle { assertThat(result).isFalse() }
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 31)
- fun testUpdateTranslationOnAppeared_showTranslated() {
- // Arrange.
- var appeared by mutableStateOf(false)
- var result = false
-
- rule.mainClock.autoAdvance = false
- rule.setContentWithContentCaptureEnabled {
- Box(
- Modifier
- .size(10.dp)
- .semantics { }) {
- if (appeared) {
- Box(
- Modifier
- .size(10.dp)
- .semantics {
- text = AnnotatedString("foo")
- isShowingTextSubstitution = false
- showTextSubstitution {
- result = it
- true
- }
- }
- )
- }
- }
- }
- rule.runOnIdle { androidComposeView.composeAccessibilityDelegate.onShowTranslation() }
-
- // Act.
- rule.runOnIdle { appeared = true }
- rule.mainClock.advanceTimeBy(contentCaptureEventLoopIntervalMs)
-
- // Assert.
- rule.runOnIdle { assertThat(result).isTrue() }
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 31)
- fun testOnCreateVirtualViewTranslationRequests() {
- // Arrange.
- rule.mainClock.autoAdvance = false
- rule.setContentWithContentCaptureEnabled {
- Box(
- Modifier
- .size(10.dp)
- .semantics { text = AnnotatedString("bar") }) {
- Box(
- Modifier
- .size(10.dp)
- .semantics {
- testTag = tag
- text = AnnotatedString("foo")
- }
- )
- }
- }
- val virtualViewId = rule.onNodeWithTag(tag).semanticsId
-
- val ids = LongArray(1).apply { this[0] = virtualViewId.toLong() }
- val requestsCollector: Consumer<ViewTranslationRequest?> = mock()
-
- // Act.
- rule.runOnIdle {
- androidComposeView.onCreateVirtualViewTranslationRequests(
- ids,
- IntArray(0),
- requestsCollector
- )
- }
-
- // Assert.
- rule.runOnIdle {
- with(argumentCaptor<ViewTranslationRequest>()) {
- verify(requestsCollector).accept(capture())
- assertThat(firstValue).isEqualTo(
- ViewTranslationRequest
- .Builder(androidComposeView.autofillId, virtualViewId.toLong())
- .setValue(ID_TEXT, TranslationRequestValue.forText(AnnotatedString("foo")))
- .build()
- )
- }
- }
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 31)
- fun testOnVirtualViewTranslationResponses() {
- // Arrange.
- var result: AnnotatedString? = null
- rule.mainClock.autoAdvance = false
- rule.setContentWithContentCaptureEnabled {
- Box(
- Modifier
- .size(10.dp)
- .semantics { text = AnnotatedString("bar") }) {
- Box(
- Modifier
- .size(10.dp)
- .semantics {
- testTag = tag
- text = AnnotatedString("foo")
- setTextSubstitution {
- result = it
- true
- }
- }
- )
- }
- }
- val virtualViewId = rule.onNodeWithTag(tag).semanticsId
-
- // Act.
- rule.runOnIdle {
- androidComposeView.onVirtualViewTranslationResponses(
- LongSparseArray<ViewTranslationResponse?>().apply {
- append(
- virtualViewId.toLong(),
- ViewTranslationResponse
- .Builder(androidComposeView.autofillId)
- .setValue(
- ID_TEXT,
- TranslationResponseValue.Builder(0).setText("bar").build()
- )
- .build()
- )
- }
- )
- }
-
- // Assert.
- rule.runOnIdle { assertThat(result).isEqualTo(AnnotatedString("bar")) }
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 31)
- fun testOnShowTranslation() {
- // Arrange.
- var result = false
- rule.mainClock.autoAdvance = false
- rule.setContentWithContentCaptureEnabled {
- Box(
- Modifier
- .size(10.dp)
- .semantics { text = AnnotatedString("bar") }) {
- Box(
- Modifier
- .size(10.dp)
- .semantics {
- textSubstitution = AnnotatedString("foo")
- isShowingTextSubstitution = false
- showTextSubstitution {
- result = it
- true
- }
- }
- )
- }
- }
-
- // Act.
- rule.runOnIdle { androidComposeView.composeAccessibilityDelegate.onShowTranslation() }
-
- // Assert.
- rule.runOnIdle { assertThat(result).isTrue() }
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 31)
- fun testOnHideTranslation() {
- // Arrange.
- var result = true
- rule.mainClock.autoAdvance = false
- rule.setContentWithContentCaptureEnabled {
- Box(
- Modifier
- .size(10.dp)
- .semantics { text = AnnotatedString("bar") }) {
- Box(
- Modifier
- .size(10.dp)
- .semantics {
- text = AnnotatedString("bar")
- textSubstitution = AnnotatedString("foo")
- isShowingTextSubstitution = true
- showTextSubstitution {
- result = it
- true
- }
- }
- )
- }
- }
-
- // Act.
- rule.runOnIdle { androidComposeView.composeAccessibilityDelegate.onHideTranslation() }
-
- // Assert.
- rule.runOnIdle { assertThat(result).isFalse() }
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 31)
- fun testOnClearTranslation() {
- // Arrange.
- var result = false
- rule.mainClock.autoAdvance = false
- rule.setContentWithContentCaptureEnabled {
- Box(
- Modifier
- .size(10.dp)
- .semantics { text = AnnotatedString("bar") }) {
- Box(
- Modifier
- .size(10.dp)
- .semantics {
- text = AnnotatedString("bar")
- isShowingTextSubstitution = true
- clearTextSubstitution {
- result = true
- true
- }
- }
- )
- }
- }
-
- // Act.
- rule.runOnIdle { androidComposeView.composeAccessibilityDelegate.onClearTranslation() }
-
- // Assert.
- rule.runOnIdle { assertThat(result).isTrue() }
- }
-
private fun Int.toDp(): Dp = with(rule.density) { [email protected]() }
private fun ComposeContentTestRule.setContentWithAccessibilityEnabled(
@@ -2570,47 +1369,6 @@
runOnIdle { dispatchedAccessibilityEvents.clear() }
}
- @RequiresApi(Build.VERSION_CODES.O)
- private fun ComposeContentTestRule.setContentWithContentCaptureEnabled(
- retainInteractionsDuringInitialization: Boolean = false,
- content: @Composable () -> Unit
- ) {
- contentCaptureSessionCompat = mock()
- viewStructureCompat = mock()
- val viewStructure: ViewStructure = mock()
-
- whenever(contentCaptureSessionCompat.newVirtualViewStructure(any(), any()))
- .thenReturn(viewStructureCompat)
- whenever(viewStructureCompat.toViewStructure())
- .thenReturn(viewStructure)
-
- setContent {
- androidComposeView = LocalView.current as AndroidComposeView
- with(androidComposeView.composeAccessibilityDelegate) {
- accessibilityForceEnabledForTesting = true
- contentCaptureForceEnabledForTesting = true
- contentCaptureSession = contentCaptureSessionCompat
- onSendAccessibilityEvent = { dispatchedAccessibilityEvents += it; false }
- }
-
- whenever(contentCaptureSessionCompat.newAutofillId(any())).thenAnswer {
- androidComposeView.autofillId
- }
-
- content()
- }
-
- // Advance the clock past the first accessibility event loop, and clear the initial
- // as we are want the assertions to check the events that were generated later.
- runOnIdle { mainClock.advanceTimeBy(contentCaptureEventLoopIntervalMs) }
-
- runOnIdle {
- if (!retainInteractionsDuringInitialization) {
- clearInvocations(contentCaptureSessionCompat, viewStructureCompat)
- }
- }
- }
-
private fun AndroidComposeView.createAccessibilityNodeInfo(
semanticsId: Int
): AccessibilityNodeInfoCompat {
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/ContentCaptureTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/ContentCaptureTest.kt
new file mode 100644
index 0000000..60c607a
--- /dev/null
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/ContentCaptureTest.kt
@@ -0,0 +1,674 @@
+
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.ui
+
+import android.os.Build
+import android.util.LongSparseArray
+import android.view.View
+import android.view.ViewStructure
+import android.view.accessibility.AccessibilityEvent
+import android.view.translation.TranslationRequestValue
+import android.view.translation.TranslationResponseValue
+import android.view.translation.ViewTranslationRequest
+import android.view.translation.ViewTranslationRequest.ID_TEXT
+import android.view.translation.ViewTranslationResponse
+import androidx.annotation.RequiresApi
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.platform.AndroidComposeView
+import androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat
+import androidx.compose.ui.platform.LocalView
+import androidx.compose.ui.platform.coreshims.ContentCaptureSessionCompat
+import androidx.compose.ui.platform.coreshims.ViewStructureCompat
+import androidx.compose.ui.semantics.clearTextSubstitution
+import androidx.compose.ui.semantics.isShowingTextSubstitution
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.semantics.setTextSubstitution
+import androidx.compose.ui.semantics.showTextSubstitution
+import androidx.compose.ui.semantics.testTag
+import androidx.compose.ui.semantics.text
+import androidx.compose.ui.semantics.textSubstitution
+import androidx.compose.ui.test.SemanticsNodeInteraction
+import androidx.compose.ui.test.TestActivity
+import androidx.compose.ui.test.junit4.ComposeContentTestRule
+import androidx.compose.ui.test.junit4.createAndroidComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.unit.dp
+import androidx.core.view.ViewCompat
+import androidx.core.view.doOnDetach
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import com.google.common.truth.Truth.assertThat
+import java.util.function.Consumer
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.clearInvocations
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.times
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.verifyNoMoreInteractions
+import org.mockito.kotlin.whenever
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class ContentCaptureTest {
+ @get:Rule
+ val rule = createAndroidComposeRule<TestActivity>()
+
+ private val tag = "tag"
+ private lateinit var androidComposeView: AndroidComposeView
+ private lateinit var contentCaptureSessionCompat: ContentCaptureSessionCompat
+ private lateinit var viewStructureCompat: ViewStructureCompat
+ private val dispatchedAccessibilityEvents = mutableListOf<AccessibilityEvent>()
+ private val contentCaptureEventLoopIntervalMs = 100L
+
+ @Test
+ @SdkSuppress(minSdkVersion = 29)
+ fun testInitContentCaptureSemanticsStructureChangeEvents_onStart() {
+ // Arrange.
+ rule.setContentWithContentCaptureEnabled(retainInteractionsDuringInitialization = true) {}
+
+ // Act - Wait for initialization that is triggered by onStart().
+
+ // Assert = verify the root node appeared.
+ rule.runOnIdle {
+ verify(contentCaptureSessionCompat).newVirtualViewStructure(any(), any())
+ verify(contentCaptureSessionCompat).notifyViewsAppeared(any())
+ verify(viewStructureCompat).setDimens(any(), any(), any(), any(), any(), any())
+ verify(viewStructureCompat).toViewStructure()
+ verifyNoMoreInteractions(contentCaptureSessionCompat)
+ verifyNoMoreInteractions(viewStructureCompat)
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 29)
+ fun testInitContentCaptureSemanticsStructureChangeEvents_onStop() {
+ // Arrange.
+ rule.setContentWithContentCaptureEnabled {}
+
+ // Act.
+ rule.runOnIdle {
+ androidComposeView.doOnDetach {
+
+ // Assert.
+ verify(contentCaptureSessionCompat).notifyViewsDisappeared(any())
+ verifyNoMoreInteractions(contentCaptureSessionCompat)
+ verifyNoMoreInteractions(viewStructureCompat)
+ }
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 29)
+ fun testSendContentCaptureSemanticsStructureChangeEvents_appeared() {
+ // Arrange.
+ var appeared by mutableStateOf(false)
+ rule.mainClock.autoAdvance = false
+ rule.setContentWithContentCaptureEnabled {
+ Row(
+ Modifier
+ .size(100.dp)
+ .semantics {}
+ ) {
+ if (appeared) {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics { text = AnnotatedString("foo") }
+ )
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics { text = AnnotatedString("bar") }
+ )
+ }
+ }
+ }
+
+ // Act.
+ rule.runOnIdle { appeared = true }
+ // TODO(b/272068594): After refactoring this code, ensure that we don't need to wait for two
+ // invocations of boundsUpdatesEventLoop.
+ repeat(2) {
+ rule.mainClock.advanceTimeBy(contentCaptureEventLoopIntervalMs)
+ rule.waitForIdle()
+ }
+
+ // Assert.
+ rule.runOnIdle {
+ with(argumentCaptor<CharSequence>()) {
+ verify(viewStructureCompat, times(2)).setText(capture())
+ assertThat(firstValue).isEqualTo("foo")
+ assertThat(secondValue).isEqualTo("bar")
+ }
+ verify(contentCaptureSessionCompat, times(0)).notifyViewsDisappeared(any())
+ with(argumentCaptor<List<ViewStructure>>()) {
+ verify(contentCaptureSessionCompat, times(1)).notifyViewsAppeared(capture())
+ assertThat(firstValue.count()).isEqualTo(2)
+ }
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 29)
+ fun testSendContentCaptureSemanticsStructureChangeEvents_disappeared() {
+ // Arrange.
+ var disappeared by mutableStateOf(false)
+
+ rule.mainClock.autoAdvance = false
+ rule.setContentWithContentCaptureEnabled {
+ if (!disappeared) {
+ Row(
+ Modifier
+ .size(100.dp)
+ .semantics { }
+ ) {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics { }
+ )
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics { }
+ )
+ }
+ }
+ }
+
+ // Act.
+ rule.runOnIdle { disappeared = true }
+
+ // TODO(b/272068594): After refactoring this code, ensure that we don't need to wait for two
+ // invocations of boundsUpdatesEventLoop.
+ repeat(2) {
+ rule.mainClock.advanceTimeBy(contentCaptureEventLoopIntervalMs)
+ rule.waitForIdle()
+ }
+
+ // Assert.
+ rule.runOnIdle {
+ with(argumentCaptor<LongArray>()) {
+ verify(contentCaptureSessionCompat, times(1)).notifyViewsDisappeared(capture())
+ assertThat(firstValue.count()).isEqualTo(3)
+ }
+ verify(contentCaptureSessionCompat, times(0)).notifyViewsAppeared(any())
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 29)
+ fun testSendContentCaptureSemanticsStructureChangeEvents_appearedAndDisappeared() {
+ // Arrange.
+ var appeared by mutableStateOf(false)
+
+ rule.mainClock.autoAdvance = false
+ rule.setContentWithContentCaptureEnabled {
+ if (appeared) {
+ Row(
+ Modifier
+ .size(100.dp)
+ .semantics { }
+ ) {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics { }
+ )
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics { }
+ )
+ }
+ }
+ }
+
+ // Act.
+ rule.runOnIdle { appeared = true }
+ // TODO(b/272068594): This test was written to ensure that if the items appeared and
+ // disappeared before the 100ms, it would still report the items that were added and the
+ // items that were removed The items were (As long as the items had different IDs). However
+ // it is not possible for a items with different IDs to disappear as they are not existing.
+ // The mocks also limit us to write this test since we can't mock AutofillIDs since
+ // AutofillId is a final class, and these tests just use the autofill id of the parent
+ // view.
+ rule.mainClock.advanceTimeBy(contentCaptureEventLoopIntervalMs)
+ rule.runOnIdle { appeared = false }
+
+ // TODO(b/272068594): After refactoring this code, ensure that we don't need to wait for
+ // two invocations of boundsUpdatesEventLoop.
+ repeat(2) {
+ rule.mainClock.advanceTimeBy(contentCaptureEventLoopIntervalMs)
+ rule.waitForIdle()
+ }
+
+ // Assert.
+ rule.runOnIdle {
+ with(argumentCaptor<LongArray>()) {
+ verify(contentCaptureSessionCompat, times(1)).notifyViewsDisappeared(capture())
+ assertThat(firstValue.count()).isEqualTo(3)
+ }
+ with(argumentCaptor<List<ViewStructure>>()) {
+ verify(contentCaptureSessionCompat, times(1)).notifyViewsAppeared(capture())
+ assertThat(firstValue.count()).isEqualTo(3)
+ }
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 29)
+ fun testSendContentCaptureSemanticsStructureChangeEvents_sameNodeAppearedThenDisappeared() {
+ // Arrange.
+ var appeared by mutableStateOf(false)
+
+ rule.mainClock.autoAdvance = false
+ rule.setContentWithContentCaptureEnabled {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics { }
+ ) {
+ if (appeared) {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics { }
+ )
+ }
+ }
+ }
+
+ // Act.
+ rule.runOnIdle { appeared = true }
+
+ // TODO(b/272068594): After refactoring this code, ensure that we don't need to wait for two
+ // invocations of boundsUpdatesEventLoop.
+ repeat(2) {
+ rule.mainClock.advanceTimeBy(contentCaptureEventLoopIntervalMs)
+ rule.waitForIdle()
+ }
+
+ // Assert.
+ rule.runOnIdle {
+ verify(contentCaptureSessionCompat, times(0)).notifyViewsDisappeared(any())
+ with(argumentCaptor<List<ViewStructure>>()) {
+ verify(contentCaptureSessionCompat, times(1)).notifyViewsAppeared(capture())
+ assertThat(firstValue.count()).isEqualTo(1)
+ }
+ clearInvocations(contentCaptureSessionCompat)
+ }
+
+ rule.runOnIdle { appeared = false }
+
+ // TODO(b/272068594): After refactoring this code, ensure that we don't need to wait for two
+ // invocations of boundsUpdatesEventLoop.
+ repeat(2) {
+ rule.mainClock.advanceTimeBy(contentCaptureEventLoopIntervalMs)
+ rule.waitForIdle()
+ }
+
+ // Assert.
+ rule.runOnIdle {
+ verify(contentCaptureSessionCompat, times(0)).notifyViewsDisappeared(any())
+ verify(contentCaptureSessionCompat, times(0)).notifyViewsAppeared(any())
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 31)
+ fun testUpdateTranslationOnAppeared_showOriginal() {
+ // Arrange.
+ var appeared by mutableStateOf(false)
+ var result = true
+
+ rule.mainClock.autoAdvance = false
+ rule.setContentWithContentCaptureEnabled {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics { }
+ ) {
+ if (appeared) {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics {
+ text = AnnotatedString("foo")
+ isShowingTextSubstitution = true
+ showTextSubstitution {
+ result = it
+ true
+ }
+ }
+ )
+ }
+ }
+ }
+ rule.runOnIdle { androidComposeView.composeAccessibilityDelegate.onHideTranslation() }
+
+ // Act.
+ rule.runOnIdle { appeared = true }
+ rule.mainClock.advanceTimeBy(contentCaptureEventLoopIntervalMs)
+
+ // Assert.
+ rule.runOnIdle { assertThat(result).isFalse() }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 31)
+ fun testUpdateTranslationOnAppeared_showTranslated() {
+ // Arrange.
+ var appeared by mutableStateOf(false)
+ var result = false
+
+ rule.mainClock.autoAdvance = false
+ rule.setContentWithContentCaptureEnabled {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics { }
+ ) {
+ if (appeared) {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics {
+ text = AnnotatedString("foo")
+ isShowingTextSubstitution = false
+ showTextSubstitution {
+ result = it
+ true
+ }
+ }
+ )
+ }
+ }
+ }
+ rule.runOnIdle { androidComposeView.composeAccessibilityDelegate.onShowTranslation() }
+
+ // Act.
+ rule.runOnIdle { appeared = true }
+ rule.mainClock.advanceTimeBy(contentCaptureEventLoopIntervalMs)
+
+ // Assert.
+ rule.runOnIdle { assertThat(result).isTrue() }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 31)
+ fun testOnCreateVirtualViewTranslationRequests() {
+ // Arrange.
+ rule.mainClock.autoAdvance = false
+ rule.setContentWithContentCaptureEnabled {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics { text = AnnotatedString("bar") }
+ ) {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics {
+ testTag = tag
+ text = AnnotatedString("foo")
+ }
+ )
+ }
+ }
+ val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+
+ val ids = LongArray(1).apply { this[0] = virtualViewId.toLong() }
+ val requestsCollector: Consumer<ViewTranslationRequest?> = mock()
+
+ // Act.
+ rule.runOnIdle {
+ androidComposeView.onCreateVirtualViewTranslationRequests(
+ ids,
+ IntArray(0),
+ requestsCollector
+ )
+ }
+
+ // Assert.
+ rule.runOnIdle {
+ with(argumentCaptor<ViewTranslationRequest>()) {
+ verify(requestsCollector).accept(capture())
+ assertThat(firstValue).isEqualTo(
+ ViewTranslationRequest
+ .Builder(androidComposeView.autofillId, virtualViewId.toLong())
+ .setValue(ID_TEXT, TranslationRequestValue.forText(AnnotatedString("foo")))
+ .build()
+ )
+ }
+ }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 31)
+ fun testOnVirtualViewTranslationResponses() {
+ // Arrange.
+ var result: AnnotatedString? = null
+ rule.mainClock.autoAdvance = false
+ rule.setContentWithContentCaptureEnabled {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics { text = AnnotatedString("bar") }
+ ) {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics {
+ testTag = tag
+ text = AnnotatedString("foo")
+ setTextSubstitution {
+ result = it
+ true
+ }
+ }
+ )
+ }
+ }
+ val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+
+ // Act.
+ rule.runOnIdle {
+ androidComposeView.onVirtualViewTranslationResponses(
+ LongSparseArray<ViewTranslationResponse?>().apply {
+ append(
+ virtualViewId.toLong(),
+ ViewTranslationResponse
+ .Builder(androidComposeView.autofillId)
+ .setValue(
+ ID_TEXT,
+ TranslationResponseValue.Builder(0).setText("bar").build()
+ )
+ .build()
+ )
+ }
+ )
+ }
+
+ // Assert.
+ rule.runOnIdle { assertThat(result).isEqualTo(AnnotatedString("bar")) }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 31)
+ fun testOnShowTranslation() {
+ // Arrange.
+ var result = false
+ rule.mainClock.autoAdvance = false
+ rule.setContentWithContentCaptureEnabled {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics { text = AnnotatedString("bar") }
+ ) {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics {
+ textSubstitution = AnnotatedString("foo")
+ isShowingTextSubstitution = false
+ showTextSubstitution {
+ result = it
+ true
+ }
+ }
+ )
+ }
+ }
+
+ // Act.
+ rule.runOnIdle { androidComposeView.composeAccessibilityDelegate.onShowTranslation() }
+
+ // Assert.
+ rule.runOnIdle { assertThat(result).isTrue() }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 31)
+ fun testOnHideTranslation() {
+ // Arrange.
+ var result = true
+ rule.mainClock.autoAdvance = false
+ rule.setContentWithContentCaptureEnabled {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics { text = AnnotatedString("bar") }
+ ) {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics {
+ text = AnnotatedString("bar")
+ textSubstitution = AnnotatedString("foo")
+ isShowingTextSubstitution = true
+ showTextSubstitution {
+ result = it
+ true
+ }
+ }
+ )
+ }
+ }
+
+ // Act.
+ rule.runOnIdle { androidComposeView.composeAccessibilityDelegate.onHideTranslation() }
+
+ // Assert.
+ rule.runOnIdle { assertThat(result).isFalse() }
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 31)
+ fun testOnClearTranslation() {
+ // Arrange.
+ var result = false
+ rule.mainClock.autoAdvance = false
+ rule.setContentWithContentCaptureEnabled {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics { text = AnnotatedString("bar") }
+ ) {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics {
+ text = AnnotatedString("bar")
+ isShowingTextSubstitution = true
+ clearTextSubstitution {
+ result = true
+ true
+ }
+ }
+ )
+ }
+ }
+
+ // Act.
+ rule.runOnIdle { androidComposeView.composeAccessibilityDelegate.onClearTranslation() }
+
+ // Assert.
+ rule.runOnIdle { assertThat(result).isTrue() }
+ }
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ private fun ComposeContentTestRule.setContentWithContentCaptureEnabled(
+ retainInteractionsDuringInitialization: Boolean = false,
+ content: @Composable () -> Unit
+ ) {
+ contentCaptureSessionCompat = mock()
+ viewStructureCompat = mock()
+ val viewStructure: ViewStructure = mock()
+
+ whenever(contentCaptureSessionCompat.newVirtualViewStructure(any(), any()))
+ .thenReturn(viewStructureCompat)
+ whenever(viewStructureCompat.toViewStructure())
+ .thenReturn(viewStructure)
+
+ setContent {
+ androidComposeView = LocalView.current as AndroidComposeView
+ with(androidComposeView.composeAccessibilityDelegate) {
+ accessibilityForceEnabledForTesting = true
+ contentCaptureForceEnabledForTesting = true
+ contentCaptureSession = contentCaptureSessionCompat
+ onSendAccessibilityEvent = { dispatchedAccessibilityEvents += it; false }
+ }
+
+ whenever(contentCaptureSessionCompat.newAutofillId(any())).thenAnswer {
+ androidComposeView.autofillId
+ }
+
+ content()
+ }
+
+ // Advance the clock past the first accessibility event loop, and clear the initial
+ // as we are want the assertions to check the events that were generated later.
+ runOnIdle { mainClock.advanceTimeBy(contentCaptureEventLoopIntervalMs) }
+
+ runOnIdle {
+ if (!retainInteractionsDuringInitialization) {
+ clearInvocations(contentCaptureSessionCompat, viewStructureCompat)
+ }
+ }
+ }
+
+ private val View.composeAccessibilityDelegate: AndroidComposeViewAccessibilityDelegateCompat
+ get() = ViewCompat.getAccessibilityDelegate(this)
+ as AndroidComposeViewAccessibilityDelegateCompat
+
+ // TODO(b/272068594): Add api to fetch the semantics id from SemanticsNodeInteraction directly.
+ private val SemanticsNodeInteraction.semanticsId: Int get() = fetchSemanticsNode().id
+}
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/accessibility/ScrollingTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/accessibility/ScrollingTest.kt
new file mode 100644
index 0000000..04494ed
--- /dev/null
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/accessibility/ScrollingTest.kt
@@ -0,0 +1,573 @@
+
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.ui.accessibility
+
+import android.graphics.Rect
+import android.os.Build.VERSION.SDK_INT
+import android.os.Build.VERSION_CODES.P
+import android.os.Build.VERSION_CODES.R
+import android.view.View
+import android.view.accessibility.AccessibilityEvent
+import android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE
+import android.view.accessibility.AccessibilityEvent.TYPE_VIEW_SCROLLED
+import android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
+import android.view.accessibility.AccessibilityNodeInfo
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.size
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshots.Snapshot
+import androidx.compose.runtime.structuralEqualityPolicy
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.platform.AndroidComposeView
+import androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat
+import androidx.compose.ui.platform.LocalView
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.ScrollAxisRange
+import androidx.compose.ui.semantics.horizontalScrollAxisRange
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.semantics.testTag
+import androidx.compose.ui.semantics.verticalScrollAxisRange
+import androidx.compose.ui.test.SemanticsNodeInteraction
+import androidx.compose.ui.test.TestActivity
+import androidx.compose.ui.test.junit4.ComposeContentTestRule
+import androidx.compose.ui.test.junit4.createAndroidComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performTouchInput
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.core.view.ViewCompat
+import androidx.core.view.accessibility.AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUSED
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import com.google.common.truth.Correspondence
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class ScrollingTest {
+ @get:Rule
+ val rule = createAndroidComposeRule<TestActivity>()
+
+ private val tag = "tag"
+ private lateinit var androidComposeView: AndroidComposeView
+ private val dispatchedAccessibilityEvents = mutableListOf<AccessibilityEvent>()
+ private val accessibilityEventLoopIntervalMs = 100L
+
+ @Test
+ fun sendScrollEvent_byStateObservation_horizontal() {
+ // Arrange.
+ var scrollValue by mutableStateOf(0f, structuralEqualityPolicy())
+ val scrollMaxValue = 100f
+ rule.mainClock.autoAdvance = false
+ rule.setContentWithAccessibilityEnabled {
+ Row(
+ Modifier
+ .size(20.toDp(), 10.toDp())
+ .semantics(mergeDescendants = false) {
+ horizontalScrollAxisRange = ScrollAxisRange(
+ { scrollValue },
+ { scrollMaxValue }
+ )
+ }
+ ) {
+ Text("foo", Modifier.size(10.toDp()))
+ Text("bar",
+ Modifier
+ .size(10.toDp())
+ .testTag(tag))
+ }
+ }
+ rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
+ val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+ rule.runOnIdle { dispatchedAccessibilityEvents.clear() }
+
+ // Act.
+ try {
+ androidComposeView.snapshotObserver.startObserving()
+ rule.runOnIdle {
+ androidComposeView.accessibilityNodeProvider
+ .performAction(virtualViewId, ACTION_ACCESSIBILITY_FOCUS, null)
+ Snapshot.notifyObjectsInitialized()
+ scrollValue = 2f
+ Snapshot.sendApplyNotifications()
+ }
+ } finally {
+ androidComposeView.snapshotObserver.stopObserving()
+ }
+ rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
+
+ // Assert.
+ rule.runOnIdle {
+ val focusedANI = androidComposeView.accessibilityNodeProvider
+ .findFocus(AccessibilityNodeInfo.FOCUS_ACCESSIBILITY)
+ assertThat(Rect().also { focusedANI?.getBoundsInScreen(it) })
+ .isEqualTo(Rect(10, 0, 20, 10))
+ assertThat(dispatchedAccessibilityEvents)
+ .comparingElementsUsing(AccessibilityEventComparator)
+ .containsExactly(
+ AccessibilityEvent().apply {
+ eventType = TYPE_VIEW_ACCESSIBILITY_FOCUSED
+ },
+ AccessibilityEvent().apply {
+ eventType = TYPE_WINDOW_CONTENT_CHANGED
+ contentChangeTypes = CONTENT_CHANGE_TYPE_SUBTREE
+ },
+ AccessibilityEvent().apply {
+ eventType = TYPE_VIEW_SCROLLED
+ scrollX = 2
+ maxScrollX = 100
+ },
+ )
+ }
+ }
+
+ @Test
+ fun sendScrollEvent_byStateObservation_vertical() {
+ // Arrange.
+ var scrollValue by mutableStateOf(0f, structuralEqualityPolicy())
+ val scrollMaxValue = 100f
+ rule.mainClock.autoAdvance = false
+ rule.setContentWithAccessibilityEnabled {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics(mergeDescendants = false) {
+ verticalScrollAxisRange = ScrollAxisRange(
+ { scrollValue },
+ { scrollMaxValue }
+ )
+ }
+ )
+ }
+
+ // TODO(b/272068594): We receive an extra TYPE_WINDOW_CONTENT_CHANGED event 100ms after
+ // setup. So we wait an extra 100ms here so that this test is not affected by that extra
+ // event.
+ rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
+ dispatchedAccessibilityEvents.clear()
+
+ // Act.
+ try {
+ androidComposeView.snapshotObserver.startObserving()
+ rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
+ rule.runOnIdle {
+ Snapshot.notifyObjectsInitialized()
+ scrollValue = 2f
+ Snapshot.sendApplyNotifications()
+ }
+ } finally {
+ androidComposeView.snapshotObserver.stopObserving()
+ }
+ rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
+
+ // Assert.
+ rule.runOnIdle {
+ assertThat(dispatchedAccessibilityEvents)
+ .comparingElementsUsing(AccessibilityEventComparator)
+ .containsExactly(
+ AccessibilityEvent().apply {
+ eventType = TYPE_WINDOW_CONTENT_CHANGED
+ contentChangeTypes = CONTENT_CHANGE_TYPE_SUBTREE
+ },
+ AccessibilityEvent().apply {
+ eventType = TYPE_VIEW_SCROLLED
+ scrollY = 2
+ maxScrollY = 100
+ },
+ )
+ }
+ }
+
+ @Test
+ fun canScroll_returnsFalse_whenPositionInvalid() {
+ // Arrange.
+ rule.setContentWithAccessibilityEnabled {
+ Box(
+ Modifier
+ .size(100.dp)
+ .semantics(mergeDescendants = true) {
+ horizontalScrollAxisRange = ScrollAxisRange(
+ value = { 0f },
+ maxValue = { 1f },
+ reverseScrolling = false
+ )
+ }
+ )
+ }
+
+ // Assert.
+ rule.runOnIdle {
+ assertThat(androidComposeView.canScrollHorizontally(1)).isFalse()
+ assertThat(androidComposeView.canScrollHorizontally(0)).isFalse()
+ assertThat(androidComposeView.canScrollHorizontally(-1)).isFalse()
+ }
+ }
+
+ @Test
+ fun canScroll_returnsTrue_whenHorizontalScrollableNotAtLimit() {
+ // Arrange.
+ rule.setContentWithAccessibilityEnabled {
+ Box(
+ Modifier
+ .size(100.toDp())
+ .semantics(mergeDescendants = true) {
+ testTag = tag
+ horizontalScrollAxisRange = ScrollAxisRange(
+ value = { 0.5f },
+ maxValue = { 1f },
+ reverseScrolling = false
+ )
+ }
+ )
+ }
+
+ // Act.
+ rule.onNodeWithTag(tag).performTouchInput { down(Offset(50f, 50f)) }
+
+ // Assert.
+ rule.runOnIdle {
+ // Should be scrollable in both directions.
+ assertThat(androidComposeView.canScrollHorizontally(1)).isTrue()
+ assertThat(androidComposeView.canScrollHorizontally(0)).isTrue()
+ assertThat(androidComposeView.canScrollHorizontally(-1)).isTrue()
+ }
+ }
+
+ @Test
+ fun canScroll_returnsTrue_whenVerticalScrollableNotAtLimit() {
+ // Arrange.
+ rule.setContentWithAccessibilityEnabled {
+ Box(
+ Modifier
+ .size(100.toDp())
+ .semantics(mergeDescendants = true) {
+ testTag = tag
+ verticalScrollAxisRange = ScrollAxisRange(
+ value = { 0.5f },
+ maxValue = { 1f },
+ reverseScrolling = false
+ )
+ }
+ )
+ }
+
+ // Act.
+ rule.onNodeWithTag(tag).performTouchInput { down(Offset(50f, 50f)) }
+
+ // Assert.
+ rule.runOnIdle {
+ // Should be scrollable in both directions.
+ assertThat(androidComposeView.canScrollVertically(1)).isTrue()
+ assertThat(androidComposeView.canScrollVertically(0)).isTrue()
+ assertThat(androidComposeView.canScrollVertically(-1)).isTrue()
+ }
+ }
+
+ @Test
+ fun canScroll_returnsFalse_whenHorizontalScrollable_whenScrolledRightAndAtLimit() {
+ // Arrange.
+ rule.setContentWithAccessibilityEnabled {
+ Box(
+ Modifier
+ .size(100.toDp())
+ .semantics(mergeDescendants = true) {
+ testTag = tag
+ horizontalScrollAxisRange = ScrollAxisRange(
+ value = { 1f },
+ maxValue = { 1f },
+ reverseScrolling = false
+ )
+ }
+ )
+ }
+
+ // Act.
+ rule.onNodeWithTag(tag).performTouchInput { down(Offset(50f, 50f)) }
+
+ // Assert.
+ rule.runOnIdle {
+ assertThat(androidComposeView.canScrollHorizontally(1)).isFalse()
+ assertThat(androidComposeView.canScrollHorizontally(0)).isFalse()
+ assertThat(androidComposeView.canScrollHorizontally(-1)).isTrue()
+ }
+ }
+
+ @Test
+ fun canScroll_returnsFalse_whenHorizontalScrollable_whenScrolledLeftAndAtLimit() {
+ // Arrange.
+ rule.setContentWithAccessibilityEnabled {
+ Box(
+ Modifier
+ .size(100.toDp())
+ .semantics(mergeDescendants = true) {
+ testTag = tag
+ horizontalScrollAxisRange = ScrollAxisRange(
+ value = { 0f },
+ maxValue = { 1f },
+ reverseScrolling = false
+ )
+ }
+ )
+ }
+
+ // Act.
+ rule.onNodeWithTag(tag).performTouchInput { down(Offset(50f, 50f)) }
+
+ // Assert.
+ rule.runOnIdle {
+ assertThat(androidComposeView.canScrollHorizontally(1)).isTrue()
+ assertThat(androidComposeView.canScrollHorizontally(0)).isTrue()
+ assertThat(androidComposeView.canScrollHorizontally(-1)).isFalse()
+ }
+ }
+
+ @Test
+ fun canScroll_returnsFalse_whenVerticalScrollable_whenScrolledDownAndAtLimit() {
+ // Arrange.
+ rule.setContentWithAccessibilityEnabled {
+ Box(
+ Modifier
+ .size(100.toDp())
+ .semantics(mergeDescendants = true) {
+ testTag = tag
+ verticalScrollAxisRange = ScrollAxisRange(
+ value = { 1f },
+ maxValue = { 1f },
+ reverseScrolling = false
+ )
+ }
+ )
+ }
+
+ // Act.
+ rule.onNodeWithTag(tag).performTouchInput { down(Offset(50f, 50f)) }
+
+ // Assert.
+ rule.runOnIdle {
+ assertThat(androidComposeView.canScrollVertically(1)).isFalse()
+ assertThat(androidComposeView.canScrollVertically(0)).isFalse()
+ assertThat(androidComposeView.canScrollVertically(-1)).isTrue()
+ }
+ }
+
+ @Test
+ fun canScroll_returnsFalse_whenVerticalScrollable_whenScrolledUpAndAtLimit() {
+ // Arrange.
+ rule.setContentWithAccessibilityEnabled {
+ Box(
+ Modifier
+ .size(100.toDp())
+ .semantics(mergeDescendants = true) {
+ testTag = tag
+ verticalScrollAxisRange = ScrollAxisRange(
+ value = { 0f },
+ maxValue = { 1f },
+ reverseScrolling = false
+ )
+ }
+ )
+ }
+
+ // Act.
+ rule.onNodeWithTag(tag).performTouchInput { down(Offset(50f, 50f)) }
+
+ // Assert.
+ rule.runOnIdle {
+ assertThat(androidComposeView.canScrollVertically(1)).isTrue()
+ assertThat(androidComposeView.canScrollVertically(0)).isTrue()
+ assertThat(androidComposeView.canScrollVertically(-1)).isFalse()
+ }
+ }
+
+ @Test
+ fun canScroll_respectsReverseDirection() {
+ // Arrange.
+ rule.setContentWithAccessibilityEnabled {
+ Box(
+ Modifier
+ .size(100.toDp())
+ .semantics(mergeDescendants = true) {
+ testTag = tag
+ horizontalScrollAxisRange = ScrollAxisRange(
+ value = { 0f },
+ maxValue = { 1f },
+ reverseScrolling = true
+ )
+ }
+ )
+ }
+
+ // Act.
+ rule.onNodeWithTag(tag).performTouchInput { down(Offset(50f, 50f)) }
+
+ // Assert.
+ rule.runOnIdle {
+ assertThat(androidComposeView.canScrollHorizontally(1)).isFalse()
+ assertThat(androidComposeView.canScrollHorizontally(0)).isFalse()
+ assertThat(androidComposeView.canScrollHorizontally(-1)).isTrue()
+ }
+ }
+
+ @Test
+ fun canScroll_returnsFalse_forVertical_whenScrollableIsHorizontal() {
+ // Arrange.
+ rule.setContentWithAccessibilityEnabled {
+ Box(
+ Modifier
+ .size(100.toDp())
+ .semantics(mergeDescendants = true) {
+ testTag = tag
+ horizontalScrollAxisRange = ScrollAxisRange(
+ value = { 0.5f },
+ maxValue = { 1f },
+ reverseScrolling = true
+ )
+ }
+ )
+ }
+
+ // Act.
+ rule.onNodeWithTag(tag).performTouchInput { down(Offset(50f, 50f)) }
+
+ // Assert.
+ rule.runOnIdle {
+ assertThat(androidComposeView.canScrollVertically(1)).isFalse()
+ assertThat(androidComposeView.canScrollVertically(0)).isFalse()
+ assertThat(androidComposeView.canScrollVertically(-1)).isFalse()
+ }
+ }
+
+ @Test
+ fun canScroll_returnsFalse_whenTouchIsOutsideBounds() {
+ // Arrange.
+ rule.setContentWithAccessibilityEnabled {
+ Box(
+ Modifier
+ .size(50.toDp())
+ .semantics(mergeDescendants = true) {
+ testTag = tag
+ horizontalScrollAxisRange = ScrollAxisRange(
+ value = { 0.5f },
+ maxValue = { 1f },
+ reverseScrolling = true
+ )
+ }
+ )
+ }
+
+ // Act.
+ rule.onNodeWithTag(tag).performTouchInput { down(Offset(100f, 100f)) }
+
+ // Assert.
+ rule.runOnIdle {
+ assertThat(androidComposeView.canScrollHorizontally(1)).isFalse()
+ assertThat(androidComposeView.canScrollHorizontally(0)).isFalse()
+ assertThat(androidComposeView.canScrollHorizontally(-1)).isFalse()
+ }
+ }
+
+ private fun Int.toDp(): Dp = with(rule.density) { [email protected]() }
+
+ private fun ComposeContentTestRule.setContentWithAccessibilityEnabled(
+ content: @Composable () -> Unit
+ ) {
+ setContent {
+ androidComposeView = LocalView.current as AndroidComposeView
+ with(androidComposeView.composeAccessibilityDelegate) {
+ accessibilityForceEnabledForTesting = true
+ onSendAccessibilityEvent = { dispatchedAccessibilityEvents += it; false }
+ }
+ content()
+ }
+
+ // Advance the clock past the first accessibility event loop, and clear the initial
+ // events as we are want the assertions to check the events that were generated later.
+ runOnIdle { mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs) }
+ runOnIdle { dispatchedAccessibilityEvents.clear() }
+ }
+
+ companion object {
+
+ internal val AccessibilityEventComparator = Correspondence
+ .from<AccessibilityEvent, AccessibilityEvent>(
+ { actual, expected ->
+ actual != null && expected != null &&
+ actual.eventType == expected.eventType &&
+ actual.eventTime == expected.eventTime &&
+ actual.packageName == expected.packageName &&
+ actual.movementGranularity == expected.movementGranularity &&
+ actual.action == expected.action &&
+ actual.contentChangeTypes == expected.contentChangeTypes &&
+ (SDK_INT < P || actual.windowChanges == expected.windowChanges) &&
+ actual.className.contentEquals(expected.className) &&
+ actual.text.toString() == expected.text.toString() &&
+ actual.contentDescription.contentEquals(expected.contentDescription) &&
+ actual.itemCount == expected.itemCount &&
+ actual.currentItemIndex == expected.currentItemIndex &&
+ actual.isEnabled == expected.isEnabled &&
+ actual.isPassword == expected.isPassword &&
+ actual.isChecked == expected.isChecked &&
+ actual.isFullScreen == expected.isFullScreen &&
+ actual.isScrollable == expected.isScrollable &&
+ actual.beforeText.contentEquals(expected.beforeText) &&
+ actual.fromIndex == expected.fromIndex &&
+ actual.toIndex == expected.toIndex &&
+ actual.scrollX == expected.scrollX &&
+ actual.scrollY == expected.scrollY &&
+ actual.maxScrollX == expected.maxScrollX &&
+ actual.maxScrollY == expected.maxScrollY &&
+ (SDK_INT < P || actual.scrollDeltaX == expected.scrollDeltaX) &&
+ (SDK_INT < P || actual.scrollDeltaY == expected.scrollDeltaY) &&
+ actual.addedCount == expected.addedCount &&
+ actual.removedCount == expected.removedCount &&
+ actual.parcelableData == expected.parcelableData &&
+ actual.recordCount == expected.recordCount
+ },
+ "has same properties as"
+ )
+ }
+
+ private val View.composeAccessibilityDelegate: AndroidComposeViewAccessibilityDelegateCompat
+ get() = ViewCompat.getAccessibilityDelegate(this)
+ as AndroidComposeViewAccessibilityDelegateCompat
+
+ // TODO(b/272068594): Add api to fetch the semantics id from SemanticsNodeInteraction directly.
+ private val SemanticsNodeInteraction.semanticsId: Int get() = fetchSemanticsNode().id
+
+ // TODO(b/304359126): Move this to AccessibilityEventCompat and use it wherever we use obtain().
+ private fun AccessibilityEvent(): AccessibilityEvent = if (SDK_INT >= R) {
+ android.view.accessibility.AccessibilityEvent()
+ } else {
+ @Suppress("DEPRECATION")
+ AccessibilityEvent.obtain()
+ }.apply {
+ packageName = "androidx.compose.ui.test"
+ className = "android.view.View"
+ isEnabled = true
+ }
+}
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/accessibility/WindowContentChangeTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/accessibility/WindowContentChangeTest.kt
new file mode 100644
index 0000000..b8f22d5
--- /dev/null
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/accessibility/WindowContentChangeTest.kt
@@ -0,0 +1,366 @@
+
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.ui.accessibility
+
+import android.os.Build.VERSION.SDK_INT
+import android.os.Build.VERSION_CODES.P
+import android.os.Build.VERSION_CODES.R
+import android.view.View
+import android.view.accessibility.AccessibilityEvent
+import android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED
+import android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.AndroidComposeView
+import androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat
+import androidx.compose.ui.platform.LocalView
+import androidx.compose.ui.semantics.CustomAccessibilityAction
+import androidx.compose.ui.semantics.customActions
+import androidx.compose.ui.semantics.disabled
+import androidx.compose.ui.semantics.onClick
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.test.TestActivity
+import androidx.compose.ui.test.junit4.ComposeContentTestRule
+import androidx.compose.ui.test.junit4.createAndroidComposeRule
+import androidx.compose.ui.unit.dp
+import androidx.core.view.ViewCompat
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import com.google.common.truth.Correspondence
+import com.google.common.truth.Truth.assertThat
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class WindowContentChangeTest {
+ @get:Rule
+ val rule = createAndroidComposeRule<TestActivity>()
+
+ private lateinit var androidComposeView: AndroidComposeView
+ private val dispatchedAccessibilityEvents = mutableListOf<AccessibilityEvent>()
+ private val accessibilityEventLoopIntervalMs = 100L
+
+ @Test
+ fun sendWindowContentChangeUndefinedEventByDefault_whenPropertyAdded() {
+ // Arrange.
+ var addProperty by mutableStateOf(false)
+ rule.mainClock.autoAdvance = false
+ rule.setContentWithAccessibilityEnabled {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics(mergeDescendants = false) {
+ if (addProperty) disabled()
+ }
+ )
+ }
+
+ // Act.
+ rule.runOnIdle { addProperty = true }
+ rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
+
+ // Assert.
+ rule.runOnIdle {
+ assertThat(dispatchedAccessibilityEvents)
+ .comparingElementsUsing(AccessibilityEventComparator)
+ .containsExactly(
+ AccessibilityEvent().apply {
+ eventType = TYPE_WINDOW_CONTENT_CHANGED
+ contentChangeTypes = CONTENT_CHANGE_TYPE_UNDEFINED
+ }
+ )
+ }
+ }
+
+ @Test
+ fun sendWindowContentChangeUndefinedEventByDefault_whenPropertyRemoved() {
+ // Arrange.
+ var removeProperty by mutableStateOf(false)
+ rule.mainClock.autoAdvance = false
+ rule.setContentWithAccessibilityEnabled {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics(mergeDescendants = false) {
+ if (!removeProperty) disabled()
+ }
+ )
+ }
+
+ // Act.
+ rule.runOnIdle { removeProperty = true }
+ rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
+
+ // Assert.
+ rule.runOnIdle {
+ assertThat(dispatchedAccessibilityEvents)
+ .comparingElementsUsing(AccessibilityEventComparator)
+ .containsExactly(
+ AccessibilityEvent().apply {
+ eventType = TYPE_WINDOW_CONTENT_CHANGED
+ contentChangeTypes = CONTENT_CHANGE_TYPE_UNDEFINED
+ }
+ )
+ }
+ }
+
+ @Test
+ @Ignore("b/307823561")
+ fun sendWindowContentChangeUndefinedEventByDefault_onlyOnce_whenMultiplePropertiesChange() {
+ // Arrange.
+ var propertiesChanged by mutableStateOf(false)
+ rule.mainClock.autoAdvance = false
+ rule.setContentWithAccessibilityEnabled {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics(mergeDescendants = false) {
+ if (!propertiesChanged) {
+ disabled()
+ } else {
+ onClick { true }
+ }
+ }
+ )
+ }
+
+ // Act.
+ rule.runOnIdle { propertiesChanged = true }
+ rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
+
+ // Assert.
+ rule.runOnIdle {
+ assertThat(dispatchedAccessibilityEvents)
+ .comparingElementsUsing(AccessibilityEventComparator)
+ .containsExactly(
+ AccessibilityEvent().apply {
+ eventType = TYPE_WINDOW_CONTENT_CHANGED
+ contentChangeTypes = CONTENT_CHANGE_TYPE_UNDEFINED
+ }
+ )
+ }
+ }
+
+ @Test
+ fun sendWindowContentChangeUndefinedEventByDefault_standardActionWithTheSameLabel() {
+ // Arrange.
+ var newAction by mutableStateOf(false)
+ rule.mainClock.autoAdvance = false
+ rule.setContentWithAccessibilityEnabled {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics(mergeDescendants = false) {
+ if (!newAction) {
+ onClick(label = "action") { true }
+ } else {
+ onClick(label = "action") { true }
+ }
+ }
+ )
+ }
+
+ // Act.
+ rule.runOnIdle { newAction = true }
+ rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
+
+ // Assert.
+ rule.runOnIdle { assertThat(dispatchedAccessibilityEvents).isEmpty() }
+ }
+
+ @Test
+ fun sendWindowContentChangeUndefinedEventByDefault_standardActionWithDifferentLabels() {
+ // Arrange.
+ var newAction by mutableStateOf(false)
+ rule.mainClock.autoAdvance = false
+ rule.setContentWithAccessibilityEnabled {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics(mergeDescendants = false) {
+ if (!newAction) {
+ onClick(label = "action1") { true }
+ } else {
+ onClick(label = "action2") { true }
+ }
+ }
+ )
+ }
+
+ // Act.
+ rule.runOnIdle { newAction = true }
+ rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
+
+ // Assert.
+ rule.runOnIdle {
+ assertThat(dispatchedAccessibilityEvents)
+ .comparingElementsUsing(AccessibilityEventComparator)
+ .containsExactly(
+ AccessibilityEvent().apply {
+ eventType = TYPE_WINDOW_CONTENT_CHANGED
+ contentChangeTypes = CONTENT_CHANGE_TYPE_UNDEFINED
+ }
+ )
+ }
+ }
+
+ @Test
+ fun sendWindowContentChangeUndefinedEventByDefault_customActionWithTheSameLabel() {
+ // Arrange.
+ var newAction by mutableStateOf(false)
+ rule.mainClock.autoAdvance = false
+ rule.setContentWithAccessibilityEnabled {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics(mergeDescendants = false) {
+ customActions = if (!newAction) {
+ listOf(CustomAccessibilityAction("action") { true })
+ } else {
+ listOf(CustomAccessibilityAction("action") { false })
+ }
+ }
+ )
+ }
+
+ // Act.
+ rule.runOnIdle { newAction = true }
+ rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
+
+ // Assert.
+ rule.runOnIdle { assertThat(dispatchedAccessibilityEvents).isEmpty() }
+ }
+
+ @Test
+ fun sendWindowContentChangeUndefinedEventByDefault_customActionWithDifferentLabels() {
+ // Arrange.
+ var newAction by mutableStateOf(false)
+ rule.mainClock.autoAdvance = false
+ rule.setContentWithAccessibilityEnabled {
+ Box(
+ Modifier
+ .size(10.dp)
+ .semantics(mergeDescendants = false) {
+ customActions = if (!newAction) {
+ listOf(CustomAccessibilityAction("action1") { true })
+ } else {
+ listOf(CustomAccessibilityAction("action2") { true })
+ }
+ }
+ )
+ }
+
+ // Act.
+ rule.runOnIdle { newAction = true }
+ rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
+
+ // Assert.
+ rule.runOnIdle {
+ assertThat(dispatchedAccessibilityEvents)
+ .comparingElementsUsing(AccessibilityEventComparator)
+ .containsExactly(
+ AccessibilityEvent().apply {
+ eventType = TYPE_WINDOW_CONTENT_CHANGED
+ contentChangeTypes = CONTENT_CHANGE_TYPE_UNDEFINED
+ }
+ )
+ }
+ }
+
+ private fun ComposeContentTestRule.setContentWithAccessibilityEnabled(
+ content: @Composable () -> Unit
+ ) {
+ setContent {
+ androidComposeView = LocalView.current as AndroidComposeView
+ with(androidComposeView.composeAccessibilityDelegate) {
+ accessibilityForceEnabledForTesting = true
+ onSendAccessibilityEvent = { dispatchedAccessibilityEvents += it; false }
+ }
+ content()
+ }
+
+ // Advance the clock past the first accessibility event loop, and clear the initial
+ // events as we are want the assertions to check the events that were generated later.
+ runOnIdle { mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs) }
+ runOnIdle { dispatchedAccessibilityEvents.clear() }
+ }
+
+ companion object {
+ internal val AccessibilityEventComparator = Correspondence
+ .from<AccessibilityEvent, AccessibilityEvent>(
+ { actual, expected ->
+ actual != null && expected != null &&
+ actual.eventType == expected.eventType &&
+ actual.eventTime == expected.eventTime &&
+ actual.packageName == expected.packageName &&
+ actual.movementGranularity == expected.movementGranularity &&
+ actual.action == expected.action &&
+ actual.contentChangeTypes == expected.contentChangeTypes &&
+ (SDK_INT < P || actual.windowChanges == expected.windowChanges) &&
+ actual.className.contentEquals(expected.className) &&
+ actual.text.toString() == expected.text.toString() &&
+ actual.contentDescription.contentEquals(expected.contentDescription) &&
+ actual.itemCount == expected.itemCount &&
+ actual.currentItemIndex == expected.currentItemIndex &&
+ actual.isEnabled == expected.isEnabled &&
+ actual.isPassword == expected.isPassword &&
+ actual.isChecked == expected.isChecked &&
+ actual.isFullScreen == expected.isFullScreen &&
+ actual.isScrollable == expected.isScrollable &&
+ actual.beforeText.contentEquals(expected.beforeText) &&
+ actual.fromIndex == expected.fromIndex &&
+ actual.toIndex == expected.toIndex &&
+ actual.scrollX == expected.scrollX &&
+ actual.scrollY == expected.scrollY &&
+ actual.maxScrollX == expected.maxScrollX &&
+ actual.maxScrollY == expected.maxScrollY &&
+ (SDK_INT < P || actual.scrollDeltaX == expected.scrollDeltaX) &&
+ (SDK_INT < P || actual.scrollDeltaY == expected.scrollDeltaY) &&
+ actual.addedCount == expected.addedCount &&
+ actual.removedCount == expected.removedCount &&
+ actual.parcelableData == expected.parcelableData &&
+ actual.recordCount == expected.recordCount
+ },
+ "has same properties as"
+ )
+ }
+
+ private val View.composeAccessibilityDelegate: AndroidComposeViewAccessibilityDelegateCompat
+ get() = ViewCompat.getAccessibilityDelegate(this)
+ as AndroidComposeViewAccessibilityDelegateCompat
+
+ // TODO(b/304359126): Move this to AccessibilityEventCompat and use it wherever we use obtain().
+ private fun AccessibilityEvent(): AccessibilityEvent = if (SDK_INT >= R) {
+ android.view.accessibility.AccessibilityEvent()
+ } else {
+ @Suppress("DEPRECATION")
+ AccessibilityEvent.obtain()
+ }.apply {
+ packageName = "androidx.compose.ui.test"
+ className = "android.view.View"
+ isEnabled = true
+ }
+}
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/ClearFocusExitTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/ClearFocusExitTest.kt
index ae6436a..331bb2a 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/ClearFocusExitTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/ClearFocusExitTest.kt
@@ -37,13 +37,13 @@
@get:Rule
val rule = createComposeRule()
- val focusRequester = FocusRequester()
- var clearTriggered = false
- lateinit var focusState: FocusState
- lateinit var focusManager: FocusManager
+ private val focusRequester = FocusRequester()
+ private var clearTriggered = false
+ private lateinit var focusState: FocusState
+ private lateinit var focusManager: FocusManager
@Test
- fun clearFocus_doesNotTriggersExit() {
+ fun clearFocus_doesNotTriggerExit() {
// Arrange.
rule.setFocusableContent {
focusManager = LocalFocusManager.current
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/FocusManagerCompositionLocalTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/FocusManagerCompositionLocalTest.kt
index 48f89f2..2799818 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/FocusManagerCompositionLocalTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/FocusManagerCompositionLocalTest.kt
@@ -18,17 +18,22 @@
import android.view.View
import androidx.compose.foundation.layout.Box
+import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusStateImpl.Active
import androidx.compose.ui.focus.FocusStateImpl.ActiveParent
import androidx.compose.ui.focus.FocusStateImpl.Inactive
+import androidx.compose.ui.input.InputMode.Companion.Keyboard
+import androidx.compose.ui.input.InputMode.Companion.Touch
+import androidx.compose.ui.input.InputModeManager
import androidx.compose.ui.platform.LocalFocusManager
+import androidx.compose.ui.platform.LocalInputModeManager
import androidx.compose.ui.platform.LocalView
+import androidx.compose.ui.test.junit4.ComposeContentTestRule
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import com.google.common.truth.Truth.assertThat
-import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -39,24 +44,25 @@
@get:Rule
val rule = createComposeRule()
+ private lateinit var focusManager: FocusManager
+ private lateinit var inputModeManager: InputModeManager
+ private val focusStates = mutableListOf<FocusState>()
+
@Test
- fun clearFocus_singleLayout() {
+ fun clearFocus_singleLayout_focusIsRestoredAfterClear() {
// Arrange.
- lateinit var focusManager: FocusManager
- lateinit var focusState: FocusState
val focusRequester = FocusRequester()
- rule.setFocusableContent {
- focusManager = LocalFocusManager.current
+ rule.setTestContent(extraItemForInitialFocus = false) {
Box(
modifier = Modifier
.focusRequester(focusRequester)
- .onFocusChanged { focusState = it }
+ .onFocusChanged { focusStates += it }
.focusTarget()
)
}
rule.runOnIdle {
focusRequester.requestFocus()
- assertThat(focusState.isFocused).isTrue()
+ focusStates.clear()
}
// Act.
@@ -64,8 +70,16 @@
// Assert.
rule.runOnIdle {
- assertThat(focusManager.rootFocusState.isFocused).isTrue()
- assertThat(focusState.isFocused).isFalse()
+ when (inputModeManager.inputMode) {
+ Keyboard -> {
+ assertThat(focusStates).containsExactly(Inactive, Active).inOrder()
+ assertThat(focusManager.rootFocusState.hasFocus).isTrue()
+ }
+ Touch -> {
+ assertThat(focusStates).containsExactly(Inactive).inOrder()
+ assertThat(focusManager.rootFocusState.hasFocus).isFalse()
+ }
+ }
}
}
@@ -77,7 +91,7 @@
lateinit var parentFocusState: FocusState
lateinit var grandparentFocusState: FocusState
val focusRequester = FocusRequester()
- rule.setFocusableContent {
+ rule.setTestContent {
focusManager = LocalFocusManager.current
Box(
modifier = Modifier
@@ -119,96 +133,38 @@
@Test
fun takeFocus_whenRootIsInactive() {
// Arrange.
- lateinit var focusManager: FocusManager
- lateinit var focusState: FocusState
lateinit var view: View
- rule.setFocusableContent {
- focusManager = LocalFocusManager.current
+ rule.setTestContent(extraItemForInitialFocus = false) {
view = LocalView.current
Box(
modifier = Modifier
- .onFocusChanged { focusState = it }
+ .onFocusChanged { focusStates += it }
.focusTarget()
)
}
// Act.
- rule.runOnIdle { view.requestFocus() }
-
- // Assert.
rule.runOnIdle {
- assertThat(focusManager.rootFocusState).isEqualTo(Active)
- assertThat(focusState.isFocused).isFalse()
+ focusStates.clear()
+ view.requestFocus()
}
- }
-
- fun takeFocus_whenRootIsActive() {
- // Arrange.
- lateinit var focusManager: FocusManager
- lateinit var focusState: FocusState
- lateinit var view: View
- rule.setFocusableContent {
- focusManager = LocalFocusManager.current
- view = LocalView.current
- Box(
- modifier = Modifier
- .onFocusChanged { focusState = it }
- .focusTarget()
- )
- }
- rule.runOnIdle { focusManager.setRootFocusState(Active) }
-
- // Act.
- rule.runOnIdle { view.requestFocus() }
-
- // Assert.
- rule.runOnIdle {
- assertThat(focusManager.rootFocusState).isEqualTo(Active)
- assertThat(focusState.isFocused).isFalse()
- }
- }
-
- @Test
- fun takeFocus_whenRootIsActiveParent() {
- // Arrange.
- lateinit var focusManager: FocusManager
- lateinit var focusState: FocusState
- lateinit var view: View
- val focusRequester = FocusRequester()
- rule.setFocusableContent {
- focusManager = LocalFocusManager.current
- view = LocalView.current
- Box(
- modifier = Modifier
- .focusRequester(focusRequester)
- .onFocusChanged { focusState = it }
- .focusTarget()
- )
- }
- rule.runOnIdle { focusRequester.requestFocus() }
-
- // Act.
- rule.runOnIdle { view.requestFocus() }
// Assert.
rule.runOnIdle {
assertThat(focusManager.rootFocusState).isEqualTo(ActiveParent)
- assertThat(focusState.isFocused).isTrue()
+ assertThat(focusStates).containsExactly(Active)
}
}
@Test
fun releaseFocus_whenRootIsInactive() {
// Arrange.
- lateinit var focusManager: FocusManager
- lateinit var focusState: FocusState
lateinit var view: View
- rule.setFocusableContent {
- focusManager = LocalFocusManager.current
+ rule.setTestContent(extraItemForInitialFocus = false) {
view = LocalView.current
Box(
modifier = Modifier
- .onFocusChanged { focusState = it }
+ .onFocusChanged { focusStates += it }
.focusTarget()
)
}
@@ -219,55 +175,28 @@
// Assert.
rule.runOnIdle {
assertThat(focusManager.rootFocusState).isEqualTo(Inactive)
- assertThat(focusState.isFocused).isFalse()
+ assertThat(focusStates).containsExactly(Inactive)
}
}
- fun releaseFocus_whenRootIsActive() {
- // Arrange.
- lateinit var focusManager: FocusManager
- lateinit var focusState: FocusState
- lateinit var view: View
- rule.setFocusableContent {
- focusManager = LocalFocusManager.current
- view = LocalView.current
- Box(
- modifier = Modifier
- .onFocusChanged { focusState = it }
- .focusTarget()
- )
- }
- rule.runOnIdle { focusManager.setRootFocusState(Active) }
-
- // Act.
- rule.runOnIdle { view.clearFocus() }
-
- // Assert.
- rule.runOnIdle {
- assertThat(focusManager.rootFocusState).isEqualTo(Inactive)
- assertThat(focusState.isFocused).isFalse()
- }
- }
-
- @Ignore("b/257499180")
@Test
- fun releaseFocus_whenRootIsActiveParent() {
+ fun releaseFocus_whenOwnerFocusIsCleared() {
// Arrange.
- lateinit var focusManager: FocusManager
- lateinit var focusState: FocusState
lateinit var view: View
val focusRequester = FocusRequester()
- rule.setFocusableContent {
- focusManager = LocalFocusManager.current
+ rule.setTestContent(extraItemForInitialFocus = false) {
view = LocalView.current
Box(
modifier = Modifier
.focusRequester(focusRequester)
- .onFocusChanged { focusState = it }
+ .onFocusChanged { focusStates += it }
.focusTarget()
)
}
- rule.runOnIdle { focusRequester.requestFocus() }
+ rule.runOnIdle {
+ focusRequester.requestFocus()
+ focusStates.clear()
+ }
// Act.
rule.runOnIdle {
@@ -276,111 +205,107 @@
// Assert.
rule.runOnIdle {
- assertThat(focusManager.rootFocusState).isEqualTo(Inactive)
- assertThat(focusState.isFocused).isFalse()
+ when (inputModeManager.inputMode) {
+ Keyboard -> {
+ // Focus is re-assigned to the initially focused item (default focus).
+ assertThat(focusManager.rootFocusState).isEqualTo(ActiveParent)
+ assertThat(focusStates).containsExactly(Inactive, Active).inOrder()
+ }
+ Touch -> {
+ assertThat(focusManager.rootFocusState).isEqualTo(Inactive)
+ assertThat(focusStates).containsExactly(Inactive)
+ }
+ else -> error("Invalid input mode")
+ }
}
}
@Test
fun clearFocus_whenRootIsInactive() {
// Arrange.
- lateinit var focusManager: FocusManager
- lateinit var focusState: FocusState
val focusRequester = FocusRequester()
- rule.setFocusableContent {
- focusManager = LocalFocusManager.current
+ rule.setTestContent {
Box(
modifier = Modifier
.focusRequester(focusRequester)
- .onFocusChanged { focusState = it }
+ .onFocusChanged { focusStates += it }
.focusTarget()
)
}
+ rule.runOnIdle { focusStates.clear() }
// Act.
rule.runOnIdle { focusManager.clearFocus() }
// Assert.
rule.runOnIdle {
- assertThat(focusManager.rootFocusState).isEqualTo(Inactive)
- assertThat(focusState.isFocused).isFalse()
- }
- }
-
- @Ignore("b/257499180")
- @Test
- fun clearFocus_whenRootIsActive() {
- // Arrange.
- lateinit var focusManager: FocusManager
- lateinit var focusState: FocusState
- val focusRequester = FocusRequester()
- rule.setFocusableContent {
- focusManager = LocalFocusManager.current
- Box(
- modifier = Modifier
- .focusRequester(focusRequester)
- .onFocusChanged { focusState = it }
- .focusTarget()
- )
- }
- rule.runOnIdle { focusManager.setRootFocusState(Active) }
-
- // Act.
- rule.runOnIdle { focusManager.clearFocus() }
-
- // Assert.
- rule.runOnIdle {
- assertThat(focusManager.rootFocusState).isEqualTo(Inactive)
- assertThat(focusState.isFocused).isFalse()
+ when (inputModeManager.inputMode) {
+ Keyboard -> {
+ assertThat(focusManager.rootFocusState).isEqualTo(Inactive)
+ assertThat(focusStates).isEmpty()
+ }
+ Touch -> {
+ assertThat(focusManager.rootFocusState).isEqualTo(Inactive)
+ assertThat(focusStates).isEmpty()
+ }
+ else -> error("Invalid input mode")
+ }
}
}
@Test
fun clearFocus_whenRootIsActiveParent() {
// Arrange.
- lateinit var focusManager: FocusManager
- lateinit var focusState: FocusState
val focusRequester = FocusRequester()
- rule.setFocusableContent {
- focusManager = LocalFocusManager.current
+ rule.setTestContent(extraItemForInitialFocus = false) {
Box(
modifier = Modifier
.focusRequester(focusRequester)
- .onFocusChanged { focusState = it }
+ .onFocusChanged { focusStates += it }
.focusTarget()
)
}
- rule.runOnIdle { focusRequester.requestFocus() }
+ rule.runOnIdle {
+ focusRequester.requestFocus()
+ focusStates.clear()
+ }
// Act.
rule.runOnIdle { focusManager.clearFocus() }
// Assert.
rule.runOnIdle {
- // TODO(b/257499180): Compose should not hold focus state when clear focus is requested.
- assertThat(focusManager.rootFocusState).isEqualTo(Active)
- assertThat(focusState.isFocused).isFalse()
+ when (inputModeManager.inputMode) {
+ Keyboard -> {
+ assertThat(focusManager.rootFocusState).isEqualTo(ActiveParent)
+ assertThat(focusStates).containsExactly(Inactive, Active).inOrder()
+ }
+ Touch -> {
+ assertThat(focusManager.rootFocusState).isEqualTo(Inactive)
+ assertThat(focusStates).containsExactly(Inactive)
+ }
+ else -> error("Invalid input mode")
+ }
}
}
@Test
fun clearFocus_whenHierarchyHasCapturedFocus() {
// Arrange.
- lateinit var focusManager: FocusManager
- lateinit var focusState: FocusState
val focusRequester = FocusRequester()
- rule.setFocusableContent {
+ rule.setTestContent {
focusManager = LocalFocusManager.current
Box(
modifier = Modifier
.focusRequester(focusRequester)
- .onFocusChanged { focusState = it }
+ .onFocusChanged { focusStates += it }
.focusTarget()
)
}
rule.runOnIdle {
focusRequester.requestFocus()
focusRequester.captureFocus()
+ focusStates.clear()
}
// Act.
@@ -389,28 +314,27 @@
// Assert.
rule.runOnIdle {
assertThat(focusManager.rootFocusState).isEqualTo(ActiveParent)
- assertThat(focusState.isFocused).isTrue()
+ assertThat(focusStates).isEmpty()
}
}
@Test
fun clearFocus_forced_whenHierarchyHasCapturedFocus() {
// Arrange.
- lateinit var focusManager: FocusManager
- lateinit var focusState: FocusState
val focusRequester = FocusRequester()
- rule.setFocusableContent {
- focusManager = LocalFocusManager.current
+ rule.setTestContent(extraItemForInitialFocus = false) {
+
Box(
modifier = Modifier
.focusRequester(focusRequester)
- .onFocusChanged { focusState = it }
+ .onFocusChanged { focusStates += it }
.focusTarget()
)
}
rule.runOnIdle {
focusRequester.requestFocus()
focusRequester.captureFocus()
+ focusStates.clear()
}
// Act.
@@ -418,16 +342,32 @@
// Assert.
rule.runOnIdle {
- // TODO(b/257499180): Compose should clear focus and send focus to the root view.
- assertThat(focusManager.rootFocusState).isEqualTo(Active)
- assertThat(focusState.isFocused).isFalse()
+ when (inputModeManager.inputMode) {
+ Keyboard -> {
+ // Focus is re-assigned to the initially focused item (default focus).
+ assertThat(focusManager.rootFocusState).isEqualTo(ActiveParent)
+ assertThat(focusStates).containsExactly(Inactive, Active).inOrder()
+ }
+ Touch -> {
+ assertThat(focusManager.rootFocusState).isEqualTo(Inactive)
+ assertThat(focusStates).containsExactly(Inactive).inOrder()
+ }
+ else -> error("Invalid input mode")
+ }
}
}
private val FocusManager.rootFocusState: FocusState
get() = (this as FocusOwnerImpl).rootFocusNode.focusState
- private fun FocusManager.setRootFocusState(focusState: FocusStateImpl) {
- (this as FocusOwnerImpl).rootFocusNode.focusState = focusState
+ private fun ComposeContentTestRule.setTestContent(
+ extraItemForInitialFocus: Boolean = true,
+ content: @Composable () -> Unit
+ ) {
+ setFocusableContent(extraItemForInitialFocus) {
+ focusManager = LocalFocusManager.current
+ inputModeManager = LocalInputModeManager.current
+ content()
+ }
}
}
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/FocusTestUtils.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/FocusTestUtils.kt
index 20fdc7a..f8be78e2 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/FocusTestUtils.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/FocusTestUtils.kt
@@ -17,6 +17,7 @@
package androidx.compose.ui.focus
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.runtime.Composable
@@ -34,10 +35,25 @@
* This function adds a parent composable which has size.
* [View.requestFocus()][android.view.View.requestFocus] will not take focus if the view has no
* size.
+ *
+ * @param extraItemForInitialFocus Includes an extra item that takes focus initially. This is
+ * useful in cases where we need tests that could be affected by initial focus. Eg. When there is
+ * only one focusable item and we clear focus, that item could end up being focused on again by the
+ * initial focus logic.
*/
-internal fun ComposeContentTestRule.setFocusableContent(content: @Composable () -> Unit) {
+internal fun ComposeContentTestRule.setFocusableContent(
+ extraItemForInitialFocus: Boolean = true,
+ content: @Composable () -> Unit
+) {
setContent {
- Box(modifier = Modifier.requiredSize(100.dp, 100.dp)) { content() }
+ if (extraItemForInitialFocus) {
+ Row {
+ Box(modifier = Modifier.requiredSize(10.dp, 10.dp).focusTarget())
+ Box(modifier = Modifier.requiredSize(100.dp, 100.dp)) { content() }
+ }
+ } else {
+ Box(modifier = Modifier.requiredSize(100.dp, 100.dp)) { content() }
+ }
}
}
@@ -66,9 +82,9 @@
.focusProperties { canFocus = !deactivated }
.focusTarget(),
measurePolicy = remember(width, height) {
- MeasurePolicy { measurables, constraint ->
+ MeasurePolicy { measurableList, constraint ->
layout(width, height) {
- measurables.forEach {
+ measurableList.forEach {
val placeable = it.measure(constraint)
placeable.placeRelative(0, 0)
}
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/FocusTransactionsTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/FocusTransactionsTest.kt
index b7caf2c..cdb0b7d 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/FocusTransactionsTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/FocusTransactionsTest.kt
@@ -23,9 +23,14 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester.Companion.Cancel
import androidx.compose.ui.focus.FocusStateImpl.Active
+import androidx.compose.ui.focus.FocusStateImpl.ActiveParent
import androidx.compose.ui.focus.FocusStateImpl.Inactive
+import androidx.compose.ui.input.InputMode.Companion.Keyboard
+import androidx.compose.ui.input.InputMode.Companion.Touch
+import androidx.compose.ui.input.InputModeManager
import androidx.compose.ui.platform.AndroidComposeView
import androidx.compose.ui.platform.LocalFocusManager
+import androidx.compose.ui.platform.LocalInputModeManager
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.unit.dp
@@ -91,33 +96,57 @@
fun cancelTakeFocus_fromOnFocusChanged() {
// Arrange.
lateinit var focusManager: FocusManager
+ lateinit var inputModeManager: InputModeManager
lateinit var view: View
+ lateinit var focusState1: FocusState
+ lateinit var focusState2: FocusState
+ lateinit var focusState3: FocusState
val box = FocusRequester()
rule.setFocusableContent {
focusManager = LocalFocusManager.current
+ inputModeManager = LocalInputModeManager.current
view = LocalView.current
Box(
Modifier
.size(10.dp)
.focusRequester(box)
- .onFocusChanged { if (it.isFocused) focusManager.clearFocus() }
+ .onFocusChanged { focusState1 = it }
+ .onFocusChanged {
+ focusState2 = it
+ if (it.isFocused) focusManager.clearFocus()
+ }
+ .onFocusChanged { focusState3 = it }
.focusTarget()
)
}
// Act.
- rule.runOnIdle {
+ rule.runOnUiThread {
box.requestFocus()
}
// Assert.
rule.runOnIdle {
+ assertThat(focusState1).isEqualTo(Inactive)
+ // TODO(b/312524818): When a focus transaction is cancelled, we should re-notify
+ // all the focus event modifiers that were called in the previous transaction.
+ assertThat(focusState2).isEqualTo(Active) // Should be Inactive.
+ assertThat(focusState3).isEqualTo(Active) // Should be Inactive.
+
val root = view as AndroidComposeView
- val focusOwner = root.focusOwner as FocusOwnerImpl
- assertThat(focusOwner.rootFocusNode.focusState).isEqualTo(Inactive)
- // TODO(b/288096244): Find out why this is flaky.
- // assertThat(view.isFocused()).isFalse()
+
+ when (inputModeManager.inputMode) {
+ Keyboard -> {
+ assertThat(root.focusOwner.rootState).isEqualTo(ActiveParent)
+ assertThat(view.isFocused).isTrue()
+ }
+ Touch -> {
+ assertThat(root.focusOwner.rootState).isEqualTo(Inactive)
+ assertThat(view.isFocused).isFalse()
+ }
+ else -> error("invalid input mode")
+ }
}
}
@@ -152,14 +181,13 @@
// Assert.
rule.runOnIdle {
val root = view as AndroidComposeView
- val focusOwner = root.focusOwner as FocusOwnerImpl
- assertThat(focusOwner.rootFocusNode.focusState).isEqualTo(Inactive)
+ assertThat(root.focusOwner.rootState).isEqualTo(Inactive)
assertThat(view.isFocused).isFalse()
}
}
@Test
- fun rootFocusNodeIsActiveWhenViewIsFocused() {
+ fun rootFocusNodeHasFocusWhenViewIsFocused() {
lateinit var view: View
val focusRequester = FocusRequester()
rule.setFocusableContent {
@@ -174,9 +202,8 @@
// Assert.
val root = view as AndroidComposeView
- val focusOwner = root.focusOwner as FocusOwnerImpl
rule.runOnIdle {
- assertThat(focusOwner.rootFocusNode.focusState).isEqualTo(Active)
+ assertThat(root.focusOwner.rootState).isEqualTo(ActiveParent)
assertThat(view.isFocused).isTrue()
}
@@ -190,7 +217,7 @@
// Assert.
rule.runOnIdle {
- assertThat(focusOwner.rootFocusNode.focusState).isEqualTo(Active)
+ assertThat(root.focusOwner.rootState.hasFocus).isEqualTo(true)
assertThat(view.isFocused).isTrue()
}
}
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/FocusViewInteropTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/FocusViewInteropTest.kt
index b2c2ef2..125adfd 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/FocusViewInteropTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/FocusViewInteropTest.kt
@@ -18,6 +18,7 @@
import android.graphics.Rect as AndroidRect
import android.view.View
+import androidx.compose.foundation.focusGroup
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.offset
@@ -25,6 +26,7 @@
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
+import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalView
@@ -101,6 +103,36 @@
)
}
+ @Test
+ fun requestFocus_returnsFalseWhenCancelled() {
+ // Arrange.
+ lateinit var view: View
+ rule.setContent {
+ view = LocalView.current
+ Box(
+ Modifier
+ .size(10.dp)
+ .focusProperties {
+ @OptIn(ExperimentalComposeUiApi::class)
+ enter = { FocusRequester.Cancel }
+ }
+ .focusGroup()
+ ) {
+ Box(
+ Modifier
+ .size(10.dp)
+ .focusable()
+ )
+ }
+ }
+
+ // Act.
+ val success = rule.runOnIdle { view.requestFocus() }
+
+ // Assert.
+ rule.runOnIdle { assertThat(success).isFalse() }
+ }
+
private fun View.getFocusedRect() = AndroidRect().run {
rule.runOnIdle {
getFocusedRect(this)
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearchNextTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearchNextTest.kt
index a622899..78c6445 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearchNextTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearchNextTest.kt
@@ -44,7 +44,7 @@
@Test
fun moveFocus_noFocusableItem() {
// Arrange.
- rule.setContentWithInitialRootFocus {}
+ rule.setContentForTest {}
// Act.
val movedFocusSuccessfully = rule.runOnIdle { focusManager.moveFocus(Next) }
@@ -57,7 +57,7 @@
fun moveFocus_oneDisabledFocusableItem() {
// Arrange.
val isItemFocused = mutableStateOf(false)
- rule.setContentWithInitialRootFocus {
+ rule.setContentForTest {
FocusableBox(isItemFocused, 0, 0, 10, 10, deactivated = true)
}
@@ -72,7 +72,7 @@
fun initialFocus_oneItem() {
// Arrange.
val isItemFocused = mutableStateOf(false)
- rule.setContentWithInitialRootFocus {
+ rule.setContentForTest {
FocusableBox(isItemFocused, 0, 0, 10, 10)
}
@@ -90,7 +90,7 @@
fun initialFocus_skipsDeactivatedItem() {
// Arrange.
val (firstItem, secondItem) = List(2) { mutableStateOf(false) }
- rule.setContentWithInitialRootFocus {
+ rule.setContentForTest {
Column {
FocusableBox(firstItem, 0, 0, 10, 10, deactivated = true)
FocusableBox(secondItem, 0, 0, 10, 10)
@@ -112,7 +112,7 @@
fun initialFocus_firstItemInCompositionOrderGetsFocus() {
// Arrange.
val (firstItem, secondItem) = List(2) { mutableStateOf(false) }
- rule.setContentWithInitialRootFocus {
+ rule.setContentForTest {
FocusableBox(firstItem, 10, 10, 10, 10)
FocusableBox(secondItem, 0, 0, 10, 10)
}
@@ -131,7 +131,7 @@
fun initialFocus_firstParentInCompositionOrderGetsFocus() {
// Arrange.
val (parent1, parent2, child1, child2) = List(4) { mutableStateOf(false) }
- rule.setContentWithInitialRootFocus {
+ rule.setContentForTest {
FocusableBox(parent1, 10, 10, 10, 10) {
FocusableBox(child1, 10, 10, 10, 10)
}
@@ -154,7 +154,7 @@
fun initialFocus_firstItemInCompositionOrderGetsFocus_evenIfAnotherNonParentIsPresent() {
// Arrange.
val (parent1, child1, item2) = List(3) { mutableStateOf(false) }
- rule.setContentWithInitialRootFocus {
+ rule.setContentForTest {
FocusableBox(parent1, 10, 10, 10, 10) {
FocusableBox(child1, 10, 10, 10, 10)
}
@@ -175,7 +175,7 @@
fun initialFocus_firstItemInCompositionOrderGetsFocus_evenIfThereIsAParentAtTheRoot() {
// Arrange.
val (parent1, child1, item1) = List(3) { mutableStateOf(false) }
- rule.setContentWithInitialRootFocus {
+ rule.setContentForTest {
FocusableBox(item1, 0, 0, 10, 10)
FocusableBox(parent1, 10, 10, 10, 10) {
FocusableBox(child1, 10, 10, 10, 10)
@@ -196,7 +196,7 @@
fun focusMovesToSecondItem() {
// Arrange.
val (item1, item2, item3) = List(3) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
FocusableBox(item1, 0, 0, 10, 10, initialFocus)
FocusableBox(item2, 10, 0, 10, 10)
FocusableBox(item3, 20, 0, 10, 10)
@@ -216,7 +216,7 @@
fun focusMovesToThirdItem_skipsDeactivatedItem() {
// Arrange.
val (item1, item2, item3, item4) = List(4) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
FocusableBox(item1, 0, 0, 10, 10, initialFocus)
FocusableBox(item2, 10, 0, 10, 10, deactivated = true)
FocusableBox(item3, 10, 0, 10, 10)
@@ -237,7 +237,7 @@
fun focusMovesToThirdItem() {
// Arrange.
val (item1, item2, item3) = List(3) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
FocusableBox(item1, 0, 0, 10, 10)
FocusableBox(item2, 10, 0, 10, 10, initialFocus)
FocusableBox(item3, 20, 0, 10, 10)
@@ -257,7 +257,7 @@
fun focusMovesToFourthItem() {
// Arrange.
val (item1, item2, item3, item4) = List(4) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
FocusableBox(item1, 0, 0, 10, 10)
FocusableBox(item2, 0, 0, 10, 10, deactivated = true)
FocusableBox(item3, 10, 0, 10, 10, initialFocus)
@@ -278,7 +278,7 @@
fun focusWrapsAroundToFirstItem() {
// Arrange.
val (item1, item2, item3) = List(3) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
FocusableBox(item1, 0, 0, 10, 10)
FocusableBox(item2, 10, 0, 10, 10)
FocusableBox(item3, 20, 0, 10, 10, initialFocus)
@@ -298,7 +298,7 @@
fun focusWrapsAroundToFirstItem_skippingLastDeactivatedItem() {
// Arrange.
val (item1, item2, item3, item4) = List(4) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
FocusableBox(item1, 0, 0, 10, 10)
FocusableBox(item2, 10, 0, 10, 10)
FocusableBox(item3, 20, 0, 10, 10, initialFocus)
@@ -319,7 +319,7 @@
fun focusWrapsAroundToFirstItem_skippingFirstDeactivatedItem() {
// Arrange.
val (item1, item2, item3, item4) = List(4) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
FocusableBox(item1, 10, 0, 10, 10, deactivated = true)
FocusableBox(item2, 0, 0, 10, 10)
FocusableBox(item3, 10, 0, 10, 10)
@@ -340,7 +340,7 @@
fun focusMovesToChildOfDeactivatedItem() {
// Arrange.
val (item1, item2, item3, child) = List(4) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
FocusableBox(item1, 0, 0, 10, 10, initialFocus)
FocusableBox(item2, 10, 0, 10, 10, deactivated = true) {
FocusableBox(child, 10, 0, 10, 10)
@@ -362,7 +362,7 @@
fun focusMovesToGrandChildOfDeactivatedItem() {
// Arrange.
val (item1, item2, item3, child, grandchild) = List(5) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
FocusableBox(item1, 0, 0, 10, 10, initialFocus)
FocusableBox(item2, 10, 0, 10, 10, deactivated = true) {
FocusableBox(child, 10, 0, 10, 10, deactivated = true) {
@@ -386,7 +386,7 @@
fun focusMovesToNextSiblingOfDeactivatedItem_evenThoughThereIsACloserNonSibling() {
// Arrange.
val (item1, item2, item3, child1, child2) = List(5) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
FocusableBox(item1, 0, 0, 10, 10)
FocusableBox(item2, 10, 0, 10, 10, deactivated = true) {
FocusableBox(child1, 10, 0, 10, 10, initialFocus)
@@ -409,7 +409,7 @@
fun focusNextOrderAmongChildrenOfMultipleParents() {
// Arrange.
val focusState = List(12) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
Column {
Row {
FocusableBox(focusState[0], 0, 0, 10, 10, initialFocus)
@@ -446,7 +446,7 @@
fun focusNextOrderAmongChildrenAtMultipleLevels() {
// Arrange.
val focusState = List(14) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
Column {
FocusableBox(focusState[0], 0, 0, 10, 10, initialFocus)
FocusableBox(focusState[1], 0, 10, 10, 10)
@@ -488,7 +488,7 @@
val (parent3, child6) = List(2) { mutableStateOf(false) }
val (parent4, child7, child8, child9, child10) = List(5) { mutableStateOf(false) }
val (parent5, child11) = List(2) { mutableStateOf(false) }
- rule.setContentWithInitialRootFocus {
+ rule.setContentForTest {
FocusableBox(parent1, 0, 0, 10, 10) {
FocusableBox(child1, 0, 0, 10, 10)
FocusableBox(child2, 20, 0, 10, 10)
@@ -553,25 +553,16 @@
rule.runOnIdle { assertThat(parent1.value).isTrue() }
}
- private fun ComposeContentTestRule.setContentForTest(composable: @Composable () -> Unit) {
- setContent {
- focusManager = LocalFocusManager.current
- composable()
- }
- rule.runOnIdle { initialFocus.requestFocus() }
- }
-
- private fun ComposeContentTestRule.setContentWithInitialRootFocus(
+ private fun ComposeContentTestRule.setContentForTest(
+ initializeFocus: Boolean = false,
composable: @Composable () -> Unit
) {
setContent {
focusManager = LocalFocusManager.current
composable()
}
- rule.runOnIdle {
- with(focusManager as FocusOwner) {
- focusTransactionManager.withNewTransaction { takeFocus() }
- }
+ if (initializeFocus) {
+ rule.runOnIdle { initialFocus.requestFocus() }
}
}
}
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearchPreviousTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearchPreviousTest.kt
index 613421e..9d248a0 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearchPreviousTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearchPreviousTest.kt
@@ -44,7 +44,7 @@
@Test
fun moveFocus_noFocusableItem() {
// Arrange.
- rule.setContentWithInitialRootFocus {}
+ rule.setContentForTest {}
// Act.
val movedFocusSuccessfully = rule.runOnIdle { focusManager.moveFocus(Previous) }
@@ -57,7 +57,7 @@
fun moveFocus_oneDisabledFocusableItem() {
// Arrange.
val isItemFocused = mutableStateOf(false)
- rule.setContentWithInitialRootFocus {
+ rule.setContentForTest {
FocusableBox(isItemFocused, 0, 0, 10, 10, deactivated = true)
}
@@ -72,7 +72,7 @@
fun initialFocus_oneItem() {
// Arrange.
val isItemFocused = mutableStateOf(false)
- rule.setContentWithInitialRootFocus {
+ rule.setContentForTest {
FocusableBox(isItemFocused, 0, 0, 10, 10)
}
@@ -90,7 +90,7 @@
fun initialFocus_skipsDeactivatedItem() {
// Arrange.
val (firstItem, secondItem) = List(2) { mutableStateOf(false) }
- rule.setContentWithInitialRootFocus {
+ rule.setContentForTest {
Column {
FocusableBox(firstItem, 0, 0, 10, 10)
FocusableBox(secondItem, 0, 0, 10, 10, deactivated = true)
@@ -112,7 +112,7 @@
fun initialFocus_lastItemInCompositionOrderGetsFocus() {
// Arrange.
val (firstItem, secondItem) = List(2) { mutableStateOf(false) }
- rule.setContentWithInitialRootFocus {
+ rule.setContentForTest {
FocusableBox(firstItem, 10, 10, 10, 10)
FocusableBox(secondItem, 0, 0, 10, 10)
}
@@ -131,7 +131,7 @@
fun initialFocus_lastChildInCompositionOrderGetsFocus() {
// Arrange.
val (parent1, parent2, child1, child2) = List(4) { mutableStateOf(false) }
- rule.setContentWithInitialRootFocus {
+ rule.setContentForTest {
FocusableBox(parent1, 10, 10, 10, 10) {
FocusableBox(child1, 10, 10, 10, 10)
}
@@ -154,7 +154,7 @@
fun initialFocus_lastItemInCompositionOrderGetsFocus_evenIfAnotherNonParentIsPresent() {
// Arrange.
val (parent1, child1, item1) = List(3) { mutableStateOf(false) }
- rule.setContentWithInitialRootFocus {
+ rule.setContentForTest {
FocusableBox(item1, 0, 0, 10, 10)
FocusableBox(parent1, 10, 10, 10, 10) {
FocusableBox(child1, 10, 10, 10, 10)
@@ -175,7 +175,7 @@
fun initialFocus_lastItemInCompositionOrderGetsFocus_evenIfThereIsAParentAtTheRoot() {
// Arrange.
val (parent1, child1, item2) = List(3) { mutableStateOf(false) }
- rule.setContentWithInitialRootFocus {
+ rule.setContentForTest {
FocusableBox(parent1, 10, 10, 10, 10) {
FocusableBox(child1, 10, 10, 10, 10)
FocusableBox(item2, 0, 0, 10, 10)
@@ -196,7 +196,7 @@
fun focusMovesToSecondItem() {
// Arrange.
val (item1, item2, item3) = List(3) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
FocusableBox(item1, 0, 0, 10, 10)
FocusableBox(item2, 10, 0, 10, 10)
FocusableBox(item3, 20, 0, 10, 10, initialFocus)
@@ -216,7 +216,7 @@
fun focusMovesToSecondItem_skipsDeactivatedItem() {
// Arrange.
val (item1, item2, item3, item4) = List(4) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
FocusableBox(item1, 0, 0, 10, 10)
FocusableBox(item2, 10, 0, 10, 10)
FocusableBox(item3, 10, 0, 10, 10, deactivated = true)
@@ -237,7 +237,7 @@
fun focusMovesToFirstItem() {
// Arrange.
val (item1, item2, item3) = List(3) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
FocusableBox(item1, 0, 0, 10, 10)
FocusableBox(item2, 10, 0, 10, 10, initialFocus)
FocusableBox(item3, 20, 0, 10, 10)
@@ -257,7 +257,7 @@
fun focusMovesToFirstItem_ignoresDeactivated() {
// Arrange.
val (item1, item2, item3, item4) = List(4) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
FocusableBox(item1, 0, 0, 10, 10)
FocusableBox(item2, 10, 0, 10, 10, initialFocus)
FocusableBox(item3, 20, 0, 10, 10, deactivated = true)
@@ -278,7 +278,7 @@
fun focusMovesToParent() {
// Arrange.
val (parent, child1, child2, child3) = List(4) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
FocusableBox(parent, 0, 0, 10, 10) {
FocusableBox(child1, 10, 0, 10, 10, initialFocus)
FocusableBox(child2, 20, 0, 10, 10)
@@ -300,7 +300,7 @@
fun focusMovesToParent_ignoresDeactivated() {
// Arrange.
val (item, parent, child1, child2) = List(4) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
FocusableBox(item, 0, 0, 10, 10)
FocusableBox(parent, 0, 0, 10, 10, deactivated = true) {
FocusableBox(child1, 10, 0, 10, 10, initialFocus)
@@ -322,7 +322,7 @@
fun focusMovesToParent_ignoresDeactivated_andWrapsAround() {
// Arrange.
val (parent, child1, child2, child3) = List(4) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
FocusableBox(parent, 0, 0, 10, 10, deactivated = true) {
FocusableBox(child1, 10, 0, 10, 10, initialFocus)
FocusableBox(child2, 20, 0, 10, 10)
@@ -344,7 +344,7 @@
fun focusWrapsAroundToLastItem() {
// Arrange.
val (item1, item2, item3) = List(3) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
FocusableBox(item1, 0, 0, 10, 10, initialFocus)
FocusableBox(item2, 10, 0, 10, 10)
FocusableBox(item3, 20, 0, 10, 10)
@@ -364,7 +364,7 @@
fun focusWrapsAroundToLastItem_skippingFirstDeactivatedItem() {
// Arrange.
val (item1, item2, item3, item4) = List(4) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
FocusableBox(item1, 20, 0, 10, 10, deactivated = true)
FocusableBox(item2, 0, 0, 10, 10, initialFocus)
FocusableBox(item3, 10, 0, 10, 10)
@@ -385,7 +385,7 @@
fun focusWrapsAroundToLastItem_skippingLastDeactivatedItem() {
// Arrange.
val (item1, item2, item3, item4) = List(4) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
FocusableBox(item1, 0, 0, 10, 10, initialFocus)
FocusableBox(item2, 10, 0, 10, 10)
FocusableBox(item3, 20, 0, 10, 10)
@@ -406,7 +406,7 @@
fun focusMovesToChildOfDeactivatedItem() {
// Arrange.
val (item1, item2, item3, child) = List(4) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
FocusableBox(item1, 0, 0, 10, 10)
FocusableBox(item2, 10, 0, 10, 10, deactivated = true) {
FocusableBox(child, 10, 0, 10, 10)
@@ -428,7 +428,7 @@
fun focusMovesToGrandChildOfDeactivatedItem() {
// Arrange.
val (item1, item2, item3, child, grandchild) = List(5) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
FocusableBox(item1, 0, 0, 10, 10)
FocusableBox(item2, 10, 0, 10, 10, deactivated = true) {
FocusableBox(child, 10, 0, 10, 10, deactivated = true) {
@@ -452,7 +452,7 @@
fun focusMovesToNextSiblingOfDeactivatedItem_evenThoughThereIsACloserNonSibling() {
// Arrange.
val (item1, item2, item3, child1, child2) = List(5) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
FocusableBox(item1, 10, 0, 10, 10)
FocusableBox(item2, 0, 0, 10, 10, deactivated = true) {
FocusableBox(child1, 0, 0, 10, 10)
@@ -475,7 +475,7 @@
fun focusNextOrderAmongChildrenOfMultipleParents() {
// Arrange.
val focusState = List(12) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
Column {
Row {
FocusableBox(focusState[0], 0, 0, 10, 10)
@@ -511,7 +511,7 @@
fun focusNextOrderAmongChildrenAtMultipleLevels() {
// Arrange.
val focusState = List(14) { mutableStateOf(false) }
- rule.setContentForTest {
+ rule.setContentForTest(initializeFocus = true) {
Column {
FocusableBox(focusState[0], 0, 0, 10, 10)
FocusableBox(focusState[1], 0, 10, 10, 10)
@@ -554,7 +554,7 @@
val (parent4, child7, child8, child11, child12) = List(5) { mutableStateOf(false) }
val (child9, child10) = List(2) { mutableStateOf(false) }
val (parent5, child13) = List(2) { mutableStateOf(false) }
- rule.setContentWithInitialRootFocus {
+ rule.setContentForTest {
FocusableBox(parent1, 0, 0, 10, 10) {
FocusableBox(child1, 0, 0, 10, 10)
FocusableBox(child2, 20, 0, 10, 10)
@@ -624,25 +624,16 @@
rule.runOnIdle { assertThat(child11.value).isTrue() }
}
- private fun ComposeContentTestRule.setContentForTest(composable: @Composable () -> Unit) {
- setContent {
- focusManager = LocalFocusManager.current
- composable()
- }
- rule.runOnIdle { initialFocus.requestFocus() }
- }
-
- private fun ComposeContentTestRule.setContentWithInitialRootFocus(
+ private fun ComposeContentTestRule.setContentForTest(
+ initializeFocus: Boolean = false,
composable: @Composable () -> Unit
) {
setContent {
focusManager = LocalFocusManager.current
composable()
}
- rule.runOnIdle {
- with(focusManager as FocusOwner) {
- focusTransactionManager.withNewTransaction { takeFocus() }
- }
+ if (initializeFocus) {
+ rule.runOnIdle { initialFocus.requestFocus() }
}
}
}
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/OwnerFocusTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/OwnerFocusTest.kt
index bfeff0b..e3843b0 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/OwnerFocusTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/OwnerFocusTest.kt
@@ -17,13 +17,18 @@
package androidx.compose.ui.focus
import android.view.View
+import android.view.View.FOCUS_DOWN
+import android.view.View.FOCUS_UP
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.size
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
+import androidx.compose.ui.unit.dp
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import com.google.common.truth.Truth.assertThat
@@ -63,19 +68,16 @@
}
}
- @Ignore("Enable this test after the owner propagates focus to the hierarchy (b/152535715)")
@Test
fun whenOwnerGainsFocus_focusModifiersAreUpdated() {
// Arrange.
lateinit var ownerView: View
lateinit var focusState: FocusState
- val focusRequester = FocusRequester()
- rule.setFocusableContent {
+ rule.setFocusableContent(extraItemForInitialFocus = false) {
ownerView = LocalView.current
Box(
modifier = Modifier
.onFocusChanged { focusState = it }
- .focusRequester(focusRequester)
.focusTarget()
)
}
@@ -91,6 +93,106 @@
}
}
+ @Test
+ fun callingRequestFocusDownWhenOwnerAlreadyHasFocus() {
+ // Arrange.
+ lateinit var ownerView: View
+ lateinit var focusState1: FocusState
+ lateinit var focusState2: FocusState
+ lateinit var focusState3: FocusState
+ val focusRequester = FocusRequester()
+ rule.setFocusableContent(extraItemForInitialFocus = false) {
+ ownerView = LocalView.current
+ Column {
+ Box(
+ modifier = Modifier
+ .size(10.dp)
+ .onFocusChanged { focusState1 = it }
+ .focusTarget()
+ )
+ Box(
+ modifier = Modifier
+ .size(10.dp)
+ .focusRequester(focusRequester)
+ .onFocusChanged { focusState2 = it }
+ .focusTarget()
+ )
+ Box(
+ modifier = Modifier
+ .size(10.dp)
+ .onFocusChanged { focusState3 = it }
+ .focusTarget()
+ )
+ }
+ }
+ rule.runOnIdle {
+ focusRequester.requestFocus()
+ }
+
+ // Act.
+ val focusRequested = rule.runOnIdle {
+ ownerView.requestFocus(FOCUS_DOWN)
+ }
+
+ // Assert.
+ rule.runOnIdle {
+ assertThat(focusRequested).isTrue()
+ assertThat(focusState1.isFocused).isFalse()
+ assertThat(focusState2.isFocused).isTrue()
+ assertThat(focusState3.isFocused).isFalse()
+ }
+ }
+
+ @Test
+ fun callingRequestFocusUpWhenOwnerAlreadyHasFocus() {
+ // Arrange.
+ lateinit var ownerView: View
+ lateinit var focusState1: FocusState
+ lateinit var focusState2: FocusState
+ lateinit var focusState3: FocusState
+ val focusRequester = FocusRequester()
+ rule.setFocusableContent(extraItemForInitialFocus = false) {
+ ownerView = LocalView.current
+ Column {
+ Box(
+ modifier = Modifier
+ .size(10.dp)
+ .onFocusChanged { focusState1 = it }
+ .focusTarget()
+ )
+ Box(
+ modifier = Modifier
+ .size(10.dp)
+ .focusRequester(focusRequester)
+ .onFocusChanged { focusState2 = it }
+ .focusTarget()
+ )
+ Box(
+ modifier = Modifier
+ .size(10.dp)
+ .onFocusChanged { focusState3 = it }
+ .focusTarget()
+ )
+ }
+ }
+ rule.runOnIdle {
+ focusRequester.requestFocus()
+ }
+
+ // Act.
+ val focusRequested = rule.runOnIdle {
+ ownerView.requestFocus(FOCUS_UP)
+ }
+
+ // Assert.
+ rule.runOnIdle {
+ assertThat(focusRequested).isTrue()
+ assertThat(focusState1.isFocused).isFalse()
+ assertThat(focusState2.isFocused).isTrue()
+ assertThat(focusState3.isFocused).isFalse()
+ }
+ }
+
@Ignore("Enable this test after the owner propagates focus to the hierarchy (b/152535715)")
@Test
fun whenWindowGainsFocus_focusModifiersAreUpdated() {
@@ -129,6 +231,7 @@
ownerView = LocalView.current
Box(
modifier = Modifier
+ .size(10.dp)
.onFocusChanged { focusState = it }
.focusRequester(focusRequester)
.focusTarget()
@@ -180,6 +283,25 @@
}
@Test
+ fun viewDoesNotTakeFocus_whenThereAreNoFocusableItems() {
+ // Arrange.
+ lateinit var ownerView: View
+ rule.setFocusableContent(extraItemForInitialFocus = false) {
+ ownerView = LocalView.current
+ Box {}
+ }
+
+ // Act.
+ val success = rule.runOnIdle { ownerView.requestFocus() }
+
+ // Assert.
+ rule.runOnIdle {
+ assertThat(success).isFalse()
+ assertThat(ownerView.isFocused).isFalse()
+ }
+ }
+
+ @Test
fun clickingOnNonClickableSpaceInAppWhenViewIsFocused_doesNotChangeViewFocus() {
// Arrange.
val nonClickable = "notClickable"
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusTraversalImplicitEnterTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusTraversalImplicitEnterTest.kt
index cd43471..30f4e1a 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusTraversalImplicitEnterTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusTraversalImplicitEnterTest.kt
@@ -152,7 +152,7 @@
* |________|
*/
@Test
- fun moveFocusEnter_blockFocusChange() {
+ fun moveFocus_skipsItemWithCustomEnter() {
// Arrange.
val (up, down, left, right, parent) = List(5) { mutableStateOf(false) }
val child = mutableStateOf(false)
@@ -185,15 +185,95 @@
// Assert.
rule.runOnIdle {
- assertThat(movedFocusSuccessfully).isFalse()
+ assertThat(movedFocusSuccessfully).isTrue()
assertThat(directionSentToEnter).isEqualTo(focusDirection)
assertThat(child.value).isFalse()
assertThat(parent.value).isFalse()
when (focusDirection) {
- Left -> assertThat(right.value).isTrue()
- Right -> assertThat(left.value).isTrue()
- Up -> assertThat(down.value).isTrue()
- Down -> assertThat(up.value).isTrue()
+ Left -> assertThat(left.value).isTrue()
+ Right -> assertThat(right.value).isTrue()
+ Up -> assertThat(left.value).isTrue()
+ Down -> assertThat(left.value).isTrue()
+ }
+ }
+ }
+
+ /**
+ * _________ | _________
+ * | Up | | | Up |
+ * |________| | |________|
+ * ________________ | ________________
+ * | parent | | | parent |
+ * | _________ | __________ | __________ | _________ |
+ * | | child0 | | | focused | | | focused | | | child0 | |
+ * | |________| | |_________| | |_________| | |________| |
+ * |_______________| | |_______________|
+ * _________ | _________
+ * | Down | | | Down |
+ * |________| | |________|
+ * |
+ * moveFocus(Left) | moveFocus(Right)
+ * |
+ * ---------------------------------------------|--------------------------------------------
+ * | __________
+ * | | focused |
+ * | |_________|
+ * ________________ | ________________
+ * | parent | | | parent |
+ * _________ | _________ | _________ | _________ | _________ | _________
+ * | Left | | | child0 | | | Right | | | Left | | | child0 | | | Right |
+ * |________| | |________| | |________| | |________| | |________| | |________|
+ * |_______________| | |_______________|
+ * __________ |
+ * | focused | |
+ * |_________| |
+ * |
+ * moveFocus(Up) | moveFocus(Down)
+ * |
+ */
+ @Test
+ fun moveFocusEnter_blockFocusChange_appropriateOtherItemIsFocused() {
+ // Arrange.
+ val (up, down, left, right, parent) = List(5) { mutableStateOf(false) }
+ val child = mutableStateOf(false)
+ var (upItem, downItem, leftItem, rightItem, childItem) = FocusRequester.createRefs()
+ var directionSentToEnter: FocusDirection? = null
+ val customFocusEnter = Modifier.focusProperties {
+ enter = {
+ directionSentToEnter = it
+ Cancel
+ }
+ }
+ when (focusDirection) {
+ Left -> rightItem = initialFocus
+ Right -> leftItem = initialFocus
+ Up -> downItem = initialFocus
+ Down -> upItem = initialFocus
+ }
+ rule.setContentForTest {
+ if (focusDirection != Up) FocusableBox(up, 30, 0, 10, 10, upItem)
+ if (focusDirection != Left) FocusableBox(left, 0, 30, 10, 10, leftItem)
+ FocusableBox(parent, 20, 20, 30, 30, deactivated = true, modifier = customFocusEnter) {
+ FocusableBox(child, 10, 10, 10, 10, childItem)
+ }
+ if (focusDirection != Right) FocusableBox(right, 60, 30, 10, 10, rightItem)
+ if (focusDirection != Down) FocusableBox(down, 30, 60, 10, 10, downItem)
+ }
+
+ // Act.
+ val movedFocusSuccessfully = rule.runOnIdle { focusManager.moveFocus(focusDirection) }
+
+ // Assert.
+ rule.runOnIdle {
+ assertThat(movedFocusSuccessfully).isTrue()
+ assertThat(directionSentToEnter).isEqualTo(focusDirection)
+ assertThat(child.value).isFalse()
+ assertThat(parent.value).isFalse()
+ when (focusDirection) {
+ Left -> assertThat(up.value).isTrue()
+ Right -> assertThat(up.value).isTrue()
+ Up -> assertThat(left.value).isTrue()
+ Down -> assertThat(left.value).isTrue()
}
}
}
@@ -205,7 +285,7 @@
* ________________
* | |
* _________ | empty | _________
- * | Left | | lazylist | | Right |
+ * | Left | | lazyList | | Right |
* |________| | | |________|
* |_______________|
* _________
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusTraversalInitialFocusTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusTraversalInitialFocusTest.kt
index bfccce6..a08a472 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusTraversalInitialFocusTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusTraversalInitialFocusTest.kt
@@ -16,7 +16,6 @@
package androidx.compose.ui.focus
-import android.view.View
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.text.BasicText
@@ -29,7 +28,6 @@
import androidx.compose.ui.focus.FocusDirection.Companion.Right
import androidx.compose.ui.focus.FocusDirection.Companion.Up
import androidx.compose.ui.platform.LocalFocusManager
-import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.test.junit4.ComposeContentTestRule
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.test.filters.MediumTest
@@ -54,7 +52,6 @@
}
private val focusDirection = param.focusDirection
- lateinit var view: View
private lateinit var focusManager: FocusManager
companion object {
@@ -214,11 +211,9 @@
private fun ComposeContentTestRule.setContentForTest(composable: @Composable () -> Unit) {
setContent {
- view = LocalView.current
focusManager = LocalFocusManager.current
composable()
}
- rule.runOnIdle { view.requestFocus() }
}
}
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/EditorInfoTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/EditorInfoTest.kt
index ddd1083..5c9a77e 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/EditorInfoTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/EditorInfoTest.kt
@@ -19,11 +19,11 @@
import android.text.InputType
import android.view.inputmethod.EditorInfo
import androidx.compose.ui.text.TextRange
-import androidx.compose.ui.text.input.AndroidImeOptions
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.ImeOptions
import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.text.input.PlatformImeOptions
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.update
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -544,7 +544,7 @@
val privateImeOptions = "testOptions"
info.update(
ImeOptions(
- platformImeOptions = AndroidImeOptions(privateImeOptions)
+ platformImeOptions = PlatformImeOptions(privateImeOptions)
)
)
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/focus/FocusAwareEventPropagationTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/focus/FocusAwareEventPropagationTest.kt
index e350b81..07764c7 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/focus/FocusAwareEventPropagationTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/focus/FocusAwareEventPropagationTest.kt
@@ -84,7 +84,6 @@
@Test
fun noFocusable_doesNotDeliverEvent() {
// Arrange.
- var error: IllegalStateException? = null
rule.setContent {
Box(
modifier = Modifier.onFocusAwareEvent {
@@ -95,25 +94,15 @@
}
// Act.
- try {
- rule.onRoot().performFocusAwareInput(sentEvent)
- } catch (exception: IllegalStateException) {
- error = exception
- }
+ rule.onRoot().performFocusAwareInput(sentEvent)
// Assert.
- assertThat(receivedEvent).isNull()
- when (nodeType) {
- KeyInput, InterruptedSoftKeyboardInput ->
- assertThat(error!!.message).contains("do not have an active focus target")
- RotaryInput -> assertThat(error).isNull()
- }
+ rule.runOnIdle { assertThat(receivedEvent).isNull() }
}
@Test
fun unfocusedFocusable_doesNotDeliverEvent() {
// Arrange.
- var error: IllegalStateException? = null
rule.setFocusableContent {
Box(
modifier = Modifier
@@ -126,18 +115,10 @@
}
// Act.
- try {
- rule.onRoot().performFocusAwareInput(sentEvent)
- } catch (exception: IllegalStateException) {
- error = exception
- }
+ rule.onRoot().performFocusAwareInput(sentEvent)
// Assert.
- assertThat(receivedEvent).isNull()
- when (nodeType) {
- KeyInput -> assertThat(error!!.message).contains("do not have an active focus target")
- InterruptedSoftKeyboardInput, RotaryInput -> assertThat(receivedEvent).isNull()
- }
+ rule.runOnIdle { assertThat(receivedEvent).isNull() }
}
@Test
@@ -526,7 +507,7 @@
}
private fun ComposeContentTestRule.setContentWithInitialFocus(content: @Composable () -> Unit) {
- setFocusableContent(content)
+ setFocusableContent(content = content)
runOnIdle { initialFocus.requestFocus() }
}
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/key/ProcessKeyInputTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/key/ProcessKeyInputTest.kt
index 70124ae..f87436d 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/key/ProcessKeyInputTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/key/ProcessKeyInputTest.kt
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package androidx.compose.ui.input.key
import android.view.KeyEvent as AndroidKeyEvent
@@ -39,7 +38,6 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import com.google.common.truth.Truth.assertThat
-import kotlin.test.assertFailsWith
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -51,44 +49,45 @@
val rule = createComposeRule()
@Test
- fun noRootFocusTarget_throwsException() {
+ fun noFocusTarget_doesNotTriggerOnKeyEvent() {
// Arrange.
- rule.setContent {
- Box(modifier = Modifier.onKeyEvent { false })
+ var receivedKeyEvent: KeyEvent? = null
+ rule.setFocusableContent {
+ Box(
+ Modifier.onKeyEvent {
+ receivedKeyEvent = it
+ true
+ }
+ )
}
// Act.
- assertFailsWith<IllegalStateException> {
- rule.onRoot().performKeyPress(keyEvent(KeyCodeA, KeyDown))
- }
+ rule.onRoot().performKeyPress(keyEvent(KeyCodeA, KeyDown))
+
+ // Assert.
+ rule.runOnIdle { assertThat(receivedKeyEvent).isNull() }
}
@Test
- fun noFocusTarget_throwsException() {
+ fun focusTargetNotFocused_doesNotTriggerOnKeyEvent() {
// Arrange.
+ var receivedKeyEvent: KeyEvent? = null
rule.setFocusableContent {
- Box(modifier = Modifier.onKeyEvent { true })
+ Box(
+ Modifier
+ .focusTarget()
+ .onKeyEvent {
+ receivedKeyEvent = it
+ true
+ }
+ )
}
// Act.
- assertFailsWith<IllegalStateException> {
- rule.onRoot().performKeyPress(keyEvent(KeyCodeA, KeyDown))
- }
- }
+ rule.onRoot().performKeyPress(keyEvent(KeyCodeA, KeyDown))
- @Test
- fun focusTargetNotFocused_throwsException() {
- // Arrange.
- rule.setFocusableContent {
- Box(modifier = Modifier
- .focusTarget()
- .onKeyEvent { true })
- }
-
- // Act.
- assertFailsWith<IllegalStateException> {
- rule.onRoot().performKeyPress(keyEvent(KeyCodeA, KeyDown))
- }
+ // Assert.
+ rule.runOnIdle { assertThat(receivedKeyEvent).isNull() }
}
@Test
@@ -681,7 +680,10 @@
* The [KeyEvent] is usually created by the system. This function creates an instance of
* [KeyEvent] that can be used in tests.
*/
- private fun keyEvent(keycode: Int, keyEventType: KeyEventType): KeyEvent {
+ private fun keyEvent(
+ @Suppress("SameParameterValue") keycode: Int,
+ keyEventType: KeyEventType
+ ): KeyEvent {
val action = when (keyEventType) {
KeyDown -> ACTION_DOWN
KeyUp -> ACTION_UP
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/SuspendingPointerInputFilterTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/SuspendingPointerInputFilterTest.kt
index c5b32c4..ad79089 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/SuspendingPointerInputFilterTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/SuspendingPointerInputFilterTest.kt
@@ -929,4 +929,130 @@
rule.onNodeWithTag(tag)
.assertHeightIsEqualTo(10.dp)
}
+
+ // Tests pointerInput with bad pointer data
+ @Test
+ fun pointerInput_badSinglePointer_composeIgnores() {
+ val events = mutableListOf<PointerEventType>()
+ val tag = "input rect"
+ rule.setContent {
+ Box(
+ Modifier.fillMaxSize()
+ .testTag(tag)
+ .pointerInput(Unit) {
+ awaitPointerEventScope {
+ while (true) {
+ val event = awaitPointerEvent()
+ events += event.type
+ }
+ }
+ }
+ )
+ }
+
+ rule.onNodeWithTag(tag).performTouchInput {
+ down(Offset.Zero) // Compose handles
+ // Adds pointer (extra finger) with bad data. Because the bad x/y are part of the
+ // MotionEvent, Compose won't process the entire event or any following events
+ // until the bad data is removed.
+ down(1, Offset(Float.NaN, Float.NaN)) // Compose ignores (adds bad data)
+ moveBy(0, Offset(10f, 10f)) // Compose ignores
+ up() // Compose ignores
+ }
+ assertThat(events).hasSize(1)
+ assertThat(events).containsExactly(PointerEventType.Press)
+ }
+
+ @Test
+ fun pointerInput_badSinglePointerRemove_composeOnlyHandlesEventsWhenBadDataRemoved() {
+ val events = mutableListOf<PointerEventType>()
+ val tag = "input rect"
+ rule.setContent {
+ Box(
+ Modifier.fillMaxSize()
+ .testTag(tag)
+ .pointerInput(Unit) {
+ awaitPointerEventScope {
+ while (true) {
+ val event = awaitPointerEvent()
+ events += event.type
+ }
+ }
+ }
+ )
+ }
+
+ rule.onNodeWithTag(tag).performTouchInput {
+ down(Offset.Zero) // Compose handles
+ // Adds pointer (extra finger) with bad data. Because the bad x/y are part of the
+ // MotionEvent, Compose won't process the entire event or any following events
+ // until the bad data is removed.
+ down(1, Offset(Float.NaN, Float.NaN)) // Compose ignores (adds bad data)
+ moveBy(0, Offset(10f, 10f)) // Compose ignores
+ moveBy(0, Offset(10f, 10f)) // Compose ignores
+
+ // Remove bad pointer, now Compose will handle events again.
+ up(1)
+ // Compose handles everything after this
+ moveBy(0, Offset(10f, 10f))
+ up()
+ }
+ assertThat(events).hasSize(3)
+ assertThat(events).containsExactly(
+ PointerEventType.Press,
+ PointerEventType.Move,
+ PointerEventType.Release
+ )
+ }
+
+ @Test
+ fun pointerInput_badMultiplePointers_composeIgnores() {
+ val events = mutableListOf<PointerEventType>()
+ val tag = "input rect"
+ rule.setContent {
+ Box(
+ Modifier.fillMaxSize()
+ .testTag(tag)
+ .pointerInput(Unit) {
+ awaitPointerEventScope {
+ while (true) {
+ val event = awaitPointerEvent()
+ events += event.type
+ }
+ }
+ }
+ )
+ }
+
+ rule.onNodeWithTag(tag).performTouchInput {
+ down(Offset.Zero)
+ // Adds pointer (extra finger) with bad data. Because the bad x/y are part of the
+ // MotionEvent, Compose won't process the entire event or any following events
+ // until the bad data is removed.
+ down(1, Offset(Float.NaN, Float.NaN)) // Compose ignores (adds bad data)
+ down(2, Offset(Float.NaN, Float.NaN)) // Compose ignores (adds bad data)
+ down(3, Offset(20f, 20f)) // Ignored by Compose
+ moveBy(3, Offset(10f, 10f)) // Ignored by Compose
+ moveBy(3, Offset(10f, 10f)) // Ignored by Compose
+ moveBy(3, Offset(10f, 10f)) // Ignored by Compose
+
+ // Remove bad pointers
+ up(1)
+ up(2)
+
+ // Now that bad pointers are gone, Compose properly handles all of these:
+ moveBy(3, Offset(10f, 10f))
+ moveBy(0, Offset(10f, 10f))
+ up() // defaults to id=0
+ up(3)
+ }
+ assertThat(events).hasSize(5)
+ assertThat(events).containsExactly(
+ PointerEventType.Press,
+ PointerEventType.Move,
+ PointerEventType.Move,
+ PointerEventType.Release,
+ PointerEventType.Release
+ )
+ }
}
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/rotary/RotaryScrollEventTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/rotary/RotaryScrollEventTest.kt
index e6eb02c..2364e7f 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/rotary/RotaryScrollEventTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/rotary/RotaryScrollEventTest.kt
@@ -45,6 +45,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import com.google.common.truth.Truth.assertThat
+import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -60,6 +61,11 @@
private var receivedEvent: RotaryScrollEvent? = null
private val tolerance: Float = 0.000001f
+ @Before
+ fun before() {
+ receivedEvent = null
+ }
+
@Test
fun androidWearCrownRotation_triggersRotaryEvent() {
// Arrange.
@@ -90,6 +96,38 @@
}
}
+ // tests bad data
+ @Test
+ fun androidWearCrownRotation_triggersRotaryEventWithBadData() {
+ // Arrange.
+ ContentWithInitialFocus {
+ Box(
+ modifier = Modifier
+ .onRotaryScrollEvent {
+ receivedEvent = it
+ true
+ }
+ .focusable(initiallyFocused = true)
+ )
+ }
+
+ // Act.
+ rule.runOnIdle {
+ rootView.dispatchGenericMotionEvent(
+ MotionEventBuilder.newBuilder()
+ .setAction(ACTION_SCROLL)
+ .setSource(SOURCE_ROTARY_ENCODER)
+ .setPointer(Float.NaN, Float.NaN)
+ .build()
+ )
+ }
+
+ // Assert.
+ rule.runOnIdle {
+ assertThat(receivedEvent).isNull()
+ }
+ }
+
@Test
fun delegated_androidWearCrownRotation_triggersRotaryEvent() {
val node = object : DelegatingNode() {
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/LookaheadScopeTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/LookaheadScopeTest.kt
index 69c453e..4de0f4c 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/LookaheadScopeTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/LookaheadScopeTest.kt
@@ -19,7 +19,6 @@
package androidx.compose.ui.layout
import androidx.activity.ComponentActivity
-import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationVector2D
@@ -53,7 +52,6 @@
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.layout.wrapContentWidth
-import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
@@ -64,7 +62,6 @@
import androidx.compose.runtime.movableContentOf
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
@@ -103,7 +100,6 @@
import kotlin.math.roundToInt
import kotlin.random.Random
import kotlin.test.assertNotNull
-import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.junit.Ignore
import org.junit.Rule
@@ -2290,83 +2286,6 @@
}
}
- @Test
- fun forceMeasureLookaheadRootInParentsMeasurePass() {
- var show by mutableStateOf(false)
- var lookaheadOffset: Offset? = null
- var offset: Offset? = null
- rule.setContent {
- CompositionLocalProvider(LocalDensity provides Density(1f)) {
- // Mutate this state in measure
- Box(Modifier.fillMaxSize()) {
- val size by produceState(initialValue = 200) {
- delay(500)
- value = 600 - value
- }
- LazyColumn(Modifier.layout { measurable, _ ->
- // Mutate this state in measure. This state will later be used in descendant's
- // composition.
- show = size > 300
- measurable.measure(Constraints.fixed(size, size)).run {
- layout(width, height) { place(0, 0) }
- }
- }) {
- item {
- SubcomposeLayout(Modifier.fillMaxSize()) {
- val placeable = subcompose(Unit) {
- // read the value to force a recomposition
- Box(
- Modifier.requiredSize(222.dp)
- ) {
- AnimatedContent(show, Modifier.requiredSize(200.dp)) {
- if (it) {
- Row(
- Modifier
- .fillMaxSize()
- .layout { measurable, constraints ->
- val p = measurable.measure(constraints)
- layout(p.width, p.height) {
- coordinates
- ?.positionInRoot()
- .let {
- if (isLookingAhead) {
- lookaheadOffset = it
- } else {
- offset = it
- }
- }
- p.place(0, 0)
- }
- }) {}
- } else {
- Row(
- Modifier.size(10.dp)
- ) {}
- }
- }
- }
- }[0].measure(Constraints(0, 2000, 0, 2000))
- // Measure with the same constraints to ensure the child (i.e. Box)
- // gets no constraints change and hence starts forceMeasureSubtree
- // from there
- layout(700, 800) {
- placeable.place(0, 0)
- }
- }
- }
- }
- }
- }
- }
- rule.waitUntil(2000) {
- show
- }
- rule.waitForIdle()
-
- assertEquals(Offset(-150f, 0f), lookaheadOffset)
- assertEquals(Offset(-150f, 0f), offset)
- }
-
@OptIn(ExperimentalComposeUiApi::class)
@Test
fun lookaheadSizeTrackedWhenModifierChanges() {
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/MeasureOnlyTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/MeasureOnlyTest.kt
index f95f492..c64186f 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/MeasureOnlyTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/MeasureOnlyTest.kt
@@ -18,14 +18,9 @@
import android.view.View
import android.view.View.MeasureSpec
import androidx.activity.ComponentActivity
-import androidx.compose.animation.AnimatedContent
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.requiredSize
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
@@ -34,19 +29,15 @@
import androidx.compose.ui.background
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.ComposeView
-import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.test.junit4.createAndroidComposeRule
-import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.constrainHeight
import androidx.compose.ui.unit.constrainWidth
-import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import com.google.common.truth.Truth.assertThat
-import kotlin.test.assertEquals
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -287,64 +278,4 @@
assertThat(view.height).isEqualTo(10)
}
}
-
- /**
- * When a descendant affects the root size, the root should resize when the
- * descendant changes size.
- */
- @Test
- fun remeasureRootWithLookahead() {
- var largeContent by mutableStateOf(false)
- var lookaheadSize: IntSize? = null
- rule.setContent {
- // Forces the box to change size, so that the containing AndroidView will get a
- // different set of measureSpec in `onMeasure`.
- Box(Modifier.size(if (largeContent) 200.dp else 100.dp)) {
- AndroidView(factory = { context ->
- ComposeView(context).apply {
- setContent {
- CompositionLocalProvider(LocalDensity provides Density(1f)) {
- Box(Modifier.requiredSize(300.dp)) {
- LazyColumn(Modifier.size(300.dp)) {
- item {
- AnimatedContent(largeContent, Modifier.fillMaxSize()) {
- if (it) {
- Box(
- Modifier
- .layout { measurable, constraints ->
- val placeable = measurable
- .measure(constraints)
- if (isLookingAhead)
- lookaheadSize = IntSize(
- placeable.width,
- placeable.height
- )
- layout(
- placeable.width,
- placeable.height
- ) {
- placeable.place(0, 0)
- }
- }
- .size(200.dp))
- } else {
- Box(Modifier.size(100.dp))
- }
- }
- }
- }
- }
- }
- }
- }
- })
- }
- }
- rule.runOnIdle {
- largeContent = true
- }
- rule.runOnIdle {
- assertEquals(lookaheadSize, IntSize(300, 200))
- }
- }
}
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/node/NodeUtils.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/node/NodeUtils.kt
index bec5a59..592ab66 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/node/NodeUtils.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/node/NodeUtils.kt
@@ -21,10 +21,10 @@
/**
* Remove the root modifier nodes as they are not relevant from the perspective of the tests.
- * There are 5 nodes:
- * KeyInputNode, FocusTargetNode, RotaryInputNode, SemanticsNode and DragAndDropNode.
+ * There are 5 nodes: FocusTargetNode, FocusPropertiesNode, KeyInputNode, RotaryInputNode,
+ * SemanticsNode and DragAndDropNode.
*/
-internal fun <T> List<T>.trimRootModifierNodes(): List<T> = dropLast(5)
+internal fun <T> List<T>.trimRootModifierNodes(): List<T> = dropLast(6)
internal fun Modifier.elementOf(node: Modifier.Node): Modifier {
return this.then(ElementOf { node })
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/platform/AndroidComposeViewsInRecyclerViewTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/platform/AndroidComposeViewsInRecyclerViewTest.kt
index e6c7ce2..179d68b 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/platform/AndroidComposeViewsInRecyclerViewTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/platform/AndroidComposeViewsInRecyclerViewTest.kt
@@ -17,13 +17,11 @@
package androidx.compose.ui.platform
import android.content.Context
-import android.os.Build
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.LinearLayout
import androidx.activity.ComponentActivity
-import androidx.annotation.RequiresApi
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.recyclerview.widget.DefaultItemAnimator
@@ -32,7 +30,6 @@
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
-import androidx.test.filters.SdkSuppress
import androidx.test.platform.app.InstrumentationRegistry
import androidx.testutils.AnimationDurationScaleRule
import com.google.common.truth.Truth.assertThat
@@ -54,7 +51,6 @@
@LargeTest
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
/**
* Note: this test's structure largely parallels PoolingContainerRecyclerViewTest
* (though there are notable implementation differences)
@@ -503,7 +499,6 @@
var binds = 0
var releases = 0
- @RequiresApi(Build.VERSION_CODES.KITKAT)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = DisposalCountingComposeView(context, this)
view.layoutParams =
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/platform/WindowInfoCompositionLocalTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/platform/WindowInfoCompositionLocalTest.kt
index 2a2d199..f539ca4 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/platform/WindowInfoCompositionLocalTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/platform/WindowInfoCompositionLocalTest.kt
@@ -18,9 +18,11 @@
import android.view.KeyEvent
import android.view.View
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.text.BasicText
import androidx.compose.runtime.mutableStateOf
-import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.focusTarget
import androidx.compose.ui.focus.setFocusableContent
import androidx.compose.ui.input.pointer.PointerKeyboardModifiers
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
@@ -53,7 +55,6 @@
rule.setContent {
BasicText("Main Window")
windowInfo = LocalWindowInfo.current
- @Suppress("DEPRECATION")
WindowFocusObserver { if (it) windowFocusGain.countDown() }
}
@@ -201,21 +202,16 @@
assertThat(mainWindowInfo.isWindowFocused).isTrue()
}
- @OptIn(ExperimentalComposeUiApi::class)
@Test
fun windowInfo_providesKeyModifiers() {
- lateinit var mainWindowInfo: WindowInfo
lateinit var ownerView: View
-
var keyModifiers = PointerKeyboardModifiers(0)
rule.setFocusableContent {
ownerView = LocalView.current
- mainWindowInfo = LocalWindowInfo.current
-
- keyModifiers = mainWindowInfo.keyboardModifiers
+ keyModifiers = LocalWindowInfo.current.keyboardModifiers
+ Box(Modifier.focusTarget())
}
-
assertThat(keyModifiers.packedValue).isEqualTo(0)
(rule as AndroidComposeTestRule<*, *>).runOnUiThread {
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/focus/FocusInteropUtils.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/focus/FocusInteropUtils.android.kt
new file mode 100644
index 0000000..922d23c
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/focus/FocusInteropUtils.android.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.ui.focus
+
+import android.view.ViewGroup
+import androidx.compose.ui.unit.LayoutDirection
+
+/**
+ * Converts an android focus direction to a compose [focus direction][FocusDirection].
+ */
+internal fun toFocusDirection(androidDirection: Int): FocusDirection? = when (androidDirection) {
+ ViewGroup.FOCUS_UP -> FocusDirection.Up
+ ViewGroup.FOCUS_DOWN -> FocusDirection.Down
+ ViewGroup.FOCUS_LEFT -> FocusDirection.Left
+ ViewGroup.FOCUS_RIGHT -> FocusDirection.Right
+ ViewGroup.FOCUS_FORWARD -> FocusDirection.Next
+ ViewGroup.FOCUS_BACKWARD -> FocusDirection.Previous
+ else -> null
+}
+
+/**
+ * Converts a compose [focus direction][FocusDirection] to an android focus direction.
+ */
+internal fun FocusDirection.toAndroidFocusDirection(): Int? = when (this) {
+ FocusDirection.Up -> ViewGroup.FOCUS_UP
+ FocusDirection.Down -> ViewGroup.FOCUS_DOWN
+ FocusDirection.Left -> ViewGroup.FOCUS_LEFT
+ FocusDirection.Right -> ViewGroup.FOCUS_RIGHT
+ FocusDirection.Next -> ViewGroup.FOCUS_FORWARD
+ FocusDirection.Previous -> ViewGroup.FOCUS_BACKWARD
+ else -> null
+ }
+
+/**
+ * Convert an Android layout direction to a compose [layout direction][LayoutDirection].
+ */
+internal fun toLayoutDirection(androidLayoutDirection: Int): LayoutDirection? {
+ return when (androidLayoutDirection) {
+ android.util.LayoutDirection.LTR -> LayoutDirection.Ltr
+ android.util.LayoutDirection.RTL -> LayoutDirection.Rtl
+ else -> null
+ }
+}
+
+/**
+ * focus search in the Android framework wraps around for 1D focus search, but not for 2D focus
+ * search. This is a helper function that can be used to determine whether we should wrap around.
+ */
+internal fun supportsWrapAroundFocus(androidDirection: Int): Boolean = when (androidDirection) {
+ ViewGroup.FOCUS_FORWARD, ViewGroup.FOCUS_BACKWARD -> true
+ else -> false
+}
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
index e2bd716..20f9dd0 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
@@ -22,7 +22,6 @@
import android.os.Build
import android.os.Looper
import android.os.SystemClock
-import android.util.Log
import android.util.LongSparseArray
import android.util.SparseArray
import android.view.DragEvent
@@ -80,6 +79,7 @@
import androidx.compose.ui.draganddrop.DragAndDropTransferData
import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.focus.FocusDirection.Companion.Down
+import androidx.compose.ui.focus.FocusDirection.Companion.Enter
import androidx.compose.ui.focus.FocusDirection.Companion.Exit
import androidx.compose.ui.focus.FocusDirection.Companion.Left
import androidx.compose.ui.focus.FocusDirection.Companion.Next
@@ -88,6 +88,11 @@
import androidx.compose.ui.focus.FocusDirection.Companion.Up
import androidx.compose.ui.focus.FocusOwner
import androidx.compose.ui.focus.FocusOwnerImpl
+import androidx.compose.ui.focus.requestFocus
+import androidx.compose.ui.focus.supportsWrapAroundFocus
+import androidx.compose.ui.focus.toAndroidFocusDirection
+import androidx.compose.ui.focus.toFocusDirection
+import androidx.compose.ui.focus.toLayoutDirection
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Canvas
@@ -95,19 +100,21 @@
import androidx.compose.ui.graphics.Matrix
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.setFrom
+import androidx.compose.ui.graphics.toAndroidRect
+import androidx.compose.ui.graphics.toComposeRect
import androidx.compose.ui.hapticfeedback.HapticFeedback
import androidx.compose.ui.hapticfeedback.PlatformHapticFeedback
import androidx.compose.ui.input.InputMode.Companion.Keyboard
import androidx.compose.ui.input.InputMode.Companion.Touch
import androidx.compose.ui.input.InputModeManager
import androidx.compose.ui.input.InputModeManagerImpl
+import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.Key.Companion.Back
import androidx.compose.ui.input.key.Key.Companion.DirectionCenter
import androidx.compose.ui.input.key.Key.Companion.DirectionDown
import androidx.compose.ui.input.key.Key.Companion.DirectionLeft
import androidx.compose.ui.input.key.Key.Companion.DirectionRight
import androidx.compose.ui.input.key.Key.Companion.DirectionUp
-import androidx.compose.ui.input.key.Key.Companion.Enter
import androidx.compose.ui.input.key.Key.Companion.Escape
import androidx.compose.ui.input.key.Key.Companion.NumPadEnter
import androidx.compose.ui.input.key.Key.Companion.PageDown
@@ -220,12 +227,15 @@
private val semanticsModifier = EmptySemanticsElement
- override val focusOwner: FocusOwner = FocusOwnerImpl { registerOnEndApplyChangesListener(it) }
-
- private val dragAndDropModifierOnDragListener = DragAndDropModifierOnDragListener(
- ::startDrag
+ override val focusOwner: FocusOwner = FocusOwnerImpl(
+ onRequestApplyChangesListener = ::registerOnEndApplyChangesListener,
+ onRequestFocusForOwner = ::onRequestFocusForOwner,
+ onClearFocusForOwner = ::onClearFocusForOwner,
+ layoutDirection = ::layoutDirection
)
+ private val dragAndDropModifierOnDragListener = DragAndDropModifierOnDragListener(::startDrag)
+
override val dragAndDropManager: DragAndDropManager = dragAndDropModifierOnDragListener
private val _windowInfo: WindowInfoImpl = WindowInfoImpl()
@@ -238,8 +248,10 @@
val focusDirection = getFocusDirection(it)
if (focusDirection == null || it.type != KeyDown) return@onKeyEvent false
- // Consume the key event if we moved focus.
- focusOwner.moveFocus(focusDirection)
+ // Consume the key event if we moved focus or if focus search or requestFocus is cancelled.
+ focusOwner.focusSearch(focusDirection, null) { focusTargetNode ->
+ focusTargetNode.requestFocus(focusDirection) ?: true
+ } ?: true
}
private val rotaryInputModifier = Modifier.onRotaryScrollEvent {
@@ -256,8 +268,8 @@
it.modifier = Modifier
.then(semanticsModifier)
.then(rotaryInputModifier)
- .then(focusOwner.modifier)
.then(keyInputModifier)
+ .then(focusOwner.modifier)
.then(dragAndDropModifierOnDragListener.modifier)
}
@@ -460,7 +472,11 @@
// Backed by mutableStateOf so that the ambient provider recomposes when it changes
override var layoutDirection by mutableStateOf(
- context.resources.configuration.localeLayoutDirection
+ // We don't use the attached View's layout direction here since that layout direction may not
+ // be resolved since composables may be composed without attaching to the RootViewImpl.
+ // In Jetpack Compose, use the locale layout direction (i.e. layoutDirection came from
+ // configuration) as a default layout direction.
+ toLayoutDirection(context.resources.configuration.layoutDirection) ?: LayoutDirection.Ltr
)
private set
@@ -646,14 +662,65 @@
showLayoutBounds = getIsShowingLayoutBounds()
}
+ override fun focusSearch(direction: Int): View? = if (focusOwner.rootState.hasFocus) {
+ // When the compose hierarchy is focused, it intercepts the key events that trigger focus
+ // search. So focus search should never find a compose hierarchy that has focus.
+ //
+ // However there is a case where we don't consume the key events. When all the components
+ // have been visited, and/or focus can't be moved within the compose hierarchy, the key
+ // events are returned to the framework so it can perform a search among other views. This
+ // focus search could land back on this view.
+ //
+ // Ideally just returning "this" to focus search should cause it to call requestFocus with
+ // the previously focused rect, and we would find the next item. However the framework does
+ // not call request focus on this view because it already has focus.
+ //
+ // To fix this issue, we manually clear focus and return this. The view with default focus
+ // might be assigned focus for a while, but requestFocus will be called which will then
+ // transfer focus to this view.
+ //
+ // There is an additional special case here. Focus wraps around only for 1D focus search
+ // and not for 2D focus search. So we clear focus only if focus search was triggered by
+ // a 1D focus search.
+ if (supportsWrapAroundFocus(direction)) clearFocus()
+ this
+ } else {
+ // TODO(b/261190892) run a mixed focus search that searches between composables and
+ // child views and chooses an appropriate result.
+ // We give the embedded children a chance to take focus before the compose view.
+ super.focusSearch(direction) ?: this
+ }
+
+ override fun requestFocus(direction: Int, previouslyFocusedRect: Rect?): Boolean {
+ if (focusOwner.rootState.hasFocus) return true
+ return focusOwner.takeFocus(
+ focusDirection = toFocusDirection(direction) ?: Enter,
+ previouslyFocusedRect = previouslyFocusedRect?.toComposeRect()
+ )
+ }
+
+ private fun onRequestFocusForOwner(
+ focusDirection: FocusDirection?,
+ previouslyFocusedRect: androidx.compose.ui.geometry.Rect?
+ ): Boolean {
+ return super.requestFocus(
+ focusDirection?.toAndroidFocusDirection() ?: FOCUS_DOWN,
+ @Suppress("DEPRECATION")
+ previouslyFocusedRect?.toAndroidRect()
+ )
+ }
+
+ private fun onClearFocusForOwner() {
+ if (isFocused || hasFocus()) {
+ super.clearFocus()
+ }
+ }
+
override fun onFocusChanged(gainFocus: Boolean, direction: Int, previouslyFocusedRect: Rect?) {
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect)
- Log.d(FocusTag, "Owner FocusChanged($gainFocus)")
- focusOwner.focusTransactionManager.withExistingTransaction(
- onCancelled = { if (gainFocus) clearFocus() else requestFocus() }
- ) {
- if (gainFocus) focusOwner.takeFocus() else focusOwner.releaseFocus()
- }
+ if (!gainFocus) {
+ focusOwner.releaseFocus()
+ }
}
override fun onWindowFocusChanged(hasWindowFocus: Boolean) {
@@ -1227,7 +1294,7 @@
// focus.
DirectionUp, PageUp -> Up
DirectionDown, PageDown -> Down
- DirectionCenter, Enter, NumPadEnter -> FocusDirection.Enter
+ DirectionCenter, Key.Enter, NumPadEnter -> Enter
Back, Escape -> Exit
else -> null
}
@@ -1443,10 +1510,11 @@
override fun dispatchGenericMotionEvent(event: MotionEvent) = when (event.actionMasked) {
ACTION_SCROLL -> when {
- event.isFromSource(SOURCE_ROTARY_ENCODER) -> handleRotaryEvent(event)
isBadMotionEvent(event) || !isAttachedToWindow ->
super.dispatchGenericMotionEvent(event)
+ event.isFromSource(SOURCE_ROTARY_ENCODER) -> handleRotaryEvent(event)
+
else -> handleMotionEvent(event).dispatchedToAPointerInputModifier
}
@@ -1808,10 +1876,7 @@
// If we get such a call, don't try to write to a property delegate
// that hasn't been initialized yet.
if (superclassInitComplete) {
- layoutDirectionFromInt(layoutDirection).let {
- this.layoutDirection = it
- focusOwner.layoutDirection = it
- }
+ this.layoutDirection = toLayoutDirection(layoutDirection) ?: LayoutDirection.Ltr
}
}
@@ -1975,7 +2040,6 @@
override fun shouldDelayChildPressedState(): Boolean = false
companion object {
- private const val FocusTag = "Compose Focus"
private const val MaximumLayerCacheSize = 10
private var systemPropertiesClass: Class<*>? = null
private var getBooleanMethod: Method? = null
@@ -2034,25 +2098,6 @@
}
/**
- * Return the layout direction set by the [Locale][java.util.Locale].
- *
- * A convenience getter that translates [Configuration.getLayoutDirection] result into
- * [LayoutDirection] instance.
- */
-internal val Configuration.localeLayoutDirection: LayoutDirection
- // We don't use the attached View's layout direction here since that layout direction may not
- // be resolved since the composables may be composed without attaching to the RootViewImpl.
- // In Jetpack Compose, use the locale layout direction (i.e. layoutDirection came from
- // configuration) as a default layout direction.
- get() = layoutDirectionFromInt(layoutDirection)
-
-private fun layoutDirectionFromInt(layoutDirection: Int): LayoutDirection = when (layoutDirection) {
- android.util.LayoutDirection.LTR -> LayoutDirection.Ltr
- android.util.LayoutDirection.RTL -> LayoutDirection.Rtl
- else -> LayoutDirection.Ltr
-}
-
-/**
* These classes are here to ensure that the classes that use this API will get verified and can be
* AOT compiled. It is expected that this class will soft-fail verification, but the classes
* which use this method will pass.
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
index a1df9ce..bce1f6ea 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
@@ -49,9 +49,6 @@
import androidx.collection.ArrayMap
import androidx.collection.ArraySet
import androidx.collection.SparseArrayCompat
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.setValue
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.R
import androidx.compose.ui.geometry.Offset
@@ -314,7 +311,7 @@
// traversal with granularity switches to the next node
private var previousTraversedNode: Int? = null
private val subtreeChangedLayoutNodes = ArraySet<LayoutNode>()
- private val boundsUpdateChannel = Channel<Unit>(Channel.CONFLATED)
+ private val boundsUpdateChannel = Channel<Unit>(1)
private var currentSemanticsNodesInvalidated = true
@VisibleForTesting
internal var contentCaptureForceEnabledForTesting = false
@@ -355,8 +352,10 @@
internal var idToBeforeMap = HashMap<Int, Int>()
internal var idToAfterMap = HashMap<Int, Int>()
internal val ExtraDataTestTraversalBeforeVal =
+ @Suppress("SpellCheckingInspection")
"android.view.accessibility.extra.EXTRA_DATA_TEST_TRAVERSALBEFORE_VAL"
internal val ExtraDataTestTraversalAfterVal =
+ @Suppress("SpellCheckingInspection")
"android.view.accessibility.extra.EXTRA_DATA_TEST_TRAVERSALAFTER_VAL"
private val urlSpanCache = URLSpanCache()
@@ -1847,7 +1846,11 @@
AccessibilityNodeInfoCompat.ACTION_CLEAR_FOCUS -> {
return if (node.unmergedConfig.getOrNull(SemanticsProperties.Focused) == true) {
- view.focusOwner.clearFocus()
+ view.focusOwner.clearFocus(
+ force = false,
+ refreshFocusEvents = true,
+ clearOwnerFocus = true
+ )
true
} else {
false
@@ -2219,7 +2222,6 @@
* recent layout changes and sends events to the accessibility and content capture framework in
* batches separated by a 100ms delay.
*/
- @OptIn(ExperimentalComposeUiApi::class)
internal suspend fun boundsUpdatesEventLoop() {
try {
val subtreeChangedSemanticsNodesIds = ArraySet<Int>()
@@ -3793,4 +3795,4 @@
@get:ExperimentalComposeUiApi
@set:ExperimentalComposeUiApi
@ExperimentalComposeUiApi
-var DisableContentCapture: Boolean by mutableStateOf(false)
+var DisableContentCapture: Boolean = false
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/TextInputServiceAndroid.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/TextInputServiceAndroid.android.kt
index b3f0880..4ef0d8d 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/TextInputServiceAndroid.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/TextInputServiceAndroid.android.kt
@@ -504,7 +504,7 @@
ImeAction.Done -> EditorInfo.IME_ACTION_DONE
else -> error("invalid ImeAction")
}
- (imeOptions.platformImeOptions as? AndroidImeOptions)?.privateImeOptions?.let {
+ imeOptions.platformImeOptions?.privateImeOptions?.let {
privateImeOptions = it
}
when (imeOptions.keyboardType) {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusInvalidationManager.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusInvalidationManager.kt
index 9843404f..c80645c 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusInvalidationManager.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusInvalidationManager.kt
@@ -26,7 +26,8 @@
* onApplyChangesListener when nodes are scheduled for invalidation.
*/
internal class FocusInvalidationManager(
- private val onRequestApplyChangesListener: (() -> Unit) -> Unit
+ private val onRequestApplyChangesListener: (() -> Unit) -> Unit,
+ private val invalidateOwnerFocusState: () -> Unit
) {
private var focusTargetNodes = mutableSetOf<FocusTargetNode>()
private var focusEventNodes = mutableSetOf<FocusEventModifierNode>()
@@ -138,6 +139,8 @@
focusTargetNodes.clear()
focusTargetsWithInvalidatedFocusEvents.clear()
+ invalidateOwnerFocusState()
+
check(focusPropertiesNodes.isEmpty()) { "Unprocessed FocusProperties nodes" }
check(focusEventNodes.isEmpty()) { "Unprocessed FocusEvent nodes" }
check(focusTargetNodes.isEmpty()) { "Unprocessed FocusTarget nodes" }
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusOwner.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusOwner.kt
index 39a0722..f50a0ef 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusOwner.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusOwner.kt
@@ -20,7 +20,6 @@
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.input.key.KeyEvent
import androidx.compose.ui.input.rotary.RotaryScrollEvent
-import androidx.compose.ui.unit.LayoutDirection
/**
* The focus owner provides some internal APIs that are not exposed by focus manager.
@@ -34,11 +33,6 @@
val modifier: Modifier
/**
- * The owner sets the layoutDirection that is then used during focus search.
- */
- var layoutDirection: LayoutDirection
-
- /**
* This manager provides a way to ensure that only one focus transaction is running at a time.
* We use this to prevent re-entrant focus operations. Starting a new transaction automatically
* cancels the previous transaction and reverts any focus state changes made during that
@@ -47,12 +41,52 @@
val focusTransactionManager: FocusTransactionManager
/**
+ * This function is called to ask the owner to request focus from the framework.
+ * eg. If a composable calls requestFocus and the root view does not have focus, this function
+ * can be used to request focus for the view.
+ *
+ * @param focusDirection If this focus request was triggered by a call to moveFocus or using the
+ * keyboard, provide the owner with the direction of focus change.
+ *
+ * @param previouslyFocusedRect The bounds of the currently focused item.
+ *
+ * @return true if the owner successfully requested focus from the framework. False otherwise.
+ */
+ fun requestFocusForOwner(focusDirection: FocusDirection?, previouslyFocusedRect: Rect?): Boolean
+
+ /**
+ * This function searches the compose hierarchy for the next focus target based on the supplied
+ * parameters.
+ *
+ * @param focusDirection the direction to search for the focus target.
+ *
+ * @param focusedRect the bounds of the currently focused item.
+ *
+ * @param onFound This lambda is called with the focus search result.
+ *
+ * @return true, if a suitable [FocusTargetNode] was found, false if no [FocusTargetNode] was
+ * found, and null if the focus search was cancelled.
+ */
+ fun focusSearch(
+ focusDirection: FocusDirection,
+ focusedRect: Rect?,
+ onFound: (FocusTargetNode) -> Boolean
+ ): Boolean?
+
+ /**
* The [Owner][androidx.compose.ui.node.Owner] calls this function when it gains focus. This
* informs the [focus manager][FocusOwnerImpl] that the
* [Owner][androidx.compose.ui.node.Owner] gained focus, and that it should propagate this
* focus to one of the focus modifiers in the component hierarchy.
+ *
+ * @param focusDirection the direction to search for the focus target.
+ *
+ * @param previouslyFocusedRect the bounds of the currently focused item.
+ *
+ * @return true, if a suitable [FocusTargetNode] was found and it took focus, false if no
+ * [FocusTargetNode] was found or if the focus search was cancelled.
*/
- fun takeFocus()
+ fun takeFocus(focusDirection: FocusDirection, previouslyFocusedRect: Rect?): Boolean
/**
* The [Owner][androidx.compose.ui.node.Owner] calls this function when it loses focus. This
@@ -71,10 +105,13 @@
* @param refreshFocusEvents: Whether we should send an event up the hierarchy to update
* the associated onFocusEvent nodes.
*
+ * @param clearOwnerFocus whether we should also clear focus from the owner. This is usually
+ * true, unless focus is being temporarily cleared (eg. to implement focus wrapping).
+ *
* This could be used to clear focus when a user clicks on empty space outside a focusable
* component.
*/
- fun clearFocus(force: Boolean, refreshFocusEvents: Boolean)
+ fun clearFocus(force: Boolean, refreshFocusEvents: Boolean, clearOwnerFocus: Boolean)
/**
* Searches for the currently focused item, and returns its coordinates as a rect.
@@ -110,4 +147,9 @@
* Schedule a FocusProperties node to be invalidated after onApplyChanges.
*/
fun scheduleInvalidation(node: FocusPropertiesModifierNode)
+
+ /**
+ * The focus state of the root focus node.
+ */
+ val rootState: FocusState
}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusOwnerImpl.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusOwnerImpl.kt
index 0a7515b..c9e4fcf 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusOwnerImpl.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusOwnerImpl.kt
@@ -28,10 +28,6 @@
import androidx.compose.ui.focus.FocusDirection.Companion.Previous
import androidx.compose.ui.focus.FocusRequester.Companion.Cancel
import androidx.compose.ui.focus.FocusRequester.Companion.Default
-import androidx.compose.ui.focus.FocusStateImpl.Active
-import androidx.compose.ui.focus.FocusStateImpl.ActiveParent
-import androidx.compose.ui.focus.FocusStateImpl.Captured
-import androidx.compose.ui.focus.FocusStateImpl.Inactive
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.input.key.KeyEvent
import androidx.compose.ui.input.key.KeyEventType.Companion.KeyDown
@@ -56,11 +52,20 @@
* The focus manager is used by different [Owner][androidx.compose.ui.node.Owner] implementations
* to control focus.
*/
-internal class FocusOwnerImpl(onRequestApplyChangesListener: (() -> Unit) -> Unit) : FocusOwner {
+internal class FocusOwnerImpl(
+ onRequestApplyChangesListener: (() -> Unit) -> Unit,
+ private val onRequestFocusForOwner:
+ (focusDirection: FocusDirection?, previouslyFocusedRect: Rect?) -> Boolean,
+ private val onClearFocusForOwner: () -> Unit,
+ private val layoutDirection: (() -> LayoutDirection)
+) : FocusOwner {
internal var rootFocusNode = FocusTargetNode()
- private val focusInvalidationManager = FocusInvalidationManager(onRequestApplyChangesListener)
+ private val focusInvalidationManager = FocusInvalidationManager(
+ onRequestApplyChangesListener,
+ ::invalidateOwnerFocusState
+ )
override val focusTransactionManager: FocusTransactionManager = FocusTransactionManager()
@@ -69,21 +74,38 @@
* list that contains the modifiers required by the focus system. (Eg, a root focus modifier).
*/
// TODO(b/168831247): return an empty Modifier when there are no focusable children.
- override val modifier: Modifier = object : ModifierNodeElement<FocusTargetNode>() {
- override fun create() = rootFocusNode
+ override val modifier: Modifier = Modifier
+ // The root focus target is not focusable, and acts like a focus group.
+ // We could save an allocation here by making FocusTargetNode implement
+ // FocusPropertiesModifierNode but to do that we would have to allocate
+ // a focus properties object. This way only the root node has this extra allocation.
+ .focusProperties { canFocus = false }
+ .then(
+ object : ModifierNodeElement<FocusTargetNode>() {
+ override fun create() = rootFocusNode
+ override fun update(node: FocusTargetNode) {}
+ override fun InspectorInfo.inspectableProperties() { name = "RootFocusTarget" }
+ override fun hashCode(): Int = rootFocusNode.hashCode()
+ override fun equals(other: Any?) = other === this
+ }
+ )
- override fun update(node: FocusTargetNode) {}
-
- override fun InspectorInfo.inspectableProperties() {
- name = "RootFocusTarget"
- }
-
- override fun hashCode(): Int = rootFocusNode.hashCode()
-
- override fun equals(other: Any?) = other === this
- }
-
- override lateinit var layoutDirection: LayoutDirection
+ /**
+ * This function is called to ask the owner to request focus from the framework.
+ * eg. If a composable calls requestFocus and the root view does not have focus, this function
+ * can be used to request focus for the view.
+ *
+ * @param focusDirection If this focus request was triggered by a call to moveFocus or using the
+ * keyboard, provide the owner with the direction of focus change.
+ *
+ * @param previouslyFocusedRect The bounds of the currently focused item.
+ *
+ * @return true if the owner successfully requested focus from the framework. False otherwise.
+ */
+ override fun requestFocusForOwner(
+ focusDirection: FocusDirection?,
+ previouslyFocusedRect: Rect?
+ ): Boolean = onRequestFocusForOwner(focusDirection, previouslyFocusedRect)
/**
* Keeps track of which keys have received DOWN events without UP events – i.e. which keys are
@@ -99,14 +121,19 @@
* informs the [focus manager][FocusOwnerImpl] that the
* [Owner][androidx.compose.ui.node.Owner] gained focus, and that it should propagate this
* focus to one of the focus modifiers in the component hierarchy.
+ *
+ * @param focusDirection the direction to search for the focus target.
+ *
+ * @param previouslyFocusedRect the bounds of the currently focused item.
+ *
+ * @return true, if a suitable [FocusTargetNode] was found and it took focus, false if no
+ * [FocusTargetNode] was found or if the focus search was cancelled.
*/
- override fun takeFocus() {
- // If the focus state is not Inactive, it indicates that the focus state is already
- // set (possibly by dispatchWindowFocusChanged). So we don't update the state.
- if (rootFocusNode.focusState == Inactive) {
- rootFocusNode.focusState = Active
- // TODO(b/152535715): propagate focus to children based on child focusability.
- // moveFocus(FocusDirection.Enter)
+ override fun takeFocus(focusDirection: FocusDirection, previouslyFocusedRect: Rect?): Boolean {
+ return focusTransactionManager.withExistingTransaction {
+ focusSearch(focusDirection, previouslyFocusedRect) {
+ it.requestFocus(focusDirection) ?: false
+ } ?: false
}
}
@@ -117,7 +144,9 @@
* all the focus modifiers in the component hierarchy.
*/
override fun releaseFocus() {
- rootFocusNode.clearFocus(forced = true, refreshFocusEvents = true)
+ focusTransactionManager.withExistingTransaction {
+ rootFocusNode.clearFocus(forced = true, refreshFocusEvents = true)
+ }
}
/**
@@ -130,30 +159,26 @@
* component.
*/
override fun clearFocus(force: Boolean) {
- clearFocus(force, refreshFocusEvents = true)
+ clearFocus(force, refreshFocusEvents = true, clearOwnerFocus = true)
}
@OptIn(ExperimentalComposeUiApi::class)
- override fun clearFocus(force: Boolean, refreshFocusEvents: Boolean) {
- focusTransactionManager.withNewTransaction {
+ override fun clearFocus(force: Boolean, refreshFocusEvents: Boolean, clearOwnerFocus: Boolean) {
+ val clearedFocusSuccessfully = focusTransactionManager.withNewTransaction(
+ onCancelled = { return@withNewTransaction }
+ ) {
// Don't clear focus if an item on the focused path has a custom exit specified.
if (!force) {
when (rootFocusNode.performCustomClearFocus(Exit)) {
- Redirected, Cancelled, RedirectCancelled -> return
+ Redirected, Cancelled, RedirectCancelled -> return@withNewTransaction false
None -> { /* Do nothing. */ }
}
}
+ return@withNewTransaction rootFocusNode.clearFocus(force, refreshFocusEvents)
+ }
- // If this hierarchy had focus before clearing it, it indicates that the host view has
- // focus. So after clearing focus within the compose hierarchy, we should restore focus
- // to the root focus modifier to maintain consistency with the host view.
- val rootInitialState = rootFocusNode.focusState
- if (rootFocusNode.clearFocus(force, refreshFocusEvents)) {
- rootFocusNode.focusState = when (rootInitialState) {
- Active, ActiveParent, Captured -> Active
- Inactive -> Inactive
- }
- }
+ if (clearedFocusSuccessfully && clearOwnerFocus) {
+ onClearFocusForOwner.invoke()
}
}
@@ -162,38 +187,45 @@
*
* @return true if focus was moved successfully. false if the focused item is unchanged.
*/
- @OptIn(ExperimentalComposeUiApi::class)
override fun moveFocus(focusDirection: FocusDirection): Boolean {
+ // moveFocus is an API that was added to compose, but isn't available in the classic view
+ // system, so for now we only search among compose items and don't support moveFocus for
+ // interop scenarios.
+ val movedFocus = focusSearch(focusDirection, null) {
+ it.requestFocus(focusDirection) ?: false
+ } ?: return false
- // If there is no active node in this sub-hierarchy, we can't move focus.
- val source = rootFocusNode.findActiveFocusNode() ?: return false
+ // To wrap focus around, we clear focus and request initial focus.
+ if (!movedFocus && focusDirection.supportsWrapAroundFocus()) {
+ clearFocus(force = false, refreshFocusEvents = true, clearOwnerFocus = false)
+ return takeFocus(focusDirection, previouslyFocusedRect = null)
+ }
- // Check if a custom focus traversal order is specified.
- source.customFocusSearch(focusDirection, layoutDirection).also {
- if (it !== Default) {
- return it !== Cancel && it.focus()
+ return movedFocus
+ }
+
+ override fun focusSearch(
+ focusDirection: FocusDirection,
+ focusedRect: Rect?,
+ onFound: (FocusTargetNode) -> Boolean
+ ): Boolean? {
+ val source = rootFocusNode.findActiveFocusNode()?.also {
+ // Check if a custom focus traversal order is specified.
+ when (val customDestination = it.customFocusSearch(focusDirection, layoutDirection())) {
+ @OptIn(ExperimentalComposeUiApi::class)
+ Cancel -> return null
+ Default -> { /* Do Nothing */ }
+ else -> return customDestination.findFocusTargetNode(onFound)
}
}
- var isCancelled = false
- val foundNextItem =
- rootFocusNode.focusSearch(focusDirection, layoutDirection) { destination ->
- if (destination == source) return@focusSearch false
- checkNotNull(destination.nearestAncestor(Nodes.FocusTarget)) {
- "Focus search landed at the root."
- }
- // If we found a potential next item, move focus to it.
- // Returning true ends focus search.
- focusTransactionManager.withNewTransaction {
- when (destination.performCustomRequestFocus(focusDirection)) {
- Redirected -> true
- Cancelled, RedirectCancelled -> { isCancelled = true; true }
- None -> destination.performRequestFocus()
- }
- }
+ return rootFocusNode.focusSearch(focusDirection, layoutDirection(), focusedRect) {
+ when (it) {
+ source -> false
+ rootFocusNode -> error("Focus search landed at the root.")
+ else -> onFound(it)
}
- // If we didn't find a potential next item, try to wrap around.
- return !isCancelled && (foundNextItem || wrapAroundFocus(focusDirection))
+ }
}
/**
@@ -207,11 +239,9 @@
if (!validateKeyEvent(keyEvent)) return false
val activeFocusTarget = rootFocusNode.findActiveFocusNode()
- checkNotNull(activeFocusTarget) {
- "Event can't be processed because we do not have an active focus target."
- }
- val focusedKeyInputNode = activeFocusTarget.lastLocalKeyInputNode()
- ?: activeFocusTarget.nearestAncestor(Nodes.KeyInput)?.node
+ val focusedKeyInputNode = activeFocusTarget?.lastLocalKeyInputNode()
+ ?: activeFocusTarget?.nearestAncestor(Nodes.KeyInput)?.node
+ ?: rootFocusNode.nearestAncestor(Nodes.KeyInput)?.node
focusedKeyInputNode?.traverseAncestors(
type = Nodes.KeyInput,
@@ -270,6 +300,18 @@
focusInvalidationManager.scheduleInvalidation(node)
}
+ /**
+ * At the end of the invalidations, we need to ensure that the focus system is in a valid state.
+ */
+ private fun invalidateOwnerFocusState() {
+ // If an active item is removed, we currently clear focus from the hierarchy. We don't
+ // clear focus from the root because that could cause initial focus logic to be re-run.
+ // Now that all the invalidations are complete, we run owner.clearFocus() if needed.
+ if (rootFocusNode.focusState == FocusStateImpl.Inactive) {
+ onClearFocusForOwner()
+ }
+ }
+
private inline fun <reified T : DelegatableNode> DelegatableNode.traverseAncestors(
type: NodeKind<T>,
onPreVisit: (T) -> Unit,
@@ -289,6 +331,9 @@
return rootFocusNode.findActiveFocusNode()?.focusRect()
}
+ override val rootState: FocusState
+ get() = rootFocusNode.focusState
+
private fun DelegatableNode.lastLocalKeyInputNode(): Modifier.Node? {
var focusedKeyInputNode: Modifier.Node? = null
visitLocalDescendants(Nodes.FocusTarget or Nodes.KeyInput) { modifierNode ->
@@ -299,26 +344,13 @@
return focusedKeyInputNode
}
- // TODO(b/144116848): This is a hack to make Next/Previous wrap around. This must be
- // replaced by code that sends the move request back to the view system. The view system
- // will then pass focus to other views, and ultimately return back to this compose view.
- private fun wrapAroundFocus(focusDirection: FocusDirection): Boolean {
- // Wrap is not supported when this sub-hierarchy doesn't have focus.
- if (!rootFocusNode.focusState.hasFocus || rootFocusNode.focusState.isFocused) return false
-
- // Next and Previous wraps around.
- when (focusDirection) {
- Next, Previous -> {
- // Clear Focus to send focus the root node.
- clearFocus(force = false)
- if (!rootFocusNode.focusState.isFocused) return false
-
- // Wrap around by calling moveFocus after the root gains focus.
- return moveFocus(focusDirection)
- }
- // We only wrap-around for 1D Focus search.
- else -> return false
- }
+ /**
+ * focus search in the Android framework wraps around for 1D focus search, but not for 2D focus
+ * search. This is a helper function that can be used to determine whether we should wrap around.
+ */
+ private fun FocusDirection.supportsWrapAroundFocus(): Boolean = when (this) {
+ Next, Previous -> true
+ else -> false
}
// TODO(b/307580000) Factor this out into a class to manage key inputs.
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusRequester.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusRequester.kt
index 97d7357..8c11a94 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusRequester.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusRequester.kt
@@ -24,7 +24,6 @@
import androidx.compose.ui.node.Nodes
import androidx.compose.ui.node.visitChildren
-@Suppress("ConstPropertyName")
private const val FocusRequesterNotInitialized = """
FocusRequester is not initialized. Here are some possible fixes:
@@ -34,7 +33,6 @@
response to some event. Eg Modifier.clickable { focusRequester.requestFocus() }
"""
-@Suppress("ConstPropertyName")
private const val InvalidFocusRequesterInvocation = """
Please check whether the focusRequester is FocusRequester.Cancel or FocusRequester.Default
before invoking any functions on the focusRequester.
@@ -66,16 +64,15 @@
}
// TODO(b/245755256): Consider making this API Public.
- internal fun focus(): Boolean {
+ internal fun focus(): Boolean = findFocusTargetNode { it.requestFocus() }
+
+ internal fun findFocusTargetNode(onFound: (FocusTargetNode) -> Boolean): Boolean {
@OptIn(ExperimentalComposeUiApi::class)
return findFocusTarget { focusTarget ->
- val focusProperties = focusTarget.fetchFocusProperties()
- if (focusProperties.canFocus) {
- focusTarget.requestFocus()
+ if (focusTarget.fetchFocusProperties().canFocus) {
+ onFound(focusTarget)
} else {
- focusTarget.findChildCorrespondingToFocusEnter(Enter) {
- it.requestFocus()
- }
+ focusTarget.findChildCorrespondingToFocusEnter(Enter, onFound)
}
}
}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusRequesterModifierNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusRequesterModifierNode.kt
index 4d95db3..cb36d0e 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusRequesterModifierNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusRequesterModifierNode.kt
@@ -38,8 +38,7 @@
@OptIn(ExperimentalComposeUiApi::class)
fun FocusRequesterModifierNode.requestFocus(): Boolean {
visitSelfAndChildren(Nodes.FocusTarget) { focusTarget ->
- val focusProperties = focusTarget.fetchFocusProperties()
- return if (focusProperties.canFocus) {
+ return if (focusTarget.fetchFocusProperties().canFocus) {
focusTarget.requestFocus()
} else {
focusTarget.findChildCorrespondingToFocusEnter(Enter) {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTargetNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTargetNode.kt
index ea6ba20..489b51e 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTargetNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTargetNode.kt
@@ -84,13 +84,22 @@
// Clear focus from the current FocusTarget.
// This currently clears focus from the entire hierarchy, but we can change the
// implementation so that focus is sent to the immediate focus parent.
- Active, Captured -> requireOwner().focusOwner.clearFocus(force = true)
-
- // If an ActiveParent is deactivated, the entire subtree containing focus is
- // deactivated, which means the Active node will also receive an onReset() call.
- // This triggers a clearFocus call, which will notify all the focus event nodes
- // associated with this FocusTargetNode.
- ActiveParent, Inactive -> {}
+ Active, Captured -> {
+ requireOwner().focusOwner.clearFocus(
+ force = true,
+ refreshFocusEvents = true,
+ clearOwnerFocus = false
+ )
+ // We don't clear the owner's focus yet, because this could trigger an initial
+ // focus scenario after the focus is cleared. Instead, we schedule invalidation
+ // after onApplyChanges. The FocusInvalidationManager contains the invalidation
+ // logic and calls clearFocus() on the owner after all the nodes in the hierarchy
+ // are invalidated.
+ invalidateFocusTarget()
+ }
+ // This node might be reused, so reset the state to Inactive.
+ ActiveParent -> requireTransactionManager().withNewTransaction { focusState = Inactive }
+ Inactive -> {}
}
// This node might be reused, so we reset its state.
committedFocusState = null
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTransactions.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTransactions.kt
index 88cc1ee..d585d28 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTransactions.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTransactions.kt
@@ -30,6 +30,7 @@
import androidx.compose.ui.node.Nodes.FocusTarget
import androidx.compose.ui.node.nearestAncestor
import androidx.compose.ui.node.observeReads
+import androidx.compose.ui.node.requireOwner
/**
* Request focus for this node.
@@ -39,12 +40,14 @@
* [FocusNode][FocusTargetNode]'s parent [FocusNode][FocusTargetNode].
*/
@OptIn(ExperimentalComposeUiApi::class)
-internal fun FocusTargetNode.requestFocus(): Boolean {
+internal fun FocusTargetNode.requestFocus(): Boolean = requestFocus(Enter) ?: false
+
+internal fun FocusTargetNode.requestFocus(focusDirection: FocusDirection): Boolean? {
return requireTransactionManager().withNewTransaction {
- when (performCustomRequestFocus(Enter)) {
+ when (performCustomRequestFocus(focusDirection)) {
None -> performRequestFocus()
Redirected -> true
- Cancelled, RedirectCancelled -> false
+ Cancelled, RedirectCancelled -> null
}
}
}
@@ -244,7 +247,7 @@
}
private fun FocusTargetNode.requestFocusForOwner(): Boolean {
- return coordinator?.layoutNode?.owner?.requestFocus() ?: error("Owner not initialized.")
+ return requireOwner().focusOwner.requestFocusForOwner(null, null)
}
private fun FocusTargetNode.requireActiveChild(): FocusTargetNode {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTraversal.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTraversal.kt
index e0f38c5..7660e54 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTraversal.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTraversal.kt
@@ -91,6 +91,7 @@
*
* @param focusDirection The requested direction to move focus.
* @param layoutDirection Whether the layout is RTL or LTR.
+ * @param previouslyFocusedRect The bounds of the previously focused item.
* @param onFound This lambda is invoked if focus search finds the next focus node.
* @return if no focus node is found, we return false. If we receive a cancel, we return null
* otherwise we return the result of [onFound].
@@ -99,16 +100,19 @@
internal fun FocusTargetNode.focusSearch(
focusDirection: FocusDirection,
layoutDirection: LayoutDirection,
+ previouslyFocusedRect: Rect?,
onFound: (FocusTargetNode) -> Boolean
-): Boolean {
+): Boolean? {
return when (focusDirection) {
Next, Previous -> oneDimensionalFocusSearch(focusDirection, onFound)
- Left, Right, Up, Down -> twoDimensionalFocusSearch(focusDirection, onFound) ?: false
+ Left, Right, Up, Down ->
+ twoDimensionalFocusSearch(focusDirection, previouslyFocusedRect, onFound)
@OptIn(ExperimentalComposeUiApi::class)
Enter -> {
// we search among the children of the active item.
val direction = when (layoutDirection) { Rtl -> Left; Ltr -> Right }
- findActiveFocusNode()?.twoDimensionalFocusSearch(direction, onFound) ?: false
+ findActiveFocusNode()
+ ?.twoDimensionalFocusSearch(direction, previouslyFocusedRect, onFound)
}
@OptIn(ExperimentalComposeUiApi::class)
Exit -> findActiveFocusNode()?.findNonDeactivatedParent().let {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusSearch.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusSearch.kt
index 987cc9a..d883a49 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusSearch.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusSearch.kt
@@ -51,10 +51,17 @@
*/
internal fun FocusTargetNode.twoDimensionalFocusSearch(
direction: FocusDirection,
+ previouslyFocusedRect: Rect?,
onFound: (FocusTargetNode) -> Boolean
): Boolean? {
when (focusState) {
- Inactive -> return if (fetchFocusProperties().canFocus) onFound.invoke(this) else false
+ Inactive -> return if (fetchFocusProperties().canFocus) {
+ onFound.invoke(this)
+ } else if (previouslyFocusedRect == null) {
+ findChildCorrespondingToFocusEnter(direction, onFound)
+ } else {
+ searchChildren(previouslyFocusedRect, direction, onFound)
+ }
ActiveParent -> {
val focusedChild = activeChild ?: error(NoActiveChild)
// For 2D focus search we only search among siblings. You have to use DPad Center or
@@ -66,15 +73,20 @@
ActiveParent -> {
// If the focusedChild is an intermediate parent, we search among its children.
- val found = focusedChild.twoDimensionalFocusSearch(direction, onFound)
+ val found = focusedChild
+ .twoDimensionalFocusSearch(direction, previouslyFocusedRect, onFound)
if (found != false) return found
// We search among the siblings of the parent.
- return generateAndSearchChildren(focusedChild.activeNode(), direction, onFound)
+ return generateAndSearchChildren(
+ focusedChild.activeNode().focusRect(),
+ direction,
+ onFound
+ )
}
// Search for the next eligible sibling.
Active, Captured ->
- return generateAndSearchChildren(focusedChild, direction, onFound)
+ return generateAndSearchChildren(focusedChild.focusRect(), direction, onFound)
Inactive -> error(NoActiveChild)
}
}
@@ -132,7 +144,7 @@
// Search among your children for the next child.
// If the next child is not found, generate more children by requesting a beyondBoundsLayout.
private fun FocusTargetNode.generateAndSearchChildren(
- focusedItem: FocusTargetNode,
+ focusedItem: Rect,
direction: FocusDirection,
onFound: (FocusTargetNode) -> Boolean
): Boolean {
@@ -152,7 +164,7 @@
}
private fun FocusTargetNode.searchChildren(
- focusedItem: FocusTargetNode,
+ focusedItem: Rect,
direction: FocusDirection,
onFound: (FocusTargetNode) -> Boolean
): Boolean {
@@ -162,7 +174,7 @@
}
}
while (children.isNotEmpty()) {
- val nextItem = children.findBestCandidate(focusedItem.focusRect(), direction)
+ val nextItem = children.findBestCandidate(focusedItem, direction)
?: return false
// If the result is not deactivated, this is a valid next item.
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/HitPathTracker.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/HitPathTracker.kt
index 1b0994a..e792460 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/HitPathTracker.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/HitPathTracker.kt
@@ -380,30 +380,35 @@
val change = changes.valueAt(j)
if (pointerIds.contains(keyValue)) {
- // And translate their position relative to the parent coordinates, to give us a
- // change local to the PointerInputFilter's coordinates
- val historical = ArrayList<HistoricalChange>(change.historical.size)
- change.historical.fastForEach {
- historical.add(
- HistoricalChange(
- it.uptimeMillis,
- coordinates!!.localPositionOf(parentCoordinates, it.position),
- it.originalEventPosition
- )
- )
- }
+ val prevPosition = change.previousPosition
+ val currentPosition = change.position
- relevantChanges.put(keyValue, change.copy(
- previousPosition = coordinates!!.localPositionOf(
- parentCoordinates,
- change.previousPosition
- ),
- currentPosition = coordinates!!.localPositionOf(
- parentCoordinates,
- change.position
- ),
- historical = historical
- ))
+ if (prevPosition.isValid() && currentPosition.isValid()) {
+ // And translate their position relative to the parent coordinates, to give us a
+ // change local to the PointerInputFilter's coordinates
+ val historical = ArrayList<HistoricalChange>(change.historical.size)
+ change.historical.fastForEach {
+ historical.add(
+ HistoricalChange(
+ it.uptimeMillis,
+ coordinates!!.localPositionOf(parentCoordinates, it.position),
+ it.originalEventPosition
+ )
+ )
+ }
+
+ relevantChanges.put(keyValue, change.copy(
+ previousPosition = coordinates!!.localPositionOf(
+ parentCoordinates,
+ prevPosition
+ ),
+ currentPosition = coordinates!!.localPositionOf(
+ parentCoordinates,
+ currentPosition
+ ),
+ historical = historical
+ ))
+ }
}
}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
index 223a4012..9df114d 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
@@ -64,7 +64,6 @@
/**
* Enable to log changes to the LayoutNode tree. This logging is quite chatty.
*/
-@Suppress("ConstPropertyName")
private const val DebugChanges = false
private val DefaultDensity = Density(1f)
@@ -1061,7 +1060,11 @@
private fun invalidateFocusOnDetach() {
nodes.tailToHead(FocusTarget) {
if (it.focusState.isFocused) {
- requireOwner().focusOwner.clearFocus(force = true, refreshFocusEvents = false)
+ requireOwner().focusOwner.clearFocus(
+ force = true,
+ refreshFocusEvents = false,
+ clearOwnerFocus = true
+ )
it.scheduleInvalidationForFocusEvents()
}
}
@@ -1373,6 +1376,7 @@
/**
* Constant used by [placeOrder].
*/
+ @Suppress("ConstPropertyName")
internal const val NotPlacedPlaceOrder = Int.MAX_VALUE
/**
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeCoordinator.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeCoordinator.kt
index 34ee53c3..4e6de06 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeCoordinator.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeCoordinator.kt
@@ -1093,9 +1093,13 @@
fun shouldSharePointerInputWithSiblings(): Boolean {
val start = headNode(Nodes.PointerInput.includeSelfInTraversal) ?: return false
- start.visitLocalDescendants(Nodes.PointerInput) {
- if (it.sharePointerInputWithSiblings()) return true
+
+ if (start.isAttached) {
+ start.visitLocalDescendants(Nodes.PointerInput) {
+ if (it.sharePointerInputWithSiblings()) return true
+ }
}
+
return false
}
diff --git a/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/platform/SkiaBasedOwner.skiko.kt b/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/platform/SkiaBasedOwner.skiko.kt
index f0c5115..596a478 100644
--- a/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/platform/SkiaBasedOwner.skiko.kt
+++ b/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/platform/SkiaBasedOwner.skiko.kt
@@ -76,7 +76,6 @@
import androidx.compose.ui.node.RootForTest
import androidx.compose.ui.semantics.EmptySemanticsElement
import androidx.compose.ui.semantics.SemanticsOwner
-import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.font.createFontFamilyResolver
import androidx.compose.ui.text.input.TextInputService
import androidx.compose.ui.text.platform.FontLoader
@@ -92,7 +91,6 @@
@OptIn(
ExperimentalComposeUiApi::class,
- ExperimentalTextApi::class,
InternalCoreApi::class,
InternalComposeUiApi::class
)
@@ -100,7 +98,7 @@
private val platformInputService: PlatformInput,
private val component: PlatformComponent,
density: Density = Density(1f, 1f),
- coroutineContext: CoroutineContext,
+ override val coroutineContext: CoroutineContext,
val isPopup: Boolean = false,
val isFocusable: Boolean = true,
val onDismissRequest: (() -> Unit)? = null,
@@ -126,12 +124,12 @@
private val semanticsModifier = EmptySemanticsElement
- override val focusOwner: FocusOwner = FocusOwnerImpl {
- registerOnEndApplyChangesListener(it)
- }.apply {
- // TODO(demin): support RTL [onRtlPropertiesChanged]
- layoutDirection = LayoutDirection.Ltr
- }
+ override val focusOwner: FocusOwner = FocusOwnerImpl(
+ onRequestApplyChangesListener = ::registerOnEndApplyChangesListener,
+ onRequestFocusForOwner = { _, _ -> true }, // TODO request focus from framework.
+ onClearFocusForOwner = {}, // TODO clear focus from framework.
+ layoutDirection = { layoutDirection } // TODO(demin): support RTL [onRtlPropertiesChanged].
+ )
// TODO: Set the input mode. For now we don't support touch mode, (always in Key mode).
private val _inputModeManager = InputModeManagerImpl(
@@ -188,8 +186,6 @@
.onKeyEvent(onKeyEvent)
}
- override val coroutineContext: CoroutineContext = coroutineContext
-
override val rootForTest = this
override val snapshotObserver = OwnerSnapshotObserver { command ->
@@ -204,7 +200,8 @@
snapshotObserver.startObserving()
root.attach(this)
focusOwner.focusTransactionManager.withNewTransaction {
- focusOwner.takeFocus()
+ // TODO instead of taking focus here, call this when the owner gets focused.
+ focusOwner.takeFocus(Enter, previouslyFocusedRect = null)
}
}
diff --git a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/motion/widget/MotionLayout.java b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/motion/widget/MotionLayout.java
index 9da084d..1c10668 100644
--- a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/motion/widget/MotionLayout.java
+++ b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/motion/widget/MotionLayout.java
@@ -1517,12 +1517,10 @@
mBeginState = mScene.getStartId();
mEndState = mScene.getEndId();
}
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT || isAttachedToWindow()) {
+ if (isAttachedToWindow()) {
try {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- Display display = getDisplay();
- mPreviouseRotation = (display == null) ? 0 : display.getRotation();
- }
+ Display display = getDisplay();
+ mPreviouseRotation = (display == null) ? 0 : display.getRotation();
if (mScene != null) {
ConstraintSet cSet = mScene.getConstraintSet(mCurrentState);
@@ -1576,17 +1574,6 @@
}
/**
- * Returns true if the provided view is currently attached to a window.
- */
- @Override
- public boolean isAttachedToWindow() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- return super.isAttachedToWindow();
- }
- return getWindowToken() != null;
- }
-
- /**
* Set the State of the Constraint layout. Causing it to load a particular ConstraintSet.
* for states with variants the variant with matching
* width and height constraintSet will be chosen
diff --git a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/Barrier.java b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/Barrier.java
index 2007e11..15d7e02 100644
--- a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/Barrier.java
+++ b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/Barrier.java
@@ -18,7 +18,6 @@
import android.content.Context;
import android.content.res.TypedArray;
-import android.os.Build;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.View;
@@ -158,29 +157,19 @@
private void updateType(ConstraintWidget widget, int type, boolean isRtl) {
mResolvedType = type;
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
- // Pre JB MR1, left/right should take precedence, unless they are
- // not defined and somehow a corresponding start/end constraint exists
+
+ if (isRtl) {
+ if (mIndicatedType == START) {
+ mResolvedType = RIGHT;
+ } else if (mIndicatedType == END) {
+ mResolvedType = LEFT;
+ }
+ } else {
if (mIndicatedType == START) {
mResolvedType = LEFT;
} else if (mIndicatedType == END) {
mResolvedType = RIGHT;
}
- } else {
- // Post JB MR1, if start/end are defined, they take precedence over left/right
- if (isRtl) {
- if (mIndicatedType == START) {
- mResolvedType = RIGHT;
- } else if (mIndicatedType == END) {
- mResolvedType = LEFT;
- }
- } else {
- if (mIndicatedType == START) {
- mResolvedType = LEFT;
- } else if (mIndicatedType == END) {
- mResolvedType = RIGHT;
- }
- }
}
if (widget instanceof androidx.constraintlayout.core.widgets.Barrier) {
androidx.constraintlayout.core.widgets.Barrier barrier =
diff --git a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayout.java b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayout.java
index 24710a1..bfc5c8b 100644
--- a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayout.java
+++ b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayout.java
@@ -1327,11 +1327,6 @@
int resolvedGuideBegin = layoutParams.mResolvedGuideBegin;
int resolvedGuideEnd = layoutParams.mResolvedGuideEnd;
float resolvedGuidePercent = layoutParams.mResolvedGuidePercent;
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
- resolvedGuideBegin = layoutParams.guideBegin;
- resolvedGuideEnd = layoutParams.guideEnd;
- resolvedGuidePercent = layoutParams.guidePercent;
- }
if (resolvedGuidePercent != UNSET) {
guideline.setGuidePercent(resolvedGuidePercent);
} else if (resolvedGuideBegin != UNSET) {
@@ -1349,33 +1344,6 @@
int resolveGoneRightMargin = layoutParams.mResolveGoneRightMargin;
float resolvedHorizontalBias = layoutParams.mResolvedHorizontalBias;
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
- // Pre JB MR1, left/right should take precedence, unless they are
- // not defined and somehow a corresponding start/end constraint exists
- resolvedLeftToLeft = layoutParams.leftToLeft;
- resolvedLeftToRight = layoutParams.leftToRight;
- resolvedRightToLeft = layoutParams.rightToLeft;
- resolvedRightToRight = layoutParams.rightToRight;
- resolveGoneLeftMargin = layoutParams.goneLeftMargin;
- resolveGoneRightMargin = layoutParams.goneRightMargin;
- resolvedHorizontalBias = layoutParams.horizontalBias;
-
- if (resolvedLeftToLeft == UNSET && resolvedLeftToRight == UNSET) {
- if (layoutParams.startToStart != UNSET) {
- resolvedLeftToLeft = layoutParams.startToStart;
- } else if (layoutParams.startToEnd != UNSET) {
- resolvedLeftToRight = layoutParams.startToEnd;
- }
- }
- if (resolvedRightToLeft == UNSET && resolvedRightToRight == UNSET) {
- if (layoutParams.endToStart != UNSET) {
- resolvedRightToLeft = layoutParams.endToStart;
- } else if (layoutParams.endToEnd != UNSET) {
- resolvedRightToRight = layoutParams.endToEnd;
- }
- }
- }
-
// Circular constraint
if (layoutParams.circleConstraint != UNSET) {
ConstraintWidget target = idToWidget.get(layoutParams.circleConstraint);
diff --git a/coordinatorlayout/coordinatorlayout/src/androidTest/java/androidx/coordinatorlayout/widget/CoordinatorLayoutTouchEventTest.java b/coordinatorlayout/coordinatorlayout/src/androidTest/java/androidx/coordinatorlayout/widget/CoordinatorLayoutTouchEventTest.java
index 9535979..b7c7bd0 100644
--- a/coordinatorlayout/coordinatorlayout/src/androidTest/java/androidx/coordinatorlayout/widget/CoordinatorLayoutTouchEventTest.java
+++ b/coordinatorlayout/coordinatorlayout/src/androidTest/java/androidx/coordinatorlayout/widget/CoordinatorLayoutTouchEventTest.java
@@ -29,7 +29,6 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
-import android.os.Build;
import android.os.SystemClock;
import android.view.MotionEvent;
import android.view.TouchDelegate;
@@ -560,11 +559,7 @@
@Override
public String toString() {
String message = "MotionEvent#getAction() == ";
- if (Build.VERSION.SDK_INT >= 19) {
- return message + MotionEvent.actionToString(mAction);
- } else {
- return message + mAction;
- }
+ return message + MotionEvent.actionToString(mAction);
}
}
diff --git a/core/core-graphics-integration-tests/testapp/src/main/java/androidx/core/graphics/sample/GraphicsSampleActivity.kt b/core/core-graphics-integration-tests/testapp/src/main/java/androidx/core/graphics/sample/GraphicsSampleActivity.kt
index 0c191e8..3021532 100644
--- a/core/core-graphics-integration-tests/testapp/src/main/java/androidx/core/graphics/sample/GraphicsSampleActivity.kt
+++ b/core/core-graphics-integration-tests/testapp/src/main/java/androidx/core/graphics/sample/GraphicsSampleActivity.kt
@@ -4,15 +4,12 @@
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.drawable.BitmapDrawable
-import android.os.Build
import android.os.Bundle
import android.view.View
import android.widget.ImageView
-import androidx.annotation.RequiresApi
import androidx.core.graphics.BitmapCompat
class GraphicsSampleActivity : Activity() {
- @RequiresApi(Build.VERSION_CODES.KITKAT)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
diff --git a/core/core-ktx/src/main/java/androidx/core/os/Bundle.kt b/core/core-ktx/src/main/java/androidx/core/os/Bundle.kt
index 9bda3bb..601fbf8 100644
--- a/core/core-ktx/src/main/java/androidx/core/os/Bundle.kt
+++ b/core/core-ktx/src/main/java/androidx/core/os/Bundle.kt
@@ -91,8 +91,8 @@
is Serializable -> putSerializable(key, value)
else -> {
- if (Build.VERSION.SDK_INT >= 18 && value is IBinder) {
- BundleApi18ImplKt.putBinder(this, key, value)
+ if (value is IBinder) {
+ this.putBinder(key, value)
} else if (Build.VERSION.SDK_INT >= 21 && value is Size) {
BundleApi21ImplKt.putSize(this, key, value)
} else if (Build.VERSION.SDK_INT >= 21 && value is SizeF) {
@@ -111,13 +111,6 @@
*/
public fun bundleOf(): Bundle = Bundle(0)
-@RequiresApi(18)
-private object BundleApi18ImplKt {
- @DoNotInline
- @JvmStatic
- fun putBinder(bundle: Bundle, key: String, value: IBinder?) = bundle.putBinder(key, value)
-}
-
@RequiresApi(21)
private object BundleApi21ImplKt {
@DoNotInline
diff --git a/core/core-remoteviews/src/main/java/androidx/core/widget/AppWidgetManagerCompat.kt b/core/core-remoteviews/src/main/java/androidx/core/widget/AppWidgetManagerCompat.kt
index 797dd21..4573d74f 100644
--- a/core/core-remoteviews/src/main/java/androidx/core/widget/AppWidgetManagerCompat.kt
+++ b/core/core-remoteviews/src/main/java/androidx/core/widget/AppWidgetManagerCompat.kt
@@ -99,14 +99,7 @@
factory
)
}
- SDK_INT >= 16 -> {
- AppWidgetManagerApi16Impl.createExactSizeAppWidget(
- appWidgetManager,
- appWidgetId,
- factory
- )
- }
- else -> createAppWidgetFromProviderInfo(appWidgetManager, appWidgetId, factory)
+ else -> createExactSizeAppWidgetInner(appWidgetManager, appWidgetId, factory)
}
}
@@ -175,15 +168,7 @@
require(dpSizes.size <= 16) { "At most 16 sizes may be provided" }
return when {
SDK_INT >= 31 -> AppWidgetManagerApi31Impl.createResponsiveSizeAppWidget(dpSizes, factory)
- SDK_INT >= 16 -> {
- AppWidgetManagerApi16Impl.createResponsiveSizeAppWidget(
- appWidgetManager,
- appWidgetId,
- dpSizes,
- factory
- )
- }
- else -> createAppWidgetFromProviderInfo(appWidgetManager, appWidgetId, factory)
+ else -> createResponsiveSizeAppWidgetInner(appWidgetManager, appWidgetId, dpSizes, factory)
}
}
@@ -208,11 +193,7 @@
"App widget SizeF sizes not found in the options bundle, falling back to the " +
"min/max sizes"
)
- return AppWidgetManagerApi16Impl.createExactSizeAppWidget(
- appWidgetManager,
- appWidgetId,
- factory
- )
+ return createExactSizeAppWidgetInner(appWidgetManager, appWidgetId, factory)
}
return RemoteViews(sizes.associateWith { factory(it.toSizeFCompat()) })
}
@@ -228,90 +209,85 @@
private fun SizeF.toSizeFCompat() = SizeFCompat.toSizeFCompat(this)
}
-@RequiresApi(16)
-private object AppWidgetManagerApi16Impl {
- @DoNotInline
- fun createExactSizeAppWidget(
- appWidgetManager: AppWidgetManager,
- appWidgetId: Int,
- factory: (SizeFCompat) -> RemoteViews
- ): RemoteViews {
- val (landscapeSize, portraitSize) =
- getSizesFromOptionsBundle(appWidgetManager, appWidgetId)
- ?: run {
- Log.w(
- LogTag,
- "App widget sizes not found in the options bundle, falling back to the " +
- "provider size"
- )
- return createAppWidgetFromProviderInfo(appWidgetManager, appWidgetId, factory)
- }
- return createAppWidget(landscapeSize = landscapeSize, portraitSize = portraitSize, factory)
- }
+internal fun createExactSizeAppWidgetInner(
+ appWidgetManager: AppWidgetManager,
+ appWidgetId: Int,
+ factory: (SizeFCompat) -> RemoteViews
+): RemoteViews {
+ val (landscapeSize, portraitSize) =
+ getSizesFromOptionsBundle(appWidgetManager, appWidgetId)
+ ?: run {
+ Log.w(
+ LogTag,
+ "App widget sizes not found in the options bundle, falling back to the " +
+ "provider size"
+ )
+ return createAppWidgetFromProviderInfo(appWidgetManager, appWidgetId, factory)
+ }
+ return createAppWidget(landscapeSize = landscapeSize, portraitSize = portraitSize, factory)
+}
- @DoNotInline
- fun createResponsiveSizeAppWidget(
- appWidgetManager: AppWidgetManager,
- appWidgetId: Int,
- sizes: Collection<SizeFCompat>,
- factory: (SizeFCompat) -> RemoteViews
- ): RemoteViews {
- val minSize = sizes.minByOrNull { it.area } ?: error("Sizes cannot be empty")
- val (landscapeSize, portraitSize) =
- getSizesFromOptionsBundle(appWidgetManager, appWidgetId)
- ?: run {
- Log.w(
- LogTag,
- "App widget sizes not found in the options bundle, falling back to the " +
- "smallest supported size ($minSize)"
- )
- LandscapePortraitSizes(minSize, minSize)
- }
- val effectiveLandscapeSize =
- sizes.filter { landscapeSize approxDominates it }.maxByOrNull { it.area } ?: minSize
- val effectivePortraitSize =
- sizes.filter { portraitSize approxDominates it }.maxByOrNull { it.area } ?: minSize
- return createAppWidget(
- landscapeSize = effectiveLandscapeSize,
- portraitSize = effectivePortraitSize,
- factory
+internal fun createResponsiveSizeAppWidgetInner(
+ appWidgetManager: AppWidgetManager,
+ appWidgetId: Int,
+ sizes: Collection<SizeFCompat>,
+ factory: (SizeFCompat) -> RemoteViews
+): RemoteViews {
+ val minSize = sizes.minByOrNull { it.area } ?: error("Sizes cannot be empty")
+ val (landscapeSize, portraitSize) =
+ getSizesFromOptionsBundle(appWidgetManager, appWidgetId)
+ ?: run {
+ Log.w(
+ LogTag,
+ "App widget sizes not found in the options bundle, falling back to the " +
+ "smallest supported size ($minSize)"
+ )
+ LandscapePortraitSizes(minSize, minSize)
+ }
+ val effectiveLandscapeSize =
+ sizes.filter { landscapeSize approxDominates it }.maxByOrNull { it.area } ?: minSize
+ val effectivePortraitSize =
+ sizes.filter { portraitSize approxDominates it }.maxByOrNull { it.area } ?: minSize
+ return createAppWidget(
+ landscapeSize = effectiveLandscapeSize,
+ portraitSize = effectivePortraitSize,
+ factory
+ )
+}
+
+private fun createAppWidget(
+ landscapeSize: SizeFCompat,
+ portraitSize: SizeFCompat,
+ factory: (SizeFCompat) -> RemoteViews
+): RemoteViews {
+ return if (landscapeSize == portraitSize) {
+ factory(landscapeSize)
+ } else {
+ RemoteViews(
+ /* landscape= */ factory(landscapeSize),
+ /* portrait= */ factory(portraitSize)
)
}
+}
- private fun createAppWidget(
- landscapeSize: SizeFCompat,
- portraitSize: SizeFCompat,
- factory: (SizeFCompat) -> RemoteViews
- ): RemoteViews {
- return if (landscapeSize == portraitSize) {
- factory(landscapeSize)
- } else {
- RemoteViews(
- /* landscape= */ factory(landscapeSize),
- /* portrait= */ factory(portraitSize)
- )
- }
- }
+private fun getSizesFromOptionsBundle(
+ appWidgetManager: AppWidgetManager,
+ appWidgetId: Int
+): LandscapePortraitSizes? {
+ val options = appWidgetManager.getAppWidgetOptions(appWidgetId)
- private fun getSizesFromOptionsBundle(
- appWidgetManager: AppWidgetManager,
- appWidgetId: Int
- ): LandscapePortraitSizes? {
- val options = appWidgetManager.getAppWidgetOptions(appWidgetId)
+ val portWidthDp = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, -1)
+ val portHeightDp = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, -1)
+ if (portWidthDp < 0 || portHeightDp < 0) return null
- val portWidthDp = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, -1)
- val portHeightDp = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, -1)
- if (portWidthDp < 0 || portHeightDp < 0) return null
+ val landWidthDp = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, -1)
+ val landHeightDp = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, -1)
+ if (landWidthDp < 0 || landHeightDp < 0) return null
- val landWidthDp = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, -1)
- val landHeightDp = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, -1)
- if (landWidthDp < 0 || landHeightDp < 0) return null
-
- return LandscapePortraitSizes(
- landscape = SizeFCompat(landWidthDp.toFloat(), landHeightDp.toFloat()),
- portrait = SizeFCompat(portWidthDp.toFloat(), portHeightDp.toFloat())
- )
- }
+ return LandscapePortraitSizes(
+ landscape = SizeFCompat(landWidthDp.toFloat(), landHeightDp.toFloat()),
+ portrait = SizeFCompat(portWidthDp.toFloat(), portHeightDp.toFloat())
+ )
}
internal fun createAppWidgetFromProviderInfo(
diff --git a/core/core-remoteviews/src/main/java/androidx/core/widget/RemoteViewsCompat.kt b/core/core-remoteviews/src/main/java/androidx/core/widget/RemoteViewsCompat.kt
index b39eeef1..7924af8 100644
--- a/core/core-remoteviews/src/main/java/androidx/core/widget/RemoteViewsCompat.kt
+++ b/core/core-remoteviews/src/main/java/androidx/core/widget/RemoteViewsCompat.kt
@@ -728,8 +728,7 @@
@JvmStatic
public fun RemoteViews.setImageViewImageAlpha(@IdRes viewId: Int, alpha: Int) {
// Note: setImageAlpha was added and is preferred to setAlpha since API 16.
- val methodName = if (Build.VERSION.SDK_INT >= 16) "setImageAlpha" else "setAlpha"
- setInt(viewId, methodName, alpha)
+ setInt(viewId, "setImageAlpha", alpha)
}
/**
diff --git a/core/core/api/current.txt b/core/core/api/current.txt
index 3cd47b6..1f15519 100644
--- a/core/core/api/current.txt
+++ b/core/core/api/current.txt
@@ -4016,9 +4016,11 @@
method public static CharSequence? getInitialSelectedText(android.view.inputmethod.EditorInfo, int);
method public static CharSequence? getInitialTextAfterCursor(android.view.inputmethod.EditorInfo, int, int);
method public static CharSequence? getInitialTextBeforeCursor(android.view.inputmethod.EditorInfo, int, int);
+ method public static boolean isStylusHandwritingEnabled(android.view.inputmethod.EditorInfo);
method public static void setContentMimeTypes(android.view.inputmethod.EditorInfo, String![]?);
method public static void setInitialSurroundingSubText(android.view.inputmethod.EditorInfo, CharSequence, int);
method public static void setInitialSurroundingText(android.view.inputmethod.EditorInfo, CharSequence);
+ method public static void setStylusHandwritingEnabled(android.view.inputmethod.EditorInfo, boolean);
field public static final int IME_FLAG_FORCE_ASCII = -2147483648; // 0x80000000
field public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 16777216; // 0x1000000
}
diff --git a/core/core/api/restricted_current.txt b/core/core/api/restricted_current.txt
index 34cf16c..c221686 100644
--- a/core/core/api/restricted_current.txt
+++ b/core/core/api/restricted_current.txt
@@ -4506,9 +4506,11 @@
method public static CharSequence? getInitialSelectedText(android.view.inputmethod.EditorInfo, int);
method public static CharSequence? getInitialTextAfterCursor(android.view.inputmethod.EditorInfo, int, int);
method public static CharSequence? getInitialTextBeforeCursor(android.view.inputmethod.EditorInfo, int, int);
+ method public static boolean isStylusHandwritingEnabled(android.view.inputmethod.EditorInfo);
method public static void setContentMimeTypes(android.view.inputmethod.EditorInfo, String![]?);
method public static void setInitialSurroundingSubText(android.view.inputmethod.EditorInfo, CharSequence, int);
method public static void setInitialSurroundingText(android.view.inputmethod.EditorInfo, CharSequence);
+ method public static void setStylusHandwritingEnabled(android.view.inputmethod.EditorInfo, boolean);
field public static final int IME_FLAG_FORCE_ASCII = -2147483648; // 0x80000000
field public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 16777216; // 0x1000000
}
diff --git a/core/core/src/androidTest/java/androidx/core/app/NotificationCompatTest.java b/core/core/src/androidTest/java/androidx/core/app/NotificationCompatTest.java
index 454cfcd..d0e1c235 100644
--- a/core/core/src/androidTest/java/androidx/core/app/NotificationCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/app/NotificationCompatTest.java
@@ -286,21 +286,15 @@
NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext);
Notification nDefault = builder.build();
- if (Build.VERSION.SDK_INT >= 19) {
- assertThat(NotificationCompat.getShowWhen(nDefault)).isTrue();
- }
+ assertThat(NotificationCompat.getShowWhen(nDefault)).isTrue();
// test true
Notification nTrue = builder.setShowWhen(true).build();
- if (Build.VERSION.SDK_INT >= 19) {
- assertTrue(NotificationCompat.getShowWhen(nTrue));
- }
+ assertTrue(NotificationCompat.getShowWhen(nTrue));
// test false
Notification nFalse = builder.setShowWhen(false).build();
- if (Build.VERSION.SDK_INT >= 19) {
- assertFalse(NotificationCompat.getShowWhen(nFalse));
- }
+ assertFalse(NotificationCompat.getShowWhen(nFalse));
}
@Test
@@ -309,15 +303,11 @@
// test true
Notification nTrue = builder.setUsesChronometer(true).build();
- if (Build.VERSION.SDK_INT >= 19) {
- assertTrue(NotificationCompat.getUsesChronometer(nTrue));
- }
+ assertTrue(NotificationCompat.getUsesChronometer(nTrue));
// test false
Notification nFalse = builder.setUsesChronometer(false).build();
- if (Build.VERSION.SDK_INT >= 19) {
- assertFalse(NotificationCompat.getUsesChronometer(nFalse));
- }
+ assertFalse(NotificationCompat.getUsesChronometer(nFalse));
}
@SdkSuppress(minSdkVersion = 24)
@@ -686,12 +676,6 @@
// Add an action so that we start getting the view
builder.addAction(new NotificationCompat.Action(null, "action", null));
- // Before Jellybean, there was no big view; expect null
- if (Build.VERSION.SDK_INT < 16) {
- assertNull(builder.createHeadsUpContentView());
- return;
- }
-
// Expect the standard big notification template
RemoteViews standardView = builder.createBigContentView();
assertNotNull(standardView);
@@ -1140,16 +1124,13 @@
.setLargeIcon((Bitmap) null)
.build();
- // Extras are not populated before API 19.
- if (Build.VERSION.SDK_INT >= 19) {
- Bundle extras = NotificationCompat.getExtras(n);
- assertNotNull(extras);
- if (Build.VERSION.SDK_INT <= 23) {
- assertFalse(extras.containsKey(NotificationCompat.EXTRA_LARGE_ICON));
- } else {
- assertTrue(extras.containsKey(NotificationCompat.EXTRA_LARGE_ICON));
- assertNull(extras.get(NotificationCompat.EXTRA_LARGE_ICON));
- }
+ Bundle extras = NotificationCompat.getExtras(n);
+ assertNotNull(extras);
+ if (Build.VERSION.SDK_INT <= 23) {
+ assertFalse(extras.containsKey(NotificationCompat.EXTRA_LARGE_ICON));
+ } else {
+ assertTrue(extras.containsKey(NotificationCompat.EXTRA_LARGE_ICON));
+ assertNull(extras.get(NotificationCompat.EXTRA_LARGE_ICON));
}
if (Build.VERSION.SDK_INT >= 23) {
@@ -1167,12 +1148,10 @@
.build();
// Extras are not populated before API 19.
- if (Build.VERSION.SDK_INT >= 19) {
- Bundle extras = NotificationCompat.getExtras(n);
- assertNotNull(extras);
- assertTrue(extras.containsKey(NotificationCompat.EXTRA_LARGE_ICON));
- assertNotNull(extras.get(NotificationCompat.EXTRA_LARGE_ICON));
- }
+ Bundle extras = NotificationCompat.getExtras(n);
+ assertNotNull(extras);
+ assertTrue(extras.containsKey(NotificationCompat.EXTRA_LARGE_ICON));
+ assertNotNull(extras.get(NotificationCompat.EXTRA_LARGE_ICON));
if (Build.VERSION.SDK_INT >= 23) {
assertNotNull(n.getLargeIcon());
}
@@ -1570,13 +1549,10 @@
.setBigContentTitle("Big Content Title")
.setSummaryText("Summary Text"))
.build();
- // Extras are not populated before KITKAT
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- Bundle extras = NotificationCompat.getExtras(n);
- assertNotNull(extras);
- assertTrue(extras.containsKey(NotificationCompat.EXTRA_LARGE_ICON_BIG));
- assertNull(extras.get(NotificationCompat.EXTRA_LARGE_ICON_BIG));
- }
+ Bundle extras = NotificationCompat.getExtras(n);
+ assertNotNull(extras);
+ assertTrue(extras.containsKey(NotificationCompat.EXTRA_LARGE_ICON_BIG));
+ assertNull(extras.get(NotificationCompat.EXTRA_LARGE_ICON_BIG));
}
@SdkSuppress(minSdkVersion = 23)
@@ -2776,25 +2752,22 @@
// Test extras values. This is equivalent to creating a new NotificationCompat.Builder,
// and checking the values in it (because those are created via restoreFromCompatExtras).
- // Extras and NotificationCompatBuilder only available on API 19 and greater.
- if (Build.VERSION.SDK_INT >= 19) {
- Bundle extras = notification.extras;
+ Bundle extras = notification.extras;
- // Checks that the notification title is set to the caller name. 11 >=
- assertEquals("test name", extras.getCharSequence(NotificationCompat.EXTRA_TITLE));
- // Checks that the notification text is set to the default text (since EXTRA_TEXT isn't
- // set).
- assertEquals(
- mContext.getResources().getString(R.string.call_notification_incoming_text),
- extras.getCharSequence(NotificationCompat.EXTRA_TEXT));
+ // Checks that the notification title is set to the caller name. 11 >=
+ assertEquals("test name", extras.getCharSequence(NotificationCompat.EXTRA_TITLE));
+ // Checks that the notification text is set to the default text (since EXTRA_TEXT isn't
+ // set).
+ assertEquals(
+ mContext.getResources().getString(R.string.call_notification_incoming_text),
+ extras.getCharSequence(NotificationCompat.EXTRA_TEXT));
- // Create a new NotificationCompat Builder object based on the notification.
- // This allows us to inspect various fields, including actions.
- NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext,
- notification);
- // For versions above 11, the "Person" name from the style is applied to the title.
- assertEquals("test name", builder.mContentTitle);
- }
+ // Create a new NotificationCompat Builder object based on the notification.
+ // This allows us to inspect various fields, including actions.
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext,
+ notification);
+ // For versions above 11, the "Person" name from the style is applied to the title.
+ assertEquals("test name", builder.mContentTitle);
if (Build.VERSION.SDK_INT >= 20) {
assertNotNull(notification.actions);
@@ -2846,13 +2819,11 @@
// Checks in this section check values in the Notification's extras, which were unavailable
// prior to API 19.
- if (Build.VERSION.SDK_INT >= 19) {
- NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext,
- notification);
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext,
+ notification);
- Bundle extras = builder.getExtras();
- assertTrue(extras.getBoolean(NotificationCompat.EXTRA_CALL_IS_VIDEO));
- }
+ Bundle extras = builder.getExtras();
+ assertTrue(extras.getBoolean(NotificationCompat.EXTRA_CALL_IS_VIDEO));
// Actions were introduced in API 20.
if (Build.VERSION.SDK_INT >= 20) {
@@ -2897,27 +2868,25 @@
// Checks in this section check values in the Notification's extras, which were unavailable
// prior to API 19.
- if (Build.VERSION.SDK_INT >= 19) {
- // Test extras values. This is equivalent to creating a new NotificationCompat.Builder,
- // and checking the values in it (as those are created via restoreFromCompatExtras).
- Bundle extras = notification.extras;
+ // Test extras values. This is equivalent to creating a new NotificationCompat.Builder,
+ // and checking the values in it (as those are created via restoreFromCompatExtras).
+ Bundle extras = notification.extras;
- // Checks that the notification title is set to the caller name. 11 >=
- assertEquals("test name", extras.getCharSequence(NotificationCompat.EXTRA_TITLE));
+ // Checks that the notification title is set to the caller name. 11 >=
+ assertEquals("test name", extras.getCharSequence(NotificationCompat.EXTRA_TITLE));
- // Checks that the notification text is set to the default text (since EXTRA_TEXT isn't
- // set). 11 >=
- assertEquals(mContext.getResources().getString(R.string.call_notification_ongoing_text),
- extras.getCharSequence(NotificationCompat.EXTRA_TEXT));
+ // Checks that the notification text is set to the default text (since EXTRA_TEXT isn't
+ // set). 11 >=
+ assertEquals(mContext.getResources().getString(R.string.call_notification_ongoing_text),
+ extras.getCharSequence(NotificationCompat.EXTRA_TEXT));
- // Create a new NotificationCompat Builder object based on the notification.
- // This allows us to inspect various fields, including actions.
- NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext,
- notification);
+ // Create a new NotificationCompat Builder object based on the notification.
+ // This allows us to inspect various fields, including actions.
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext,
+ notification);
- // For versions above 11, the "Person" name from the style is applied to the title.
- assertEquals("test name", builder.mContentTitle);
- }
+ // For versions above 11, the "Person" name from the style is applied to the title.
+ assertEquals("test name", builder.mContentTitle);
// Actions were introduced in API 20.
if (Build.VERSION.SDK_INT >= 20) {
@@ -2965,28 +2934,27 @@
// Checks in this section check values in the Notification's extras, which were unavailable
// prior to API 19.
- if (Build.VERSION.SDK_INT >= 19) {
- // Test extras values. This is equivalent to creating a new NotificationCompat.Builder,
- // and checking the values in it (as those are created via restoreFromCompatExtras).
- Bundle extras = notification.extras;
+ // Test extras values. This is equivalent to creating a new NotificationCompat.Builder,
+ // and checking the values in it (as those are created via restoreFromCompatExtras).
+ Bundle extras = notification.extras;
- // Checks that the notification title is set to the caller name. 11 >=
- assertEquals("test name", extras.getCharSequence(NotificationCompat.EXTRA_TITLE));
+ // Checks that the notification title is set to the caller name. 11 >=
+ assertEquals("test name", extras.getCharSequence(NotificationCompat.EXTRA_TITLE));
- // Checks that the notification text is set to the default text (since EXTRA_TEXT isn't
- // set). 11 >=
- assertEquals(
- mContext.getResources().getString(R.string.call_notification_screening_text),
- extras.getCharSequence(NotificationCompat.EXTRA_TEXT));
+ // Checks that the notification text is set to the default text (since EXTRA_TEXT isn't
+ // set). 11 >=
+ assertEquals(
+ mContext.getResources().getString(R.string.call_notification_screening_text),
+ extras.getCharSequence(NotificationCompat.EXTRA_TEXT));
- // Create a new NotificationCompat Builder object based on the notification.
- // This allows us to inspect various fields, including actions.
- NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext,
- notification);
+ // Create a new NotificationCompat Builder object based on the notification.
+ // This allows us to inspect various fields, including actions.
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext,
+ notification);
- // For versions above 11, the "Person" name from the style is applied to the title.
- assertEquals("test name", builder.mContentTitle);
- }
+ // For versions above 11, the "Person" name from the style is applied to the title.
+ assertEquals("test name", builder.mContentTitle);
+
// Actions were introduced in API 20.
if (Build.VERSION.SDK_INT >= 20) {
@@ -3569,10 +3537,8 @@
// before testing the notification we've built with people, test the clearPeople() method
final Notification notificationWithoutPeople = builder.clearPeople().build();
- if (Build.VERSION.SDK_INT >= 19) {
- assertNull(notificationWithoutPeople.extras.get(NotificationCompat.EXTRA_PEOPLE));
- assertNull(notificationWithoutPeople.extras.get(NotificationCompat.EXTRA_PEOPLE_LIST));
- }
+ assertNull(notificationWithoutPeople.extras.get(NotificationCompat.EXTRA_PEOPLE));
+ assertNull(notificationWithoutPeople.extras.get(NotificationCompat.EXTRA_PEOPLE_LIST));
if (Build.VERSION.SDK_INT >= 29) {
assertNull(notificationWithoutPeople.extras.get(NotificationCompat.EXTRA_PEOPLE));
@@ -3598,7 +3564,7 @@
expected.add("test name\tnull");
expected.add("test name 2\tnull");
assertEquals(expected, people);
- } else if (Build.VERSION.SDK_INT >= 19) {
+ } else {
assertNull(notificationWithoutPeople.extras.get(NotificationCompat.EXTRA_PEOPLE_LIST));
final String[] peopleArray =
notification.extras.getStringArray(Notification.EXTRA_PEOPLE);
@@ -3624,7 +3590,7 @@
expected.add("test name\tnull");
expected.add("test name 2\tnull");
expected.add("null\ttest:selfUri");
- } else if (Build.VERSION.SDK_INT >= 19) {
+ } else {
// On older platforms, the name is converted into a URI
expected.add("null\tname:test name");
expected.add("null\tname:test name 2");
diff --git a/core/core/src/androidTest/java/androidx/core/content/PackageManagerCompatTest.java b/core/core/src/androidTest/java/androidx/core/content/PackageManagerCompatTest.java
index d612ba4..ebe6103 100644
--- a/core/core/src/androidTest/java/androidx/core/content/PackageManagerCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/content/PackageManagerCompatTest.java
@@ -48,10 +48,8 @@
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
-import android.os.Build;
import android.os.UserManager;
-import androidx.annotation.RequiresApi;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SdkSuppress;
@@ -317,7 +315,6 @@
* Setup applications with the verifier role can handle unused app restriction features. In
* this case, they are permission revocation apps.
*/
- @RequiresApi(api = Build.VERSION_CODES.KITKAT)
@SuppressWarnings("deprecation")
static void setupPermissionRevocationApps(
PackageManager packageManager, List<String> packageNames) {
diff --git a/core/core/src/androidTest/java/androidx/core/content/res/ResourcesCompatTest.java b/core/core/src/androidTest/java/androidx/core/content/res/ResourcesCompatTest.java
index 16c5ef7..e877a26 100644
--- a/core/core/src/androidTest/java/androidx/core/content/res/ResourcesCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/content/res/ResourcesCompatTest.java
@@ -179,8 +179,7 @@
// For pre-v15 devices we should get a drawable that corresponds to the density of the
// current device. For v15+ devices we should get a drawable that corresponds to the
// density requested in the API call.
- final int expectedSizeForMediumDensity = (SDK_INT < 15) ?
- mResources.getDimensionPixelSize(R.dimen.density_aware_size) : 12;
+ final int expectedSizeForMediumDensity = 12;
assertEquals("Unthemed density-aware drawable load: medium width",
expectedSizeForMediumDensity, unthemedDrawableForMediumDensity.getIntrinsicWidth());
assertEquals("Unthemed density-aware drawable load: medium height",
@@ -190,11 +189,8 @@
final Drawable unthemedDrawableForHighDensity =
ResourcesCompat.getDrawableForDensity(mResources, R.drawable.density_aware_drawable,
DisplayMetrics.DENSITY_HIGH, null);
- // For pre-v15 devices we should get a drawable that corresponds to the density of the
- // current device. For v15+ devices we should get a drawable that corresponds to the
- // density requested in the API call.
- final int expectedSizeForHighDensity = (SDK_INT < 15) ?
- mResources.getDimensionPixelSize(R.dimen.density_aware_size) : 21;
+
+ final int expectedSizeForHighDensity = 21;
assertEquals("Unthemed density-aware drawable load: high width",
expectedSizeForHighDensity, unthemedDrawableForHighDensity.getIntrinsicWidth());
assertEquals("Unthemed density-aware drawable load: high height",
@@ -203,11 +199,8 @@
final Drawable unthemedDrawableForXHighDensity =
ResourcesCompat.getDrawableForDensity(mResources, R.drawable.density_aware_drawable,
DisplayMetrics.DENSITY_XHIGH, null);
- // For pre-v15 devices we should get a drawable that corresponds to the density of the
- // current device. For v15+ devices we should get a drawable that corresponds to the
- // density requested in the API call.
- final int expectedSizeForXHighDensity = (SDK_INT < 15) ?
- mResources.getDimensionPixelSize(R.dimen.density_aware_size) : 32;
+
+ final int expectedSizeForXHighDensity = 32;
assertEquals("Unthemed density-aware drawable load: xhigh width",
expectedSizeForXHighDensity, unthemedDrawableForXHighDensity.getIntrinsicWidth());
assertEquals("Unthemed density-aware drawable load: xhigh height",
@@ -216,11 +209,8 @@
final Drawable unthemedDrawableForXXHighDensity =
ResourcesCompat.getDrawableForDensity(mResources, R.drawable.density_aware_drawable,
DisplayMetrics.DENSITY_XXHIGH, null);
- // For pre-v15 devices we should get a drawable that corresponds to the density of the
- // current device. For v15+ devices we should get a drawable that corresponds to the
- // density requested in the API call.
- final int expectedSizeForXXHighDensity = (SDK_INT < 15) ?
- mResources.getDimensionPixelSize(R.dimen.density_aware_size) : 54;
+
+ final int expectedSizeForXXHighDensity = 54;
assertEquals("Unthemed density-aware drawable load: xxhigh width",
expectedSizeForXXHighDensity, unthemedDrawableForXXHighDensity.getIntrinsicWidth());
assertEquals("Unthemed density-aware drawable load: xxhigh height",
diff --git a/core/core/src/androidTest/java/androidx/core/graphics/BitmapCompatTest.java b/core/core/src/androidTest/java/androidx/core/graphics/BitmapCompatTest.java
index 0c5e39a..ae50a71 100644
--- a/core/core/src/androidTest/java/androidx/core/graphics/BitmapCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/graphics/BitmapCompatTest.java
@@ -30,7 +30,6 @@
import android.hardware.HardwareBuffer;
import android.os.Build;
-import androidx.annotation.RequiresApi;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SdkSuppress;
import androidx.test.filters.SmallTest;
@@ -39,7 +38,6 @@
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
-@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@SmallTest
public class BitmapCompatTest {
@@ -381,7 +379,6 @@
// For a resize smaller than 1/2 of the original dimensions, the result should basically be
// uniform grey, so the higher quality the resize, the lower the variance in grey values is
// expected to be.
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
private void scaledBitmapAndAssertQuality(int scaledWidth, int scaledHeight,
boolean scaleInLinearSpace,
float expectedMeanValue, float expectedVariance, Bitmap.Config inputConfig) {
@@ -435,7 +432,6 @@
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void testQualityDownscaleNonLinear() {
scaledBitmapAndAssertQuality(19, 19, false, 127.0f, DOWNSCALE_VARIANCE,
Bitmap.Config.ARGB_8888);
@@ -449,7 +445,6 @@
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void testQualityUpscaleNonLinear() {
scaledBitmapAndAssertQuality(1213, 1213, false, 127.0f, UPSCALE_VARIANCE,
Bitmap.Config.ARGB_8888);
diff --git a/core/core/src/androidTest/java/androidx/core/graphics/TypefaceCompatUtilTest.java b/core/core/src/androidTest/java/androidx/core/graphics/TypefaceCompatUtilTest.java
index 245f6c5..e282798 100644
--- a/core/core/src/androidTest/java/androidx/core/graphics/TypefaceCompatUtilTest.java
+++ b/core/core/src/androidTest/java/androidx/core/graphics/TypefaceCompatUtilTest.java
@@ -20,7 +20,6 @@
import android.content.ContentUris;
import android.content.Context;
import android.net.Uri;
-import android.os.Build;
import androidx.annotation.RequiresApi;
import androidx.core.provider.MockFontProvider;
@@ -43,10 +42,6 @@
@Test
@RequiresApi(19)
public void testMmapNullPfd() {
- if (Build.VERSION.SDK_INT < 19) {
- // The API tested here requires SDK level 19.
- return;
- }
final Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
.authority(MockFontProvider.AUTHORITY).build();
final Uri fileUri = ContentUris.withAppendedId(uri, MockFontProvider.INVALID_FONT_FILE_ID);
diff --git a/core/core/src/androidTest/java/androidx/core/location/LocationCompatTest.java b/core/core/src/androidTest/java/androidx/core/location/LocationCompatTest.java
index 2c9770b..6cf5ee3 100644
--- a/core/core/src/androidTest/java/androidx/core/location/LocationCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/location/LocationCompatTest.java
@@ -25,7 +25,6 @@
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import android.location.Location;
-import android.os.Build;
import android.os.SystemClock;
import androidx.test.filters.SmallTest;
@@ -40,16 +39,10 @@
@Test
public void testGetElapsedRealtimeNanos() {
long locationElapsedRealtimeNs;
- if (Build.VERSION.SDK_INT >= 17) {
- locationElapsedRealtimeNs = SystemClock.elapsedRealtimeNanos();
- } else {
- locationElapsedRealtimeNs = MILLISECONDS.toNanos(SystemClock.elapsedRealtime());
- }
+ locationElapsedRealtimeNs = SystemClock.elapsedRealtimeNanos();
Location location = new Location("");
- if (Build.VERSION.SDK_INT >= 17) {
- location.setElapsedRealtimeNanos(locationElapsedRealtimeNs);
- }
+ location.setElapsedRealtimeNanos(locationElapsedRealtimeNs);
location.setTime(System.currentTimeMillis());
assertTrue(NANOSECONDS.toMillis(Math.abs(
@@ -62,9 +55,7 @@
long locationElapsedRealtimeMs = SystemClock.elapsedRealtime();
Location location = new Location("");
- if (Build.VERSION.SDK_INT >= 17) {
- location.setElapsedRealtimeNanos(MILLISECONDS.toNanos(locationElapsedRealtimeMs));
- }
+ location.setElapsedRealtimeNanos(MILLISECONDS.toNanos(locationElapsedRealtimeMs));
location.setTime(System.currentTimeMillis());
assertTrue(Math.abs(
diff --git a/core/core/src/androidTest/java/androidx/core/location/LocationManagerCompatTest.java b/core/core/src/androidTest/java/androidx/core/location/LocationManagerCompatTest.java
index b95610f..ba8bf19 100644
--- a/core/core/src/androidTest/java/androidx/core/location/LocationManagerCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/location/LocationManagerCompatTest.java
@@ -33,7 +33,6 @@
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
-import android.text.TextUtils;
import androidx.core.os.ExecutorCompat;
import androidx.test.core.app.ApplicationProvider;
@@ -63,13 +62,9 @@
boolean isLocationEnabled;
if (VERSION.SDK_INT >= 28) {
isLocationEnabled = mLocationManager.isLocationEnabled();
- } else if (VERSION.SDK_INT >= 19) {
+ } else {
isLocationEnabled = Settings.Secure.getInt(mContext.getContentResolver(), LOCATION_MODE,
LOCATION_MODE_OFF) != LOCATION_MODE_OFF;
- } else {
- isLocationEnabled = !TextUtils.isEmpty(
- Settings.Secure.getString(mContext.getContentResolver(),
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
}
assertEquals(isLocationEnabled, LocationManagerCompat.isLocationEnabled(mLocationManager));
diff --git a/core/core/src/androidTest/java/androidx/core/provider/DocumentsContractCompatTest.kt b/core/core/src/androidTest/java/androidx/core/provider/DocumentsContractCompatTest.kt
index e5ab057..6fd9d1f 100644
--- a/core/core/src/androidTest/java/androidx/core/provider/DocumentsContractCompatTest.kt
+++ b/core/core/src/androidTest/java/androidx/core/provider/DocumentsContractCompatTest.kt
@@ -48,25 +48,16 @@
@Test
fun testBuildChildDocumentsUri() {
- if (isAtLeastKitKat()) {
- assertEquals(
- DocumentsContractCompat.buildChildDocumentsUri(
- EXTERNAL_STORAGE_PROVIDER_AUTHORITY,
- DOWNLOAD_DOCID
- ),
- DocumentsContract.buildChildDocumentsUri(
- EXTERNAL_STORAGE_PROVIDER_AUTHORITY,
- DOWNLOAD_DOCID
- )
+ assertEquals(
+ DocumentsContractCompat.buildChildDocumentsUri(
+ EXTERNAL_STORAGE_PROVIDER_AUTHORITY,
+ DOWNLOAD_DOCID
+ ),
+ DocumentsContract.buildChildDocumentsUri(
+ EXTERNAL_STORAGE_PROVIDER_AUTHORITY,
+ DOWNLOAD_DOCID
)
- } else {
- assertNull(
- DocumentsContractCompat.buildChildDocumentsUri(
- EXTERNAL_STORAGE_PROVIDER_AUTHORITY,
- DOWNLOAD_DOCID
- )
- )
- }
+ )
}
@Test
@@ -95,25 +86,16 @@
@Test
fun testBuildDocumentUri() {
- if (isAtLeastKitKat()) {
- assertEquals(
- DocumentsContractCompat.buildDocumentUri(
- EXTERNAL_STORAGE_PROVIDER_AUTHORITY,
- DOWNLOAD_DOCID
- ),
- DocumentsContract.buildDocumentUri(
- EXTERNAL_STORAGE_PROVIDER_AUTHORITY,
- DOWNLOAD_DOCID
- )
+ assertEquals(
+ DocumentsContractCompat.buildDocumentUri(
+ EXTERNAL_STORAGE_PROVIDER_AUTHORITY,
+ DOWNLOAD_DOCID
+ ),
+ DocumentsContract.buildDocumentUri(
+ EXTERNAL_STORAGE_PROVIDER_AUTHORITY,
+ DOWNLOAD_DOCID
)
- } else {
- assertNull(
- DocumentsContractCompat.buildDocumentUri(
- EXTERNAL_STORAGE_PROVIDER_AUTHORITY,
- DOWNLOAD_DOCID
- )
- )
- }
+ )
}
@Test
@@ -159,20 +141,15 @@
@Test
fun testGetDocumentId() {
- if (isAtLeastKitKat()) {
- val documentUri =
- DocumentsContract.buildDocumentUri(
- EXTERNAL_STORAGE_PROVIDER_AUTHORITY,
- DOWNLOAD_DOCID
- )
- assertEquals(
- DocumentsContractCompat.getDocumentId(documentUri),
- DocumentsContract.getDocumentId(documentUri)
+ val documentUri =
+ DocumentsContract.buildDocumentUri(
+ EXTERNAL_STORAGE_PROVIDER_AUTHORITY,
+ DOWNLOAD_DOCID
)
- } else {
- val documentUri = buildDocUri(EXTERNAL_STORAGE_PROVIDER_AUTHORITY, DOWNLOAD_DOCID)
- assertNull(DocumentsContractCompat.getDocumentId(documentUri))
- }
+ assertEquals(
+ DocumentsContractCompat.getDocumentId(documentUri),
+ DocumentsContract.getDocumentId(documentUri)
+ )
}
@Test
@@ -247,19 +224,12 @@
val mediaStoreUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
assertFalse(DocumentsContractCompat.isDocumentUri(context, mediaStoreUri))
- if (isAtLeastKitKat()) {
- val documentUri =
- DocumentsContract.buildDocumentUri(
- EXTERNAL_STORAGE_PROVIDER_AUTHORITY,
- DOWNLOAD_DOCID
- )
- assertTrue(DocumentsContractCompat.isDocumentUri(context, documentUri))
- } else {
- val documentUri = buildDocUri(EXTERNAL_STORAGE_PROVIDER_AUTHORITY, DOWNLOAD_DOCID)
-
- // DocumentsProvider doesn't exist before KitKat.
- assertFalse(DocumentsContractCompat.isDocumentUri(context, documentUri))
- }
+ val documentUri =
+ DocumentsContract.buildDocumentUri(
+ EXTERNAL_STORAGE_PROVIDER_AUTHORITY,
+ DOWNLOAD_DOCID
+ )
+ assertTrue(DocumentsContractCompat.isDocumentUri(context, documentUri))
if (isAtLeastLollipop()) {
val downloadTree =
@@ -283,7 +253,6 @@
}
}
- private fun isAtLeastKitKat() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
private fun isAtLeastLollipop() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
/** Helper method that works similar to [DocumentsContract.buildDocumentUri]. */
diff --git a/core/core/src/androidTest/java/androidx/core/view/MarginLayoutParamsCompatTest.java b/core/core/src/androidTest/java/androidx/core/view/MarginLayoutParamsCompatTest.java
index 77676e7..7289810 100644
--- a/core/core/src/androidTest/java/androidx/core/view/MarginLayoutParamsCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/view/MarginLayoutParamsCompatTest.java
@@ -37,14 +37,8 @@
MarginLayoutParamsCompat.getLayoutDirection(mlp));
MarginLayoutParamsCompat.setLayoutDirection(mlp, ViewCompat.LAYOUT_DIRECTION_RTL);
- if (Build.VERSION.SDK_INT >= 17) {
- assertEquals("RTL layout direction", ViewCompat.LAYOUT_DIRECTION_RTL,
- MarginLayoutParamsCompat.getLayoutDirection(mlp));
- } else {
- assertEquals("Still LTR layout direction on older devices",
- ViewCompat.LAYOUT_DIRECTION_LTR,
- MarginLayoutParamsCompat.getLayoutDirection(mlp));
- }
+ assertEquals("RTL layout direction", ViewCompat.LAYOUT_DIRECTION_RTL,
+ MarginLayoutParamsCompat.getLayoutDirection(mlp));
MarginLayoutParamsCompat.setLayoutDirection(mlp, ViewCompat.LAYOUT_DIRECTION_LTR);
assertEquals("Back to LTR layout direction", ViewCompat.LAYOUT_DIRECTION_LTR,
diff --git a/core/core/src/androidTest/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompatTest.java b/core/core/src/androidTest/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompatTest.java
index 281bc49..2305523 100644
--- a/core/core/src/androidTest/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompatTest.java
@@ -140,7 +140,7 @@
@Test
public void testGetSetHintText() {
- final CharSequence hintText = (Build.VERSION.SDK_INT >= 19) ? "hint text" : null;
+ final CharSequence hintText = "hint text";
AccessibilityNodeInfoCompat nodeCompat = obtainedWrappedNodeCompat();
nodeCompat.setHintText(hintText);
assertThat(nodeCompat.getHintText()).isEqualTo(hintText);
@@ -148,7 +148,7 @@
@Test
public void testGetSetPaneTitle() {
- final CharSequence paneTitle = (Build.VERSION.SDK_INT >= 19) ? "pane title" : null;
+ final CharSequence paneTitle = "pane title";
AccessibilityNodeInfoCompat nodeCompat = obtainedWrappedNodeCompat();
nodeCompat.setPaneTitle(paneTitle);
assertThat(nodeCompat.getPaneTitle()).isEqualTo(paneTitle);
@@ -156,7 +156,7 @@
@Test
public void testGetSetTooltipText() {
- final CharSequence tooltipText = (Build.VERSION.SDK_INT >= 19) ? "tooltip" : null;
+ final CharSequence tooltipText = "tooltip";
AccessibilityNodeInfoCompat nodeCompat = obtainedWrappedNodeCompat();
nodeCompat.setTooltipText(tooltipText);
assertThat(nodeCompat.getTooltipText()).isEqualTo(tooltipText);
@@ -197,7 +197,7 @@
@Test
public void testGetSetContainerTitle() {
- final CharSequence containerTitle = (Build.VERSION.SDK_INT >= 19) ? "title" : null;
+ final CharSequence containerTitle = "title";
AccessibilityNodeInfoCompat nodeCompat = obtainedWrappedNodeCompat();
nodeCompat.setContainerTitle(containerTitle);
assertThat(nodeCompat.getContainerTitle()).isEqualTo(containerTitle);
@@ -265,7 +265,7 @@
@Test
public void testGetSetUniqueId() {
- final String uniqueId = (Build.VERSION.SDK_INT >= 19) ? "localUId" : null;
+ final String uniqueId = "localUId";
AccessibilityNodeInfoCompat nodeCompat = obtainedWrappedNodeCompat();
nodeCompat.setUniqueId(uniqueId);
assertThat(nodeCompat.getUniqueId()).isEqualTo(uniqueId);
diff --git a/core/core/src/androidTest/java/androidx/core/view/inputmethod/EditorInfoCompatTest.java b/core/core/src/androidTest/java/androidx/core/view/inputmethod/EditorInfoCompatTest.java
index 1e14e1f..d213e1f 100644
--- a/core/core/src/androidTest/java/androidx/core/view/inputmethod/EditorInfoCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/view/inputmethod/EditorInfoCompatTest.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -88,6 +89,16 @@
}
@Test
+ public void testSetStylusHandwritingEnabled() {
+ EditorInfo editorInfo = new EditorInfo();
+ EditorInfoCompat.setStylusHandwritingEnabled(editorInfo, true /* enabled */);
+ assertTrue(EditorInfoCompat.isStylusHandwritingEnabled(editorInfo));
+
+ EditorInfoCompat.setStylusHandwritingEnabled(editorInfo, false /* enabled */);
+ assertFalse(EditorInfoCompat.isStylusHandwritingEnabled(editorInfo));
+ }
+
+ @Test
public void setInitialText_nullInputText_throwsException() {
final CharSequence testText = null;
final EditorInfo editorInfo = new EditorInfo();
diff --git a/core/core/src/androidTest/res/values-hdpi/dimens.xml b/core/core/src/androidTest/res/values-hdpi/dimens.xml
deleted file mode 100755
index 3126a6e..0000000
--- a/core/core/src/androidTest/res/values-hdpi/dimens.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<resources>
- <dimen name="density_aware_size">14dip</dimen>
-</resources>
\ No newline at end of file
diff --git a/core/core/src/androidTest/res/values-mdpi/dimens.xml b/core/core/src/androidTest/res/values-mdpi/dimens.xml
deleted file mode 100755
index ada2cae..0000000
--- a/core/core/src/androidTest/res/values-mdpi/dimens.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<resources>
- <dimen name="density_aware_size">12dip</dimen>
-</resources>
\ No newline at end of file
diff --git a/core/core/src/androidTest/res/values-xhdpi/dimens.xml b/core/core/src/androidTest/res/values-xhdpi/dimens.xml
deleted file mode 100755
index 21125b8..0000000
--- a/core/core/src/androidTest/res/values-xhdpi/dimens.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<resources>
- <dimen name="density_aware_size">16dip</dimen>
-</resources>
\ No newline at end of file
diff --git a/core/core/src/androidTest/res/values-xxhdpi/dimens.xml b/core/core/src/androidTest/res/values-xxhdpi/dimens.xml
deleted file mode 100755
index aaee862..0000000
--- a/core/core/src/androidTest/res/values-xxhdpi/dimens.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<resources>
- <dimen name="density_aware_size">18dip</dimen>
-</resources>
\ No newline at end of file
diff --git a/core/core/src/main/java/androidx/core/accessibilityservice/AccessibilityServiceInfoCompat.java b/core/core/src/main/java/androidx/core/accessibilityservice/AccessibilityServiceInfoCompat.java
index 9f4cd4e..d1dc409 100644
--- a/core/core/src/main/java/androidx/core/accessibilityservice/AccessibilityServiceInfoCompat.java
+++ b/core/core/src/main/java/androidx/core/accessibilityservice/AccessibilityServiceInfoCompat.java
@@ -280,14 +280,7 @@
*/
@SuppressWarnings("deprecation")
public static int getCapabilities(@NonNull AccessibilityServiceInfo info) {
- if (Build.VERSION.SDK_INT >= 18) {
- return info.getCapabilities();
- } else {
- if (info.getCanRetrieveWindowContent()) {
- return CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT;
- }
- return 0;
- }
+ return info.getCapabilities();
}
/**
diff --git a/core/core/src/main/java/androidx/core/app/ActivityManagerCompat.java b/core/core/src/main/java/androidx/core/app/ActivityManagerCompat.java
index 2e5abb5..696e01f 100644
--- a/core/core/src/main/java/androidx/core/app/ActivityManagerCompat.java
+++ b/core/core/src/main/java/androidx/core/app/ActivityManagerCompat.java
@@ -17,7 +17,6 @@
package androidx.core.app;
import android.app.ActivityManager;
-import android.os.Build;
import androidx.annotation.NonNull;
@@ -37,9 +36,6 @@
* off certain features that require more RAM.
*/
public static boolean isLowRamDevice(@NonNull ActivityManager activityManager) {
- if (Build.VERSION.SDK_INT >= 19) {
- return activityManager.isLowRamDevice();
- }
- return false;
+ return activityManager.isLowRamDevice();
}
}
diff --git a/core/core/src/main/java/androidx/core/app/AlarmManagerCompat.java b/core/core/src/main/java/androidx/core/app/AlarmManagerCompat.java
index 659f4c8..1603dc5 100644
--- a/core/core/src/main/java/androidx/core/app/AlarmManagerCompat.java
+++ b/core/core/src/main/java/androidx/core/app/AlarmManagerCompat.java
@@ -164,11 +164,7 @@
*/
public static void setExact(@NonNull AlarmManager alarmManager, int type, long triggerAtMillis,
@NonNull PendingIntent operation) {
- if (Build.VERSION.SDK_INT >= 19) {
- Api19Impl.setExact(alarmManager, type, triggerAtMillis, operation);
- } else {
- alarmManager.set(type, triggerAtMillis, operation);
- }
+ alarmManager.setExact(type, triggerAtMillis, operation);
}
/**
@@ -271,17 +267,4 @@
alarmManager.setExactAndAllowWhileIdle(type, triggerAtMillis, operation);
}
}
-
- @RequiresApi(19)
- static class Api19Impl {
- private Api19Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static void setExact(AlarmManager alarmManager, int type, long triggerAtMillis,
- PendingIntent operation) {
- alarmManager.setExact(type, triggerAtMillis, operation);
- }
- }
}
diff --git a/core/core/src/main/java/androidx/core/app/AppOpsManagerCompat.java b/core/core/src/main/java/androidx/core/app/AppOpsManagerCompat.java
index 1a8727f..52e248a 100644
--- a/core/core/src/main/java/androidx/core/app/AppOpsManagerCompat.java
+++ b/core/core/src/main/java/androidx/core/app/AppOpsManagerCompat.java
@@ -104,13 +104,9 @@
*/
public static int noteOp(@NonNull Context context, @NonNull String op, int uid,
@NonNull String packageName) {
- if (SDK_INT >= 19) {
- AppOpsManager appOpsManager =
- (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
- return Api19Impl.noteOp(appOpsManager, op, uid, packageName);
- } else {
- return MODE_IGNORED;
- }
+ AppOpsManager appOpsManager =
+ (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ return appOpsManager.noteOp(op, uid, packageName);
}
/**
@@ -124,13 +120,9 @@
*/
public static int noteOpNoThrow(@NonNull Context context, @NonNull String op, int uid,
@NonNull String packageName) {
- if (SDK_INT >= 19) {
- AppOpsManager appOpsManager =
- (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
- return Api19Impl.noteOpNoThrow(appOpsManager, op, uid, packageName);
- } else {
- return MODE_IGNORED;
- }
+ AppOpsManager appOpsManager =
+ (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ return appOpsManager.noteOpNoThrow(op, uid, packageName);
}
/**
@@ -282,22 +274,4 @@
return appOpsManager.noteProxyOpNoThrow(op, proxiedPackageName);
}
}
-
- @RequiresApi(19)
- static class Api19Impl {
- private Api19Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static int noteOpNoThrow(AppOpsManager appOpsManager, String op, int uid,
- String packageName) {
- return appOpsManager.noteOpNoThrow(op, uid, packageName);
- }
-
- @DoNotInline
- static int noteOp(AppOpsManager appOpsManager, String op, int uid, String packageName) {
- return appOpsManager.noteOp(op, uid, packageName);
- }
- }
}
diff --git a/core/core/src/main/java/androidx/core/app/NotificationCompat.java b/core/core/src/main/java/androidx/core/app/NotificationCompat.java
index 0cd62f5..33b1459 100644
--- a/core/core/src/main/java/androidx/core/app/NotificationCompat.java
+++ b/core/core/src/main/java/androidx/core/app/NotificationCompat.java
@@ -2219,10 +2219,6 @@
*/
@SuppressLint("BuilderSetStyle") // This API is copied from Notification.Builder
public @Nullable RemoteViews createBigContentView() {
- // Before Jellybean, there was no "big" notification view
- if (Build.VERSION.SDK_INT < 16) {
- return null;
- }
// If the user setCustomBigContentView(), return it if appropriate for the style.
if (mBigContentView != null && useExistingRemoteView()) {
return mBigContentView;
@@ -9213,7 +9209,7 @@
public static @Nullable Action getAction(@NonNull Notification notification, int actionIndex) {
if (Build.VERSION.SDK_INT >= 20) {
return getActionCompatFromAction(notification.actions[actionIndex]);
- } else if (Build.VERSION.SDK_INT >= 19) {
+ } else {
Notification.Action action = notification.actions[actionIndex];
Bundle actionExtras = null;
SparseArray<Bundle> actionExtrasMap = notification.extras.getSparseParcelableArray(
@@ -9223,8 +9219,6 @@
}
return NotificationCompatJellybean.readAction(action.icon, action.title,
action.actionIntent, actionExtras);
- } else {
- return NotificationCompatJellybean.getAction(notification, actionIndex);
}
}
@@ -9319,19 +9313,17 @@
@RequiresApi(21)
public static @NonNull List<Action> getInvisibleActions(@NonNull Notification notification) {
ArrayList<Action> result = new ArrayList<>();
- if (Build.VERSION.SDK_INT >= 19) {
- Bundle carExtenderBundle =
- notification.extras.getBundle(CarExtender.EXTRA_CAR_EXTENDER);
- if (carExtenderBundle == null) {
- return result;
- }
+ Bundle carExtenderBundle =
+ notification.extras.getBundle(CarExtender.EXTRA_CAR_EXTENDER);
+ if (carExtenderBundle == null) {
+ return result;
+ }
- Bundle listBundle = carExtenderBundle.getBundle(CarExtender.EXTRA_INVISIBLE_ACTIONS);
- if (listBundle != null) {
- for (int i = 0; i < listBundle.size(); i++) {
- result.add(NotificationCompatJellybean.getActionFromBundle(
- listBundle.getBundle(Integer.toString(i))));
- }
+ Bundle listBundle = carExtenderBundle.getBundle(CarExtender.EXTRA_INVISIBLE_ACTIONS);
+ if (listBundle != null) {
+ for (int i = 0; i < listBundle.size(); i++) {
+ result.add(NotificationCompatJellybean.getActionFromBundle(
+ listBundle.getBundle(Integer.toString(i))));
}
}
return result;
@@ -9353,7 +9345,7 @@
result.add(Person.fromAndroidPerson(person));
}
}
- } else if (Build.VERSION.SDK_INT >= 19) {
+ } else {
final String[] peopleArray = notification.extras.getStringArray(EXTRA_PEOPLE);
if (peopleArray != null && peopleArray.length != 0) {
for (String personUri : peopleArray) {
diff --git a/core/core/src/main/java/androidx/core/app/NotificationCompatBuilder.java b/core/core/src/main/java/androidx/core/app/NotificationCompatBuilder.java
index 927e008..edb7913 100644
--- a/core/core/src/main/java/androidx/core/app/NotificationCompatBuilder.java
+++ b/core/core/src/main/java/androidx/core/app/NotificationCompatBuilder.java
@@ -157,16 +157,12 @@
mContentView = b.mContentView;
mBigContentView = b.mBigContentView;
}
- if (Build.VERSION.SDK_INT >= 17) {
- Api17Impl.setShowWhen(mBuilder, b.mShowWhen);
- }
- if (Build.VERSION.SDK_INT >= 19) {
- if (Build.VERSION.SDK_INT < 21) {
- final List<String> people = combineLists(getPeople(b.mPersonList), b.mPeople);
- if (people != null && !people.isEmpty()) {
- mExtras.putStringArray(Notification.EXTRA_PEOPLE,
- people.toArray(new String[people.size()]));
- }
+ mBuilder.setShowWhen(b.mShowWhen);
+ if (Build.VERSION.SDK_INT < 21) {
+ final List<String> people = combineLists(getPeople(b.mPersonList), b.mPeople);
+ if (people != null && !people.isEmpty()) {
+ mExtras.putStringArray(Notification.EXTRA_PEOPLE,
+ people.toArray(new String[people.size()]));
}
}
if (Build.VERSION.SDK_INT >= 20) {
@@ -229,7 +225,7 @@
}
}
if (Build.VERSION.SDK_INT >= 24) {
- Api19Impl.setExtras(mBuilder, b.mExtras);
+ mBuilder.setExtras(b.mExtras);
Api24Impl.setRemoteInputHistory(mBuilder, b.mRemoteInputHistory);
if (b.mContentView != null) {
Api24Impl.setCustomContentView(mBuilder, b.mContentView);
@@ -457,7 +453,7 @@
return notification;
} else if (Build.VERSION.SDK_INT >= 21) {
- Api19Impl.setExtras(mBuilder, mExtras);
+ mBuilder.setExtras(mExtras);
Notification notification = Api16Impl.build(mBuilder);
if (mContentView != null) {
notification.contentView = mContentView;
@@ -485,7 +481,7 @@
}
return notification;
} else if (Build.VERSION.SDK_INT >= 20) {
- Api19Impl.setExtras(mBuilder, mExtras);
+ mBuilder.setExtras(mExtras);
Notification notification = Api16Impl.build(mBuilder);
if (mContentView != null) {
notification.contentView = mContentView;
@@ -510,7 +506,7 @@
}
return notification;
- } else if (Build.VERSION.SDK_INT >= 19) {
+ } else {
SparseArray<Bundle> actionExtrasMap =
NotificationCompatJellybean.buildActionExtrasMap(mActionExtrasList);
if (actionExtrasMap != null) {
@@ -518,7 +514,7 @@
mExtras.putSparseParcelableArray(
NotificationCompatExtras.EXTRA_ACTION_EXTRAS, actionExtrasMap);
}
- Api19Impl.setExtras(mBuilder, mExtras);
+ mBuilder.setExtras(mExtras);
Notification notification = Api16Impl.build(mBuilder);
if (mContentView != null) {
notification.contentView = mContentView;
@@ -527,34 +523,6 @@
notification.bigContentView = mBigContentView;
}
return notification;
- } else if (Build.VERSION.SDK_INT >= 16) {
- Notification notification = Api16Impl.build(mBuilder);
- // Merge in developer provided extras, but let the values already set
- // for keys take precedence.
- Bundle extras = NotificationCompat.getExtras(notification);
- Bundle mergeBundle = new Bundle(mExtras);
- for (String key : mExtras.keySet()) {
- if (extras.containsKey(key)) {
- mergeBundle.remove(key);
- }
- }
- extras.putAll(mergeBundle);
- SparseArray<Bundle> actionExtrasMap =
- NotificationCompatJellybean.buildActionExtrasMap(mActionExtrasList);
- if (actionExtrasMap != null) {
- // Add the action extras sparse array if any action was added with extras.
- NotificationCompat.getExtras(notification).putSparseParcelableArray(
- NotificationCompatExtras.EXTRA_ACTION_EXTRAS, actionExtrasMap);
- }
- if (mContentView != null) {
- notification.contentView = mContentView;
- }
- if (mBigContentView != null) {
- notification.bigContentView = mBigContentView;
- }
- return notification;
- } else {
- return mBuilder.getNotification();
}
}
@@ -597,38 +565,6 @@
/**
* A class for wrapping calls to {@link NotificationCompatBuilder} methods which
- * were added in API 17; these calls must be wrapped to avoid performance issues.
- * See the UnsafeNewApiCall lint rule for more details.
- */
- @RequiresApi(17)
- static class Api17Impl {
- private Api17Impl() {
- }
-
- @DoNotInline
- static Notification.Builder setShowWhen(Notification.Builder builder, boolean show) {
- return builder.setShowWhen(show);
- }
-
- }
-
- /**
- * A class for wrapping calls to {@link NotificationCompatBuilder} methods which
- * were added in API 19; these calls must be wrapped to avoid performance issues.
- * See the UnsafeNewApiCall lint rule for more details.
- */
- @RequiresApi(19)
- static class Api19Impl {
- private Api19Impl() { }
-
- @DoNotInline
- static Notification.Builder setExtras(Notification.Builder builder, Bundle extras) {
- return builder.setExtras(extras);
- }
- }
-
- /**
- * A class for wrapping calls to {@link NotificationCompatBuilder} methods which
* were added in API 20; these calls must be wrapped to avoid performance issues.
* See the UnsafeNewApiCall lint rule for more details.
*/
diff --git a/core/core/src/main/java/androidx/core/app/NotificationManagerCompat.java b/core/core/src/main/java/androidx/core/app/NotificationManagerCompat.java
index 48bf924..1fcf6fc 100644
--- a/core/core/src/main/java/androidx/core/app/NotificationManagerCompat.java
+++ b/core/core/src/main/java/androidx/core/app/NotificationManagerCompat.java
@@ -367,7 +367,7 @@
public boolean areNotificationsEnabled() {
if (Build.VERSION.SDK_INT >= 24) {
return Api24Impl.areNotificationsEnabled(mNotificationManager);
- } else if (Build.VERSION.SDK_INT >= 19) {
+ } else {
AppOpsManager appOps =
(AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
ApplicationInfo appInfo = mContext.getApplicationInfo();
@@ -385,8 +385,6 @@
| InvocationTargetException | IllegalAccessException | RuntimeException e) {
return true;
}
- } else {
- return true;
}
}
diff --git a/core/core/src/main/java/androidx/core/app/ShareCompat.java b/core/core/src/main/java/androidx/core/app/ShareCompat.java
index 7f4b1d0..818210a 100644
--- a/core/core/src/main/java/androidx/core/app/ShareCompat.java
+++ b/core/core/src/main/java/androidx/core/app/ShareCompat.java
@@ -16,8 +16,6 @@
package androidx.core.app;
-import static android.os.Build.VERSION.SDK_INT;
-
import static androidx.core.util.Preconditions.checkNotNull;
import android.app.Activity;
@@ -246,12 +244,6 @@
+ shareIntent.getContext().getClass().getName());
provider.setShareIntent(shareIntent.getIntent());
item.setActionProvider(provider);
-
- if (SDK_INT < 16) {
- if (!item.hasSubMenu()) {
- item.setIntent(shareIntent.createChooserIntent());
- }
- }
}
/**
diff --git a/core/core/src/main/java/androidx/core/content/ContextCompat.java b/core/core/src/main/java/androidx/core/content/ContextCompat.java
index 61c464a..eeb5c6c 100644
--- a/core/core/src/main/java/androidx/core/content/ContextCompat.java
+++ b/core/core/src/main/java/androidx/core/content/ContextCompat.java
@@ -365,11 +365,7 @@
*/
@NonNull
public static File[] getObbDirs(@NonNull Context context) {
- if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.getObbDirs(context);
- } else {
- return new File[]{context.getObbDir()};
- }
+ return context.getObbDirs();
}
/**
@@ -418,11 +414,7 @@
*/
@NonNull
public static File[] getExternalFilesDirs(@NonNull Context context, @Nullable String type) {
- if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.getExternalFilesDirs(context, type);
- } else {
- return new File[]{context.getExternalFilesDir(type)};
- }
+ return context.getExternalFilesDirs(type);
}
/**
@@ -471,11 +463,7 @@
*/
@NonNull
public static File[] getExternalCacheDirs(@NonNull Context context) {
- if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.getExternalCacheDirs(context);
- } else {
- return new File[]{context.getExternalCacheDir()};
- }
+ return context.getExternalCacheDirs();
}
/**
@@ -907,12 +895,12 @@
// The Android framework supports per-app locales on API 33, so we assume the
// configuration has been updated after API 32.
- if (Build.VERSION.SDK_INT <= 32 && Build.VERSION.SDK_INT >= 17) {
+ if (Build.VERSION.SDK_INT <= 32) {
if (!locales.isEmpty()) {
Configuration newConfig = new Configuration(
context.getResources().getConfiguration());
ConfigurationCompat.setLocales(newConfig, locales);
- return Api17Impl.createConfigurationContext(context, newConfig);
+ return context.createConfigurationContext(newConfig);
}
}
return context;
@@ -1006,24 +994,18 @@
SERVICES.put(TelecomManager.class, TELECOM_SERVICE);
SERVICES.put(TvInputManager.class, TV_INPUT_SERVICE);
}
- if (Build.VERSION.SDK_INT >= 19) {
- SERVICES.put(AppOpsManager.class, APP_OPS_SERVICE);
- SERVICES.put(CaptioningManager.class, CAPTIONING_SERVICE);
- SERVICES.put(ConsumerIrManager.class, CONSUMER_IR_SERVICE);
- SERVICES.put(PrintManager.class, PRINT_SERVICE);
- }
- if (Build.VERSION.SDK_INT >= 18) {
- SERVICES.put(BluetoothManager.class, BLUETOOTH_SERVICE);
- }
- if (Build.VERSION.SDK_INT >= 17) {
- SERVICES.put(DisplayManager.class, DISPLAY_SERVICE);
- SERVICES.put(UserManager.class, USER_SERVICE);
- }
- if (Build.VERSION.SDK_INT >= 16) {
- SERVICES.put(InputManager.class, INPUT_SERVICE);
- SERVICES.put(MediaRouter.class, MEDIA_ROUTER_SERVICE);
- SERVICES.put(NsdManager.class, NSD_SERVICE);
- }
+
+ SERVICES.put(AppOpsManager.class, APP_OPS_SERVICE);
+ SERVICES.put(CaptioningManager.class, CAPTIONING_SERVICE);
+ SERVICES.put(ConsumerIrManager.class, CONSUMER_IR_SERVICE);
+ SERVICES.put(PrintManager.class, PRINT_SERVICE);
+ SERVICES.put(BluetoothManager.class, BLUETOOTH_SERVICE);
+ SERVICES.put(DisplayManager.class, DISPLAY_SERVICE);
+ SERVICES.put(UserManager.class, USER_SERVICE);
+
+ SERVICES.put(InputManager.class, INPUT_SERVICE);
+ SERVICES.put(MediaRouter.class, MEDIA_ROUTER_SERVICE);
+ SERVICES.put(NsdManager.class, NSD_SERVICE);
SERVICES.put(AccessibilityManager.class, ACCESSIBILITY_SERVICE);
SERVICES.put(AccountManager.class, ACCOUNT_SERVICE);
SERVICES.put(ActivityManager.class, ACTIVITY_SERVICE);
@@ -1056,40 +1038,6 @@
}
}
- @RequiresApi(17)
- static class Api17Impl {
- private Api17Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static Context createConfigurationContext(Context obj, Configuration config) {
- return obj.createConfigurationContext(config);
- }
- }
-
- @RequiresApi(19)
- static class Api19Impl {
- private Api19Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static File[] getExternalCacheDirs(Context obj) {
- return obj.getExternalCacheDirs();
- }
-
- @DoNotInline
- static File[] getExternalFilesDirs(Context obj, String type) {
- return obj.getExternalFilesDirs(type);
- }
-
- @DoNotInline
- static File[] getObbDirs(Context obj) {
- return obj.getObbDirs();
- }
- }
-
@RequiresApi(21)
static class Api21Impl {
private Api21Impl() {
diff --git a/core/core/src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java b/core/core/src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java
index f8d72df..03e4741 100644
--- a/core/core/src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java
+++ b/core/core/src/main/java/androidx/core/content/pm/ShortcutManagerCompat.java
@@ -831,8 +831,7 @@
final boolean isHorizontal) {
final ActivityManager am = (ActivityManager)
context.getSystemService(Context.ACTIVITY_SERVICE);
- final boolean isLowRamDevice =
- Build.VERSION.SDK_INT < 19 || am == null || am.isLowRamDevice();
+ final boolean isLowRamDevice = am == null || am.isLowRamDevice();
final int iconDimensionDp = Math.max(1, isLowRamDevice
? DEFAULT_MAX_ICON_DIMENSION_LOWRAM_DP : DEFAULT_MAX_ICON_DIMENSION_DP);
final DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
diff --git a/core/core/src/main/java/androidx/core/content/res/ConfigurationHelper.java b/core/core/src/main/java/androidx/core/content/res/ConfigurationHelper.java
index ca5094d..dcfb64c 100644
--- a/core/core/src/main/java/androidx/core/content/res/ConfigurationHelper.java
+++ b/core/core/src/main/java/androidx/core/content/res/ConfigurationHelper.java
@@ -16,8 +16,6 @@
package androidx.core.content.res;
-import static android.os.Build.VERSION.SDK_INT;
-
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -38,10 +36,6 @@
* is computed and returned.</p>
*/
public static int getDensityDpi(@NonNull Resources resources) {
- if (SDK_INT >= 17) {
- return resources.getConfiguration().densityDpi;
- } else {
- return resources.getDisplayMetrics().densityDpi;
- }
+ return resources.getConfiguration().densityDpi;
}
}
diff --git a/core/core/src/main/java/androidx/core/graphics/BitmapCompat.java b/core/core/src/main/java/androidx/core/graphics/BitmapCompat.java
index b10563e..25d0b7b 100644
--- a/core/core/src/main/java/androidx/core/graphics/BitmapCompat.java
+++ b/core/core/src/main/java/androidx/core/graphics/BitmapCompat.java
@@ -54,10 +54,7 @@
* @see Bitmap#hasMipMap()
*/
public static boolean hasMipMap(@NonNull Bitmap bitmap) {
- if (Build.VERSION.SDK_INT >= 17) {
- return Api17Impl.hasMipMap(bitmap);
- }
- return false;
+ return bitmap.hasMipMap();
}
/**
@@ -81,9 +78,7 @@
* @see Bitmap#setHasMipMap(boolean)
*/
public static void setHasMipMap(@NonNull Bitmap bitmap, boolean hasMipMap) {
- if (Build.VERSION.SDK_INT >= 17) {
- Api17Impl.setHasMipMap(bitmap, hasMipMap);
- }
+ bitmap.setHasMipMap(hasMipMap);
}
/**
@@ -94,10 +89,7 @@
* @see Bitmap#getAllocationByteCount()
*/
public static int getAllocationByteCount(@NonNull Bitmap bitmap) {
- if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.getAllocationByteCount(bitmap);
- }
- return bitmap.getByteCount();
+ return bitmap.getAllocationByteCount();
}
/**
@@ -334,35 +326,6 @@
// This class is not instantiable.
}
- @RequiresApi(17)
- static class Api17Impl {
- private Api17Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static boolean hasMipMap(Bitmap bitmap) {
- return bitmap.hasMipMap();
- }
-
- @DoNotInline
- static void setHasMipMap(Bitmap bitmap, boolean hasMipMap) {
- bitmap.setHasMipMap(hasMipMap);
- }
- }
-
- @RequiresApi(19)
- static class Api19Impl {
- private Api19Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static int getAllocationByteCount(Bitmap bitmap) {
- return bitmap.getAllocationByteCount();
- }
- }
-
@RequiresApi(27)
static class Api27Impl {
private Api27Impl() {
diff --git a/core/core/src/main/java/androidx/core/graphics/drawable/DrawableCompat.java b/core/core/src/main/java/androidx/core/graphics/drawable/DrawableCompat.java
index 3d01b86..a4d6ea9 100644
--- a/core/core/src/main/java/androidx/core/graphics/drawable/DrawableCompat.java
+++ b/core/core/src/main/java/androidx/core/graphics/drawable/DrawableCompat.java
@@ -77,9 +77,7 @@
* not.
*/
public static void setAutoMirrored(@NonNull Drawable drawable, boolean mirrored) {
- if (Build.VERSION.SDK_INT >= 19) {
- Api19Impl.setAutoMirrored(drawable, mirrored);
- }
+ drawable.setAutoMirrored(mirrored);
}
/**
@@ -94,11 +92,7 @@
* mirrored.
*/
public static boolean isAutoMirrored(@NonNull Drawable drawable) {
- if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.isAutoMirrored(drawable);
- } else {
- return false;
- }
+ return drawable.isAutoMirrored();
}
/**
@@ -181,11 +175,7 @@
*/
@SuppressWarnings("unused")
public static int getAlpha(@NonNull Drawable drawable) {
- if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.getAlpha(drawable);
- } else {
- return 0;
- }
+ return drawable.getAlpha();
}
/**
@@ -241,7 +231,7 @@
// to find any DrawableContainers, and then unwrap those to clear the filter on its
// children manually
if (drawable instanceof InsetDrawable) {
- clearColorFilter(Api19Impl.getDrawable((InsetDrawable) drawable));
+ clearColorFilter(((InsetDrawable) drawable).getDrawable());
} else if (drawable instanceof WrappedDrawable) {
clearColorFilter(((WrappedDrawable) drawable).getWrappedDrawable());
} else if (drawable instanceof DrawableContainer) {
@@ -251,7 +241,7 @@
if (state != null) {
Drawable child;
for (int i = 0, count = state.getChildCount(); i < count; i++) {
- child = Api19Impl.getChild(state, i);
+ child = state.getChild(i);
if (child != null) {
clearColorFilter(child);
}
@@ -435,39 +425,6 @@
private DrawableCompat() {
}
- @RequiresApi(19)
- static class Api19Impl {
- private Api19Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static void setAutoMirrored(Drawable drawable, boolean mirrored) {
- drawable.setAutoMirrored(mirrored);
- }
-
- @DoNotInline
- static boolean isAutoMirrored(Drawable drawable) {
- return drawable.isAutoMirrored();
- }
-
- @DoNotInline
- static int getAlpha(Drawable drawable) {
- return drawable.getAlpha();
- }
-
- @DoNotInline
- static Drawable getChild(DrawableContainer.DrawableContainerState drawableContainerState,
- int index) {
- return drawableContainerState.getChild(index);
- }
-
- @DoNotInline
- static Drawable getDrawable(InsetDrawable drawable) {
- return drawable.getDrawable();
- }
- }
-
@RequiresApi(21)
static class Api21Impl {
private Api21Impl() {
diff --git a/core/core/src/main/java/androidx/core/hardware/display/DisplayManagerCompat.java b/core/core/src/main/java/androidx/core/hardware/display/DisplayManagerCompat.java
index 4f6a511..396cadf 100644
--- a/core/core/src/main/java/androidx/core/hardware/display/DisplayManagerCompat.java
+++ b/core/core/src/main/java/androidx/core/hardware/display/DisplayManagerCompat.java
@@ -18,14 +18,10 @@
import android.content.Context;
import android.hardware.display.DisplayManager;
-import android.os.Build;
import android.view.Display;
-import android.view.WindowManager;
-import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
/**
* Helper for accessing features in {@link android.hardware.display.DisplayManager}.
@@ -73,17 +69,9 @@
@Nullable
@SuppressWarnings("deprecation")
public Display getDisplay(int displayId) {
- if (Build.VERSION.SDK_INT >= 17) {
- return Api17Impl.getDisplay(
- (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE), displayId);
- }
-
- Display display = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
- .getDefaultDisplay();
- if (display.getDisplayId() == displayId) {
- return display;
- }
- return null;
+ DisplayManager displayManager =
+ (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
+ return displayManager.getDisplay(displayId);
}
/**
@@ -94,14 +82,7 @@
@SuppressWarnings("deprecation")
@NonNull
public Display[] getDisplays() {
- if (Build.VERSION.SDK_INT >= 17) {
- return Api17Impl.getDisplays(
- (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE));
- }
-
- Display display = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
- .getDefaultDisplay();
- return new Display[] { display };
+ return ((DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE)).getDisplays();
}
/**
@@ -123,33 +104,6 @@
@NonNull
@SuppressWarnings("deprecation")
public Display[] getDisplays(@Nullable String category) {
- if (Build.VERSION.SDK_INT >= 17) {
- return Api17Impl.getDisplays(
- (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE));
- }
- if (category == null) {
- return new Display[0];
- }
-
- Display display = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
- .getDefaultDisplay();
- return new Display[]{display};
- }
-
- @RequiresApi(17)
- static class Api17Impl {
- private Api17Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static Display getDisplay(DisplayManager displayManager, int displayId) {
- return displayManager.getDisplay(displayId);
- }
-
- @DoNotInline
- static Display[] getDisplays(DisplayManager displayManager) {
- return displayManager.getDisplays();
- }
+ return ((DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE)).getDisplays();
}
}
diff --git a/core/core/src/main/java/androidx/core/location/LocationCompat.java b/core/core/src/main/java/androidx/core/location/LocationCompat.java
index 634dea0..883ff8a 100644
--- a/core/core/src/main/java/androidx/core/location/LocationCompat.java
+++ b/core/core/src/main/java/androidx/core/location/LocationCompat.java
@@ -16,14 +16,12 @@
package androidx.core.location;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import android.annotation.SuppressLint;
import android.location.Location;
import android.os.Build.VERSION;
import android.os.Bundle;
-import android.os.SystemClock;
import androidx.annotation.DoNotInline;
import androidx.annotation.FloatRange;
@@ -111,11 +109,7 @@
* location derivation is different from the system clock, the results may be inaccurate.
*/
public static long getElapsedRealtimeNanos(@NonNull Location location) {
- if (VERSION.SDK_INT >= 17) {
- return Api17Impl.getElapsedRealtimeNanos(location);
- } else {
- return MILLISECONDS.toNanos(getElapsedRealtimeMillis(location));
- }
+ return location.getElapsedRealtimeNanos();
}
/**
@@ -124,21 +118,7 @@
* @see #getElapsedRealtimeNanos(Location)
*/
public static long getElapsedRealtimeMillis(@NonNull Location location) {
- if (VERSION.SDK_INT >= 17) {
- return NANOSECONDS.toMillis(Api17Impl.getElapsedRealtimeNanos(location));
- } else {
- long timeDeltaMs = System.currentTimeMillis() - location.getTime();
- long elapsedRealtimeMs = SystemClock.elapsedRealtime();
- if (timeDeltaMs < 0) {
- // don't return an elapsed realtime from the future
- return elapsedRealtimeMs;
- } else if (timeDeltaMs > elapsedRealtimeMs) {
- // don't return an elapsed realtime from before boot
- return 0;
- } else {
- return elapsedRealtimeMs - timeDeltaMs;
- }
- }
+ return NANOSECONDS.toMillis(location.getElapsedRealtimeNanos());
}
/**
@@ -517,16 +497,7 @@
* @see android.location.LocationManager#addTestProvider
*/
public static boolean isMock(@NonNull Location location) {
- if (VERSION.SDK_INT >= 18) {
- return Api18Impl.isMock(location);
- } else {
- Bundle extras = location.getExtras();
- if (extras == null) {
- return false;
- }
-
- return extras.getBoolean(EXTRA_IS_MOCK, false);
- }
+ return location.isFromMockProvider();
}
/**
@@ -537,9 +508,9 @@
* boolean extra with the key {@link #EXTRA_IS_MOCK} to mark the location as mock. Be aware that
* this will overwrite any prior extra value under the same key.
*/
+ @SuppressLint("BanUncheckedReflection")
public static void setMock(@NonNull Location location, boolean mock) {
- if (VERSION.SDK_INT >= 18) {
- try {
+ try {
getSetIsFromMockProviderMethod().invoke(location, mock);
} catch (NoSuchMethodException e) {
Error error = new NoSuchMethodError();
@@ -552,25 +523,6 @@
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
- } else {
- Bundle extras = location.getExtras();
- if (extras == null) {
- if (mock) {
- extras = new Bundle();
- extras.putBoolean(EXTRA_IS_MOCK, true);
- location.setExtras(extras);
- }
- } else {
- if (mock) {
- extras.putBoolean(EXTRA_IS_MOCK, true);
- } else {
- extras.remove(EXTRA_IS_MOCK);
- if (extras.isEmpty()) {
- location.setExtras(null);
- }
- }
- }
- }
}
@RequiresApi(34)
@@ -960,30 +912,6 @@
}
}
- @RequiresApi(18)
- private static class Api18Impl {
-
- private Api18Impl() {
- }
-
- @DoNotInline
- static boolean isMock(Location location) {
- return location.isFromMockProvider();
- }
- }
-
- @RequiresApi(17)
- private static class Api17Impl {
-
- private Api17Impl() {
- }
-
- @DoNotInline
- static long getElapsedRealtimeNanos(Location location) {
- return location.getElapsedRealtimeNanos();
- }
- }
-
private static Method getSetIsFromMockProviderMethod() throws NoSuchMethodException {
if (sSetIsFromMockProviderMethod == null) {
sSetIsFromMockProviderMethod = Location.class.getDeclaredMethod("setIsFromMockProvider",
diff --git a/core/core/src/main/java/androidx/core/location/LocationManagerCompat.java b/core/core/src/main/java/androidx/core/location/LocationManagerCompat.java
index da63ac2..c53c2e4 100644
--- a/core/core/src/main/java/androidx/core/location/LocationManagerCompat.java
+++ b/core/core/src/main/java/androidx/core/location/LocationManagerCompat.java
@@ -281,7 +281,7 @@
LocationListenerTransport transport = new LocationListenerTransport(
new LocationListenerKey(provider, listener), executor);
- if (VERSION.SDK_INT >= 19 && Api19Impl.tryRequestLocationUpdates(
+ if (Api19Impl.tryRequestLocationUpdates(
locationManager, provider, locationRequest, transport)) {
return;
}
@@ -328,7 +328,7 @@
return;
}
- if (VERSION.SDK_INT >= 19 && Api19Impl.tryRequestLocationUpdates(
+ if (Api19Impl.tryRequestLocationUpdates(
locationManager, provider, locationRequest, listener, looper)) {
return;
}
@@ -1316,7 +1316,6 @@
}
}
- @RequiresApi(19)
static class Api19Impl {
private static Class<?> sLocationRequestClass;
private static Method sRequestLocationUpdatesLooperMethod;
@@ -1325,79 +1324,79 @@
// This class is not instantiable.
}
+ @SuppressLint("BanUncheckedReflection")
@SuppressWarnings("JavaReflectionMemberAccess")
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
@DoNotInline
static boolean tryRequestLocationUpdates(LocationManager locationManager,
String provider, LocationRequestCompat locationRequest,
LocationListenerTransport transport) {
- if (VERSION.SDK_INT >= 19) { // Satisfy reflection lint check
- try {
- if (sLocationRequestClass == null) {
- sLocationRequestClass = Class.forName("android.location.LocationRequest");
- }
- if (sRequestLocationUpdatesLooperMethod == null) {
- sRequestLocationUpdatesLooperMethod =
- LocationManager.class.getDeclaredMethod(
- "requestLocationUpdates",
- sLocationRequestClass, LocationListener.class,
- Looper.class);
- sRequestLocationUpdatesLooperMethod.setAccessible(true);
- }
-
- LocationRequest request = locationRequest.toLocationRequest(provider);
- if (request != null) {
- synchronized (sLocationListeners) {
- sRequestLocationUpdatesLooperMethod.invoke(locationManager, request,
- transport, Looper.getMainLooper());
- registerLocationListenerTransport(locationManager, transport);
- return true;
- }
- }
- } catch (NoSuchMethodException
- | InvocationTargetException
- | IllegalAccessException
- | ClassNotFoundException
- | UnsupportedOperationException e) {
- // ignored
+ // Satisfy reflection lint check
+ try {
+ if (sLocationRequestClass == null) {
+ sLocationRequestClass = Class.forName("android.location.LocationRequest");
}
+ if (sRequestLocationUpdatesLooperMethod == null) {
+ sRequestLocationUpdatesLooperMethod =
+ LocationManager.class.getDeclaredMethod(
+ "requestLocationUpdates",
+ sLocationRequestClass, LocationListener.class,
+ Looper.class);
+ sRequestLocationUpdatesLooperMethod.setAccessible(true);
+ }
+
+ LocationRequest request = locationRequest.toLocationRequest(provider);
+ if (request != null) {
+ synchronized (sLocationListeners) {
+ sRequestLocationUpdatesLooperMethod.invoke(locationManager, request,
+ transport, Looper.getMainLooper());
+ registerLocationListenerTransport(locationManager, transport);
+ return true;
+ }
+ }
+ } catch (NoSuchMethodException
+ | InvocationTargetException
+ | IllegalAccessException
+ | ClassNotFoundException
+ | UnsupportedOperationException e) {
+ // ignored
}
return false;
}
+ @SuppressLint("BanUncheckedReflection")
@SuppressWarnings("JavaReflectionMemberAccess")
@DoNotInline
static boolean tryRequestLocationUpdates(LocationManager locationManager, String provider,
LocationRequestCompat locationRequest, LocationListenerCompat listener,
Looper looper) {
- if (VERSION.SDK_INT >= 19) { // Satisfy reflection lint check
- try {
- if (sLocationRequestClass == null) {
- sLocationRequestClass = Class.forName("android.location.LocationRequest");
- }
-
- if (sRequestLocationUpdatesLooperMethod == null) {
- sRequestLocationUpdatesLooperMethod =
- LocationManager.class.getDeclaredMethod(
- "requestLocationUpdates",
- sLocationRequestClass, LocationListener.class,
- Looper.class);
- sRequestLocationUpdatesLooperMethod.setAccessible(true);
- }
-
- LocationRequest request = locationRequest.toLocationRequest(provider);
- if (request != null) {
- sRequestLocationUpdatesLooperMethod.invoke(
- locationManager, request, listener, looper);
- return true;
- }
- } catch (NoSuchMethodException
- | InvocationTargetException
- | IllegalAccessException
- | ClassNotFoundException
- | UnsupportedOperationException e) {
- // ignored
+ // Satisfy reflection lint check
+ try {
+ if (sLocationRequestClass == null) {
+ sLocationRequestClass = Class.forName("android.location.LocationRequest");
}
+
+ if (sRequestLocationUpdatesLooperMethod == null) {
+ sRequestLocationUpdatesLooperMethod =
+ LocationManager.class.getDeclaredMethod(
+ "requestLocationUpdates",
+ sLocationRequestClass, LocationListener.class,
+ Looper.class);
+ sRequestLocationUpdatesLooperMethod.setAccessible(true);
+ }
+
+ LocationRequest request = locationRequest.toLocationRequest(provider);
+ if (request != null) {
+ sRequestLocationUpdatesLooperMethod.invoke(
+ locationManager, request, listener, looper);
+ return true;
+ }
+ } catch (NoSuchMethodException
+ | InvocationTargetException
+ | IllegalAccessException
+ | ClassNotFoundException
+ | UnsupportedOperationException e) {
+ // ignored
}
return false;
}
diff --git a/core/core/src/main/java/androidx/core/location/LocationRequestCompat.java b/core/core/src/main/java/androidx/core/location/LocationRequestCompat.java
index 1f6eba5..9c7d074 100644
--- a/core/core/src/main/java/androidx/core/location/LocationRequestCompat.java
+++ b/core/core/src/main/java/androidx/core/location/LocationRequestCompat.java
@@ -531,69 +531,69 @@
// This class is not instantiable.
}
+ @SuppressLint("BanUncheckedReflection")
public static Object toLocationRequest(LocationRequestCompat obj, String provider) {
- if (VERSION.SDK_INT >= 19) { // Satisfy reflection lint check
- try {
- if (sLocationRequestClass == null) {
- sLocationRequestClass = Class.forName("android.location.LocationRequest");
- }
- if (sCreateFromDeprecatedProviderMethod == null) {
- sCreateFromDeprecatedProviderMethod =
- sLocationRequestClass.getDeclaredMethod(
- "createFromDeprecatedProvider", String.class, long.class,
- float.class,
- boolean.class);
- sCreateFromDeprecatedProviderMethod.setAccessible(true);
- }
-
- Object request = sCreateFromDeprecatedProviderMethod.invoke(null,
- provider,
- obj.getIntervalMillis(),
- obj.getMinUpdateDistanceMeters(), false);
- if (request == null) {
- return null;
- }
-
- if (sSetQualityMethod == null) {
- sSetQualityMethod = sLocationRequestClass.getDeclaredMethod(
- "setQuality", int.class);
- sSetQualityMethod.setAccessible(true);
- }
- sSetQualityMethod.invoke(request, obj.getQuality());
-
- if (sSetFastestIntervalMethod == null) {
- sSetFastestIntervalMethod = sLocationRequestClass.getDeclaredMethod(
- "setFastestInterval", long.class);
- sSetFastestIntervalMethod.setAccessible(true);
- }
-
- sSetFastestIntervalMethod.invoke(request, obj.getMinUpdateIntervalMillis());
-
- if (obj.getMaxUpdates() < Integer.MAX_VALUE) {
- if (sSetNumUpdatesMethod == null) {
- sSetNumUpdatesMethod = sLocationRequestClass.getDeclaredMethod(
- "setNumUpdates", int.class);
- sSetNumUpdatesMethod.setAccessible(true);
- }
-
- sSetNumUpdatesMethod.invoke(request, obj.getMaxUpdates());
- }
-
- if (obj.getDurationMillis() < Long.MAX_VALUE) {
- if (sSetExpireInMethod == null) {
- sSetExpireInMethod = sLocationRequestClass.getDeclaredMethod(
- "setExpireIn", long.class);
- sSetExpireInMethod.setAccessible(true);
- }
-
- sSetExpireInMethod.invoke(request, obj.getDurationMillis());
- }
-
- return request;
- } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException
- | ClassNotFoundException e) {
- // Ignore
+ // Satisfy reflection lint check
+ try {
+ if (sLocationRequestClass == null) {
+ sLocationRequestClass = Class.forName("android.location.LocationRequest");
}
+ if (sCreateFromDeprecatedProviderMethod == null) {
+ sCreateFromDeprecatedProviderMethod =
+ sLocationRequestClass.getDeclaredMethod(
+ "createFromDeprecatedProvider", String.class, long.class,
+ float.class,
+ boolean.class);
+ sCreateFromDeprecatedProviderMethod.setAccessible(true);
+ }
+
+ Object request = sCreateFromDeprecatedProviderMethod.invoke(null,
+ provider,
+ obj.getIntervalMillis(),
+ obj.getMinUpdateDistanceMeters(), false);
+ if (request == null) {
+ return null;
+ }
+
+ if (sSetQualityMethod == null) {
+ sSetQualityMethod = sLocationRequestClass.getDeclaredMethod(
+ "setQuality", int.class);
+ sSetQualityMethod.setAccessible(true);
+ }
+ sSetQualityMethod.invoke(request, obj.getQuality());
+
+ if (sSetFastestIntervalMethod == null) {
+ sSetFastestIntervalMethod = sLocationRequestClass.getDeclaredMethod(
+ "setFastestInterval", long.class);
+ sSetFastestIntervalMethod.setAccessible(true);
+ }
+
+ sSetFastestIntervalMethod.invoke(request, obj.getMinUpdateIntervalMillis());
+
+ if (obj.getMaxUpdates() < Integer.MAX_VALUE) {
+ if (sSetNumUpdatesMethod == null) {
+ sSetNumUpdatesMethod = sLocationRequestClass.getDeclaredMethod(
+ "setNumUpdates", int.class);
+ sSetNumUpdatesMethod.setAccessible(true);
+ }
+
+ sSetNumUpdatesMethod.invoke(request, obj.getMaxUpdates());
+ }
+
+ if (obj.getDurationMillis() < Long.MAX_VALUE) {
+ if (sSetExpireInMethod == null) {
+ sSetExpireInMethod = sLocationRequestClass.getDeclaredMethod(
+ "setExpireIn", long.class);
+ sSetExpireInMethod.setAccessible(true);
+ }
+
+ sSetExpireInMethod.invoke(request, obj.getDurationMillis());
+ }
+
+ return request;
+ } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException
+ | ClassNotFoundException e) {
+ // Ignore
}
return null;
}
diff --git a/core/core/src/main/java/androidx/core/os/BundleCompat.java b/core/core/src/main/java/androidx/core/os/BundleCompat.java
index 94555cf..3aea8a8 100644
--- a/core/core/src/main/java/androidx/core/os/BundleCompat.java
+++ b/core/core/src/main/java/androidx/core/os/BundleCompat.java
@@ -21,7 +21,6 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcelable;
-import android.util.Log;
import android.util.SparseArray;
import androidx.annotation.DoNotInline;
@@ -29,8 +28,6 @@
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.util.ArrayList;
/**
@@ -192,11 +189,7 @@
*/
@Nullable
public static IBinder getBinder(@NonNull Bundle bundle, @Nullable String key) {
- if (Build.VERSION.SDK_INT >= 18) {
- return Api18Impl.getBinder(bundle, key);
- } else {
- return BeforeApi18Impl.getBinder(bundle, key);
- }
+ return bundle.getBinder(key);
}
/**
@@ -209,11 +202,7 @@
*/
public static void putBinder(@NonNull Bundle bundle, @Nullable String key,
@Nullable IBinder binder) {
- if (Build.VERSION.SDK_INT >= 18) {
- Api18Impl.putBinder(bundle, key, binder);
- } else {
- BeforeApi18Impl.putBinder(bundle, key, binder);
- }
+ bundle.putBinder(key, binder);
}
@RequiresApi(33)
@@ -246,84 +235,4 @@
return in.getSparseParcelableArray(key, clazz);
}
}
-
- @RequiresApi(18)
- static class Api18Impl {
- private Api18Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static IBinder getBinder(Bundle bundle, String key) {
- return bundle.getBinder(key);
- }
-
- @DoNotInline
- static void putBinder(Bundle bundle, String key, IBinder value) {
- bundle.putBinder(key, value);
- }
- }
-
- @SuppressLint("BanUncheckedReflection") // Only called prior to API 18
- static class BeforeApi18Impl {
- private static final String TAG = "BundleCompat";
-
- private static Method sGetIBinderMethod;
- private static boolean sGetIBinderMethodFetched;
-
- private static Method sPutIBinderMethod;
- private static boolean sPutIBinderMethodFetched;
-
- private BeforeApi18Impl() {
- // This class is not instantiable.
- }
-
- @SuppressWarnings("JavaReflectionMemberAccess")
- public static IBinder getBinder(Bundle bundle, String key) {
- if (!sGetIBinderMethodFetched) {
- try {
- sGetIBinderMethod = Bundle.class.getMethod("getIBinder", String.class);
- sGetIBinderMethod.setAccessible(true);
- } catch (NoSuchMethodException e) {
- Log.i(TAG, "Failed to retrieve getIBinder method", e);
- }
- sGetIBinderMethodFetched = true;
- }
-
- if (sGetIBinderMethod != null) {
- try {
- return (IBinder) sGetIBinderMethod.invoke(bundle, key);
- } catch (InvocationTargetException | IllegalAccessException
- | IllegalArgumentException e) {
- Log.i(TAG, "Failed to invoke getIBinder via reflection", e);
- sGetIBinderMethod = null;
- }
- }
- return null;
- }
-
- @SuppressWarnings("JavaReflectionMemberAccess")
- public static void putBinder(Bundle bundle, String key, IBinder binder) {
- if (!sPutIBinderMethodFetched) {
- try {
- sPutIBinderMethod =
- Bundle.class.getMethod("putIBinder", String.class, IBinder.class);
- sPutIBinderMethod.setAccessible(true);
- } catch (NoSuchMethodException e) {
- Log.i(TAG, "Failed to retrieve putIBinder method", e);
- }
- sPutIBinderMethodFetched = true;
- }
-
- if (sPutIBinderMethod != null) {
- try {
- sPutIBinderMethod.invoke(bundle, key, binder);
- } catch (InvocationTargetException | IllegalAccessException
- | IllegalArgumentException e) {
- Log.i(TAG, "Failed to invoke putIBinder via reflection", e);
- sPutIBinderMethod = null;
- }
- }
- }
- }
}
diff --git a/core/core/src/main/java/androidx/core/os/ConfigurationCompat.java b/core/core/src/main/java/androidx/core/os/ConfigurationCompat.java
index e5e80dc..d4438ce 100644
--- a/core/core/src/main/java/androidx/core/os/ConfigurationCompat.java
+++ b/core/core/src/main/java/androidx/core/os/ConfigurationCompat.java
@@ -57,20 +57,7 @@
@NonNull Configuration configuration, @NonNull LocaleListCompat locales) {
if (SDK_INT >= 24) {
Api24Impl.setLocales(configuration, locales);
- } else if (SDK_INT >= 17) {
- Api17Impl.setLocale(configuration, locales);
- }
- }
-
- @RequiresApi(17)
- static class Api17Impl {
- private Api17Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static void setLocale(
- @NonNull Configuration configuration, @NonNull LocaleListCompat locales) {
+ } else {
if (!locales.isEmpty()) {
configuration.setLocale(locales.get(0));
}
diff --git a/core/core/src/main/java/androidx/core/os/EnvironmentCompat.java b/core/core/src/main/java/androidx/core/os/EnvironmentCompat.java
index 78d1f2a..98d1939 100644
--- a/core/core/src/main/java/androidx/core/os/EnvironmentCompat.java
+++ b/core/core/src/main/java/androidx/core/os/EnvironmentCompat.java
@@ -18,14 +18,12 @@
import android.os.Build;
import android.os.Environment;
-import android.util.Log;
import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import java.io.File;
-import java.io.IOException;
/**
* Helper for accessing features in {@link Environment}.
@@ -60,24 +58,9 @@
public static String getStorageState(@NonNull File path) {
if (Build.VERSION.SDK_INT >= 21) {
return Api21Impl.getExternalStorageState(path);
- } else if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.getStorageState(path);
+ } else {
+ return Environment.getStorageState(path);
}
-
- try {
- final String canonicalPath = path.getCanonicalPath();
- @SuppressWarnings("deprecation")
- final String canonicalExternal = Environment.getExternalStorageDirectory()
- .getCanonicalPath();
-
- if (canonicalPath.startsWith(canonicalExternal)) {
- return Environment.getExternalStorageState();
- }
- } catch (IOException e) {
- Log.w(TAG, "Failed to resolve canonical path: " + e);
- }
-
- return MEDIA_UNKNOWN;
}
private EnvironmentCompat() {
@@ -94,16 +77,4 @@
return Environment.getExternalStorageState(path);
}
}
-
- @RequiresApi(19)
- static class Api19Impl {
- private Api19Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static String getStorageState(File path) {
- return Environment.getStorageState(path);
- }
- }
}
diff --git a/core/core/src/main/java/androidx/core/os/ProcessCompat.java b/core/core/src/main/java/androidx/core/os/ProcessCompat.java
index 6343cf3..f2c38d0 100644
--- a/core/core/src/main/java/androidx/core/os/ProcessCompat.java
+++ b/core/core/src/main/java/androidx/core/os/ProcessCompat.java
@@ -54,12 +54,8 @@
public static boolean isApplicationUid(int uid) {
if (Build.VERSION.SDK_INT >= 24) {
return Api24Impl.isApplicationUid(uid);
- } else if (Build.VERSION.SDK_INT >= 17) {
- return Api17Impl.isApplicationUid(uid);
- } else if (Build.VERSION.SDK_INT == 16) {
- return Api16Impl.isApplicationUid(uid);
} else {
- return true;
+ return Api17Impl.isApplicationUid(uid);
}
}
@@ -76,7 +72,6 @@
}
}
- @RequiresApi(17)
static class Api17Impl {
private static final Object sResolvedLock = new Object();
@@ -114,43 +109,4 @@
return true;
}
}
-
- @RequiresApi(16)
- static class Api16Impl {
- private static final Object sResolvedLock = new Object();
-
- private static Method sMethodUserIdIsAppMethod;
- private static boolean sResolved;
-
- private Api16Impl() {
- // This class is non-instantiable.
- }
-
- @SuppressLint("PrivateApi")
- @SuppressWarnings("CatchAndPrintStackTrace")
- static boolean isApplicationUid(int uid) {
- // In JELLY_BEAN_MR1, the equivalent isApp(int) hidden method was available on hidden
- // class android.os.UserId.
- try {
- synchronized (sResolvedLock) {
- if (!sResolved) {
- sResolved = true;
- sMethodUserIdIsAppMethod = Class.forName("android.os.UserId")
- .getDeclaredMethod("isApp", int.class);
- }
- }
- if (sMethodUserIdIsAppMethod != null) {
- Boolean result = (Boolean) sMethodUserIdIsAppMethod.invoke(null, uid);
- if (result == null) {
- // This should never happen, as the method returns a boolean primitive.
- throw new NullPointerException();
- }
- return result;
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return true;
- }
- }
}
diff --git a/core/core/src/main/java/androidx/core/os/TraceCompat.java b/core/core/src/main/java/androidx/core/os/TraceCompat.java
index f5022c6..7689534 100644
--- a/core/core/src/main/java/androidx/core/os/TraceCompat.java
+++ b/core/core/src/main/java/androidx/core/os/TraceCompat.java
@@ -81,7 +81,7 @@
public static boolean isEnabled() {
if (Build.VERSION.SDK_INT >= 29) {
return Api29Impl.isEnabled();
- } else if (Build.VERSION.SDK_INT >= 18) {
+ } else {
try {
return (boolean) sIsTagEnabledMethod.invoke(null, sTraceTagApp);
} catch (Exception e) {
@@ -105,9 +105,7 @@
* most 127 Unicode code units long.
*/
public static void beginSection(@NonNull String sectionName) {
- if (Build.VERSION.SDK_INT >= 18) {
- Api18Impl.beginSection(sectionName);
- }
+ Trace.beginSection(sectionName);
}
/**
@@ -118,9 +116,7 @@
* thread.
*/
public static void endSection() {
- if (Build.VERSION.SDK_INT >= 18) {
- Api18Impl.endSection();
- }
+ Trace.endSection();
}
/**
@@ -136,7 +132,7 @@
public static void beginAsyncSection(@NonNull String methodName, int cookie) {
if (Build.VERSION.SDK_INT >= 29) {
Api29Impl.beginAsyncSection(methodName, cookie);
- } else if (Build.VERSION.SDK_INT >= 18) {
+ } else {
try {
sAsyncTraceBeginMethod.invoke(null, sTraceTagApp, methodName, cookie);
} catch (Exception e) {
@@ -156,7 +152,7 @@
public static void endAsyncSection(@NonNull String methodName, int cookie) {
if (Build.VERSION.SDK_INT >= 29) {
Api29Impl.endAsyncSection(methodName, cookie);
- } else if (Build.VERSION.SDK_INT >= 18) {
+ } else {
try {
sAsyncTraceEndMethod.invoke(null, sTraceTagApp, methodName, cookie);
} catch (Exception e) {
@@ -175,7 +171,7 @@
public static void setCounter(@NonNull String counterName, int counterValue) {
if (Build.VERSION.SDK_INT >= 29) {
Api29Impl.setCounter(counterName, counterValue);
- } else if (Build.VERSION.SDK_INT >= 18) {
+ } else {
try {
sTraceCounterMethod.invoke(null, sTraceTagApp, counterName, counterValue);
} catch (Exception e) {
@@ -213,21 +209,4 @@
Trace.setCounter(counterName, counterValue);
}
}
-
- @RequiresApi(18)
- static class Api18Impl {
- private Api18Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static void beginSection(String sectionName) {
- Trace.beginSection(sectionName);
- }
-
- @DoNotInline
- static void endSection() {
- Trace.endSection();
- }
- }
}
diff --git a/core/core/src/main/java/androidx/core/provider/DocumentsContractCompat.java b/core/core/src/main/java/androidx/core/provider/DocumentsContractCompat.java
index 3765bfc..923f3c4 100644
--- a/core/core/src/main/java/androidx/core/provider/DocumentsContractCompat.java
+++ b/core/core/src/main/java/androidx/core/provider/DocumentsContractCompat.java
@@ -66,10 +66,7 @@
* @see DocumentsContract#isDocumentUri(Context, Uri)
*/
public static boolean isDocumentUri(@NonNull Context context, @Nullable Uri uri) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- return DocumentsContractApi19Impl.isDocumentUri(context, uri);
- }
- return false;
+ return DocumentsContract.isDocumentUri(context, uri);
}
/**
@@ -96,10 +93,7 @@
*/
@Nullable
public static String getDocumentId(@NonNull Uri documentUri) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- return DocumentsContractApi19Impl.getDocumentId(documentUri);
- }
- return null;
+ return DocumentsContract.getDocumentId(documentUri);
}
/**
@@ -124,10 +118,7 @@
*/
@Nullable
public static Uri buildDocumentUri(@NonNull String authority, @NonNull String documentId) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- return DocumentsContractApi19Impl.buildDocumentUri(authority, documentId);
- }
- return null;
+ return DocumentsContract.buildDocumentUri(authority, documentId);
}
/**
@@ -243,39 +234,9 @@
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return DocumentsContractApi24Impl.removeDocument(content, documentUri,
parentDocumentUri);
- } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- return DocumentsContractApi19Impl.deleteDocument(content, documentUri);
} else {
- return false;
- }
- }
-
- @RequiresApi(19)
- private static class DocumentsContractApi19Impl {
-
- @DoNotInline
- public static Uri buildDocumentUri(String authority, String documentId) {
- return DocumentsContract.buildDocumentUri(authority, documentId);
- }
-
- @DoNotInline
- static boolean isDocumentUri(Context context, @Nullable Uri uri) {
- return DocumentsContract.isDocumentUri(context, uri);
- }
-
- @DoNotInline
- static String getDocumentId(Uri documentUri) {
- return DocumentsContract.getDocumentId(documentUri);
- }
-
- @DoNotInline
- static boolean deleteDocument(ContentResolver content, Uri documentUri)
- throws FileNotFoundException {
return DocumentsContract.deleteDocument(content, documentUri);
}
-
- private DocumentsContractApi19Impl() {
- }
}
@RequiresApi(21)
diff --git a/core/core/src/main/java/androidx/core/provider/FontProvider.java b/core/core/src/main/java/androidx/core/provider/FontProvider.java
index 6b2101b..1559dff 100644
--- a/core/core/src/main/java/androidx/core/provider/FontProvider.java
+++ b/core/core/src/main/java/androidx/core/provider/FontProvider.java
@@ -238,9 +238,7 @@
void close();
static ContentQueryWrapper make(Context context, Uri uri) {
- if (Build.VERSION.SDK_INT < 16) {
- return new ContentQueryWrapperBaseImpl(context);
- } else if (Build.VERSION.SDK_INT < 24) {
+ if (Build.VERSION.SDK_INT < 24) {
return new ContentQueryWrapperApi16Impl(context, uri);
} else {
return new ContentQueryWrapperApi24Impl(context, uri);
@@ -248,25 +246,6 @@
}
}
- private static class ContentQueryWrapperBaseImpl implements ContentQueryWrapper {
- private ContentResolver mResolver;
- ContentQueryWrapperBaseImpl(Context context) {
- mResolver = context.getContentResolver();
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
- String sortOrder, CancellationSignal cancellationSignal) {
- return mResolver.query(uri, projection, selection, selectionArgs, sortOrder);
- }
-
- @Override
- public void close() {
- mResolver = null;
- }
- }
-
- @RequiresApi(16)
private static class ContentQueryWrapperApi16Impl implements ContentQueryWrapper {
private final ContentProviderClient mClient;
ContentQueryWrapperApi16Impl(Context context, Uri uri) {
diff --git a/core/core/src/main/java/androidx/core/text/TextUtilsCompat.java b/core/core/src/main/java/androidx/core/text/TextUtilsCompat.java
index 3085998..bdcd81ee 100644
--- a/core/core/src/main/java/androidx/core/text/TextUtilsCompat.java
+++ b/core/core/src/main/java/androidx/core/text/TextUtilsCompat.java
@@ -16,14 +16,10 @@
package androidx.core.text;
-import static android.os.Build.VERSION.SDK_INT;
-
import android.text.TextUtils;
-import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
import androidx.core.view.ViewCompat;
import java.util.Locale;
@@ -32,9 +28,6 @@
* Backwards compatible version of {@link TextUtils}.
*/
public final class TextUtilsCompat {
- private static final Locale ROOT = new Locale("", "");
- private static final String ARAB_SCRIPT_SUBTAG = "Arab";
- private static final String HEBR_SCRIPT_SUBTAG = "Hebr";
/**
* Html-encode the string.
@@ -44,40 +37,7 @@
*/
@NonNull
public static String htmlEncode(@NonNull String s) {
- if (SDK_INT >= 17) {
- return TextUtils.htmlEncode(s);
- } else {
- StringBuilder sb = new StringBuilder();
- char c;
- for (int i = 0; i < s.length(); i++) {
- c = s.charAt(i);
- switch (c) {
- case '<':
- sb.append("<"); //$NON-NLS-1$
- break;
- case '>':
- sb.append(">"); //$NON-NLS-1$
- break;
- case '&':
- sb.append("&"); //$NON-NLS-1$
- break;
- case '\'':
- //http://www.w3.org/TR/xhtml1
- // The named character reference ' (the apostrophe, U+0027) was
- // introduced in XML 1.0 but does not appear in HTML. Authors should
- // therefore use ' instead of ' to work as expected in HTML 4
- // user agents.
- sb.append("'"); //$NON-NLS-1$
- break;
- case '"':
- sb.append("""); //$NON-NLS-1$
- break;
- default:
- sb.append(c);
- }
- }
- return sb.toString();
- }
+ return TextUtils.htmlEncode(s);
}
/**
@@ -89,58 +49,9 @@
* {@link ViewCompat#LAYOUT_DIRECTION_RTL}.
*/
public static int getLayoutDirectionFromLocale(@Nullable Locale locale) {
- if (SDK_INT >= 17) {
- return Api17Impl.getLayoutDirectionFromLocale(locale);
- } else {
- if (locale != null && !locale.equals(ROOT)) {
- final String scriptSubtag = ICUCompat.maximizeAndGetScript(locale);
- if (scriptSubtag == null) return getLayoutDirectionFromFirstChar(locale);
-
- // This is intentionally limited to Arabic and Hebrew scripts, since older
- // versions of Android platform only considered those scripts to be right-to-left.
- if (scriptSubtag.equalsIgnoreCase(ARAB_SCRIPT_SUBTAG)
- || scriptSubtag.equalsIgnoreCase(HEBR_SCRIPT_SUBTAG)) {
- return ViewCompat.LAYOUT_DIRECTION_RTL;
- }
- }
- return ViewCompat.LAYOUT_DIRECTION_LTR;
- }
- }
-
- /**
- * Fallback algorithm to detect the locale direction. Rely on the first char of the
- * localized locale name. This will not work if the localized locale name is in English
- * (this is the case for ICU 4.4 and "Urdu" script)
- *
- * @param locale the {@link Locale} for which we want the layout direction, maybe be
- * {@code null}.
- * @return the layout direction, either {@link ViewCompat#LAYOUT_DIRECTION_LTR} or
- * {@link ViewCompat#LAYOUT_DIRECTION_RTL}.
- */
- private static int getLayoutDirectionFromFirstChar(@NonNull Locale locale) {
- switch(Character.getDirectionality(locale.getDisplayName(locale).charAt(0))) {
- case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
- case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
- return ViewCompat.LAYOUT_DIRECTION_RTL;
-
- case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
- default:
- return ViewCompat.LAYOUT_DIRECTION_LTR;
- }
+ return TextUtils.getLayoutDirectionFromLocale(locale);
}
private TextUtilsCompat() {
}
-
- @RequiresApi(17)
- static class Api17Impl {
- private Api17Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static int getLayoutDirectionFromLocale(Locale locale) {
- return TextUtils.getLayoutDirectionFromLocale(locale);
- }
- }
}
diff --git a/core/core/src/main/java/androidx/core/util/ObjectsCompat.java b/core/core/src/main/java/androidx/core/util/ObjectsCompat.java
index e9e5ccb..b7b9a03 100644
--- a/core/core/src/main/java/androidx/core/util/ObjectsCompat.java
+++ b/core/core/src/main/java/androidx/core/util/ObjectsCompat.java
@@ -15,12 +15,8 @@
*/
package androidx.core.util;
-import android.os.Build;
-
-import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
import java.util.Arrays;
import java.util.Objects;
@@ -51,11 +47,7 @@
*/
@SuppressWarnings("EqualsReplaceableByObjectsCall")
public static boolean equals(@Nullable Object a, @Nullable Object b) {
- if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.equals(a, b);
- } else {
- return (a == b) || (a != null && a.equals(b));
- }
+ return Objects.equals(a, b);
}
/**
@@ -93,11 +85,7 @@
* @see Arrays#hashCode(Object[])
*/
public static int hash(@Nullable Object... values) {
- if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.hash(values);
- } else {
- return Arrays.hashCode(values);
- }
+ return Objects.hash(values);
}
/**
@@ -159,21 +147,4 @@
if (obj == null) throw new NullPointerException(message);
return obj;
}
-
- @RequiresApi(19)
- static class Api19Impl {
- private Api19Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static boolean equals(Object a, Object b) {
- return Objects.equals(a, b);
- }
-
- @DoNotInline
- static int hash(Object... values) {
- return Objects.hash(values);
- }
- }
}
diff --git a/core/core/src/main/java/androidx/core/view/GravityCompat.java b/core/core/src/main/java/androidx/core/view/GravityCompat.java
index 5935241..b7e1215 100644
--- a/core/core/src/main/java/androidx/core/view/GravityCompat.java
+++ b/core/core/src/main/java/androidx/core/view/GravityCompat.java
@@ -17,14 +17,10 @@
package androidx.core.view;
-import static android.os.Build.VERSION.SDK_INT;
-
import android.graphics.Rect;
import android.view.Gravity;
-import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
/**
* Compatibility shim for accessing newer functionality from {@link Gravity}.
@@ -65,11 +61,7 @@
*/
public static void apply(int gravity, int w, int h, @NonNull Rect container,
@NonNull Rect outRect, int layoutDirection) {
- if (SDK_INT >= 17) {
- Api17Impl.apply(gravity, w, h, container, outRect, layoutDirection);
- } else {
- Gravity.apply(gravity, w, h, container, outRect);
- }
+ Gravity.apply(gravity, w, h, container, outRect, layoutDirection);
}
/**
@@ -99,11 +91,7 @@
*/
public static void apply(int gravity, int w, int h, @NonNull Rect container,
int xAdj, int yAdj, @NonNull Rect outRect, int layoutDirection) {
- if (SDK_INT >= 17) {
- Api17Impl.apply(gravity, w, h, container, xAdj, yAdj, outRect, layoutDirection);
- } else {
- Gravity.apply(gravity, w, h, container, xAdj, yAdj, outRect);
- }
+ Gravity.apply(gravity, w, h, container, xAdj, yAdj, outRect, layoutDirection);
}
/**
@@ -128,11 +116,7 @@
*/
public static void applyDisplay(int gravity, @NonNull Rect display, @NonNull Rect inoutObj,
int layoutDirection) {
- if (SDK_INT >= 17) {
- Api17Impl.applyDisplay(gravity, display, inoutObj, layoutDirection);
- } else {
- Gravity.applyDisplay(gravity, display, inoutObj);
- }
+ Gravity.applyDisplay(gravity, display, inoutObj, layoutDirection);
}
/**
@@ -147,38 +131,9 @@
* @return gravity converted to absolute (horizontal) values.
*/
public static int getAbsoluteGravity(int gravity, int layoutDirection) {
- if (SDK_INT >= 17) {
- return Gravity.getAbsoluteGravity(gravity, layoutDirection);
- } else {
- // Just strip off the relative bit to get LEFT/RIGHT.
- return gravity & ~RELATIVE_LAYOUT_DIRECTION;
- }
+ return Gravity.getAbsoluteGravity(gravity, layoutDirection);
}
private GravityCompat() {
}
-
- @RequiresApi(17)
- static class Api17Impl {
- private Api17Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static void apply(int gravity, int w, int h, Rect container, Rect outRect,
- int layoutDirection) {
- Gravity.apply(gravity, w, h, container, outRect, layoutDirection);
- }
-
- @DoNotInline
- static void apply(int gravity, int w, int h, Rect container, int xAdj, int yAdj,
- Rect outRect, int layoutDirection) {
- Gravity.apply(gravity, w, h, container, xAdj, yAdj, outRect, layoutDirection);
- }
-
- @DoNotInline
- static void applyDisplay(int gravity, Rect display, Rect inoutObj, int layoutDirection) {
- Gravity.applyDisplay(gravity, display, inoutObj, layoutDirection);
- }
- }
}
diff --git a/core/core/src/main/java/androidx/core/view/MarginLayoutParamsCompat.java b/core/core/src/main/java/androidx/core/view/MarginLayoutParamsCompat.java
index 4237d43..8039d09 100644
--- a/core/core/src/main/java/androidx/core/view/MarginLayoutParamsCompat.java
+++ b/core/core/src/main/java/androidx/core/view/MarginLayoutParamsCompat.java
@@ -17,14 +17,10 @@
package androidx.core.view;
-import static android.os.Build.VERSION.SDK_INT;
-
import android.view.View;
import android.view.ViewGroup;
-import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
/**
* Helper for accessing API features in
@@ -44,11 +40,7 @@
* @return the margin along the starting edge in pixels
*/
public static int getMarginStart(@NonNull ViewGroup.MarginLayoutParams lp) {
- if (SDK_INT >= 17) {
- return Api17Impl.getMarginStart(lp);
- } else {
- return lp.leftMargin;
- }
+ return lp.getMarginStart();
}
/**
@@ -63,11 +55,7 @@
* @return the margin along the ending edge in pixels
*/
public static int getMarginEnd(@NonNull ViewGroup.MarginLayoutParams lp) {
- if (SDK_INT >= 17) {
- return Api17Impl.getMarginEnd(lp);
- } else {
- return lp.rightMargin;
- }
+ return lp.getMarginEnd();
}
/**
@@ -82,11 +70,7 @@
* @param marginStart the desired start margin in pixels
*/
public static void setMarginStart(@NonNull ViewGroup.MarginLayoutParams lp, int marginStart) {
- if (SDK_INT >= 17) {
- Api17Impl.setMarginStart(lp, marginStart);
- } else {
- lp.leftMargin = marginStart;
- }
+ lp.setMarginStart(marginStart);
}
/**
@@ -101,11 +85,7 @@
* @param marginEnd the desired end margin in pixels
*/
public static void setMarginEnd(@NonNull ViewGroup.MarginLayoutParams lp, int marginEnd) {
- if (SDK_INT >= 17) {
- Api17Impl.setMarginEnd(lp, marginEnd);
- } else {
- lp.rightMargin = marginEnd;
- }
+ lp.setMarginEnd(marginEnd);
}
/**
@@ -114,11 +94,7 @@
* @return true if either marginStart or marginEnd has been set.
*/
public static boolean isMarginRelative(@NonNull ViewGroup.MarginLayoutParams lp) {
- if (SDK_INT >= 17) {
- return Api17Impl.isMarginRelative(lp);
- } else {
- return false;
- }
+ return lp.isMarginRelative();
}
/**
@@ -129,11 +105,7 @@
*/
public static int getLayoutDirection(@NonNull ViewGroup.MarginLayoutParams lp) {
int result;
- if (SDK_INT >= 17) {
- result = Api17Impl.getLayoutDirection(lp);
- } else {
- result = ViewCompat.LAYOUT_DIRECTION_LTR;
- }
+ result = lp.getLayoutDirection();
if ((result != ViewCompat.LAYOUT_DIRECTION_LTR)
&& (result != ViewCompat.LAYOUT_DIRECTION_RTL)) {
@@ -154,9 +126,7 @@
*/
public static void setLayoutDirection(@NonNull ViewGroup.MarginLayoutParams lp,
int layoutDirection) {
- if (SDK_INT >= 17) {
- Api17Impl.setLayoutDirection(lp, layoutDirection);
- }
+ lp.setLayoutDirection(layoutDirection);
}
/**
@@ -165,60 +135,10 @@
*/
public static void resolveLayoutDirection(@NonNull ViewGroup.MarginLayoutParams lp,
int layoutDirection) {
- if (SDK_INT >= 17) {
- Api17Impl.resolveLayoutDirection(lp, layoutDirection);
- }
+ lp.resolveLayoutDirection(layoutDirection);
}
private MarginLayoutParamsCompat() {
}
- @RequiresApi(17)
- static class Api17Impl {
- private Api17Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static int getMarginStart(ViewGroup.MarginLayoutParams marginLayoutParams) {
- return marginLayoutParams.getMarginStart();
- }
-
- @DoNotInline
- static int getMarginEnd(ViewGroup.MarginLayoutParams marginLayoutParams) {
- return marginLayoutParams.getMarginEnd();
- }
-
- @DoNotInline
- static void setMarginStart(ViewGroup.MarginLayoutParams marginLayoutParams, int start) {
- marginLayoutParams.setMarginStart(start);
- }
-
- @DoNotInline
- static void setMarginEnd(ViewGroup.MarginLayoutParams marginLayoutParams, int end) {
- marginLayoutParams.setMarginEnd(end);
- }
-
- @DoNotInline
- static boolean isMarginRelative(ViewGroup.MarginLayoutParams marginLayoutParams) {
- return marginLayoutParams.isMarginRelative();
- }
-
- @DoNotInline
- static int getLayoutDirection(ViewGroup.MarginLayoutParams marginLayoutParams) {
- return marginLayoutParams.getLayoutDirection();
- }
-
- @DoNotInline
- static void setLayoutDirection(ViewGroup.MarginLayoutParams marginLayoutParams,
- int layoutDirection) {
- marginLayoutParams.setLayoutDirection(layoutDirection);
- }
-
- @DoNotInline
- static void resolveLayoutDirection(ViewGroup.MarginLayoutParams marginLayoutParams,
- int layoutDirection) {
- marginLayoutParams.resolveLayoutDirection(layoutDirection);
- }
- }
}
diff --git a/core/core/src/main/java/androidx/core/view/ScaleGestureDetectorCompat.java b/core/core/src/main/java/androidx/core/view/ScaleGestureDetectorCompat.java
index 317f3b4..f24ea50 100644
--- a/core/core/src/main/java/androidx/core/view/ScaleGestureDetectorCompat.java
+++ b/core/core/src/main/java/androidx/core/view/ScaleGestureDetectorCompat.java
@@ -16,12 +16,9 @@
package androidx.core.view;
-import android.os.Build;
import android.view.ScaleGestureDetector;
-import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
/**
* Helper for accessing features in {@link ScaleGestureDetector}.
@@ -56,9 +53,7 @@
*/
public static void setQuickScaleEnabled(
@NonNull ScaleGestureDetector scaleGestureDetector, boolean enabled) {
- if (Build.VERSION.SDK_INT >= 19) {
- Api19Impl.setQuickScaleEnabled(scaleGestureDetector, enabled);
- }
+ scaleGestureDetector.setQuickScaleEnabled(enabled);
}
/**
@@ -81,28 +76,6 @@
* {@link #setQuickScaleEnabled(ScaleGestureDetector, boolean)}.
*/
public static boolean isQuickScaleEnabled(@NonNull ScaleGestureDetector scaleGestureDetector) {
- if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.isQuickScaleEnabled(scaleGestureDetector);
- } else {
- return false;
- }
- }
-
- @RequiresApi(19)
- static class Api19Impl {
- private Api19Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static void setQuickScaleEnabled(ScaleGestureDetector scaleGestureDetector,
- boolean scales) {
- scaleGestureDetector.setQuickScaleEnabled(scales);
- }
-
- @DoNotInline
- static boolean isQuickScaleEnabled(ScaleGestureDetector scaleGestureDetector) {
- return scaleGestureDetector.isQuickScaleEnabled();
- }
+ return scaleGestureDetector.isQuickScaleEnabled();
}
}
diff --git a/core/core/src/main/java/androidx/core/view/ViewGroupCompat.java b/core/core/src/main/java/androidx/core/view/ViewGroupCompat.java
index 207e55f..3034440 100644
--- a/core/core/src/main/java/androidx/core/view/ViewGroupCompat.java
+++ b/core/core/src/main/java/androidx/core/view/ViewGroupCompat.java
@@ -113,10 +113,7 @@
* @see #setLayoutMode(ViewGroup, int)
*/
public static int getLayoutMode(@NonNull ViewGroup group) {
- if (Build.VERSION.SDK_INT >= 18) {
- return Api18Impl.getLayoutMode(group);
- }
- return LAYOUT_MODE_CLIP_BOUNDS;
+ return group.getLayoutMode();
}
/**
@@ -130,9 +127,7 @@
* @see #getLayoutMode(ViewGroup)
*/
public static void setLayoutMode(@NonNull ViewGroup group, int mode) {
- if (Build.VERSION.SDK_INT >= 18) {
- Api18Impl.setLayoutMode(group, mode);
- }
+ group.setLayoutMode(mode);
}
/**
@@ -191,23 +186,6 @@
return ViewCompat.SCROLL_AXIS_NONE;
}
- @RequiresApi(18)
- static class Api18Impl {
- private Api18Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static int getLayoutMode(ViewGroup viewGroup) {
- return viewGroup.getLayoutMode();
- }
-
- @DoNotInline
- static void setLayoutMode(ViewGroup viewGroup, int layoutMode) {
- viewGroup.setLayoutMode(layoutMode);
- }
- }
-
@RequiresApi(21)
static class Api21Impl {
private Api21Impl() {
diff --git a/core/core/src/main/java/androidx/core/view/ViewParentCompat.java b/core/core/src/main/java/androidx/core/view/ViewParentCompat.java
index 517fc9b8..1e3cdef 100644
--- a/core/core/src/main/java/androidx/core/view/ViewParentCompat.java
+++ b/core/core/src/main/java/androidx/core/view/ViewParentCompat.java
@@ -507,9 +507,7 @@
*/
public static void notifySubtreeAccessibilityStateChanged(@NonNull ViewParent parent,
@NonNull View child, @NonNull View source, int changeType) {
- if (Build.VERSION.SDK_INT >= 19) {
- Api19Impl.notifySubtreeAccessibilityStateChanged(parent, child, source, changeType);
- }
+ parent.notifySubtreeAccessibilityStateChanged(child, source, changeType);
}
private static int[] getTempNestedScrollConsumed() {
@@ -522,19 +520,6 @@
return sTempNestedScrollConsumed;
}
- @RequiresApi(19)
- static class Api19Impl {
- private Api19Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static void notifySubtreeAccessibilityStateChanged(ViewParent viewParent, View view,
- View view1, int i) {
- viewParent.notifySubtreeAccessibilityStateChanged(view, view1, i);
- }
- }
-
@RequiresApi(21)
static class Api21Impl {
private Api21Impl() {
diff --git a/core/core/src/main/java/androidx/core/view/ViewPropertyAnimatorCompat.java b/core/core/src/main/java/androidx/core/view/ViewPropertyAnimatorCompat.java
index 2e6d559..daa7481 100644
--- a/core/core/src/main/java/androidx/core/view/ViewPropertyAnimatorCompat.java
+++ b/core/core/src/main/java/androidx/core/view/ViewPropertyAnimatorCompat.java
@@ -228,13 +228,8 @@
public ViewPropertyAnimatorCompat withEndAction(@NonNull Runnable runnable) {
View view;
if ((view = mView.get()) != null) {
- if (Build.VERSION.SDK_INT >= 16) {
- ViewPropertyAnimator animator = view.animate();
- Api16Impl.withEndAction(animator, runnable);
- } else {
- setListenerInternal(view, new ViewPropertyAnimatorListenerApi14(this));
- mEndAction = runnable;
- }
+ ViewPropertyAnimator animator = view.animate();
+ animator.withEndAction(runnable);
}
return this;
}
@@ -282,10 +277,8 @@
public Interpolator getInterpolator() {
View view;
if ((view = mView.get()) != null) {
- if (Build.VERSION.SDK_INT >= 18) {
- ViewPropertyAnimator animator = view.animate();
- return Api18Impl.getInterpolator(animator);
- }
+ ViewPropertyAnimator animator = view.animate();
+ return (Interpolator) animator.getInterpolator();
}
return null;
}
@@ -722,13 +715,8 @@
public ViewPropertyAnimatorCompat withLayer() {
View view;
if ((view = mView.get()) != null) {
- if (Build.VERSION.SDK_INT >= 16) {
- ViewPropertyAnimator animator = view.animate();
- Api16Impl.withLayer(animator);
- } else {
- mOldLayerType = view.getLayerType();
- setListenerInternal(view, new ViewPropertyAnimatorListenerApi14(this));
- }
+ ViewPropertyAnimator animator = view.animate();
+ animator.withLayer();
}
return this;
}
@@ -752,13 +740,8 @@
public ViewPropertyAnimatorCompat withStartAction(@NonNull Runnable runnable) {
View view;
if ((view = mView.get()) != null) {
- if (Build.VERSION.SDK_INT >= 16) {
- ViewPropertyAnimator animator = view.animate();
- Api16Impl.withStartAction(animator, runnable);
- } else {
- setListenerInternal(view, new ViewPropertyAnimatorListenerApi14(this));
- mStartAction = runnable;
- }
+ ViewPropertyAnimator animator = view.animate();
+ animator.withStartAction(runnable);
}
return this;
}
@@ -819,55 +802,16 @@
final @Nullable ViewPropertyAnimatorUpdateListener listener) {
final View view;
if ((view = mView.get()) != null) {
- if (Build.VERSION.SDK_INT >= 19) {
- ValueAnimator.AnimatorUpdateListener wrapped = null;
- if (listener != null) {
+ ValueAnimator.AnimatorUpdateListener wrapped = null;
+ if (listener != null) {
wrapped = valueAnimator -> listener.onAnimationUpdate(view);
}
- ViewPropertyAnimator animator = view.animate();
- Api19Impl.setUpdateListener(animator, wrapped);
- }
+ ViewPropertyAnimator animator = view.animate();
+ animator.setUpdateListener(wrapped);
}
return this;
}
- @RequiresApi(16)
- static class Api16Impl {
- private Api16Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static ViewPropertyAnimator withEndAction(ViewPropertyAnimator viewPropertyAnimator,
- Runnable runnable) {
- return viewPropertyAnimator.withEndAction(runnable);
- }
-
- @DoNotInline
- static ViewPropertyAnimator withLayer(ViewPropertyAnimator viewPropertyAnimator) {
- return viewPropertyAnimator.withLayer();
- }
-
- @DoNotInline
- static ViewPropertyAnimator withStartAction(ViewPropertyAnimator viewPropertyAnimator,
- Runnable runnable) {
- return viewPropertyAnimator.withStartAction(runnable);
- }
- }
-
- @RequiresApi(18)
- static class Api18Impl {
- private Api18Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static Interpolator getInterpolator(ViewPropertyAnimator viewPropertyAnimator) {
- return (Interpolator) viewPropertyAnimator.getInterpolator();
- }
-
- }
-
@RequiresApi(21)
static class Api21Impl {
private Api21Impl() {
@@ -896,18 +840,4 @@
return viewPropertyAnimator.zBy(value);
}
}
-
- @RequiresApi(19)
- static class Api19Impl {
- private Api19Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static ViewPropertyAnimator setUpdateListener(ViewPropertyAnimator viewPropertyAnimator,
- ValueAnimator.AnimatorUpdateListener listener) {
- return viewPropertyAnimator.setUpdateListener(listener);
- }
-
- }
}
diff --git a/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityEventCompat.java b/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityEventCompat.java
index fec6650..30470be 100644
--- a/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityEventCompat.java
+++ b/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityEventCompat.java
@@ -18,6 +18,7 @@
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;
+import android.annotation.SuppressLint;
import android.os.Build;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
@@ -431,9 +432,7 @@
*/
public static void setContentChangeTypes(@NonNull AccessibilityEvent event,
@ContentChangeType int changeTypes) {
- if (Build.VERSION.SDK_INT >= 19) {
- Api19Impl.setContentChangeTypes(event, changeTypes);
- }
+ event.setContentChangeTypes(changeTypes);
}
/**
@@ -450,13 +449,10 @@
* <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_UNDEFINED}
* </ul>
*/
+ @SuppressLint("WrongConstant")
@ContentChangeType
public static int getContentChangeTypes(@NonNull AccessibilityEvent event) {
- if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.getContentChangeTypes(event);
- } else {
- return 0;
- }
+ return event.getContentChangeTypes();
}
/**
@@ -577,20 +573,4 @@
event.setAccessibilityDataSensitive(accessibilityDataSensitive);
}
}
- @RequiresApi(19)
- static class Api19Impl {
- private Api19Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static void setContentChangeTypes(AccessibilityEvent accessibilityEvent, int changeTypes) {
- accessibilityEvent.setContentChangeTypes(changeTypes);
- }
-
- @DoNotInline
- static int getContentChangeTypes(AccessibilityEvent accessibilityEvent) {
- return accessibilityEvent.getContentChangeTypes();
- }
- }
}
diff --git a/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityManagerCompat.java b/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityManagerCompat.java
index a5e0a2b..0073c4b 100644
--- a/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityManagerCompat.java
+++ b/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityManagerCompat.java
@@ -168,11 +168,8 @@
public static boolean addTouchExplorationStateChangeListener(
@NonNull AccessibilityManager manager,
@NonNull TouchExplorationStateChangeListener listener) {
- if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.addTouchExplorationStateChangeListenerWrapper(manager, listener);
- } else {
- return false;
- }
+ return manager.addTouchExplorationStateChangeListener(
+ new TouchExplorationStateChangeListenerWrapper(listener));
}
/**
@@ -185,11 +182,8 @@
public static boolean removeTouchExplorationStateChangeListener(
@NonNull AccessibilityManager manager,
@NonNull TouchExplorationStateChangeListener listener) {
- if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.removeTouchExplorationStateChangeListenerWrapper(manager, listener);
- } else {
- return false;
- }
+ return manager.removeTouchExplorationStateChangeListener(
+ new TouchExplorationStateChangeListenerWrapper(listener));
}
@@ -316,26 +310,4 @@
return accessibilityManager.isRequestFromAccessibilityTool();
}
}
- @RequiresApi(19)
- static class Api19Impl {
- private Api19Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static boolean addTouchExplorationStateChangeListenerWrapper(
- AccessibilityManager accessibilityManager,
- TouchExplorationStateChangeListener listener) {
- return accessibilityManager.addTouchExplorationStateChangeListener(
- new TouchExplorationStateChangeListenerWrapper(listener));
- }
-
- @DoNotInline
- static boolean removeTouchExplorationStateChangeListenerWrapper(
- AccessibilityManager accessibilityManager,
- TouchExplorationStateChangeListener listener) {
- return accessibilityManager.removeTouchExplorationStateChangeListener(
- new TouchExplorationStateChangeListenerWrapper(listener));
- }
- }
}
diff --git a/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java b/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java
index f8d31ba..596cb43 100644
--- a/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java
+++ b/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java
@@ -994,11 +994,9 @@
if (Build.VERSION.SDK_INT >= 21) {
return new CollectionInfoCompat(AccessibilityNodeInfo.CollectionInfo.obtain(
rowCount, columnCount, hierarchical, selectionMode));
- } else if (Build.VERSION.SDK_INT >= 19) {
+ } else {
return new CollectionInfoCompat(AccessibilityNodeInfo.CollectionInfo.obtain(
rowCount, columnCount, hierarchical));
- } else {
- return new CollectionInfoCompat(null);
}
}
@@ -1013,12 +1011,8 @@
*/
public static CollectionInfoCompat obtain(int rowCount, int columnCount,
boolean hierarchical) {
- if (Build.VERSION.SDK_INT >= 19) {
- return new CollectionInfoCompat(AccessibilityNodeInfo.CollectionInfo.obtain(
- rowCount, columnCount, hierarchical));
- } else {
- return new CollectionInfoCompat(null);
- }
+ return new CollectionInfoCompat(AccessibilityNodeInfo.CollectionInfo.obtain(
+ rowCount, columnCount, hierarchical));
}
CollectionInfoCompat(Object info) {
@@ -1031,11 +1025,7 @@
* @return The column count, or -1 if count is unknown.
*/
public int getColumnCount() {
- if (Build.VERSION.SDK_INT >= 19) {
- return ((AccessibilityNodeInfo.CollectionInfo) mInfo).getColumnCount();
- } else {
- return -1;
- }
+ return ((AccessibilityNodeInfo.CollectionInfo) mInfo).getColumnCount();
}
/**
@@ -1044,11 +1034,7 @@
* @return The row count, or -1 if count is unknown.
*/
public int getRowCount() {
- if (Build.VERSION.SDK_INT >= 19) {
- return ((AccessibilityNodeInfo.CollectionInfo) mInfo).getRowCount();
- } else {
- return -1;
- }
+ return ((AccessibilityNodeInfo.CollectionInfo) mInfo).getRowCount();
}
/**
@@ -1057,11 +1043,7 @@
* @return Whether the collection is hierarchical.
*/
public boolean isHierarchical() {
- if (Build.VERSION.SDK_INT >= 19) {
- return ((AccessibilityNodeInfo.CollectionInfo) mInfo).isHierarchical();
- } else {
- return false;
- }
+ return ((AccessibilityNodeInfo.CollectionInfo) mInfo).isHierarchical();
}
/**
@@ -1115,11 +1097,9 @@
if (Build.VERSION.SDK_INT >= 21) {
return new CollectionItemInfoCompat(AccessibilityNodeInfo.CollectionItemInfo.obtain(
rowIndex, rowSpan, columnIndex, columnSpan, heading, selected));
- } else if (Build.VERSION.SDK_INT >= 19) {
+ } else {
return new CollectionItemInfoCompat(AccessibilityNodeInfo.CollectionItemInfo.obtain(
rowIndex, rowSpan, columnIndex, columnSpan, heading));
- } else {
- return new CollectionItemInfoCompat(null);
}
}
@@ -1137,12 +1117,8 @@
*/
public static CollectionItemInfoCompat obtain(int rowIndex, int rowSpan,
int columnIndex, int columnSpan, boolean heading) {
- if (Build.VERSION.SDK_INT >= 19) {
- return new CollectionItemInfoCompat(AccessibilityNodeInfo.CollectionItemInfo.obtain(
- rowIndex, rowSpan, columnIndex, columnSpan, heading));
- } else {
- return new CollectionItemInfoCompat(null);
- }
+ return new CollectionItemInfoCompat(AccessibilityNodeInfo.CollectionItemInfo.obtain(
+ rowIndex, rowSpan, columnIndex, columnSpan, heading));
}
CollectionItemInfoCompat(Object info) {
@@ -1155,11 +1131,7 @@
* @return The column index.
*/
public int getColumnIndex() {
- if (Build.VERSION.SDK_INT >= 19) {
- return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).getColumnIndex();
- } else {
- return 0;
- }
+ return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).getColumnIndex();
}
/**
@@ -1168,11 +1140,7 @@
* @return The column span.
*/
public int getColumnSpan() {
- if (Build.VERSION.SDK_INT >= 19) {
- return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).getColumnSpan();
- } else {
- return 0;
- }
+ return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).getColumnSpan();
}
/**
@@ -1181,11 +1149,7 @@
* @return The row index.
*/
public int getRowIndex() {
- if (Build.VERSION.SDK_INT >= 19) {
- return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).getRowIndex();
- } else {
- return 0;
- }
+ return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).getRowIndex();
}
/**
@@ -1194,11 +1158,7 @@
* @return The row span.
*/
public int getRowSpan() {
- if (Build.VERSION.SDK_INT >= 19) {
- return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).getRowSpan();
- } else {
- return 0;
- }
+ return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).getRowSpan();
}
/**
@@ -1211,11 +1171,7 @@
@SuppressWarnings("deprecation")
@Deprecated
public boolean isHeading() {
- if (Build.VERSION.SDK_INT >= 19) {
- return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).isHeading();
- } else {
- return false;
- }
+ return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).isHeading();
}
/**
@@ -1385,11 +1341,11 @@
} else if (Build.VERSION.SDK_INT >= 21) {
return Api21Impl.createCollectionItemInfo(mRowIndex, mRowSpan, mColumnIndex,
mColumnSpan, mHeading, mSelected);
- } else if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.createCollectionItemInfo(mRowIndex, mRowSpan, mColumnIndex,
- mColumnSpan, mHeading);
} else {
- return new CollectionItemInfoCompat(null);
+ return new CollectionItemInfoCompat(
+ AccessibilityNodeInfo.CollectionItemInfo.obtain(mRowIndex, mRowSpan,
+ mColumnIndex,
+ mColumnSpan, mHeading));
}
}
}
@@ -1416,12 +1372,8 @@
* @return The instance
*/
public static RangeInfoCompat obtain(int type, float min, float max, float current) {
- if (Build.VERSION.SDK_INT >= 19) {
- return new RangeInfoCompat(
- AccessibilityNodeInfo.RangeInfo.obtain(type, min, max, current));
- } else {
- return new RangeInfoCompat(null);
- }
+ return new RangeInfoCompat(
+ AccessibilityNodeInfo.RangeInfo.obtain(type, min, max, current));
}
final Object mInfo;
@@ -1443,10 +1395,8 @@
public RangeInfoCompat(int type, float min, float max, float current) {
if (Build.VERSION.SDK_INT >= 30) {
mInfo = Api30Impl.createRangeInfo(type, min, max, current);
- } else if (Build.VERSION.SDK_INT >= 19) {
- mInfo = Api19Impl.createRangeInfo(type, min, max, current);
} else {
- mInfo = null;
+ mInfo = AccessibilityNodeInfo.RangeInfo.obtain(type, min, max, current);
}
}
@@ -1456,11 +1406,7 @@
* @return The current value.
*/
public float getCurrent() {
- if (Build.VERSION.SDK_INT >= 19) {
- return ((AccessibilityNodeInfo.RangeInfo) mInfo).getCurrent();
- } else {
- return 0;
- }
+ return ((AccessibilityNodeInfo.RangeInfo) mInfo).getCurrent();
}
/**
@@ -1469,11 +1415,7 @@
* @return The max value.
*/
public float getMax() {
- if (Build.VERSION.SDK_INT >= 19) {
- return ((AccessibilityNodeInfo.RangeInfo) mInfo).getMax();
- } else {
- return 0;
- }
+ return ((AccessibilityNodeInfo.RangeInfo) mInfo).getMax();
}
/**
@@ -1482,11 +1424,7 @@
* @return The min value.
*/
public float getMin() {
- if (Build.VERSION.SDK_INT >= 19) {
- return ((AccessibilityNodeInfo.RangeInfo) mInfo).getMin();
- } else {
- return 0;
- }
+ return ((AccessibilityNodeInfo.RangeInfo) mInfo).getMin();
}
/**
@@ -1499,11 +1437,7 @@
* @see #RANGE_TYPE_PERCENT
*/
public int getType() {
- if (Build.VERSION.SDK_INT >= 19) {
- return ((AccessibilityNodeInfo.RangeInfo) mInfo).getType();
- } else {
- return RANGE_TYPE_INT;
- }
+ return ((AccessibilityNodeInfo.RangeInfo) mInfo).getType();
}
}
@@ -2607,14 +2541,11 @@
}
private List<Integer> extrasIntList(String key) {
- if (Build.VERSION.SDK_INT < 19) {
- return new ArrayList<Integer>();
- }
- ArrayList<Integer> list = Api19Impl.getExtras(mInfo)
+ ArrayList<Integer> list = mInfo.getExtras()
.getIntegerArrayList(key);
if (list == null) {
list = new ArrayList<Integer>();
- Api19Impl.getExtras(mInfo).putIntegerArrayList(key, list);
+ mInfo.getExtras().putIntegerArrayList(key, list);
}
return list;
}
@@ -2914,8 +2845,8 @@
public void getBoundsInWindow(@NonNull Rect outBounds) {
if (Build.VERSION.SDK_INT >= 34) {
Api34Impl.getBoundsInWindow(mInfo, outBounds);
- } else if (Build.VERSION.SDK_INT >= 19) {
- Rect extraBounds = Api19Impl.getExtras(mInfo).getParcelable(BOUNDS_IN_WINDOW_KEY);
+ } else {
+ Rect extraBounds = mInfo.getExtras().getParcelable(BOUNDS_IN_WINDOW_KEY);
if (extraBounds != null) {
outBounds.set(extraBounds.left, extraBounds.top, extraBounds.right,
extraBounds.bottom);
@@ -2942,8 +2873,8 @@
public void setBoundsInWindow(@NonNull Rect bounds) {
if (Build.VERSION.SDK_INT >= 34) {
Api34Impl.setBoundsInWindow(mInfo, bounds);
- } else if (Build.VERSION.SDK_INT >= 19) {
- Api19Impl.getExtras(mInfo).putParcelable(BOUNDS_IN_WINDOW_KEY, bounds);
+ } else {
+ mInfo.getExtras().putParcelable(BOUNDS_IN_WINDOW_KEY, bounds);
}
}
@@ -3332,10 +3263,9 @@
public long getMinDurationBetweenContentChangesMillis() {
if (Build.VERSION.SDK_INT >= 34) {
return Api34Impl.getMinDurationBetweenContentChangeMillis(mInfo);
- } else if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.getExtras(mInfo).getLong(MIN_DURATION_BETWEEN_CONTENT_CHANGES_KEY);
+ } else {
+ return mInfo.getExtras().getLong(MIN_DURATION_BETWEEN_CONTENT_CHANGES_KEY);
}
- return 0;
}
/**
@@ -3355,8 +3285,8 @@
public void setMinDurationBetweenContentChangesMillis(long duration) {
if (Build.VERSION.SDK_INT >= 34) {
Api34Impl.setMinDurationBetweenContentChangeMillis(mInfo, duration);
- } else if (Build.VERSION.SDK_INT >= 19) {
- Api19Impl.getExtras(mInfo).putLong(MIN_DURATION_BETWEEN_CONTENT_CHANGES_KEY, duration);
+ } else {
+ mInfo.getExtras().putLong(MIN_DURATION_BETWEEN_CONTENT_CHANGES_KEY, duration);
}
}
@@ -3530,7 +3460,7 @@
*/
@RestrictTo(LIBRARY_GROUP_PREFIX)
public void addSpansToExtras(CharSequence text, View view) {
- if (Build.VERSION.SDK_INT >= 19 && Build.VERSION.SDK_INT < 26) {
+ if (Build.VERSION.SDK_INT < 26) {
clearExtrasSpans();
removeCollectedSpans(view);
ClickableSpan[] spans = getClickableSpans(text);
@@ -3591,12 +3521,10 @@
}
private void clearExtrasSpans() {
- if (Build.VERSION.SDK_INT >= 19) {
- Api19Impl.getExtras(mInfo).remove(SPANS_START_KEY);
- Api19Impl.getExtras(mInfo).remove(SPANS_END_KEY);
- Api19Impl.getExtras(mInfo).remove(SPANS_FLAGS_KEY);
- Api19Impl.getExtras(mInfo).remove(SPANS_ID_KEY);
- }
+ mInfo.getExtras().remove(SPANS_START_KEY);
+ mInfo.getExtras().remove(SPANS_END_KEY);
+ mInfo.getExtras().remove(SPANS_FLAGS_KEY);
+ mInfo.getExtras().remove(SPANS_ID_KEY);
}
private void addSpanLocationToExtras(ClickableSpan span, Spanned spanned, int id) {
@@ -3638,11 +3566,10 @@
*/
public @Nullable CharSequence getStateDescription() {
if (Build.VERSION.SDK_INT >= 30) {
- return Api30Impl.getStateDescription(mInfo);
- } else if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.getExtras(mInfo).getCharSequence(STATE_DESCRIPTION_KEY);
+ return Api30Impl.getStateDescription(mInfo);
+ } else {
+ return mInfo.getExtras().getCharSequence(STATE_DESCRIPTION_KEY);
}
- return null;
}
/**
@@ -3674,8 +3601,8 @@
public void setStateDescription(@Nullable CharSequence stateDescription) {
if (Build.VERSION.SDK_INT >= 30) {
Api30Impl.setStateDescription(mInfo, stateDescription);
- } else if (Build.VERSION.SDK_INT >= 19) {
- Api19Impl.getExtras(mInfo).putCharSequence(STATE_DESCRIPTION_KEY, stateDescription);
+ } else {
+ mInfo.getExtras().putCharSequence(STATE_DESCRIPTION_KEY, stateDescription);
}
}
@@ -3688,10 +3615,9 @@
public @Nullable String getUniqueId() {
if (Build.VERSION.SDK_INT >= 33) {
return Api33Impl.getUniqueId(mInfo);
- } else if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.getExtras(mInfo).getString(UNIQUE_ID_KEY);
+ } else {
+ return mInfo.getExtras().getString(UNIQUE_ID_KEY);
}
- return null;
}
/**
@@ -3708,8 +3634,8 @@
public void setUniqueId(@Nullable String uniqueId) {
if (Build.VERSION.SDK_INT >= 33) {
Api33Impl.setUniqueId(mInfo, uniqueId);
- } else if (Build.VERSION.SDK_INT >= 19) {
- Api19Impl.getExtras(mInfo).putString(UNIQUE_ID_KEY, uniqueId);
+ } else {
+ mInfo.getExtras().putString(UNIQUE_ID_KEY, uniqueId);
}
}
@@ -3745,8 +3671,8 @@
public void setContainerTitle(@Nullable CharSequence containerTitle) {
if (Build.VERSION.SDK_INT >= 34) {
Api34Impl.setContainerTitle(mInfo, containerTitle);
- } else if (Build.VERSION.SDK_INT >= 19) {
- Api19Impl.getExtras(mInfo).putCharSequence(CONTAINER_TITLE_KEY, containerTitle);
+ } else {
+ mInfo.getExtras().putCharSequence(CONTAINER_TITLE_KEY, containerTitle);
}
}
@@ -3763,10 +3689,9 @@
public CharSequence getContainerTitle() {
if (Build.VERSION.SDK_INT >= 34) {
return Api34Impl.getContainerTitle(mInfo);
- } else if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.getExtras(mInfo).getCharSequence(CONTAINER_TITLE_KEY);
+ } else {
+ return mInfo.getExtras().getCharSequence(CONTAINER_TITLE_KEY);
}
- return null;
}
/**
@@ -3792,9 +3717,7 @@
* @param viewId The id resource name.
*/
public void setViewIdResourceName(String viewId) {
- if (Build.VERSION.SDK_INT >= 18) {
- mInfo.setViewIdResourceName(viewId);
- }
+ mInfo.setViewIdResourceName(viewId);
}
/**
@@ -3810,11 +3733,7 @@
* @return The id resource name.
*/
public String getViewIdResourceName() {
- if (Build.VERSION.SDK_INT >= 18) {
- return mInfo.getViewIdResourceName();
- } else {
- return null;
- }
+ return mInfo.getViewIdResourceName();
}
/**
@@ -3836,11 +3755,7 @@
* @see ViewCompat#getAccessibilityLiveRegion(View)
*/
public int getLiveRegion() {
- if (Build.VERSION.SDK_INT >= 19) {
- return mInfo.getLiveRegion();
- } else {
- return ViewCompat.ACCESSIBILITY_LIVE_REGION_NONE;
- }
+ return mInfo.getLiveRegion();
}
/**
@@ -3856,9 +3771,7 @@
* @see ViewCompat#setAccessibilityLiveRegion(View, int)
*/
public void setLiveRegion(int mode) {
- if (Build.VERSION.SDK_INT >= 19) {
- mInfo.setLiveRegion(mode);
- }
+ mInfo.setLiveRegion(mode);
}
/**
@@ -3904,30 +3817,24 @@
* @return The collection info.
*/
public CollectionInfoCompat getCollectionInfo() {
- if (Build.VERSION.SDK_INT >= 19) {
- AccessibilityNodeInfo.CollectionInfo info = mInfo.getCollectionInfo();
- if (info != null) {
- return new CollectionInfoCompat(info);
- }
+ AccessibilityNodeInfo.CollectionInfo info = mInfo.getCollectionInfo();
+ if (info != null) {
+ return new CollectionInfoCompat(info);
}
return null;
}
public void setCollectionInfo(Object collectionInfo) {
- if (Build.VERSION.SDK_INT >= 19) {
- mInfo.setCollectionInfo((collectionInfo == null) ? null
- : (AccessibilityNodeInfo.CollectionInfo) ((CollectionInfoCompat)
- collectionInfo).mInfo);
- }
+ mInfo.setCollectionInfo((collectionInfo == null) ? null
+ : (AccessibilityNodeInfo.CollectionInfo) ((CollectionInfoCompat)
+ collectionInfo).mInfo);
}
public void setCollectionItemInfo(Object collectionItemInfo) {
- if (Build.VERSION.SDK_INT >= 19) {
- mInfo.setCollectionItemInfo((collectionItemInfo == null) ? null
- : (AccessibilityNodeInfo.CollectionItemInfo) ((CollectionItemInfoCompat)
- collectionItemInfo).mInfo);
- }
+ mInfo.setCollectionItemInfo((collectionItemInfo == null) ? null
+ : (AccessibilityNodeInfo.CollectionItemInfo) ((CollectionItemInfoCompat)
+ collectionItemInfo).mInfo);
}
/**
@@ -3937,11 +3844,9 @@
* @return The collection item info.
*/
public CollectionItemInfoCompat getCollectionItemInfo() {
- if (Build.VERSION.SDK_INT >= 19) {
- AccessibilityNodeInfo.CollectionItemInfo info = mInfo.getCollectionItemInfo();
- if (info != null) {
- return new CollectionItemInfoCompat(info);
- }
+ AccessibilityNodeInfo.CollectionItemInfo info = mInfo.getCollectionItemInfo();
+ if (info != null) {
+ return new CollectionItemInfoCompat(info);
}
return null;
}
@@ -3952,11 +3857,9 @@
* @return The range.
*/
public RangeInfoCompat getRangeInfo() {
- if (Build.VERSION.SDK_INT >= 19) {
- AccessibilityNodeInfo.RangeInfo info = mInfo.getRangeInfo();
- if (info != null) {
- return new RangeInfoCompat(info);
- }
+ AccessibilityNodeInfo.RangeInfo info = mInfo.getRangeInfo();
+ if (info != null) {
+ return new RangeInfoCompat(info);
}
return null;
}
@@ -3972,9 +3875,7 @@
* @param rangeInfo The range info.
*/
public void setRangeInfo(RangeInfoCompat rangeInfo) {
- if (Build.VERSION.SDK_INT >= 19) {
- mInfo.setRangeInfo((AccessibilityNodeInfo.RangeInfo) rangeInfo.mInfo);
- }
+ mInfo.setRangeInfo((AccessibilityNodeInfo.RangeInfo) rangeInfo.mInfo);
}
/**
@@ -4035,9 +3936,7 @@
* @param contentInvalid If the node content is invalid.
*/
public void setContentInvalid(boolean contentInvalid) {
- if (Build.VERSION.SDK_INT >= 19) {
- mInfo.setContentInvalid(contentInvalid);
- }
+ mInfo.setContentInvalid(contentInvalid);
}
/**
@@ -4047,11 +3946,7 @@
* @return If the node content is invalid.
*/
public boolean isContentInvalid() {
- if (Build.VERSION.SDK_INT >= 19) {
- return mInfo.isContentInvalid();
- } else {
- return false;
- }
+ return mInfo.isContentInvalid();
}
/**
@@ -4092,10 +3987,9 @@
public @Nullable CharSequence getHintText() {
if (Build.VERSION.SDK_INT >= 26) {
return mInfo.getHintText();
- } else if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.getExtras(mInfo).getCharSequence(HINT_TEXT_KEY);
+ } else {
+ return mInfo.getExtras().getCharSequence(HINT_TEXT_KEY);
}
- return null;
}
/**
@@ -4114,8 +4008,8 @@
public void setHintText(@Nullable CharSequence hintText) {
if (Build.VERSION.SDK_INT >= 26) {
mInfo.setHintText(hintText);
- } else if (Build.VERSION.SDK_INT >= 19) {
- Api19Impl.getExtras(mInfo).putCharSequence(HINT_TEXT_KEY, hintText);
+ } else {
+ mInfo.getExtras().putCharSequence(HINT_TEXT_KEY, hintText);
}
}
@@ -4158,9 +4052,7 @@
* @param labeled The view for which this info serves as a label.
*/
public void setLabelFor(View labeled) {
- if (Build.VERSION.SDK_INT >= 17) {
- mInfo.setLabelFor(labeled);
- }
+ mInfo.setLabelFor(labeled);
}
/**
@@ -4178,9 +4070,7 @@
* @param virtualDescendantId The id of the virtual descendant.
*/
public void setLabelFor(View root, int virtualDescendantId) {
- if (Build.VERSION.SDK_INT >= 17) {
- mInfo.setLabelFor(root, virtualDescendantId);
- }
+ mInfo.setLabelFor(root, virtualDescendantId);
}
/**
@@ -4190,11 +4080,7 @@
* @return The labeled info.
*/
public AccessibilityNodeInfoCompat getLabelFor() {
- if (Build.VERSION.SDK_INT >= 17) {
- return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getLabelFor());
- } else {
- return null;
- }
+ return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getLabelFor());
}
/**
@@ -4204,9 +4090,7 @@
* @param label The view that labels this node's source.
*/
public void setLabeledBy(View label) {
- if (Build.VERSION.SDK_INT >= 17) {
- mInfo.setLabeledBy(label);
- }
+ mInfo.setLabeledBy(label);
}
/**
@@ -4229,9 +4113,7 @@
* @param virtualDescendantId The id of the virtual descendant.
*/
public void setLabeledBy(View root, int virtualDescendantId) {
- if (Build.VERSION.SDK_INT >= 17) {
- mInfo.setLabeledBy(root, virtualDescendantId);
- }
+ mInfo.setLabeledBy(root, virtualDescendantId);
}
/**
@@ -4241,11 +4123,7 @@
* @return The label.
*/
public AccessibilityNodeInfoCompat getLabeledBy() {
- if (Build.VERSION.SDK_INT >= 17) {
- return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getLabeledBy());
- } else {
- return null;
- }
+ return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getLabeledBy());
}
/**
@@ -4254,11 +4132,7 @@
* @return If the the node opens a popup.
*/
public boolean canOpenPopup() {
- if (Build.VERSION.SDK_INT >= 19) {
- return mInfo.canOpenPopup();
- } else {
- return false;
- }
+ return mInfo.canOpenPopup();
}
/**
@@ -4272,9 +4146,7 @@
* @param opensPopup If the the node opens a popup.
*/
public void setCanOpenPopup(boolean opensPopup) {
- if (Build.VERSION.SDK_INT >= 19) {
- mInfo.setCanOpenPopup(opensPopup);
- }
+ mInfo.setCanOpenPopup(opensPopup);
}
/**
@@ -4322,11 +4194,7 @@
* @return The bundle.
*/
public Bundle getExtras() {
- if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.getExtras(mInfo);
- } else {
- return new Bundle();
- }
+ return mInfo.getExtras();
}
/**
@@ -4335,11 +4203,7 @@
* @return The input type.
*/
public int getInputType() {
- if (Build.VERSION.SDK_INT >= 19) {
- return mInfo.getInputType();
- } else {
- return InputType.TYPE_NULL;
- }
+ return mInfo.getInputType();
}
/**
@@ -4356,9 +4220,7 @@
* @throws IllegalStateException If called from an AccessibilityService.
*/
public void setInputType(int inputType) {
- if (Build.VERSION.SDK_INT >= 19) {
- mInfo.setInputType(inputType);
- }
+ mInfo.setInputType(inputType);
}
/**
@@ -4452,9 +4314,7 @@
* @throws IllegalStateException If called from an AccessibilityService.
*/
public void setTextSelection(int start, int end) {
- if (Build.VERSION.SDK_INT >= 18) {
- mInfo.setTextSelection(start, end);
- }
+ mInfo.setTextSelection(start, end);
}
/**
@@ -4463,11 +4323,7 @@
* @return The text selection start if there is selection or -1.
*/
public int getTextSelectionStart() {
- if (Build.VERSION.SDK_INT >= 18) {
- return mInfo.getTextSelectionStart();
- } else {
- return -1;
- }
+ return mInfo.getTextSelectionStart();
}
/**
@@ -4476,11 +4332,7 @@
* @return The text selection end if there is selection or -1.
*/
public int getTextSelectionEnd() {
- if (Build.VERSION.SDK_INT >= 18) {
- return mInfo.getTextSelectionEnd();
- } else {
- return -1;
- }
+ return mInfo.getTextSelectionEnd();
}
/**
@@ -4632,11 +4484,7 @@
* @return If the node can be dismissed.
*/
public boolean isDismissable() {
- if (Build.VERSION.SDK_INT >= 19) {
- return mInfo.isDismissable();
- } else {
- return false;
- }
+ return mInfo.isDismissable();
}
/**
@@ -4650,9 +4498,7 @@
* @param dismissable If the node can be dismissed.
*/
public void setDismissable(boolean dismissable) {
- if (Build.VERSION.SDK_INT >= 19) {
- mInfo.setDismissable(dismissable);
- }
+ mInfo.setDismissable(dismissable);
}
/**
@@ -4661,11 +4507,7 @@
* @return True if the node is editable, false otherwise.
*/
public boolean isEditable() {
- if (Build.VERSION.SDK_INT >= 18) {
- return mInfo.isEditable();
- } else {
- return false;
- }
+ return mInfo.isEditable();
}
/**
@@ -4681,9 +4523,7 @@
* @throws IllegalStateException If called from an AccessibilityService.
*/
public void setEditable(boolean editable) {
- if (Build.VERSION.SDK_INT >= 18) {
- mInfo.setEditable(editable);
- }
+ mInfo.setEditable(editable);
}
/**
@@ -4692,11 +4532,7 @@
* @return True if the node is multi line.
*/
public boolean isMultiLine() {
- if (Build.VERSION.SDK_INT >= 19) {
- return mInfo.isMultiLine();
- } else {
- return false;
- }
+ return mInfo.isMultiLine();
}
/**
@@ -4710,9 +4546,7 @@
* @param multiLine True if the node is multi line.
*/
public void setMultiLine(boolean multiLine) {
- if (Build.VERSION.SDK_INT >= 19) {
- mInfo.setMultiLine(multiLine);
- }
+ mInfo.setMultiLine(multiLine);
}
/**
@@ -4724,10 +4558,9 @@
public CharSequence getTooltipText() {
if (Build.VERSION.SDK_INT >= 28) {
return mInfo.getTooltipText();
- } else if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.getExtras(mInfo).getCharSequence(TOOLTIP_TEXT_KEY);
+ } else {
+ return mInfo.getExtras().getCharSequence(TOOLTIP_TEXT_KEY);
}
- return null;
}
/**
@@ -4746,8 +4579,8 @@
public void setTooltipText(@Nullable CharSequence tooltipText) {
if (Build.VERSION.SDK_INT >= 28) {
mInfo.setTooltipText(tooltipText);
- } else if (Build.VERSION.SDK_INT >= 19) {
- Api19Impl.getExtras(mInfo).putCharSequence(TOOLTIP_TEXT_KEY, tooltipText);
+ } else {
+ mInfo.getExtras().putCharSequence(TOOLTIP_TEXT_KEY, tooltipText);
}
}
@@ -4766,8 +4599,8 @@
public void setPaneTitle(@Nullable CharSequence paneTitle) {
if (Build.VERSION.SDK_INT >= 28) {
mInfo.setPaneTitle(paneTitle);
- } else if (Build.VERSION.SDK_INT >= 19) {
- Api19Impl.getExtras(mInfo).putCharSequence(PANE_TITLE_KEY, paneTitle);
+ } else {
+ mInfo.getExtras().putCharSequence(PANE_TITLE_KEY, paneTitle);
}
}
@@ -4780,10 +4613,9 @@
public @Nullable CharSequence getPaneTitle() {
if (Build.VERSION.SDK_INT >= 28) {
return mInfo.getPaneTitle();
- } else if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.getExtras(mInfo).getCharSequence(PANE_TITLE_KEY);
+ } else {
+ return mInfo.getExtras().getCharSequence(PANE_TITLE_KEY);
}
- return null;
}
/**
@@ -4977,11 +4809,7 @@
* @return Whether the refresh succeeded.
*/
public boolean refresh() {
- if (Build.VERSION.SDK_INT >= 18) {
- return mInfo.refresh();
- } else {
- return false;
- }
+ return mInfo.refresh();
}
/**
@@ -4989,11 +4817,7 @@
* @return The role description.
*/
public @Nullable CharSequence getRoleDescription() {
- if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.getExtras(mInfo).getCharSequence(ROLE_DESCRIPTION_KEY);
- } else {
- return null;
- }
+ return mInfo.getExtras().getCharSequence(ROLE_DESCRIPTION_KEY);
}
/**
@@ -5021,9 +4845,7 @@
* @param roleDescription The role description.
*/
public void setRoleDescription(@Nullable CharSequence roleDescription) {
- if (Build.VERSION.SDK_INT >= 19) {
- Api19Impl.getExtras(mInfo).putCharSequence(ROLE_DESCRIPTION_KEY, roleDescription);
- }
+ mInfo.getExtras().putCharSequence(ROLE_DESCRIPTION_KEY, roleDescription);
}
/**
@@ -5344,31 +5166,6 @@
}
}
- @RequiresApi(19)
- private static class Api19Impl {
- private Api19Impl() {
- // This class is non instantiable.
- }
-
- @DoNotInline
- public static Bundle getExtras(AccessibilityNodeInfo info) {
- return info.getExtras();
- }
-
- @DoNotInline
- public static Object createRangeInfo(int type, float min, float max, float current) {
- return AccessibilityNodeInfo.RangeInfo.obtain(type, min, max, current);
- }
-
- @DoNotInline
- public static CollectionItemInfoCompat createCollectionItemInfo(int rowIndex, int rowSpan,
- int columnIndex, int columnSpan, boolean heading) {
- return new CollectionItemInfoCompat(
- AccessibilityNodeInfo.CollectionItemInfo.obtain(rowIndex, rowSpan, columnIndex,
- columnSpan, heading));
- }
- }
-
@RequiresApi(21)
private static class Api21Impl {
private Api21Impl() {
diff --git a/core/core/src/main/java/androidx/core/view/inputmethod/EditorInfoCompat.java b/core/core/src/main/java/androidx/core/view/inputmethod/EditorInfoCompat.java
index 5f89ffe..7ef503a 100644
--- a/core/core/src/main/java/androidx/core/view/inputmethod/EditorInfoCompat.java
+++ b/core/core/src/main/java/androidx/core/view/inputmethod/EditorInfoCompat.java
@@ -34,6 +34,7 @@
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodManager;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
@@ -103,6 +104,8 @@
private static final String CONTENT_SELECTION_END_KEY =
"androidx.core.view.inputmethod.EditorInfoCompat.CONTENT_SELECTION_END";
+ private static final String STYLUS_HANDWRITING_ENABLED_KEY =
+ "androidx.core.view.inputmethod.EditorInfoCompat.STYLUS_HANDWRITING_ENABLED";
@Retention(SOURCE)
@IntDef({Protocol.Unknown, Protocol.PlatformApi, Protocol.SupportLib, Protocol.AndroidX_1_0_0,
@@ -196,6 +199,37 @@
}
/**
+ * Set {@code true} if the editor has {@link InputMethodManager#startStylusHandwriting stylus
+ * handwriting} enabled.
+ * {@code false} by default, editor must set it {@code true} to indicate that it supports
+ * stylus handwriting.
+ * @param editorInfo the editor with which we set handwriting enabled.
+ * @param enabled {@code true} if stylus handwriting is enabled.
+ * @see View#setAutoHandwritingEnabled(boolean)
+ */
+ public static void setStylusHandwritingEnabled(@NonNull EditorInfo editorInfo,
+ boolean enabled) {
+ if (editorInfo.extras == null) {
+ editorInfo.extras = new Bundle();
+ }
+ editorInfo.extras.putBoolean(STYLUS_HANDWRITING_ENABLED_KEY, enabled);
+ }
+
+ /**
+ * Returns {@code true} when an editor has stylus handwriting enabled. {@code false} by default.
+ * @param editorInfo the editor from which we get stylus handwriting enabled.
+ * @see #setStylusHandwritingEnabled(EditorInfo, boolean)
+ * @see InputMethodManager#isStylusHandwritingAvailable()
+ */
+ public static boolean isStylusHandwritingEnabled(@NonNull EditorInfo editorInfo) {
+ if (editorInfo.extras == null) {
+ // disabled by default
+ return false;
+ }
+ return editorInfo.extras.getBoolean(STYLUS_HANDWRITING_ENABLED_KEY);
+ }
+
+ /**
* Editors may use this method to provide initial input text to IMEs. As the surrounding text
* could be used to provide various input assistance, we recommend editors to provide the
* complete initial input text in its {@link View#onCreateInputConnection(EditorInfo)} callback.
diff --git a/core/core/src/main/java/androidx/core/widget/ListPopupWindowCompat.java b/core/core/src/main/java/androidx/core/widget/ListPopupWindowCompat.java
index 1c49b95..4b8c16c 100644
--- a/core/core/src/main/java/androidx/core/widget/ListPopupWindowCompat.java
+++ b/core/core/src/main/java/androidx/core/widget/ListPopupWindowCompat.java
@@ -21,10 +21,8 @@
import android.view.View.OnTouchListener;
import android.widget.ListPopupWindow;
-import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
/**
* Helper for accessing features in {@link ListPopupWindow}.
@@ -96,22 +94,6 @@
@Nullable
public static OnTouchListener createDragToOpenListener(
@NonNull ListPopupWindow listPopupWindow, @NonNull View src) {
- if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.createDragToOpenListener(listPopupWindow, src);
- } else {
- return null;
- }
- }
-
- @RequiresApi(19)
- static class Api19Impl {
- private Api19Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static OnTouchListener createDragToOpenListener(ListPopupWindow listPopupWindow, View src) {
- return listPopupWindow.createDragToOpenListener(src);
- }
+ return listPopupWindow.createDragToOpenListener(src);
}
}
diff --git a/core/core/src/main/java/androidx/core/widget/PopupMenuCompat.java b/core/core/src/main/java/androidx/core/widget/PopupMenuCompat.java
index 67c3263..01a7071 100644
--- a/core/core/src/main/java/androidx/core/widget/PopupMenuCompat.java
+++ b/core/core/src/main/java/androidx/core/widget/PopupMenuCompat.java
@@ -20,10 +20,8 @@
import android.view.View.OnTouchListener;
import android.widget.PopupMenu;
-import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
/**
* Helper for accessing features in {@link PopupMenu}.
@@ -54,22 +52,6 @@
*/
@Nullable
public static OnTouchListener getDragToOpenListener(@NonNull Object popupMenu) {
- if (Build.VERSION.SDK_INT >= 19) {
- return Api19Impl.getDragToOpenListener((PopupMenu) popupMenu);
- } else {
- return null;
- }
- }
-
- @RequiresApi(19)
- static class Api19Impl {
- private Api19Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static OnTouchListener getDragToOpenListener(PopupMenu popupMenu) {
- return popupMenu.getDragToOpenListener();
- }
+ return ((PopupMenu) popupMenu).getDragToOpenListener();
}
}
diff --git a/core/core/src/main/java/androidx/core/widget/PopupWindowCompat.java b/core/core/src/main/java/androidx/core/widget/PopupWindowCompat.java
index 415bedd..b87351b 100644
--- a/core/core/src/main/java/androidx/core/widget/PopupWindowCompat.java
+++ b/core/core/src/main/java/androidx/core/widget/PopupWindowCompat.java
@@ -18,15 +18,12 @@
import android.os.Build;
import android.util.Log;
-import android.view.Gravity;
import android.view.View;
import android.widget.PopupWindow;
import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
-import androidx.core.view.GravityCompat;
-import androidx.core.view.ViewCompat;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@@ -67,19 +64,7 @@
*/
public static void showAsDropDown(@NonNull PopupWindow popup, @NonNull View anchor,
int xoff, int yoff, int gravity) {
- if (Build.VERSION.SDK_INT >= 19) {
- Api19Impl.showAsDropDown(popup, anchor, xoff, yoff, gravity);
- } else {
- int xoff1 = xoff;
- final int hgrav = GravityCompat.getAbsoluteGravity(gravity,
- ViewCompat.getLayoutDirection(anchor)) & Gravity.HORIZONTAL_GRAVITY_MASK;
- if (hgrav == Gravity.RIGHT) {
- // Flip the location to align the right sides of the popup and
- // anchor instead of left.
- xoff1 -= (popup.getWidth() - anchor.getWidth());
- }
- popup.showAsDropDown(anchor, xoff1, yoff);
- }
+ popup.showAsDropDown(anchor, xoff, yoff, gravity);
}
/**
@@ -236,17 +221,4 @@
return popupWindow.getWindowLayoutType();
}
}
-
- @RequiresApi(19)
- static class Api19Impl {
- private Api19Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static void showAsDropDown(PopupWindow popupWindow, View anchor, int xoff, int yoff,
- int gravity) {
- popupWindow.showAsDropDown(anchor, xoff, yoff, gravity);
- }
- }
}
diff --git a/core/core/src/main/java/androidx/core/widget/TextViewCompat.java b/core/core/src/main/java/androidx/core/widget/TextViewCompat.java
index b63d1df..df34fd0 100644
--- a/core/core/src/main/java/androidx/core/widget/TextViewCompat.java
+++ b/core/core/src/main/java/androidx/core/widget/TextViewCompat.java
@@ -120,14 +120,7 @@
public static void setCompoundDrawablesRelative(@NonNull TextView textView,
@Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
@Nullable Drawable bottom) {
- if (Build.VERSION.SDK_INT >= 18) {
- Api17Impl.setCompoundDrawablesRelative(textView, start, top, end, bottom);
- } else if (Build.VERSION.SDK_INT >= 17) {
- boolean rtl = Api17Impl.getLayoutDirection(textView) == View.LAYOUT_DIRECTION_RTL;
- textView.setCompoundDrawables(rtl ? end : start, top, rtl ? start : end, bottom);
- } else {
- textView.setCompoundDrawables(start, top, end, bottom);
- }
+ textView.setCompoundDrawablesRelative(start, top, end, bottom);
}
/**
@@ -152,16 +145,7 @@
public static void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
@Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
@Nullable Drawable bottom) {
- if (Build.VERSION.SDK_INT >= 18) {
- Api17Impl.setCompoundDrawablesRelativeWithIntrinsicBounds(textView, start, top, end,
- bottom);
- } else if (Build.VERSION.SDK_INT >= 17) {
- boolean rtl = Api17Impl.getLayoutDirection(textView) == View.LAYOUT_DIRECTION_RTL;
- textView.setCompoundDrawablesWithIntrinsicBounds(rtl ? end : start, top,
- rtl ? start : end, bottom);
- } else {
- textView.setCompoundDrawablesWithIntrinsicBounds(start, top, end, bottom);
- }
+ textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
}
/**
@@ -185,16 +169,7 @@
public static void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
@DrawableRes int start, @DrawableRes int top, @DrawableRes int end,
@DrawableRes int bottom) {
- if (Build.VERSION.SDK_INT >= 18) {
- Api17Impl.setCompoundDrawablesRelativeWithIntrinsicBounds(textView, start, top, end,
- bottom);
- } else if (Build.VERSION.SDK_INT >= 17) {
- boolean rtl = Api17Impl.getLayoutDirection(textView) == View.LAYOUT_DIRECTION_RTL;
- textView.setCompoundDrawablesWithIntrinsicBounds(rtl ? end : start, top,
- rtl ? start : end, bottom);
- } else {
- textView.setCompoundDrawablesWithIntrinsicBounds(start, top, end, bottom);
- }
+ textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
}
/**
@@ -235,22 +210,7 @@
*/
@NonNull
public static Drawable[] getCompoundDrawablesRelative(@NonNull TextView textView) {
- if (Build.VERSION.SDK_INT >= 18) {
- return Api17Impl.getCompoundDrawablesRelative(textView);
- }
- if (Build.VERSION.SDK_INT >= 17) {
- final boolean rtl = Api17Impl.getLayoutDirection(textView) == View.LAYOUT_DIRECTION_RTL;
- final Drawable[] compounds = textView.getCompoundDrawables();
- if (rtl) {
- // If we're on RTL, we need to invert the horizontal result like above
- final Drawable start = compounds[2];
- final Drawable end = compounds[0];
- compounds[0] = start;
- compounds[2] = end;
- }
- return compounds;
- }
- return textView.getCompoundDrawables();
+ return textView.getCompoundDrawablesRelative();
}
/**
@@ -815,9 +775,7 @@
builder.setBreakStrategy(Api23Impl.getBreakStrategy(textView));
builder.setHyphenationFrequency(Api23Impl.getHyphenationFrequency(textView));
}
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
- builder.setTextDirection(getTextDirectionHeuristic(textView));
- }
+ builder.setTextDirection(getTextDirectionHeuristic(textView));
return builder.build();
}
}
@@ -833,9 +791,7 @@
// There is no way of setting text direction heuristics to TextView.
// Convert to the View's text direction int values.
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
- Api17Impl.setTextDirection(textView, getTextDirection(params.getTextDirection()));
- }
+ textView.setTextDirection(getTextDirection(params.getTextDirection()));
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
float paintTextScaleX = params.getTextPaint().getTextScaleX();
@@ -910,7 +866,7 @@
// have LTR digits, but some locales, such as those written in the Adlam or N'Ko
// scripts, have RTL digits.
final DecimalFormatSymbols symbols =
- Api24Impl.getInstance(Api17Impl.getTextLocale(textView));
+ Api24Impl.getInstance(textView.getTextLocale());
final String zero = Api28Impl.getDigitStrings(symbols)[0];
// In case the zero digit is multi-codepoint, just use the first codepoint to
// determine direction.
@@ -927,10 +883,10 @@
// Always need to resolve layout direction first
final boolean defaultIsRtl =
- (Api17Impl.getLayoutDirection(textView) == View.LAYOUT_DIRECTION_RTL);
+ (textView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL);
// Now, we can select the heuristic
- switch (Api17Impl.getTextDirection(textView)) {
+ switch (textView.getTextDirection()) {
default:
case TEXT_DIRECTION_FIRST_STRONG:
return (defaultIsRtl ? TextDirectionHeuristics.FIRSTSTRONG_RTL :
@@ -953,7 +909,6 @@
/**
* Convert TextDirectionHeuristic to TextDirection int values
*/
- @RequiresApi(18)
private static int getTextDirection(@NonNull TextDirectionHeuristic heuristic) {
if (heuristic == TextDirectionHeuristics.FIRSTSTRONG_RTL) {
return TEXT_DIRECTION_FIRST_STRONG;
@@ -1045,56 +1000,6 @@
return null;
}
- @RequiresApi(17)
- static class Api17Impl {
- private Api17Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static void setCompoundDrawablesRelative(TextView textView, Drawable start, Drawable top,
- Drawable end, Drawable bottom) {
- textView.setCompoundDrawablesRelative(start, top, end, bottom);
- }
-
- @DoNotInline
- static int getLayoutDirection(View view) {
- return view.getLayoutDirection();
- }
-
- @DoNotInline
- static void setCompoundDrawablesRelativeWithIntrinsicBounds(TextView textView,
- Drawable start, Drawable top, Drawable end, Drawable bottom) {
- textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
- }
-
- @DoNotInline
- static void setCompoundDrawablesRelativeWithIntrinsicBounds(TextView textView, int start,
- int top, int end, int bottom) {
- textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
- }
-
- @DoNotInline
- static Drawable[] getCompoundDrawablesRelative(TextView textView) {
- return textView.getCompoundDrawablesRelative();
- }
-
- @DoNotInline
- static void setTextDirection(View view, int textDirection) {
- view.setTextDirection(textDirection);
- }
-
- @DoNotInline
- static Locale getTextLocale(TextView textView) {
- return textView.getTextLocale();
- }
-
- @DoNotInline
- static int getTextDirection(View view) {
- return view.getTextDirection();
- }
- }
-
@RequiresApi(26)
static class Api26Impl {
private Api26Impl() {
diff --git a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/CredentialProviderPlayServicesImpl.kt b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/CredentialProviderPlayServicesImpl.kt
index 55b92f5..6e280c7 100644
--- a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/CredentialProviderPlayServicesImpl.kt
+++ b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/CredentialProviderPlayServicesImpl.kt
@@ -159,7 +159,7 @@
// This points to the min APK version of GMS that contains required changes
// to make passkeys work well
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
- const val MIN_GMS_APK_VERSION = 231200000
+ const val MIN_GMS_APK_VERSION = 230815045
internal fun cancellationReviewerWithCallback(
cancellationSignal: CancellationSignal?,
diff --git a/development/build_log_simplifier/messages.ignore b/development/build_log_simplifier/messages.ignore
index 491d65e..9fecfb4 100644
--- a/development/build_log_simplifier/messages.ignore
+++ b/development/build_log_simplifier/messages.ignore
@@ -30,6 +30,7 @@
Configuration cache entry reused\.
[0-9]+ actionable tasks: [0-9]+ executed, [0-9]+ from cache
Configuration cache entry stored\.
+Calculating task graph as no cached configuration is available for tasks.*
See the profiling report at\: file\:\/\/\$OUT_DIR\/androidx\/build\/reports\/profile\/profile\-[0-9]+\-[0-9]+\-[0-9]+\-[0-9]+\-[0-9]+\-[0-9]+\.html
# > Task :lifecycle:lifecycle-common:compileJava
Note: \$[^ ]+ uses or overrides a deprecated API\.
diff --git a/development/update-verification-metadata.sh b/development/update-verification-metadata.sh
index e588ec0..70b1472 100755
--- a/development/update-verification-metadata.sh
+++ b/development/update-verification-metadata.sh
@@ -73,10 +73,6 @@
# rename keyring
mv gradle/verification-keyring-dryrun.keys gradle/verification-keyring.keys 2>/dev/null || true
-
- # remove temporary files
- rm -f gradle/verification-keyring-dryrun.gpg
- rm -f gradle/verification-keyring.gpg
}
regenerateVerificationMetadata
diff --git a/docs-public/build.gradle b/docs-public/build.gradle
index e5f979b3..4ae0c8d 100644
--- a/docs-public/build.gradle
+++ b/docs-public/build.gradle
@@ -32,10 +32,10 @@
docs("androidx.asynclayoutinflater:asynclayoutinflater:1.1.0-alpha01")
docs("androidx.asynclayoutinflater:asynclayoutinflater-appcompat:1.1.0-alpha01")
docs("androidx.autofill:autofill:1.3.0-alpha01")
- docs("androidx.benchmark:benchmark-common:1.2.1")
- docs("androidx.benchmark:benchmark-junit4:1.2.1")
- docs("androidx.benchmark:benchmark-macro:1.2.1")
- docs("androidx.benchmark:benchmark-macro-junit4:1.2.1")
+ docs("androidx.benchmark:benchmark-common:1.2.2")
+ docs("androidx.benchmark:benchmark-junit4:1.2.2")
+ docs("androidx.benchmark:benchmark-macro:1.2.2")
+ docs("androidx.benchmark:benchmark-macro-junit4:1.2.2")
docs("androidx.biometric:biometric:1.2.0-alpha05")
docs("androidx.biometric:biometric-ktx:1.2.0-alpha05")
samples("androidx.biometric:biometric-ktx-samples:1.2.0-alpha05")
diff --git a/documentfile/documentfile/src/main/java/androidx/documentfile/provider/DocumentFile.java b/documentfile/documentfile/src/main/java/androidx/documentfile/provider/DocumentFile.java
index f29d0a1..743daa3 100644
--- a/documentfile/documentfile/src/main/java/androidx/documentfile/provider/DocumentFile.java
+++ b/documentfile/documentfile/src/main/java/androidx/documentfile/provider/DocumentFile.java
@@ -114,11 +114,7 @@
*/
@Nullable
public static DocumentFile fromSingleUri(@NonNull Context context, @NonNull Uri singleUri) {
- if (Build.VERSION.SDK_INT >= 19) {
- return new SingleDocumentFile(null, context, singleUri);
- } else {
- return null;
- }
+ return new SingleDocumentFile(null, context, singleUri);
}
/**
diff --git a/drawerlayout/drawerlayout/src/main/java/androidx/drawerlayout/widget/DrawerLayout.java b/drawerlayout/drawerlayout/src/main/java/androidx/drawerlayout/widget/DrawerLayout.java
index 0eab442..0ffddb8 100644
--- a/drawerlayout/drawerlayout/src/main/java/androidx/drawerlayout/widget/DrawerLayout.java
+++ b/drawerlayout/drawerlayout/src/main/java/androidx/drawerlayout/widget/DrawerLayout.java
@@ -41,7 +41,6 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewParent;
import android.view.accessibility.AccessibilityEvent;
import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedDispatcher;
@@ -194,9 +193,6 @@
android.R.attr.layout_gravity
};
- /** Whether we can use NO_HIDE_DESCENDANTS accessibility importance. */
- static final boolean CAN_HIDE_DESCENDANTS = Build.VERSION.SDK_INT >= 19;
-
/** Whether the drawer shadow comes from setting elevation on the drawer. */
private static final boolean SET_DRAWER_SHADOW_FROM_ELEVATION =
Build.VERSION.SDK_INT >= 21;
@@ -2181,11 +2177,6 @@
ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
}
- // We only need a delegate here if the framework doesn't understand
- // NO_HIDE_DESCENDANTS importance.
- if (!CAN_HIDE_DESCENDANTS) {
- ViewCompat.setAccessibilityDelegate(child, mChildAccessibilityDelegate);
- }
}
static boolean includeChildForAccessibility(View child) {
@@ -2461,25 +2452,7 @@
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
- if (CAN_HIDE_DESCENDANTS) {
- super.onInitializeAccessibilityNodeInfo(host, info);
- } else {
- // Obtain a node for the host, then manually generate the list
- // of children to only include non-obscured views.
- final AccessibilityNodeInfoCompat superNode =
- AccessibilityNodeInfoCompat.obtain(info);
- super.onInitializeAccessibilityNodeInfo(host, superNode);
-
- info.setSource(host);
- final ViewParent parent = ViewCompat.getParentForAccessibility(host);
- if (parent instanceof View) {
- info.setParent((View) parent);
- }
- copyNodeInfoNoChildren(info, superNode);
- superNode.recycle();
-
- addChildrenForAccessibility(info, (ViewGroup) host);
- }
+ super.onInitializeAccessibilityNodeInfo(host, info);
info.setClassName(ACCESSIBILITY_CLASS_NAME);
@@ -2523,15 +2496,6 @@
return super.dispatchPopulateAccessibilityEvent(host, event);
}
- @Override
- public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
- AccessibilityEvent event) {
- if (CAN_HIDE_DESCENDANTS || includeChildForAccessibility(child)) {
- return super.onRequestSendAccessibilityEvent(host, child, event);
- }
- return false;
- }
-
private void addChildrenForAccessibility(AccessibilityNodeInfoCompat info, ViewGroup v) {
final int childCount = v.getChildCount();
for (int i = 0; i < childCount; i++) {
diff --git a/emoji/emoji/src/main/java/androidx/emoji/text/EmojiCompat.java b/emoji/emoji/src/main/java/androidx/emoji/text/EmojiCompat.java
index da9477f..50a8a75 100644
--- a/emoji/emoji/src/main/java/androidx/emoji/text/EmojiCompat.java
+++ b/emoji/emoji/src/main/java/androidx/emoji/text/EmojiCompat.java
@@ -19,7 +19,6 @@
import android.graphics.Color;
import android.graphics.Paint;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -281,8 +280,7 @@
if (config.mInitCallbacks != null && !config.mInitCallbacks.isEmpty()) {
mInitCallbacks.addAll(config.mInitCallbacks);
}
- mHelper = Build.VERSION.SDK_INT < 19 ? new CompatInternal(this) : new CompatInternal19(
- this);
+ mHelper = new CompatInternal(this);
loadMetadata();
}
@@ -532,11 +530,7 @@
*/
public static boolean handleOnKeyDown(@NonNull final Editable editable, final int keyCode,
final KeyEvent event) {
- if (Build.VERSION.SDK_INT >= 19) {
- return EmojiProcessor.handleOnKeyDown(editable, keyCode, event);
- } else {
- return false;
- }
+ return EmojiProcessor.handleOnKeyDown(editable, keyCode, event);
}
/**
@@ -561,12 +555,8 @@
@NonNull final InputConnection inputConnection, @NonNull final Editable editable,
@IntRange(from = 0) final int beforeLength, @IntRange(from = 0) final int afterLength,
final boolean inCodePoints) {
- if (Build.VERSION.SDK_INT >= 19) {
- return EmojiProcessor.handleDeleteSurroundingText(inputConnection, editable,
- beforeLength, afterLength, inCodePoints);
- } else {
- return false;
- }
+ return EmojiProcessor.handleDeleteSurroundingText(inputConnection, editable,
+ beforeLength, afterLength, inCodePoints);
}
/**
@@ -1201,49 +1191,7 @@
}
}
- /**
- * Internal helper class to behave no-op for certain functions.
- */
- private static class CompatInternal {
- final EmojiCompat mEmojiCompat;
-
- CompatInternal(EmojiCompat emojiCompat) {
- mEmojiCompat = emojiCompat;
- }
-
- void loadMetadata() {
- // Moves into LOAD_STATE_SUCCESS state immediately.
- mEmojiCompat.onMetadataLoadSuccess();
- }
-
- boolean hasEmojiGlyph(@NonNull final CharSequence sequence) {
- // Since no metadata is loaded, EmojiCompat cannot detect or render any emojis.
- return false;
- }
-
- boolean hasEmojiGlyph(@NonNull final CharSequence sequence, final int metadataVersion) {
- // Since no metadata is loaded, EmojiCompat cannot detect or render any emojis.
- return false;
- }
-
- CharSequence process(@NonNull final CharSequence charSequence,
- @IntRange(from = 0) final int start, @IntRange(from = 0) final int end,
- @IntRange(from = 0) final int maxEmojiCount, boolean replaceAll) {
- // Returns the given charSequence as it is.
- return charSequence;
- }
-
- void updateEditorInfoAttrs(@NonNull final EditorInfo outAttrs) {
- // Does not add any EditorInfo attributes.
- }
-
- String getAssetSignature() {
- return "";
- }
- }
-
- @RequiresApi(19)
- private static final class CompatInternal19 extends CompatInternal {
+ private static final class CompatInternal {
/**
* Responsible to process a CharSequence and add the spans. @{code Null} until the time the
* metadata is loaded.
@@ -1254,13 +1202,13 @@
* Keeps the information about emojis. Null until the time the data is loaded.
*/
private volatile MetadataRepo mMetadataRepo;
+ final EmojiCompat mEmojiCompat;
- CompatInternal19(EmojiCompat emojiCompat) {
- super(emojiCompat);
+ CompatInternal(EmojiCompat emojiCompat) {
+ mEmojiCompat = emojiCompat;
}
- @Override
void loadMetadata() {
try {
final MetadataRepoLoaderCallback callback = new MetadataRepoLoaderCallback() {
@@ -1299,30 +1247,25 @@
mEmojiCompat.onMetadataLoadSuccess();
}
- @Override
boolean hasEmojiGlyph(@NonNull CharSequence sequence) {
return mProcessor.getEmojiMetadata(sequence) != null;
}
- @Override
boolean hasEmojiGlyph(@NonNull CharSequence sequence, int metadataVersion) {
final EmojiMetadata emojiMetadata = mProcessor.getEmojiMetadata(sequence);
return emojiMetadata != null && emojiMetadata.getCompatAdded() <= metadataVersion;
}
- @Override
CharSequence process(@NonNull CharSequence charSequence, int start, int end,
int maxEmojiCount, boolean replaceAll) {
return mProcessor.process(charSequence, start, end, maxEmojiCount, replaceAll);
}
- @Override
void updateEditorInfoAttrs(@NonNull EditorInfo outAttrs) {
outAttrs.extras.putInt(EDITOR_INFO_METAVERSION_KEY, mMetadataRepo.getMetadataVersion());
outAttrs.extras.putBoolean(EDITOR_INFO_REPLACE_ALL_KEY, mEmojiCompat.mReplaceAll);
}
- @Override
String getAssetSignature() {
final String sha = mMetadataRepo.getMetadataList().sourceSha();
return sha == null ? "" : sha;
diff --git a/emoji/emoji/src/main/java/androidx/emoji/widget/EmojiEditTextHelper.java b/emoji/emoji/src/main/java/androidx/emoji/widget/EmojiEditTextHelper.java
index 824c1c9..2f621ee 100644
--- a/emoji/emoji/src/main/java/androidx/emoji/widget/EmojiEditTextHelper.java
+++ b/emoji/emoji/src/main/java/androidx/emoji/widget/EmojiEditTextHelper.java
@@ -17,7 +17,6 @@
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;
-import android.os.Build;
import android.text.method.KeyListener;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
@@ -81,8 +80,7 @@
*/
public EmojiEditTextHelper(@NonNull final EditText editText) {
Preconditions.checkNotNull(editText, "editText cannot be null");
- mHelper = Build.VERSION.SDK_INT >= 19 ? new HelperInternal19(editText)
- : new HelperInternal();
+ mHelper = new HelperInternal19(editText);
}
/**
diff --git a/emoji/emoji/src/main/java/androidx/emoji/widget/EmojiTextViewHelper.java b/emoji/emoji/src/main/java/androidx/emoji/widget/EmojiTextViewHelper.java
index 40030f9..d061388 100644
--- a/emoji/emoji/src/main/java/androidx/emoji/widget/EmojiTextViewHelper.java
+++ b/emoji/emoji/src/main/java/androidx/emoji/widget/EmojiTextViewHelper.java
@@ -15,7 +15,6 @@
*/
package androidx.emoji.widget;
-import android.os.Build;
import android.text.InputFilter;
import android.text.method.PasswordTransformationMethod;
import android.text.method.TransformationMethod;
@@ -23,7 +22,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
import androidx.core.util.Preconditions;
import androidx.emoji.text.EmojiCompat;
@@ -71,8 +69,7 @@
*/
public EmojiTextViewHelper(@NonNull TextView textView) {
Preconditions.checkNotNull(textView, "textView cannot be null");
- mHelper = Build.VERSION.SDK_INT >= 19 ? new HelperInternal19(textView)
- : new HelperInternal();
+ mHelper = new HelperInternal(textView);
}
/**
@@ -124,37 +121,15 @@
mHelper.setAllCaps(allCaps);
}
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- static class HelperInternal {
-
- void updateTransformationMethod() {
- // do nothing
- }
-
- InputFilter[] getFilters(@NonNull final InputFilter[] filters) {
- return filters;
- }
-
- TransformationMethod wrapTransformationMethod(TransformationMethod transformationMethod) {
- return transformationMethod;
- }
-
- void setAllCaps(boolean allCaps) {
- // do nothing
- }
- }
-
- @RequiresApi(19)
- private static class HelperInternal19 extends HelperInternal {
+ private static class HelperInternal {
private final TextView mTextView;
private final EmojiInputFilter mEmojiInputFilter;
- HelperInternal19(TextView textView) {
+ HelperInternal(TextView textView) {
mTextView = textView;
mEmojiInputFilter = new EmojiInputFilter(textView);
}
- @Override
void updateTransformationMethod() {
final TransformationMethod tm = mTextView.getTransformationMethod();
if (tm != null && !(tm instanceof PasswordTransformationMethod)) {
@@ -162,7 +137,6 @@
}
}
- @Override
InputFilter[] getFilters(@NonNull final InputFilter[] filters) {
final int count = filters.length;
for (int i = 0; i < count; i++) {
@@ -176,7 +150,6 @@
return newFilters;
}
- @Override
TransformationMethod wrapTransformationMethod(TransformationMethod transformationMethod) {
if (transformationMethod instanceof EmojiTransformationMethod) {
return transformationMethod;
@@ -184,7 +157,6 @@
return new EmojiTransformationMethod(transformationMethod);
}
- @Override
void setAllCaps(boolean allCaps) {
// When allCaps is set to false TextView sets the transformation method to be null. We
// are only interested when allCaps is set to true in order to wrap the original method.
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-ca/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-ca/strings.xml
index 985e0cd..251972d 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-ca/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-ca/strings.xml
@@ -21,7 +21,7 @@
<string name="emoji_category_emotions" msgid="1570830970240985537">"EMOTICONES I EMOCIONS"</string>
<string name="emoji_category_people" msgid="7968173366822927025">"PERSONES"</string>
<string name="emoji_category_animals_nature" msgid="4640771324837307541">"ANIMALS I NATURALESA"</string>
- <string name="emoji_category_food_drink" msgid="1189971856721244395">"MENJAR I BEGUDES"</string>
+ <string name="emoji_category_food_drink" msgid="1189971856721244395">"MENJAR I BEGUDA"</string>
<string name="emoji_category_travel_places" msgid="8105712773237012672">"VIATGES I LLOCS"</string>
<string name="emoji_category_activity" msgid="4381135114947330911">"ACTIVITATS I ESDEVENIMENTS"</string>
<string name="emoji_category_objects" msgid="6106115586332708067">"OBJECTES"</string>
diff --git a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiEditableFactoryTest.java b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiEditableFactoryTest.java
index ffa1803..df55f27 100644
--- a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiEditableFactoryTest.java
+++ b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiEditableFactoryTest.java
@@ -24,12 +24,10 @@
import static org.mockito.Mockito.mock;
import android.annotation.SuppressLint;
-import android.os.Build;
import android.text.Editable;
import android.text.SpannableString;
import android.text.Spanned;
-import androidx.annotation.RequiresApi;
import androidx.emoji2.text.EmojiSpan;
import androidx.emoji2.text.SpannableBuilder;
import androidx.emoji2.text.TypefaceEmojiRasterizer;
@@ -60,7 +58,6 @@
assertThat(editable, instanceOf(Editable.class));
}
- @RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Test
public void testNewEditable_preservesCharSequenceData() {
final String string = "abc";
diff --git a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTransformationMethodTest.java b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTransformationMethodTest.java
index 71dfe18..b8e13b7 100644
--- a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTransformationMethodTest.java
+++ b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTransformationMethodTest.java
@@ -30,14 +30,12 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.os.Build;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.method.TransformationMethod;
import android.view.View;
-import androidx.annotation.RequiresApi;
import androidx.emoji2.text.EmojiCompat;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -49,7 +47,6 @@
import org.mockito.stubbing.Answer;
@SmallTest
-@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@RunWith(AndroidJUnit4.class)
public class EmojiTransformationMethodTest {
diff --git a/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiEditTextHelper.java b/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiEditTextHelper.java
index de5847c..c41335f 100644
--- a/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiEditTextHelper.java
+++ b/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiEditTextHelper.java
@@ -15,7 +15,6 @@
*/
package androidx.emoji2.viewsintegration;
-import android.os.Build;
import android.text.method.KeyListener;
import android.text.method.NumberKeyListener;
import android.view.inputmethod.EditorInfo;
@@ -104,11 +103,7 @@
public EmojiEditTextHelper(@NonNull EditText editText,
boolean expectInitializedEmojiCompat) {
Preconditions.checkNotNull(editText, "editText cannot be null");
- if (Build.VERSION.SDK_INT < 19) {
- mHelper = new HelperInternal();
- } else {
- mHelper = new HelperInternal19(editText, expectInitializedEmojiCompat);
- }
+ mHelper = new HelperInternal19(editText, expectInitializedEmojiCompat);
}
/**
diff --git a/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiTextViewHelper.java b/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiTextViewHelper.java
index 7748ba2..6ac961b 100644
--- a/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiTextViewHelper.java
+++ b/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiTextViewHelper.java
@@ -15,7 +15,6 @@
*/
package androidx.emoji2.viewsintegration;
-import android.os.Build;
import android.text.InputFilter;
import android.text.method.PasswordTransformationMethod;
import android.text.method.TransformationMethod;
@@ -95,9 +94,7 @@
*/
public EmojiTextViewHelper(@NonNull TextView textView, boolean expectInitializedEmojiCompat) {
Preconditions.checkNotNull(textView, "textView cannot be null");
- if (Build.VERSION.SDK_INT < 19) {
- mHelper = new HelperInternal();
- } else if (!expectInitializedEmojiCompat) {
+ if (!expectInitializedEmojiCompat) {
mHelper = new SkippingHelper19(textView);
} else {
mHelper = new HelperInternal19(textView);
diff --git a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/DefaultEmojiCompatConfigTest.java b/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/DefaultEmojiCompatConfigTest.java
index eda1b9d..bb4ecd2 100644
--- a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/DefaultEmojiCompatConfigTest.java
+++ b/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/DefaultEmojiCompatConfigTest.java
@@ -72,9 +72,6 @@
@SuppressWarnings("deprecation")
private boolean providerOnSystem() {
- if (Build.VERSION.SDK_INT < 19) {
- return false;
- }
List<ResolveInfo> result = ApplicationProvider.getApplicationContext()
.getPackageManager().queryIntentContentProviders(generateIntent(), 0);
for (ResolveInfo resolveInfo : result) {
@@ -218,12 +215,9 @@
Object result = reflectHelper.get(factory);
int apiVersion = Build.VERSION.SDK_INT;
Class<?> helperClass = Objects.requireNonNull(result).getClass();
- if (apiVersion < 19) {
+ if (apiVersion < 28) {
assertEquals(DefaultEmojiCompatConfig.DefaultEmojiCompatConfigHelper.class,
helperClass);
- } else if (apiVersion < 28) {
- assertEquals(DefaultEmojiCompatConfig.DefaultEmojiCompatConfigHelper_API19.class,
- helperClass);
} else {
assertEquals(DefaultEmojiCompatConfig.DefaultEmojiCompatConfigHelper_API28.class,
helperClass);
diff --git a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/NoFontTestEmojiConfig.java b/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/NoFontTestEmojiConfig.java
index 648f1bd..812a223 100644
--- a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/NoFontTestEmojiConfig.java
+++ b/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/NoFontTestEmojiConfig.java
@@ -19,12 +19,9 @@
import static org.mockito.Mockito.mock;
import android.graphics.Typeface;
-import android.os.Build;
import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
-@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public class NoFontTestEmojiConfig extends EmojiCompat.Config {
static EmojiCompat.Config emptyConfig() {
diff --git a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/SpannableBuilderTest.java b/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/SpannableBuilderTest.java
index d0ba42d..3e7d8ca 100644
--- a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/SpannableBuilderTest.java
+++ b/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/SpannableBuilderTest.java
@@ -35,7 +35,6 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.withSettings;
-import android.os.Build;
import android.text.DynamicLayout;
import android.text.Editable;
import android.text.Layout;
@@ -46,7 +45,6 @@
import android.text.style.QuoteSpan;
import android.text.style.TypefaceSpan;
-import androidx.annotation.RequiresApi;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.MediumTest;
import androidx.test.filters.SdkSuppress;
@@ -127,7 +125,6 @@
assertEquals(1, start);
}
- @RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Test
public void testBlocksSpanCallbacks_forEmojiSpans() {
final EmojiSpan span = mock(EmojiSpan.class);
@@ -189,7 +186,6 @@
verify(mWatcher, times(1)).afterTextChanged(any(Editable.class));
}
- @RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Test
public void testDoesNotBlockSpanCallbacksForOtherWatchers() {
final TextWatcher textWatcher = mock(TextWatcher.class);
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/text/DefaultEmojiCompatConfig.java b/emoji2/emoji2/src/main/java/androidx/emoji2/text/DefaultEmojiCompatConfig.java
index f9ca103..c0bb50e 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/text/DefaultEmojiCompatConfig.java
+++ b/emoji2/emoji2/src/main/java/androidx/emoji2/text/DefaultEmojiCompatConfig.java
@@ -241,8 +241,6 @@
private static DefaultEmojiCompatConfigHelper getHelperForApi() {
if (Build.VERSION.SDK_INT >= 28) {
return new DefaultEmojiCompatConfigHelper_API28();
- } else if (Build.VERSION.SDK_INT >= 19) {
- return new DefaultEmojiCompatConfigHelper_API19();
} else {
return new DefaultEmojiCompatConfigHelper();
}
@@ -250,30 +248,17 @@
}
/**
- * Helper to lookup signatures in package manager.
- *
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public static class DefaultEmojiCompatConfigHelper {
/**
- * Get the signing signatures for a package in package manager.
- */
- @SuppressWarnings("deprecation") // replaced in API 28
- @NonNull
- public Signature[] getSigningSignatures(@NonNull PackageManager packageManager,
- @NonNull String providerPackage) throws PackageManager.NameNotFoundException {
- PackageInfo packageInfoForSignatures = packageManager.getPackageInfo(providerPackage,
- PackageManager.GET_SIGNATURES);
- return packageInfoForSignatures.signatures;
- }
-
- /**
* Get the content provider by intent.
*/
@NonNull
+ @SuppressWarnings("deprecation")
public List<ResolveInfo> queryIntentContentProviders(@NonNull PackageManager packageManager,
@NonNull Intent intent, int flags) {
- return Collections.emptyList();
+ return packageManager.queryIntentContentProviders(intent, flags);
}
/**
@@ -283,31 +268,20 @@
*/
@Nullable
public ProviderInfo getProviderInfo(@NonNull ResolveInfo resolveInfo) {
- throw new IllegalStateException("Unable to get provider info prior to API 19");
- }
- }
-
- /**
- * Actually do lookups > API 19
- *
- */
- @RestrictTo(RestrictTo.Scope.LIBRARY)
- @RequiresApi(19)
- public static class DefaultEmojiCompatConfigHelper_API19
- extends DefaultEmojiCompatConfigHelper {
- @NonNull
- @Override
- @SuppressWarnings("deprecation")
- public List<ResolveInfo> queryIntentContentProviders(@NonNull PackageManager packageManager,
- @NonNull Intent intent, int flags) {
- return packageManager.queryIntentContentProviders(intent, flags);
- }
-
- @Nullable
- @Override
- public ProviderInfo getProviderInfo(@NonNull ResolveInfo resolveInfo) {
return resolveInfo.providerInfo;
}
+
+ /**
+ * Get the signing signatures for a package in package manager.
+ */
+ @SuppressWarnings("deprecation") // using deprecated API to match exact behavior in core
+ @NonNull
+ public Signature[] getSigningSignatures(@NonNull PackageManager packageManager,
+ @NonNull String providerPackage) throws PackageManager.NameNotFoundException {
+ PackageInfo packageInfoForSignatures = packageManager.getPackageInfo(providerPackage,
+ PackageManager.GET_SIGNATURES);
+ return packageInfoForSignatures.signatures;
+ }
}
/**
@@ -316,7 +290,7 @@
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(28)
public static class DefaultEmojiCompatConfigHelper_API28
- extends DefaultEmojiCompatConfigHelper_API19 {
+ extends DefaultEmojiCompatConfigHelper {
@SuppressWarnings("deprecation") // using deprecated API to match exact behavior in core
@Override
@NonNull
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiCompat.java b/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiCompat.java
index 3f6f2af..1755b2d 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiCompat.java
+++ b/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiCompat.java
@@ -22,7 +22,6 @@
import android.content.Context;
import android.graphics.Color;
import android.graphics.Paint;
-import android.os.Build;
import android.os.Bundle;
import android.text.Editable;
import android.text.method.KeyListener;
@@ -463,8 +462,7 @@
if (config.mInitCallbacks != null && !config.mInitCallbacks.isEmpty()) {
mInitCallbacks.addAll(config.mInitCallbacks);
}
- mHelper = Build.VERSION.SDK_INT < 19 ? new CompatInternal(this) : new CompatInternal19(
- this);
+ mHelper = new CompatInternal(this);
loadMetadata();
}
@@ -889,11 +887,7 @@
*/
public static boolean handleOnKeyDown(@NonNull final Editable editable, final int keyCode,
@NonNull final KeyEvent event) {
- if (Build.VERSION.SDK_INT >= 19) {
- return EmojiProcessor.handleOnKeyDown(editable, keyCode, event);
- } else {
- return false;
- }
+ return EmojiProcessor.handleOnKeyDown(editable, keyCode, event);
}
/**
@@ -918,12 +912,8 @@
@NonNull final InputConnection inputConnection, @NonNull final Editable editable,
@IntRange(from = 0) final int beforeLength, @IntRange(from = 0) final int afterLength,
final boolean inCodePoints) {
- if (Build.VERSION.SDK_INT >= 19) {
- return EmojiProcessor.handleDeleteSurroundingText(inputConnection, editable,
- beforeLength, afterLength, inCodePoints);
- } else {
- return false;
- }
+ return EmojiProcessor.handleDeleteSurroundingText(inputConnection, editable,
+ beforeLength, afterLength, inCodePoints);
}
/**
@@ -1646,64 +1636,7 @@
}
}
- /**
- * Internal helper class to behave no-op for certain functions.
- */
- private static class CompatInternal {
- final EmojiCompat mEmojiCompat;
-
- CompatInternal(EmojiCompat emojiCompat) {
- mEmojiCompat = emojiCompat;
- }
-
- void loadMetadata() {
- // Moves into LOAD_STATE_SUCCESS state immediately.
- mEmojiCompat.onMetadataLoadSuccess();
- }
-
- boolean hasEmojiGlyph(@NonNull final CharSequence sequence) {
- // Since no metadata is loaded, EmojiCompat cannot detect or render any emojis.
- return false;
- }
-
- boolean hasEmojiGlyph(@NonNull final CharSequence sequence, final int metadataVersion) {
- // Since no metadata is loaded, EmojiCompat cannot detect or render any emojis.
- return false;
- }
-
- int getEmojiStart(@NonNull final CharSequence cs, @IntRange(from = 0) final int offset) {
- // Since no metadata is loaded, EmojiCompat cannot detect any emojis.
- return -1;
- }
-
- int getEmojiEnd(@NonNull final CharSequence cs, @IntRange(from = 0) final int offset) {
- // Since no metadata is loaded, EmojiCompat cannot detect any emojis.
- return -1;
- }
-
- CharSequence process(@NonNull final CharSequence charSequence,
- @IntRange(from = 0) final int start, @IntRange(from = 0) final int end,
- @IntRange(from = 0) final int maxEmojiCount, boolean replaceAll) {
- // Returns the given charSequence as it is.
- return charSequence;
- }
-
- void updateEditorInfoAttrs(@NonNull final EditorInfo outAttrs) {
- // Does not add any EditorInfo attributes.
- }
-
- String getAssetSignature() {
- return "";
- }
-
- @CodepointSequenceMatchResult
- public int getEmojiMatch(CharSequence sequence, int metadataVersion) {
- return EMOJI_UNSUPPORTED;
- }
- }
-
- @RequiresApi(19)
- private static final class CompatInternal19 extends CompatInternal {
+ private static final class CompatInternal {
/**
* Responsible to process a CharSequence and add the spans. @{code Null} until the time the
* metadata is loaded.
@@ -1714,13 +1647,12 @@
* Keeps the information about emojis. Null until the time the data is loaded.
*/
private volatile MetadataRepo mMetadataRepo;
+ private final EmojiCompat mEmojiCompat;
-
- CompatInternal19(EmojiCompat emojiCompat) {
- super(emojiCompat);
+ CompatInternal(EmojiCompat emojiCompat) {
+ mEmojiCompat = emojiCompat;
}
- @Override
void loadMetadata() {
try {
final MetadataRepoLoaderCallback callback = new MetadataRepoLoaderCallback() {
@@ -1761,45 +1693,37 @@
mEmojiCompat.onMetadataLoadSuccess();
}
- @Override
boolean hasEmojiGlyph(@NonNull CharSequence sequence) {
return mProcessor.getEmojiMatch(sequence) == EMOJI_SUPPORTED;
}
- @Override
boolean hasEmojiGlyph(@NonNull CharSequence sequence, int metadataVersion) {
int emojiMatch = mProcessor.getEmojiMatch(sequence, metadataVersion);
return emojiMatch == EMOJI_SUPPORTED;
}
- @Override
public int getEmojiMatch(CharSequence sequence, int metadataVersion) {
return mProcessor.getEmojiMatch(sequence, metadataVersion);
}
- @Override
int getEmojiStart(@NonNull final CharSequence sequence, final int offset) {
return mProcessor.getEmojiStart(sequence, offset);
}
- @Override
int getEmojiEnd(@NonNull final CharSequence sequence, final int offset) {
return mProcessor.getEmojiEnd(sequence, offset);
}
- @Override
CharSequence process(@NonNull CharSequence charSequence, int start, int end,
int maxEmojiCount, boolean replaceAll) {
return mProcessor.process(charSequence, start, end, maxEmojiCount, replaceAll);
}
- @Override
void updateEditorInfoAttrs(@NonNull EditorInfo outAttrs) {
outAttrs.extras.putInt(EDITOR_INFO_METAVERSION_KEY, mMetadataRepo.getMetadataVersion());
outAttrs.extras.putBoolean(EDITOR_INFO_REPLACE_ALL_KEY, mEmojiCompat.mReplaceAll);
}
- @Override
String getAssetSignature() {
final String sha = mMetadataRepo.getMetadataList().sourceSha();
return sha == null ? "" : sha;
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiCompatInitializer.java b/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiCompatInitializer.java
index f4823bf..fb3f8f0 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiCompatInitializer.java
+++ b/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiCompatInitializer.java
@@ -17,7 +17,6 @@
package androidx.emoji2.text;
import android.content.Context;
-import android.os.Build;
import android.os.Handler;
import androidx.annotation.NonNull;
@@ -84,12 +83,9 @@
@NonNull
@Override
public Boolean create(@NonNull Context context) {
- if (Build.VERSION.SDK_INT >= 19) {
- EmojiCompat.init(new BackgroundDefaultConfig(context));
- delayUntilFirstResume(context);
- return true;
- }
- return false;
+ EmojiCompat.init(new BackgroundDefaultConfig(context));
+ delayUntilFirstResume(context);
+ return true;
}
/**
diff --git a/exifinterface/exifinterface/src/androidTest/java/androidx/exifinterface/media/ExifInterfaceTest.java b/exifinterface/exifinterface/src/androidTest/java/androidx/exifinterface/media/ExifInterfaceTest.java
index ca2a19f..4381628 100644
--- a/exifinterface/exifinterface/src/androidTest/java/androidx/exifinterface/media/ExifInterfaceTest.java
+++ b/exifinterface/exifinterface/src/androidTest/java/androidx/exifinterface/media/ExifInterfaceTest.java
@@ -50,7 +50,6 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -1443,10 +1442,6 @@
* <p>This does not check the image itself for similarity/equality.
*/
private void assertBitmapsEquivalent(File expectedImageFile, File actualImageFile) {
- if (Build.VERSION.SDK_INT < 16 && expectedImageFile.getName().endsWith("webp")) {
- // BitmapFactory can't parse WebP files on API levels before 16: b/254571189
- return;
- }
if (Build.VERSION.SDK_INT < 26
&& expectedImageFile.getName().equals(WEBP_WITHOUT_EXIF_WITH_ANIM_DATA)) {
// BitmapFactory can't parse animated WebP files on API levels before 26: b/259964971
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimatorTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimatorTest.kt
index 7ca4c07..61da32d 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimatorTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimatorTest.kt
@@ -411,7 +411,6 @@
// Ensure that removing and popping a Fragment uses the exit and popEnter animators,
// but the animators are delayed when an entering Fragment is postponed.
- @RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
@Test
fun postponedRemoveAnimators() {
val fm = activityRule.activity.supportFragmentManager
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java b/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
index dad6a69..fa5874e 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
@@ -30,7 +30,6 @@
import android.content.IntentSender;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -67,7 +66,6 @@
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.annotation.StringRes;
import androidx.annotation.UiThread;
@@ -3083,19 +3081,17 @@
mChildFragmentManager.noteStateNotSaved();
mState = CREATED;
mCalled = false;
- if (Build.VERSION.SDK_INT >= 19) {
- mLifecycleRegistry.addObserver(new LifecycleEventObserver() {
- @Override
- public void onStateChanged(@NonNull LifecycleOwner source,
- @NonNull Lifecycle.Event event) {
- if (event == Lifecycle.Event.ON_STOP) {
- if (mView != null) {
- Api19Impl.cancelPendingInputEvents(mView);
- }
+ mLifecycleRegistry.addObserver(new LifecycleEventObserver() {
+ @Override
+ public void onStateChanged(@NonNull LifecycleOwner source,
+ @NonNull Lifecycle.Event event) {
+ if (event == Lifecycle.Event.ON_STOP) {
+ if (mView != null) {
+ mView.cancelPendingInputEvents();
}
}
- });
- }
+ }
+ });
onCreate(savedInstanceState);
mIsCreated = true;
if (!mCalled) {
@@ -3713,13 +3709,4 @@
// hasn't been called yet.
boolean mEnterTransitionPostponed;
}
-
- @RequiresApi(19)
- static class Api19Impl {
- private Api19Impl() { }
-
- static void cancelPendingInputEvents(@NonNull View view) {
- view.cancelPendingInputEvents();
- }
- }
}
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentContainerView.kt b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentContainerView.kt
index 43f6429..e9dd1a8 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentContainerView.kt
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentContainerView.kt
@@ -18,7 +18,6 @@
import android.animation.LayoutTransition
import android.content.Context
import android.graphics.Canvas
-import android.os.Build
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
@@ -178,13 +177,6 @@
* @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
*/
public override fun setLayoutTransition(transition: LayoutTransition?) {
- if (Build.VERSION.SDK_INT < 18) {
- // Transitions on APIs below 18 are using an empty LayoutTransition as a replacement
- // for suppressLayout(true) and null LayoutTransition to then unsuppress it. If the
- // API is below 18, we should allow FrameLayout to handle this call.
- super.setLayoutTransition(transition)
- return
- }
throw UnsupportedOperationException(
"FragmentContainerView does not support Layout Transitions or " +
"animateLayoutChanges=\"true\"."
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/AppWidgetSession.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/AppWidgetSession.kt
index fdc700d..09be273 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/AppWidgetSession.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/AppWidgetSession.kt
@@ -45,7 +45,8 @@
import androidx.glance.state.GlanceState
import androidx.glance.state.GlanceStateDefinition
import kotlinx.coroutines.CancellationException
-import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.CompletableJob
+import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
/**
@@ -100,6 +101,7 @@
private var glanceState by mutableStateOf(initialGlanceState, neverEqualPolicy())
private var options by mutableStateOf(initialOptions, neverEqualPolicy())
private var lambdas = mapOf<String, List<LambdaAction>>()
+ private val parentJob = Job()
internal val lastRemoteViews = MutableStateFlow<RemoteViews?>(null)
@@ -226,7 +228,9 @@
lambdas[event.key]?.forEach { it.block() }
} ?: Log.w(TAG, "Triggering Action(${event.key}) for session($key) failed")
}
- is WaitForReady -> event.resume.send(Unit)
+ is WaitForReady -> {
+ event.job.apply { if (isActive) complete() }
+ }
else -> {
throw IllegalArgumentException(
"Sent unrecognized event type ${event.javaClass} to AppWidgetSession"
@@ -235,6 +239,16 @@
}
}
+ override fun onClosed() {
+ // Normally when we are closed, any pending events are processed before the channel is
+ // shutdown. However, it is possible that the Worker for this session will die before
+ // processing the remaining events. So when this session is closed, we will immediately
+ // resume all waiters without waiting for their events to be processed. If the Worker lives
+ // long enough to process their events, it will have no effect because their Jobs are no
+ // longer active.
+ parentJob.cancel()
+ }
+
suspend fun updateGlance() {
sendEvent(UpdateGlanceState)
}
@@ -247,11 +261,17 @@
sendEvent(RunLambda(key))
}
- suspend fun waitForReady() {
- WaitForReady().let {
- sendEvent(it)
- it.resume.receive()
- }
+ /**
+ * Returns a Job that can be used to wait until the session is ready (i.e. has finished
+ * processEmittableTree for the first time and is now receiving events). You can wait on the
+ * session to be ready by calling [Job.join] on the returned [Job]. When the session is ready,
+ * join will resume successfully (Job is completed). If the session is closed before it is
+ * ready, we call [Job.cancel] and the call to join resumes with [CancellationException].
+ */
+ suspend fun waitForReady(): Job {
+ val event = WaitForReady(Job(parentJob))
+ sendEvent(event)
+ return event.job
}
private fun notifyWidgetOfError(context: Context, throwable: Throwable) {
@@ -276,7 +296,5 @@
@VisibleForTesting
internal class RunLambda(val key: String)
@VisibleForTesting
- internal class WaitForReady(
- val resume: Channel<Unit> = Channel(Channel.CONFLATED)
- )
+ internal class WaitForReady(val job: CompletableJob)
}
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceAppWidget.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceAppWidget.kt
index dac5826..1ce033a 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceAppWidget.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceAppWidget.kt
@@ -31,6 +31,7 @@
import androidx.glance.appwidget.state.getAppWidgetState
import androidx.glance.session.GlanceSessionManager
import androidx.glance.session.SessionManager
+import androidx.glance.session.SessionManagerScope
import androidx.glance.state.GlanceState
import androidx.glance.state.GlanceStateDefinition
import androidx.glance.state.PreferencesGlanceStateDefinition
@@ -120,7 +121,9 @@
*/
internal suspend fun deleted(context: Context, appWidgetId: Int) {
val glanceId = AppWidgetId(appWidgetId)
- sessionManager.closeSession(glanceId.toSessionKey())
+ sessionManager.runWithLock {
+ closeSession(glanceId.toSessionKey())
+ }
try {
onDelete(context, glanceId)
} catch (cancelled: CancellationException) {
@@ -144,10 +147,12 @@
) {
Tracing.beginGlanceAppWidgetUpdate()
val glanceId = AppWidgetId(appWidgetId)
- if (!sessionManager.isSessionRunning(context, glanceId.toSessionKey())) {
- sessionManager.startSession(context, AppWidgetSession(this, glanceId, options))
- } else {
- val session = sessionManager.getSession(glanceId.toSessionKey()) as AppWidgetSession
+ sessionManager.runWithLock {
+ if (!isSessionRunning(context, glanceId.toSessionKey())) {
+ startSession(context, AppWidgetSession(this@GlanceAppWidget, glanceId, options))
+ return@runWithLock
+ }
+ val session = getSession(glanceId.toSessionKey()) as AppWidgetSession
session.updateGlance()
}
}
@@ -163,14 +168,9 @@
options: Bundle? = null,
) {
val glanceId = AppWidgetId(appWidgetId)
- val session = if (!sessionManager.isSessionRunning(context, glanceId.toSessionKey())) {
- AppWidgetSession(this, glanceId, options).also { session ->
- sessionManager.startSession(context, session)
- }
- } else {
- sessionManager.getSession(glanceId.toSessionKey()) as AppWidgetSession
+ sessionManager.getOrCreateAppWidgetSession(context, glanceId, options) { session ->
+ session.runLambda(actionKey)
}
- session.runLambda(actionKey)
}
/**
@@ -189,10 +189,7 @@
return
}
val glanceId = AppWidgetId(appWidgetId)
- if (!sessionManager.isSessionRunning(context, glanceId.toSessionKey())) {
- sessionManager.startSession(context, AppWidgetSession(this, glanceId, options))
- } else {
- val session = sessionManager.getSession(glanceId.toSessionKey()) as AppWidgetSession
+ sessionManager.getOrCreateAppWidgetSession(context, glanceId, options) { session ->
session.updateAppWidgetOptions(options)
}
}
@@ -230,6 +227,19 @@
AppWidgetManager.getInstance(context).updateAppWidget(appWidgetId, rv)
}
}
+
+ private suspend fun SessionManager.getOrCreateAppWidgetSession(
+ context: Context,
+ glanceId: AppWidgetId,
+ options: Bundle? = null,
+ block: suspend SessionManagerScope.(AppWidgetSession) -> Unit
+ ) = runWithLock {
+ if (!isSessionRunning(context, glanceId.toSessionKey())) {
+ startSession(context, AppWidgetSession(this@GlanceAppWidget, glanceId, options))
+ }
+ val session = getSession(glanceId.toSessionKey()) as AppWidgetSession
+ block(session)
+ }
}
@RestrictTo(Scope.LIBRARY_GROUP)
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceRemoteViewsService.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceRemoteViewsService.kt
index 1e91d1c..52058e4 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceRemoteViewsService.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceRemoteViewsService.kt
@@ -21,12 +21,14 @@
import android.content.Intent
import android.net.Uri
import android.os.Build
+import android.util.Log
import android.widget.RemoteViews
import android.widget.RemoteViewsService
import androidx.annotation.DoNotInline
import androidx.annotation.RequiresApi
import androidx.annotation.RestrictTo
import androidx.glance.session.GlanceSessionManager
+import kotlinx.coroutines.channels.ClosedSendChannelException
import kotlinx.coroutines.runBlocking
/**
@@ -51,6 +53,7 @@
companion object {
const val EXTRA_VIEW_ID = "androidx.glance.widget.extra.view_id"
const val EXTRA_SIZE_INFO = "androidx.glance.widget.extra.size_info"
+ const val TAG = "GlanceRemoteViewService"
// An in-memory store containing items to be returned via the adapter when requested.
private val InMemoryStore = RemoteCollectionItemsInMemoryStore()
@@ -107,26 +110,49 @@
private fun loadData() {
runBlocking {
val glanceId = AppWidgetId(appWidgetId)
- // If session is already running, data must have already been loaded into the store
- // during composition.
- if (!GlanceSessionManager.isSessionRunning(context, glanceId.toSessionKey())) {
- startSessionAndWaitUntilReady(glanceId)
+ try {
+ startSessionIfNeededAndWaitUntilReady(glanceId)
+ } catch (e: ClosedSendChannelException) {
+ // This catch should no longer be necessary.
+ // Because we use SessionManager.runWithLock, we are guaranteed that the session
+ // we create won't be closed by concurrent calls to SessionManager. Currently,
+ // the only way a session would be closed is if there is an error in the
+ // composition that happens between the call to `startSession` and
+ // `waitForReady()` In that case, the composition error will be logged by
+ // GlanceAppWidget.onCompositionError, but could still cause
+ // ClosedSendChannelException. This is pretty unlikely, however keeping this
+ // here to avoid crashes in that scenario.
+ Log.e(TAG, "Error when trying to start session for list items", e)
}
}
}
- private suspend fun startSessionAndWaitUntilReady(glanceId: AppWidgetId) {
+ private suspend fun startSessionIfNeededAndWaitUntilReady(glanceId: AppWidgetId) {
+ val job = getGlanceAppWidget()?.let { widget ->
+ GlanceSessionManager.runWithLock {
+ if (isSessionRunning(context, glanceId.toSessionKey())) {
+ // If session is already running, data must have already been loaded into
+ // the store during composition.
+ return@runWithLock null
+ }
+ startSession(context, AppWidgetSession(widget, glanceId))
+ val session = getSession(glanceId.toSessionKey()) as AppWidgetSession
+ session.waitForReady()
+ }
+ } ?: UnmanagedSessionReceiver.getSession(appWidgetId)?.waitForReady()
+ // The following join() may throw CancellationException if the session is closed before
+ // it is ready. This will have the effect of cancelling the runBlocking scope.
+ job?.join()
+ }
+
+ private fun getGlanceAppWidget(): GlanceAppWidget? {
val appWidgetManager = AppWidgetManager.getInstance(context)
val providerInfo = appWidgetManager.getAppWidgetInfo(appWidgetId)
- providerInfo?.provider?.className?.let { className ->
+ return providerInfo?.provider?.className?.let { className ->
val receiverClass = Class.forName(className)
- val glanceAppWidget =
- (receiverClass.getDeclaredConstructor()
- .newInstance() as GlanceAppWidgetReceiver).glanceAppWidget
- AppWidgetSession(glanceAppWidget, glanceId)
- .also { GlanceSessionManager.startSession(context, it) }
- .waitForReady()
- } ?: UnmanagedSessionReceiver.getSession(appWidgetId)?.waitForReady()
+ (receiverClass.getDeclaredConstructor()
+ .newInstance() as GlanceAppWidgetReceiver).glanceAppWidget
+ }
}
override fun onDestroy() {
diff --git a/glance/glance-appwidget/src/test/kotlin/androidx/glance/appwidget/AppWidgetSessionTest.kt b/glance/glance-appwidget/src/test/kotlin/androidx/glance/appwidget/AppWidgetSessionTest.kt
index 6eaa1a5..4c62efd 100644
--- a/glance/glance-appwidget/src/test/kotlin/androidx/glance/appwidget/AppWidgetSessionTest.kt
+++ b/glance/glance-appwidget/src/test/kotlin/androidx/glance/appwidget/AppWidgetSessionTest.kt
@@ -219,6 +219,25 @@
assertThat(caught).isEqualTo(null)
}
+ @Test
+ fun waitForReadyResumesWhenEventIsReceived() = runTest {
+ launch {
+ session.waitForReady().join()
+ session.close()
+ }
+ session.receiveEvents(context) {}
+ }
+
+ @Test
+ fun waitForReadyResumesWhenSessionIsClosed() = runTest {
+ launch {
+ session.waitForReady().join()
+ }
+ // Advance until waitForReady suspends.
+ this.testScheduler.advanceUntilIdle()
+ session.close()
+ }
+
private class TestGlanceState : ConfigManager {
val getValueCalls = mutableListOf<String>()
diff --git a/glance/glance/src/androidTest/kotlin/androidx/glance/session/GlanceSessionManagerTest.kt b/glance/glance/src/androidTest/kotlin/androidx/glance/session/GlanceSessionManagerTest.kt
index 3f4fa05..474e759 100644
--- a/glance/glance/src/androidTest/kotlin/androidx/glance/session/GlanceSessionManagerTest.kt
+++ b/glance/glance/src/androidTest/kotlin/androidx/glance/session/GlanceSessionManagerTest.kt
@@ -127,7 +127,9 @@
val text = assertIs<EmittableText>(testSession.uiTree.receive().children.single())
assertThat(text.text).isEqualTo("Hello World")
- assertNotNull(GlanceSessionManager.getSession(testSession.key)).close()
+ GlanceSessionManager.runWithLock {
+ assertNotNull(getSession(testSession.key)).close()
+ }
waitForWorkerSuccess()
}
@@ -150,7 +152,9 @@
// The session is not subject to a timeout before the composition has been processed
// successfully for the first time.
delay(initialTimeout * 5)
- assertThat(GlanceSessionManager.isSessionRunning(context, testSession.key)).isTrue()
+ GlanceSessionManager.runWithLock {
+ assertThat(isSessionRunning(context, testSession.key)).isTrue()
+ }
testSession.uiTree.receive()
val timeout = testTimeSource.measureTime {
@@ -189,9 +193,11 @@
}
private suspend fun startSession() {
- GlanceSessionManager.startSession(context, testSession)
- waitForWorkerStart()
- assertThat(GlanceSessionManager.isSessionRunning(context, testSession.key)).isTrue()
+ GlanceSessionManager.runWithLock {
+ startSession(context, testSession)
+ waitForWorkerStart()
+ assertThat(isSessionRunning(context, testSession.key)).isTrue()
+ }
}
private suspend fun waitForWorkerState(vararg state: State) = workerState.first {
diff --git a/glance/glance/src/main/java/androidx/glance/session/Session.kt b/glance/glance/src/main/java/androidx/glance/session/Session.kt
index c7aec1e..614aff6 100644
--- a/glance/glance/src/main/java/androidx/glance/session/Session.kt
+++ b/glance/glance/src/main/java/androidx/glance/session/Session.kt
@@ -22,6 +22,7 @@
import androidx.compose.runtime.Composable
import androidx.glance.EmittableWithChildren
import androidx.glance.GlanceComposable
+import java.util.concurrent.atomic.AtomicBoolean
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.ClosedReceiveChannelException
@@ -32,6 +33,12 @@
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
abstract class Session(val key: String) {
+ // _isOpen/isOpen is used to check whether this Session's event channel is still open and
+ // accepting events (close has not been called). It may be checked or set from different
+ // threads, so we use an AtomicBoolean so that the value is updated atomically.
+ private val _isOpen = AtomicBoolean(true)
+ internal val isOpen: Boolean
+ get() = _isOpen.get()
private val eventChannel = Channel<Any>(Channel.UNLIMITED)
/**
@@ -85,11 +92,22 @@
}
}
+ /**
+ * Close the session. Any events sent before [close] will be processed unless the Worker for
+ * this session is cancelled.
+ */
fun close() {
eventChannel.close()
+ _isOpen.set(false)
+ onClosed()
}
/**
+ * Called after the session is closed. Can be used by implementers to clean up any resources.
+ */
+ open fun onClosed() {}
+
+ /**
* Called when there is an error in the composition. The session will be closed immediately
* after this.
*/
diff --git a/glance/glance/src/main/java/androidx/glance/session/SessionManager.kt b/glance/glance/src/main/java/androidx/glance/session/SessionManager.kt
index 5b83da2..4099d5e 100644
--- a/glance/glance/src/main/java/androidx/glance/session/SessionManager.kt
+++ b/glance/glance/src/main/java/androidx/glance/session/SessionManager.kt
@@ -16,6 +16,7 @@
package androidx.glance.session
+import android.annotation.SuppressLint
import android.content.Context
import android.util.Log
import androidx.annotation.RestrictTo
@@ -28,6 +29,8 @@
import androidx.work.await
import androidx.work.workDataOf
import java.util.concurrent.TimeUnit
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
@JvmDefaultWithCompatibility
/**
@@ -38,6 +41,27 @@
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
interface SessionManager {
/**
+ * [runWithLock] provides a scope in which to run operations on SessionManager.
+ *
+ * The implementation must ensure that concurrent calls to [runWithLock] are mutually exclusive.
+ * Because this function holds a lock while running [block], clients should not run any
+ * long-running operations in [block]. The client should not maintain a reference to the
+ * [SessionManagerScope] after [block] returns.
+ */
+ suspend fun <T> runWithLock(block: suspend SessionManagerScope.() -> T): T
+
+ /**
+ * The name of the session key parameter, which is used to set the session key in the Worker's
+ * input data.
+ * TODO: consider using a typealias instead
+ */
+ val keyParam: String
+ get() = "KEY"
+}
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+interface SessionManagerScope {
+ /**
* Start a session for the Glance in [session].
*/
suspend fun startSession(context: Context, session: Session)
@@ -56,9 +80,6 @@
* Gets the session corresponding to [key] if it exists
*/
fun getSession(key: String): Session?
-
- val keyParam: String
- get() = "KEY"
}
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@@ -67,49 +88,65 @@
internal class SessionManagerImpl(
private val workerClass: Class<out ListenableWorker>
) : SessionManager {
- private val sessions = mutableMapOf<String, Session>()
- companion object {
- private const val TAG = "GlanceSessionManager"
- private const val DEBUG = false
+ private companion object {
+ const val TAG = "GlanceSessionManager"
+ const val DEBUG = false
}
- override suspend fun startSession(context: Context, session: Session) {
- if (DEBUG) Log.d(TAG, "startSession(${session.key})")
- synchronized(sessions) {
- sessions.put(session.key, session)
- }?.close()
- val workRequest = OneTimeWorkRequest.Builder(workerClass)
- .setInputData(
- workDataOf(
- keyParam to session.key
+ // This mutex guards access to the SessionManagerScope, to prevent multiple clients from
+ // performing SessionManagerScope operations at the same time.
+ private val mutex = Mutex()
+
+ // All external access to this object is protected with a mutex, so there is no need for any
+ // internal synchronization.
+ private val scope = object : SessionManagerScope {
+ private val sessions = mutableMapOf<String, Session>()
+
+ override suspend fun startSession(context: Context, session: Session) {
+ if (DEBUG) Log.d(TAG, "startSession(${session.key})")
+ sessions.put(session.key, session)?.let { previousSession ->
+ previousSession.close()
+ }
+ val workRequest = OneTimeWorkRequest.Builder(workerClass)
+ .setInputData(
+ workDataOf(
+ keyParam to session.key
+ )
)
- )
- .build()
- WorkManager.getInstance(context)
- .enqueueUniqueWork(session.key, ExistingWorkPolicy.REPLACE, workRequest)
- .result.await()
- enqueueDelayedWorker(context)
- }
-
- override fun getSession(key: String): Session? = synchronized(sessions) {
- sessions[key]
- }
-
- override suspend fun isSessionRunning(context: Context, key: String) =
- (WorkManager.getInstance(context).getWorkInfosForUniqueWork(key).await()
- .any { it.state == WorkInfo.State.RUNNING } && synchronized(sessions) {
- sessions.containsKey(key)
- }).also {
- if (DEBUG) Log.d(TAG, "isSessionRunning($key) == $it")
+ .build()
+ WorkManager.getInstance(context)
+ .enqueueUniqueWork(session.key, ExistingWorkPolicy.REPLACE, workRequest)
+ .result.await()
+ enqueueDelayedWorker(context)
}
- override suspend fun closeSession(key: String) {
- if (DEBUG) Log.d(TAG, "closeSession($key)")
- synchronized(sessions) {
- sessions.remove(key)
- }?.close()
+ override fun getSession(key: String): Session? = sessions[key]
+
+ @SuppressLint("ListIterator")
+ override suspend fun isSessionRunning(
+ context: Context,
+ key: String
+ ): Boolean {
+ val workerIsRunningOrEnqueued = WorkManager.getInstance(context)
+ .getWorkInfosForUniqueWork(key)
+ .await()
+ .any { it.state in listOf(WorkInfo.State.RUNNING, WorkInfo.State.ENQUEUED) }
+ val hasOpenSession = sessions[key]?.isOpen ?: false
+ val isRunning = hasOpenSession && workerIsRunningOrEnqueued
+ if (DEBUG) Log.d(TAG, "isSessionRunning($key) == $isRunning")
+ return isRunning
+ }
+
+ override suspend fun closeSession(key: String) {
+ if (DEBUG) Log.d(TAG, "closeSession($key)")
+ sessions.remove(key)?.close()
+ }
}
+ override suspend fun <T> runWithLock(
+ block: suspend SessionManagerScope.() -> T
+ ): T = mutex.withLock { scope.block() }
+
/**
* Workaround worker to fix b/119920965
*/
diff --git a/glance/glance/src/main/java/androidx/glance/session/SessionWorker.kt b/glance/glance/src/main/java/androidx/glance/session/SessionWorker.kt
index 2cff47b..544dd2d 100644
--- a/glance/glance/src/main/java/androidx/glance/session/SessionWorker.kt
+++ b/glance/glance/src/main/java/androidx/glance/session/SessionWorker.kt
@@ -101,12 +101,14 @@
if (DEBUG) Log.d(TAG, "Received idle event, session timeout $timeLeft")
}
) {
- val session = sessionManager.getSession(key) ?: if (params.runAttemptCount == 0) {
+ val session = sessionManager.runWithLock {
+ getSession(key)
+ } ?: if (params.runAttemptCount == 0) {
error("No session available for key $key")
} else {
- // If this is a retry because the process was restarted (e.g. on app upgrade or
- // reinstall), the Session object won't be available because it's not persistable
- // at the moment.
+ // If this is a retry because the process was restarted (e.g. on app upgrade
+ // or reinstall), the Session object won't be available because it's not
+ // persistable.
Log.w(
TAG,
"SessionWorker attempted restart but Session is not available for $key"
@@ -114,14 +116,18 @@
return@observeIdleEvents Result.success()
}
- runSession(
- applicationContext,
- session,
- timeouts,
- effectJobFactory = {
- Job().also { effectJob = it }
- }
- )
+ try {
+ runSession(
+ applicationContext,
+ session,
+ timeouts,
+ effectJobFactory = {
+ Job().also { effectJob = it }
+ }
+ )
+ } finally {
+ session.close()
+ }
Result.success()
}
} ?: Result.success(Data.Builder().putBoolean(TimeoutExitReason, true).build())
diff --git a/glance/glance/src/test/kotlin/androidx/glance/session/SessionManagerImplTest.kt b/glance/glance/src/test/kotlin/androidx/glance/session/SessionManagerImplTest.kt
index 9a05800..b47fa4f 100644
--- a/glance/glance/src/test/kotlin/androidx/glance/session/SessionManagerImplTest.kt
+++ b/glance/glance/src/test/kotlin/androidx/glance/session/SessionManagerImplTest.kt
@@ -29,9 +29,12 @@
import androidx.work.impl.WorkManagerImpl
import androidx.work.testing.WorkManagerTestInitHelper
import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.atomic.AtomicBoolean
import kotlin.coroutines.suspendCoroutine
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest
+import kotlinx.coroutines.yield
import org.junit.After
import org.junit.Before
import org.junit.Test
@@ -84,19 +87,55 @@
@Test
fun startSession() = runTest {
- assertThat(sessionManager.isSessionRunning(context, key)).isFalse()
- sessionManager.startSession(context, session)
- assertThat(sessionManager.isSessionRunning(context, key)).isTrue()
- assertThat(sessionManager.getSession(key)).isSameInstanceAs(session)
+ sessionManager.runWithLock {
+ assertThat(isSessionRunning(context, key)).isFalse()
+ startSession(context, session)
+ assertThat(isSessionRunning(context, key)).isTrue()
+ assertThat(getSession(key)).isSameInstanceAs(session)
+ }
}
@Test
fun closeSession() = runTest {
- sessionManager.startSession(context, session)
- assertThat(sessionManager.isSessionRunning(context, key)).isTrue()
- sessionManager.closeSession(key)
- assertThat(sessionManager.isSessionRunning(context, key)).isFalse()
- assertThat(sessionManager.getSession(key)).isNull()
+ sessionManager.runWithLock {
+ startSession(context, session)
+ assertThat(isSessionRunning(context, key)).isTrue()
+ closeSession(key)
+ assertThat(isSessionRunning(context, key)).isFalse()
+ assertThat(getSession(key)).isNull()
+ }
+ }
+
+ @Test
+ fun closedSessionIsNotRunning() = runTest {
+ sessionManager.runWithLock {
+ assertThat(isSessionRunning(context, key)).isFalse()
+ startSession(context, session)
+ assertThat(isSessionRunning(context, key)).isTrue()
+ session.close()
+ assertThat(isSessionRunning(context, key)).isFalse()
+ }
+ }
+
+ @Test
+ fun runWithLockIsMutuallyExclusive() = runTest {
+ val firstRan = AtomicBoolean(false)
+ launch {
+ sessionManager.runWithLock {
+ yield()
+ firstRan.set(true)
+ }
+ }
+ // Because test dispatchers are single threaded and do not run background `launch`es until
+ // we suspend, we yield here to allow the first transaction to run. This resumes after the
+ // yield above, while the first transaction still has the lock but is suspended.
+ yield()
+ // This call to runWithLock should suspend until the first transaction finishes, then run
+ // the block. If it is not mutually exclusive, it will run right away and firstRan will not
+ // be true.
+ sessionManager.runWithLock {
+ assertThat(firstRan.get()).isTrue()
+ }
}
}
diff --git a/glance/glance/src/test/kotlin/androidx/glance/session/SessionWorkerTest.kt b/glance/glance/src/test/kotlin/androidx/glance/session/SessionWorkerTest.kt
index c8275e6..693218f 100644
--- a/glance/glance/src/test/kotlin/androidx/glance/session/SessionWorkerTest.kt
+++ b/glance/glance/src/test/kotlin/androidx/glance/session/SessionWorkerTest.kt
@@ -75,8 +75,8 @@
val result = worker.doWork()
assertThat(result).isEqualTo(Result.success())
}
- sessionManager.startSession(context)
- sessionManager.closeSession()
+ sessionManager.scope.startSession(context)
+ sessionManager.scope.closeSession()
}
@Test
@@ -86,7 +86,7 @@
assertThat(result).isEqualTo(Result.success())
}
- val root = sessionManager.startSession(context) {
+ val root = sessionManager.scope.startSession(context) {
Box {
Text("Hello World")
}
@@ -94,7 +94,7 @@
val box = assertIs<EmittableBox>(root.children.single())
val text = assertIs<EmittableText>(box.children.single())
assertThat(text.text).isEqualTo("Hello World")
- sessionManager.closeSession()
+ sessionManager.scope.closeSession()
}
@Test
@@ -103,10 +103,10 @@
val result = worker.doWork()
assertThat(result).isEqualTo(Result.success())
}
- sessionManager.startSession(context).first()
- val session = assertIs<TestSession>(sessionManager.getSession(SESSION_KEY))
+ sessionManager.scope.startSession(context).first()
+ val session = assertIs<TestSession>(sessionManager.scope.getSession(SESSION_KEY))
assertThat(session.provideGlanceCalled).isEqualTo(1)
- sessionManager.closeSession()
+ sessionManager.scope.closeSession()
}
@Test
@@ -117,7 +117,7 @@
}
val state = mutableStateOf("Hello World")
- val uiFlow = sessionManager.startSession(context) {
+ val uiFlow = sessionManager.scope.startSession(context) {
Text(state.value)
}
uiFlow.first().getOrThrow().let { root ->
@@ -130,7 +130,7 @@
val text = assertIs<EmittableText>(root.children.single())
assertThat(text.text).isEqualTo("Hello Earth")
}
- sessionManager.closeSession()
+ sessionManager.scope.closeSession()
}
@Test
@@ -141,14 +141,14 @@
}
val state = mutableStateOf("Hello World")
- val uiFlow = sessionManager.startSession(context) {
+ val uiFlow = sessionManager.scope.startSession(context) {
Text(state.value)
}
uiFlow.first().getOrThrow().let { root ->
val text = assertIs<EmittableText>(root.children.single())
assertThat(text.text).isEqualTo("Hello World")
}
- val session = assertIs<TestSession>(sessionManager.getSession(SESSION_KEY))
+ val session = assertIs<TestSession>(sessionManager.scope.getSession(SESSION_KEY))
session.sendEvent {
state.value = "Hello Earth"
}
@@ -156,7 +156,7 @@
val text = assertIs<EmittableText>(root.children.single())
assertThat(text.text).isEqualTo("Hello Earth")
}
- sessionManager.closeSession()
+ sessionManager.scope.closeSession()
}
@Test
@@ -167,7 +167,7 @@
}
val state = mutableStateOf("Hello World")
- val uiFlow = sessionManager.startDelayedProcessingSession(context) {
+ val uiFlow = sessionManager.scope.startDelayedProcessingSession(context) {
Text(state.value)
}
uiFlow.first().getOrThrow().let { root ->
@@ -183,9 +183,9 @@
assertThat(text.text).isEqualTo("Hello Earth")
}
- val session = assertIs<TestSession>(sessionManager.getSession(SESSION_KEY))
+ val session = assertIs<TestSession>(sessionManager.scope.getSession(SESSION_KEY))
assertThat(session.processEmittableTreeCancelCount).isEqualTo(1)
- sessionManager.closeSession()
+ sessionManager.scope.closeSession()
}
@Test
@@ -197,7 +197,7 @@
val cause = Throwable()
val exception = Exception("message", cause)
- val result = sessionManager.startSession(context) {
+ val result = sessionManager.scope.startSession(context) {
throw exception
}.first().exceptionOrNull()
assertThat(result).hasCauseThat().isEqualTo(cause)
@@ -214,7 +214,7 @@
val runError = mutableStateOf(false)
val cause = Throwable()
val exception = Exception("message", cause)
- val resultFlow = sessionManager.startSession(context) {
+ val resultFlow = sessionManager.scope.startSession(context) {
if (runError.value) {
throw exception
} else {
@@ -245,7 +245,7 @@
val cause = Throwable()
val exception = Exception("message", cause)
- val result = sessionManager.startSession(context) {
+ val result = sessionManager.scope.startSession(context) {
SideEffect { throw exception }
}.first().exceptionOrNull()
assertThat(result).hasCauseThat().isEqualTo(cause)
@@ -261,7 +261,7 @@
val cause = Throwable()
val exception = Exception("message", cause)
- val result = sessionManager.startSession(context) {
+ val result = sessionManager.scope.startSession(context) {
LaunchedEffect(true) { throw exception }
}.first().exceptionOrNull()
assertThat(result).hasCauseThat().isEqualTo(cause)
@@ -282,7 +282,7 @@
}
}
- sessionManager.startSession(context).first()
+ sessionManager.scope.startSession(context).first()
workerJob.cancel()
}
@@ -294,54 +294,60 @@
assertThat(worker.effectJob?.isCancelled).isTrue()
}
- sessionManager.startSession(context).first()
- sessionManager.closeSession()
+ sessionManager.scope.startSession(context).first()
+ sessionManager.scope.closeSession()
}
}
private const val SESSION_KEY = "123"
class TestSessionManager : SessionManager {
- private val sessions = mutableMapOf<String, Session>()
+ val scope = TestSessionManagerScope()
+ // No locking needed, tests are run on single threaded environment and is only user of this
+ // SessionManager.
+ override suspend fun <T> runWithLock(block: suspend SessionManagerScope.() -> T): T =
+ scope.block()
- suspend fun startSession(
- context: Context,
- content: @GlanceComposable @Composable () -> Unit = {}
- ) = MutableSharedFlow<kotlin.Result<EmittableWithChildren>>().also { flow ->
- startSession(context, TestSession(resultFlow = flow, content = content))
- }
+ class TestSessionManagerScope : SessionManagerScope {
+ private val sessions = mutableMapOf<String, Session>()
+ suspend fun startSession(
+ context: Context,
+ content: @GlanceComposable @Composable () -> Unit = {}
+ ) = MutableSharedFlow<kotlin.Result<EmittableWithChildren>>().also { flow ->
+ startSession(context, TestSession(resultFlow = flow, content = content))
+ }
- suspend fun startDelayedProcessingSession(
- context: Context,
- content: @GlanceComposable @Composable () -> Unit = {}
- ) = MutableSharedFlow<kotlin.Result<EmittableWithChildren>>().also { flow ->
- startSession(
- context,
- TestSession(
- resultFlow = flow,
- content = content,
- processEmittableTreeHasInfiniteDelay = true,
+ suspend fun startDelayedProcessingSession(
+ context: Context,
+ content: @GlanceComposable @Composable () -> Unit = {}
+ ) = MutableSharedFlow<kotlin.Result<EmittableWithChildren>>().also { flow ->
+ startSession(
+ context,
+ TestSession(
+ resultFlow = flow,
+ content = content,
+ processEmittableTreeHasInfiniteDelay = true,
+ )
)
- )
- }
+ }
- suspend fun closeSession() {
- closeSession(SESSION_KEY)
- }
+ suspend fun closeSession() {
+ closeSession(SESSION_KEY)
+ }
- override suspend fun startSession(context: Context, session: Session) {
- sessions[session.key] = session
- }
+ override suspend fun startSession(context: Context, session: Session) {
+ sessions[session.key] = session
+ }
- override suspend fun closeSession(key: String) {
- sessions[key]?.close()
- }
+ override suspend fun closeSession(key: String) {
+ sessions[key]?.close()
+ }
- override suspend fun isSessionRunning(context: Context, key: String): Boolean {
- TODO("Not yet implemented")
+ override suspend fun isSessionRunning(context: Context, key: String): Boolean {
+ TODO("Not yet implemented")
+ }
+ override fun getSession(key: String): Session? = sessions[key]
}
-
- override fun getSession(key: String): Session? = sessions[key]
}
class TestSession(
diff --git a/gradle.properties b/gradle.properties
index 86c8736..470ef1a3 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -27,8 +27,6 @@
android.enableAdditionalTestOutput=true
android.useAndroidX=true
android.nonTransitiveRClass=true
-# Pending cleanup to support non-constant R class IDs b/260409846
-android.nonFinalResIds=false
android.experimental.lint.missingBaselineIsEmptyBaseline=true
android.experimental.lint.reservedMemoryPerTask=1g
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index d7c926c..ef9344a 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -39,10 +39,10 @@
jcodec = "0.2.5"
kotlin17 = "1.7.10"
kotlin18 = "1.8.22"
-kotlin19 = "1.9.20"
-kotlin = "1.9.20"
+kotlin19 = "1.9.21"
+kotlin = "1.9.21"
kotlinBenchmark = "0.4.8"
-kotlinNative = "1.9.20"
+kotlinNative = "1.9.21"
kotlinCompileTesting = "1.4.9"
kotlinCoroutines = "1.7.3"
kotlinSerialization = "1.3.3"
@@ -106,7 +106,7 @@
checkerframework = { module = "org.checkerframework:checker-qual", version = "2.5.3" }
checkmark = { module = "net.saff.checkmark:checkmark", version = "0.1.6" }
constraintLayout = { module = "androidx.constraintlayout:constraintlayout", version = "2.0.1"}
-dackka = { module = "com.google.devsite:dackka", version = "1.4.0" }
+dackka = { module = "com.google.devsite:dackka", version = "1.4.1" }
dagger = { module = "com.google.dagger:dagger", version.ref = "dagger" }
daggerCompiler = { module = "com.google.dagger:dagger-compiler", version.ref = "dagger" }
desugarJdkLibs = { module = "com.android.tools:desugar_jdk_libs", version = "2.0.3" }
diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index e0c828e..e5f9139 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -1,9 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- To regenerate this file, run development/update-verification-metadata.sh -->
-<verification-metadata xmlns="https://schema.gradle.org/dependency-verification" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://schema.gradle.org/dependency-verification https://schema.gradle.org/dependency-verification/dependency-verification-1.2.xsd">
+<verification-metadata xmlns="https://schema.gradle.org/dependency-verification" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://schema.gradle.org/dependency-verification https://schema.gradle.org/dependency-verification/dependency-verification-1.3.xsd">
<configuration>
<verify-metadata>true</verify-metadata>
<verify-signatures>true</verify-signatures>
+ <keyring-format>armored</keyring-format>
<key-servers enabled="false">
<key-server uri="https://keyserver.ubuntu.com"/>
<key-server uri="https://keys.openpgp.org"/>
@@ -477,19 +478,19 @@
</trusted-keys>
</configuration>
<components>
- <component group="" name="kotlin-native-prebuilt-linux-x86_64" version="1.9.20">
- <artifact name="kotlin-native-prebuilt-linux-x86_64-1.9.20.tar.gz">
- <sha256 value="21899334495a5340c5504b1f7698db425b94ffeb633d809668c308e1f15bf585" origin="Hand-built using sha256sum kotlin-native-prebuilt-linux-x86_64-1.9.20.tar.gz" reason="Artifact is not signed"/>
+ <component group="" name="kotlin-native-prebuilt-linux-x86_64" version="1.9.21">
+ <artifact name="kotlin-native-prebuilt-linux-x86_64-1.9.21.tar.gz">
+ <sha256 value="8fbabb93092de6047345f1a9134e41e778828d51e70a44a7a50044b8471ce900" origin="Hand-built using sha256sum kotlin-native-prebuilt-linux-x86_64-1.9.21.tar.gz" reason="Artifact is not signed"/>
</artifact>
</component>
- <component group="" name="kotlin-native-prebuilt-macos-aarch64" version="1.9.20">
- <artifact name="kotlin-native-prebuilt-macos-aarch64-1.9.20.tar.gz">
- <sha256 value="1c6a149c98d7c2f557b638465b415152d30b80746a3582235b1cd0484d320da8" origin="Hand-built using sha256sum kotlin-native-prebuilt-macos-aarch64-1.9.20.tar.gz"/>
+ <component group="" name="kotlin-native-prebuilt-macos-aarch64" version="1.9.21">
+ <artifact name="kotlin-native-prebuilt-macos-aarch64-1.9.21.tar.gz">
+ <sha256 value="8a05fb4645f5252143e6262e9207f60902ab4641ae08bc7cb40f93b47771358f" origin="Hand-built using sha256sum kotlin-native-prebuilt-macos-aarch64-1.9.21.tar.gz"/>
</artifact>
</component>
- <component group="" name="kotlin-native-prebuilt-macos-x86_64" version="1.9.20">
- <artifact name="kotlin-native-prebuilt-macos-x86_64-1.9.20.tar.gz">
- <sha256 value="3e39493d86f8175a34698a5c884e127dde04390629942f3c52eeca5bdc1ccf56" origin="Hand-built using sha256sum kotlin-native-prebuilt-macos-x86_64-1.9.20.tar.gz"/>
+ <component group="" name="kotlin-native-prebuilt-macos-x86_64" version="1.9.21">
+ <artifact name="kotlin-native-prebuilt-macos-x86_64-1.9.21.tar.gz">
+ <sha256 value="11c8e5764f05541d23c09db75d1f975930cfe38962bb264ad0719e45fb0e6f9c" origin="Hand-built using sha256sum kotlin-native-prebuilt-macos-x86_64-1.9.21.tar.gz"/>
</artifact>
</component>
<component group="aopalliance" name="aopalliance" version="1.0">
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 48a5558..570dfce 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=../../../../tools/external/gradle/gradle-8.4-bin.zip
-distributionSha256Sum=3e1af3ae886920c3ac87f7a91f816c0c7c436f276a6eefdb3da152100fef72ae
+distributionUrl=../../../../tools/external/gradle/gradle-8.5-bin.zip
+distributionSha256Sum=9d926787066a081739e8200858338b4a69e837c3a821a33aca9db09dd4a41026
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 45c5536..11901b7e 100755
--- a/gradlew
+++ b/gradlew
@@ -43,12 +43,6 @@
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-if [[ " ${@} " =~ " -PupdateLintBaseline " ]]; then
- # remove when b/188666845 is complete
- # Inform lint to not fail even when creating a baseline file
- JAVA_OPTS="$JAVA_OPTS -Dlint.baselines.continue=true"
-fi
-
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
diff --git a/graphics/graphics-core/api/1.0.0-beta01.txt b/graphics/graphics-core/api/1.0.0-beta01.txt
index e1b45be..bcf0955 100644
--- a/graphics/graphics-core/api/1.0.0-beta01.txt
+++ b/graphics/graphics-core/api/1.0.0-beta01.txt
@@ -13,6 +13,7 @@
method public void setLightSourceAlpha(float ambientShadowAlpha, float spotShadowAlpha);
method public void setLightSourceGeometry(float lightX, float lightY, float lightZ, float lightRadius);
property public final int bufferFormat;
+ property public final boolean isClosed;
property public final int maxBuffers;
property public final long usageFlags;
}
@@ -26,7 +27,8 @@
}
public final class CanvasBufferedRenderer.RenderRequest {
- method public void draw(java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.graphics.CanvasBufferedRenderer.RenderResult> callback);
+ method public suspend Object? draw(optional boolean waitForFence, kotlin.coroutines.Continuation<? super androidx.graphics.CanvasBufferedRenderer.RenderResult>);
+ method public void drawAsync(java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.graphics.CanvasBufferedRenderer.RenderResult> callback);
method public androidx.graphics.CanvasBufferedRenderer.RenderRequest preserveContents(boolean preserve);
method public androidx.graphics.CanvasBufferedRenderer.RenderRequest setBufferTransform(int bufferTransform);
method public androidx.graphics.CanvasBufferedRenderer.RenderRequest setColorSpace(android.graphics.ColorSpace? colorSpace);
@@ -88,7 +90,7 @@
public final class FrontBufferSyncStrategy implements androidx.graphics.opengl.SyncStrategy {
ctor public FrontBufferSyncStrategy(long usageFlags);
- method @RequiresApi(android.os.Build.VERSION_CODES.KITKAT) public androidx.hardware.SyncFenceCompat? createSyncFence(androidx.graphics.opengl.egl.EGLSpec eglSpec);
+ method public androidx.hardware.SyncFenceCompat? createSyncFence(androidx.graphics.opengl.egl.EGLSpec eglSpec);
method public boolean isVisible();
method public void setVisible(boolean);
property public final boolean isVisible;
@@ -243,7 +245,7 @@
}
public interface SyncStrategy {
- method @RequiresApi(android.os.Build.VERSION_CODES.KITKAT) public androidx.hardware.SyncFenceCompat? createSyncFence(androidx.graphics.opengl.egl.EGLSpec eglSpec);
+ method public androidx.hardware.SyncFenceCompat? createSyncFence(androidx.graphics.opengl.egl.EGLSpec eglSpec);
field public static final androidx.graphics.opengl.SyncStrategy ALWAYS;
field public static final androidx.graphics.opengl.SyncStrategy.Companion Companion;
}
@@ -463,7 +465,7 @@
public static final class DataSpace.Companion {
}
- @RequiresApi(android.os.Build.VERSION_CODES.KITKAT) public final class SyncFenceCompat implements java.lang.AutoCloseable {
+ public final class SyncFenceCompat implements java.lang.AutoCloseable {
method public boolean await(long timeoutNanos);
method public boolean awaitForever();
method public void close();
diff --git a/graphics/graphics-core/api/current.ignore b/graphics/graphics-core/api/current.ignore
new file mode 100644
index 0000000..af77f0d
--- /dev/null
+++ b/graphics/graphics-core/api/current.ignore
@@ -0,0 +1,11 @@
+// Baseline format: 1.0
+AddedMethod: androidx.graphics.CanvasBufferedRenderer.RenderRequest#draw(boolean, kotlin.coroutines.Continuation<? super androidx.graphics.CanvasBufferedRenderer.RenderResult>):
+ Added method androidx.graphics.CanvasBufferedRenderer.RenderRequest.draw(boolean,kotlin.coroutines.Continuation<? super androidx.graphics.CanvasBufferedRenderer.RenderResult>)
+AddedMethod: androidx.graphics.CanvasBufferedRenderer.RenderRequest#drawAsync(java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.graphics.CanvasBufferedRenderer.RenderResult>):
+ Added method androidx.graphics.CanvasBufferedRenderer.RenderRequest.drawAsync(java.util.concurrent.Executor,androidx.core.util.Consumer<androidx.graphics.CanvasBufferedRenderer.RenderResult>)
+
+
+RemovedMethod: androidx.graphics.CanvasBufferedRenderer.RenderRequest#draw(java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.graphics.CanvasBufferedRenderer.RenderResult>):
+ Removed method androidx.graphics.CanvasBufferedRenderer.RenderRequest.draw(java.util.concurrent.Executor,androidx.core.util.Consumer<androidx.graphics.CanvasBufferedRenderer.RenderResult>)
+RemovedMethod: androidx.graphics.CanvasBufferedRenderer.RenderRequest#drawSync(boolean):
+ Removed method androidx.graphics.CanvasBufferedRenderer.RenderRequest.drawSync(boolean)
diff --git a/graphics/graphics-core/api/current.txt b/graphics/graphics-core/api/current.txt
index e1b45be..bcf0955 100644
--- a/graphics/graphics-core/api/current.txt
+++ b/graphics/graphics-core/api/current.txt
@@ -13,6 +13,7 @@
method public void setLightSourceAlpha(float ambientShadowAlpha, float spotShadowAlpha);
method public void setLightSourceGeometry(float lightX, float lightY, float lightZ, float lightRadius);
property public final int bufferFormat;
+ property public final boolean isClosed;
property public final int maxBuffers;
property public final long usageFlags;
}
@@ -26,7 +27,8 @@
}
public final class CanvasBufferedRenderer.RenderRequest {
- method public void draw(java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.graphics.CanvasBufferedRenderer.RenderResult> callback);
+ method public suspend Object? draw(optional boolean waitForFence, kotlin.coroutines.Continuation<? super androidx.graphics.CanvasBufferedRenderer.RenderResult>);
+ method public void drawAsync(java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.graphics.CanvasBufferedRenderer.RenderResult> callback);
method public androidx.graphics.CanvasBufferedRenderer.RenderRequest preserveContents(boolean preserve);
method public androidx.graphics.CanvasBufferedRenderer.RenderRequest setBufferTransform(int bufferTransform);
method public androidx.graphics.CanvasBufferedRenderer.RenderRequest setColorSpace(android.graphics.ColorSpace? colorSpace);
@@ -88,7 +90,7 @@
public final class FrontBufferSyncStrategy implements androidx.graphics.opengl.SyncStrategy {
ctor public FrontBufferSyncStrategy(long usageFlags);
- method @RequiresApi(android.os.Build.VERSION_CODES.KITKAT) public androidx.hardware.SyncFenceCompat? createSyncFence(androidx.graphics.opengl.egl.EGLSpec eglSpec);
+ method public androidx.hardware.SyncFenceCompat? createSyncFence(androidx.graphics.opengl.egl.EGLSpec eglSpec);
method public boolean isVisible();
method public void setVisible(boolean);
property public final boolean isVisible;
@@ -243,7 +245,7 @@
}
public interface SyncStrategy {
- method @RequiresApi(android.os.Build.VERSION_CODES.KITKAT) public androidx.hardware.SyncFenceCompat? createSyncFence(androidx.graphics.opengl.egl.EGLSpec eglSpec);
+ method public androidx.hardware.SyncFenceCompat? createSyncFence(androidx.graphics.opengl.egl.EGLSpec eglSpec);
field public static final androidx.graphics.opengl.SyncStrategy ALWAYS;
field public static final androidx.graphics.opengl.SyncStrategy.Companion Companion;
}
@@ -463,7 +465,7 @@
public static final class DataSpace.Companion {
}
- @RequiresApi(android.os.Build.VERSION_CODES.KITKAT) public final class SyncFenceCompat implements java.lang.AutoCloseable {
+ public final class SyncFenceCompat implements java.lang.AutoCloseable {
method public boolean await(long timeoutNanos);
method public boolean awaitForever();
method public void close();
diff --git a/graphics/graphics-core/api/restricted_1.0.0-beta01.txt b/graphics/graphics-core/api/restricted_1.0.0-beta01.txt
index 74ac194..0c3a248 100644
--- a/graphics/graphics-core/api/restricted_1.0.0-beta01.txt
+++ b/graphics/graphics-core/api/restricted_1.0.0-beta01.txt
@@ -13,6 +13,7 @@
method public void setLightSourceAlpha(float ambientShadowAlpha, float spotShadowAlpha);
method public void setLightSourceGeometry(float lightX, float lightY, float lightZ, float lightRadius);
property public final int bufferFormat;
+ property public final boolean isClosed;
property public final int maxBuffers;
property public final long usageFlags;
}
@@ -26,7 +27,8 @@
}
public final class CanvasBufferedRenderer.RenderRequest {
- method public void draw(java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.graphics.CanvasBufferedRenderer.RenderResult> callback);
+ method public suspend Object? draw(optional boolean waitForFence, kotlin.coroutines.Continuation<? super androidx.graphics.CanvasBufferedRenderer.RenderResult>);
+ method public void drawAsync(java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.graphics.CanvasBufferedRenderer.RenderResult> callback);
method public androidx.graphics.CanvasBufferedRenderer.RenderRequest preserveContents(boolean preserve);
method public androidx.graphics.CanvasBufferedRenderer.RenderRequest setBufferTransform(int bufferTransform);
method public androidx.graphics.CanvasBufferedRenderer.RenderRequest setColorSpace(android.graphics.ColorSpace? colorSpace);
@@ -88,7 +90,7 @@
public final class FrontBufferSyncStrategy implements androidx.graphics.opengl.SyncStrategy {
ctor public FrontBufferSyncStrategy(long usageFlags);
- method @RequiresApi(android.os.Build.VERSION_CODES.KITKAT) public androidx.hardware.SyncFenceCompat? createSyncFence(androidx.graphics.opengl.egl.EGLSpec eglSpec);
+ method public androidx.hardware.SyncFenceCompat? createSyncFence(androidx.graphics.opengl.egl.EGLSpec eglSpec);
method public boolean isVisible();
method public void setVisible(boolean);
property public final boolean isVisible;
@@ -243,7 +245,7 @@
}
public interface SyncStrategy {
- method @RequiresApi(android.os.Build.VERSION_CODES.KITKAT) public androidx.hardware.SyncFenceCompat? createSyncFence(androidx.graphics.opengl.egl.EGLSpec eglSpec);
+ method public androidx.hardware.SyncFenceCompat? createSyncFence(androidx.graphics.opengl.egl.EGLSpec eglSpec);
field public static final androidx.graphics.opengl.SyncStrategy ALWAYS;
field public static final androidx.graphics.opengl.SyncStrategy.Companion Companion;
}
@@ -464,7 +466,7 @@
public static final class DataSpace.Companion {
}
- @RequiresApi(android.os.Build.VERSION_CODES.KITKAT) public final class SyncFenceCompat implements java.lang.AutoCloseable {
+ public final class SyncFenceCompat implements java.lang.AutoCloseable {
method public boolean await(long timeoutNanos);
method public boolean awaitForever();
method public void close();
diff --git a/graphics/graphics-core/api/restricted_current.ignore b/graphics/graphics-core/api/restricted_current.ignore
new file mode 100644
index 0000000..af77f0d
--- /dev/null
+++ b/graphics/graphics-core/api/restricted_current.ignore
@@ -0,0 +1,11 @@
+// Baseline format: 1.0
+AddedMethod: androidx.graphics.CanvasBufferedRenderer.RenderRequest#draw(boolean, kotlin.coroutines.Continuation<? super androidx.graphics.CanvasBufferedRenderer.RenderResult>):
+ Added method androidx.graphics.CanvasBufferedRenderer.RenderRequest.draw(boolean,kotlin.coroutines.Continuation<? super androidx.graphics.CanvasBufferedRenderer.RenderResult>)
+AddedMethod: androidx.graphics.CanvasBufferedRenderer.RenderRequest#drawAsync(java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.graphics.CanvasBufferedRenderer.RenderResult>):
+ Added method androidx.graphics.CanvasBufferedRenderer.RenderRequest.drawAsync(java.util.concurrent.Executor,androidx.core.util.Consumer<androidx.graphics.CanvasBufferedRenderer.RenderResult>)
+
+
+RemovedMethod: androidx.graphics.CanvasBufferedRenderer.RenderRequest#draw(java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.graphics.CanvasBufferedRenderer.RenderResult>):
+ Removed method androidx.graphics.CanvasBufferedRenderer.RenderRequest.draw(java.util.concurrent.Executor,androidx.core.util.Consumer<androidx.graphics.CanvasBufferedRenderer.RenderResult>)
+RemovedMethod: androidx.graphics.CanvasBufferedRenderer.RenderRequest#drawSync(boolean):
+ Removed method androidx.graphics.CanvasBufferedRenderer.RenderRequest.drawSync(boolean)
diff --git a/graphics/graphics-core/api/restricted_current.txt b/graphics/graphics-core/api/restricted_current.txt
index 74ac194..0c3a248 100644
--- a/graphics/graphics-core/api/restricted_current.txt
+++ b/graphics/graphics-core/api/restricted_current.txt
@@ -13,6 +13,7 @@
method public void setLightSourceAlpha(float ambientShadowAlpha, float spotShadowAlpha);
method public void setLightSourceGeometry(float lightX, float lightY, float lightZ, float lightRadius);
property public final int bufferFormat;
+ property public final boolean isClosed;
property public final int maxBuffers;
property public final long usageFlags;
}
@@ -26,7 +27,8 @@
}
public final class CanvasBufferedRenderer.RenderRequest {
- method public void draw(java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.graphics.CanvasBufferedRenderer.RenderResult> callback);
+ method public suspend Object? draw(optional boolean waitForFence, kotlin.coroutines.Continuation<? super androidx.graphics.CanvasBufferedRenderer.RenderResult>);
+ method public void drawAsync(java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.graphics.CanvasBufferedRenderer.RenderResult> callback);
method public androidx.graphics.CanvasBufferedRenderer.RenderRequest preserveContents(boolean preserve);
method public androidx.graphics.CanvasBufferedRenderer.RenderRequest setBufferTransform(int bufferTransform);
method public androidx.graphics.CanvasBufferedRenderer.RenderRequest setColorSpace(android.graphics.ColorSpace? colorSpace);
@@ -88,7 +90,7 @@
public final class FrontBufferSyncStrategy implements androidx.graphics.opengl.SyncStrategy {
ctor public FrontBufferSyncStrategy(long usageFlags);
- method @RequiresApi(android.os.Build.VERSION_CODES.KITKAT) public androidx.hardware.SyncFenceCompat? createSyncFence(androidx.graphics.opengl.egl.EGLSpec eglSpec);
+ method public androidx.hardware.SyncFenceCompat? createSyncFence(androidx.graphics.opengl.egl.EGLSpec eglSpec);
method public boolean isVisible();
method public void setVisible(boolean);
property public final boolean isVisible;
@@ -243,7 +245,7 @@
}
public interface SyncStrategy {
- method @RequiresApi(android.os.Build.VERSION_CODES.KITKAT) public androidx.hardware.SyncFenceCompat? createSyncFence(androidx.graphics.opengl.egl.EGLSpec eglSpec);
+ method public androidx.hardware.SyncFenceCompat? createSyncFence(androidx.graphics.opengl.egl.EGLSpec eglSpec);
field public static final androidx.graphics.opengl.SyncStrategy ALWAYS;
field public static final androidx.graphics.opengl.SyncStrategy.Companion Companion;
}
@@ -464,7 +466,7 @@
public static final class DataSpace.Companion {
}
- @RequiresApi(android.os.Build.VERSION_CODES.KITKAT) public final class SyncFenceCompat implements java.lang.AutoCloseable {
+ public final class SyncFenceCompat implements java.lang.AutoCloseable {
method public boolean await(long timeoutNanos);
method public boolean awaitForever();
method public void close();
diff --git a/graphics/graphics-core/build.gradle b/graphics/graphics-core/build.gradle
index f5a4f87..9dfe084 100644
--- a/graphics/graphics-core/build.gradle
+++ b/graphics/graphics-core/build.gradle
@@ -25,6 +25,7 @@
dependencies {
api(libs.kotlinStdlib)
+ implementation(libs.kotlinCoroutinesAndroid)
implementation("androidx.annotation:annotation-experimental:1.1.0-rc01")
implementation("androidx.core:core:1.8.0")
androidTestImplementation(libs.testExtJunit)
diff --git a/graphics/graphics-core/src/androidTest/java/androidx/graphics/CanvasBufferedRendererTests.kt b/graphics/graphics-core/src/androidTest/java/androidx/graphics/CanvasBufferedRendererTests.kt
index c606168..9420dab 100644
--- a/graphics/graphics-core/src/androidTest/java/androidx/graphics/CanvasBufferedRendererTests.kt
+++ b/graphics/graphics-core/src/androidTest/java/androidx/graphics/CanvasBufferedRendererTests.kt
@@ -53,6 +53,7 @@
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import kotlin.math.abs
+import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull
@@ -72,16 +73,16 @@
fun testRenderAfterCloseReturnsError() = hardwareBufferRendererTest { renderer ->
renderer.close()
assertThrows(IllegalStateException::class.java) {
- renderer.obtainRenderRequest().draw(mExecutor) { _ -> /* NO-OP */ }
+ renderer.obtainRenderRequest().drawAsync(mExecutor) { _ -> /* NO-OP */ }
}
}
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
@Test
fun testIsClosed() = hardwareBufferRendererTest { renderer ->
- assertFalse(renderer.isClosed())
+ assertFalse(renderer.isClosed)
renderer.close()
- assertTrue(renderer.isClosed())
+ assertTrue(renderer.isClosed)
}
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
@@ -106,7 +107,7 @@
var bitmap: Bitmap? = null
renderer.obtainRenderRequest()
.preserveContents(true)
- .draw(mExecutor) { result ->
+ .drawAsync(mExecutor) { result ->
assertEquals(SUCCESS, result.status)
result.fence?.awaitForever()
bitmap = Bitmap.wrapHardwareBuffer(result.hardwareBuffer, null)
@@ -122,7 +123,7 @@
latch = CountDownLatch(1)
renderer.obtainRenderRequest()
.preserveContents(false)
- .draw(mExecutor) { result ->
+ .drawAsync(mExecutor) { result ->
assertEquals(SUCCESS, result.status)
result.fence?.awaitForever()
bitmap = Bitmap.wrapHardwareBuffer(result.hardwareBuffer, null)
@@ -138,12 +139,16 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
@Test
fun testPreservationEnabledPreservesContents() =
- verifyPreservedBuffer(CanvasBufferedRenderer.DEFAULT_IMPL)
+ repeat(20) {
+ verifyPreservedBuffer(CanvasBufferedRenderer.DEFAULT_IMPL)
+ }
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
@Test
fun testPreservationEnabledPreservesContentsWithRedrawStrategy() =
- verifyPreservedBuffer(CanvasBufferedRenderer.USE_V29_IMPL_WITH_REDRAW)
+ repeat(20) {
+ verifyPreservedBuffer(CanvasBufferedRenderer.USE_V29_IMPL_WITH_REDRAW)
+ }
@RequiresApi(Build.VERSION_CODES.Q)
private fun verifyPreservedBuffer(
@@ -208,7 +213,7 @@
var bitmap: Bitmap? = null
renderer.obtainRenderRequest()
.preserveContents(true)
- .draw(executor) { result ->
+ .drawAsync(executor) { result ->
assertEquals(SUCCESS, result.status)
result.fence?.awaitForever()
bitmap = Bitmap.wrapHardwareBuffer(result.hardwareBuffer, null)
@@ -224,7 +229,7 @@
val secondRenderLatch = CountDownLatch(1)
renderer.obtainRenderRequest()
.preserveContents(true)
- .draw(executor) { result ->
+ .drawAsync(executor) { result ->
assertEquals(SUCCESS, result.status)
result.fence?.awaitForever()
bitmap = Bitmap.wrapHardwareBuffer(result.hardwareBuffer, null)
@@ -250,11 +255,13 @@
val colorSpace = ColorSpace.get(ColorSpace.Named.SRGB)
val latch = CountDownLatch(1)
var hardwareBuffer: HardwareBuffer? = null
- renderer.obtainRenderRequest().setColorSpace(colorSpace).draw(mExecutor) { renderResult ->
- renderResult.fence?.awaitForever()
- hardwareBuffer = renderResult.hardwareBuffer
- latch.countDown()
- }
+ renderer.obtainRenderRequest()
+ .setColorSpace(colorSpace)
+ .drawAsync(mExecutor) { renderResult ->
+ renderResult.fence?.awaitForever()
+ hardwareBuffer = renderResult.hardwareBuffer
+ latch.countDown()
+ }
assertTrue(latch.await(3000, TimeUnit.MILLISECONDS))
@@ -268,6 +275,73 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
@Test
+ fun testDrawSync() = hardwareBufferRendererTest { renderer ->
+ val contentRoot = RenderNode("content").apply {
+ setPosition(0, 0, TEST_WIDTH, TEST_HEIGHT)
+ record { canvas -> canvas.drawColor(Color.BLUE) }
+ }
+ renderer.setContentRoot(contentRoot)
+
+ val colorSpace = ColorSpace.get(ColorSpace.Named.SRGB)
+
+ var renderResult: CanvasBufferedRenderer.RenderResult?
+ runBlocking {
+ renderResult = renderer.obtainRenderRequest().setColorSpace(colorSpace).draw()
+ }
+ assertNotNull(renderResult)
+ assertEquals(SUCCESS, renderResult!!.status)
+ val fence = renderResult?.fence
+ if (fence != null) {
+ // by default drawSync will automatically wait on the fence and close it leaving
+ // it in the invalid state
+ assertFalse(fence.isValid())
+ }
+
+ val hardwareBuffer = renderResult!!.hardwareBuffer
+
+ val bitmap = Bitmap.wrapHardwareBuffer(hardwareBuffer, colorSpace)!!
+ .copy(Bitmap.Config.ARGB_8888, false)
+
+ assertEquals(TEST_WIDTH, bitmap.width)
+ assertEquals(TEST_HEIGHT, bitmap.height)
+ assertEquals(0xFF0000FF.toInt(), bitmap.getPixel(0, 0))
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Test
+ fun testDrawSyncWithoutBlockingFence() = hardwareBufferRendererTest { renderer ->
+ val contentRoot = RenderNode("content").apply {
+ setPosition(0, 0, TEST_WIDTH, TEST_HEIGHT)
+ record { canvas -> canvas.drawColor(Color.BLUE) }
+ }
+ renderer.setContentRoot(contentRoot)
+
+ val colorSpace = ColorSpace.get(ColorSpace.Named.SRGB)
+
+ var renderResult: CanvasBufferedRenderer.RenderResult?
+ runBlocking {
+ renderResult = renderer.obtainRenderRequest().setColorSpace(colorSpace).draw(false)
+ }
+ assertNotNull(renderResult)
+ assertEquals(SUCCESS, renderResult!!.status)
+ val fence = renderResult?.fence
+ assertNotNull(fence)
+ assertTrue(fence!!.isValid())
+ fence.awaitForever()
+ fence.close()
+
+ val hardwareBuffer = renderResult!!.hardwareBuffer
+
+ val bitmap = Bitmap.wrapHardwareBuffer(hardwareBuffer, colorSpace)!!
+ .copy(Bitmap.Config.ARGB_8888, false)
+
+ assertEquals(TEST_WIDTH, bitmap.width)
+ assertEquals(TEST_HEIGHT, bitmap.height)
+ assertEquals(0xFF0000FF.toInt(), bitmap.getPixel(0, 0))
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
+ @Test
fun testContentsPreservedSRGB() = preservedContentsTest { bitmap ->
assertEquals(Color.RED, bitmap.getPixel(TEST_WIDTH / 2, TEST_HEIGHT / 4))
assertEquals(Color.BLUE, bitmap.getPixel(TEST_WIDTH / 2, TEST_HEIGHT / 2 + TEST_HEIGHT / 4))
@@ -342,7 +416,7 @@
renderer.obtainRenderRequest()
.setColorSpace(colorSpace)
.preserveContents(true)
- .draw(mExecutor) { renderResult ->
+ .drawAsync(mExecutor) { renderResult ->
renderResult.fence?.awaitForever()
hardwareBuffer = renderResult.hardwareBuffer
latch.countDown()
@@ -361,7 +435,7 @@
renderer.obtainRenderRequest()
.setColorSpace(colorSpace)
.preserveContents(true)
- .draw(mExecutor) { renderResult ->
+ .drawAsync(mExecutor) { renderResult ->
renderResult.fence?.awaitForever()
hardwareBuffer = renderResult.hardwareBuffer
latch2.countDown()
@@ -535,7 +609,7 @@
renderer.obtainRenderRequest()
.setColorSpace(colorSpace)
.setBufferTransform(42)
- .draw(mExecutor) { renderResult ->
+ .drawAsync(mExecutor) { renderResult ->
renderResult.fence?.awaitForever()
latch.countDown()
}
@@ -602,7 +676,7 @@
renderer.obtainRenderRequest()
.setColorSpace(colorSpace)
.setBufferTransform(transform)
- .draw(mExecutor) { renderResult ->
+ .drawAsync(mExecutor) { renderResult ->
renderStatus = renderResult.status
renderResult.fence?.awaitForever()
hardwareBuffer = renderResult.hardwareBuffer
@@ -704,7 +778,7 @@
val latch2 = CountDownLatch(1)
val latch3 = CountDownLatch(1)
var hardwareBuffer: HardwareBuffer? = null
- renderer.obtainRenderRequest().draw(executor) { result ->
+ renderer.obtainRenderRequest().drawAsync(executor) { result ->
result.fence?.awaitForever()
result.fence?.close()
hardwareBuffer = result.hardwareBuffer
@@ -717,7 +791,7 @@
canvas.drawColor(Color.BLUE)
renderNode.endRecording()
- renderer.obtainRenderRequest().draw(executor) { _ ->
+ renderer.obtainRenderRequest().drawAsync(executor) { _ ->
latch2.countDown()
}
@@ -727,7 +801,7 @@
canvas.drawColor(Color.GREEN)
renderNode.endRecording()
- renderer.obtainRenderRequest().draw(executor) { _ ->
+ renderer.obtainRenderRequest().drawAsync(executor) { _ ->
latch3.countDown()
}
@@ -845,7 +919,7 @@
renderNode.endRecording()
val latch = CountDownLatch(1)
- hbr.obtainRenderRequest().draw(executor) { result ->
+ hbr.obtainRenderRequest().drawAsync(executor) { result ->
hbr.releaseBuffer(result.hardwareBuffer, result.fence)
latch.countDown()
}
@@ -920,7 +994,7 @@
.setColorSpace(colorSpace)
.preserveContents(true)
.setBufferTransform(transform)
- .draw(executor) { renderResult ->
+ .drawAsync(executor) { renderResult ->
renderResult.fence?.awaitForever()
hardwareBuffer = renderResult.hardwareBuffer
latch.countDown()
diff --git a/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/GLRendererTest.kt b/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/GLRendererTest.kt
index 7e7d5ef..3637e56 100644
--- a/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/GLRendererTest.kt
+++ b/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/GLRendererTest.kt
@@ -103,7 +103,6 @@
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
fun testRender() {
val latch = CountDownLatch(1)
val renderer = object : GLRenderer.RenderCallback {
@@ -129,7 +128,7 @@
assertEquals(4, plane.pixelStride)
val targetColor = Color.argb(255, 255, 0, 255)
- Api19Helpers.verifyPlaneContent(width, height, plane, targetColor)
+ verifyPlaneContent(width, height, plane, targetColor)
target.detach(true)
@@ -137,7 +136,6 @@
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
fun testDetachExecutesPendingRequests() {
val latch = CountDownLatch(1)
val renderer = object : GLRenderer.RenderCallback {
@@ -164,13 +162,12 @@
assertEquals(4, plane.pixelStride)
val targetColor = Color.argb(255, 255, 0, 255)
- Api19Helpers.verifyPlaneContent(width, height, plane, targetColor)
+ verifyPlaneContent(width, height, plane, targetColor)
glRenderer.stop(true)
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
fun testStopExecutesPendingRequests() {
val latch = CountDownLatch(1)
val surfaceWidth = 5
@@ -200,11 +197,10 @@
assertEquals(4, plane.pixelStride)
val targetColor = Color.argb(255, 255, 0, 255)
- Api19Helpers.verifyPlaneContent(surfaceWidth, surfaceHeight, plane, targetColor)
+ verifyPlaneContent(surfaceWidth, surfaceHeight, plane, targetColor)
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
fun testDetachExecutesMultiplePendingRequests() {
val numRenders = 4
val latch = CountDownLatch(numRenders)
@@ -254,13 +250,12 @@
assertEquals(4, plane.pixelStride)
val targetColor = Color.argb(255, 0, 0, 255)
- Api19Helpers.verifyPlaneContent(width, height, plane, targetColor)
+ verifyPlaneContent(width, height, plane, targetColor)
glRenderer.stop(true)
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
fun testDetachCancelsPendingRequests() {
val latch = CountDownLatch(1)
val renderer = object : GLRenderer.RenderCallback {
@@ -286,7 +281,6 @@
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
fun testMultipleAttachedSurfaces() {
val latch = CountDownLatch(2)
val renderer1 = object : GLRenderer.RenderCallback {
@@ -329,8 +323,8 @@
val plane1 = reader1.acquireLatestImage().planes[0]
val plane2 = reader2.acquireLatestImage().planes[0]
- Api19Helpers.verifyPlaneContent(width1, height1, plane1, Color.argb(255, 255, 0, 0))
- Api19Helpers.verifyPlaneContent(width2, height2, plane2, Color.argb(255, 0, 0, 255))
+ verifyPlaneContent(width1, height1, plane1, Color.argb(255, 255, 0, 0))
+ verifyPlaneContent(width2, height2, plane2, Color.argb(255, 0, 0, 255))
target1.detach(true)
target2.detach(true)
@@ -351,25 +345,20 @@
* there are corresponding @SdkSuppress and @RequiresApi
* See https://b.corp.google.com/issues/221485597
*/
- class Api19Helpers private constructor() {
- companion object {
- @RequiresApi(Build.VERSION_CODES.KITKAT)
- fun verifyPlaneContent(width: Int, height: Int, plane: Image.Plane, targetColor: Int) {
- val rowPadding = plane.rowStride - plane.pixelStride * width
- var offset = 0
- for (y in 0 until height) {
- for (x in 0 until width) {
- val red = plane.buffer[offset].toInt() and 0xff
- val green = plane.buffer[offset + 1].toInt() and 0xff
- val blue = plane.buffer[offset + 2].toInt() and 0xff
- val alpha = plane.buffer[offset + 3].toInt() and 0xff
- val packedColor = Color.argb(alpha, red, green, blue)
- assertEquals("Index: $x, $y", targetColor, packedColor)
- offset += plane.pixelStride
- }
- offset += rowPadding
- }
+ private fun verifyPlaneContent(width: Int, height: Int, plane: Image.Plane, targetColor: Int) {
+ val rowPadding = plane.rowStride - plane.pixelStride * width
+ var offset = 0
+ for (y in 0 until height) {
+ for (x in 0 until width) {
+ val red = plane.buffer[offset].toInt() and 0xff
+ val green = plane.buffer[offset + 1].toInt() and 0xff
+ val blue = plane.buffer[offset + 2].toInt() and 0xff
+ val alpha = plane.buffer[offset + 3].toInt() and 0xff
+ val packedColor = Color.argb(alpha, red, green, blue)
+ assertEquals("Index: $x, $y", targetColor, packedColor)
+ offset += plane.pixelStride
}
+ offset += rowPadding
}
}
diff --git a/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/egl/EGLManagerTest.kt b/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/egl/EGLManagerTest.kt
index b0ec6e1..0fd265f 100644
--- a/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/egl/EGLManagerTest.kt
+++ b/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/egl/EGLManagerTest.kt
@@ -27,7 +27,6 @@
import android.opengl.GLES20
import android.os.Build
import android.view.Surface
-import androidx.annotation.RequiresApi
import androidx.hardware.SyncFenceCompat
import androidx.opengl.EGLBindings
import androidx.opengl.EGLExt
@@ -290,19 +289,16 @@
}
}
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
@Test
fun testSurfaceContentsWithBackBuffer() {
verifySurfaceContentsWithWindowConfig()
}
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
@Test
fun testSurfaceContentsWithFrontBuffer() {
verifySurfaceContentsWithWindowConfig(true)
}
- @RequiresApi(api = Build.VERSION_CODES.KITKAT)
private fun verifySurfaceContentsWithWindowConfig(
singleBuffered: Boolean = false
) {
@@ -499,7 +495,6 @@
}
}
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
@Test
fun testEGLDupNativeFenceFDMethodLinked() {
verifyMethodLinked {
@@ -688,7 +683,6 @@
}
}
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
@Test
fun testEglDupNativeFenceFDANDROID() {
testEGLManager {
diff --git a/graphics/graphics-core/src/androidTest/java/androidx/hardware/SyncFenceV19Test.kt b/graphics/graphics-core/src/androidTest/java/androidx/hardware/SyncFenceV19Test.kt
index 7a0a842..889086f 100644
--- a/graphics/graphics-core/src/androidTest/java/androidx/hardware/SyncFenceV19Test.kt
+++ b/graphics/graphics-core/src/androidTest/java/androidx/hardware/SyncFenceV19Test.kt
@@ -29,7 +29,6 @@
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
@SmallTest
class SyncFenceV19Test {
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/CanvasBufferedRenderer.kt b/graphics/graphics-core/src/main/java/androidx/graphics/CanvasBufferedRenderer.kt
index 742e437..7b58718 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/CanvasBufferedRenderer.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/CanvasBufferedRenderer.kt
@@ -31,13 +31,14 @@
import androidx.hardware.HardwareBufferFormat
import androidx.hardware.HardwareBufferUsage
import androidx.hardware.SyncFenceCompat
-import java.lang.IllegalStateException
import java.util.concurrent.Executor
+import kotlin.coroutines.resume
+import kotlinx.coroutines.suspendCancellableCoroutine
/**
* Creates an instance of a hardware-accelerated renderer. This is used to render a scene built
* from [RenderNode]s to an output [HardwareBuffer]. There can be as many
- * HardwareBufferRenderer instances as desired.
+ * [CanvasBufferedRenderer] instances as desired.
*
* Resources & lifecycle
*
@@ -125,7 +126,8 @@
* Returns if the [CanvasBufferedRenderer] has already been closed. That is
* [CanvasBufferedRenderer.close] has been invoked.
*/
- fun isClosed(): Boolean = mImpl.isClosed()
+ val isClosed: Boolean
+ get() = mImpl.isClosed()
/**
* Returns a [RenderRequest] that can be used to render into the provided HardwareBuffer.
@@ -140,7 +142,7 @@
* Sets the content root to render. It is not necessary to call this whenever the content
* recording changes. Any mutations to the [RenderNode] content, or any of the [RenderNode]s
* contained within the content node, will be applied whenever a new [RenderRequest] is issued
- * via [obtainRenderRequest] and [RenderRequest.draw].
+ * via [obtainRenderRequest] and [RenderRequest.drawAsync].
*/
fun setContentRoot(renderNode: RenderNode) {
mImpl.setContentRoot(renderNode)
@@ -217,8 +219,8 @@
* [CanvasBufferedRenderer].
* If 1 is specified, then the created [CanvasBufferedRenderer] is running in
* "single buffer mode". In this case consumption of the buffer content would need to be
- * coordinated with the [SyncFenceCompat] returned by the callback of [RenderRequest.draw].
- * @see CanvasBufferedRenderer.RenderRequest.draw
+ * coordinated with the [SyncFenceCompat] returned by the callback of [RenderRequest.drawAsync].
+ * @see CanvasBufferedRenderer.RenderRequest.drawAsync
*
* @param numBuffers The number of buffers within the swap chain to be consumed by the
* created [CanvasBufferedRenderer]. This must be greater than zero. The default
@@ -312,14 +314,42 @@
* @throws IllegalStateException if this method is invoked after the
* [CanvasBufferedRenderer] has been closed.
*/
- fun draw(executor: Executor, callback: Consumer<RenderResult>) {
- if (isClosed()) {
+ fun drawAsync(executor: Executor, callback: Consumer<RenderResult>) {
+ if (isClosed) {
throw IllegalStateException("Attempt to draw after renderer has been closed")
}
mImpl.draw(this, executor, callback)
}
/**
+ * Syncs the [RenderNode] tree to the render thread and requests content to be drawn
+ * synchronously.
+ * This [RenderRequest] instance should no longer be used after calling this method.
+ * The system internally may reuse instances of [RenderRequest] to reduce allocation churn.
+ *
+ * @param waitForFence Optional flag to determine if the [SyncFenceCompat] is also waited
+ * upon before returning as a convenience in order to enable callers to consume the
+ * [HardwareBuffer] returned in the [RenderResult] immediately after this method returns.
+ * Passing `false` here on Android T and below is a no-op as the graphics rendering pipeline
+ * internally blocks on the fence before returning.
+ */
+ suspend fun draw(waitForFence: Boolean = true): RenderResult {
+ check(!isClosed) { "Attempt to draw after renderer has been closed" }
+
+ return suspendCancellableCoroutine { continuation ->
+ drawAsync(Runnable::run) { result ->
+ if (waitForFence) {
+ result.fence?.apply {
+ awaitForever()
+ close()
+ }
+ }
+ continuation.resume(result)
+ }
+ }
+ }
+
+ /**
* Specifies a transform to be applied before content is rendered. This is useful
* for pre-rotating content for the current display orientation to increase performance
* of displaying the associated buffer. This transformation will also adjust the light
@@ -367,11 +397,19 @@
/**
* Determines whether or not previous buffer contents will be persisted across render
* requests. If false then contents are cleared before issuing drawing instructions,
- * otherwise contents will remain. If contents are known in advance to be completely opaque
- * and cover all pixels within the buffer, setting this flag to false will slightly improve
- * performance as the clear operation will be skipped. Additionally for single buffered
- * rendering scenarios, persisting contents can be beneficial in order to draw the deltas of
- * content across frames. The default setting is false
+ * otherwise contents will remain.
+ *
+ * If contents are known in advance to be completely opaque and cover all pixels within the
+ * buffer, setting this flag to true will slightly improve performance as the clear
+ * operation will be skipped.
+ *
+ * For low latency use cases (ex applications that support drawing with a stylus), setting
+ * this value to true alongside single buffered rendering by configuring
+ * [CanvasBufferedRenderer.Builder.setMaxBuffers] to 1 allows for reduced latency by allowing
+ * consumers to only render the deltas across frames as the previous content would be
+ * persisted.
+ *
+ * The default setting is false.
*/
fun preserveContents(preserve: Boolean): RenderRequest {
mPreserveContents = preserve
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/CanvasBufferedRendererV29.kt b/graphics/graphics-core/src/main/java/androidx/graphics/CanvasBufferedRendererV29.kt
index acb359c..a9ae731 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/CanvasBufferedRendererV29.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/CanvasBufferedRendererV29.kt
@@ -155,7 +155,7 @@
CanvasBufferedRenderer.RenderResult(
buffer,
fence,
- if (result != 0) ERROR_UNKNOWN else SUCCESS
+ if (isSuccess(result)) SUCCESS else ERROR_UNKNOWN
)
)
if (mMaxBuffers == 1) {
@@ -171,6 +171,14 @@
}
}
+ /**
+ * Helper method to determine if [HardwareRenderer.FrameRenderRequest.syncAndDraw] was
+ * successful. In this case we wait for the next buffer even if we miss the vsync.
+ */
+ private fun isSuccess(result: Int) =
+ result == HardwareRenderer.SYNC_OK ||
+ result == HardwareRenderer.SYNC_FRAME_DROPPED
+
private fun updateTransform(transform: Int): Matrix {
mBufferTransform = transform
return BufferTransformHintResolver.configureTransformMatrix(
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/CanvasFrontBufferedRenderer.kt b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/CanvasFrontBufferedRenderer.kt
index 3464fd6..062ef16 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/CanvasFrontBufferedRenderer.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/CanvasFrontBufferedRenderer.kt
@@ -470,7 +470,7 @@
}
}
.setColorSpace(targetColorSpace)
- .draw(mHandlerThread) { result ->
+ .drawAsync(mHandlerThread) { result ->
setParentSurfaceControlBuffer(
frontBufferSurfaceControl,
parentSurfaceControl,
@@ -543,7 +543,7 @@
}
}
.setColorSpace(targetColorSpace)
- .draw(mHandlerThread) { result ->
+ .drawAsync(mHandlerThread) { result ->
setParentSurfaceControlBuffer(
frontBufferSurfaceControl,
parentSurfaceControl,
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/FrontBufferSyncStrategy.kt b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/FrontBufferSyncStrategy.kt
index b500c89..5915cdc 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/FrontBufferSyncStrategy.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/FrontBufferSyncStrategy.kt
@@ -18,8 +18,6 @@
import android.hardware.HardwareBuffer
import android.opengl.GLES20
-import android.os.Build
-import androidx.annotation.RequiresApi
import androidx.graphics.opengl.FrameBufferRenderer
import androidx.graphics.opengl.SyncStrategy
import androidx.graphics.opengl.egl.EGLSpec
@@ -65,7 +63,6 @@
* If front buffer usage is not supported, then a fence is created and destroyed to flush
* contents to screen.
*/
- @RequiresApi(Build.VERSION_CODES.KITKAT)
override fun createSyncFence(eglSpec: EGLSpec): SyncFenceCompat? {
return if (!isVisible) {
SyncFenceCompat.createNativeSyncFence()
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/PreservedBufferContentsVerifier.kt b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/PreservedBufferContentsVerifier.kt
index 2fe214f..3f15b61 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/PreservedBufferContentsVerifier.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/PreservedBufferContentsVerifier.kt
@@ -85,7 +85,7 @@
val firstRenderLatch = CountDownLatch(1)
multiBufferedRenderer.obtainRenderRequest()
.preserveContents(true)
- .draw(executor) { _ ->
+ .drawAsync(executor) { _ ->
firstRenderLatch.countDown()
}
@@ -107,7 +107,7 @@
val secondRenderLatch = CountDownLatch(1)
multiBufferedRenderer.obtainRenderRequest()
.preserveContents(true)
- .draw(executor) { result ->
+ .drawAsync(executor) { result ->
result.fence?.awaitForever()
bitmap = Bitmap.wrapHardwareBuffer(
result.hardwareBuffer,
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/SingleBufferedCanvasRenderer.kt b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/SingleBufferedCanvasRenderer.kt
index 3e4476e..699ed6d 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/SingleBufferedCanvasRenderer.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/SingleBufferedCanvasRenderer.kt
@@ -103,7 +103,7 @@
}
preserveContents(true)
setColorSpace([email protected])
- draw(executor) { result ->
+ drawAsync(executor) { result ->
requestComplete.invoke(result.hardwareBuffer, result.fence)
}
}
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/FrameBufferRenderer.kt b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/FrameBufferRenderer.kt
index bafcff8..c49cc78 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/FrameBufferRenderer.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/FrameBufferRenderer.kt
@@ -211,7 +211,6 @@
*
* @param eglSpec an [EGLSpec] object to dictate the version of EGL and make EGL calls.
*/
- @RequiresApi(Build.VERSION_CODES.KITKAT)
fun createSyncFence(eglSpec: EGLSpec): SyncFenceCompat?
companion object {
@@ -220,7 +219,6 @@
*/
@JvmField
val ALWAYS = object : SyncStrategy {
- @RequiresApi(Build.VERSION_CODES.KITKAT)
override fun createSyncFence(eglSpec: EGLSpec): SyncFenceCompat? {
return SyncFenceCompat.createNativeSyncFence()
}
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlImpl.kt b/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlImpl.kt
index 6362285..c2cd443 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlImpl.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlImpl.kt
@@ -89,7 +89,6 @@
}
@JvmDefaultWithCompatibility
- @RequiresApi(Build.VERSION_CODES.KITKAT)
interface Transaction : AutoCloseable {
/**
diff --git a/graphics/graphics-core/src/main/java/androidx/hardware/SyncFenceCompat.kt b/graphics/graphics-core/src/main/java/androidx/hardware/SyncFenceCompat.kt
index 581b0b2..0c5d152 100644
--- a/graphics/graphics-core/src/main/java/androidx/hardware/SyncFenceCompat.kt
+++ b/graphics/graphics-core/src/main/java/androidx/hardware/SyncFenceCompat.kt
@@ -35,7 +35,6 @@
* [SurfaceControlCompat.Transaction.setBuffer]. Note that depending on API level, this will
* utilize either [android.hardware.SyncFence] or a compatibility implementation.
*/
-@RequiresApi(Build.VERSION_CODES.KITKAT)
class SyncFenceCompat : AutoCloseable {
internal val mImpl: SyncFenceImpl
diff --git a/graphics/graphics-core/src/main/java/androidx/hardware/SyncFenceV19.kt b/graphics/graphics-core/src/main/java/androidx/hardware/SyncFenceV19.kt
index 13e9c66..3019108 100644
--- a/graphics/graphics-core/src/main/java/androidx/hardware/SyncFenceV19.kt
+++ b/graphics/graphics-core/src/main/java/androidx/hardware/SyncFenceV19.kt
@@ -33,7 +33,6 @@
* When the fence signals, then the backing storage for the framebuffer may be safely read from,
* such as for display or media encoding.
*/
-@RequiresApi(Build.VERSION_CODES.KITKAT)
@JniVisible
internal class SyncFenceV19(private var fd: Int) : AutoCloseable, SyncFenceImpl {
diff --git a/graphics/graphics-core/src/main/java/androidx/opengl/EGLExt.kt b/graphics/graphics-core/src/main/java/androidx/opengl/EGLExt.kt
index b851c5d..89acecb 100644
--- a/graphics/graphics-core/src/main/java/androidx/opengl/EGLExt.kt
+++ b/graphics/graphics-core/src/main/java/androidx/opengl/EGLExt.kt
@@ -573,7 +573,6 @@
*/
@JvmStatic
@Suppress("AcronymName")
- @RequiresApi(Build.VERSION_CODES.KITKAT)
internal fun eglDupNativeFenceFDANDROID(
display: EGLDisplay,
sync: EGLSyncKHR
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/HealthEvent.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/HealthEvent.kt
index bcf82b4..5c2b868 100644
--- a/health/health-services-client/src/main/java/androidx/health/services/client/data/HealthEvent.kt
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/HealthEvent.kt
@@ -16,6 +16,8 @@
package androidx.health.services.client.data
+import androidx.annotation.RestrictTo
+import androidx.annotation.RestrictTo.Scope
import androidx.health.services.client.proto.DataProto
import androidx.health.services.client.proto.DataProto.HealthEvent.MetricsEntry
import java.time.Instant
@@ -33,7 +35,13 @@
) {
/** Health event types. */
- public class Type private constructor(public val id: Int, public val name: String) {
+ public class Type @RestrictTo(Scope.LIBRARY) constructor(
+ /** Returns a unique identifier for the [Type], as an `int`. */
+ public val id: Int,
+
+ /** Returns a human readable name to represent this [Type]. */
+ public val name: String
+ ) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
diff --git a/kruth/kruth/api/api_lint.ignore b/kruth/kruth/api/api_lint.ignore
index 97444da..7ac8a1f 100644
--- a/kruth/kruth/api/api_lint.ignore
+++ b/kruth/kruth/api/api_lint.ignore
@@ -7,6 +7,10 @@
Method parameter should be Collection<Object> (or subclass) instead of raw array; was `java.lang.Object[]`
ArrayReturn: androidx.kruth.IterableSubject#containsNoneIn(Object[]) parameter #0:
Method parameter should be Collection<Object> (or subclass) instead of raw array; was `java.lang.Object[]`
+ArrayReturn: androidx.kruth.KruthKt#assertThat(T[]) parameter #0:
+ Method parameter should be Collection<T> (or subclass) instead of raw array; was `T[]`
+ArrayReturn: androidx.kruth.StandardSubjectBuilder#that(T[]) parameter #0:
+ Method parameter should be Collection<T> (or subclass) instead of raw array; was `T[]`
AutoBoxing: androidx.kruth.KruthKt#assertThat(Boolean) parameter #0:
@@ -43,10 +47,26 @@
Builder methods names should use setFoo() / addFoo() / clearFoo() style: method androidx.kruth.StandardSubjectBuilder.that(String)
BuilderSetStyle: androidx.kruth.StandardSubjectBuilder#that(T):
Builder methods names should use setFoo() / addFoo() / clearFoo() style: method androidx.kruth.StandardSubjectBuilder.that(T)
+BuilderSetStyle: androidx.kruth.StandardSubjectBuilder#that(T[]):
+ Builder methods names should use setFoo() / addFoo() / clearFoo() style: method androidx.kruth.StandardSubjectBuilder.that(T[])
+BuilderSetStyle: androidx.kruth.StandardSubjectBuilder#that(boolean[]):
+ Builder methods names should use setFoo() / addFoo() / clearFoo() style: method androidx.kruth.StandardSubjectBuilder.that(boolean[])
BuilderSetStyle: androidx.kruth.StandardSubjectBuilder#that(byte[]):
Builder methods names should use setFoo() / addFoo() / clearFoo() style: method androidx.kruth.StandardSubjectBuilder.that(byte[])
+BuilderSetStyle: androidx.kruth.StandardSubjectBuilder#that(char[]):
+ Builder methods names should use setFoo() / addFoo() / clearFoo() style: method androidx.kruth.StandardSubjectBuilder.that(char[])
+BuilderSetStyle: androidx.kruth.StandardSubjectBuilder#that(double[]):
+ Builder methods names should use setFoo() / addFoo() / clearFoo() style: method androidx.kruth.StandardSubjectBuilder.that(double[])
+BuilderSetStyle: androidx.kruth.StandardSubjectBuilder#that(float[]):
+ Builder methods names should use setFoo() / addFoo() / clearFoo() style: method androidx.kruth.StandardSubjectBuilder.that(float[])
+BuilderSetStyle: androidx.kruth.StandardSubjectBuilder#that(int[]):
+ Builder methods names should use setFoo() / addFoo() / clearFoo() style: method androidx.kruth.StandardSubjectBuilder.that(int[])
BuilderSetStyle: androidx.kruth.StandardSubjectBuilder#that(java.util.Map<K,? extends V>):
Builder methods names should use setFoo() / addFoo() / clearFoo() style: method androidx.kruth.StandardSubjectBuilder.that(java.util.Map<K,? extends V>)
+BuilderSetStyle: androidx.kruth.StandardSubjectBuilder#that(long[]):
+ Builder methods names should use setFoo() / addFoo() / clearFoo() style: method androidx.kruth.StandardSubjectBuilder.that(long[])
+BuilderSetStyle: androidx.kruth.StandardSubjectBuilder#that(short[]):
+ Builder methods names should use setFoo() / addFoo() / clearFoo() style: method androidx.kruth.StandardSubjectBuilder.that(short[])
BuilderSetStyle: androidx.kruth.StandardSubjectBuilder#withMessage(String):
Builder methods names should use setFoo() / addFoo() / clearFoo() style: method androidx.kruth.StandardSubjectBuilder.withMessage(String)
diff --git a/kruth/kruth/api/current.ignore b/kruth/kruth/api/current.ignore
index 33fd741..f064a31 100644
--- a/kruth/kruth/api/current.ignore
+++ b/kruth/kruth/api/current.ignore
@@ -39,8 +39,20 @@
Class androidx.kruth.ThrowableSubject added 'final' qualifier
+ChangedType: androidx.kruth.ObjectArraySubject#asList():
+ Method androidx.kruth.ObjectArraySubject.asList has changed return type from androidx.kruth.IterableSubject to androidx.kruth.IterableSubject<?>
+ChangedType: androidx.kruth.PrimitiveBooleanArraySubject#asList():
+ Method androidx.kruth.PrimitiveBooleanArraySubject.asList has changed return type from androidx.kruth.IterableSubject to androidx.kruth.IterableSubject<java.lang.Boolean>
ChangedType: androidx.kruth.PrimitiveByteArraySubject#asList():
Method androidx.kruth.PrimitiveByteArraySubject.asList has changed return type from androidx.kruth.IterableSubject to androidx.kruth.IterableSubject<java.lang.Byte>
+ChangedType: androidx.kruth.PrimitiveCharArraySubject#asList():
+ Method androidx.kruth.PrimitiveCharArraySubject.asList has changed return type from androidx.kruth.IterableSubject to androidx.kruth.IterableSubject<java.lang.Character>
+ChangedType: androidx.kruth.PrimitiveIntArraySubject#asList():
+ Method androidx.kruth.PrimitiveIntArraySubject.asList has changed return type from androidx.kruth.IterableSubject to androidx.kruth.IterableSubject<java.lang.Integer>
+ChangedType: androidx.kruth.PrimitiveLongArraySubject#asList():
+ Method androidx.kruth.PrimitiveLongArraySubject.asList has changed return type from androidx.kruth.IterableSubject to androidx.kruth.IterableSubject<java.lang.Long>
+ChangedType: androidx.kruth.PrimitiveShortArraySubject#asList():
+ Method androidx.kruth.PrimitiveShortArraySubject.asList has changed return type from androidx.kruth.IterableSubject to androidx.kruth.IterableSubject<java.lang.Short>
ChangedType: androidx.kruth.SimpleSubjectBuilder#that(T):
Method androidx.kruth.SimpleSubjectBuilder.that has changed return type from SubjectT (extends androidx.kruth.Subject) to S (extends androidx.kruth.Subject<? extends T>)
ChangedType: androidx.kruth.StandardSubjectBuilder#about(androidx.kruth.Subject.Factory<? extends S,T>):
@@ -51,8 +63,8 @@
Method androidx.kruth.StandardSubjectBuilder.that has changed return type from androidx.kruth.IterableSubject to androidx.kruth.IterableSubject<T>
ChangedType: androidx.kruth.StandardSubjectBuilder#that(T):
Method androidx.kruth.StandardSubjectBuilder.that has changed return type from androidx.kruth.ClassSubject to androidx.kruth.Subject<T>
-ChangedType: androidx.kruth.StandardSubjectBuilder#that(byte[]):
- Method androidx.kruth.StandardSubjectBuilder.that has changed return type from androidx.kruth.ObjectArraySubject<T> to androidx.kruth.PrimitiveByteArraySubject
+ChangedType: androidx.kruth.StandardSubjectBuilder#that(T[]):
+ Method androidx.kruth.StandardSubjectBuilder.that has changed return type from androidx.kruth.ObjectArraySubject<T> to androidx.kruth.ObjectArraySubject<T>
ChangedType: androidx.kruth.StandardSubjectBuilder#that(java.util.Map<K,? extends V>):
Method androidx.kruth.StandardSubjectBuilder.that has changed return type from androidx.kruth.MapSubject to androidx.kruth.MapSubject<K,V>
ChangedType: androidx.kruth.Subject#failWithActual(String, Object):
@@ -123,22 +135,10 @@
Removed class androidx.kruth.MultimapSubject
RemovedClass: androidx.kruth.MultisetSubject:
Removed class androidx.kruth.MultisetSubject
-RemovedClass: androidx.kruth.ObjectArraySubject:
- Removed class androidx.kruth.ObjectArraySubject
-RemovedClass: androidx.kruth.PrimitiveBooleanArraySubject:
- Removed class androidx.kruth.PrimitiveBooleanArraySubject
-RemovedClass: androidx.kruth.PrimitiveCharArraySubject:
- Removed class androidx.kruth.PrimitiveCharArraySubject
-RemovedClass: androidx.kruth.PrimitiveDoubleArraySubject:
- Removed class androidx.kruth.PrimitiveDoubleArraySubject
-RemovedClass: androidx.kruth.PrimitiveFloatArraySubject:
- Removed class androidx.kruth.PrimitiveFloatArraySubject
-RemovedClass: androidx.kruth.PrimitiveIntArraySubject:
- Removed class androidx.kruth.PrimitiveIntArraySubject
-RemovedClass: androidx.kruth.PrimitiveLongArraySubject:
- Removed class androidx.kruth.PrimitiveLongArraySubject
-RemovedClass: androidx.kruth.PrimitiveShortArraySubject:
- Removed class androidx.kruth.PrimitiveShortArraySubject
+RemovedClass: androidx.kruth.PrimitiveDoubleArraySubject.DoubleArrayAsIterable:
+ Removed class androidx.kruth.PrimitiveDoubleArraySubject.DoubleArrayAsIterable
+RemovedClass: androidx.kruth.PrimitiveFloatArraySubject.FloatArrayAsIterable:
+ Removed class androidx.kruth.PrimitiveFloatArraySubject.FloatArrayAsIterable
RemovedClass: androidx.kruth.TableSubject:
Removed class androidx.kruth.TableSubject
RemovedClass: androidx.kruth.Truth:
@@ -181,6 +181,14 @@
Removed method androidx.kruth.MapSubject.containsExactly(Object,Object,java.lang.Object...)
RemovedMethod: androidx.kruth.MapSubject#formattingDiffsUsing(androidx.kruth.Correspondence.DiffFormatter<? super V,? super V>):
Removed method androidx.kruth.MapSubject.formattingDiffsUsing(androidx.kruth.Correspondence.DiffFormatter<? super V,? super V>)
+RemovedMethod: androidx.kruth.PrimitiveDoubleArraySubject#usingExactEquality():
+ Removed method androidx.kruth.PrimitiveDoubleArraySubject.usingExactEquality()
+RemovedMethod: androidx.kruth.PrimitiveDoubleArraySubject#usingTolerance(double):
+ Removed method androidx.kruth.PrimitiveDoubleArraySubject.usingTolerance(double)
+RemovedMethod: androidx.kruth.PrimitiveFloatArraySubject#usingExactEquality():
+ Removed method androidx.kruth.PrimitiveFloatArraySubject.usingExactEquality()
+RemovedMethod: androidx.kruth.PrimitiveFloatArraySubject#usingTolerance(double):
+ Removed method androidx.kruth.PrimitiveFloatArraySubject.usingTolerance(double)
RemovedMethod: androidx.kruth.StandardSubjectBuilder#about(androidx.kruth.CustomSubjectBuilder.Factory<CustomSubjectBuilderT>):
Removed method androidx.kruth.StandardSubjectBuilder.about(androidx.kruth.CustomSubjectBuilder.Factory<CustomSubjectBuilderT>)
RemovedMethod: androidx.kruth.StandardSubjectBuilder#withMessage(String, java.lang.Object...):
diff --git a/kruth/kruth/api/current.txt b/kruth/kruth/api/current.txt
index 8c39acad..4ab5149 100644
--- a/kruth/kruth/api/current.txt
+++ b/kruth/kruth/api/current.txt
@@ -113,16 +113,24 @@
public final class KruthKt {
method public static <S extends androidx.kruth.Subject<? extends T>, T> androidx.kruth.SimpleSubjectBuilder<S,T> assertAbout(androidx.kruth.Subject.Factory<? extends S,T> subjectFactory);
+ method public static androidx.kruth.PrimitiveBooleanArraySubject assertThat(boolean[]? actual);
method public static androidx.kruth.PrimitiveByteArraySubject assertThat(byte[]? actual);
+ method public static androidx.kruth.PrimitiveCharArraySubject assertThat(char[]? actual);
+ method public static androidx.kruth.PrimitiveDoubleArraySubject assertThat(double[]? actual);
+ method public static androidx.kruth.PrimitiveFloatArraySubject assertThat(float[]? actual);
+ method public static androidx.kruth.PrimitiveIntArraySubject assertThat(int[]? actual);
method public static androidx.kruth.BooleanSubject assertThat(Boolean? actual);
method public static androidx.kruth.DoubleSubject assertThat(Double? actual);
method public static androidx.kruth.IntegerSubject assertThat(Integer? actual);
method public static <T> androidx.kruth.IterableSubject<T> assertThat(Iterable<? extends T>? actual);
method public static androidx.kruth.StringSubject assertThat(String? actual);
method public static <K, V> androidx.kruth.MapSubject<K,V> assertThat(java.util.Map<K,? extends V>? actual);
+ method public static androidx.kruth.PrimitiveLongArraySubject assertThat(long[]? actual);
+ method public static androidx.kruth.PrimitiveShortArraySubject assertThat(short[]? actual);
method public static <T extends java.lang.Comparable<? super T>> androidx.kruth.ComparableSubject<T> assertThat(T? actual);
method public static <T> androidx.kruth.Subject<T> assertThat(T? actual);
method public static <T extends java.lang.Throwable> androidx.kruth.ThrowableSubject<T> assertThat(T? actual);
+ method public static <T> androidx.kruth.ObjectArraySubject<T> assertThat(T![]? actual);
method public static androidx.kruth.StandardSubjectBuilder assertWithMessage(String messageToPrepend);
}
@@ -142,10 +150,24 @@
method public void isNotEmpty();
}
+ public final class ObjectArraySubject<T> extends androidx.kruth.Subject<T[]> {
+ method public androidx.kruth.IterableSubject<?> asList();
+ method public void hasLength(int length);
+ method public void isEmpty();
+ method public void isNotEmpty();
+ }
+
public interface Ordered {
method public void inOrder();
}
+ public final class PrimitiveBooleanArraySubject extends androidx.kruth.Subject<boolean[]> {
+ method public androidx.kruth.IterableSubject<java.lang.Boolean> asList();
+ method public void hasLength(int length);
+ method public void isEmpty();
+ method public void isNotEmpty();
+ }
+
public final class PrimitiveByteArraySubject extends androidx.kruth.Subject<byte[]> {
method public androidx.kruth.IterableSubject<java.lang.Byte> asList();
method public void hasLength(int length);
@@ -153,6 +175,48 @@
method public void isNotEmpty();
}
+ public final class PrimitiveCharArraySubject extends androidx.kruth.Subject<char[]> {
+ method public androidx.kruth.IterableSubject<java.lang.Character> asList();
+ method public void hasLength(int length);
+ method public void isEmpty();
+ method public void isNotEmpty();
+ }
+
+ public final class PrimitiveDoubleArraySubject extends androidx.kruth.Subject<double[]> {
+ method public androidx.kruth.IterableSubject<java.lang.Double> asList();
+ method public void hasLength(int length);
+ method public void isEmpty();
+ method public void isNotEmpty();
+ }
+
+ public final class PrimitiveFloatArraySubject extends androidx.kruth.Subject<float[]> {
+ method public androidx.kruth.IterableSubject<java.lang.Float> asList();
+ method public void hasLength(int length);
+ method public void isEmpty();
+ method public void isNotEmpty();
+ }
+
+ public final class PrimitiveIntArraySubject extends androidx.kruth.Subject<int[]> {
+ method public androidx.kruth.IterableSubject<java.lang.Integer> asList();
+ method public void hasLength(int length);
+ method public void isEmpty();
+ method public void isNotEmpty();
+ }
+
+ public final class PrimitiveLongArraySubject extends androidx.kruth.Subject<long[]> {
+ method public androidx.kruth.IterableSubject<java.lang.Long> asList();
+ method public void hasLength(int length);
+ method public void isEmpty();
+ method public void isNotEmpty();
+ }
+
+ public final class PrimitiveShortArraySubject extends androidx.kruth.Subject<short[]> {
+ method public androidx.kruth.IterableSubject<java.lang.Short> asList();
+ method public void hasLength(int length);
+ method public void isEmpty();
+ method public void isNotEmpty();
+ }
+
public final class SimpleSubjectBuilder<S extends androidx.kruth.Subject<? extends T>, T> {
method public S that(T actual);
}
@@ -160,23 +224,31 @@
public final class StandardSubjectBuilder {
method public <T, S extends androidx.kruth.Subject<? extends T>> androidx.kruth.SimpleSubjectBuilder<S,T> about(androidx.kruth.Subject.Factory<? extends S,T> subjectFactory);
method public Void fail();
- method public static androidx.kruth.StandardSubjectBuilder? forCustomFailureStrategy(androidx.kruth.FailureStrategy failureStrategy);
+ method public static androidx.kruth.StandardSubjectBuilder forCustomFailureStrategy(androidx.kruth.FailureStrategy failureStrategy);
+ method public androidx.kruth.PrimitiveBooleanArraySubject that(boolean[]? actual);
method public androidx.kruth.PrimitiveByteArraySubject that(byte[]? actual);
+ method public androidx.kruth.PrimitiveCharArraySubject that(char[]? actual);
+ method public androidx.kruth.PrimitiveDoubleArraySubject that(double[]? actual);
+ method public androidx.kruth.PrimitiveFloatArraySubject that(float[]? actual);
+ method public androidx.kruth.PrimitiveIntArraySubject that(int[]? actual);
method public androidx.kruth.BooleanSubject that(Boolean? actual);
method public androidx.kruth.DoubleSubject that(Double? actual);
method public androidx.kruth.IntegerSubject that(Integer? actual);
method public <T> androidx.kruth.IterableSubject<T> that(Iterable<? extends T>? actual);
method public androidx.kruth.StringSubject that(String? actual);
method public <K, V> androidx.kruth.MapSubject<K,V> that(java.util.Map<K,? extends V>? actual);
+ method public androidx.kruth.PrimitiveLongArraySubject that(long[]? actual);
+ method public androidx.kruth.PrimitiveShortArraySubject that(short[]? actual);
method public <T> androidx.kruth.Subject<T> that(T actual);
method public <T extends java.lang.Comparable<? super T>> androidx.kruth.ComparableSubject<T> that(T? actual);
method public <T extends java.lang.Throwable> androidx.kruth.ThrowableSubject<T> that(T? actual);
+ method public <T> androidx.kruth.ObjectArraySubject<T> that(T![]? actual);
method public androidx.kruth.StandardSubjectBuilder withMessage(String messageToPrepend);
field public static final androidx.kruth.StandardSubjectBuilder.Companion Companion;
}
public static final class StandardSubjectBuilder.Companion {
- method public androidx.kruth.StandardSubjectBuilder? forCustomFailureStrategy(androidx.kruth.FailureStrategy failureStrategy);
+ method public androidx.kruth.StandardSubjectBuilder forCustomFailureStrategy(androidx.kruth.FailureStrategy failureStrategy);
}
public final class StringSubject extends androidx.kruth.ComparableSubject<java.lang.String> {
diff --git a/kruth/kruth/api/restricted_current.ignore b/kruth/kruth/api/restricted_current.ignore
index 33fd741..f064a31 100644
--- a/kruth/kruth/api/restricted_current.ignore
+++ b/kruth/kruth/api/restricted_current.ignore
@@ -39,8 +39,20 @@
Class androidx.kruth.ThrowableSubject added 'final' qualifier
+ChangedType: androidx.kruth.ObjectArraySubject#asList():
+ Method androidx.kruth.ObjectArraySubject.asList has changed return type from androidx.kruth.IterableSubject to androidx.kruth.IterableSubject<?>
+ChangedType: androidx.kruth.PrimitiveBooleanArraySubject#asList():
+ Method androidx.kruth.PrimitiveBooleanArraySubject.asList has changed return type from androidx.kruth.IterableSubject to androidx.kruth.IterableSubject<java.lang.Boolean>
ChangedType: androidx.kruth.PrimitiveByteArraySubject#asList():
Method androidx.kruth.PrimitiveByteArraySubject.asList has changed return type from androidx.kruth.IterableSubject to androidx.kruth.IterableSubject<java.lang.Byte>
+ChangedType: androidx.kruth.PrimitiveCharArraySubject#asList():
+ Method androidx.kruth.PrimitiveCharArraySubject.asList has changed return type from androidx.kruth.IterableSubject to androidx.kruth.IterableSubject<java.lang.Character>
+ChangedType: androidx.kruth.PrimitiveIntArraySubject#asList():
+ Method androidx.kruth.PrimitiveIntArraySubject.asList has changed return type from androidx.kruth.IterableSubject to androidx.kruth.IterableSubject<java.lang.Integer>
+ChangedType: androidx.kruth.PrimitiveLongArraySubject#asList():
+ Method androidx.kruth.PrimitiveLongArraySubject.asList has changed return type from androidx.kruth.IterableSubject to androidx.kruth.IterableSubject<java.lang.Long>
+ChangedType: androidx.kruth.PrimitiveShortArraySubject#asList():
+ Method androidx.kruth.PrimitiveShortArraySubject.asList has changed return type from androidx.kruth.IterableSubject to androidx.kruth.IterableSubject<java.lang.Short>
ChangedType: androidx.kruth.SimpleSubjectBuilder#that(T):
Method androidx.kruth.SimpleSubjectBuilder.that has changed return type from SubjectT (extends androidx.kruth.Subject) to S (extends androidx.kruth.Subject<? extends T>)
ChangedType: androidx.kruth.StandardSubjectBuilder#about(androidx.kruth.Subject.Factory<? extends S,T>):
@@ -51,8 +63,8 @@
Method androidx.kruth.StandardSubjectBuilder.that has changed return type from androidx.kruth.IterableSubject to androidx.kruth.IterableSubject<T>
ChangedType: androidx.kruth.StandardSubjectBuilder#that(T):
Method androidx.kruth.StandardSubjectBuilder.that has changed return type from androidx.kruth.ClassSubject to androidx.kruth.Subject<T>
-ChangedType: androidx.kruth.StandardSubjectBuilder#that(byte[]):
- Method androidx.kruth.StandardSubjectBuilder.that has changed return type from androidx.kruth.ObjectArraySubject<T> to androidx.kruth.PrimitiveByteArraySubject
+ChangedType: androidx.kruth.StandardSubjectBuilder#that(T[]):
+ Method androidx.kruth.StandardSubjectBuilder.that has changed return type from androidx.kruth.ObjectArraySubject<T> to androidx.kruth.ObjectArraySubject<T>
ChangedType: androidx.kruth.StandardSubjectBuilder#that(java.util.Map<K,? extends V>):
Method androidx.kruth.StandardSubjectBuilder.that has changed return type from androidx.kruth.MapSubject to androidx.kruth.MapSubject<K,V>
ChangedType: androidx.kruth.Subject#failWithActual(String, Object):
@@ -123,22 +135,10 @@
Removed class androidx.kruth.MultimapSubject
RemovedClass: androidx.kruth.MultisetSubject:
Removed class androidx.kruth.MultisetSubject
-RemovedClass: androidx.kruth.ObjectArraySubject:
- Removed class androidx.kruth.ObjectArraySubject
-RemovedClass: androidx.kruth.PrimitiveBooleanArraySubject:
- Removed class androidx.kruth.PrimitiveBooleanArraySubject
-RemovedClass: androidx.kruth.PrimitiveCharArraySubject:
- Removed class androidx.kruth.PrimitiveCharArraySubject
-RemovedClass: androidx.kruth.PrimitiveDoubleArraySubject:
- Removed class androidx.kruth.PrimitiveDoubleArraySubject
-RemovedClass: androidx.kruth.PrimitiveFloatArraySubject:
- Removed class androidx.kruth.PrimitiveFloatArraySubject
-RemovedClass: androidx.kruth.PrimitiveIntArraySubject:
- Removed class androidx.kruth.PrimitiveIntArraySubject
-RemovedClass: androidx.kruth.PrimitiveLongArraySubject:
- Removed class androidx.kruth.PrimitiveLongArraySubject
-RemovedClass: androidx.kruth.PrimitiveShortArraySubject:
- Removed class androidx.kruth.PrimitiveShortArraySubject
+RemovedClass: androidx.kruth.PrimitiveDoubleArraySubject.DoubleArrayAsIterable:
+ Removed class androidx.kruth.PrimitiveDoubleArraySubject.DoubleArrayAsIterable
+RemovedClass: androidx.kruth.PrimitiveFloatArraySubject.FloatArrayAsIterable:
+ Removed class androidx.kruth.PrimitiveFloatArraySubject.FloatArrayAsIterable
RemovedClass: androidx.kruth.TableSubject:
Removed class androidx.kruth.TableSubject
RemovedClass: androidx.kruth.Truth:
@@ -181,6 +181,14 @@
Removed method androidx.kruth.MapSubject.containsExactly(Object,Object,java.lang.Object...)
RemovedMethod: androidx.kruth.MapSubject#formattingDiffsUsing(androidx.kruth.Correspondence.DiffFormatter<? super V,? super V>):
Removed method androidx.kruth.MapSubject.formattingDiffsUsing(androidx.kruth.Correspondence.DiffFormatter<? super V,? super V>)
+RemovedMethod: androidx.kruth.PrimitiveDoubleArraySubject#usingExactEquality():
+ Removed method androidx.kruth.PrimitiveDoubleArraySubject.usingExactEquality()
+RemovedMethod: androidx.kruth.PrimitiveDoubleArraySubject#usingTolerance(double):
+ Removed method androidx.kruth.PrimitiveDoubleArraySubject.usingTolerance(double)
+RemovedMethod: androidx.kruth.PrimitiveFloatArraySubject#usingExactEquality():
+ Removed method androidx.kruth.PrimitiveFloatArraySubject.usingExactEquality()
+RemovedMethod: androidx.kruth.PrimitiveFloatArraySubject#usingTolerance(double):
+ Removed method androidx.kruth.PrimitiveFloatArraySubject.usingTolerance(double)
RemovedMethod: androidx.kruth.StandardSubjectBuilder#about(androidx.kruth.CustomSubjectBuilder.Factory<CustomSubjectBuilderT>):
Removed method androidx.kruth.StandardSubjectBuilder.about(androidx.kruth.CustomSubjectBuilder.Factory<CustomSubjectBuilderT>)
RemovedMethod: androidx.kruth.StandardSubjectBuilder#withMessage(String, java.lang.Object...):
diff --git a/kruth/kruth/api/restricted_current.txt b/kruth/kruth/api/restricted_current.txt
index 66bf3b0..e00143f 100644
--- a/kruth/kruth/api/restricted_current.txt
+++ b/kruth/kruth/api/restricted_current.txt
@@ -113,16 +113,24 @@
public final class KruthKt {
method public static <S extends androidx.kruth.Subject<? extends T>, T> androidx.kruth.SimpleSubjectBuilder<S,T> assertAbout(androidx.kruth.Subject.Factory<? extends S,T> subjectFactory);
+ method public static androidx.kruth.PrimitiveBooleanArraySubject assertThat(boolean[]? actual);
method public static androidx.kruth.PrimitiveByteArraySubject assertThat(byte[]? actual);
+ method public static androidx.kruth.PrimitiveCharArraySubject assertThat(char[]? actual);
+ method public static androidx.kruth.PrimitiveDoubleArraySubject assertThat(double[]? actual);
+ method public static androidx.kruth.PrimitiveFloatArraySubject assertThat(float[]? actual);
+ method public static androidx.kruth.PrimitiveIntArraySubject assertThat(int[]? actual);
method public static androidx.kruth.BooleanSubject assertThat(Boolean? actual);
method public static androidx.kruth.DoubleSubject assertThat(Double? actual);
method public static androidx.kruth.IntegerSubject assertThat(Integer? actual);
method public static <T> androidx.kruth.IterableSubject<T> assertThat(Iterable<? extends T>? actual);
method public static androidx.kruth.StringSubject assertThat(String? actual);
method public static <K, V> androidx.kruth.MapSubject<K,V> assertThat(java.util.Map<K,? extends V>? actual);
+ method public static androidx.kruth.PrimitiveLongArraySubject assertThat(long[]? actual);
+ method public static androidx.kruth.PrimitiveShortArraySubject assertThat(short[]? actual);
method public static <T extends java.lang.Comparable<? super T>> androidx.kruth.ComparableSubject<T> assertThat(T? actual);
method public static <T> androidx.kruth.Subject<T> assertThat(T? actual);
method public static <T extends java.lang.Throwable> androidx.kruth.ThrowableSubject<T> assertThat(T? actual);
+ method public static <T> androidx.kruth.ObjectArraySubject<T> assertThat(T![]? actual);
method public static androidx.kruth.StandardSubjectBuilder assertWithMessage(String messageToPrepend);
}
@@ -142,10 +150,24 @@
method public void isNotEmpty();
}
+ public final class ObjectArraySubject<T> extends androidx.kruth.Subject<T[]> {
+ method public androidx.kruth.IterableSubject<?> asList();
+ method public void hasLength(int length);
+ method public void isEmpty();
+ method public void isNotEmpty();
+ }
+
public interface Ordered {
method public void inOrder();
}
+ public final class PrimitiveBooleanArraySubject extends androidx.kruth.Subject<boolean[]> {
+ method public androidx.kruth.IterableSubject<java.lang.Boolean> asList();
+ method public void hasLength(int length);
+ method public void isEmpty();
+ method public void isNotEmpty();
+ }
+
public final class PrimitiveByteArraySubject extends androidx.kruth.Subject<byte[]> {
method public androidx.kruth.IterableSubject<java.lang.Byte> asList();
method public void hasLength(int length);
@@ -153,6 +175,48 @@
method public void isNotEmpty();
}
+ public final class PrimitiveCharArraySubject extends androidx.kruth.Subject<char[]> {
+ method public androidx.kruth.IterableSubject<java.lang.Character> asList();
+ method public void hasLength(int length);
+ method public void isEmpty();
+ method public void isNotEmpty();
+ }
+
+ public final class PrimitiveDoubleArraySubject extends androidx.kruth.Subject<double[]> {
+ method public androidx.kruth.IterableSubject<java.lang.Double> asList();
+ method public void hasLength(int length);
+ method public void isEmpty();
+ method public void isNotEmpty();
+ }
+
+ public final class PrimitiveFloatArraySubject extends androidx.kruth.Subject<float[]> {
+ method public androidx.kruth.IterableSubject<java.lang.Float> asList();
+ method public void hasLength(int length);
+ method public void isEmpty();
+ method public void isNotEmpty();
+ }
+
+ public final class PrimitiveIntArraySubject extends androidx.kruth.Subject<int[]> {
+ method public androidx.kruth.IterableSubject<java.lang.Integer> asList();
+ method public void hasLength(int length);
+ method public void isEmpty();
+ method public void isNotEmpty();
+ }
+
+ public final class PrimitiveLongArraySubject extends androidx.kruth.Subject<long[]> {
+ method public androidx.kruth.IterableSubject<java.lang.Long> asList();
+ method public void hasLength(int length);
+ method public void isEmpty();
+ method public void isNotEmpty();
+ }
+
+ public final class PrimitiveShortArraySubject extends androidx.kruth.Subject<short[]> {
+ method public androidx.kruth.IterableSubject<java.lang.Short> asList();
+ method public void hasLength(int length);
+ method public void isEmpty();
+ method public void isNotEmpty();
+ }
+
public final class SimpleSubjectBuilder<S extends androidx.kruth.Subject<? extends T>, T> {
method public S that(T actual);
}
@@ -160,23 +224,31 @@
public final class StandardSubjectBuilder {
method public <T, S extends androidx.kruth.Subject<? extends T>> androidx.kruth.SimpleSubjectBuilder<S,T> about(androidx.kruth.Subject.Factory<? extends S,T> subjectFactory);
method public Void fail();
- method public static androidx.kruth.StandardSubjectBuilder? forCustomFailureStrategy(androidx.kruth.FailureStrategy failureStrategy);
+ method public static androidx.kruth.StandardSubjectBuilder forCustomFailureStrategy(androidx.kruth.FailureStrategy failureStrategy);
+ method public androidx.kruth.PrimitiveBooleanArraySubject that(boolean[]? actual);
method public androidx.kruth.PrimitiveByteArraySubject that(byte[]? actual);
+ method public androidx.kruth.PrimitiveCharArraySubject that(char[]? actual);
+ method public androidx.kruth.PrimitiveDoubleArraySubject that(double[]? actual);
+ method public androidx.kruth.PrimitiveFloatArraySubject that(float[]? actual);
+ method public androidx.kruth.PrimitiveIntArraySubject that(int[]? actual);
method public androidx.kruth.BooleanSubject that(Boolean? actual);
method public androidx.kruth.DoubleSubject that(Double? actual);
method public androidx.kruth.IntegerSubject that(Integer? actual);
method public <T> androidx.kruth.IterableSubject<T> that(Iterable<? extends T>? actual);
method public androidx.kruth.StringSubject that(String? actual);
method public <K, V> androidx.kruth.MapSubject<K,V> that(java.util.Map<K,? extends V>? actual);
+ method public androidx.kruth.PrimitiveLongArraySubject that(long[]? actual);
+ method public androidx.kruth.PrimitiveShortArraySubject that(short[]? actual);
method public <T> androidx.kruth.Subject<T> that(T actual);
method public <T extends java.lang.Comparable<? super T>> androidx.kruth.ComparableSubject<T> that(T? actual);
method public <T extends java.lang.Throwable> androidx.kruth.ThrowableSubject<T> that(T? actual);
+ method public <T> androidx.kruth.ObjectArraySubject<T> that(T![]? actual);
method public androidx.kruth.StandardSubjectBuilder withMessage(String messageToPrepend);
field public static final androidx.kruth.StandardSubjectBuilder.Companion Companion;
}
public static final class StandardSubjectBuilder.Companion {
- method public androidx.kruth.StandardSubjectBuilder? forCustomFailureStrategy(androidx.kruth.FailureStrategy failureStrategy);
+ method public androidx.kruth.StandardSubjectBuilder forCustomFailureStrategy(androidx.kruth.FailureStrategy failureStrategy);
}
public final class StringSubject extends androidx.kruth.ComparableSubject<java.lang.String> {
diff --git a/kruth/kruth/build.gradle b/kruth/kruth/build.gradle
index 1726625..5025ed1 100644
--- a/kruth/kruth/build.gradle
+++ b/kruth/kruth/build.gradle
@@ -72,6 +72,10 @@
nativeMain {
dependsOn(commonMain)
}
+
+ nativeTest {
+ dependsOn(commonTest)
+ }
}
targets.all { target ->
@@ -79,6 +83,9 @@
target.compilations["main"].defaultSourceSet {
dependsOn(nativeMain)
}
+ target.compilations["test"].defaultSourceSet {
+ dependsOn(nativeTest)
+ }
}
}
diff --git a/kruth/kruth/src/commonMain/kotlin/androidx/kruth/HelperArraySubject.kt b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/HelperArraySubject.kt
new file mode 100644
index 0000000..029e460
--- /dev/null
+++ b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/HelperArraySubject.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2023 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.kruth
+
+internal class HelperArraySubject<out T>(
+ actual: T?,
+ private val size: (T) -> Int,
+ metadata: FailureMetadata = FailureMetadata(),
+) : Subject<T>(actual = actual, metadata = metadata) {
+
+ /** Fails if the array is not empty (i.e. `array.size > 0`). */
+ fun isEmpty() {
+ metadata.assertNotNull(actual) { "Expected array to be empty, but was null" }
+
+ if (size(actual) > 0) {
+ failWithActual(Fact.simpleFact("Expected to be empty"))
+ }
+ }
+
+ /** Fails if the array is empty (i.e. `array.size == 0`). */
+ fun isNotEmpty() {
+ metadata.assertNotNull(actual) { "Expected array not to be empty, but was null" }
+
+ if (size(actual) == 0) {
+ failWithoutActual(Fact.simpleFact("Expected not to be empty"))
+ }
+ }
+
+ /**
+ * Fails if the array does not have the given length.
+ *
+ * @throws IllegalArgumentException if [length] < 0
+ */
+ fun hasLength(length: Int) {
+ require(length >= 0) { "length (%d) must be >= 0" }
+
+ metadata.assertNotNull(actual) { "Expected length to be equal to $length, but was null" }
+
+ val actualSize = size(actual)
+ metadata.assertEquals(length, actualSize) {
+ "Expected length to be equal to $length, but was $actualSize"
+ }
+ }
+}
diff --git a/kruth/kruth/src/commonMain/kotlin/androidx/kruth/Kruth.kt b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/Kruth.kt
index 5454dfa..9e6da3f 100644
--- a/kruth/kruth/src/commonMain/kotlin/androidx/kruth/Kruth.kt
+++ b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/Kruth.kt
@@ -51,9 +51,33 @@
fun <T> assertThat(actual: Iterable<T>?): IterableSubject<T> =
IterableSubject(actual)
+fun <T> assertThat(actual: Array<out T>?): ObjectArraySubject<T> =
+ ObjectArraySubject(actual)
+
+fun assertThat(actual: BooleanArray?): PrimitiveBooleanArraySubject =
+ PrimitiveBooleanArraySubject(actual)
+
+fun assertThat(actual: ShortArray?): PrimitiveShortArraySubject =
+ PrimitiveShortArraySubject(actual)
+
+fun assertThat(actual: IntArray?): PrimitiveIntArraySubject =
+ PrimitiveIntArraySubject(actual)
+
+fun assertThat(actual: LongArray?): PrimitiveLongArraySubject =
+ PrimitiveLongArraySubject(actual)
+
fun assertThat(actual: ByteArray?): PrimitiveByteArraySubject =
PrimitiveByteArraySubject(actual)
+fun assertThat(actual: CharArray?): PrimitiveCharArraySubject =
+ PrimitiveCharArraySubject(actual)
+
+fun assertThat(actual: FloatArray?): PrimitiveFloatArraySubject =
+ PrimitiveFloatArraySubject(actual)
+
+fun assertThat(actual: DoubleArray?): PrimitiveDoubleArraySubject =
+ PrimitiveDoubleArraySubject(actual)
+
fun <K, V> assertThat(actual: Map<K, V>?): MapSubject<K, V> =
MapSubject(actual)
diff --git a/kruth/kruth/src/commonMain/kotlin/androidx/kruth/ObjectArraySubject.kt b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/ObjectArraySubject.kt
new file mode 100644
index 0000000..fb4125a
--- /dev/null
+++ b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/ObjectArraySubject.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2023 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.kruth
+
+/**
+ * A Subject for object arrays.
+ */
+class ObjectArraySubject<T> internal constructor(
+ actual: Array<out T>?,
+ metadata: FailureMetadata = FailureMetadata(),
+) : Subject<Array<out T>>(actual = actual, metadata = metadata) {
+
+ private val helper =
+ HelperArraySubject(
+ actual = actual,
+ size = Array<*>::size,
+ metadata = metadata,
+ )
+
+ /** Fails if the array is not empty (i.e. `array.size > 0`). */
+ fun isEmpty() {
+ helper.isEmpty()
+ }
+
+ /** Fails if the array is empty (i.e. `array.size == 0`). */
+ fun isNotEmpty() {
+ helper.isNotEmpty()
+ }
+
+ /**
+ * Fails if the array does not have the given length.
+ *
+ * @throws IllegalArgumentException if [length] < 0
+ */
+ fun hasLength(length: Int) {
+ helper.hasLength(length)
+ }
+
+ /** Converts this [ObjectArraySubject] to [IterableSubject].*/
+ fun asList(): IterableSubject<*> {
+ metadata.assertNotNull(actual)
+
+ return IterableSubject(actual = actual.toList(), metadata = metadata)
+ }
+}
diff --git a/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveBooleanArraySubject.kt b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveBooleanArraySubject.kt
new file mode 100644
index 0000000..e260fb7
--- /dev/null
+++ b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveBooleanArraySubject.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2023 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.kruth
+
+/**
+ * A Subject for [Boolean] arrays.
+ */
+class PrimitiveBooleanArraySubject internal constructor(
+ actual: BooleanArray?,
+ metadata: FailureMetadata = FailureMetadata(),
+) : Subject<BooleanArray?>(actual = actual, metadata = metadata) {
+
+ private val helper =
+ HelperArraySubject(
+ actual = actual,
+ size = BooleanArray::size,
+ metadata = metadata,
+ )
+
+ /** Fails if the array is not empty (i.e. `array.size > 0`). */
+ fun isEmpty() {
+ helper.isEmpty()
+ }
+
+ /** Fails if the array is empty (i.e. `array.size == 0`). */
+ fun isNotEmpty() {
+ helper.isNotEmpty()
+ }
+
+ /**
+ * Fails if the array does not have the given length.
+ *
+ * @throws IllegalArgumentException if [length] < 0
+ */
+ fun hasLength(length: Int) {
+ helper.hasLength(length)
+ }
+
+ /** Converts this [PrimitiveBooleanArraySubject] to [IterableSubject].*/
+ fun asList(): IterableSubject<Boolean> {
+ metadata.assertNotNull(actual)
+
+ return IterableSubject(actual = actual.asList(), metadata = metadata)
+ }
+}
diff --git a/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveByteArraySubject.kt b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveByteArraySubject.kt
index f9a044a..98ff764 100644
--- a/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveByteArraySubject.kt
+++ b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveByteArraySubject.kt
@@ -16,29 +16,26 @@
package androidx.kruth
-import androidx.kruth.Fact.Companion.simpleFact
-
class PrimitiveByteArraySubject internal constructor(
actual: ByteArray?,
metadata: FailureMetadata = FailureMetadata(),
) : Subject<ByteArray?>(actual = actual, metadata = metadata) {
+ private val helper =
+ HelperArraySubject(
+ actual = actual,
+ size = ByteArray::size,
+ metadata = metadata,
+ )
+
/** Fails if the array is not empty (i.e. `array.size > 0`). */
fun isEmpty() {
- metadata.assertNotNull(actual) { "Expected array to be empty, but was null" }
-
- if (actual.isNotEmpty()) {
- failWithActual(simpleFact("Expected to be empty"))
- }
+ helper.isEmpty()
}
/** Fails if the array is empty (i.e. `array.size == 0`). */
fun isNotEmpty() {
- metadata.assertNotNull(actual) { "Expected array not to be empty, but was null" }
-
- if (actual.isEmpty()) {
- failWithoutActual(simpleFact("Expected not to be empty"))
- }
+ helper.isNotEmpty()
}
/**
@@ -47,19 +44,13 @@
* @throws IllegalArgumentException if [length] < 0
*/
fun hasLength(length: Int) {
- require(length >= 0) { "length (%d) must be >= 0" }
-
- metadata.assertNotNull(actual) { "Expected length to be equal to $length, but was null" }
-
- metadata.assertEquals(length, actual.size) {
- "Expected length to be equal to $length, but was ${actual.size}"
- }
+ helper.hasLength(length)
}
/** Converts this [PrimitiveByteArraySubject] to [IterableSubject].*/
fun asList(): IterableSubject<Byte> {
metadata.assertNotNull(actual)
- return IterableSubject(actual = actual.toList(), metadata = metadata)
+ return IterableSubject(actual = actual.asList(), metadata = metadata)
}
}
diff --git a/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveCharArraySubject.kt b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveCharArraySubject.kt
new file mode 100644
index 0000000..d11c068
--- /dev/null
+++ b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveCharArraySubject.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2023 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.kruth
+
+/**
+ * A Subject for [Char] arrays.
+ */
+class PrimitiveCharArraySubject internal constructor(
+ actual: CharArray?,
+ metadata: FailureMetadata = FailureMetadata(),
+) : Subject<CharArray?>(actual = actual, metadata = metadata) {
+
+ private val helper =
+ HelperArraySubject(
+ actual = actual,
+ size = CharArray::size,
+ metadata = metadata,
+ )
+
+ /** Fails if the array is not empty (i.e. `array.size > 0`). */
+ fun isEmpty() {
+ helper.isEmpty()
+ }
+
+ /** Fails if the array is empty (i.e. `array.size == 0`). */
+ fun isNotEmpty() {
+ helper.isNotEmpty()
+ }
+
+ /**
+ * Fails if the array does not have the given length.
+ *
+ * @throws IllegalArgumentException if [length] < 0
+ */
+ fun hasLength(length: Int) {
+ helper.hasLength(length)
+ }
+
+ /** Converts this [PrimitiveBooleanArraySubject] to [IterableSubject].*/
+ fun asList(): IterableSubject<Char> {
+ metadata.assertNotNull(actual)
+
+ return IterableSubject(actual = actual.asList(), metadata = metadata)
+ }
+}
diff --git a/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveDoubleArraySubject.kt b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveDoubleArraySubject.kt
new file mode 100644
index 0000000..8ffcce7
--- /dev/null
+++ b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveDoubleArraySubject.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2023 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.kruth
+
+/**
+ * A Subject for [Char] arrays.
+ */
+class PrimitiveDoubleArraySubject internal constructor(
+ actual: DoubleArray?,
+ metadata: FailureMetadata = FailureMetadata(),
+) : Subject<DoubleArray?>(actual = actual, metadata = metadata) {
+
+ private val helper =
+ HelperArraySubject(
+ actual = actual,
+ size = DoubleArray::size,
+ metadata = metadata,
+ )
+
+ /**
+ * A check that the actual array and [expected] are arrays of the same length and type,
+ * containing elements such that each element in [expected] is equal to each element in the
+ * actual array, and in the same position, with element equality defined the same way that
+ * [Double.equals] define it (which is different to the way that the `==` operator on primitive
+ * [Double] defines it). This method is *not* recommended when the code under test is doing any
+ * kind of arithmetic: use `usingTolerance` with a suitable tolerance in that case, e.g.
+ * `assertThat(actualArray).usingTolerance(1.0e-10).containsExactly(expectedArray).inOrder()`.
+ * (Remember that the exact result of floating point arithmetic is sensitive to apparently
+ * trivial changes such as replacing `(a + b) + c` with `a + (b + c)`, and that unless
+ * `strictfp` is in force even the result of `(a + b) + c` is sensitive to the JVM's choice of
+ * precision for the intermediate result.) This method is recommended when the code under test
+ * is specified as either copying values without modification from its input or returning
+ * well-defined literal or constant values.
+ *
+ * - It considers [Double.POSITIVE_INFINITY], [Double.NEGATIVE_INFINITY], and
+ * [Double.NaN] to be equal to themselves (contrast with `usingTolerance(0.0)` which does not).
+ * - It does *not* consider `-0.0` to be equal to `0.0` (contrast with `usingTolerance(0.0)`
+ * which does).
+ */
+ @Suppress("RedundantOverride") // Documented
+ override fun isEqualTo(expected: Any?) {
+ super.isEqualTo(expected)
+ }
+
+ /**
+ * A check that the actual array and [unexpected] are not arrays of the same length and type,
+ * containing elements such that each element in [unexpected] is equal to each element in the
+ * actual array, and in the same position, with element equality defined the same way that
+ * [Double.equals] define it (which is different to the way that the `==` operator on primitive
+ * [Double] defines it). See [isEqualTo] for advice on when exact equality is recommended.
+ *
+ * - It considers [Double.POSITIVE_INFINITY], [Double.NEGATIVE_INFINITY], and [Double.NaN] to be
+ * equal to themselves.
+ * - It does *not* consider `-0.0` to be equal to `0.0`.
+ */
+ @Suppress("RedundantOverride") // Documented
+ override fun isNotEqualTo(unexpected: Any?) {
+ super.isNotEqualTo(unexpected)
+ }
+
+ /** Fails if the array is not empty (i.e. `array.size > 0`). */
+ fun isEmpty() {
+ helper.isEmpty()
+ }
+
+ /** Fails if the array is empty (i.e. `array.size == 0`). */
+ fun isNotEmpty() {
+ helper.isNotEmpty()
+ }
+
+ /**
+ * Fails if the array does not have the given length.
+ *
+ * @throws IllegalArgumentException if [length] < 0
+ */
+ fun hasLength(length: Int) {
+ helper.hasLength(length)
+ }
+
+ /** Converts this [PrimitiveBooleanArraySubject] to [IterableSubject].*/
+ fun asList(): IterableSubject<Double> {
+ metadata.assertNotNull(actual)
+
+ return IterableSubject(actual = actual.asList(), metadata = metadata)
+ }
+}
diff --git a/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveFloatArraySubject.kt b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveFloatArraySubject.kt
new file mode 100644
index 0000000..c2b7deaa
--- /dev/null
+++ b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveFloatArraySubject.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2023 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.kruth
+
+/**
+ * A Subject for [Char] arrays.
+ */
+class PrimitiveFloatArraySubject internal constructor(
+ actual: FloatArray?,
+ metadata: FailureMetadata = FailureMetadata(),
+) : Subject<FloatArray?>(actual = actual, metadata = metadata) {
+
+ private val helper =
+ HelperArraySubject(
+ actual = actual,
+ size = FloatArray::size,
+ metadata = metadata,
+ )
+
+ /**
+ * A check that the actual array and [expected] are arrays of the same length and type,
+ * containing elements such that each element in [expected] is equal to each element in the
+ * actual array, and in the same position, with element equality defined the same way that
+ * [Float.equals] define it (which is different to the way that the `==` operator on primitive
+ * [Float] defines it). This method is *not* recommended when the code under test is doing any
+ * kind of arithmetic: use `usingTolerance` with a suitable tolerance in that case, e.g.
+ * `assertThat(actualArray).usingTolerance(1.0e-10).containsExactly(expectedArray).inOrder()`.
+ * (Remember that the exact result of floating point arithmetic is sensitive to apparently
+ * trivial changes such as replacing `(a + b) + c` with `a + (b + c)`, and that unless
+ * `strictfp` is in force even the result of `(a + b) + c` is sensitive to the JVM's choice of
+ * precision for the intermediate result.) This method is recommended when the code under test
+ * is specified as either copying values without modification from its input or returning
+ * well-defined literal or constant values.
+ *
+ * - It considers [Float.POSITIVE_INFINITY], [Float.NEGATIVE_INFINITY], and
+ * [Float.NaN] to be equal to themselves (contrast with `usingTolerance(0.0)` which does not).
+ * - It does *not* consider `-0.0` to be equal to `0.0` (contrast with `usingTolerance(0.0)`
+ * which does).
+ */
+ @Suppress("RedundantOverride") // Documented
+ override fun isEqualTo(expected: Any?) {
+ super.isEqualTo(expected)
+ }
+
+ /**
+ * A check that the actual array and [unexpected] are not arrays of the same length and type,
+ * containing elements such that each element in [unexpected] is equal to each element in the
+ * actual array, and in the same position, with element equality defined the same way that
+ * [Float.equals] define it (which is different to the way that the `==` operator on primitive
+ * [Float] defines it). See [isEqualTo] for advice on when exact equality is recommended.
+ *
+ * - It considers [Float.POSITIVE_INFINITY], [Float.NEGATIVE_INFINITY], and [Float.NaN] to be
+ * equal to themselves.
+ * - It does *not* consider `-0.0` to be equal to `0.0`.
+ */
+ @Suppress("RedundantOverride") // Documented
+ override fun isNotEqualTo(unexpected: Any?) {
+ super.isNotEqualTo(unexpected)
+ }
+
+ /** Fails if the array is not empty (i.e. `array.size > 0`). */
+ fun isEmpty() {
+ helper.isEmpty()
+ }
+
+ /** Fails if the array is empty (i.e. `array.size == 0`). */
+ fun isNotEmpty() {
+ helper.isNotEmpty()
+ }
+
+ /**
+ * Fails if the array does not have the given length.
+ *
+ * @throws IllegalArgumentException if [length] < 0
+ */
+ fun hasLength(length: Int) {
+ helper.hasLength(length)
+ }
+
+ /** Converts this [PrimitiveBooleanArraySubject] to [IterableSubject].*/
+ fun asList(): IterableSubject<Float> {
+ metadata.assertNotNull(actual)
+
+ return IterableSubject(actual = actual.asList(), metadata = metadata)
+ }
+}
diff --git a/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveIntArraySubject.kt b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveIntArraySubject.kt
new file mode 100644
index 0000000..b4b1a4f
--- /dev/null
+++ b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveIntArraySubject.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2023 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.kruth
+
+/**
+ * A Subject for [Char] arrays.
+ */
+class PrimitiveIntArraySubject internal constructor(
+ actual: IntArray?,
+ metadata: FailureMetadata = FailureMetadata(),
+) : Subject<IntArray?>(actual = actual, metadata = metadata) {
+
+ private val helper =
+ HelperArraySubject(
+ actual = actual,
+ size = IntArray::size,
+ metadata = metadata,
+ )
+
+ /** Fails if the array is not empty (i.e. `array.size > 0`). */
+ fun isEmpty() {
+ helper.isEmpty()
+ }
+
+ /** Fails if the array is empty (i.e. `array.size == 0`). */
+ fun isNotEmpty() {
+ helper.isNotEmpty()
+ }
+
+ /**
+ * Fails if the array does not have the given length.
+ *
+ * @throws IllegalArgumentException if [length] < 0
+ */
+ fun hasLength(length: Int) {
+ helper.hasLength(length)
+ }
+
+ /** Converts this [PrimitiveBooleanArraySubject] to [IterableSubject].*/
+ fun asList(): IterableSubject<Int> {
+ metadata.assertNotNull(actual)
+
+ return IterableSubject(actual = actual.asList(), metadata = metadata)
+ }
+}
diff --git a/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveLongArraySubject.kt b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveLongArraySubject.kt
new file mode 100644
index 0000000..934506b
--- /dev/null
+++ b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveLongArraySubject.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2023 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.kruth
+
+/**
+ * A Subject for [Char] arrays.
+ */
+class PrimitiveLongArraySubject internal constructor(
+ actual: LongArray?,
+ metadata: FailureMetadata = FailureMetadata(),
+) : Subject<LongArray?>(actual = actual, metadata = metadata) {
+
+ private val helper =
+ HelperArraySubject(
+ actual = actual,
+ size = LongArray::size,
+ metadata = metadata,
+ )
+
+ /** Fails if the array is not empty (i.e. `array.size > 0`). */
+ fun isEmpty() {
+ helper.isEmpty()
+ }
+
+ /** Fails if the array is empty (i.e. `array.size == 0`). */
+ fun isNotEmpty() {
+ helper.isNotEmpty()
+ }
+
+ /**
+ * Fails if the array does not have the given length.
+ *
+ * @throws IllegalArgumentException if [length] < 0
+ */
+ fun hasLength(length: Int) {
+ helper.hasLength(length)
+ }
+
+ /** Converts this [PrimitiveBooleanArraySubject] to [IterableSubject].*/
+ fun asList(): IterableSubject<Long> {
+ metadata.assertNotNull(actual)
+
+ return IterableSubject(actual = actual.asList(), metadata = metadata)
+ }
+}
diff --git a/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveShortArraySubject.kt b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveShortArraySubject.kt
new file mode 100644
index 0000000..d0231d7
--- /dev/null
+++ b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/PrimitiveShortArraySubject.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2023 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.kruth
+
+/**
+ * A Subject for [Char] arrays.
+ */
+class PrimitiveShortArraySubject internal constructor(
+ actual: ShortArray?,
+ metadata: FailureMetadata = FailureMetadata(),
+) : Subject<ShortArray?>(actual = actual, metadata = metadata) {
+
+ private val helper =
+ HelperArraySubject(
+ actual = actual,
+ size = ShortArray::size,
+ metadata = metadata,
+ )
+
+ /** Fails if the array is not empty (i.e. `array.size > 0`). */
+ fun isEmpty() {
+ helper.isEmpty()
+ }
+
+ /** Fails if the array is empty (i.e. `array.size == 0`). */
+ fun isNotEmpty() {
+ helper.isNotEmpty()
+ }
+
+ /**
+ * Fails if the array does not have the given length.
+ *
+ * @throws IllegalArgumentException if [length] < 0
+ */
+ fun hasLength(length: Int) {
+ helper.hasLength(length)
+ }
+
+ /** Converts this [PrimitiveBooleanArraySubject] to [IterableSubject].*/
+ fun asList(): IterableSubject<Short> {
+ metadata.assertNotNull(actual)
+
+ return IterableSubject(actual = actual.asList(), metadata = metadata)
+ }
+}
diff --git a/kruth/kruth/src/commonMain/kotlin/androidx/kruth/StandardSubjectBuilder.kt b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/StandardSubjectBuilder.kt
index fc5ebc5..fc9e951 100644
--- a/kruth/kruth/src/commonMain/kotlin/androidx/kruth/StandardSubjectBuilder.kt
+++ b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/StandardSubjectBuilder.kt
@@ -33,7 +33,7 @@
* Returns a new instance that invokes the given [FailureStrategy] when a check fails.
*/
@JvmStatic
- fun forCustomFailureStrategy(failureStrategy: FailureStrategy): StandardSubjectBuilder? {
+ fun forCustomFailureStrategy(failureStrategy: FailureStrategy): StandardSubjectBuilder {
return StandardSubjectBuilder(FailureMetadata.forFailureStrategy(failureStrategy))
}
}
@@ -70,9 +70,33 @@
fun <T> that(actual: Iterable<T>?): IterableSubject<T> =
IterableSubject(actual = actual, metadata = metadata)
+ fun <T> that(actual: Array<out T>?): ObjectArraySubject<T> =
+ ObjectArraySubject(actual = actual, metadata = metadata)
+
+ fun that(actual: BooleanArray?): PrimitiveBooleanArraySubject =
+ PrimitiveBooleanArraySubject(actual = actual, metadata = metadata)
+
+ fun that(actual: ShortArray?): PrimitiveShortArraySubject =
+ PrimitiveShortArraySubject(actual = actual, metadata = metadata)
+
+ fun that(actual: IntArray?): PrimitiveIntArraySubject =
+ PrimitiveIntArraySubject(actual = actual, metadata = metadata)
+
+ fun that(actual: LongArray?): PrimitiveLongArraySubject =
+ PrimitiveLongArraySubject(actual = actual, metadata = metadata)
+
fun that(actual: ByteArray?): PrimitiveByteArraySubject =
PrimitiveByteArraySubject(actual = actual, metadata = metadata)
+ fun that(actual: CharArray?): PrimitiveCharArraySubject =
+ PrimitiveCharArraySubject(actual = actual, metadata = metadata)
+
+ fun that(actual: FloatArray?): PrimitiveFloatArraySubject =
+ PrimitiveFloatArraySubject(actual = actual, metadata = metadata)
+
+ fun that(actual: DoubleArray?): PrimitiveDoubleArraySubject =
+ PrimitiveDoubleArraySubject(actual = actual, metadata = metadata)
+
fun <K, V> that(actual: Map<K, V>?): MapSubject<K, V> =
MapSubject(actual = actual, metadata = metadata)
diff --git a/kruth/kruth/src/commonTest/kotlin/androidx/kruth/ObjectArraySubjectTest.kt b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/ObjectArraySubjectTest.kt
new file mode 100644
index 0000000..4ece17a
--- /dev/null
+++ b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/ObjectArraySubjectTest.kt
@@ -0,0 +1,279 @@
+/*
+ * Copyright 2023 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.kruth
+
+import kotlin.test.Test
+import kotlin.test.assertFailsWith
+import kotlin.test.fail
+
+class ObjectArraySubjectTest {
+
+ @Test
+ fun isEqualTo() {
+ assertThat(arrayOf("A", 5L)).isEqualTo(arrayOf("A", 5L))
+ }
+
+ @Test
+ fun isEqualTo_same() {
+ val same = arrayOf("A", 5L)
+ assertThat(same).isEqualTo(same)
+ }
+
+ @Test
+ fun asList() {
+ assertThat(arrayOf("A", 5L)).asList().contains("A")
+ }
+
+ @Test
+ fun hasLength() {
+ assertThat(emptyArray<Any>()).hasLength(0)
+ assertThat(arrayOf("A", 5L)).hasLength(2)
+ assertThat(arrayOf<Array<Any>>()).hasLength(0)
+ assertThat(arrayOf<Array<Any>>(emptyArray())).hasLength(1)
+ }
+
+ @Test
+ fun hasLengthFail() {
+ assertFailsWith<AssertionError> {
+ assertThat(arrayOf("A", 5L)).hasLength(1)
+ }
+ }
+
+ @Test
+ fun hasLengthMultiFail() {
+ assertFailsWith<AssertionError> {
+ assertThat(arrayOf<Array<Any>>(arrayOf("A"), arrayOf(5L))).hasLength(1)
+ }
+ }
+
+ @Test
+ fun hasLengthNegative() {
+ try {
+ assertThat(arrayOf(2, 5)).hasLength(-1)
+ fail("Should have failed")
+ } catch (expected: IllegalArgumentException) {
+ // no-op
+ }
+ }
+
+ @Test
+ fun isEmpty() {
+ assertThat(emptyArray<Any>()).isEmpty()
+ assertThat(arrayOf<Array<Any>>()).isEmpty()
+ }
+
+ @Test
+ fun isEmptyFail() {
+ assertFailsWith<AssertionError> {
+ assertThat(arrayOf("A", 5L)).isEmpty()
+ }
+ }
+
+ @Test
+ fun isNotEmpty() {
+ assertThat(arrayOf("A", 5L)).isNotEmpty()
+ assertThat(arrayOf(arrayOf("A"), arrayOf(5L))).isNotEmpty()
+ }
+
+ @Test
+ fun isNotEmptyFail() {
+ assertFailsWith<AssertionError> {
+ assertThat(emptyArray<Any>()).isNotEmpty()
+ }
+ }
+
+ @Test
+ fun isEqualTo_fail_unequalOrdering() {
+ assertFailsWith<AssertionError> {
+ assertThat(arrayOf("A", 5L)).isEqualTo(arrayOf(5L, "A"))
+ }
+ }
+
+ @Test
+ fun isEqualTo_fail_unequalOrderingMultiDimensional_00() {
+ assertFailsWith<AssertionError> {
+ assertThat(arrayOf(arrayOf("A"), arrayOf(5L)))
+ .isEqualTo(arrayOf(arrayOf(5L), arrayOf("A")))
+ }
+ }
+
+ @Test
+ fun isEqualTo_fail_unequalOrderingMultiDimensional_01() {
+ assertFailsWith<AssertionError> {
+ assertThat(arrayOf(arrayOf("A", "B"), arrayOf(5L)))
+ .isEqualTo(arrayOf(arrayOf("A"), arrayOf(5L)))
+ }
+ }
+
+ @Test
+ fun isEqualTo_fail_unequalOrderingMultiDimensional_11() {
+ assertFailsWith<AssertionError> {
+ assertThat(arrayOf(arrayOf("A"), arrayOf(5L)))
+ .isEqualTo(arrayOf(arrayOf("A"), arrayOf(5L, 6L)))
+ }
+ }
+
+ @Test
+ fun isEqualTo_fail_notAnArray() {
+ assertFailsWith<AssertionError> {
+ assertThat(arrayOf("A", 5L)).isEqualTo(Any())
+ }
+ }
+
+ @Test
+ fun isNotEqualTo_sameLengths() {
+ assertThat(arrayOf("A", 5L)).isNotEqualTo(arrayOf("C", 5L))
+ assertThat(arrayOf(arrayOf("A"), arrayOf(5L)))
+ .isNotEqualTo(arrayOf(arrayOf("C"), arrayOf(5L)))
+ }
+
+ @Test
+ fun isNotEqualTo_differentLengths() {
+ assertThat(arrayOf("A", 5L)).isNotEqualTo(arrayOf("A", 5L, "c"))
+ assertThat(arrayOf(arrayOf("A"), arrayOf(5L)))
+ .isNotEqualTo(arrayOf(arrayOf("A", "c"), arrayOf(5L)))
+ assertThat(arrayOf(arrayOf("A"), arrayOf(5L)))
+ .isNotEqualTo(arrayOf(arrayOf("A"), arrayOf(5L), arrayOf("C")))
+ }
+
+ @Test
+ fun isNotEqualTo_differentTypes() {
+ assertThat(arrayOf("A", 5L)).isNotEqualTo(Any())
+ }
+
+ @Test
+ fun isNotEqualTo_failEquals() {
+ assertFailsWith<AssertionError> {
+ assertThat(arrayOf("A", 5L)).isNotEqualTo(arrayOf("A", 5L))
+ }
+ }
+
+ @Test
+ fun isNotEqualTo_failEqualsMultiDimensional() {
+ assertFailsWith<AssertionError> {
+ assertThat(arrayOf(arrayOf("A"), arrayOf(5L)))
+ .isNotEqualTo(arrayOf(arrayOf("A"), arrayOf(5L)))
+ }
+ }
+
+ @Test
+ fun isNotEqualTo_failSame() {
+ val same = arrayOf("A", 5L)
+ assertFailsWith<AssertionError> {
+ assertThat(same).isNotEqualTo(same)
+ }
+ }
+
+ @Test
+ fun isNotEqualTo_failSameMultiDimensional() {
+ val same = arrayOf(arrayOf("A"), arrayOf(5L))
+ assertFailsWith<AssertionError> {
+ assertThat(same).isNotEqualTo(same)
+ }
+ }
+
+ @Test
+ fun stringArrayIsEqualTo() {
+ assertThat(arrayOf("A", "B")).isEqualTo(arrayOf("A", "B"))
+ assertThat(arrayOf(arrayOf("A"), arrayOf("B")))
+ .isEqualTo(arrayOf(arrayOf("A"), arrayOf("B")))
+ }
+
+ @Test
+ fun stringArrayAsList() {
+ assertThat(arrayOf("A", "B")).asList().contains("A")
+ }
+
+ @Test
+ fun multiDimensionalStringArrayAsList() {
+ val ab = arrayOf("A", "B")
+ assertThat(arrayOf(ab, arrayOf("C"))).asList().contains(ab)
+ }
+
+ @Test
+ fun stringArrayIsEqualTo_fail_unequalLength() {
+ assertFailsWith<AssertionError> {
+ assertThat(arrayOf("A", "B")).isEqualTo(arrayOf("B"))
+ }
+ }
+
+ @Test
+ fun stringArrayIsEqualTo_fail_unequalLengthMultiDimensional() {
+ assertFailsWith<AssertionError> {
+ assertThat(arrayOf(arrayOf("A"), arrayOf("B")))
+ .isEqualTo(arrayOf(arrayOf("A")))
+ }
+ }
+
+ @Test
+ fun stringArrayIsEqualTo_fail_unequalOrdering() {
+ assertFailsWith<AssertionError> {
+ assertThat(arrayOf("A", "B")).isEqualTo(arrayOf("B", "A"))
+ }
+ }
+
+ @Test
+ fun stringArrayIsEqualTo_fail_unequalOrderingMultiDimensional() {
+ assertFailsWith<AssertionError> {
+ assertThat(arrayOf(arrayOf("A"), arrayOf("B")))
+ .isEqualTo(arrayOf(arrayOf("B"), arrayOf("A")))
+ }
+ }
+
+ @Test
+ fun setArrayIsEqualTo_fail_unequalOrdering() {
+ assertFailsWith<AssertionError> {
+ assertThat(arrayOf(setOf("A"), setOf("B")))
+ .isEqualTo(arrayOf(setOf("B"), setOf("A")))
+ }
+ }
+
+ @Test
+ fun primitiveMultiDimensionalArrayIsEqualTo() {
+ assertThat(arrayOf(intArrayOf(1, 2), intArrayOf(3), intArrayOf(4, 5, 6)))
+ .isEqualTo(arrayOf(intArrayOf(1, 2), intArrayOf(3), intArrayOf(4, 5, 6)))
+ }
+
+ @Test
+ fun primitiveMultiDimensionalArrayIsEqualTo_fail_unequalOrdering() {
+ assertFailsWith<AssertionError> {
+ assertThat(arrayOf(intArrayOf(1, 2), intArrayOf(3), intArrayOf(4, 5, 6)))
+ .isEqualTo(arrayOf(intArrayOf(1, 2), intArrayOf(3), intArrayOf(4, 5, 6, 7)))
+ }
+ }
+
+ @Test
+ fun primitiveMultiDimensionalArrayIsNotEqualTo() {
+ assertThat(arrayOf(intArrayOf(1, 2), intArrayOf(3), intArrayOf(4, 5, 6)))
+ .isNotEqualTo(arrayOf(intArrayOf(1, 2), intArrayOf(3), intArrayOf(4, 5, 6, 7)))
+ }
+
+ @Test
+ fun primitiveMultiDimensionalArrayIsNotEqualTo_fail_equal() {
+ assertFailsWith<AssertionError> {
+ assertThat(arrayOf(intArrayOf(1, 2), intArrayOf(3), intArrayOf(4, 5, 6)))
+ .isNotEqualTo(arrayOf(intArrayOf(1, 2), intArrayOf(3), intArrayOf(4, 5, 6)))
+ }
+ }
+
+ @Test
+ fun boxedAndUnboxed() {
+ assertFailsWith<AssertionError> {
+ assertThat(arrayOf(intArrayOf(0))).isEqualTo(arrayOf(arrayOf(0)))
+ }
+ }
+}
diff --git a/kruth/kruth/src/commonTest/kotlin/androidx/kruth/PrimitiveBooleanArraySubjectTest.kt b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/PrimitiveBooleanArraySubjectTest.kt
new file mode 100644
index 0000000..4b23cc5
--- /dev/null
+++ b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/PrimitiveBooleanArraySubjectTest.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2023 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.kruth
+
+import kotlin.test.Test
+import kotlin.test.assertFailsWith
+
+class PrimitiveBooleanArraySubjectTest {
+
+ @Test
+ fun isEqualTo() {
+ assertThat(booleanArrayOf(true, false, true)).isEqualTo(booleanArrayOf(true, false, true))
+ }
+
+ @Test
+ fun isEqualTo_Same() {
+ val same = booleanArrayOf(true, false, true)
+ assertThat(same).isEqualTo(same)
+ }
+
+ @Test
+ fun asList() {
+ assertThat(booleanArrayOf(true, true, false)).asList().containsAtLeast(true, false)
+ }
+
+ @Test
+ fun isEqualTo_Fail_UnequalOrdering() {
+ assertFailsWith<AssertionError> {
+ assertThat(booleanArrayOf(true, false, true))
+ .isEqualTo(booleanArrayOf(false, true, true))
+ }
+ }
+
+ @Test
+ fun isEqualTo_Fail_NotAnArray() {
+ assertFailsWith<AssertionError> {
+ assertThat(booleanArrayOf(true, false, true)).isEqualTo(Any())
+ }
+ }
+
+ @Test
+ fun isNotEqualTo_SameLengths() {
+ assertThat(booleanArrayOf(true, false)).isNotEqualTo(booleanArrayOf(true, true))
+ }
+
+ @Test
+ fun isNotEqualTo_DifferentLengths() {
+ assertThat(booleanArrayOf(true, false)).isNotEqualTo(booleanArrayOf(true, false, true))
+ }
+
+ @Test
+ fun isNotEqualTo_DifferentTypes() {
+ assertThat(booleanArrayOf(true, false)).isNotEqualTo(Any())
+ }
+
+ @Test
+ fun isNotEqualTo_FailEquals() {
+ assertFailsWith<AssertionError> {
+ assertThat(booleanArrayOf(true, false)).isNotEqualTo(booleanArrayOf(true, false))
+ }
+ }
+
+ @Test
+ fun isNotEqualTo_FailSame() {
+ val same = booleanArrayOf(true, false)
+ assertFailsWith<AssertionError> {
+ assertThat(same).isNotEqualTo(same)
+ }
+ }
+}
diff --git a/kruth/kruth/src/commonTest/kotlin/androidx/kruth/PrimitiveCharArraySubjectTest.kt b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/PrimitiveCharArraySubjectTest.kt
new file mode 100644
index 0000000..2ca29ff
--- /dev/null
+++ b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/PrimitiveCharArraySubjectTest.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2023 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.kruth
+
+import kotlin.test.Test
+import kotlin.test.assertFailsWith
+
+class PrimitiveCharArraySubjectTest {
+
+ @Test
+ fun isEqualTo() {
+ assertThat(charArrayOf('a', 'q')).isEqualTo(charArrayOf('a', 'q'))
+ }
+
+ @Test
+ fun isEqualTo_Same() {
+ val same = charArrayOf('a', 'q')
+ assertThat(same).isEqualTo(same)
+ }
+
+ @Test
+ fun asList() {
+ assertThat(charArrayOf('a', 'q', 'z')).asList().containsAtLeast('a', 'z')
+ }
+
+ @Test
+ fun isEqualTo_Fail_UnequalOrdering() {
+ assertFailsWith<AssertionError> {
+ assertThat(charArrayOf('a', 'q')).isEqualTo(charArrayOf('q', 'a'))
+ }
+ }
+
+ @Test
+ fun isEqualTo_Fail_DifferentKindOfcharArrayOf() {
+ assertFailsWith<AssertionError> {
+ assertThat(charArrayOf('a', 'q')).isEqualTo(intArrayOf())
+ }
+ }
+
+ @Test
+ fun isNotEqualTo_SameLengths() {
+ assertThat(charArrayOf('a', 'q')).isNotEqualTo(charArrayOf('q', 'a'))
+ }
+
+ @Test
+ fun isNotEqualTo_DifferentLengths() {
+ assertThat(charArrayOf('a', 'q')).isNotEqualTo(charArrayOf('q', 'a', 'b'))
+ }
+
+ @Test
+ fun isNotEqualTo_DifferentTypes() {
+ assertThat(charArrayOf('a', 'q')).isNotEqualTo(Any())
+ }
+
+ @Test
+ fun isNotEqualTo_FailEquals() {
+ assertFailsWith<AssertionError> {
+ assertThat(charArrayOf('a', 'q')).isNotEqualTo(charArrayOf('a', 'q'))
+ }
+ }
+
+ @Test
+ fun isNotEqualTo_FailSame() {
+ val same = charArrayOf('a', 'q')
+ assertFailsWith<AssertionError> {
+ assertThat(same).isNotEqualTo(same)
+ }
+ }
+}
diff --git a/kruth/kruth/src/commonTest/kotlin/androidx/kruth/PrimitiveDoubleArraySubjectTest.kt b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/PrimitiveDoubleArraySubjectTest.kt
new file mode 100644
index 0000000..5199d0c
--- /dev/null
+++ b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/PrimitiveDoubleArraySubjectTest.kt
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2023 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.kruth
+
+import kotlin.Double.Companion.NEGATIVE_INFINITY
+import kotlin.Double.Companion.NaN
+import kotlin.Double.Companion.POSITIVE_INFINITY
+import kotlin.math.nextDown
+import kotlin.math.nextUp
+import kotlin.test.Test
+import kotlin.test.assertFailsWith
+
+class PrimitiveDoubleArraySubjectTest {
+
+ @Test
+ fun testDoubleConstants_matchNextAfter() {
+ assertThat((2.0 + DEFAULT_TOLERANCE).nextDown()).isEqualTo(TOLERABLE_2)
+ assertThat((2.2 + DEFAULT_TOLERANCE).nextDown()).isEqualTo(TOLERABLE_2POINT2)
+ assertThat((2.2 + DEFAULT_TOLERANCE).nextUp()).isEqualTo(INTOLERABLE_2POINT2)
+ assertThat(2.2.nextUp()).isEqualTo(OVER_2POINT2)
+ assertThat((3.3 + DEFAULT_TOLERANCE).nextDown()).isEqualTo(TOLERABLE_3POINT3)
+ assertThat((3.3 + DEFAULT_TOLERANCE).nextUp()).isEqualTo(INTOLERABLE_3POINT3)
+ assertThat(Long.MIN_VALUE.toDouble().nextDown()).isEqualTo(UNDER_MIN_OF_LONG)
+ }
+
+ @Test
+ fun isEqualTo_WithoutToleranceParameter_Success() {
+ assertThat(doubleArrayOf(2.2, 5.4, POSITIVE_INFINITY, NEGATIVE_INFINITY, 0.0, -0.0))
+ .isEqualTo(doubleArrayOf(2.2, 5.4, POSITIVE_INFINITY, NEGATIVE_INFINITY, 0.0, -0.0))
+ }
+
+ @Test
+ fun isEqualTo_WithoutToleranceParameter_NaN_Success() {
+ val actual = doubleArrayOf(2.2, 5.4, POSITIVE_INFINITY, NEGATIVE_INFINITY, NaN, 0.0, -0.0)
+ val expected = doubleArrayOf(2.2, 5.4, POSITIVE_INFINITY, NEGATIVE_INFINITY, NaN, 0.0, -0.0)
+ assertThat(actual).isEqualTo(expected)
+ }
+
+ @Test
+ fun isEqualTo_WithoutToleranceParameter_Fail_NotEqual() {
+ assertFailsWith<AssertionError> {
+ assertThat(doubleArrayOf(2.2)).isEqualTo(doubleArrayOf(OVER_2POINT2))
+ }
+ }
+
+ @Test
+ fun isEqualTo_WithoutToleranceParameter_Fail_DifferentOrder() {
+ assertFailsWith<AssertionError> {
+ assertThat(doubleArrayOf(2.2, 3.3)).isEqualTo(doubleArrayOf(3.3, 2.2))
+ }
+ }
+
+ @Test
+ fun isEqualTo_WithoutToleranceParameter_Fail_Longer() {
+ assertFailsWith<AssertionError> {
+ assertThat(doubleArrayOf(2.2, 3.3)).isEqualTo(doubleArrayOf(2.2, 3.3, 4.4))
+ }
+ }
+
+ @Test
+ fun isEqualTo_WithoutToleranceParameter_Fail_Shorter() {
+ assertFailsWith<AssertionError> {
+ assertThat(doubleArrayOf(2.2, 3.3)).isEqualTo(doubleArrayOf(2.2))
+ }
+ }
+
+ @Test
+ fun isEqualTo_WithoutToleranceParameter_Fail_PlusMinusZero() {
+ assertFailsWith<AssertionError> {
+ assertThat(doubleArrayOf(0.0)).isEqualTo(doubleArrayOf(-0.0))
+ }
+ }
+
+ @Test
+ fun isEqualTo_WithoutToleranceParameter_Fail_NotAndoubleArrayOf() {
+ assertFailsWith<AssertionError> {
+ assertThat(doubleArrayOf(2.2, 3.3, 4.4)).isEqualTo(Any())
+ }
+ }
+
+ @Test
+ fun isNotEqualTo_WithoutToleranceParameter_FailEquals() {
+ assertFailsWith<AssertionError> {
+ assertThat(doubleArrayOf(2.2, 5.4, POSITIVE_INFINITY, NEGATIVE_INFINITY))
+ .isNotEqualTo(doubleArrayOf(2.2, 5.4, POSITIVE_INFINITY, NEGATIVE_INFINITY))
+ }
+ }
+
+ @Test
+ fun isNotEqualTo_WithoutToleranceParameter_NaN_plusZero_FailEquals() {
+ val actual = doubleArrayOf(2.2, 5.4, POSITIVE_INFINITY, NEGATIVE_INFINITY, NaN, 0.0, -0.0)
+ val expected = doubleArrayOf(2.2, 5.4, POSITIVE_INFINITY, NEGATIVE_INFINITY, NaN, 0.0, -0.0)
+ assertFailsWith<AssertionError> {
+ assertThat(actual).isNotEqualTo(expected)
+ }
+ }
+
+ @Test
+ fun isNotEqualTo_WithoutToleranceParameter_Success_NotEqual() {
+ assertThat(doubleArrayOf(2.2)).isNotEqualTo(doubleArrayOf(OVER_2POINT2))
+ }
+
+ @Test
+ fun isNotEqualTo_WithoutToleranceParameter_Success_DifferentOrder() {
+ assertThat(doubleArrayOf(2.2, 3.3)).isNotEqualTo(doubleArrayOf(3.3, 2.2))
+ }
+
+ @Test
+ fun isNotEqualTo_WithoutToleranceParameter_Success_Longer() {
+ assertThat(doubleArrayOf(2.2, 3.3)).isNotEqualTo(doubleArrayOf(2.2, 3.3, 4.4))
+ }
+
+ @Test
+ fun isNotEqualTo_WithoutToleranceParameter_Success_Shorter() {
+ assertThat(doubleArrayOf(2.2, 3.3)).isNotEqualTo(doubleArrayOf(2.2))
+ }
+
+ @Test
+ fun isNotEqualTo_WithoutToleranceParameter_Success_PlusMinusZero() {
+ assertThat(doubleArrayOf(0.0)).isNotEqualTo(doubleArrayOf(-0.0))
+ }
+
+ @Test
+ fun isNotEqualTo_WithoutToleranceParameter_Success_NotAndoubleArrayOf() {
+ assertThat(doubleArrayOf(2.2, 3.3, 4.4)).isNotEqualTo(Any())
+ }
+
+ @Test
+ fun smallDifferenceInLongRepresentation() {
+ assertFailsWith<AssertionError> {
+ assertThat(doubleArrayOf(-4.4501477170144023E-308))
+ .isEqualTo(doubleArrayOf(-4.450147717014402E-308))
+ }
+ }
+
+ @Test
+ fun noCommas() {
+ assertFailsWith<AssertionError> {
+ assertThat(doubleArrayOf(10000.0)).isEqualTo(doubleArrayOf(20000.0))
+ }
+ }
+
+ private companion object {
+ private const val DEFAULT_TOLERANCE = 0.000005
+ private const val OVER_2POINT2 = 2.2000000000000006
+ private const val TOLERABLE_2 = 2.0000049999999994
+ private const val TOLERABLE_2POINT2 = 2.2000049999999995
+ private const val INTOLERABLE_2POINT2 = 2.2000050000000004
+ private const val TOLERABLE_3POINT3 = 3.300004999999999
+ private const val INTOLERABLE_3POINT3 = 3.300005
+ private const val UNDER_MIN_OF_LONG = -9.223372036854778E18
+ }
+}
diff --git a/kruth/kruth/src/commonTest/kotlin/androidx/kruth/PrimitiveFloatArraySubjectTest.kt b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/PrimitiveFloatArraySubjectTest.kt
new file mode 100644
index 0000000..c2845b5
--- /dev/null
+++ b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/PrimitiveFloatArraySubjectTest.kt
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2023 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.kruth
+
+import kotlin.Float.Companion.NEGATIVE_INFINITY
+import kotlin.Float.Companion.NaN
+import kotlin.Float.Companion.POSITIVE_INFINITY
+import kotlin.test.Test
+import kotlin.test.assertFailsWith
+
+class PrimitiveFloatArraySubjectTest {
+
+ @Test
+ fun testFloatConstants_matchNextAfter() {
+ assertThat(2.2F.nextUp()).isEqualTo(JUST_OVER_2POINT2)
+ assertThat(3.3f.nextUp()).isEqualTo(JUST_OVER_3POINT3)
+ assertThat((3.3f + DEFAULT_TOLERANCE).nextDown()).isEqualTo(TOLERABLE_3POINT3)
+ assertThat((3.3f + DEFAULT_TOLERANCE).nextUp()).isEqualTo(INTOLERABLE_3POINT3)
+ assertThat(Long.MIN_VALUE.toFloat().nextDown()).isEqualTo(UNDER_LONG_MIN)
+ assertThat((2.2f + DEFAULT_TOLERANCE).nextDown()).isEqualTo(TOLERABLE_2POINT2)
+ assertThat((2.2f + DEFAULT_TOLERANCE).nextUp()).isEqualTo(INTOLERABLE_2POINT2)
+ }
+
+ @Test
+ fun isEqualTo_WithoutToleranceParameter_Success() {
+ val actual =
+ floatArrayOf(2.2f, 5.4f, POSITIVE_INFINITY, NEGATIVE_INFINITY, NaN, 0.0f, -0.0f)
+ val expected =
+ floatArrayOf(2.2f, 5.4f, POSITIVE_INFINITY, NEGATIVE_INFINITY, NaN, 0.0f, -0.0f)
+ assertThat(actual).isEqualTo(expected)
+ }
+
+ @Test
+ fun isEqualTo_WithoutToleranceParameter_Fail_NotEqual() {
+ assertFailsWith<AssertionError> {
+ assertThat(floatArrayOf(2.2f)).isEqualTo(floatArrayOf(JUST_OVER_2POINT2))
+ }
+ }
+
+ @Test
+ fun isEqualTo_WithoutToleranceParameter_Fail_DifferentOrder() {
+ assertFailsWith<AssertionError> {
+ assertThat(floatArrayOf(2.2f, 3.3f)).isEqualTo(floatArrayOf(3.3f, 2.2f))
+ }
+ }
+
+ @Test
+ fun isEqualTo_WithoutToleranceParameter_Fail_Longer() {
+ assertFailsWith<AssertionError> {
+ assertThat(floatArrayOf(2.2f, 3.3f)).isEqualTo(floatArrayOf(2.2f, 3.3f, 4.4f))
+ }
+ }
+
+ @Test
+ fun isEqualTo_WithoutToleranceParameter_Fail_Shorter() {
+ assertFailsWith<AssertionError> {
+ assertThat(floatArrayOf(2.2f, 3.3f)).isEqualTo(floatArrayOf(2.2f))
+ }
+ }
+
+ @Test
+ fun isEqualTo_WithoutToleranceParameter_Fail_PlusMinusZero() {
+ assertFailsWith<AssertionError> {
+ assertThat(floatArrayOf(0.0f)).isEqualTo(floatArrayOf(-0.0f))
+ }
+ }
+
+ @Test
+ fun isEqualTo_WithoutToleranceParameter_Fail_NotAnfloatArrayOf() {
+ assertFailsWith<AssertionError> {
+ assertThat(floatArrayOf(2.2f, 3.3f, 4.4f)).isEqualTo(Any())
+ }
+ }
+
+ @Test
+ fun isNotEqualTo_WithoutToleranceParameter_FailEquals() {
+ val actual =
+ floatArrayOf(2.2f, 5.4f, POSITIVE_INFINITY, NEGATIVE_INFINITY, NaN, 0.0f, -0.0f)
+ val expected =
+ floatArrayOf(2.2f, 5.4f, POSITIVE_INFINITY, NEGATIVE_INFINITY, NaN, 0.0f, -0.0f)
+ assertFailsWith<AssertionError> {
+ assertThat(actual).isNotEqualTo(expected)
+ }
+ }
+
+ @Test
+ fun isNotEqualTo_WithoutToleranceParameter_Success_NotEqual() {
+ assertThat(floatArrayOf(2.2f)).isNotEqualTo(floatArrayOf(JUST_OVER_2POINT2))
+ }
+
+ @Test
+ fun isNotEqualTo_WithoutToleranceParameter_Success_DifferentOrder() {
+ assertThat(floatArrayOf(2.2f, 3.3f)).isNotEqualTo(floatArrayOf(3.3f, 2.2f))
+ }
+
+ @Test
+ fun isNotEqualTo_WithoutToleranceParameter_Success_Longer() {
+ assertThat(floatArrayOf(2.2f, 3.3f)).isNotEqualTo(floatArrayOf(2.2f, 3.3f, 4.4f))
+ }
+
+ @Test
+ fun isNotEqualTo_WithoutToleranceParameter_Success_Shorter() {
+ assertThat(floatArrayOf(2.2f, 3.3f)).isNotEqualTo(floatArrayOf(2.2f))
+ }
+
+ @Test
+ fun isNotEqualTo_WithoutToleranceParameter_Success_PlusMinusZero() {
+ assertThat(floatArrayOf(0.0f)).isNotEqualTo(floatArrayOf(-0.0f))
+ }
+
+ @Test
+ fun isNotEqualTo_WithoutToleranceParameter_Success_NotAnfloatArrayOf() {
+ assertThat(floatArrayOf(2.2f, 3.3f, 4.4f)).isNotEqualTo(Any())
+ }
+
+ private companion object {
+ private const val DEFAULT_TOLERANCE = 0.000005f
+ private const val JUST_OVER_2POINT2 = 2.2000003f
+ private const val JUST_OVER_3POINT3 = 3.3000002f
+ private const val TOLERABLE_3POINT3 = 3.3000047f
+ private const val INTOLERABLE_3POINT3 = 3.3000052f
+ private const val UNDER_LONG_MIN = -9.223373E18f
+ private const val TOLERABLE_2POINT2 = 2.2000048f
+ private const val INTOLERABLE_2POINT2 = 2.2000053f
+ }
+}
diff --git a/kruth/kruth/src/commonTest/kotlin/androidx/kruth/PrimitiveIntArraySubjectTest.kt b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/PrimitiveIntArraySubjectTest.kt
new file mode 100644
index 0000000..8a7b1a5
--- /dev/null
+++ b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/PrimitiveIntArraySubjectTest.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2023 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.kruth
+
+import kotlin.test.Test
+import kotlin.test.assertFailsWith
+import kotlin.test.fail
+
+class PrimitiveIntArraySubjectTest {
+
+ @Test
+ fun isEqualTo() {
+ assertThat(intArrayOf(2, 5)).isEqualTo(intArrayOf(2, 5))
+ }
+
+ @Test
+ fun isEqualTo_Same() {
+ val same = intArrayOf(2, 5)
+ assertThat(same).isEqualTo(same)
+ }
+
+ @Test
+ fun asList() {
+ assertThat(intArrayOf(5, 2, 9)).asList().containsAtLeast(2, 9)
+ }
+
+ @Test
+ fun hasLength() {
+ assertThat(intArrayOf()).hasLength(0)
+ assertThat(intArrayOf(2, 5)).hasLength(2)
+ }
+
+ @Test
+ fun hasLengthFail() {
+ assertFailsWith<AssertionError> {
+ assertThat(intArrayOf(2, 5)).hasLength(1)
+ }
+ }
+
+ @Test
+ fun hasLengthNegative() {
+ try {
+ assertThat(intArrayOf(2, 5)).hasLength(-1)
+ fail("Should have failed.")
+ } catch (expected: IllegalArgumentException) {
+ // no-op
+ }
+ }
+
+ @Test
+ fun isEmpty() {
+ assertThat(intArrayOf()).isEmpty()
+ }
+
+ @Test
+ fun isEmptyFail() {
+ assertFailsWith<AssertionError> {
+ assertThat(intArrayOf(2, 5)).isEmpty()
+ }
+ }
+
+ @Test
+ fun isNotEmpty() {
+ assertThat(intArrayOf(2, 5)).isNotEmpty()
+ }
+
+ @Test
+ fun isNotEmptyFail() {
+ assertFailsWith<AssertionError> {
+ assertThat(intArrayOf()).isNotEmpty()
+ }
+ }
+
+ @Test
+ fun isEqualTo_Fail_UnequalOrdering() {
+ assertFailsWith<AssertionError> {
+ assertThat(intArrayOf(2, 3)).isEqualTo(intArrayOf(3, 2))
+ }
+ }
+
+ @Test
+ fun isEqualTo_Fail_NotAnintArrayOf() {
+ assertFailsWith<AssertionError> {
+ assertThat(intArrayOf(2, 3, 4)).isEqualTo(Any())
+ }
+ }
+
+ @Test
+ fun isNotEqualTo_SameLengths() {
+ assertThat(intArrayOf(2, 3)).isNotEqualTo(intArrayOf(3, 2))
+ }
+
+ @Test
+ fun isNotEqualTo_DifferentLengths() {
+ assertThat(intArrayOf(2, 3)).isNotEqualTo(intArrayOf(2, 3, 1))
+ }
+
+ @Test
+ fun isNotEqualTo_DifferentTypes() {
+ assertThat(intArrayOf(2, 3)).isNotEqualTo(Any())
+ }
+
+ @Test
+ fun isNotEqualTo_FailEquals() {
+ assertFailsWith<AssertionError> {
+ assertThat(intArrayOf(2, 3)).isNotEqualTo(intArrayOf(2, 3))
+ }
+ }
+
+ @Test
+ fun isNotEqualTo_FailSame() {
+ val same = intArrayOf(2, 3)
+ assertFailsWith<AssertionError> {
+ assertThat(same).isNotEqualTo(same)
+ }
+ }
+}
diff --git a/kruth/kruth/src/commonTest/kotlin/androidx/kruth/PrimitiveLongArraySubjectTest.kt b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/PrimitiveLongArraySubjectTest.kt
new file mode 100644
index 0000000..9f23b73
--- /dev/null
+++ b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/PrimitiveLongArraySubjectTest.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2023 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.kruth
+
+import kotlin.test.Test
+import kotlin.test.assertFailsWith
+
+class PrimitiveLongArraySubjectTest {
+
+ @Test
+ fun isEqualTo() {
+ assertThat(longArrayOf(2, 5)).isEqualTo(longArrayOf(2, 5))
+ }
+
+ @Test
+ fun isEqualTo_Same() {
+ val same = longArrayOf(2, 5)
+ assertThat(same).isEqualTo(same)
+ }
+
+ @Test
+ fun asList() {
+ assertThat(longArrayOf(5, 2, 9)).asList().containsAtLeast(2L, 9L)
+ }
+
+ @Test
+ fun isEqualTo_Fail_UnequalOrdering() {
+ assertFailsWith<AssertionError> {
+ assertThat(longArrayOf(2, 3)).isEqualTo(longArrayOf(3, 2))
+ }
+ }
+
+ @Test
+ fun isEqualTo_Fail_NotAnlongArrayOf() {
+ assertFailsWith<AssertionError> {
+ assertThat(longArrayOf(2, 3, 4)).isEqualTo(intArrayOf())
+ }
+ }
+
+ @Test
+ fun isNotEqualTo_SameLengths() {
+ assertThat(longArrayOf(2, 3)).isNotEqualTo(longArrayOf(3, 2))
+ }
+
+ @Test
+ fun isNotEqualTo_DifferentLengths() {
+ assertThat(longArrayOf(2, 3)).isNotEqualTo(longArrayOf(2, 3, 1))
+ }
+
+ @Test
+ fun isNotEqualTo_DifferentTypes() {
+ assertThat(longArrayOf(2, 3)).isNotEqualTo(Any())
+ }
+
+ @Test
+ fun isNotEqualTo_FailEquals() {
+ assertFailsWith<AssertionError> {
+ assertThat(longArrayOf(2, 3)).isNotEqualTo(longArrayOf(2, 3))
+ }
+ }
+
+ @Test
+ fun isNotEqualTo_FailSame() {
+ val same = longArrayOf(2, 3)
+ assertFailsWith<AssertionError> {
+ assertThat(same).isNotEqualTo(same)
+ }
+ }
+}
diff --git a/kruth/kruth/src/commonTest/kotlin/androidx/kruth/PrimitiveShortArraySubjectTest.kt b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/PrimitiveShortArraySubjectTest.kt
new file mode 100644
index 0000000..4742fbc
--- /dev/null
+++ b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/PrimitiveShortArraySubjectTest.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2023 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.kruth
+
+import kotlin.test.Test
+import kotlin.test.assertFailsWith
+
+class PrimitiveShortArraySubjectTest {
+
+ @Test
+ fun isEqualTo() {
+ assertThat(shortArrayOf(1, 0, 1)).isEqualTo(shortArrayOf(1, 0, 1))
+ }
+
+ @Test
+ fun isEqualTo_Same() {
+ val same = shortArrayOf(1, 0, 1)
+ assertThat(same).isEqualTo(same)
+ }
+
+ @Test
+ fun asList() {
+ assertThat(shortArrayOf(1, 1, 0)).asList().containsAtLeast(1.toShort(), 0.toShort())
+ }
+
+ @Test
+ fun asListWithoutCastingFails() {
+ assertFailsWith<AssertionError> {
+ assertThat(shortArrayOf(1, 1, 0)).asList().containsAtLeast(1, 0)
+ }
+ }
+
+ @Test
+ fun isEqualTo_Fail_UnequalOrdering() {
+ assertFailsWith<AssertionError> {
+ assertThat(shortArrayOf(1, 0, 1)).isEqualTo(shortArrayOf(0, 1, 1))
+ }
+ }
+
+ @Test
+ fun isEqualTo_Fail_NotAnshortArrayOf() {
+ assertFailsWith<AssertionError> {
+ assertThat(shortArrayOf(1, 0, 1)).isEqualTo(Any())
+ }
+ }
+
+ @Test
+ fun isNotEqualTo_SameLengths() {
+ assertThat(shortArrayOf(1, 0)).isNotEqualTo(shortArrayOf(1, 1))
+ }
+
+ @Test
+ fun isNotEqualTo_DifferentLengths() {
+ assertThat(shortArrayOf(1, 0)).isNotEqualTo(shortArrayOf(1, 0, 1))
+ }
+
+ @Test
+ fun isNotEqualTo_DifferentTypes() {
+ assertThat(shortArrayOf(1, 0)).isNotEqualTo(Any())
+ }
+
+ @Test
+ fun isNotEqualTo_FailEquals() {
+ assertFailsWith<AssertionError> {
+ assertThat(shortArrayOf(1, 0)).isNotEqualTo(shortArrayOf(1, 0))
+ }
+ }
+
+ @Test
+ fun isNotEqualTo_FailSame() {
+ val same = shortArrayOf(1, 0)
+ assertFailsWith<AssertionError> {
+ assertThat(same).isNotEqualTo(same)
+ }
+ }
+}
diff --git a/kruth/kruth/src/commonTest/kotlin/androidx/kruth/TestingUtils.kt b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/TestingUtils.kt
index 4f9dfa1..dffae5e 100644
--- a/kruth/kruth/src/commonTest/kotlin/androidx/kruth/TestingUtils.kt
+++ b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/TestingUtils.kt
@@ -27,3 +27,7 @@
assertEquals(expected = message, actual = e.message)
}
}
+
+internal expect fun Float.nextUp(): Float
+
+internal expect fun Float.nextDown(): Float
diff --git a/kruth/kruth/src/jvmTest/kotlin/androidx/kruth/TestingUtils.jvm.kt b/kruth/kruth/src/jvmTest/kotlin/androidx/kruth/TestingUtils.jvm.kt
new file mode 100644
index 0000000..0903009
--- /dev/null
+++ b/kruth/kruth/src/jvmTest/kotlin/androidx/kruth/TestingUtils.jvm.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2023 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.kruth
+
+import kotlin.math.nextDown as kotlinNextDown
+import kotlin.math.nextUp as kotlinNextUp
+
+internal actual fun Float.nextUp(): Float =
+ kotlinNextUp()
+
+internal actual fun Float.nextDown(): Float =
+ kotlinNextDown()
diff --git a/kruth/kruth/src/nativeTest/kotlin/androidx/kruth/TestingUtils.jvm.kt b/kruth/kruth/src/nativeTest/kotlin/androidx/kruth/TestingUtils.jvm.kt
new file mode 100644
index 0000000..0903009
--- /dev/null
+++ b/kruth/kruth/src/nativeTest/kotlin/androidx/kruth/TestingUtils.jvm.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2023 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.kruth
+
+import kotlin.math.nextDown as kotlinNextDown
+import kotlin.math.nextUp as kotlinNextUp
+
+internal actual fun Float.nextUp(): Float =
+ kotlinNextUp()
+
+internal actual fun Float.nextDown(): Float =
+ kotlinNextDown()
diff --git a/leanback/leanback/src/androidTest/java/androidx/leanback/graphics/CompositeDrawableTest.java b/leanback/leanback/src/androidTest/java/androidx/leanback/graphics/CompositeDrawableTest.java
index 1cbaa74..a4b38df 100644
--- a/leanback/leanback/src/androidTest/java/androidx/leanback/graphics/CompositeDrawableTest.java
+++ b/leanback/leanback/src/androidTest/java/androidx/leanback/graphics/CompositeDrawableTest.java
@@ -23,11 +23,9 @@
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
-import android.os.Build;
import androidx.leanback.graphics.BoundsRule.ValueRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SdkSuppress;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -161,7 +159,6 @@
}
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
@Test
public void constantState() {
Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
diff --git a/leanback/leanback/src/androidTest/java/androidx/leanback/graphics/FitWidthBitmapDrawableTest.java b/leanback/leanback/src/androidTest/java/androidx/leanback/graphics/FitWidthBitmapDrawableTest.java
index 43cf638..6212404 100644
--- a/leanback/leanback/src/androidTest/java/androidx/leanback/graphics/FitWidthBitmapDrawableTest.java
+++ b/leanback/leanback/src/androidTest/java/androidx/leanback/graphics/FitWidthBitmapDrawableTest.java
@@ -24,11 +24,9 @@
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
-import android.os.Build;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
-import androidx.test.filters.SdkSuppress;
import androidx.test.filters.SmallTest;
import org.junit.Test;
@@ -69,7 +67,6 @@
}
@SmallTest
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
@Test
public void constantState() {
FitWidthBitmapDrawable drawable = new FitWidthBitmapDrawable();
diff --git a/leanback/leanback/src/main/java/androidx/leanback/app/BackgroundManager.java b/leanback/leanback/src/main/java/androidx/leanback/app/BackgroundManager.java
index 9f58f44..3fc4c83 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/app/BackgroundManager.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/app/BackgroundManager.java
@@ -42,7 +42,6 @@
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.interpolator.view.animation.FastOutLinearInInterpolator;
import androidx.leanback.R;
-import androidx.leanback.widget.BackgroundHelper;
import java.lang.ref.WeakReference;
@@ -354,8 +353,7 @@
// For each child drawable, we multiple Wrapper's alpha and LayerDrawable's alpha
// temporarily using mSuspendInvalidation to suppress invalidate event.
if (mWrapper[i] != null && (d = mWrapper[i].getDrawable()) != null) {
- int alpha = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
- ? DrawableCompat.getAlpha(d) : FULL_ALPHA;
+ int alpha = DrawableCompat.getAlpha(d);
final int savedAlpha = alpha;
int multiple = 0;
if (mAlpha < FULL_ALPHA) {
@@ -791,7 +789,10 @@
mLayerDrawable = createTranslucentLayerDrawable(layerDrawable);
mImageInWrapperIndex = mLayerDrawable.findWrapperIndexById(R.id.background_imagein);
mImageOutWrapperIndex = mLayerDrawable.findWrapperIndexById(R.id.background_imageout);
- BackgroundHelper.setBackgroundPreservingAlpha(mBgView, mLayerDrawable);
+ if (mBgView.getBackground() != null) {
+ ((Drawable) mLayerDrawable).setAlpha(mBgView.getBackground().getAlpha());
+ }
+ mBgView.setBackground(mLayerDrawable);
}
private void updateImmediate() {
diff --git a/leanback/leanback/src/main/java/androidx/leanback/transition/LeanbackTransitionHelper.java b/leanback/leanback/src/main/java/androidx/leanback/transition/LeanbackTransitionHelper.java
index f1389ba..5c5eda2 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/transition/LeanbackTransitionHelper.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/transition/LeanbackTransitionHelper.java
@@ -30,7 +30,7 @@
public class LeanbackTransitionHelper {
public static Object loadTitleInTransition(Context context) {
- if (Build.VERSION.SDK_INT < 19 || Build.VERSION.SDK_INT >= 21) {
+ if (Build.VERSION.SDK_INT >= 21) {
return TransitionHelper.loadTransition(context, R.transition.lb_title_in);
}
@@ -43,7 +43,7 @@
}
public static Object loadTitleOutTransition(Context context) {
- if (Build.VERSION.SDK_INT < 19 || Build.VERSION.SDK_INT >= 21) {
+ if (Build.VERSION.SDK_INT >= 21) {
return TransitionHelper.loadTransition(context, R.transition.lb_title_out);
}
diff --git a/leanback/leanback/src/main/java/androidx/leanback/transition/TransitionHelper.java b/leanback/leanback/src/main/java/androidx/leanback/transition/TransitionHelper.java
index c117aa5..7e2f8e4c 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/transition/TransitionHelper.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/transition/TransitionHelper.java
@@ -39,8 +39,6 @@
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
-import java.util.ArrayList;
-
/**
* Helper for view transitions.
*/
@@ -59,8 +57,6 @@
}
private static class TransitionStub {
- ArrayList<TransitionListener> mTransitionListeners;
-
TransitionStub() {
}
}
@@ -174,23 +170,17 @@
@SuppressLint("ClassVerificationFailure")
@Nullable
public static Object createScene(@NonNull ViewGroup sceneRoot, @Nullable Runnable r) {
- if (Build.VERSION.SDK_INT >= 19) {
- Scene scene = new Scene(sceneRoot);
- scene.setEnterAction(r);
- return scene;
- }
- return r;
+ Scene scene = new Scene(sceneRoot);
+ scene.setEnterAction(r);
+ return scene;
}
@SuppressLint("ClassVerificationFailure")
@NonNull
public static Object createChangeBounds(boolean reparent) {
- if (Build.VERSION.SDK_INT >= 19) {
- CustomChangeBounds changeBounds = new CustomChangeBounds();
- changeBounds.setReparent(reparent);
- return changeBounds;
- }
- return new TransitionStub();
+ CustomChangeBounds changeBounds = new CustomChangeBounds();
+ changeBounds.setReparent(reparent);
+ return changeBounds;
}
@SuppressLint("ClassVerificationFailure")
@@ -208,9 +198,7 @@
@NonNull View view,
int startDelay
) {
- if (Build.VERSION.SDK_INT >= 19) {
- ((CustomChangeBounds) changeBounds).setStartDelay(view, startDelay);
- }
+ ((CustomChangeBounds) changeBounds).setStartDelay(view, startDelay);
}
public static void setChangeBoundsStartDelay(
@@ -218,9 +206,7 @@
int viewId,
int startDelay
) {
- if (Build.VERSION.SDK_INT >= 19) {
- ((CustomChangeBounds) changeBounds).setStartDelay(viewId, startDelay);
- }
+ ((CustomChangeBounds) changeBounds).setStartDelay(viewId, startDelay);
}
public static void setChangeBoundsStartDelay(
@@ -228,40 +214,30 @@
@NonNull String className,
int startDelay
) {
- if (Build.VERSION.SDK_INT >= 19) {
- ((CustomChangeBounds) changeBounds).setStartDelay(className, startDelay);
- }
+ ((CustomChangeBounds) changeBounds).setStartDelay(className, startDelay);
}
public static void setChangeBoundsDefaultStartDelay(
@NonNull Object changeBounds,
int startDelay
) {
- if (Build.VERSION.SDK_INT >= 19) {
- ((CustomChangeBounds) changeBounds).setDefaultStartDelay(startDelay);
- }
+ ((CustomChangeBounds) changeBounds).setDefaultStartDelay(startDelay);
}
@SuppressLint("ClassVerificationFailure")
@NonNull
public static Object createTransitionSet(boolean sequential) {
- if (Build.VERSION.SDK_INT >= 19) {
- TransitionSet set = new TransitionSet();
- set.setOrdering(sequential ? TransitionSet.ORDERING_SEQUENTIAL
- : TransitionSet.ORDERING_TOGETHER);
- return set;
- }
- return new TransitionStub();
+ TransitionSet set = new TransitionSet();
+ set.setOrdering(sequential ? TransitionSet.ORDERING_SEQUENTIAL
+ : TransitionSet.ORDERING_TOGETHER);
+ return set;
}
@NonNull
public static Object createSlide(int slideEdge) {
- if (Build.VERSION.SDK_INT >= 19) {
- SlideKitkat slide = new SlideKitkat();
- slide.setSlideEdge(slideEdge);
- return slide;
- }
- return new TransitionStub();
+ SlideKitkat slide = new SlideKitkat();
+ slide.setSlideEdge(slideEdge);
+ return slide;
}
@SuppressLint("ClassVerificationFailure")
@@ -270,24 +246,17 @@
if (Build.VERSION.SDK_INT >= 21) {
return new ChangeTransform();
}
- if (Build.VERSION.SDK_INT >= 19) {
- return new Scale();
- }
- return new TransitionStub();
+ return new Scale();
}
@SuppressLint("ClassVerificationFailure")
public static void addTransition(@NonNull Object transitionSet, @NonNull Object transition) {
- if (Build.VERSION.SDK_INT >= 19) {
- ((TransitionSet) transitionSet).addTransition((Transition) transition);
- }
+ ((TransitionSet) transitionSet).addTransition((Transition) transition);
}
@SuppressLint("ClassVerificationFailure")
public static void exclude(@NonNull Object transition, int targetId, boolean exclude) {
- if (Build.VERSION.SDK_INT >= 19) {
- ((Transition) transition).excludeTarget(targetId, exclude);
- }
+ ((Transition) transition).excludeTarget(targetId, exclude);
}
@SuppressLint("ClassVerificationFailure")
@@ -296,16 +265,12 @@
@NonNull View targetView,
boolean exclude
) {
- if (Build.VERSION.SDK_INT >= 19) {
- ((Transition) transition).excludeTarget(targetView, exclude);
- }
+ ((Transition) transition).excludeTarget(targetView, exclude);
}
@SuppressLint("ClassVerificationFailure")
public static void excludeChildren(@NonNull Object transition, int targetId, boolean exclude) {
- if (Build.VERSION.SDK_INT >= 19) {
- ((Transition) transition).excludeChildren(targetId, exclude);
- }
+ ((Transition) transition).excludeChildren(targetId, exclude);
}
@SuppressLint("ClassVerificationFailure")
@@ -314,55 +279,39 @@
@NonNull View targetView,
boolean exclude
) {
- if (Build.VERSION.SDK_INT >= 19) {
- ((Transition) transition).excludeChildren(targetView, exclude);
- }
+ ((Transition) transition).excludeChildren(targetView, exclude);
}
@SuppressLint("ClassVerificationFailure")
public static void include(@NonNull Object transition, int targetId) {
- if (Build.VERSION.SDK_INT >= 19) {
- ((Transition) transition).addTarget(targetId);
- }
+ ((Transition) transition).addTarget(targetId);
}
@SuppressLint("ClassVerificationFailure")
public static void include(@NonNull Object transition, @NonNull View targetView) {
- if (Build.VERSION.SDK_INT >= 19) {
- ((Transition) transition).addTarget(targetView);
- }
+ ((Transition) transition).addTarget(targetView);
}
@SuppressLint("ClassVerificationFailure")
public static void setStartDelay(@NonNull Object transition, long startDelay) {
- if (Build.VERSION.SDK_INT >= 19) {
- ((Transition) transition).setStartDelay(startDelay);
- }
+ ((Transition) transition).setStartDelay(startDelay);
}
@SuppressLint("ClassVerificationFailure")
public static void setDuration(@NonNull Object transition, long duration) {
- if (Build.VERSION.SDK_INT >= 19) {
- ((Transition) transition).setDuration(duration);
- }
+ ((Transition) transition).setDuration(duration);
}
@SuppressLint("ClassVerificationFailure")
@NonNull
public static Object createAutoTransition() {
- if (Build.VERSION.SDK_INT >= 19) {
- return new AutoTransition();
- }
- return new TransitionStub();
+ return new AutoTransition();
}
@SuppressLint("ClassVerificationFailure")
@NonNull
public static Object createFadeTransition(int fadeMode) {
- if (Build.VERSION.SDK_INT >= 19) {
- return new Fade(fadeMode);
- }
- return new TransitionStub();
+ return new Fade(fadeMode);
}
@SuppressLint("ClassVerificationFailure")
@@ -373,42 +322,34 @@
if (listener == null) {
return;
}
- if (Build.VERSION.SDK_INT >= 19) {
- Transition t = (Transition) transition;
- listener.mImpl = new Transition.TransitionListener() {
- @Override
- public void onTransitionStart(Transition transition11) {
- listener.onTransitionStart(transition11);
- }
-
- @Override
- public void onTransitionResume(Transition transition11) {
- listener.onTransitionResume(transition11);
- }
-
- @Override
- public void onTransitionPause(Transition transition11) {
- listener.onTransitionPause(transition11);
- }
-
- @Override
- public void onTransitionEnd(Transition transition11) {
- listener.onTransitionEnd(transition11);
- }
-
- @Override
- public void onTransitionCancel(Transition transition11) {
- listener.onTransitionCancel(transition11);
- }
- };
- t.addListener((Transition.TransitionListener) listener.mImpl);
- } else {
- TransitionStub stub = (TransitionStub) transition;
- if (stub.mTransitionListeners == null) {
- stub.mTransitionListeners = new ArrayList<>();
+ Transition t = (Transition) transition;
+ listener.mImpl = new Transition.TransitionListener() {
+ @Override
+ public void onTransitionStart(Transition transition11) {
+ listener.onTransitionStart(transition11);
}
- stub.mTransitionListeners.add(listener);
- }
+
+ @Override
+ public void onTransitionResume(Transition transition11) {
+ listener.onTransitionResume(transition11);
+ }
+
+ @Override
+ public void onTransitionPause(Transition transition11) {
+ listener.onTransitionPause(transition11);
+ }
+
+ @Override
+ public void onTransitionEnd(Transition transition11) {
+ listener.onTransitionEnd(transition11);
+ }
+
+ @Override
+ public void onTransitionCancel(Transition transition11) {
+ listener.onTransitionCancel(transition11);
+ }
+ };
+ t.addListener((Transition.TransitionListener) listener.mImpl);
}
@SuppressLint("ClassVerificationFailure")
@@ -416,42 +357,17 @@
@NonNull Object transition,
@Nullable TransitionListener listener
) {
- if (Build.VERSION.SDK_INT >= 19) {
- if (listener == null || listener.mImpl == null) {
- return;
- }
- Transition t = (Transition) transition;
- t.removeListener((Transition.TransitionListener) listener.mImpl);
- listener.mImpl = null;
- } else {
- TransitionStub stub = (TransitionStub) transition;
- if (stub.mTransitionListeners != null) {
- stub.mTransitionListeners.remove(listener);
- }
+ if (listener == null || listener.mImpl == null) {
+ return;
}
+ Transition t = (Transition) transition;
+ t.removeListener((Transition.TransitionListener) listener.mImpl);
+ listener.mImpl = null;
}
@SuppressLint("ClassVerificationFailure")
public static void runTransition(@Nullable Object scene, @Nullable Object transition) {
- if (Build.VERSION.SDK_INT >= 19) {
- TransitionManager.go((Scene) scene, (Transition) transition);
- } else {
- TransitionStub transitionStub = (TransitionStub) transition;
- if (transitionStub != null && transitionStub.mTransitionListeners != null) {
- for (int i = 0, size = transitionStub.mTransitionListeners.size(); i < size; i++) {
- transitionStub.mTransitionListeners.get(i).onTransitionStart(transition);
- }
- }
- Runnable r = ((Runnable) scene);
- if (r != null) {
- r.run();
- }
- if (transitionStub != null && transitionStub.mTransitionListeners != null) {
- for (int i = 0, size = transitionStub.mTransitionListeners.size(); i < size; i++) {
- transitionStub.mTransitionListeners.get(i).onTransitionEnd(transition);
- }
- }
- }
+ TransitionManager.go((Scene) scene, (Transition) transition);
}
@SuppressLint("ClassVerificationFailure")
@@ -459,16 +375,12 @@
@NonNull Object transition,
@Nullable Object timeInterpolator
) {
- if (Build.VERSION.SDK_INT >= 19) {
- ((Transition) transition).setInterpolator((TimeInterpolator) timeInterpolator);
- }
+ ((Transition) transition).setInterpolator((TimeInterpolator) timeInterpolator);
}
@SuppressLint("ClassVerificationFailure")
public static void addTarget(@NonNull Object transition, @NonNull View view) {
- if (Build.VERSION.SDK_INT >= 19) {
- ((Transition) transition).addTarget(view);
- }
+ ((Transition) transition).addTarget(view);
}
@SuppressLint("ClassVerificationFailure")
@@ -484,10 +396,7 @@
@SuppressLint("ClassVerificationFailure")
@NonNull
public static Object loadTransition(@NonNull Context context, int resId) {
- if (Build.VERSION.SDK_INT >= 19) {
- return TransitionInflater.from(context).inflateTransition(resId);
- }
- return new TransitionStub();
+ return TransitionInflater.from(context).inflateTransition(resId);
}
@SuppressLint({"ReferencesDeprecated", "ClassVerificationFailure"})
diff --git a/leanback/leanback/src/main/java/androidx/leanback/widget/BackgroundHelper.java b/leanback/leanback/src/main/java/androidx/leanback/widget/BackgroundHelper.java
index 69fa9dc..c3df78f 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/widget/BackgroundHelper.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/widget/BackgroundHelper.java
@@ -18,7 +18,6 @@
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;
import android.graphics.drawable.Drawable;
-import android.os.Build;
import android.view.View;
import androidx.annotation.RestrictTo;
@@ -29,15 +28,10 @@
@RestrictTo(LIBRARY_GROUP_PREFIX)
public final class BackgroundHelper {
public static void setBackgroundPreservingAlpha(View view, Drawable drawable) {
- if (Build.VERSION.SDK_INT >= 19) {
- if (view.getBackground() != null) {
- drawable.setAlpha(view.getBackground().getAlpha());
- }
- view.setBackground(drawable);
- } else {
- // Cannot query drawable alpha
- view.setBackground(drawable);
+ if (view.getBackground() != null) {
+ drawable.setAlpha(view.getBackground().getAlpha());
}
+ view.setBackground(drawable);
}
private BackgroundHelper() {
diff --git a/libraryversions.toml b/libraryversions.toml
index ee4cf11..872c259 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -21,8 +21,8 @@
CAR_APP = "1.7.0-alpha01"
COLLECTION = "1.4.0-beta02"
COMPOSE = "1.7.0-alpha01"
-COMPOSE_COMPILER = "1.5.5"
-COMPOSE_MATERIAL3 = "1.2.0-alpha12"
+COMPOSE_COMPILER = "1.5.6"
+COMPOSE_MATERIAL3 = "1.2.0-beta01"
COMPOSE_MATERIAL3_ADAPTIVE = "1.0.0-alpha02"
COMPOSE_MATERIAL3_ADAPTIVE_NAVIGATION_SUITE = "1.0.0-alpha01"
COMPOSE_MATERIAL3_COMMON = "1.0.0-alpha01"
@@ -136,10 +136,10 @@
SWIPEREFRESHLAYOUT = "1.2.0-alpha01"
TESTEXT = "1.0.0-alpha02"
TESTSCREENSHOT = "1.0.0-alpha01"
-TEST_UIAUTOMATOR = "2.3.0-alpha05"
+TEST_UIAUTOMATOR = "2.3.0-beta01"
TEXT = "1.0.0-alpha01"
TRACING = "1.3.0-alpha02"
-TRACING_PERFETTO = "1.0.0-beta03"
+TRACING_PERFETTO = "1.0.0"
TRANSITION = "1.5.0-alpha05"
TV = "1.0.0-alpha11"
TVPROVIDER = "1.1.0-alpha02"
@@ -161,7 +161,7 @@
WEAR_TILES = "1.3.0-alpha03"
WEAR_TOOLING_PREVIEW = "1.0.0-rc01"
WEAR_WATCHFACE = "1.3.0-alpha01"
-WEBKIT = "1.10.0-alpha01"
+WEBKIT = "1.10.0-beta01"
# Adding a comment to prevent merge conflicts for Window artifact
WINDOW = "1.3.0-alpha01"
WINDOW_EXTENSIONS = "1.3.0-alpha01"
diff --git a/media/media/src/main/java/android/support/v4/media/MediaMetadataCompat.java b/media/media/src/main/java/android/support/v4/media/MediaMetadataCompat.java
index afb4f31..8c3a9c8 100644
--- a/media/media/src/main/java/android/support/v4/media/MediaMetadataCompat.java
+++ b/media/media/src/main/java/android/support/v4/media/MediaMetadataCompat.java
@@ -425,13 +425,9 @@
public RatingCompat getRating(@RatingKey String key) {
RatingCompat rating = null;
try {
- if (Build.VERSION.SDK_INT >= 19) {
- // On platform version 19 or higher, mBundle stores a Rating object. Convert it to
- // RatingCompat.
- rating = RatingCompat.fromRating(mBundle.getParcelable(key));
- } else {
- rating = mBundle.getParcelable(key);
- }
+ // On platform version 19 or higher, mBundle stores a Rating object. Convert it to
+ // RatingCompat.
+ rating = RatingCompat.fromRating(mBundle.getParcelable(key));
} catch (Exception e) {
// ignore, value was not a bitmap
Log.w(TAG, "Failed to retrieve a key as Rating.", e);
@@ -819,13 +815,9 @@
+ " key cannot be used to put a Rating");
}
}
- if (Build.VERSION.SDK_INT >= 19) {
- // On platform version 19 or higher, use Rating instead of RatingCompat so mBundle
- // can be unmarshalled.
- mBundle.putParcelable(key, (Parcelable) value.getRating());
- } else {
- mBundle.putParcelable(key, value);
- }
+ // On platform version 19 or higher, use Rating instead of RatingCompat so mBundle
+ // can be unmarshalled.
+ mBundle.putParcelable(key, (Parcelable) value.getRating());
return this;
}
diff --git a/media/media/src/main/java/android/support/v4/media/RatingCompat.java b/media/media/src/main/java/android/support/v4/media/RatingCompat.java
index 570577f..c49338e 100644
--- a/media/media/src/main/java/android/support/v4/media/RatingCompat.java
+++ b/media/media/src/main/java/android/support/v4/media/RatingCompat.java
@@ -21,14 +21,11 @@
import android.annotation.SuppressLint;
import android.media.Rating;
-import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
-import androidx.annotation.DoNotInline;
import androidx.annotation.IntDef;
-import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import java.lang.annotation.Retention;
@@ -329,27 +326,28 @@
* @param ratingObj A {@link android.media.Rating} object, or null if none.
* @return An equivalent {@link RatingCompat} object, or null if none.
*/
+ @SuppressLint("WrongConstant")
public static RatingCompat fromRating(Object ratingObj) {
- if (ratingObj != null && Build.VERSION.SDK_INT >= 19) {
- final int ratingStyle = Api19Impl.getRatingStyle((Rating) ratingObj);
+ if (ratingObj != null) {
+ final int ratingStyle = ((Rating) ratingObj).getRatingStyle();
final RatingCompat rating;
- if (Api19Impl.isRated((Rating) ratingObj)) {
+ if (((Rating) ratingObj).isRated()) {
switch (ratingStyle) {
case RATING_HEART:
- rating = newHeartRating(Api19Impl.hasHeart((Rating) ratingObj));
+ rating = newHeartRating(((Rating) ratingObj).hasHeart());
break;
case RATING_THUMB_UP_DOWN:
- rating = newThumbRating(Api19Impl.isThumbUp((Rating) ratingObj));
+ rating = newThumbRating(((Rating) ratingObj).isThumbUp());
break;
case RATING_3_STARS:
case RATING_4_STARS:
case RATING_5_STARS:
rating = newStarRating(ratingStyle,
- Api19Impl.getStarRating((Rating) ratingObj));
+ ((Rating) ratingObj).getStarRating());
break;
case RATING_PERCENTAGE:
rating = newPercentageRating(
- Api19Impl.getPercentRating((Rating) ratingObj));
+ ((Rating) ratingObj).getPercentRating());
break;
default:
return null;
@@ -373,91 +371,30 @@
* @return An equivalent {@link android.media.Rating} object, or null if none.
*/
public Object getRating() {
- if (mRatingObj == null && Build.VERSION.SDK_INT >= 19) {
+ if (mRatingObj == null) {
if (isRated()) {
switch (mRatingStyle) {
case RATING_HEART:
- mRatingObj = Api19Impl.newHeartRating(hasHeart());
+ mRatingObj = Rating.newHeartRating(hasHeart());
break;
case RATING_THUMB_UP_DOWN:
- mRatingObj = Api19Impl.newThumbRating(isThumbUp());
+ mRatingObj = Rating.newThumbRating(isThumbUp());
break;
case RATING_3_STARS:
case RATING_4_STARS:
case RATING_5_STARS:
- mRatingObj = Api19Impl.newStarRating(mRatingStyle,
- getStarRating());
+ mRatingObj = Rating.newStarRating(mRatingStyle, getStarRating());
break;
case RATING_PERCENTAGE:
- mRatingObj = Api19Impl.newPercentageRating(getPercentRating());
+ mRatingObj = Rating.newPercentageRating(getPercentRating());
break;
default:
return null;
}
} else {
- mRatingObj = Api19Impl.newUnratedRating(mRatingStyle);
+ mRatingObj = Rating.newUnratedRating(mRatingStyle);
}
}
return mRatingObj;
}
-
- @RequiresApi(19)
- private static class Api19Impl {
- private Api19Impl() {}
-
- @DoNotInline
- static int getRatingStyle(Rating rating) {
- return rating.getRatingStyle();
- }
-
- @DoNotInline
- static boolean isRated(Rating rating) {
- return rating.isRated();
- }
-
- @DoNotInline
- static boolean hasHeart(Rating rating) {
- return rating.hasHeart();
- }
-
- @DoNotInline
- static boolean isThumbUp(Rating rating) {
- return rating.isThumbUp();
- }
-
- @DoNotInline
- static float getStarRating(Rating rating) {
- return rating.getStarRating();
- }
-
- @DoNotInline
- static float getPercentRating(Rating rating) {
- return rating.getPercentRating();
- }
-
- @DoNotInline
- static Rating newHeartRating(boolean hasHeart) {
- return Rating.newHeartRating(hasHeart);
- }
-
- @DoNotInline
- static Rating newThumbRating(boolean thumbIsUp) {
- return Rating.newThumbRating(thumbIsUp);
- }
-
- @DoNotInline
- static Rating newStarRating(int starRatingStyle, float starRating) {
- return Rating.newStarRating(starRatingStyle, starRating);
- }
-
- @DoNotInline
- static Rating newPercentageRating(float percent) {
- return Rating.newPercentageRating(percent);
- }
-
- @DoNotInline
- static Rating newUnratedRating(int ratingStyle) {
- return Rating.newUnratedRating(ratingStyle);
- }
- }
}
diff --git a/media/media/src/main/java/android/support/v4/media/session/MediaSessionCompat.java b/media/media/src/main/java/android/support/v4/media/session/MediaSessionCompat.java
index a92d2198..cf9e20d 100644
--- a/media/media/src/main/java/android/support/v4/media/session/MediaSessionCompat.java
+++ b/media/media/src/main/java/android/support/v4/media/session/MediaSessionCompat.java
@@ -553,15 +553,9 @@
? Looper.myLooper() : Looper.getMainLooper());
setCallback(new Callback() {}, handler);
mImpl.setMediaButtonReceiver(mbrIntent);
- } else if (android.os.Build.VERSION.SDK_INT >= 19) {
+ } else {
mImpl = new MediaSessionImplApi19(context, tag, mbrComponent, mbrIntent,
session2Token, sessionInfo);
- } else if (android.os.Build.VERSION.SDK_INT >= 18) {
- mImpl = new MediaSessionImplApi18(context, tag, mbrComponent, mbrIntent,
- session2Token, sessionInfo);
- } else {
- mImpl = new MediaSessionImplBase(context, tag, mbrComponent, mbrIntent, session2Token,
- sessionInfo);
}
mController = new MediaControllerCompat(context, this);
@@ -3758,7 +3752,6 @@
}
}
- @RequiresApi(18)
static class MediaSessionImplApi18 extends MediaSessionImplBase {
private static boolean sIsMbrPendingIntentSupported = true;
@@ -3844,7 +3837,6 @@
}
}
- @RequiresApi(19)
static class MediaSessionImplApi19 extends MediaSessionImplApi18 {
MediaSessionImplApi19(Context context, String tag, ComponentName mbrComponent,
PendingIntent mbrIntent, VersionedParcelable session2Token, Bundle sessionInfo) {
diff --git a/media/media/src/main/java/androidx/media/AudioFocusRequestCompat.java b/media/media/src/main/java/androidx/media/AudioFocusRequestCompat.java
index d79fdc5..a126a53 100644
--- a/media/media/src/main/java/androidx/media/AudioFocusRequestCompat.java
+++ b/media/media/src/main/java/androidx/media/AudioFocusRequestCompat.java
@@ -263,10 +263,6 @@
throw new IllegalArgumentException("Illegal audio focus gain type " + focusGain);
}
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT
- && focusGain == AudioManagerCompat.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE) {
- focusGain = AudioManagerCompat.AUDIOFOCUS_GAIN_TRANSIENT;
- }
mFocusGain = focusGain;
return this;
}
diff --git a/media2/media2-common/src/main/java/androidx/media2/common/ClassVerificationHelper.java b/media2/media2-common/src/main/java/androidx/media2/common/ClassVerificationHelper.java
index f6e962ee..5fc397b 100644
--- a/media2/media2-common/src/main/java/androidx/media2/common/ClassVerificationHelper.java
+++ b/media2/media2-common/src/main/java/androidx/media2/common/ClassVerificationHelper.java
@@ -51,25 +51,6 @@
private AudioManager() {}
}
- /** Helper class for {@link android.os.HandlerThread}. */
- public static final class HandlerThread {
-
- /** Helper methods for {@link android.os.HandlerThread} APIs added in API level 18. */
- @RequiresApi(18)
- public static final class Api18 {
-
- /** Helper method to call {@link android.os.HandlerThread#quitSafely()}. */
- @DoNotInline
- public static boolean quitSafely(@NonNull android.os.HandlerThread handlerThread) {
- return handlerThread.quitSafely();
- }
-
- private Api18() {}
- }
-
- private HandlerThread() {}
- }
-
/** Helper class for {@link android.app.PendingIntent}. */
public static final class PendingIntent {
diff --git a/media2/media2-player/src/androidTest/java/androidx/media2/player/MediaPlayer2Test.java b/media2/media2-player/src/androidTest/java/androidx/media2/player/MediaPlayer2Test.java
index c12fa6e..11585c6 100644
--- a/media2/media2-player/src/androidTest/java/androidx/media2/player/MediaPlayer2Test.java
+++ b/media2/media2-player/src/androidTest/java/androidx/media2/player/MediaPlayer2Test.java
@@ -1349,8 +1349,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_MKV_H265_1280x720_500kbps_25fps_AAC_Stereo_128kbps_44100Hz()
throws Exception {
playVideoTest(
@@ -1359,8 +1358,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_MP4_H264_480x360_500kbps_25fps_AAC_Stereo_128kbps_44110Hz()
throws Exception {
playVideoTest(
@@ -1369,8 +1367,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_MP4_H264_480x360_500kbps_30fps_AAC_Stereo_128kbps_44110Hz()
throws Exception {
playVideoTest(
@@ -1379,8 +1376,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_MP4_H264_480x360_1000kbps_25fps_AAC_Stereo_128kbps_44110Hz()
throws Exception {
playVideoTest(
@@ -1389,8 +1385,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_MP4_H264_480x360_1000kbps_30fps_AAC_Stereo_128kbps_44110Hz()
throws Exception {
playVideoTest(
@@ -1399,8 +1394,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_MP4_H264_480x360_1350kbps_25fps_AAC_Stereo_128kbps_44110Hz()
throws Exception {
playVideoTest(
@@ -1409,8 +1403,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_MP4_H264_480x360_1350kbps_30fps_AAC_Stereo_128kbps_44110Hz()
throws Exception {
playVideoTest(
@@ -1419,8 +1412,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_MP4_H264_480x360_1350kbps_30fps_AAC_Stereo_128kbps_44110Hz_frag()
throws Exception {
playVideoTest(
@@ -1430,8 +1422,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_MP4_H264_480x360_1350kbps_30fps_AAC_Stereo_192kbps_44110Hz()
throws Exception {
playVideoTest(
@@ -1440,8 +1431,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_3gp_H263_176x144_56kbps_12fps_AAC_Mono_24kbps_11025Hz()
throws Exception {
playVideoTest(
@@ -1450,8 +1440,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_3gp_H263_176x144_56kbps_12fps_AAC_Mono_24kbps_22050Hz()
throws Exception {
playVideoTest(
@@ -1460,8 +1449,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_3gp_H263_176x144_56kbps_12fps_AAC_Stereo_24kbps_11025Hz()
throws Exception {
playVideoTest(
@@ -1470,8 +1458,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_3gp_H263_176x144_56kbps_12fps_AAC_Stereo_24kbps_22050Hz()
throws Exception {
playVideoTest(
@@ -1480,8 +1467,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_3gp_H263_176x144_56kbps_12fps_AAC_Stereo_128kbps_11025Hz()
throws Exception {
playVideoTest(
@@ -1490,8 +1476,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_3gp_H263_176x144_56kbps_12fps_AAC_Stereo_128kbps_22050Hz()
throws Exception {
playVideoTest(
@@ -1500,8 +1485,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_3gp_H263_176x144_56kbps_25fps_AAC_Mono_24kbps_11025Hz()
throws Exception {
playVideoTest(
@@ -1510,8 +1494,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_3gp_H263_176x144_56kbps_25fps_AAC_Mono_24kbps_22050Hz()
throws Exception {
playVideoTest(
@@ -1520,8 +1503,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_3gp_H263_176x144_56kbps_25fps_AAC_Stereo_24kbps_11025Hz()
throws Exception {
playVideoTest(
@@ -1530,8 +1512,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_3gp_H263_176x144_56kbps_25fps_AAC_Stereo_24kbps_22050Hz()
throws Exception {
playVideoTest(
@@ -1540,8 +1521,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_3gp_H263_176x144_56kbps_25fps_AAC_Stereo_128kbps_11025Hz()
throws Exception {
playVideoTest(
@@ -1550,8 +1530,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_3gp_H263_176x144_56kbps_25fps_AAC_Stereo_128kbps_22050Hz()
throws Exception {
playVideoTest(
@@ -1560,8 +1539,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_3gp_H263_176x144_300kbps_12fps_AAC_Mono_24kbps_11025Hz()
throws Exception {
playVideoTest(
@@ -1570,8 +1548,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_3gp_H263_176x144_300kbps_12fps_AAC_Mono_24kbps_22050Hz()
throws Exception {
playVideoTest(
@@ -1580,8 +1557,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_3gp_H263_176x144_300kbps_12fps_AAC_Stereo_24kbps_11025Hz()
throws Exception {
playVideoTest(
@@ -1590,8 +1566,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_3gp_H263_176x144_300kbps_12fps_AAC_Stereo_24kbps_22050Hz()
throws Exception {
playVideoTest(
@@ -1600,8 +1575,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_3gp_H263_176x144_300kbps_12fps_AAC_Stereo_128kbps_11025Hz()
throws Exception {
playVideoTest(
@@ -1610,8 +1584,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_3gp_H263_176x144_300kbps_12fps_AAC_Stereo_128kbps_22050Hz()
throws Exception {
playVideoTest(
@@ -1620,8 +1593,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_3gp_H263_176x144_300kbps_25fps_AAC_Mono_24kbps_11025Hz()
throws Exception {
playVideoTest(
@@ -1630,8 +1602,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_3gp_H263_176x144_300kbps_25fps_AAC_Mono_24kbps_22050Hz()
throws Exception {
playVideoTest(
@@ -1640,8 +1611,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_3gp_H263_176x144_300kbps_25fps_AAC_Stereo_24kbps_11025Hz()
throws Exception {
playVideoTest(
@@ -1650,8 +1620,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_3gp_H263_176x144_300kbps_25fps_AAC_Stereo_24kbps_22050Hz()
throws Exception {
playVideoTest(
@@ -1660,8 +1629,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_3gp_H263_176x144_300kbps_25fps_AAC_Stereo_128kbps_11025Hz()
throws Exception {
playVideoTest(
@@ -1670,8 +1638,7 @@
@Test
@LargeTest
- @SdkSuppress(
- minSdkVersion = Build.VERSION_CODES.KITKAT, maxSdkVersion = Build.VERSION_CODES.O_MR1)
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
public void localVideo_3gp_H263_176x144_300kbps_25fps_AAC_Stereo_128kbps_22050Hz()
throws Exception {
playVideoTest(
diff --git a/media2/media2-player/src/androidTest/java/androidx/media2/player/MediaPlayer_AudioFocusTest.java b/media2/media2-player/src/androidTest/java/androidx/media2/player/MediaPlayer_AudioFocusTest.java
index 20d1c73..6636bb4 100644
--- a/media2/media2-player/src/androidTest/java/androidx/media2/player/MediaPlayer_AudioFocusTest.java
+++ b/media2/media2-player/src/androidTest/java/androidx/media2/player/MediaPlayer_AudioFocusTest.java
@@ -43,7 +43,6 @@
import android.content.Intent;
import android.media.AudioManager;
import android.media.AudioManager.OnAudioFocusChangeListener;
-import android.os.Build;
import android.os.Build.VERSION;
import android.os.HandlerThread;
import android.os.Looper;
@@ -125,11 +124,7 @@
if (sHandler == null) {
return;
}
- if (Build.VERSION.SDK_INT >= 18) {
- sHandler.getLooper().quitSafely();
- } else {
- sHandler.getLooper().quit();
- }
+ sHandler.getLooper().quitSafely();
sHandler = null;
sHandlerExecutor = null;
}
diff --git a/media2/media2-session/src/androidTest/java/androidx/media2/session/MediaSessionTestBase.java b/media2/media2-session/src/androidTest/java/androidx/media2/session/MediaSessionTestBase.java
index d39d457..2b482e0 100644
--- a/media2/media2-session/src/androidTest/java/androidx/media2/session/MediaSessionTestBase.java
+++ b/media2/media2-session/src/androidTest/java/androidx/media2/session/MediaSessionTestBase.java
@@ -17,7 +17,6 @@
package androidx.media2.session;
import android.content.Context;
-import android.os.Build;
import android.os.Bundle;
import android.os.HandlerThread;
@@ -84,11 +83,7 @@
if (sHandler == null) {
return;
}
- if (Build.VERSION.SDK_INT >= 18) {
- sHandler.getLooper().quitSafely();
- } else {
- sHandler.getLooper().quit();
- }
+ sHandler.getLooper().quitSafely();
sHandler = null;
sHandlerExecutor = null;
}
diff --git a/media2/media2-session/src/main/java/androidx/media2/session/MediaControllerImplLegacy.java b/media2/media2-session/src/main/java/androidx/media2/session/MediaControllerImplLegacy.java
index dc21534..9a4987c 100644
--- a/media2/media2-session/src/main/java/androidx/media2/session/MediaControllerImplLegacy.java
+++ b/media2/media2-session/src/main/java/androidx/media2/session/MediaControllerImplLegacy.java
@@ -36,7 +36,6 @@
import android.app.PendingIntent;
import android.content.Context;
import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
@@ -56,7 +55,6 @@
import androidx.annotation.Nullable;
import androidx.concurrent.futures.ResolvableFuture;
import androidx.core.util.ObjectsCompat;
-import androidx.media2.common.ClassVerificationHelper;
import androidx.media2.common.MediaItem;
import androidx.media2.common.MediaMetadata;
import androidx.media2.common.Rating;
@@ -205,11 +203,7 @@
}
mHandler.removeCallbacksAndMessages(null);
- if (Build.VERSION.SDK_INT >= 18) {
- ClassVerificationHelper.HandlerThread.Api18.quitSafely(mHandlerThread);
- } else {
- mHandlerThread.quit();
- }
+ mHandlerThread.quitSafely();
mClosed = true;
diff --git a/media2/media2-session/src/main/java/androidx/media2/session/MediaSessionImplBase.java b/media2/media2-session/src/main/java/androidx/media2/session/MediaSessionImplBase.java
index 52ae967..e4ea230 100644
--- a/media2/media2-session/src/main/java/androidx/media2/session/MediaSessionImplBase.java
+++ b/media2/media2-session/src/main/java/androidx/media2/session/MediaSessionImplBase.java
@@ -322,11 +322,7 @@
});
mHandler.removeCallbacksAndMessages(null);
if (mHandlerThread.isAlive()) {
- if (Build.VERSION.SDK_INT >= 18) {
- ClassVerificationHelper.HandlerThread.Api18.quitSafely(mHandlerThread);
- } else {
- mHandlerThread.quit();
- }
+ mHandlerThread.quitSafely();
}
}
diff --git a/media2/media2-session/src/main/java/androidx/media2/session/MediaUtils.java b/media2/media2-session/src/main/java/androidx/media2/session/MediaUtils.java
index d726eb2..0aaec2b 100644
--- a/media2/media2-session/src/main/java/androidx/media2/session/MediaUtils.java
+++ b/media2/media2-session/src/main/java/androidx/media2/session/MediaUtils.java
@@ -48,7 +48,6 @@
import android.media.AudioManager;
import android.net.Uri;
import android.os.BadParcelableException;
-import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -334,8 +333,7 @@
builder.putBitmap(metadataKey, (Bitmap) value);
} else if (value instanceof Long) {
builder.putLong(metadataKey, (Long) value);
- } else if ((value instanceof RatingCompat)
- || (Build.VERSION.SDK_INT >= 19 && value instanceof android.media.Rating)) {
+ } else if (value instanceof RatingCompat || value instanceof android.media.Rating) {
// Must be fwk Rating or RatingCompat according to SDK versions.
// Use MediaMetadataCompat#getRating(key) to get a RatingCompat object.
try {
diff --git a/media2/media2-session/src/main/java/androidx/media2/session/SessionToken.java b/media2/media2-session/src/main/java/androidx/media2/session/SessionToken.java
index b6c7f26..a0997be 100644
--- a/media2/media2-session/src/main/java/androidx/media2/session/SessionToken.java
+++ b/media2/media2-session/src/main/java/androidx/media2/session/SessionToken.java
@@ -23,7 +23,6 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
@@ -38,7 +37,6 @@
import androidx.annotation.RestrictTo;
import androidx.media.MediaBrowserServiceCompat;
import androidx.media.MediaSessionManager;
-import androidx.media2.common.ClassVerificationHelper;
import androidx.versionedparcelable.ParcelField;
import androidx.versionedparcelable.VersionedParcelable;
import androidx.versionedparcelable.VersionedParcelize;
@@ -345,11 +343,7 @@
@SuppressWarnings("WeakerAccess") /* synthetic access */
static void quitHandlerThread(HandlerThread thread) {
- if (Build.VERSION.SDK_INT >= 18) {
- ClassVerificationHelper.HandlerThread.Api18.quitSafely(thread);
- } else {
- thread.quit();
- }
+ thread.quitSafely();
}
@SuppressWarnings("deprecation")
diff --git a/media2/media2-session/version-compat-tests/common/src/main/java/androidx/media2/test/common/TestUtils.java b/media2/media2-session/version-compat-tests/common/src/main/java/androidx/media2/test/common/TestUtils.java
index 51689e8..1fd6712 100644
--- a/media2/media2-session/version-compat-tests/common/src/main/java/androidx/media2/test/common/TestUtils.java
+++ b/media2/media2-session/version-compat-tests/common/src/main/java/androidx/media2/test/common/TestUtils.java
@@ -18,7 +18,6 @@
import static org.junit.Assert.assertTrue;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -74,11 +73,7 @@
// Copied code from ObjectsCompat.java due to build dependency problem of
// previous version of support lib.
public static boolean equals(Object a, Object b) {
- if (Build.VERSION.SDK_INT >= 19) {
- return Objects.equals(a, b);
- } else {
- return (a == b) || (a != null && a.equals(b));
- }
+ return Objects.equals(a, b);
}
/**
diff --git a/media2/media2-session/version-compat-tests/current/client/src/androidTest/java/androidx/media2/test/client/tests/MediaSessionTestBase.java b/media2/media2-session/version-compat-tests/current/client/src/androidTest/java/androidx/media2/test/client/tests/MediaSessionTestBase.java
index 639fb5b..ea17c74 100644
--- a/media2/media2-session/version-compat-tests/current/client/src/androidTest/java/androidx/media2/test/client/tests/MediaSessionTestBase.java
+++ b/media2/media2-session/version-compat-tests/current/client/src/androidTest/java/androidx/media2/test/client/tests/MediaSessionTestBase.java
@@ -17,7 +17,6 @@
package androidx.media2.test.client.tests;
import android.content.Context;
-import android.os.Build;
import android.os.Bundle;
import android.os.HandlerThread;
import android.support.v4.media.session.MediaSessionCompat;
@@ -88,11 +87,7 @@
if (sHandler == null) {
return;
}
- if (Build.VERSION.SDK_INT >= 18) {
- sHandler.getLooper().quitSafely();
- } else {
- sHandler.getLooper().quit();
- }
+ sHandler.getLooper().quitSafely();
sHandler = null;
sHandlerExecutor = null;
}
diff --git a/media2/media2-session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/MockMediaLibraryService.java b/media2/media2-session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/MockMediaLibraryService.java
index 78b5841..cb8b580 100644
--- a/media2/media2-session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/MockMediaLibraryService.java
+++ b/media2/media2-session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/MockMediaLibraryService.java
@@ -54,7 +54,6 @@
import android.app.Service;
import android.content.Context;
-import android.os.Build;
import android.os.Bundle;
import android.os.HandlerThread;
import android.util.Log;
@@ -124,11 +123,7 @@
sAssertLibraryParams = false;
sExpectedParams = null;
}
- if (Build.VERSION.SDK_INT >= 18) {
- mHandler.getLooper().quitSafely();
- } else {
- mHandler.getLooper().quit();
- }
+ mHandler.getLooper().quitSafely();
mHandler = null;
TestServiceRegistry.getInstance().cleanUp();
}
diff --git a/media2/media2-session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSessionTestBase.java b/media2/media2-session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSessionTestBase.java
index 6db0c22..40529f8 100644
--- a/media2/media2-session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSessionTestBase.java
+++ b/media2/media2-session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSessionTestBase.java
@@ -17,7 +17,6 @@
package androidx.media2.test.service.tests;
import android.content.Context;
-import android.os.Build;
import android.os.Bundle;
import android.os.HandlerThread;
@@ -79,11 +78,7 @@
if (sHandler == null) {
return;
}
- if (Build.VERSION.SDK_INT >= 18) {
- sHandler.getLooper().quitSafely();
- } else {
- sHandler.getLooper().quit();
- }
+ sHandler.getLooper().quitSafely();
sHandler = null;
sHandlerExecutor = null;
}
diff --git a/media2/media2-session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSession_KeyEventTest.java b/media2/media2-session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSession_KeyEventTest.java
index 6104b39..c12f098 100644
--- a/media2/media2-session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSession_KeyEventTest.java
+++ b/media2/media2-session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSession_KeyEventTest.java
@@ -39,7 +39,6 @@
import androidx.media2.test.service.R;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
-import androidx.test.filters.SdkSuppress;
import org.junit.After;
import org.junit.Before;
@@ -54,7 +53,6 @@
* In order to get the media key events, the player state is set to 'Playing' before every test
* method.
*/
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT) // For AudioManager#dispatchMediaKeyEvent()
@RunWith(AndroidJUnit4.class)
@LargeTest
public class MediaSession_KeyEventTest extends MediaSessionTestBase {
diff --git a/media2/media2-session/version-compat-tests/previous/client/build.gradle b/media2/media2-session/version-compat-tests/previous/client/build.gradle
index 5ca0a2c..d16354e 100644
--- a/media2/media2-session/version-compat-tests/previous/client/build.gradle
+++ b/media2/media2-session/version-compat-tests/previous/client/build.gradle
@@ -20,7 +20,7 @@
}
dependencies {
- androidTestImplementation("androidx.media2:media2-session:1.2.0-rc01")
+ androidTestImplementation("androidx.media2:media2-session:1.2.0")
androidTestImplementation(project(":media2:media2-session:version-compat-tests:common"))
androidTestImplementation(libs.testExtJunit)
diff --git a/media2/media2-session/version-compat-tests/previous/client/src/androidTest/java/androidx/media2/test/client/tests/MediaSessionTestBase.java b/media2/media2-session/version-compat-tests/previous/client/src/androidTest/java/androidx/media2/test/client/tests/MediaSessionTestBase.java
index 639fb5b..ea17c74 100644
--- a/media2/media2-session/version-compat-tests/previous/client/src/androidTest/java/androidx/media2/test/client/tests/MediaSessionTestBase.java
+++ b/media2/media2-session/version-compat-tests/previous/client/src/androidTest/java/androidx/media2/test/client/tests/MediaSessionTestBase.java
@@ -17,7 +17,6 @@
package androidx.media2.test.client.tests;
import android.content.Context;
-import android.os.Build;
import android.os.Bundle;
import android.os.HandlerThread;
import android.support.v4.media.session.MediaSessionCompat;
@@ -88,11 +87,7 @@
if (sHandler == null) {
return;
}
- if (Build.VERSION.SDK_INT >= 18) {
- sHandler.getLooper().quitSafely();
- } else {
- sHandler.getLooper().quit();
- }
+ sHandler.getLooper().quitSafely();
sHandler = null;
sHandlerExecutor = null;
}
diff --git a/media2/media2-session/version-compat-tests/previous/service/build.gradle b/media2/media2-session/version-compat-tests/previous/service/build.gradle
index 0f6afc1..001262f 100644
--- a/media2/media2-session/version-compat-tests/previous/service/build.gradle
+++ b/media2/media2-session/version-compat-tests/previous/service/build.gradle
@@ -20,7 +20,7 @@
}
dependencies {
- androidTestImplementation("androidx.media2:media2-session:1.2.0-rc01")
+ androidTestImplementation("androidx.media2:media2-session:1.2.0")
androidTestImplementation(project(":media2:media2-session:version-compat-tests:common"))
androidTestImplementation(libs.testExtJunit)
diff --git a/media2/media2-session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/MockMediaLibraryService.java b/media2/media2-session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/MockMediaLibraryService.java
index 78b5841..cb8b580 100644
--- a/media2/media2-session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/MockMediaLibraryService.java
+++ b/media2/media2-session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/MockMediaLibraryService.java
@@ -54,7 +54,6 @@
import android.app.Service;
import android.content.Context;
-import android.os.Build;
import android.os.Bundle;
import android.os.HandlerThread;
import android.util.Log;
@@ -124,11 +123,7 @@
sAssertLibraryParams = false;
sExpectedParams = null;
}
- if (Build.VERSION.SDK_INT >= 18) {
- mHandler.getLooper().quitSafely();
- } else {
- mHandler.getLooper().quit();
- }
+ mHandler.getLooper().quitSafely();
mHandler = null;
TestServiceRegistry.getInstance().cleanUp();
}
diff --git a/media2/media2-session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSessionTestBase.java b/media2/media2-session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSessionTestBase.java
index 6db0c22..40529f8 100644
--- a/media2/media2-session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSessionTestBase.java
+++ b/media2/media2-session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSessionTestBase.java
@@ -17,7 +17,6 @@
package androidx.media2.test.service.tests;
import android.content.Context;
-import android.os.Build;
import android.os.Bundle;
import android.os.HandlerThread;
@@ -79,11 +78,7 @@
if (sHandler == null) {
return;
}
- if (Build.VERSION.SDK_INT >= 18) {
- sHandler.getLooper().quitSafely();
- } else {
- sHandler.getLooper().quit();
- }
+ sHandler.getLooper().quitSafely();
sHandler = null;
sHandlerExecutor = null;
}
diff --git a/media2/media2-session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSession_KeyEventTest.java b/media2/media2-session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSession_KeyEventTest.java
index 6104b39..c12f098 100644
--- a/media2/media2-session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSession_KeyEventTest.java
+++ b/media2/media2-session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSession_KeyEventTest.java
@@ -39,7 +39,6 @@
import androidx.media2.test.service.R;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
-import androidx.test.filters.SdkSuppress;
import org.junit.After;
import org.junit.Before;
@@ -54,7 +53,6 @@
* In order to get the media key events, the player state is set to 'Playing' before every test
* method.
*/
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT) // For AudioManager#dispatchMediaKeyEvent()
@RunWith(AndroidJUnit4.class)
@LargeTest
public class MediaSession_KeyEventTest extends MediaSessionTestBase {
diff --git a/media2/media2-widget/src/main/java/androidx/media2/widget/CaptioningManagerHelper.java b/media2/media2-widget/src/main/java/androidx/media2/widget/CaptioningManagerHelper.java
deleted file mode 100644
index d94b2ad..0000000
--- a/media2/media2-widget/src/main/java/androidx/media2/widget/CaptioningManagerHelper.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2021 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.media2.widget;
-
-import android.view.accessibility.CaptioningManager;
-
-import androidx.annotation.DoNotInline;
-import androidx.annotation.RequiresApi;
-
-import java.util.Locale;
-
-final class CaptioningManagerHelper {
-
- @RequiresApi(19)
- static final class Api19Impl {
-
- @DoNotInline
- static void addCaptioningChangeListener(CaptioningManager manager,
- CaptioningManager.CaptioningChangeListener listener) {
- manager.addCaptioningChangeListener(listener);
- }
-
- @DoNotInline
- static void removeCaptioningChangeListener(CaptioningManager manager,
- CaptioningManager.CaptioningChangeListener listener) {
- manager.removeCaptioningChangeListener(listener);
- }
-
- @DoNotInline
- static float getFontScale(CaptioningManager manager) {
- return manager.getFontScale();
- }
-
- @DoNotInline
- static Locale getLocale(CaptioningManager manager) {
- return manager.getLocale();
- }
-
- @DoNotInline
- static CaptioningManager.CaptionStyle getUserStyle(CaptioningManager manager) {
- return manager.getUserStyle();
- }
-
- @DoNotInline
- static boolean isEnabled(CaptioningManager manager) {
- return manager.isEnabled();
- }
-
- private Api19Impl() {}
- }
-
- private CaptioningManagerHelper() {}
-}
diff --git a/media2/media2-widget/src/main/java/androidx/media2/widget/Cea708CaptionRenderer.java b/media2/media2-widget/src/main/java/androidx/media2/widget/Cea708CaptionRenderer.java
index e7d9609..25c513c 100644
--- a/media2/media2-widget/src/main/java/androidx/media2/widget/Cea708CaptionRenderer.java
+++ b/media2/media2-widget/src/main/java/androidx/media2/widget/Cea708CaptionRenderer.java
@@ -787,17 +787,13 @@
addView(mCCView, params);
// Set the system wide CC preferences to the subtitle view.
- if (Build.VERSION.SDK_INT >= 19) {
- CaptioningManager captioningManager =
- (CaptioningManager) context.getSystemService(
- Context.CAPTIONING_SERVICE);
- mFontScale = CaptioningManagerHelper.Api19Impl.getFontScale(captioningManager);
- setCaptionStyle(new CaptionStyle(
- CaptioningManagerHelper.Api19Impl.getUserStyle(captioningManager)));
- } else {
- mFontScale = 1f;
- setCaptionStyle(CaptionStyle.DEFAULT);
- }
+ CaptioningManager captioningManager =
+ (CaptioningManager) context.getSystemService(
+ Context.CAPTIONING_SERVICE);
+ mFontScale = captioningManager.getFontScale();
+ setCaptionStyle(new CaptionStyle(
+ captioningManager.getUserStyle()));
+
mCCView.setText("");
updateWidestChar();
}
diff --git a/media2/media2-widget/src/main/java/androidx/media2/widget/ClosedCaptionWidget.java b/media2/media2-widget/src/main/java/androidx/media2/widget/ClosedCaptionWidget.java
index 70d7711..66c8cc2 100644
--- a/media2/media2-widget/src/main/java/androidx/media2/widget/ClosedCaptionWidget.java
+++ b/media2/media2-widget/src/main/java/androidx/media2/widget/ClosedCaptionWidget.java
@@ -17,7 +17,6 @@
package androidx.media2.widget;
import android.content.Context;
-import android.os.Build.VERSION;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
@@ -69,27 +68,21 @@
// Cannot render text over video when layer type is hardware.
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
- float fontScale = 1.f;
- if (VERSION.SDK_INT >= 19) {
- mCaptioningListener = new CaptioningChangeListener() {
- @Override
- public void onUserStyleChanged(CaptioningManager.CaptionStyle userStyle) {
- mCaptionStyle = new CaptionStyle(userStyle);
- mClosedCaptionLayout.setCaptionStyle(mCaptionStyle);
- }
+ mCaptioningListener = new CaptioningChangeListener() {
+ @Override
+ public void onUserStyleChanged(CaptioningManager.CaptionStyle userStyle) {
+ mCaptionStyle = new CaptionStyle(userStyle);
+ mClosedCaptionLayout.setCaptionStyle(mCaptionStyle);
+ }
- @Override
- public void onFontScaleChanged(float fontScale) {
- mClosedCaptionLayout.setFontScale(fontScale);
- }
- };
- mManager = (CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE);
- mCaptionStyle = new CaptionStyle(
- CaptioningManagerHelper.Api19Impl.getUserStyle(mManager));
- fontScale = CaptioningManagerHelper.Api19Impl.getFontScale(mManager);
- } else {
- mCaptionStyle = CaptionStyle.DEFAULT;
- }
+ @Override
+ public void onFontScaleChanged(float fontScale) {
+ mClosedCaptionLayout.setFontScale(fontScale);
+ }
+ };
+ mManager = (CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE);
+ mCaptionStyle = new CaptionStyle(mManager.getUserStyle());
+ float fontScale = mManager.getFontScale();
mClosedCaptionLayout = createCaptionLayout(context);
mClosedCaptionLayout.setCaptionStyle(mCaptionStyle);
@@ -156,20 +149,15 @@
* Manages whether this renderer is listening for caption style changes.
*/
private void manageChangeListener() {
- if (VERSION.SDK_INT < 19) {
- return;
- }
final boolean needsListener =
ViewCompat.isAttachedToWindow(this) && getVisibility() == View.VISIBLE;
if (mHasChangeListener != needsListener) {
mHasChangeListener = needsListener;
if (needsListener) {
- CaptioningManagerHelper.Api19Impl.addCaptioningChangeListener(mManager,
- mCaptioningListener);
+ mManager.addCaptioningChangeListener(mCaptioningListener);
} else {
- CaptioningManagerHelper.Api19Impl.removeCaptioningChangeListener(mManager,
- mCaptioningListener);
+ mManager.removeCaptioningChangeListener(mCaptioningListener);
}
}
}
diff --git a/media2/media2-widget/src/main/java/androidx/media2/widget/SubtitleController.java b/media2/media2-widget/src/main/java/androidx/media2/widget/SubtitleController.java
index d43ae78..4526353 100644
--- a/media2/media2-widget/src/main/java/androidx/media2/widget/SubtitleController.java
+++ b/media2/media2-widget/src/main/java/androidx/media2/widget/SubtitleController.java
@@ -20,7 +20,6 @@
import android.media.MediaFormat;
import android.media.MediaPlayer;
import android.media.MediaPlayer.TrackInfo;
-import android.os.Build.VERSION;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -100,30 +99,24 @@
mRenderers = new ArrayList<Renderer>();
mTracks = new ArrayList<SubtitleTrack>();
- if (VERSION.SDK_INT >= 19) {
- mCaptioningManager =
- (CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE);
- mCaptioningChangeListener =
- new CaptioningManager.CaptioningChangeListener() {
- @Override
- public void onEnabledChanged(boolean enabled) {
- selectDefaultTrack();
- }
+ mCaptioningManager =
+ (CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE);
+ mCaptioningChangeListener = new CaptioningManager.CaptioningChangeListener() {
+ @Override
+ public void onEnabledChanged(boolean enabled) {
+ selectDefaultTrack();
+ }
- @Override
- public void onLocaleChanged(Locale locale) {
- selectDefaultTrack();
- }
- };
- }
+ @Override
+ public void onLocaleChanged(Locale locale) {
+ selectDefaultTrack();
+ }
+ };
}
@Override
protected void finalize() throws Throwable {
- if (VERSION.SDK_INT >= 19) {
- CaptioningManagerHelper.Api19Impl.removeCaptioningChangeListener(mCaptioningManager,
- mCaptioningChangeListener);
- }
+ mCaptioningManager.removeCaptioningChangeListener(mCaptioningChangeListener);
super.finalize();
}
@@ -228,14 +221,12 @@
SubtitleTrack bestTrack = null;
int bestScore = -1;
- Locale selectedLocale = VERSION.SDK_INT >= 19
- ? CaptioningManagerHelper.Api19Impl.getLocale(mCaptioningManager) : null;
+ Locale selectedLocale = mCaptioningManager.getLocale();
Locale locale = selectedLocale;
if (locale == null) {
locale = Locale.getDefault();
}
- boolean selectForced = VERSION.SDK_INT >= 19
- ? !CaptioningManagerHelper.Api19Impl.isEnabled(mCaptioningManager) : true;
+ boolean selectForced = !mCaptioningManager.isEnabled();
synchronized (mTracksLock) {
for (SubtitleTrack track: mTracks) {
@@ -302,8 +293,7 @@
}
// If track selection is explicit, but visibility
// is not, it falls back to the captioning setting
- boolean captionIsEnabledOnSystem = VERSION.SDK_INT >= 19
- ? CaptioningManagerHelper.Api19Impl.isEnabled(mCaptioningManager) : false;
+ boolean captionIsEnabledOnSystem = mCaptioningManager.isEnabled();
if (captionIsEnabledOnSystem
|| (mSelectedTrack != null && MediaFormatUtil.getInteger(
mSelectedTrack.getFormat(),
@@ -337,10 +327,7 @@
mTracks.clear();
mTrackIsExplicit = false;
mVisibilityIsExplicit = false;
- if (VERSION.SDK_INT >= 19) {
- CaptioningManagerHelper.Api19Impl.removeCaptioningChangeListener(mCaptioningManager,
- mCaptioningChangeListener);
- }
+ mCaptioningManager.removeCaptioningChangeListener(mCaptioningChangeListener);
}
/**
@@ -357,9 +344,9 @@
SubtitleTrack track = renderer.createTrack(format);
if (track != null) {
synchronized (mTracksLock) {
- if (mTracks.size() == 0 && VERSION.SDK_INT >= 19) {
- CaptioningManagerHelper.Api19Impl.addCaptioningChangeListener(
- mCaptioningManager, mCaptioningChangeListener);
+ if (mTracks.size() == 0) {
+ mCaptioningManager.addCaptioningChangeListener(
+ mCaptioningChangeListener);
}
mTracks.add(track);
}
diff --git a/mediarouter/mediarouter/src/main/res/values-ca/strings.xml b/mediarouter/mediarouter/src/main/res/values-ca/strings.xml
index 6744047..a02305f 100644
--- a/mediarouter/mediarouter/src/main/res/values-ca/strings.xml
+++ b/mediarouter/mediarouter/src/main/res/values-ca/strings.xml
@@ -33,7 +33,7 @@
<string name="mr_controller_stop" msgid="5497722768305745508">"Atura"</string>
<string name="mr_controller_expand_group" msgid="4521419834052044261">"Desplega"</string>
<string name="mr_controller_collapse_group" msgid="2585048604188129749">"Replega"</string>
- <string name="mr_controller_album_art" msgid="3330502667672708728">"Imatge de l\'àlbum"</string>
+ <string name="mr_controller_album_art" msgid="3330502667672708728">"Coberta de l\'àlbum"</string>
<string name="mr_controller_volume_slider" msgid="2955862765169128170">"Control lliscant de volum"</string>
<string name="mr_controller_no_media_selected" msgid="5495452265246139458">"No hi ha contingut multimèdia seleccionat"</string>
<string name="mr_controller_no_info_available" msgid="855271725131981086">"No hi ha informació disponible"</string>
diff --git a/mediarouter/mediarouter/src/main/res/values-fa/strings.xml b/mediarouter/mediarouter/src/main/res/values-fa/strings.xml
index b27a5dc..d13e45f 100644
--- a/mediarouter/mediarouter/src/main/res/values-fa/strings.xml
+++ b/mediarouter/mediarouter/src/main/res/values-fa/strings.xml
@@ -33,7 +33,7 @@
<string name="mr_controller_stop" msgid="5497722768305745508">"متوقف کردن"</string>
<string name="mr_controller_expand_group" msgid="4521419834052044261">"بزرگ کردن"</string>
<string name="mr_controller_collapse_group" msgid="2585048604188129749">"کوچک کردن"</string>
- <string name="mr_controller_album_art" msgid="3330502667672708728">"عکس روی جلد آلبوم"</string>
+ <string name="mr_controller_album_art" msgid="3330502667672708728">"جلد آلبوم"</string>
<string name="mr_controller_volume_slider" msgid="2955862765169128170">"لغزنده میزان صدا"</string>
<string name="mr_controller_no_media_selected" msgid="5495452265246139458">"رسانهای انتخاب نشده است"</string>
<string name="mr_controller_no_info_available" msgid="855271725131981086">"اطلاعاتی در دسترس نیست"</string>
diff --git a/mediarouter/mediarouter/src/main/res/values-fr/strings.xml b/mediarouter/mediarouter/src/main/res/values-fr/strings.xml
index 754f775..dc37209 100644
--- a/mediarouter/mediarouter/src/main/res/values-fr/strings.xml
+++ b/mediarouter/mediarouter/src/main/res/values-fr/strings.xml
@@ -33,7 +33,7 @@
<string name="mr_controller_stop" msgid="5497722768305745508">"Arrêt"</string>
<string name="mr_controller_expand_group" msgid="4521419834052044261">"Développer"</string>
<string name="mr_controller_collapse_group" msgid="2585048604188129749">"Réduire"</string>
- <string name="mr_controller_album_art" msgid="3330502667672708728">"Image de l\'album"</string>
+ <string name="mr_controller_album_art" msgid="3330502667672708728">"Pochette de l\'album"</string>
<string name="mr_controller_volume_slider" msgid="2955862765169128170">"Curseur de volume"</string>
<string name="mr_controller_no_media_selected" msgid="5495452265246139458">"Aucun contenu multimédia sélectionné"</string>
<string name="mr_controller_no_info_available" msgid="855271725131981086">"Aucune information disponible"</string>
diff --git a/metrics/metrics-benchmark/src/androidTest/java/androidx/metrics/performance/benchmark/JankStatsBenchmark.kt b/metrics/metrics-benchmark/src/androidTest/java/androidx/metrics/performance/benchmark/JankStatsBenchmark.kt
index 3749d2b..3048ad2 100644
--- a/metrics/metrics-benchmark/src/androidTest/java/androidx/metrics/performance/benchmark/JankStatsBenchmark.kt
+++ b/metrics/metrics-benchmark/src/androidTest/java/androidx/metrics/performance/benchmark/JankStatsBenchmark.kt
@@ -114,7 +114,6 @@
}
}
- @RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
@Test
fun getFrameData() {
metricsStateHolder.state?.putState("Activity", "activity")
@@ -166,7 +165,6 @@
}
}
- @RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
@Test
fun logFrameData() {
metricsStateHolder.state?.putState("Activity", "activity")
diff --git a/metrics/metrics-performance/src/androidTest/java/androidx/metrics/performance/test/DelayedView.kt b/metrics/metrics-performance/src/androidTest/java/androidx/metrics/performance/test/DelayedView.kt
index b107f1f..28b77ce 100644
--- a/metrics/metrics-performance/src/androidTest/java/androidx/metrics/performance/test/DelayedView.kt
+++ b/metrics/metrics-performance/src/androidTest/java/androidx/metrics/performance/test/DelayedView.kt
@@ -4,10 +4,8 @@
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
-import android.os.Build
import android.util.AttributeSet
import android.view.View
-import androidx.annotation.RequiresApi
import androidx.metrics.performance.PerformanceMetricsState
class DelayedView(context: Context?, attrs: AttributeSet?) :
@@ -23,7 +21,6 @@
textPaint.textSize = 50f
}
- @RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
override fun onDraw(canvas: Canvas) {
repetitions++
if (delayMs > 0) {
@@ -54,11 +51,7 @@
}
}
if (repetitions < maxReps) {
- if (Build.VERSION.SDK_INT >= 16) {
- postInvalidateOnAnimation()
- } else {
- postInvalidate()
- }
+ postInvalidateOnAnimation()
}
}
}
diff --git a/metrics/metrics-performance/src/androidTest/java/androidx/metrics/performance/test/JankStatsTest.kt b/metrics/metrics-performance/src/androidTest/java/androidx/metrics/performance/test/JankStatsTest.kt
index 58b7ba0..18928bb 100644
--- a/metrics/metrics-performance/src/androidTest/java/androidx/metrics/performance/test/JankStatsTest.kt
+++ b/metrics/metrics-performance/src/androidTest/java/androidx/metrics/performance/test/JankStatsTest.kt
@@ -15,12 +15,9 @@
*/
package androidx.metrics.performance.test
-import android.os.Build
import android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1
-import android.os.Build.VERSION_CODES.JELLY_BEAN
import android.util.Log
import android.view.Choreographer
-import androidx.annotation.RequiresApi
import androidx.metrics.performance.FrameData
import androidx.metrics.performance.FrameDataApi24
import androidx.metrics.performance.FrameDataApi31
@@ -57,8 +54,6 @@
private lateinit var delayedView: DelayedView
private lateinit var latchedListener: LatchedListener
- private var frameInit: FrameInitCompat
-
private val NUM_FRAMES = 10
/**
@@ -67,14 +62,6 @@
*/
private val MIN_JANK_NS = 100000000
- init {
- if (Build.VERSION.SDK_INT >= 16) {
- frameInit = FrameInit16(this)
- } else {
- frameInit = FrameInitCompat(this)
- }
- }
-
@Rule
@JvmField
var delayedActivityRule: ActivityScenarioRule<DelayedActivity> =
@@ -172,12 +159,11 @@
assertNotEquals(frameData31, frameData31A)
}
- @SdkSuppress(minSdkVersion = JELLY_BEAN)
@Test
fun testNoJank() {
val frameDelay = 0
- frameInit.initFramePipeline()
+ initFramePipeline()
runDelayTest(frameDelay, NUM_FRAMES, latchedListener)
assertEquals("numJankFrames should equal 0", 0, latchedListener.numJankFrames)
@@ -194,13 +180,12 @@
)
}
- @SdkSuppress(minSdkVersion = JELLY_BEAN)
@Test
fun testMultipleListeners() {
var secondListenerLatch = CountDownLatch(0)
val frameDelay = 0
- frameInit.initFramePipeline()
+ initFramePipeline()
var numSecondListenerCalls = 0
val secondListenerStates = mutableListOf<StateInfo>()
@@ -264,12 +249,11 @@
runDelayTest(frameDelay, NUM_FRAMES * 100, latchedListener)
}
- @SdkSuppress(minSdkVersion = JELLY_BEAN)
@Test
fun testRegularJank() {
val frameDelay = 100
- frameInit.initFramePipeline()
+ initFramePipeline()
runDelayTest(frameDelay, NUM_FRAMES, latchedListener)
@@ -289,12 +273,11 @@
)
}
- @SdkSuppress(minSdkVersion = JELLY_BEAN)
@Test
fun testFrameStates() {
val frameDelay = 0
- frameInit.initFramePipeline()
+ initFramePipeline()
resetFrameStateData()
@@ -379,7 +362,7 @@
)
/**
- * Utility function (embedded in a class because it uses version-specific APIs) which
+ * Utility function which
* is used by tests which require the frame pipeline to be empty when they
* start. When the activity first starts, there are usually a couple of frames drawn.
* Depending on when those frames are drawn relative to when the JankStats object and
@@ -389,31 +372,24 @@
* begins, so that any data used by the test will only land on frames after the test begins
* instead of these old activity-creation frames.
*/
- open class FrameInitCompat(val jankStatsTest: JankStatsTest) {
- open fun initFramePipeline() {}
- }
-
- @RequiresApi(16)
- class FrameInit16(jankStatsTest: JankStatsTest) : FrameInitCompat(jankStatsTest) {
- override fun initFramePipeline() {
- val latch = CountDownLatch(10)
- var numFrames = 10
- val callback: Choreographer.FrameCallback = object : Choreographer.FrameCallback {
- override fun doFrame(frameTimeNanos: Long) {
- --numFrames
- latch.countDown()
- if (numFrames > 0) {
- Choreographer.getInstance().postFrameCallback(this)
- }
+ private fun initFramePipeline() {
+ val latch = CountDownLatch(10)
+ var numFrames = 10
+ val callback: Choreographer.FrameCallback = object : Choreographer.FrameCallback {
+ override fun doFrame(frameTimeNanos: Long) {
+ --numFrames
+ latch.countDown()
+ if (numFrames > 0) {
+ Choreographer.getInstance().postFrameCallback(this)
}
}
- jankStatsTest.delayedActivityRule.getScenario().onActivity {
- Choreographer.getInstance().postFrameCallback(callback)
- }
- latch.await(5, TimeUnit.SECONDS)
-
- jankStatsTest.latchedListener.reset()
}
+ delayedActivityRule.getScenario().onActivity {
+ Choreographer.getInstance().postFrameCallback(callback)
+ }
+ latch.await(5, TimeUnit.SECONDS)
+
+ latchedListener.reset()
}
/**
@@ -433,10 +409,9 @@
runDelayTest(0, NUM_FRAMES, latchedListener)
}
- @SdkSuppress(minSdkVersion = JELLY_BEAN)
@Test
fun testComplexFrameStateData() {
- frameInit.initFramePipeline()
+ initFramePipeline()
// perFrameStateData is a structure for testing which holds information about the
// states that should be added or removed on every frame. This functionality is
diff --git a/metrics/metrics-performance/src/main/java/androidx/metrics/performance/JankStats.kt b/metrics/metrics-performance/src/main/java/androidx/metrics/performance/JankStats.kt
index 9b13051..567ae1b 100644
--- a/metrics/metrics-performance/src/main/java/androidx/metrics/performance/JankStats.kt
+++ b/metrics/metrics-performance/src/main/java/androidx/metrics/performance/JankStats.kt
@@ -103,11 +103,8 @@
Build.VERSION.SDK_INT >= 22 -> {
JankStatsApi22Impl(this, decorView)
}
- Build.VERSION.SDK_INT >= 16 -> {
- JankStatsApi16Impl(this, decorView)
- }
else -> {
- JankStatsBaseImpl(this)
+ JankStatsApi16Impl(this, decorView)
}
}
implementation.setupFrameTimer(true)
diff --git a/metrics/metrics-performance/src/main/java/androidx/metrics/performance/JankStatsApi16Impl.kt b/metrics/metrics-performance/src/main/java/androidx/metrics/performance/JankStatsApi16Impl.kt
index 920fdb7..c2999cf6 100644
--- a/metrics/metrics-performance/src/main/java/androidx/metrics/performance/JankStatsApi16Impl.kt
+++ b/metrics/metrics-performance/src/main/java/androidx/metrics/performance/JankStatsApi16Impl.kt
@@ -29,7 +29,6 @@
* Subclass of JankStatsBaseImpl records frame timing data for API 16 and later,
* using Choreographer (which was introduced in API 16).
*/
-@RequiresApi(16)
internal open class JankStatsApi16Impl(
jankStats: JankStats,
view: View
diff --git a/metrics/metrics-performance/src/main/java/androidx/metrics/performance/JankStatsInternalsForTesting.kt b/metrics/metrics-performance/src/main/java/androidx/metrics/performance/JankStatsInternalsForTesting.kt
index b4f5083..2030fa6 100644
--- a/metrics/metrics-performance/src/main/java/androidx/metrics/performance/JankStatsInternalsForTesting.kt
+++ b/metrics/metrics-performance/src/main/java/androidx/metrics/performance/JankStatsInternalsForTesting.kt
@@ -35,7 +35,6 @@
performanceMetricsState.removeStateNow(stateName)
}
- @RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
fun getFrameData(): FrameData? {
when (impl) {
is JankStatsApi16Impl -> {
@@ -55,7 +54,6 @@
return null
}
- @RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
fun logFrameData(frameData: FrameData) {
jankStats.logFrameData(frameData)
}
diff --git a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavGraphTest.kt b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavGraphTest.kt
index c0b072a..937c4c8 100644
--- a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavGraphTest.kt
+++ b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavGraphTest.kt
@@ -97,6 +97,34 @@
.isFalse()
}
+ @Test
+ fun graphEqualsId() {
+ val graph = NavGraph(navGraphNavigator)
+ graph += navigator.createDestination().apply { id = DESTINATION_ID }
+ graph += navigator.createDestination().apply { id = SECOND_DESTINATION_ID }
+ val other = NavGraph(navGraphNavigator)
+ other += navigator.createDestination().apply { id = DESTINATION_ID }
+ other += navigator.createDestination().apply { id = SECOND_DESTINATION_ID }
+
+ assertWithMessage("Graphs should be equal")
+ .that(graph)
+ .isEqualTo(other)
+ }
+
+ @Test
+ fun graphNotEqualsId() {
+ val graph = NavGraph(navGraphNavigator)
+ graph += navigator.createDestination().apply { id = DESTINATION_ID }
+ graph += navigator.createDestination().apply { id = SECOND_DESTINATION_ID }
+ val other = NavGraph(navGraphNavigator)
+ other += navigator.createDestination().apply { id = DESTINATION_ID }
+ other += navigator.createDestination().apply { id = 3 }
+
+ assertWithMessage("Graphs should not be equal")
+ .that(graph)
+ .isNotEqualTo(other)
+ }
+
@Test(expected = IllegalArgumentException::class)
fun getIllegalArgumentException() {
val graph = NavGraph(navGraphNavigator)
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NavGraph.kt b/navigation/navigation-common/src/main/java/androidx/navigation/NavGraph.kt
index f4b21df..1e1020e 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavGraph.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavGraph.kt
@@ -384,7 +384,7 @@
return super.equals(other) &&
nodes.size == other.nodes.size &&
startDestinationId == other.startDestinationId &&
- nodes.valueIterator().asSequence().all { it == nodes.get(it.id) }
+ nodes.valueIterator().asSequence().all { it == other.nodes.get(it.id) }
}
override fun hashCode(): Int {
diff --git a/percentlayout/percentlayout/src/androidTest/java/androidx/percentlayout/widget/PercentRelativeRtlTest.java b/percentlayout/percentlayout/src/androidTest/java/androidx/percentlayout/widget/PercentRelativeRtlTest.java
index 640be5b..68d01a3 100644
--- a/percentlayout/percentlayout/src/androidTest/java/androidx/percentlayout/widget/PercentRelativeRtlTest.java
+++ b/percentlayout/percentlayout/src/androidTest/java/androidx/percentlayout/widget/PercentRelativeRtlTest.java
@@ -161,22 +161,14 @@
@Test
public void testStartChild() {
- if (Build.VERSION.SDK_INT == 17) {
- return;
- }
+
final View childToTest = mPercentRelativeLayout.findViewById(R.id.child_start);
- if (Build.VERSION.SDK_INT >= 17) {
- switchToRtl();
+ switchToRtl();
- final int childRight = childToTest.getRight();
- assertFuzzyEquals("Child start margin as 5% of the container",
- 0.05f * mContainerWidth, mContainerWidth - childRight);
- } else {
- final int childLeft = childToTest.getLeft();
- assertFuzzyEquals("Child start margin as 5% of the container",
- 0.05f * mContainerWidth, childLeft);
- }
+ final int childRight = childToTest.getRight();
+ assertFuzzyEquals("Child start margin as 5% of the container",
+ 0.05f * mContainerWidth, mContainerWidth - childRight);
final int childWidth = childToTest.getWidth();
final int childHeight = childToTest.getHeight();
@@ -194,23 +186,13 @@
@Test
public void testBottomChild() {
- if (Build.VERSION.SDK_INT == 17) {
- return;
- }
final View childToTest = mPercentRelativeLayout.findViewById(R.id.child_bottom);
- if (Build.VERSION.SDK_INT >= 17) {
- switchToRtl();
+ switchToRtl();
- final int childLeft = childToTest.getLeft();
- assertFuzzyEquals("Child end margin as 20% of the container",
- 0.2f * mContainerWidth, childLeft);
- } else {
- final int childRight = childToTest.getRight();
- assertFuzzyEquals("Child end margin as 20% of the container",
- 0.2f * mContainerWidth, mContainerWidth - childRight);
- }
-
+ final int childLeft = childToTest.getLeft();
+ assertFuzzyEquals("Child end margin as 20% of the container",
+ 0.2f * mContainerWidth, childLeft);
final int childWidth = childToTest.getWidth();
final int childHeight = childToTest.getHeight();
@@ -228,22 +210,13 @@
@Test
public void testEndChild() {
- if (Build.VERSION.SDK_INT == 17) {
- return;
- }
final View childToTest = mPercentRelativeLayout.findViewById(R.id.child_end);
- if (Build.VERSION.SDK_INT >= 17) {
- switchToRtl();
+ switchToRtl();
- final int childLeft = childToTest.getLeft();
- assertFuzzyEquals("Child end margin as 5% of the container",
- 0.05f * mContainerWidth, childLeft);
- } else {
- final int childRight = childToTest.getRight();
- assertFuzzyEquals("Child end margin as 5% of the container",
- 0.05f * mContainerWidth, mContainerWidth - childRight);
- }
+ final int childLeft = childToTest.getLeft();
+ assertFuzzyEquals("Child end margin as 5% of the container",
+ 0.05f * mContainerWidth, childLeft);
final int childWidth = childToTest.getWidth();
final int childHeight = childToTest.getHeight();
@@ -261,24 +234,15 @@
@Test
public void testCenterChild() {
- if (Build.VERSION.SDK_INT == 17) {
- return;
- }
final View childToTest = mPercentRelativeLayout.findViewById(R.id.child_center);
-
- boolean supportsRtl = Build.VERSION.SDK_INT >= 17;
- if (supportsRtl) {
- switchToRtl();
- }
+ switchToRtl();
final int childLeft = childToTest.getLeft();
final int childTop = childToTest.getTop();
final int childRight = childToTest.getRight();
final int childBottom = childToTest.getBottom();
- final View leftChild = supportsRtl
- ? mPercentRelativeLayout.findViewById(R.id.child_end)
- : mPercentRelativeLayout.findViewById(R.id.child_start);
+ final View leftChild = mPercentRelativeLayout.findViewById(R.id.child_end);
assertFuzzyEquals("Child left margin as 10% of the container",
leftChild.getRight() + 0.1f * mContainerWidth, childLeft);
@@ -286,9 +250,8 @@
assertFuzzyEquals("Child top margin as 10% of the container",
topChild.getBottom() + 0.1f * mContainerHeight, childTop);
- final View rightChild = supportsRtl
- ? mPercentRelativeLayout.findViewById(R.id.child_start)
- : mPercentRelativeLayout.findViewById(R.id.child_end);
+ final View rightChild = mPercentRelativeLayout.findViewById(R.id.child_start);
+
assertFuzzyEquals("Child right margin as 10% of the container",
rightChild.getLeft() - 0.1f * mContainerWidth, childRight);
diff --git a/playground-common/gradle/wrapper/gradle-wrapper.properties b/playground-common/gradle/wrapper/gradle-wrapper.properties
index d55a029..9cac784 100644
--- a/playground-common/gradle/wrapper/gradle-wrapper.properties
+++ b/playground-common/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
-distributionSha256Sum=3e1af3ae886920c3ac87f7a91f816c0c7c436f276a6eefdb3da152100fef72ae
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
+distributionSha256Sum=9d926787066a081739e8200858338b4a69e837c3a821a33aca9db09dd4a41026
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/print/print/src/main/java/androidx/print/PrintHelper.java b/print/print/src/main/java/androidx/print/PrintHelper.java
index 01f01f7..6a0aa14 100644
--- a/print/print/src/main/java/androidx/print/PrintHelper.java
+++ b/print/print/src/main/java/androidx/print/PrintHelper.java
@@ -155,7 +155,7 @@
*/
public static boolean systemSupportsPrint() {
// Supported on Android 4.4 or later.
- return Build.VERSION.SDK_INT >= 19;
+ return true;
}
/**
@@ -233,7 +233,7 @@
*/
public int getOrientation() {
// Unset defaults to landscape but might turn image
- if (Build.VERSION.SDK_INT >= 19 && mOrientation == 0) {
+ if (mOrientation == 0) {
return ORIENTATION_LANDSCAPE;
}
return mOrientation;
@@ -259,7 +259,7 @@
*/
public void printBitmap(@NonNull final String jobName, @NonNull final Bitmap bitmap,
@Nullable final OnPrintFinishCallback callback) {
- if (Build.VERSION.SDK_INT < 19 || bitmap == null) {
+ if (bitmap == null) {
return;
}
@@ -357,10 +357,6 @@
public void printBitmap(@NonNull final String jobName, @NonNull final Uri imageFile,
@Nullable final OnPrintFinishCallback callback)
throws FileNotFoundException {
- if (Build.VERSION.SDK_INT < 19) {
- return;
- }
-
PrintDocumentAdapter printDocumentAdapter = new PrintUriAdapter(jobName, imageFile,
callback, mScaleMode);
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompatSandboxedTest.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompatSandboxedTest.kt
index 2f31e22..1d50290 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompatSandboxedTest.kt
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompatSandboxedTest.kt
@@ -22,14 +22,10 @@
import android.app.sdksandbox.SdkSandboxManager
import android.content.Context
import android.os.Binder
-import android.os.Build
import android.os.Bundle
import android.os.IBinder
import android.os.OutcomeReceiver
-import android.os.ext.SdkExtensions.AD_SERVICES
-import androidx.annotation.RequiresExtension
import androidx.privacysandbox.sdkruntime.client.loader.asTestSdk
-import androidx.privacysandbox.sdkruntime.core.AdServicesInfo
import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -39,8 +35,6 @@
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Assert.assertThrows
-import org.junit.Assume.assumeFalse
-import org.junit.Assume.assumeTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -52,23 +46,19 @@
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
-import org.mockito.Mockito.verifyZeroInteractions
import org.mockito.Mockito.`when`
import org.mockito.invocation.InvocationOnMock
@SmallTest
@RunWith(AndroidJUnit4::class)
// TODO(b/249982507) Test should be rewritten to use real SDK in sandbox instead of mocking manager
-// TODO(b/262577044) Remove RequiresExtension after extensions support in @SdkSuppress
-@RequiresExtension(extension = AD_SERVICES, version = 4)
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
+@SdkSuppress(minSdkVersion = 34)
class SdkSandboxManagerCompatSandboxedTest {
private lateinit var mContext: Context
@Before
fun setUp() {
- assumeTrue("Requires Sandbox API available", isSandboxApiAvailable())
mContext = Mockito.spy(ApplicationProvider.getApplicationContext<Context>())
}
@@ -171,7 +161,6 @@
}
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
fun startSdkSandboxActivity_whenSandboxAvailable_delegateToPlatform() {
val sdkSandboxManager = mockSandboxManager(mContext)
val managerCompat = SdkSandboxManagerCompat.from(mContext)
@@ -222,43 +211,7 @@
}
@Test
- fun getSandboxedSdks_whenLoadedSdkListNotAvailable_dontDelegateToSandbox() {
- assumeFalse("Requires getSandboxedSdks API not available", isAtLeastV5())
-
- val sdkSandboxManager = mockSandboxManager(mContext)
- val managerCompat = SdkSandboxManagerCompat.from(mContext)
-
- managerCompat.getSandboxedSdks()
-
- verifyZeroInteractions(sdkSandboxManager)
- }
-
- @Test
- fun getSandboxedSdks_whenLoadedSdkListNotAvailable_returnsLocallyLoadedSdkList() {
- assumeFalse("Requires getSandboxedSdks API not available", isAtLeastV5())
-
- // SdkSandboxManagerCompat.from require SandboxManager available for AdServices version >= 4
- mockSandboxManager(mContext)
- val managerCompat = SdkSandboxManagerCompat.from(mContext)
-
- val localSdk = runBlocking {
- managerCompat.loadSdk(
- TestSdkConfigs.CURRENT.packageName,
- Bundle()
- )
- }
-
- val sandboxedSdks = managerCompat.getSandboxedSdks()
-
- assertThat(sandboxedSdks).containsExactly(localSdk)
- }
-
- @Test
- // TODO(b/262577044) Remove RequiresExtension after extensions support in @SdkSuppress
- @RequiresExtension(extension = AD_SERVICES, version = 5)
- fun getSandboxedSdks_whenLoadedSdkListAvailable_returnCombinedLocalAndPlatformResult() {
- assumeTrue("Requires getSandboxedSdks API available", isAtLeastV5())
-
+ fun getSandboxedSdks_whenSandboxAvailable_returnCombinedLocalAndPlatformResult() {
val sdkSandboxManager = mockSandboxManager(mContext)
val sandboxedSdk = SandboxedSdk(Binder())
`when`(sdkSandboxManager.sandboxedSdks)
@@ -279,11 +232,7 @@
}
@Test
- // TODO(b/262577044) Remove RequiresExtension after extensions support in @SdkSuppress
- @RequiresExtension(extension = AD_SERVICES, version = 5)
fun sdkController_getSandboxedSdks_dontIncludeSandboxedSdk() {
- assumeTrue("Requires getSandboxedSdks API available", isAtLeastV5())
-
val sdkSandboxManager = mockSandboxManager(mContext)
val sandboxedSdk = SandboxedSdk(Binder())
`when`(sdkSandboxManager.sandboxedSdks)
@@ -306,55 +255,46 @@
assertThat(result).isEqualTo(localSdk.getInterface())
}
- companion object SandboxApi {
+ private fun mockSandboxManager(spyContext: Context): SdkSandboxManager {
+ val sdkSandboxManager = mock(SdkSandboxManager::class.java)
+ `when`(spyContext.getSystemService(SdkSandboxManager::class.java))
+ .thenReturn(sdkSandboxManager)
+ return sdkSandboxManager
+ }
- private fun isSandboxApiAvailable() =
- AdServicesInfo.isAtLeastV4()
-
- private fun isAtLeastV5() =
- AdServicesInfo.isAtLeastV5()
-
- private fun mockSandboxManager(spyContext: Context): SdkSandboxManager {
- val sdkSandboxManager = mock(SdkSandboxManager::class.java)
- `when`(spyContext.getSystemService(SdkSandboxManager::class.java))
- .thenReturn(sdkSandboxManager)
- return sdkSandboxManager
+ private fun setupLoadSdkAnswer(
+ sdkSandboxManager: SdkSandboxManager,
+ sandboxedSdk: SandboxedSdk
+ ) {
+ val answer = { args: InvocationOnMock ->
+ val receiver = args.getArgument<OutcomeReceiver<SandboxedSdk, LoadSdkException>>(3)
+ receiver.onResult(sandboxedSdk)
+ null
}
+ doAnswer(answer)
+ .`when`(sdkSandboxManager).loadSdk(
+ any(),
+ any(),
+ any(),
+ any()
+ )
+ }
- private fun setupLoadSdkAnswer(
- sdkSandboxManager: SdkSandboxManager,
- sandboxedSdk: SandboxedSdk
- ) {
- val answer = { args: InvocationOnMock ->
- val receiver = args.getArgument<OutcomeReceiver<SandboxedSdk, LoadSdkException>>(3)
- receiver.onResult(sandboxedSdk)
- null
- }
- doAnswer(answer)
- .`when`(sdkSandboxManager).loadSdk(
- any(),
- any(),
- any(),
- any()
- )
+ private fun setupLoadSdkAnswer(
+ sdkSandboxManager: SdkSandboxManager,
+ loadSdkException: LoadSdkException
+ ) {
+ val answer = { args: InvocationOnMock ->
+ val receiver = args.getArgument<OutcomeReceiver<SandboxedSdk, LoadSdkException>>(3)
+ receiver.onError(loadSdkException)
+ null
}
-
- private fun setupLoadSdkAnswer(
- sdkSandboxManager: SdkSandboxManager,
- loadSdkException: LoadSdkException
- ) {
- val answer = { args: InvocationOnMock ->
- val receiver = args.getArgument<OutcomeReceiver<SandboxedSdk, LoadSdkException>>(3)
- receiver.onError(loadSdkException)
- null
- }
- doAnswer(answer)
- .`when`(sdkSandboxManager).loadSdk(
- any(),
- any(),
- any(),
- any()
- )
- }
+ doAnswer(answer)
+ .`when`(sdkSandboxManager).loadSdk(
+ any(),
+ any(),
+ any(),
+ any()
+ )
}
}
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompatTest.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompatTest.kt
index 5ee872d..81d35cf 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompatTest.kt
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompatTest.kt
@@ -15,18 +15,15 @@
*/
package androidx.privacysandbox.sdkruntime.client
-import android.app.Activity
import android.content.Context
import android.content.ContextWrapper
import android.os.Binder
-import android.os.Build
import android.os.Bundle
import androidx.privacysandbox.sdkruntime.client.activity.LocalSdkActivityHandlerRegistry
import androidx.privacysandbox.sdkruntime.client.activity.SdkActivity
import androidx.privacysandbox.sdkruntime.client.loader.CatchingSdkActivityHandler
import androidx.privacysandbox.sdkruntime.client.loader.asTestSdk
import androidx.privacysandbox.sdkruntime.client.loader.extractSdkProviderFieldValue
-import androidx.privacysandbox.sdkruntime.core.AdServicesInfo
import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException
import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException.Companion.LOAD_SDK_INTERNAL_ERROR
import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException.Companion.LOAD_SDK_SDK_DEFINED_ERROR
@@ -41,13 +38,8 @@
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Assert.assertThrows
-import org.junit.Assume.assumeTrue
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mockito
-import org.mockito.Mockito.any
-import org.mockito.Mockito.spy
-import org.mockito.Mockito.verify
@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -80,29 +72,8 @@
}
@Test
- // TODO(b/249982507) DexmakerMockitoInline requires P+. Rewrite to support P-
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.P)
- fun loadSdk_whenNoLocalSdkExistsAndSandboxNotAvailable_dontDelegateToSandbox() {
- // TODO(b/262577044) Replace with @SdkSuppress after supporting maxExtensionVersion
- assumeTrue("Requires Sandbox API not available", isSandboxApiNotAvailable())
-
- val context = spy(ApplicationProvider.getApplicationContext<Context>())
- val managerCompat = SdkSandboxManagerCompat.from(context)
-
- assertThrows(LoadSdkCompatException::class.java) {
- runBlocking {
- managerCompat.loadSdk("sdk-not-exists", Bundle())
- }
- }
-
- verify(context, Mockito.never()).getSystemService(any())
- }
-
- @Test
- fun loadSdk_whenNoLocalSdkExistsAndSandboxNotAvailable_throwsSdkNotFoundException() {
- // TODO(b/262577044) Replace with @SdkSuppress after supporting maxExtensionVersion
- assumeTrue("Requires Sandbox API not available", isSandboxApiNotAvailable())
-
+ @SdkSuppress(maxSdkVersion = 33)
+ fun loadSdk_whenNoLocalSdkExistsAndApiBelow34_throwsSdkNotFoundException() {
val context = ApplicationProvider.getApplicationContext<Context>()
val managerCompat = SdkSandboxManagerCompat.from(context)
@@ -203,18 +174,11 @@
}
@Test
- // TODO(b/249982507) DexmakerMockitoInline requires P+. Rewrite to support P-
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.P)
- fun unloadSdk_whenNoLocalSdkLoadedAndSandboxNotAvailable_dontDelegateToSandbox() {
- // TODO(b/262577044) Replace with @SdkSuppress after supporting maxExtensionVersion
- assumeTrue("Requires Sandbox API not available", isSandboxApiNotAvailable())
-
- val context = spy(ApplicationProvider.getApplicationContext<Context>())
+ @SdkSuppress(maxSdkVersion = 33)
+ fun unloadSdk_whenNoLocalSdkLoadedAndApiBelow34_doesntThrow() {
+ val context = ApplicationProvider.getApplicationContext<Context>()
val managerCompat = SdkSandboxManagerCompat.from(context)
-
managerCompat.unloadSdk("sdk-not-loaded")
-
- verify(context, Mockito.never()).getSystemService(any())
}
@Test
@@ -268,13 +232,9 @@
}
@Test
- // TODO(b/249982507) DexmakerMockitoInline requires P+. Rewrite to support P-
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.P)
- fun addSdkSandboxProcessDeathCallback_whenSandboxNotAvailable_dontDelegateToSandbox() {
- // TODO(b/262577044) Replace with @SdkSuppress after supporting maxExtensionVersion
- assumeTrue("Requires Sandbox API not available", isSandboxApiNotAvailable())
-
- val context = spy(ApplicationProvider.getApplicationContext<Context>())
+ @SdkSuppress(maxSdkVersion = 33)
+ fun addSdkSandboxProcessDeathCallback_whenApiBelow34_doesntThrow() {
+ val context = ApplicationProvider.getApplicationContext<Context>()
val managerCompat = SdkSandboxManagerCompat.from(context)
managerCompat.addSdkSandboxProcessDeathCallback(Runnable::run, object :
@@ -282,18 +242,12 @@
override fun onSdkSandboxDied() {
}
})
-
- verify(context, Mockito.never()).getSystemService(any())
}
@Test
- // TODO(b/249982507) DexmakerMockitoInline requires P+. Rewrite to support P-
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.P)
- fun removeSdkSandboxProcessDeathCallback_whenSandboxNotAvailable_dontDelegateToSandbox() {
- // TODO(b/262577044) Replace with @SdkSuppress after supporting maxExtensionVersion
- assumeTrue("Requires Sandbox API not available", isSandboxApiNotAvailable())
-
- val context = spy(ApplicationProvider.getApplicationContext<Context>())
+ @SdkSuppress(maxSdkVersion = 33)
+ fun removeSdkSandboxProcessDeathCallback_whenApiBelow34_doesntThrow() {
+ val context = ApplicationProvider.getApplicationContext<Context>()
val managerCompat = SdkSandboxManagerCompat.from(context)
managerCompat.removeSdkSandboxProcessDeathCallback(object :
@@ -301,39 +255,37 @@
override fun onSdkSandboxDied() {
}
})
-
- verify(context, Mockito.never()).getSystemService(any())
}
@Test
- // TODO(b/249982507) DexmakerMockitoInline requires P+. Rewrite to support P-
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.P)
- fun getSandboxedSdks_whenSandboxNotAvailable_dontDelegateToSandbox() {
- // TODO(b/262577044) Replace with @SdkSuppress after supporting maxExtensionVersion
- assumeTrue("Requires Sandbox API not available", isSandboxApiNotAvailable())
-
- val context = spy(ApplicationProvider.getApplicationContext<Context>())
+ @SdkSuppress(maxSdkVersion = 33)
+ fun getSandboxedSdks_whenApiBelow34_returnsLocallyLoadedSdkList() {
+ val context = ApplicationProvider.getApplicationContext<Context>()
val managerCompat = SdkSandboxManagerCompat.from(context)
- managerCompat.getSandboxedSdks()
+ val localSdk = runBlocking {
+ managerCompat.loadSdk(
+ TestSdkConfigs.CURRENT.packageName,
+ Bundle()
+ )
+ }
- verify(context, Mockito.never()).getSystemService(any())
+ val sandboxedSdks = managerCompat.getSandboxedSdks()
+
+ assertThat(sandboxedSdks).containsExactly(localSdk)
}
@Test
- // TODO(b/249982507) DexmakerMockitoInline requires P+. Rewrite to support P-
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.P)
- fun startSdkSandboxActivity_whenSandboxNotAvailable_dontDelegateToSandbox() {
- // TODO(b/262577044) Replace with @SdkSuppress after supporting maxExtensionVersion
- assumeTrue("Requires Sandbox API not available", isSandboxApiNotAvailable())
-
- val context = spy(ApplicationProvider.getApplicationContext<Context>())
+ @SdkSuppress(maxSdkVersion = 33)
+ fun startSdkSandboxActivity_whenNoHandlerRegisteredAndApiBelow34_doesntThrow() {
+ val context = ApplicationProvider.getApplicationContext<Context>()
val managerCompat = SdkSandboxManagerCompat.from(context)
- val fromActivitySpy = Mockito.mock(Activity::class.java)
- managerCompat.startSdkSandboxActivity(fromActivitySpy, Binder())
-
- verify(context, Mockito.never()).getSystemService(any())
+ with(ActivityScenario.launch(EmptyActivity::class.java)) {
+ withActivity {
+ managerCompat.startSdkSandboxActivity(this, Binder())
+ }
+ }
}
@Test
@@ -392,27 +344,4 @@
anotherLocalSdk.getInterface(),
)
}
-
- @Test
- fun getSandboxedSdks_whenSandboxNotAvailable_returnsLocallyLoadedSdkList() {
- // TODO(b/262577044) Replace with @SdkSuppress after supporting maxExtensionVersion
- assumeTrue("Requires Sandbox API not available", isSandboxApiNotAvailable())
-
- val context = ApplicationProvider.getApplicationContext<Context>()
- val managerCompat = SdkSandboxManagerCompat.from(context)
-
- val localSdk = runBlocking {
- managerCompat.loadSdk(
- TestSdkConfigs.CURRENT.packageName,
- Bundle()
- )
- }
-
- val sandboxedSdks = managerCompat.getSandboxedSdks()
-
- assertThat(sandboxedSdks).containsExactly(localSdk)
- }
-
- private fun isSandboxApiNotAvailable() =
- !AdServicesInfo.isAtLeastV4()
}
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompat.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompat.kt
index a3f2e01..59ee471 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompat.kt
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompat.kt
@@ -24,10 +24,8 @@
import android.os.Build
import android.os.Bundle
import android.os.IBinder
-import android.os.ext.SdkExtensions.AD_SERVICES
import androidx.annotation.DoNotInline
import androidx.annotation.RequiresApi
-import androidx.annotation.RequiresExtension
import androidx.core.os.BuildCompat
import androidx.core.os.asOutcomeReceiver
import androidx.privacysandbox.sdkruntime.client.activity.LocalSdkActivityHandlerRegistry
@@ -290,14 +288,14 @@
)
@DoNotInline
- fun getSandboxedSdks(): List<SandboxedSdkCompat> = emptyList()
+ fun getSandboxedSdks(): List<SandboxedSdkCompat>
fun startSdkSandboxActivity(fromActivity: Activity, sdkActivityToken: IBinder)
}
- @RequiresApi(33)
- @RequiresExtension(extension = AD_SERVICES, version = 4)
- private open class ApiAdServicesV4Impl(context: Context) : PlatformApi {
+ @RequiresApi(34)
+ @SuppressLint("NewApi", "ClassVerificationFailure") // until updating checks to requires api 34
+ private open class Api34Impl(context: Context) : PlatformApi {
protected val sdkSandboxManager = context.getSystemService(
SdkSandboxManager::class.java
)
@@ -322,6 +320,12 @@
sdkSandboxManager.unloadSdk(sdkName)
}
+ override fun getSandboxedSdks(): List<SandboxedSdkCompat> {
+ return sdkSandboxManager
+ .sandboxedSdks
+ .map { platformSdk -> SandboxedSdkCompat(platformSdk) }
+ }
+
@DoNotInline
override fun addSdkSandboxProcessDeathCallback(
callbackExecutor: Executor,
@@ -350,9 +354,7 @@
}
override fun startSdkSandboxActivity(fromActivity: Activity, sdkActivityToken: IBinder) {
- throw UnsupportedOperationException(
- "This API is only supported for devices run on Android U+"
- )
+ sdkSandboxManager.startSdkSandboxActivity(fromActivity, sdkActivityToken)
}
private suspend fun loadSdkInternal(
@@ -379,29 +381,6 @@
}
}
- @RequiresApi(33)
- @RequiresExtension(extension = AD_SERVICES, version = 5)
- private open class ApiAdServicesV5Impl(
- context: Context
- ) : ApiAdServicesV4Impl(context) {
- @DoNotInline
- override fun getSandboxedSdks(): List<SandboxedSdkCompat> {
- return sdkSandboxManager
- .sandboxedSdks
- .map { platformSdk -> SandboxedSdkCompat(platformSdk) }
- }
- }
-
- @RequiresExtension(extension = AD_SERVICES, version = 5)
- @RequiresApi(34)
- private class ApiAdServicesUDCImpl(
- context: Context
- ) : ApiAdServicesV5Impl(context) {
- override fun startSdkSandboxActivity(fromActivity: Activity, sdkActivityToken: IBinder) {
- sdkSandboxManager.startSdkSandboxActivity(fromActivity, sdkActivityToken)
- }
- }
-
private class FailImpl : PlatformApi {
@DoNotInline
override suspend fun loadSdk(
@@ -414,6 +393,8 @@
override fun unloadSdk(sdkName: String) {
}
+ override fun getSandboxedSdks(): List<SandboxedSdkCompat> = emptyList()
+
override fun addSdkSandboxProcessDeathCallback(
callbackExecutor: Executor,
callback: SdkSandboxProcessDeathCallbackCompat
@@ -474,14 +455,9 @@
}
private object PlatformApiFactory {
- @SuppressLint("NewApi", "ClassVerificationFailure")
fun create(context: Context): PlatformApi {
return if (Build.VERSION.SDK_INT >= 34 || AdServicesInfo.isDeveloperPreview()) {
- ApiAdServicesUDCImpl(context)
- } else if (AdServicesInfo.isAtLeastV5()) {
- ApiAdServicesV5Impl(context)
- } else if (AdServicesInfo.isAtLeastV4()) {
- ApiAdServicesV4Impl(context)
+ Api34Impl(context)
} else {
FailImpl()
}
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/api/current.txt b/privacysandbox/sdkruntime/sdkruntime-core/api/current.txt
index 2e8451a..73911a2 100644
--- a/privacysandbox/sdkruntime/sdkruntime-core/api/current.txt
+++ b/privacysandbox/sdkruntime/sdkruntime-core/api/current.txt
@@ -40,12 +40,6 @@
property public final long version;
}
- @Deprecated @RequiresExtension(extension=android.os.ext.SdkExtensions.AD_SERVICES, version=4) public final class SandboxedSdkProviderAdapter extends android.app.sdksandbox.SandboxedSdkProvider {
- ctor @Deprecated public SandboxedSdkProviderAdapter();
- method @Deprecated public android.view.View getView(android.content.Context windowContext, android.os.Bundle params, int width, int height);
- method @Deprecated @kotlin.jvm.Throws(exceptionClasses=LoadSdkException::class) public android.app.sdksandbox.SandboxedSdk onLoadSdk(android.os.Bundle params) throws android.app.sdksandbox.LoadSdkException;
- }
-
public abstract class SandboxedSdkProviderCompat {
ctor public SandboxedSdkProviderCompat();
method public final void attachContext(android.content.Context context);
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/api/restricted_current.txt b/privacysandbox/sdkruntime/sdkruntime-core/api/restricted_current.txt
index 2e8451a..73911a2 100644
--- a/privacysandbox/sdkruntime/sdkruntime-core/api/restricted_current.txt
+++ b/privacysandbox/sdkruntime/sdkruntime-core/api/restricted_current.txt
@@ -40,12 +40,6 @@
property public final long version;
}
- @Deprecated @RequiresExtension(extension=android.os.ext.SdkExtensions.AD_SERVICES, version=4) public final class SandboxedSdkProviderAdapter extends android.app.sdksandbox.SandboxedSdkProvider {
- ctor @Deprecated public SandboxedSdkProviderAdapter();
- method @Deprecated public android.view.View getView(android.content.Context windowContext, android.os.Bundle params, int width, int height);
- method @Deprecated @kotlin.jvm.Throws(exceptionClasses=LoadSdkException::class) public android.app.sdksandbox.SandboxedSdk onLoadSdk(android.os.Bundle params) throws android.app.sdksandbox.LoadSdkException;
- }
-
public abstract class SandboxedSdkProviderCompat {
ctor public SandboxedSdkProviderCompat();
method public final void attachContext(android.content.Context context);
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/assets/SandboxedSdkProviderCompatClassName.txt b/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/assets/SandboxedSdkProviderCompatClassName.txt
deleted file mode 100644
index 3d062e4..0000000
--- a/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/assets/SandboxedSdkProviderCompatClassName.txt
+++ /dev/null
@@ -1 +0,0 @@
-androidx.privacysandbox.sdkruntime.core.SandboxedSdkProviderAdapterTest$TestOnLoadReturnResultSdkProvider
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkProviderAdapterTest.kt b/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkProviderAdapterTest.kt
deleted file mode 100644
index ba919c3..0000000
--- a/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkProviderAdapterTest.kt
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * Copyright 2022 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.privacysandbox.sdkruntime.core
-
-import android.app.sdksandbox.LoadSdkException
-import android.content.Context
-import android.os.Binder
-import android.os.Build.VERSION_CODES.TIRAMISU
-import android.os.Bundle
-import android.os.ext.SdkExtensions.AD_SERVICES
-import android.view.View
-import androidx.annotation.RequiresExtension
-import androidx.test.core.app.ApplicationProvider
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import androidx.test.filters.SmallTest
-import com.google.common.truth.Truth.assertThat
-import kotlin.reflect.KClass
-import org.junit.Assert.assertThrows
-import org.junit.Assume.assumeTrue
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mockito.mock
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-// TODO(b/262577044) Remove RequiresExtension after extensions support in @SdkSuppress
-@RequiresExtension(extension = AD_SERVICES, version = 4)
-@SdkSuppress(minSdkVersion = TIRAMISU)
-@Suppress("DEPRECATION")
-class SandboxedSdkProviderAdapterTest {
-
- private lateinit var context: Context
-
- @Before
- fun setUp() {
- assumeTrue("Requires Sandbox API available", isSandboxApiAvailable())
- context = ApplicationProvider.getApplicationContext()
- }
-
- @Test
- fun testAdapterGetCompatClassNameFromAsset() {
- val expectedClassName = context.assets
- .open("SandboxedSdkProviderCompatClassName.txt")
- .use { inputStream ->
- inputStream.bufferedReader().readLine()
- }
-
- val adapter = SandboxedSdkProviderAdapter()
- adapter.attachContext(context)
-
- adapter.onLoadSdk(Bundle())
-
- val delegate = adapter.extractDelegate<SandboxedSdkProviderCompat>()
- assertThat(delegate.javaClass.name)
- .isEqualTo(expectedClassName)
- }
-
- @Test
- fun onLoadSdk_shouldInstantiateDelegateAndAttachContext() {
- val adapter = createAdapterFor(TestOnLoadReturnResultSdkProvider::class)
-
- adapter.onLoadSdk(Bundle())
-
- val delegate = adapter.extractDelegate<TestOnLoadReturnResultSdkProvider>()
- assertThat(delegate.context)
- .isSameInstanceAs(context)
- }
-
- @Test
- fun onLoadSdk_shouldDelegateToCompatClassAndReturnResult() {
- val adapter = createAdapterFor(TestOnLoadReturnResultSdkProvider::class)
- val params = Bundle()
-
- val result = adapter.onLoadSdk(params)
-
- val delegate = adapter.extractDelegate<TestOnLoadReturnResultSdkProvider>()
- assertThat(delegate.mLastOnLoadSdkBundle)
- .isSameInstanceAs(params)
- assertThat(result.getInterface())
- .isEqualTo(delegate.mResult.getInterface())
- }
-
- @Test
- fun loadSdk_shouldRethrowExceptionFromCompatClass() {
- val adapter = createAdapterFor(TestOnLoadThrowSdkProvider::class)
-
- val ex = assertThrows(LoadSdkException::class.java) {
- adapter.onLoadSdk(Bundle())
- }
-
- val delegate = adapter.extractDelegate<TestOnLoadThrowSdkProvider>()
- assertThat(ex.cause)
- .isSameInstanceAs(delegate.mError.cause)
- assertThat(ex.extraInformation)
- .isSameInstanceAs(delegate.mError.extraInformation)
- }
-
- @Test
- fun loadSdk_shouldThrowIfCompatClassNotExists() {
- val adapter = createAdapterFor("NOTEXISTS")
-
- assertThrows(ClassNotFoundException::class.java) {
- adapter.onLoadSdk(Bundle())
- }
- }
-
- @Test
- fun beforeUnloadSdk_shouldDelegateToCompatProvider() {
- val adapter = createAdapterFor(TestOnBeforeUnloadDelegateSdkProvider::class)
-
- adapter.beforeUnloadSdk()
-
- val delegate = adapter.extractDelegate<TestOnBeforeUnloadDelegateSdkProvider>()
- assertThat(delegate.mBeforeUnloadSdkCalled)
- .isTrue()
- }
-
- @Test
- fun getView_shouldDelegateToCompatProviderAndReturnResult() {
- val adapter = createAdapterFor(TestGetViewSdkProvider::class)
- val windowContext = mock(Context::class.java)
- val params = Bundle()
- val width = 1
- val height = 2
-
- val result = adapter.getView(windowContext, params, width, height)
-
- val delegate = adapter.extractDelegate<TestGetViewSdkProvider>()
- assertThat(result)
- .isSameInstanceAs(delegate.mView)
- assertThat(delegate.mLastWindowContext)
- .isSameInstanceAs(windowContext)
- assertThat(delegate.mLastParams)
- .isSameInstanceAs(params)
- assertThat(delegate.mLastWidth)
- .isSameInstanceAs(width)
- assertThat(delegate.mLastHeigh)
- .isSameInstanceAs(height)
- }
-
- private fun createAdapterFor(
- clazz: KClass<out SandboxedSdkProviderCompat>
- ): SandboxedSdkProviderAdapter = createAdapterFor(clazz.java.name)
-
- private fun createAdapterFor(delegateClassName: String): SandboxedSdkProviderAdapter {
- val adapter = SandboxedSdkProviderAdapter(
- object : SandboxedSdkProviderAdapter.CompatClassNameProvider {
- override fun getCompatProviderClassName(context: Context): String {
- return delegateClassName
- }
- })
- adapter.attachContext(context)
- return adapter
- }
-
- private inline fun <reified T : SandboxedSdkProviderCompat>
- SandboxedSdkProviderAdapter.extractDelegate(): T = delegate as T
-
- class TestOnLoadReturnResultSdkProvider : SandboxedSdkProviderCompat() {
- var mResult = SandboxedSdkCompat(Binder())
- var mLastOnLoadSdkBundle: Bundle? = null
-
- override fun onLoadSdk(params: Bundle): SandboxedSdkCompat {
- mLastOnLoadSdkBundle = params
- return mResult
- }
-
- override fun getView(
- windowContext: Context,
- params: Bundle,
- width: Int,
- height: Int
- ): View {
- throw RuntimeException("Not implemented")
- }
- }
-
- class TestOnLoadThrowSdkProvider : SandboxedSdkProviderCompat() {
- var mError = LoadSdkCompatException(RuntimeException(), Bundle())
-
- @Throws(LoadSdkCompatException::class)
- override fun onLoadSdk(params: Bundle): SandboxedSdkCompat {
- throw mError
- }
-
- override fun getView(
- windowContext: Context,
- params: Bundle,
- width: Int,
- height: Int
- ): View {
- throw RuntimeException("Stub!")
- }
- }
-
- class TestOnBeforeUnloadDelegateSdkProvider : SandboxedSdkProviderCompat() {
- var mBeforeUnloadSdkCalled = false
-
- override fun onLoadSdk(params: Bundle): SandboxedSdkCompat {
- throw RuntimeException("Not implemented")
- }
-
- override fun beforeUnloadSdk() {
- mBeforeUnloadSdkCalled = true
- }
-
- override fun getView(
- windowContext: Context,
- params: Bundle,
- width: Int,
- height: Int
- ): View {
- throw RuntimeException("Not implemented")
- }
- }
-
- class TestGetViewSdkProvider : SandboxedSdkProviderCompat() {
- val mView: View = mock(View::class.java)
-
- var mLastWindowContext: Context? = null
- var mLastParams: Bundle? = null
- var mLastWidth = 0
- var mLastHeigh = 0
-
- override fun onLoadSdk(params: Bundle): SandboxedSdkCompat {
- throw RuntimeException("Not implemented")
- }
-
- override fun getView(
- windowContext: Context,
- params: Bundle,
- width: Int,
- height: Int
- ): View {
- mLastWindowContext = windowContext
- mLastParams = params
- mLastWidth = width
- mLastHeigh = height
-
- return mView
- }
- }
-
- private fun isSandboxApiAvailable() =
- AdServicesInfo.isAtLeastV4()
-}
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/controller/SdkSandboxControllerAppOwnedInterfacesTest.kt b/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/controller/SdkSandboxControllerAppOwnedInterfacesTest.kt
index c7cc743d..6e1b54f 100644
--- a/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/controller/SdkSandboxControllerAppOwnedInterfacesTest.kt
+++ b/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/controller/SdkSandboxControllerAppOwnedInterfacesTest.kt
@@ -20,7 +20,6 @@
import android.app.sdksandbox.sdkprovider.SdkSandboxController
import android.content.Context
import android.os.Binder
-import android.os.Build
import android.os.ext.SdkExtensions
import androidx.annotation.RequiresExtension
import androidx.core.os.BuildCompat
@@ -39,31 +38,11 @@
import org.mockito.Mockito.`when`
// TODO(b/249982507) Rewrite test to use real SDK in sandbox instead of mocking controller
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
+@SdkSuppress(minSdkVersion = 34)
class SdkSandboxControllerAppOwnedInterfacesTest {
@Test
- fun getAppOwnedSdkSandboxInterfaces_whenControllerNotAvailable_returnsEmptyList() {
- assumeFalse(
- "Requires SandboxController not available",
- isSandboxControllerAvailable()
- )
-
- val context = ApplicationProvider.getApplicationContext<Context>()
- val controllerCompat = SdkSandboxControllerCompat.from(context)
-
- val appOwnedInterfaces = controllerCompat.getAppOwnedSdkSandboxInterfaces()
- assertThat(appOwnedInterfaces).isEmpty()
- }
-
- @Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
fun getAppOwnedSdkSandboxInterfaces_whenApiNotAvailable_returnsEmptyList() {
- assumeTrue(
- "Requires SandboxController available",
- isSandboxControllerAvailable()
- )
assumeFalse(
"Requires AppOwnedInterfaces API not available",
isAppOwnedInterfacesApiAvailable()
@@ -83,7 +62,7 @@
@Test
@RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 8)
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
+ @SdkSuppress(minSdkVersion = 34)
fun getAppOwnedSdkSandboxInterfaces_whenApiAvailable_delegateToPlatform() {
assumeTrue(
"Requires AppOwnedInterfaces API available",
@@ -112,9 +91,6 @@
assertThat(resultObj.getInterface()).isEqualTo(expectedObj.getInterface())
}
- private fun isSandboxControllerAvailable() =
- AdServicesInfo.isAtLeastV5()
-
private fun isAppOwnedInterfacesApiAvailable() =
BuildCompat.AD_SERVICES_EXTENSION_INT >= 8 || AdServicesInfo.isDeveloperPreview()
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/controller/SdkSandboxControllerCompatSandboxedTest.kt b/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/controller/SdkSandboxControllerCompatSandboxedTest.kt
index be2fb94..c8a0ba0f 100644
--- a/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/controller/SdkSandboxControllerCompatSandboxedTest.kt
+++ b/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/controller/SdkSandboxControllerCompatSandboxedTest.kt
@@ -23,13 +23,9 @@
import android.app.sdksandbox.sdkprovider.SdkSandboxController
import android.content.Context
import android.os.Binder
-import android.os.Build
import android.os.Bundle
-import android.os.ext.SdkExtensions
import android.window.OnBackInvokedDispatcher
-import androidx.annotation.RequiresExtension
import androidx.lifecycle.Lifecycle
-import androidx.privacysandbox.sdkruntime.core.AdServicesInfo
import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException
import androidx.privacysandbox.sdkruntime.core.activity.ActivityHolder
import androidx.privacysandbox.sdkruntime.core.activity.SdkSandboxActivityHandlerCompat
@@ -39,52 +35,34 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.runBlocking
import org.junit.Assert
-import org.junit.Assume.assumeFalse
-import org.junit.Assume.assumeTrue
import org.junit.Test
import org.mockito.ArgumentCaptor
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
-import org.mockito.Mockito.verifyZeroInteractions
import org.mockito.Mockito.`when`
// TODO(b/249982507) Rewrite test to use real SDK in sandbox instead of mocking controller
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
class SdkSandboxControllerCompatSandboxedTest {
@Test
- fun controllerAPIs_whenApiNotAvailable_notDelegateToSandbox() {
- assumeFalse(
- "Requires SandboxController API not available",
- isSandboxControllerAvailable()
- )
+ @SdkSuppress(maxSdkVersion = 33)
+ fun from_whenApiBelow34_throwUnsupportedOperationException() {
+ val context = ApplicationProvider.getApplicationContext<Context>()
+ Assert.assertThrows(UnsupportedOperationException::class.java) {
+ SdkSandboxControllerCompat.from(context)
+ }
+ }
+ @Test
+ @SdkSuppress(minSdkVersion = 34)
+ fun loadSdk_withoutLocalImpl_throwsLoadSdkCompatException() {
val context = spy(ApplicationProvider.getApplicationContext<Context>())
- val controllerCompat = SdkSandboxControllerCompat.from(context)
+ val sdkSandboxController = mock(SdkSandboxController::class.java)
+ doReturn(sdkSandboxController)
+ .`when`(context).getSystemService(SdkSandboxController::class.java)
- controllerCompat.getSandboxedSdks()
- val handlerCompat = object : SdkSandboxActivityHandlerCompat {
- override fun onActivityCreated(activityHolder: ActivityHolder) {}
- }
- Assert.assertThrows(UnsupportedOperationException::class.java) {
- controllerCompat.registerSdkSandboxActivityHandler(handlerCompat)
- }
- Assert.assertThrows(UnsupportedOperationException::class.java) {
- controllerCompat.unregisterSdkSandboxActivityHandler(handlerCompat)
- }
- Assert.assertThrows(LoadSdkCompatException::class.java) {
- runBlocking {
- controllerCompat.loadSdk("SDK", Bundle())
- }
- }
- verifyZeroInteractions(context)
- }
-
- @Test
- fun loadSdk_throwsLoadSdkCompatException() {
- val context = ApplicationProvider.getApplicationContext<Context>()
val controllerCompat = SdkSandboxControllerCompat.from(context)
Assert.assertThrows(LoadSdkCompatException::class.java) {
@@ -95,30 +73,8 @@
}
@Test
- fun getSandboxedSdks_whenApiNotAvailable_returnsEmptyList() {
- assumeFalse(
- "Requires SandboxController API not available",
- isSandboxControllerAvailable()
- )
-
- val context = ApplicationProvider.getApplicationContext<Context>()
- val controllerCompat = SdkSandboxControllerCompat.from(context)
-
- val sandboxedSdks = controllerCompat.getSandboxedSdks()
-
- assertThat(sandboxedSdks).isEmpty()
- }
-
- @Test
- // TODO(b/262577044) Remove RequiresExtension after extensions support in @SdkSuppress
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
- fun getSandboxedSdks_whenApiAvailable_returnsListFromPlatformApi() {
- assumeTrue(
- "Requires SandboxController API available",
- isSandboxControllerAvailable()
- )
-
+ @SdkSuppress(minSdkVersion = 34)
+ fun getSandboxedSdks_withoutLocalImpl_returnsListFromPlatformApi() {
val context = spy(ApplicationProvider.getApplicationContext<Context>())
val sdkSandboxController = mock(SdkSandboxController::class.java)
doReturn(sdkSandboxController)
@@ -137,10 +93,8 @@
}
@Test
- // TODO(b/262577044) Remove RequiresExtension after extensions support in @SdkSuppress
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
- fun registerSdkSandboxHandlerCompat_whenApiAvailable_registerItToPlatform() {
+ @SdkSuppress(minSdkVersion = 34)
+ fun registerSdkSandboxHandlerCompat_withoutLocalImpl_registerItToPlatform() {
val context = spy(ApplicationProvider.getApplicationContext<Context>())
val sdkSandboxController = mock(SdkSandboxController::class.java)
doReturn(sdkSandboxController)
@@ -211,10 +165,8 @@
}
@Test
- // TODO(b/262577044) Remove RequiresExtension after extensions support in @SdkSuppress
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
- fun unregisterSdkSandboxHandlerCompat_whenApiAvailable_unregisterItToPlatform() {
+ @SdkSuppress(minSdkVersion = 34)
+ fun unregisterSdkSandboxHandlerCompat_withoutLocalImpl_unregisterItToPlatform() {
val context = spy(ApplicationProvider.getApplicationContext<Context>())
val sdkSandboxController = mock(SdkSandboxController::class.java)
doReturn(sdkSandboxController)
@@ -242,9 +194,6 @@
assertThat(unregisteredHandlerCaptor.value).isEqualTo(registeredHandlerCaptor.value)
}
- private fun isSandboxControllerAvailable() =
- AdServicesInfo.isAtLeastV5()
-
// To capture non null arguments.
private fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkProviderAdapter.kt b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkProviderAdapter.kt
index e62fc1d..24771d7 100644
--- a/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkProviderAdapter.kt
+++ b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkProviderAdapter.kt
@@ -23,7 +23,9 @@
import android.os.Bundle
import android.os.ext.SdkExtensions.AD_SERVICES
import android.view.View
+import androidx.annotation.RequiresApi
import androidx.annotation.RequiresExtension
+import androidx.annotation.RestrictTo
/**
* Implementation of platform [SandboxedSdkProvider] that delegate to [SandboxedSdkProviderCompat]
@@ -31,6 +33,7 @@
*
*/
@SuppressLint("Override") // b/273473397
+@RequiresApi(34)
@RequiresExtension(extension = AD_SERVICES, version = 4)
// TODO(b/301437557) Remove after documentation migration to sdkruntime-provider
@Deprecated(
@@ -38,8 +41,10 @@
replaceWith = ReplaceWith(
expression = "SandboxedSdkProviderAdapter",
imports = arrayOf("androidx.privacysandbox.sdkruntime.provider.SandboxedSdkProviderAdapter")
- )
+ ),
+ level = DeprecationLevel.HIDDEN
)
+@RestrictTo(RestrictTo.Scope.LIBRARY) // removing from public API surface
class SandboxedSdkProviderAdapter internal constructor(
private val classNameProvider: CompatClassNameProvider
) : SandboxedSdkProvider() {
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/controller/SdkSandboxControllerCompat.kt b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/controller/SdkSandboxControllerCompat.kt
index c56f630..3d1a408 100644
--- a/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/controller/SdkSandboxControllerCompat.kt
+++ b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/controller/SdkSandboxControllerCompat.kt
@@ -33,7 +33,6 @@
import androidx.privacysandbox.sdkruntime.core.activity.SdkSandboxActivityHandlerCompat
import androidx.privacysandbox.sdkruntime.core.controller.impl.LocalImpl
import androidx.privacysandbox.sdkruntime.core.controller.impl.NoOpImpl
-import androidx.privacysandbox.sdkruntime.core.controller.impl.PlatformImpl
import androidx.privacysandbox.sdkruntime.core.controller.impl.PlatformUDCImpl
import org.jetbrains.annotations.TestOnly
@@ -181,13 +180,10 @@
private object PlatformImplFactory {
fun create(context: Context): SandboxControllerImpl {
- if (AdServicesInfo.isAtLeastV5()) {
- if (Build.VERSION.SDK_INT >= 34 || AdServicesInfo.isDeveloperPreview()) {
- return PlatformUDCImpl.from(context)
- }
- return PlatformImpl.from(context)
+ if (Build.VERSION.SDK_INT >= 34 || AdServicesInfo.isDeveloperPreview()) {
+ return PlatformUDCImpl.from(context)
}
- return NoOpImpl()
+ throw UnsupportedOperationException("SDK should be loaded locally on API below 34")
}
}
}
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/controller/impl/PlatformImpl.kt b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/controller/impl/PlatformImpl.kt
deleted file mode 100644
index 7c1de6b..0000000
--- a/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/controller/impl/PlatformImpl.kt
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2023 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.privacysandbox.sdkruntime.core.controller.impl
-
-import android.app.sdksandbox.sdkprovider.SdkSandboxController
-import android.content.Context
-import android.os.Bundle
-import android.os.IBinder
-import android.os.ext.SdkExtensions.AD_SERVICES
-import androidx.annotation.RequiresApi
-import androidx.annotation.RequiresExtension
-import androidx.privacysandbox.sdkruntime.core.AppOwnedSdkSandboxInterfaceCompat
-import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException
-import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException.Companion.LOAD_SDK_NOT_FOUND
-import androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat
-import androidx.privacysandbox.sdkruntime.core.activity.SdkSandboxActivityHandlerCompat
-import androidx.privacysandbox.sdkruntime.core.controller.SdkSandboxControllerCompat
-
-/**
- * Implementation that delegates to platform [SdkSandboxController].
- */
-@RequiresApi(33)
-@RequiresExtension(extension = AD_SERVICES, version = 5)
-internal open class PlatformImpl(
- private val controller: SdkSandboxController
-) : SdkSandboxControllerCompat.SandboxControllerImpl {
-
- private val appOwnedSdkProvider = AppOwnedSdkProvider.create(controller)
-
- override suspend fun loadSdk(sdkName: String, params: Bundle): SandboxedSdkCompat {
- throw LoadSdkCompatException(
- LOAD_SDK_NOT_FOUND,
- "Loading SDK not supported on this device"
- )
- }
-
- override fun getSandboxedSdks(): List<SandboxedSdkCompat> {
- return controller
- .sandboxedSdks
- .map { platformSdk -> SandboxedSdkCompat(platformSdk) }
- }
-
- override fun getAppOwnedSdkSandboxInterfaces(): List<AppOwnedSdkSandboxInterfaceCompat> =
- appOwnedSdkProvider.getAppOwnedSdkSandboxInterfaces()
-
- override fun registerSdkSandboxActivityHandler(
- handlerCompat: SdkSandboxActivityHandlerCompat
- ): IBinder {
- throw UnsupportedOperationException("This API only available for devices run on Android U+")
- }
-
- override fun unregisterSdkSandboxActivityHandler(
- handlerCompat: SdkSandboxActivityHandlerCompat
- ) {
- throw UnsupportedOperationException("This API only available for devices run on Android U+")
- }
-
- companion object {
- fun from(context: Context): PlatformImpl {
- val sdkSandboxController = context.getSystemService(SdkSandboxController::class.java)
- return PlatformImpl(sdkSandboxController)
- }
- }
-}
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/controller/impl/PlatformUDCImpl.kt b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/controller/impl/PlatformUDCImpl.kt
index a143ea0..601d474 100644
--- a/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/controller/impl/PlatformUDCImpl.kt
+++ b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/controller/impl/PlatformUDCImpl.kt
@@ -16,6 +16,7 @@
package androidx.privacysandbox.sdkruntime.core.controller.impl
+import android.annotation.SuppressLint
import android.app.Activity
import android.app.Application
import android.app.sdksandbox.sdkprovider.SdkSandboxActivityHandler
@@ -23,27 +24,47 @@
import android.content.Context
import android.os.Bundle
import android.os.IBinder
-import android.os.ext.SdkExtensions
import androidx.activity.OnBackPressedDispatcher
import androidx.annotation.RequiresApi
-import androidx.annotation.RequiresExtension
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleRegistry
+import androidx.privacysandbox.sdkruntime.core.AppOwnedSdkSandboxInterfaceCompat
+import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException
+import androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat
import androidx.privacysandbox.sdkruntime.core.activity.ActivityHolder
import androidx.privacysandbox.sdkruntime.core.activity.SdkSandboxActivityHandlerCompat
+import androidx.privacysandbox.sdkruntime.core.controller.SdkSandboxControllerCompat
/**
* Implementation that delegates to platform [SdkSandboxController] for Android U.
*/
-@RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
@RequiresApi(34)
+@SuppressLint("NewApi", "ClassVerificationFailure") // until updating checks to requires api 34
internal class PlatformUDCImpl(
private val controller: SdkSandboxController
-) : PlatformImpl(controller) {
+) : SdkSandboxControllerCompat.SandboxControllerImpl {
+
+ private val appOwnedSdkProvider = AppOwnedSdkProvider.create(controller)
private val compatToPlatformMap =
hashMapOf<SdkSandboxActivityHandlerCompat, SdkSandboxActivityHandler>()
+ override suspend fun loadSdk(sdkName: String, params: Bundle): SandboxedSdkCompat {
+ throw LoadSdkCompatException(
+ LoadSdkCompatException.LOAD_SDK_NOT_FOUND,
+ "Loading SDK not supported on this device"
+ )
+ }
+
+ override fun getSandboxedSdks(): List<SandboxedSdkCompat> {
+ return controller
+ .sandboxedSdks
+ .map { platformSdk -> SandboxedSdkCompat(platformSdk) }
+ }
+
+ override fun getAppOwnedSdkSandboxInterfaces(): List<AppOwnedSdkSandboxInterfaceCompat> =
+ appOwnedSdkProvider.getAppOwnedSdkSandboxInterfaces()
+
override fun registerSdkSandboxActivityHandler(
handlerCompat: SdkSandboxActivityHandlerCompat
): IBinder {
@@ -142,7 +163,7 @@
}
companion object {
- fun from(context: Context): PlatformImpl {
+ fun from(context: Context): PlatformUDCImpl {
val sdkSandboxController = context.getSystemService(SdkSandboxController::class.java)
return PlatformUDCImpl(sdkSandboxController)
}
diff --git a/privacysandbox/sdkruntime/sdkruntime-provider/api/current.txt b/privacysandbox/sdkruntime/sdkruntime-provider/api/current.txt
index bad8190..00612b5a 100644
--- a/privacysandbox/sdkruntime/sdkruntime-provider/api/current.txt
+++ b/privacysandbox/sdkruntime/sdkruntime-provider/api/current.txt
@@ -1,7 +1,7 @@
// Signature format: 4.0
package androidx.privacysandbox.sdkruntime.provider {
- @RequiresExtension(extension=android.os.ext.SdkExtensions.AD_SERVICES, version=4) public final class SandboxedSdkProviderAdapter extends android.app.sdksandbox.SandboxedSdkProvider {
+ @RequiresApi(34) public final class SandboxedSdkProviderAdapter extends android.app.sdksandbox.SandboxedSdkProvider {
ctor public SandboxedSdkProviderAdapter();
method public android.view.View getView(android.content.Context windowContext, android.os.Bundle params, int width, int height);
method @kotlin.jvm.Throws(exceptionClasses=LoadSdkException::class) public android.app.sdksandbox.SandboxedSdk onLoadSdk(android.os.Bundle params) throws android.app.sdksandbox.LoadSdkException;
diff --git a/privacysandbox/sdkruntime/sdkruntime-provider/api/restricted_current.txt b/privacysandbox/sdkruntime/sdkruntime-provider/api/restricted_current.txt
index bad8190..00612b5a 100644
--- a/privacysandbox/sdkruntime/sdkruntime-provider/api/restricted_current.txt
+++ b/privacysandbox/sdkruntime/sdkruntime-provider/api/restricted_current.txt
@@ -1,7 +1,7 @@
// Signature format: 4.0
package androidx.privacysandbox.sdkruntime.provider {
- @RequiresExtension(extension=android.os.ext.SdkExtensions.AD_SERVICES, version=4) public final class SandboxedSdkProviderAdapter extends android.app.sdksandbox.SandboxedSdkProvider {
+ @RequiresApi(34) public final class SandboxedSdkProviderAdapter extends android.app.sdksandbox.SandboxedSdkProvider {
ctor public SandboxedSdkProviderAdapter();
method public android.view.View getView(android.content.Context windowContext, android.os.Bundle params, int width, int height);
method @kotlin.jvm.Throws(exceptionClasses=LoadSdkException::class) public android.app.sdksandbox.SandboxedSdk onLoadSdk(android.os.Bundle params) throws android.app.sdksandbox.LoadSdkException;
diff --git a/privacysandbox/sdkruntime/sdkruntime-provider/src/androidTest/java/androidx/privacysandbox/sdkruntime/provider/SandboxedSdkProviderAdapterTest.kt b/privacysandbox/sdkruntime/sdkruntime-provider/src/androidTest/java/androidx/privacysandbox/sdkruntime/provider/SandboxedSdkProviderAdapterTest.kt
index debd913a..5bd11b1 100644
--- a/privacysandbox/sdkruntime/sdkruntime-provider/src/androidTest/java/androidx/privacysandbox/sdkruntime/provider/SandboxedSdkProviderAdapterTest.kt
+++ b/privacysandbox/sdkruntime/sdkruntime-provider/src/androidTest/java/androidx/privacysandbox/sdkruntime/provider/SandboxedSdkProviderAdapterTest.kt
@@ -19,12 +19,8 @@
import android.app.sdksandbox.LoadSdkException
import android.content.Context
import android.os.Binder
-import android.os.Build.VERSION_CODES.TIRAMISU
import android.os.Bundle
-import android.os.ext.SdkExtensions.AD_SERVICES
import android.view.View
-import androidx.annotation.RequiresExtension
-import androidx.privacysandbox.sdkruntime.core.AdServicesInfo
import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException
import androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat
import androidx.privacysandbox.sdkruntime.core.SandboxedSdkProviderCompat
@@ -35,7 +31,6 @@
import com.google.common.truth.Truth.assertThat
import kotlin.reflect.KClass
import org.junit.Assert.assertThrows
-import org.junit.Assume.assumeTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -43,16 +38,13 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
-// TODO(b/262577044) Remove RequiresExtension after extensions support in @SdkSuppress
-@RequiresExtension(extension = AD_SERVICES, version = 4)
-@SdkSuppress(minSdkVersion = TIRAMISU)
+@SdkSuppress(minSdkVersion = 34)
class SandboxedSdkProviderAdapterTest {
private lateinit var context: Context
@Before
fun setUp() {
- assumeTrue("Requires Sandbox API available", isSandboxApiAvailable())
context = ApplicationProvider.getApplicationContext()
}
@@ -259,7 +251,4 @@
return mView
}
}
-
- private fun isSandboxApiAvailable() =
- AdServicesInfo.isAtLeastV4()
}
diff --git a/privacysandbox/sdkruntime/sdkruntime-provider/src/main/java/androidx/privacysandbox/sdkruntime/provider/SandboxedSdkProviderAdapter.kt b/privacysandbox/sdkruntime/sdkruntime-provider/src/main/java/androidx/privacysandbox/sdkruntime/provider/SandboxedSdkProviderAdapter.kt
index 05a6eb0..5c70191 100644
--- a/privacysandbox/sdkruntime/sdkruntime-provider/src/main/java/androidx/privacysandbox/sdkruntime/provider/SandboxedSdkProviderAdapter.kt
+++ b/privacysandbox/sdkruntime/sdkruntime-provider/src/main/java/androidx/privacysandbox/sdkruntime/provider/SandboxedSdkProviderAdapter.kt
@@ -22,9 +22,8 @@
import android.app.sdksandbox.SandboxedSdkProvider
import android.content.Context
import android.os.Bundle
-import android.os.ext.SdkExtensions.AD_SERVICES
import android.view.View
-import androidx.annotation.RequiresExtension
+import androidx.annotation.RequiresApi
import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException
import androidx.privacysandbox.sdkruntime.core.SandboxedSdkProviderCompat
@@ -33,8 +32,8 @@
* Gets compat class name from asset "SandboxedSdkProviderCompatClassName.txt"
*
*/
-@RequiresExtension(extension = AD_SERVICES, version = 4)
-@SuppressLint("ClassVerificationFailure")
+@RequiresApi(34)
+@SuppressLint("NewApi", "ClassVerificationFailure") // until updating checks to requires api 34
class SandboxedSdkProviderAdapter internal constructor(
private val classNameProvider: CompatClassNameProvider
) : SandboxedSdkProvider() {
diff --git a/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/ProfileInstaller.java b/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/ProfileInstaller.java
index 70f4305..61a098e 100644
--- a/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/ProfileInstaller.java
+++ b/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/ProfileInstaller.java
@@ -21,7 +21,6 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
-import android.os.Build;
import android.util.Log;
import androidx.annotation.IntDef;
@@ -423,10 +422,6 @@
@NonNull Executor executor,
@NonNull DiagnosticsCallback diagnostics
) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
- result(executor, diagnostics, ProfileInstaller.RESULT_UNSUPPORTED_ART_VERSION, null);
- return false;
- }
File curProfile = new File(new File(PROFILE_BASE_DIR, packageName), PROFILE_FILE);
DeviceProfileWriter deviceProfileWriter = new DeviceProfileWriter(assets, executor,
diff --git a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/PoolingContainerRecyclerViewTest.kt b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/PoolingContainerRecyclerViewTest.kt
index 93c19e6..05a9fde 100644
--- a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/PoolingContainerRecyclerViewTest.kt
+++ b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/PoolingContainerRecyclerViewTest.kt
@@ -17,11 +17,9 @@
package androidx.recyclerview.widget
import android.content.Context
-import android.os.Build
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
-import androidx.annotation.RequiresApi
import androidx.customview.poolingcontainer.addPoolingContainerListener
import androidx.recyclerview.test.awaitScrollIdle
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -428,7 +426,6 @@
var binds = 0
var releases = 0
- @RequiresApi(Build.VERSION_CODES.KITKAT)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = View(context)
view.layoutParams =
diff --git a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewAccessibilityLifecycleTest.java b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewAccessibilityLifecycleTest.java
index 2e6e604..3d5e3c6 100644
--- a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewAccessibilityLifecycleTest.java
+++ b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewAccessibilityLifecycleTest.java
@@ -229,9 +229,7 @@
AccessibilityNodeInfo info = recyclerView.getChildAt(i)
.createAccessibilityNodeInfo();
assertTrue("custom delegate sets isChecked", info.isChecked());
- if (Build.VERSION.SDK_INT >= 19) {
- assertNotNull(info.getCollectionItemInfo());
- }
+ assertNotNull(info.getCollectionItemInfo());
children.add(view);
}
}
@@ -254,9 +252,7 @@
assertTrue(children.contains(view));
AccessibilityNodeInfo info = view.createAccessibilityNodeInfo();
assertTrue("custom delegate sets isChecked", info.isChecked());
- if (Build.VERSION.SDK_INT >= 19) {
- assertNotNull(info.getCollectionItemInfo());
- }
+ assertNotNull(info.getCollectionItemInfo());
}
}
});
@@ -307,9 +303,7 @@
assertEquals(i, recyclerView.getChildAdapterPosition(view));
assertTrue(accessibiltyDelegateIsItemDelegate(recyclerView, view));
AccessibilityNodeInfo info = view.createAccessibilityNodeInfo();
- if (Build.VERSION.SDK_INT >= 19) {
- assertNotNull(info.getCollectionItemInfo());
- }
+ assertNotNull(info.getCollectionItemInfo());
}
}
});
diff --git a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewAccessibilityTest.java b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewAccessibilityTest.java
index a6d44ad..69ee2cf 100644
--- a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewAccessibilityTest.java
+++ b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewAccessibilityTest.java
@@ -22,7 +22,6 @@
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
-import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
@@ -52,8 +51,6 @@
@SmallTest
@RunWith(Parameterized.class)
public class RecyclerViewAccessibilityTest extends BaseRecyclerViewInstrumentationTest {
- private static final boolean SUPPORTS_COLLECTION_INFO =
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
private final boolean mVerticalScrollBefore;
private final boolean mHorizontalScrollBefore;
private final boolean mVerticalScrollAfter;
@@ -164,16 +161,14 @@
(info.getActions() & AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD) != 0);
assertEquals(mHorizontalScrollAfter || mVerticalScrollAfter,
(info.getActions() & AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD) != 0);
- if (SUPPORTS_COLLECTION_INFO) {
- final AccessibilityNodeInfoCompat.CollectionInfoCompat collectionInfo = info
- .getCollectionInfo();
- assertNotNull(collectionInfo);
- if (recyclerView.getLayoutManager().canScrollVertically()) {
- assertEquals(adapter.getItemCount(), collectionInfo.getRowCount());
- }
- if (recyclerView.getLayoutManager().canScrollHorizontally()) {
- assertEquals(adapter.getItemCount(), collectionInfo.getColumnCount());
- }
+ final AccessibilityNodeInfoCompat.CollectionInfoCompat collectionInfo = info
+ .getCollectionInfo();
+ assertNotNull(collectionInfo);
+ if (recyclerView.getLayoutManager().canScrollVertically()) {
+ assertEquals(adapter.getItemCount(), collectionInfo.getRowCount());
+ }
+ if (recyclerView.getLayoutManager().canScrollHorizontally()) {
+ assertEquals(adapter.getItemCount(), collectionInfo.getColumnCount());
}
final AccessibilityEvent event = AccessibilityEvent.obtain();
@@ -188,31 +183,29 @@
assertEquals(event.getItemCount(), adapter.getItemCount());
getInstrumentation().waitForIdleSync();
- if (SUPPORTS_COLLECTION_INFO) {
- for (int i = 0; i < mRecyclerView.getChildCount(); i++) {
- final View view = mRecyclerView.getChildAt(i);
- final AccessibilityNodeInfoCompat childInfo = AccessibilityNodeInfoCompat.obtain();
- mActivityRule.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- delegateCompat.getItemDelegate().
- onInitializeAccessibilityNodeInfo(view, childInfo);
- }
- });
- final AccessibilityNodeInfoCompat.CollectionItemInfoCompat collectionItemInfo =
- childInfo.getCollectionItemInfo();
- assertNotNull(collectionItemInfo);
- if (recyclerView.getLayoutManager().canScrollHorizontally()) {
- assertEquals(i, collectionItemInfo.getColumnIndex());
- } else {
- assertEquals(0, collectionItemInfo.getColumnIndex());
+ for (int i = 0; i < mRecyclerView.getChildCount(); i++) {
+ final View view = mRecyclerView.getChildAt(i);
+ final AccessibilityNodeInfoCompat childInfo = AccessibilityNodeInfoCompat.obtain();
+ mActivityRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ delegateCompat.getItemDelegate()
+ .onInitializeAccessibilityNodeInfo(view, childInfo);
}
+ });
+ final AccessibilityNodeInfoCompat.CollectionItemInfoCompat collectionItemInfo =
+ childInfo.getCollectionItemInfo();
+ assertNotNull(collectionItemInfo);
+ if (recyclerView.getLayoutManager().canScrollHorizontally()) {
+ assertEquals(i, collectionItemInfo.getColumnIndex());
+ } else {
+ assertEquals(0, collectionItemInfo.getColumnIndex());
+ }
- if (recyclerView.getLayoutManager().canScrollVertically()) {
- assertEquals(i, collectionItemInfo.getRowIndex());
- } else {
- assertEquals(0, collectionItemInfo.getRowIndex());
- }
+ if (recyclerView.getLayoutManager().canScrollVertically()) {
+ assertEquals(i, collectionItemInfo.getRowIndex());
+ } else {
+ assertEquals(0, collectionItemInfo.getRowIndex());
}
}
diff --git a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewLayoutTest.java b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewLayoutTest.java
index c19f539..741bb69 100644
--- a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewLayoutTest.java
+++ b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewLayoutTest.java
@@ -53,7 +53,6 @@
import android.graphics.Color;
import android.graphics.PointF;
import android.graphics.Rect;
-import android.os.Build;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.Gravity;
@@ -841,8 +840,7 @@
public View onFocusSearchFailed(View focused, int direction,
RecyclerView.Recycler recycler,
RecyclerView.State state) {
- int expectedDir = Build.VERSION.SDK_INT <= 15 ? View.FOCUS_DOWN :
- View.FOCUS_FORWARD;
+ int expectedDir = View.FOCUS_FORWARD;
assertEquals(expectedDir, direction);
assertEquals(1, getChildCount());
View child0 = getChildAt(0);
diff --git a/room/benchmark/src/androidTest/java/androidx/room/benchmark/AmbiguousColumnResolverBenchmark.kt b/room/benchmark/src/androidTest/java/androidx/room/benchmark/AmbiguousColumnResolverBenchmark.kt
index a60af6b..09770b8 100644
--- a/room/benchmark/src/androidTest/java/androidx/room/benchmark/AmbiguousColumnResolverBenchmark.kt
+++ b/room/benchmark/src/androidTest/java/androidx/room/benchmark/AmbiguousColumnResolverBenchmark.kt
@@ -16,12 +16,10 @@
package androidx.room.benchmark
-import android.os.Build
import androidx.benchmark.junit4.BenchmarkRule
import androidx.benchmark.junit4.measureRepeated
import androidx.room.AmbiguousColumnResolver
import androidx.test.filters.LargeTest
-import androidx.test.filters.SdkSuppress
import androidx.testutils.generateAllEnumerations
import kotlin.random.Random
import org.junit.Assert.assertArrayEquals
@@ -32,7 +30,6 @@
@LargeTest
@RunWith(Parameterized::class)
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
class AmbiguousColumnResolverBenchmark(
private val numOfColumns: Int,
private val numOfTables: Int,
diff --git a/room/benchmark/src/androidTest/java/androidx/room/benchmark/InvalidationTrackerBenchmark.kt b/room/benchmark/src/androidTest/java/androidx/room/benchmark/InvalidationTrackerBenchmark.kt
index 2d19f32..62de81d 100644
--- a/room/benchmark/src/androidTest/java/androidx/room/benchmark/InvalidationTrackerBenchmark.kt
+++ b/room/benchmark/src/androidTest/java/androidx/room/benchmark/InvalidationTrackerBenchmark.kt
@@ -16,7 +16,6 @@
package androidx.room.benchmark
-import android.os.Build
import androidx.benchmark.junit4.BenchmarkRule
import androidx.benchmark.junit4.measureRepeated
import androidx.room.Dao
@@ -30,7 +29,6 @@
import androidx.room.RoomDatabase
import androidx.test.core.app.ApplicationProvider
import androidx.test.filters.LargeTest
-import androidx.test.filters.SdkSuppress
import androidx.testutils.generateAllEnumerations
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
@@ -42,7 +40,6 @@
@LargeTest
@RunWith(Parameterized::class)
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN) // TODO Fix me for API 15 - b/120098504
class InvalidationTrackerBenchmark(private val sampleSize: Int, private val mode: Mode) {
@get:Rule
diff --git a/room/benchmark/src/androidTest/java/androidx/room/benchmark/RelationBenchmark.kt b/room/benchmark/src/androidTest/java/androidx/room/benchmark/RelationBenchmark.kt
index 53c9fe0..b0ba110 100644
--- a/room/benchmark/src/androidTest/java/androidx/room/benchmark/RelationBenchmark.kt
+++ b/room/benchmark/src/androidTest/java/androidx/room/benchmark/RelationBenchmark.kt
@@ -16,7 +16,6 @@
package androidx.room.benchmark
-import android.os.Build
import androidx.benchmark.junit4.BenchmarkRule
import androidx.benchmark.junit4.measureRepeated
import androidx.room.Dao
@@ -32,7 +31,6 @@
import androidx.room.RoomWarnings
import androidx.test.core.app.ApplicationProvider
import androidx.test.filters.LargeTest
-import androidx.test.filters.SdkSuppress
import androidx.testutils.generateAllEnumerations
import org.junit.Assert
import org.junit.Assert.assertEquals
@@ -44,7 +42,6 @@
@LargeTest
@RunWith(Parameterized::class)
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
class RelationBenchmark(private val parentSampleSize: Int, private val childSampleSize: Int) {
@get:Rule
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/migration/AutoMigrationTest.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/migration/AutoMigrationTest.kt
index 186154a..7e2e54b 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/migration/AutoMigrationTest.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/migration/AutoMigrationTest.kt
@@ -16,13 +16,11 @@
package androidx.room.integration.kotlintestapp.migration
import android.database.sqlite.SQLiteConstraintException
-import android.os.Build
import androidx.kruth.assertThat
import androidx.room.testing.MigrationTestHelper
import androidx.room.util.TableInfo.Companion.read
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
-import androidx.test.filters.SdkSuppress
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Rule
import org.junit.Test
@@ -33,7 +31,6 @@
*/
@RunWith(AndroidJUnit4::class)
@LargeTest
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN) // Due to FTS table migrations
class AutoMigrationTest {
@JvmField
@Rule
diff --git a/room/room-compiler-processing-testing/src/main/java/androidx/room/compiler/processing/util/runner/KspCompilationTestRunner.kt b/room/room-compiler-processing-testing/src/main/java/androidx/room/compiler/processing/util/runner/KspCompilationTestRunner.kt
index 2e7bc22..a7a4b8d 100644
--- a/room/room-compiler-processing-testing/src/main/java/androidx/room/compiler/processing/util/runner/KspCompilationTestRunner.kt
+++ b/room/room-compiler-processing-testing/src/main/java/androidx/room/compiler/processing/util/runner/KspCompilationTestRunner.kt
@@ -49,6 +49,8 @@
config = params.config
).also { processor = it }
}
+
+ fun isProcessorInitialized() = this::processor.isInitialized
}
val args = TestCompilationArguments(
sources = params.sources,
@@ -62,6 +64,23 @@
workingDir = workingDir,
arguments = args
)
+ if (!processorProvider.isProcessorInitialized()) {
+ // KSP did not completely run, report diagnostic messages those with an exception.
+ val exceptionMsg = buildString {
+ append("KSP did not completely run!")
+ if (result.diagnostics.isNotEmpty()) {
+ appendLine()
+ appendLine("--- Diagnostic messages:")
+ result.diagnostics.values.flatten().forEach {
+ appendLine("${it.kind}: ${it.msg}")
+ }
+ append("--- End of Diagnostic messages")
+ } else {
+ append(" No diagnostic messages...")
+ }
+ }
+ error(exceptionMsg)
+ }
return KotlinCompilationResult(
testRunner = this,
processor = processorProvider.processor,
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/AnnotationMirrorExt.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/AnnotationMirrorExt.kt
index 3b1368b..244390e 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/AnnotationMirrorExt.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/AnnotationMirrorExt.kt
@@ -25,33 +25,39 @@
/** Returns true if the given [AnnotationMirror] represents a repeatable annotation. */
internal fun AnnotationMirror.isRepeatable(): Boolean {
- val valueType =
- ElementFilter.methodsIn(MoreTypes.asTypeElement(annotationType).enclosedElements)
- .singleOrNull { it.simpleName.toString() == "value" }
- ?.returnType
+ try {
+ val valueType =
+ ElementFilter.methodsIn(MoreTypes.asTypeElement(annotationType).enclosedElements)
+ .singleOrNull { it.simpleName.toString() == "value" }
+ ?.returnType
- // The contract of a repeatable annotation requires that the container annotation have a
- // single "default" method that returns an array typed with the repeatable annotation type.
- if (valueType == null || valueType.kind != TypeKind.ARRAY) {
+ // The contract of a repeatable annotation requires that the container annotation have a
+ // single "default" method that returns an array typed with the repeatable annotation type.
+ if (valueType == null || valueType.kind != TypeKind.ARRAY) {
+ return false
+ }
+ val componentType = MoreTypes.asArray(valueType).componentType
+ if (componentType.kind != TypeKind.DECLARED) {
+ return false
+ }
+ val componentElement = MoreTypes.asDeclared(componentType).asElement()
+
+ // Ideally we would read the value of the Repeatable annotation to get the container class
+ // type and check that it matches "this" type. However, there seems to be a KSP bug where
+ // the value of Repeatable is not present so the best we can do is check that all the nested
+ // members are annotated with repeatable.
+ // https://github.com/google/ksp/issues/358
+ return MoreElements.isAnnotationPresent(componentElement, Repeatable::class.java) ||
+ // The java and kotlin versions of Repeatable are not interchangeable.
+ // https://github.com/google/ksp/issues/459 asks whether the built in type
+ // mapper should convert them, but it may not be possible because there are
+ // differences to how they work (eg different parameters).
+ MoreElements.isAnnotationPresent(
+ componentElement, kotlin.annotation.Repeatable::class.java
+ )
+ } catch (t: Throwable) {
+ // TODO(b/314160063): Turbine can throw when getting enclosed elements. Remove this once
+ // we have a better way to work around Turbine exception.
return false
}
- val componentType = MoreTypes.asArray(valueType).componentType
- if (componentType.kind != TypeKind.DECLARED) {
- return false
- }
- val componentElement = MoreTypes.asDeclared(componentType).asElement()
-
- // Ideally we would read the value of the Repeatable annotation to get the container class
- // type and check that it matches "this" type. However, there seems to be a KSP bug where
- // the value of Repeatable is not present so the best we can do is check that all the nested
- // members are annotated with repeatable.
- // https://github.com/google/ksp/issues/358
- return MoreElements.isAnnotationPresent(componentElement, Repeatable::class.java) ||
- // The java and kotlin versions of Repeatable are not interchangeable.
- // https://github.com/google/ksp/issues/459 asks whether the built in type
- // mapper should convert them, but it may not be possible because there are
- // differences to how they work (eg different parameters).
- MoreElements.isAnnotationPresent(
- componentElement, kotlin.annotation.Repeatable::class.java
- )
}
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/ext/xelement_ext.kt b/room/room-compiler/src/main/kotlin/androidx/room/ext/xelement_ext.kt
index 42a63d5..d7fb0fa 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/ext/xelement_ext.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/ext/xelement_ext.kt
@@ -17,7 +17,7 @@
package androidx.room.ext
import androidx.room.compiler.processing.XElement
-import androidx.room.compiler.processing.XFieldElement
+import androidx.room.compiler.processing.XExecutableParameterElement
import androidx.room.compiler.processing.XTypeElement
import kotlin.contracts.contract
@@ -28,11 +28,17 @@
return this.hasAnnotation(androidx.room.Entity::class)
}
-fun XTypeElement.getValueClassUnderlyingProperty(): XFieldElement {
+fun XTypeElement.getValueClassUnderlyingElement(): XExecutableParameterElement {
check(this.isValueClass()) {
"Can't get value class property, type element '$this' is not a value class"
}
- return this.getDeclaredFields().single()
+ // Kotlin states:
+ // * Primary constructor is required for value class
+ // * Value class must have exactly one primary constructor parameter
+ // * Value class primary constructor must only have final read-only (val) property parameter
+ return checkNotNull(this.findPrimaryConstructor()) {
+ "Couldn't find primary constructor for value class."
+ }.parameters.single()
}
/**
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
index 614b818..f398487 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
@@ -28,7 +28,7 @@
import androidx.room.ext.CollectionTypeNames.LONG_SPARSE_ARRAY
import androidx.room.ext.CommonTypeNames
import androidx.room.ext.GuavaTypeNames
-import androidx.room.ext.getValueClassUnderlyingProperty
+import androidx.room.ext.getValueClassUnderlyingElement
import androidx.room.ext.isByteBuffer
import androidx.room.ext.isEntityElement
import androidx.room.ext.isNotByte
@@ -380,7 +380,7 @@
val typeElement = type.typeElement
if (typeElement?.isValueClass() == true) {
// Extract the type value of the Value class element
- val underlyingProperty = typeElement.getValueClassUnderlyingProperty()
+ val underlyingProperty = typeElement.getValueClassUnderlyingElement()
val underlyingTypeColumnAdapter = findColumnTypeAdapter(
// Find an adapter for the non-null underlying type, nullability will be handled
// by the value class adapter.
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/ext/ElementExtTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/ext/ElementExtTest.kt
index 1c19e7f..ec688de 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/ext/ElementExtTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/ext/ElementExtTest.kt
@@ -20,9 +20,11 @@
import androidx.room.compiler.codegen.XClassName
import androidx.room.compiler.codegen.XTypeName
import androidx.room.compiler.processing.XMethodElement
+import androidx.room.compiler.processing.XProcessingEnvConfig
import androidx.room.compiler.processing.util.Source
import androidx.room.compiler.processing.util.XTestInvocation
import androidx.room.compiler.processing.util.compileFiles
+import androidx.room.compiler.processing.util.runKspTest
import androidx.room.compiler.processing.util.runProcessorTest
import org.junit.Test
import org.junit.runner.RunWith
@@ -216,6 +218,36 @@
}
}
+ @Test
+ fun valueClassUnderlyingProperty() {
+ val src = Source.kotlin(
+ "Subject.kt",
+ """
+ package foo
+ class Subject {
+ fun makeULong(): ULong {
+ TODO()
+ }
+ }
+ """.trimIndent()
+ )
+ runKspTest(
+ sources = listOf(src),
+ config = XProcessingEnvConfig.DEFAULT.copy(
+ excludeMethodsWithInvalidJvmSourceNames = false
+ )
+ ) { invocation ->
+ val subject = invocation.processingEnv.requireTypeElement("foo.Subject")
+ val returnType = subject.getDeclaredMethods()
+ .single { it.name == "makeULong" }
+ .returnType
+ val prop = checkNotNull(returnType.typeElement).getValueClassUnderlyingElement()
+ assertThat(prop.name).isEqualTo("data")
+ assertThat(prop.type)
+ .isEqualTo(invocation.processingEnv.requireType(XTypeName.PRIMITIVE_LONG))
+ }
+ }
+
@Suppress("NAME_SHADOWING") // intentional
private fun runTest(
sources: List<Source> = emptyList(),
diff --git a/room/room-runtime/build.gradle b/room/room-runtime/build.gradle
index b3a01b3..a31d80b 100644
--- a/room/room-runtime/build.gradle
+++ b/room/room-runtime/build.gradle
@@ -25,6 +25,12 @@
}
android {
+ sourceSets {
+ main {
+ // Align AGP main source set root with KMP
+ root = 'src/androidMain'
+ }
+ }
defaultConfig {
multiDexEnabled true
}
diff --git a/room/room-runtime/src/androidInstrumentedTest/kotlin/androidx/room/AutoClosingRoomOpenHelperFactoryTest.kt b/room/room-runtime/src/androidInstrumentedTest/kotlin/androidx/room/AutoClosingRoomOpenHelperFactoryTest.kt
index df0f033..93a3f73 100644
--- a/room/room-runtime/src/androidInstrumentedTest/kotlin/androidx/room/AutoClosingRoomOpenHelperFactoryTest.kt
+++ b/room/room-runtime/src/androidInstrumentedTest/kotlin/androidx/room/AutoClosingRoomOpenHelperFactoryTest.kt
@@ -19,7 +19,6 @@
import android.annotation.SuppressLint
import android.content.Context
import android.os.Build
-import android.os.Build.VERSION_CODES.JELLY_BEAN
import androidx.annotation.RequiresApi
import androidx.sqlite.db.SupportSQLiteDatabase
import androidx.sqlite.db.SupportSQLiteOpenHelper
@@ -89,28 +88,16 @@
autoClosingRoomOpenHelper.writableDatabase
- if (android.os.Build.VERSION.SDK_INT < JELLY_BEAN) {
- // onConfigure does not exist before JELLY_BEAN
- // onCreate + onOpen
- assertEquals(2, callbackCount.get())
- } else {
- // onConfigure + onCreate + onOpen
- assertEquals(3, callbackCount.get())
- }
+ // onConfigure + onCreate + onOpen
+ assertEquals(3, callbackCount.get())
Thread.sleep(100)
autoClosingRoomOpenHelper.writableDatabase
// onCreate won't be called the second time.
- if (android.os.Build.VERSION.SDK_INT < JELLY_BEAN) {
- // onConfigure does not exist before JELLY_BEAN
- // onCreate + onOpen + onOpen
- assertEquals(3, callbackCount.get())
- } else {
- // onConfigure + onCreate + onOpen + onConfigure + onOpen
- assertEquals(5, callbackCount.get())
- }
+ // onConfigure + onCreate + onOpen + onConfigure + onOpen
+ assertEquals(5, callbackCount.get())
}
@RequiresApi(Build.VERSION_CODES.N)
diff --git a/room/room-runtime/src/androidInstrumentedTest/kotlin/androidx/room/AutoClosingRoomOpenHelperTest.kt b/room/room-runtime/src/androidInstrumentedTest/kotlin/androidx/room/AutoClosingRoomOpenHelperTest.kt
index 77e1a2b..8621c189 100644
--- a/room/room-runtime/src/androidInstrumentedTest/kotlin/androidx/room/AutoClosingRoomOpenHelperTest.kt
+++ b/room/room-runtime/src/androidInstrumentedTest/kotlin/androidx/room/AutoClosingRoomOpenHelperTest.kt
@@ -28,7 +28,6 @@
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
import androidx.test.core.app.ApplicationProvider
import androidx.test.filters.FlakyTest
-import androidx.test.filters.SdkSuppress
import androidx.testutils.assertThrows
import java.io.IOException
import java.util.concurrent.Executors
@@ -121,7 +120,6 @@
@SuppressLint("BanThreadSleep")
@RequiresApi(Build.VERSION_CODES.N)
@Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
fun enableWriteAheadLogging_onOpenHelper() {
val autoClosingRoomOpenHelper = getAutoClosingRoomOpenHelper()
diff --git a/room/room-runtime/src/main/java/androidx/room/paging/LimitOffsetDataSource.java b/room/room-runtime/src/androidMain/java/androidx/room/paging/LimitOffsetDataSource.java
similarity index 100%
rename from room/room-runtime/src/main/java/androidx/room/paging/LimitOffsetDataSource.java
rename to room/room-runtime/src/androidMain/java/androidx/room/paging/LimitOffsetDataSource.java
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/AutoClosingRoomOpenHelper.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/AutoClosingRoomOpenHelper.android.kt
index 0b47d27..2d29e36 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/AutoClosingRoomOpenHelper.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/AutoClosingRoomOpenHelper.android.kt
@@ -356,12 +356,9 @@
}
}
- @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
override fun setForeignKeyConstraintsEnabled(enabled: Boolean) {
autoCloser.executeRefCountingFunction<Any?> { db: SupportSQLiteDatabase ->
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- db.setForeignKeyConstraintsEnabled(enabled)
- }
+ db.setForeignKeyConstraintsEnabled(enabled)
null
}
}
@@ -380,13 +377,9 @@
)
}
- @get:RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
override val isWriteAheadLoggingEnabled: Boolean
get() = autoCloser.executeRefCountingFunction { db: SupportSQLiteDatabase ->
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- return@executeRefCountingFunction db.isWriteAheadLoggingEnabled
- }
- false
+ return@executeRefCountingFunction db.isWriteAheadLoggingEnabled
}
override val attachedDbs: List<Pair<String, String>>?
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/InvalidationTracker.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/InvalidationTracker.android.kt
index 38067b7..5c2e38d 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/InvalidationTracker.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/InvalidationTracker.android.kt
@@ -19,7 +19,6 @@
import android.content.Context
import android.content.Intent
import android.database.sqlite.SQLiteException
-import android.os.Build
import android.util.Log
import androidx.annotation.GuardedBy
import androidx.annotation.RestrictTo
@@ -827,9 +826,7 @@
) = "`room_table_modification_trigger_${tableName}_$triggerType`"
internal fun beginTransactionInternal(database: SupportSQLiteDatabase) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN &&
- database.isWriteAheadLoggingEnabled
- ) {
+ if (database.isWriteAheadLoggingEnabled) {
database.beginTransactionNonExclusive()
} else {
database.beginTransaction()
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/SQLiteCopyOpenHelper.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/SQLiteCopyOpenHelper.android.kt
index 3672ab0..883fe26 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/SQLiteCopyOpenHelper.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/SQLiteCopyOpenHelper.android.kt
@@ -16,9 +16,7 @@
package androidx.room
import android.content.Context
-import android.os.Build
import android.util.Log
-import androidx.annotation.RequiresApi
import androidx.room.Room.LOG_TAG
import androidx.room.util.copy
import androidx.room.util.readVersion
@@ -31,9 +29,6 @@
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
-import java.lang.Exception
-import java.lang.IllegalStateException
-import java.lang.RuntimeException
import java.nio.channels.Channels
import java.nio.channels.ReadableByteChannel
import java.util.concurrent.Callable
@@ -57,7 +52,6 @@
override val databaseName: String?
get() = delegate.databaseName
- @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
override fun setWriteAheadLoggingEnabled(enabled: Boolean) {
delegate.setWriteAheadLoggingEnabled(enabled)
}
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/Placeholder.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/Placeholder.kt
new file mode 100644
index 0000000..bad50f2
--- /dev/null
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/Placeholder.kt
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2023 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.room
+// empty file to trigger klib creation
+// see: https://youtrack.jetbrains.com/issue/KT-52344
diff --git a/samples/AndroidXDemos/src/main/java/com/example/androidx/app/ActionBarDisplayOptions.java b/samples/AndroidXDemos/src/main/java/com/example/androidx/app/ActionBarDisplayOptions.java
index 47c07b3..47db7ac 100644
--- a/samples/AndroidXDemos/src/main/java/com/example/androidx/app/ActionBarDisplayOptions.java
+++ b/samples/AndroidXDemos/src/main/java/com/example/androidx/app/ActionBarDisplayOptions.java
@@ -76,47 +76,41 @@
public void onClick(View v) {
final ActionBar bar = getSupportActionBar();
int flags = 0;
- switch (v.getId()) {
- case R.id.toggle_home_as_up:
- flags = ActionBar.DISPLAY_HOME_AS_UP;
- break;
- case R.id.toggle_show_home:
- flags = ActionBar.DISPLAY_SHOW_HOME;
- break;
- case R.id.toggle_use_logo:
- flags = ActionBar.DISPLAY_USE_LOGO;
- break;
- case R.id.toggle_show_title:
- flags = ActionBar.DISPLAY_SHOW_TITLE;
- break;
- case R.id.toggle_show_custom:
- flags = ActionBar.DISPLAY_SHOW_CUSTOM;
- break;
- case R.id.cycle_custom_gravity: {
- ActionBar.LayoutParams lp = mCustomViewLayoutParams;
- int newGravity = 0;
- switch (lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
- case Gravity.LEFT:
- newGravity = Gravity.CENTER_HORIZONTAL;
- break;
- case Gravity.CENTER_HORIZONTAL:
- newGravity = Gravity.RIGHT;
- break;
- case Gravity.RIGHT:
- newGravity = Gravity.LEFT;
- break;
- }
- lp.gravity = (lp.gravity & ~Gravity.HORIZONTAL_GRAVITY_MASK) | newGravity;
- bar.setCustomView(mCustomView, lp);
- return;
+ int id = v.getId();
+ if (id == R.id.toggle_home_as_up) {
+ flags = ActionBar.DISPLAY_HOME_AS_UP;
+ } else if (id == R.id.toggle_show_home) {
+ flags = ActionBar.DISPLAY_SHOW_HOME;
+ } else if (id == R.id.toggle_use_logo) {
+ flags = ActionBar.DISPLAY_USE_LOGO;
+ } else if (id == R.id.toggle_show_title) {
+ flags = ActionBar.DISPLAY_SHOW_TITLE;
+ } else if (id == R.id.toggle_show_custom) {
+ flags = ActionBar.DISPLAY_SHOW_CUSTOM;
+ } else if (id == R.id.cycle_custom_gravity) {
+ ActionBar.LayoutParams lp = mCustomViewLayoutParams;
+ int newGravity = 0;
+ switch (lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
+ case Gravity.LEFT:
+ newGravity = Gravity.CENTER_HORIZONTAL;
+ break;
+ case Gravity.CENTER_HORIZONTAL:
+ newGravity = Gravity.RIGHT;
+ break;
+ case Gravity.RIGHT:
+ newGravity = Gravity.LEFT;
+ break;
}
- case R.id.toggle_visibility:
- if (bar.isShowing()) {
- bar.hide();
- } else {
- bar.show();
- }
- return;
+ lp.gravity = (lp.gravity & ~Gravity.HORIZONTAL_GRAVITY_MASK) | newGravity;
+ bar.setCustomView(mCustomView, lp);
+ return;
+ } else if (id == R.id.toggle_visibility) {
+ if (bar.isShowing()) {
+ bar.hide();
+ } else {
+ bar.show();
+ }
+ return;
}
int change = bar.getDisplayOptions() ^ flags;
diff --git a/samples/AndroidXDemos/src/main/java/com/example/androidx/app/ActionBarUsage.java b/samples/AndroidXDemos/src/main/java/com/example/androidx/app/ActionBarUsage.java
index 942b569..e21d40d 100644
--- a/samples/AndroidXDemos/src/main/java/com/example/androidx/app/ActionBarUsage.java
+++ b/samples/AndroidXDemos/src/main/java/com/example/androidx/app/ActionBarUsage.java
@@ -72,11 +72,9 @@
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.action_sort_alpha:
- case R.id.action_sort_size:
- onSort(item);
- break;
+ int itemId = item.getItemId();
+ if (itemId == R.id.action_sort_alpha || itemId == R.id.action_sort_size) {
+ onSort(item);
}
Toast.makeText(this, "Selected Item: " + item.getTitle(), Toast.LENGTH_SHORT).show();
diff --git a/samples/AndroidXDemos/src/main/java/com/example/androidx/app/ToolbarDisplayOptions.java b/samples/AndroidXDemos/src/main/java/com/example/androidx/app/ToolbarDisplayOptions.java
index ef2f7be..8898417 100644
--- a/samples/AndroidXDemos/src/main/java/com/example/androidx/app/ToolbarDisplayOptions.java
+++ b/samples/AndroidXDemos/src/main/java/com/example/androidx/app/ToolbarDisplayOptions.java
@@ -76,48 +76,42 @@
public void onClick(View v) {
final ActionBar bar = getSupportActionBar();
int flags = 0;
- switch (v.getId()) {
- case R.id.toggle_home_as_up:
- flags = ActionBar.DISPLAY_HOME_AS_UP;
- break;
- case R.id.toggle_show_home:
- flags = ActionBar.DISPLAY_SHOW_HOME;
- break;
- case R.id.toggle_use_logo:
- flags = ActionBar.DISPLAY_USE_LOGO;
- getSupportActionBar().setLogo(R.drawable.ic_media_play);
- break;
- case R.id.toggle_show_title:
- flags = ActionBar.DISPLAY_SHOW_TITLE;
- break;
- case R.id.toggle_show_custom:
- flags = ActionBar.DISPLAY_SHOW_CUSTOM;
- break;
- case R.id.cycle_custom_gravity: {
- ActionBar.LayoutParams lp = mCustomViewLayoutParams;
- int newGravity = 0;
- switch (lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
- case Gravity.LEFT:
- newGravity = Gravity.CENTER_HORIZONTAL;
- break;
- case Gravity.CENTER_HORIZONTAL:
- newGravity = Gravity.RIGHT;
- break;
- case Gravity.RIGHT:
- newGravity = Gravity.LEFT;
- break;
- }
- lp.gravity = (lp.gravity & ~Gravity.HORIZONTAL_GRAVITY_MASK) | newGravity;
- bar.setCustomView(mCustomView, lp);
- return;
+ int id = v.getId();
+ if (id == R.id.toggle_home_as_up) {
+ flags = ActionBar.DISPLAY_HOME_AS_UP;
+ } else if (id == R.id.toggle_show_home) {
+ flags = ActionBar.DISPLAY_SHOW_HOME;
+ } else if (id == R.id.toggle_use_logo) {
+ flags = ActionBar.DISPLAY_USE_LOGO;
+ getSupportActionBar().setLogo(R.drawable.ic_media_play);
+ } else if (id == R.id.toggle_show_title) {
+ flags = ActionBar.DISPLAY_SHOW_TITLE;
+ } else if (id == R.id.toggle_show_custom) {
+ flags = ActionBar.DISPLAY_SHOW_CUSTOM;
+ } else if (id == R.id.cycle_custom_gravity) {
+ ActionBar.LayoutParams lp = mCustomViewLayoutParams;
+ int newGravity = 0;
+ switch (lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
+ case Gravity.LEFT:
+ newGravity = Gravity.CENTER_HORIZONTAL;
+ break;
+ case Gravity.CENTER_HORIZONTAL:
+ newGravity = Gravity.RIGHT;
+ break;
+ case Gravity.RIGHT:
+ newGravity = Gravity.LEFT;
+ break;
}
- case R.id.toggle_visibility:
- if (bar.isShowing()) {
- bar.hide();
- } else {
- bar.show();
- }
- return;
+ lp.gravity = (lp.gravity & ~Gravity.HORIZONTAL_GRAVITY_MASK) | newGravity;
+ bar.setCustomView(mCustomView, lp);
+ return;
+ } else if (id == R.id.toggle_visibility) {
+ if (bar.isShowing()) {
+ bar.hide();
+ } else {
+ bar.show();
+ }
+ return;
}
int change = bar.getDisplayOptions() ^ flags;
diff --git a/samples/AndroidXDemos/src/main/java/com/example/androidx/graphics/PaletteActivity.java b/samples/AndroidXDemos/src/main/java/com/example/androidx/graphics/PaletteActivity.java
index d98583a..3eed2a3 100644
--- a/samples/AndroidXDemos/src/main/java/com/example/androidx/graphics/PaletteActivity.java
+++ b/samples/AndroidXDemos/src/main/java/com/example/androidx/graphics/PaletteActivity.java
@@ -112,27 +112,27 @@
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.menu_num_colors_8:
- mAdapter.setNumColors(8);
- item.setChecked(true);
- return true;
- case R.id.menu_num_colors_12:
- mAdapter.setNumColors(12);
- item.setChecked(true);
- return true;
- case R.id.menu_num_colors_16:
- mAdapter.setNumColors(16);
- item.setChecked(true);
- return true;
- case R.id.menu_num_colors_24:
- mAdapter.setNumColors(24);
- item.setChecked(true);
- return true;
- case R.id.menu_num_colors_32:
- mAdapter.setNumColors(32);
- item.setChecked(true);
- return true;
+ int itemId = item.getItemId();
+ if (itemId == R.id.menu_num_colors_8) {
+ mAdapter.setNumColors(8);
+ item.setChecked(true);
+ return true;
+ } else if (itemId == R.id.menu_num_colors_12) {
+ mAdapter.setNumColors(12);
+ item.setChecked(true);
+ return true;
+ } else if (itemId == R.id.menu_num_colors_16) {
+ mAdapter.setNumColors(16);
+ item.setChecked(true);
+ return true;
+ } else if (itemId == R.id.menu_num_colors_24) {
+ mAdapter.setNumColors(24);
+ item.setChecked(true);
+ return true;
+ } else if (itemId == R.id.menu_num_colors_32) {
+ mAdapter.setNumColors(32);
+ item.setChecked(true);
+ return true;
}
return super.onOptionsItemSelected(item);
diff --git a/samples/AndroidXDemos/src/main/java/com/example/androidx/graphics/PaletteDetailActivity.java b/samples/AndroidXDemos/src/main/java/com/example/androidx/graphics/PaletteDetailActivity.java
index bbd39ea..2ad9c3a 100644
--- a/samples/AndroidXDemos/src/main/java/com/example/androidx/graphics/PaletteDetailActivity.java
+++ b/samples/AndroidXDemos/src/main/java/com/example/androidx/graphics/PaletteDetailActivity.java
@@ -96,27 +96,27 @@
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.menu_num_colors_8:
- loadImage(8);
- item.setChecked(true);
- return true;
- case R.id.menu_num_colors_12:
- loadImage(12);
- item.setChecked(true);
- return true;
- case R.id.menu_num_colors_16:
- loadImage(16);
- item.setChecked(true);
- return true;
- case R.id.menu_num_colors_24:
- loadImage(24);
- item.setChecked(true);
- return true;
- case R.id.menu_num_colors_32:
- loadImage(32);
- item.setChecked(true);
- return true;
+ int itemId = item.getItemId();
+ if (itemId == R.id.menu_num_colors_8) {
+ loadImage(8);
+ item.setChecked(true);
+ return true;
+ } else if (itemId == R.id.menu_num_colors_12) {
+ loadImage(12);
+ item.setChecked(true);
+ return true;
+ } else if (itemId == R.id.menu_num_colors_16) {
+ loadImage(16);
+ item.setChecked(true);
+ return true;
+ } else if (itemId == R.id.menu_num_colors_24) {
+ loadImage(24);
+ item.setChecked(true);
+ return true;
+ } else if (itemId == R.id.menu_num_colors_32) {
+ loadImage(32);
+ item.setChecked(true);
+ return true;
}
return super.onOptionsItemSelected(item);
}
diff --git a/samples/AndroidXDemos/src/main/java/com/example/androidx/view/CardViewActivity.java b/samples/AndroidXDemos/src/main/java/com/example/androidx/view/CardViewActivity.java
index 7cd5e7a..4e6ff95 100644
--- a/samples/AndroidXDemos/src/main/java/com/example/androidx/view/CardViewActivity.java
+++ b/samples/AndroidXDemos/src/main/java/com/example/androidx/view/CardViewActivity.java
@@ -170,21 +170,19 @@
}
private int getColorId(int id) {
- switch (id) {
- case R.id.yellow:
- return R.color.card_yellow;
- case R.id.aquatic:
- return R.color.card_aquatic;
- case R.id.classic:
- return R.color.card_classic;
- case R.id.sunbrite:
- return R.color.card_sunbrite;
- case R.id.tropical:
- return R.color.card_tropical;
- case R.id.selector:
- return R.color.card_selector;
- default:
- return androidx.cardview.R.color.cardview_light_background;
+ if (id == R.id.yellow) {
+ return R.color.card_yellow;
+ } else if (id == R.id.aquatic) {
+ return R.color.card_aquatic;
+ } else if (id == R.id.classic) {
+ return R.color.card_classic;
+ } else if (id == R.id.sunbrite) {
+ return R.color.card_sunbrite;
+ } else if (id == R.id.tropical) {
+ return R.color.card_tropical;
+ } else if (id == R.id.selector) {
+ return R.color.card_selector;
}
+ return androidx.cardview.R.color.cardview_light_background;
}
}
diff --git a/samples/AndroidXDemos/src/main/java/com/example/androidx/view/SystemUIModes.java b/samples/AndroidXDemos/src/main/java/com/example/androidx/view/SystemUIModes.java
index 920c70d..debcaed 100644
--- a/samples/AndroidXDemos/src/main/java/com/example/androidx/view/SystemUIModes.java
+++ b/samples/AndroidXDemos/src/main/java/com/example/androidx/view/SystemUIModes.java
@@ -238,15 +238,15 @@
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.show_tabs:
- getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
- item.setChecked(true);
- return true;
- case R.id.hide_tabs:
- getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
- item.setChecked(true);
- return true;
+ int itemId = item.getItemId();
+ if (itemId == R.id.show_tabs) {
+ getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+ item.setChecked(true);
+ return true;
+ } else if (itemId == R.id.hide_tabs) {
+ getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
+ item.setChecked(true);
+ return true;
}
return false;
}
diff --git a/samples/AndroidXDemos/src/main/java/com/example/androidx/widget/selection/fancy/FancySelectionDemoActivity.java b/samples/AndroidXDemos/src/main/java/com/example/androidx/widget/selection/fancy/FancySelectionDemoActivity.java
index 15fa441..40d5f95 100644
--- a/samples/AndroidXDemos/src/main/java/com/example/androidx/widget/selection/fancy/FancySelectionDemoActivity.java
+++ b/samples/AndroidXDemos/src/main/java/com/example/androidx/widget/selection/fancy/FancySelectionDemoActivity.java
@@ -252,16 +252,13 @@
getMenuInflater().inflate(R.menu.selection_demo_actions, menu);
for (int i = 0; i < menu.size(); i++) {
MenuItem item = menu.getItem(i);
- switch (item.getItemId()) {
- case R.id.option_menu_more_cheese:
- item.setChecked(mAdapter.allCheesesEnabled());
- break;
- case R.id.option_menu_grid_layout:
- item.setChecked(mAdapter.smallItemLayoutEnabled());
- break;
- case R.id.option_menu_swipe_during_select:
- item.setChecked(mSwipeDuringSelectionEnabled);
- break;
+ int itemId = item.getItemId();
+ if (itemId == R.id.option_menu_more_cheese) {
+ item.setChecked(mAdapter.allCheesesEnabled());
+ } else if (itemId == R.id.option_menu_grid_layout) {
+ item.setChecked(mAdapter.smallItemLayoutEnabled());
+ } else if (itemId == R.id.option_menu_swipe_during_select) {
+ item.setChecked(mSwipeDuringSelectionEnabled);
}
}
return showMenu;
@@ -277,19 +274,16 @@
}
private void updateOptionFromMenu(@NonNull MenuItem item) {
- switch (item.getItemId()) {
- case R.id.option_menu_more_cheese:
- mAdapter.enableAllCheeses(item.isChecked());
- mAdapter.refresh();
- break;
- case R.id.option_menu_grid_layout:
- mAdapter.enableSmallItemLayout(item.isChecked());
- mLayout.setSpanCount(item.isChecked() ? 2 : 1);
- mAdapter.refresh();
- break;
- case R.id.option_menu_swipe_during_select:
- mSwipeDuringSelectionEnabled = item.isChecked();
- break;
+ int itemId = item.getItemId();
+ if (itemId == R.id.option_menu_more_cheese) {
+ mAdapter.enableAllCheeses(item.isChecked());
+ mAdapter.refresh();
+ } else if (itemId == R.id.option_menu_grid_layout) {
+ mAdapter.enableSmallItemLayout(item.isChecked());
+ mLayout.setSpanCount(item.isChecked() ? 2 : 1);
+ mAdapter.refresh();
+ } else if (itemId == R.id.option_menu_swipe_during_select) {
+ mSwipeDuringSelectionEnabled = item.isChecked();
}
}
@@ -315,14 +309,13 @@
@Override
public boolean onContextItemSelected(@NonNull MenuItem item) {
- switch (item.getItemId()) {
- case R.id.option_menu_item_eat_single:
- case R.id.option_menu_item_eat_multiple:
- toast(this, "Num, num, num...done!");
- return true;
- default:
- return super.onContextItemSelected(item);
+ int itemId = item.getItemId();
+ if (itemId == R.id.option_menu_item_eat_single
+ || itemId == R.id.option_menu_item_eat_multiple) {
+ toast(this, "Num, num, num...done!");
+ return true;
}
+ return super.onContextItemSelected(item);
}
@SuppressWarnings("deprecation")
diff --git a/samples/Support4Demos/src/main/java/com/example/android/supportv4/app/FragmentContextMenuSupport.java b/samples/Support4Demos/src/main/java/com/example/android/supportv4/app/FragmentContextMenuSupport.java
index a350afb..2e242b5 100644
--- a/samples/Support4Demos/src/main/java/com/example/android/supportv4/app/FragmentContextMenuSupport.java
+++ b/samples/Support4Demos/src/main/java/com/example/android/supportv4/app/FragmentContextMenuSupport.java
@@ -65,13 +65,13 @@
@Override
public boolean onContextItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.a_item:
- Log.i("ContextMenu", "Item 1a was chosen");
- return true;
- case R.id.b_item:
- Log.i("ContextMenu", "Item 1b was chosen");
- return true;
+ int itemId = item.getItemId();
+ if (itemId == R.id.a_item) {
+ Log.i("ContextMenu", "Item 1a was chosen");
+ return true;
+ } else if (itemId == R.id.b_item) {
+ Log.i("ContextMenu", "Item 1b was chosen");
+ return true;
}
return super.onContextItemSelected(item);
}
diff --git a/samples/Support4Demos/src/main/java/com/example/android/supportv4/graphics/DrawableCompatActivity.java b/samples/Support4Demos/src/main/java/com/example/android/supportv4/graphics/DrawableCompatActivity.java
index 47d8d96..6dfd07d1 100644
--- a/samples/Support4Demos/src/main/java/com/example/android/supportv4/graphics/DrawableCompatActivity.java
+++ b/samples/Support4Demos/src/main/java/com/example/android/supportv4/graphics/DrawableCompatActivity.java
@@ -54,16 +54,12 @@
rg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup radioGroup, int id) {
- switch (id) {
- case R.id.drawable_compat_no_tint:
- clearTint();
- break;
- case R.id.drawable_compat_color:
- setColorTint();
- break;
- case R.id.drawable_compat_state_list:
- setColorStateListTint();
- break;
+ if (id == R.id.drawable_compat_no_tint) {
+ clearTint();
+ } else if (id == R.id.drawable_compat_color) {
+ setColorTint();
+ } else if (id == R.id.drawable_compat_state_list) {
+ setColorStateListTint();
}
}
});
diff --git a/samples/Support4Demos/src/main/java/com/example/android/supportv4/media/QueueFragment.java b/samples/Support4Demos/src/main/java/com/example/android/supportv4/media/QueueFragment.java
index a1246cf..800b54f 100644
--- a/samples/Support4Demos/src/main/java/com/example/android/supportv4/media/QueueFragment.java
+++ b/samples/Support4Demos/src/main/java/com/example/android/supportv4/media/QueueFragment.java
@@ -255,24 +255,21 @@
public void onClick(View v) {
final int state = mPlaybackState == null ?
PlaybackStateCompat.STATE_NONE : mPlaybackState.getState();
- switch (v.getId()) {
- case R.id.play_pause:
- Log.d(TAG, "Play button pressed, in state " + state);
- if (state == PlaybackStateCompat.STATE_PAUSED ||
- state == PlaybackStateCompat.STATE_STOPPED ||
- state == PlaybackStateCompat.STATE_NONE) {
- playMedia();
- } else if (state == PlaybackStateCompat.STATE_PLAYING) {
- pauseMedia();
- }
- break;
- case R.id.skip_previous:
- Log.d(TAG, "Start button pressed, in state " + state);
- skipToPrevious();
- break;
- case R.id.skip_next:
- skipToNext();
- break;
+ int id = v.getId();
+ if (id == R.id.play_pause) {
+ Log.d(TAG, "Play button pressed, in state " + state);
+ if (state == PlaybackStateCompat.STATE_PAUSED
+ || state == PlaybackStateCompat.STATE_STOPPED
+ || state == PlaybackStateCompat.STATE_NONE) {
+ playMedia();
+ } else if (state == PlaybackStateCompat.STATE_PLAYING) {
+ pauseMedia();
+ }
+ } else if (id == R.id.skip_previous) {
+ Log.d(TAG, "Start button pressed, in state " + state);
+ skipToPrevious();
+ } else if (id == R.id.skip_next) {
+ skipToNext();
}
}
};
diff --git a/samples/Support4Demos/src/main/java/com/example/android/supportv4/widget/BaseSwipeRefreshLayoutActivity.java b/samples/Support4Demos/src/main/java/com/example/android/supportv4/widget/BaseSwipeRefreshLayoutActivity.java
index 423cbfc..adf2b8d 100644
--- a/samples/Support4Demos/src/main/java/com/example/android/supportv4/widget/BaseSwipeRefreshLayoutActivity.java
+++ b/samples/Support4Demos/src/main/java/com/example/android/supportv4/widget/BaseSwipeRefreshLayoutActivity.java
@@ -166,11 +166,10 @@
@Override
public boolean onOptionsItemSelected(MenuItem item) {
final int id = item.getItemId();
- switch(id) {
- case R.id.force_refresh:
- mSwipeRefreshWidget.setRefreshing(true);
- refresh();
- return true;
+ if (id == R.id.force_refresh) {
+ mSwipeRefreshWidget.setRefreshing(true);
+ refresh();
+ return true;
}
return false;
}
diff --git a/samples/Support4Demos/src/main/java/com/example/android/supportv4/widget/ContentLoadingProgressBarActivity.java b/samples/Support4Demos/src/main/java/com/example/android/supportv4/widget/ContentLoadingProgressBarActivity.java
index 0133412..af4b870 100644
--- a/samples/Support4Demos/src/main/java/com/example/android/supportv4/widget/ContentLoadingProgressBarActivity.java
+++ b/samples/Support4Demos/src/main/java/com/example/android/supportv4/widget/ContentLoadingProgressBarActivity.java
@@ -73,17 +73,15 @@
@Override
public void onClick(View v) {
- switch (v.getId()) {
- case R.id.show:
- mBar.show();
- mShowTime = System.currentTimeMillis();
- mShowText.setText("Show clicked at " + mShowTime);
- break;
- case R.id.hide:
- mBar.hide();
- mHideTime = System.currentTimeMillis();
- mHideText.setText("Hide clicked at " + mHideTime);
- break;
+ int id = v.getId();
+ if (id == R.id.show) {
+ mBar.show();
+ mShowTime = System.currentTimeMillis();
+ mShowText.setText("Show clicked at " + mShowTime);
+ } else if (id == R.id.hide) {
+ mBar.hide();
+ mHideTime = System.currentTimeMillis();
+ mHideText.setText("Hide clicked at " + mHideTime);
}
}
diff --git a/samples/Support4Demos/src/main/java/com/example/android/supportv4/widget/SlidingPaneLayoutActivity.java b/samples/Support4Demos/src/main/java/com/example/android/supportv4/widget/SlidingPaneLayoutActivity.java
index 3c84764..6e61388 100644
--- a/samples/Support4Demos/src/main/java/com/example/android/supportv4/widget/SlidingPaneLayoutActivity.java
+++ b/samples/Support4Demos/src/main/java/com/example/android/supportv4/widget/SlidingPaneLayoutActivity.java
@@ -108,19 +108,19 @@
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
- switch (item.getItemId()) {
- case R.id.lock_mode_unlocked:
- mSlidingLayout.setLockMode(SlidingPaneLayout.LOCK_MODE_UNLOCKED);
- return true;
- case R.id.lock_mode_locked_open:
- mSlidingLayout.setLockMode(SlidingPaneLayout.LOCK_MODE_LOCKED_OPEN);
- return true;
- case R.id.lock_mode_locked_closed:
- mSlidingLayout.setLockMode(SlidingPaneLayout.LOCK_MODE_LOCKED_CLOSED);
- return true;
- case R.id.lock_mode_locked:
- mSlidingLayout.setLockMode(SlidingPaneLayout.LOCK_MODE_LOCKED);
- return true;
+ int itemId = item.getItemId();
+ if (itemId == R.id.lock_mode_unlocked) {
+ mSlidingLayout.setLockMode(SlidingPaneLayout.LOCK_MODE_UNLOCKED);
+ return true;
+ } else if (itemId == R.id.lock_mode_locked_open) {
+ mSlidingLayout.setLockMode(SlidingPaneLayout.LOCK_MODE_LOCKED_OPEN);
+ return true;
+ } else if (itemId == R.id.lock_mode_locked_closed) {
+ mSlidingLayout.setLockMode(SlidingPaneLayout.LOCK_MODE_LOCKED_CLOSED);
+ return true;
+ } else if (itemId == R.id.lock_mode_locked) {
+ mSlidingLayout.setLockMode(SlidingPaneLayout.LOCK_MODE_LOCKED);
+ return true;
}
return super.onOptionsItemSelected(item);
}
diff --git a/samples/SupportContentDemos/src/main/java/com/example/android/support/content/demos/ContentPagerDemoActivity.java b/samples/SupportContentDemos/src/main/java/com/example/android/support/content/demos/ContentPagerDemoActivity.java
index a615a78..d8429a2 100644
--- a/samples/SupportContentDemos/src/main/java/com/example/android/support/content/demos/ContentPagerDemoActivity.java
+++ b/samples/SupportContentDemos/src/main/java/com/example/android/support/content/demos/ContentPagerDemoActivity.java
@@ -83,26 +83,14 @@
@Override
public boolean onOptionsItemSelected(MenuItem item) {
-
- switch (item.getItemId()) {
- case R.id.action_load:
- onLoadContent();
- break;
- case R.id.action_previous:
- onLoadPreviousPage();
- break;
- case R.id.action_next:
- onLoadNextPage();
- break;
- }
- // Handle action bar item clicks here. The action bar will
- // automatically handle clicks on the Home/Up button, so long
- // as you specify a parent activity in AndroidManifest.xml.
- int id = item.getItemId();
-
- //noinspection SimplifiableIfStatement
- if (id == R.id.action_load) {
+ int itemId = item.getItemId();
+ if (itemId == R.id.action_load) {
+ onLoadContent();
return true;
+ } else if (itemId == R.id.action_previous) {
+ onLoadPreviousPage();
+ } else if (itemId == R.id.action_next) {
+ onLoadNextPage();
}
return super.onOptionsItemSelected(item);
diff --git a/samples/SupportTransitionDemos/src/main/java/com/example/android/support/transition/widget/ChangeImageTransformUsage.java b/samples/SupportTransitionDemos/src/main/java/com/example/android/support/transition/widget/ChangeImageTransformUsage.java
index a8198d5..c789534 100644
--- a/samples/SupportTransitionDemos/src/main/java/com/example/android/support/transition/widget/ChangeImageTransformUsage.java
+++ b/samples/SupportTransitionDemos/src/main/java/com/example/android/support/transition/widget/ChangeImageTransformUsage.java
@@ -52,29 +52,23 @@
@Override
public void onClick(View v) {
TransitionManager.beginDelayedTransition(mRoot, TRANSITION);
- switch (v.getId()) {
- case R.id.fit_xy:
- mPhoto.setScaleType(ImageView.ScaleType.FIT_XY);
- break;
- case R.id.center:
- mPhoto.setScaleType(ImageView.ScaleType.CENTER);
- break;
- case R.id.center_crop:
- mPhoto.setScaleType(ImageView.ScaleType.CENTER_CROP);
- break;
- case R.id.fit_start:
- mPhoto.setScaleType(ImageView.ScaleType.FIT_START);
- break;
- case R.id.fit_end:
- mPhoto.setScaleType(ImageView.ScaleType.FIT_END);
- break;
- case R.id.matrix:
- mPhoto.setScaleType(ImageView.ScaleType.MATRIX);
- final Matrix matrix = new Matrix();
- matrix.setRotate(45.f);
- matrix.postTranslate(200, 10);
- mPhoto.setImageMatrix(matrix);
- break;
+ int id = v.getId();
+ if (id == R.id.fit_xy) {
+ mPhoto.setScaleType(ImageView.ScaleType.FIT_XY);
+ } else if (id == R.id.center) {
+ mPhoto.setScaleType(ImageView.ScaleType.CENTER);
+ } else if (id == R.id.center_crop) {
+ mPhoto.setScaleType(ImageView.ScaleType.CENTER_CROP);
+ } else if (id == R.id.fit_start) {
+ mPhoto.setScaleType(ImageView.ScaleType.FIT_START);
+ } else if (id == R.id.fit_end) {
+ mPhoto.setScaleType(ImageView.ScaleType.FIT_END);
+ } else if (id == R.id.matrix) {
+ mPhoto.setScaleType(ImageView.ScaleType.MATRIX);
+ final Matrix matrix = new Matrix();
+ matrix.setRotate(45.f);
+ matrix.postTranslate(200, 10);
+ mPhoto.setImageMatrix(matrix);
}
}
};
diff --git a/samples/SupportTransitionDemos/src/main/java/com/example/android/support/transition/widget/SceneUsageBase.java b/samples/SupportTransitionDemos/src/main/java/com/example/android/support/transition/widget/SceneUsageBase.java
index fa9d9c7..2c40b70 100644
--- a/samples/SupportTransitionDemos/src/main/java/com/example/android/support/transition/widget/SceneUsageBase.java
+++ b/samples/SupportTransitionDemos/src/main/java/com/example/android/support/transition/widget/SceneUsageBase.java
@@ -59,11 +59,10 @@
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.action_toggle:
- mCurrentScene = (mCurrentScene + 1) % mScenes.length;
- go(mScenes[mCurrentScene]);
- return true;
+ if (item.getItemId() == R.id.action_toggle) {
+ mCurrentScene = (mCurrentScene + 1) % mScenes.length;
+ go(mScenes[mCurrentScene]);
+ return true;
}
return false;
}
diff --git a/sharetarget/integration-tests/testapp/src/main/java/androidx/sharetarget/testapp/MainActivity.java b/sharetarget/integration-tests/testapp/src/main/java/androidx/sharetarget/testapp/MainActivity.java
index d1ed33e..138d206 100644
--- a/sharetarget/integration-tests/testapp/src/main/java/androidx/sharetarget/testapp/MainActivity.java
+++ b/sharetarget/integration-tests/testapp/src/main/java/androidx/sharetarget/testapp/MainActivity.java
@@ -53,13 +53,11 @@
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
- switch (view.getId()) {
- case R.id.push_targets:
- pushDirectShareTargets();
- break;
- case R.id.remove_targets:
- removeAllDirectShareTargets();
- break;
+ int id = view.getId();
+ if (id == R.id.push_targets) {
+ pushDirectShareTargets();
+ } else if (id == R.id.remove_targets) {
+ removeAllDirectShareTargets();
}
}
};
diff --git a/sharetarget/sharetarget/src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java b/sharetarget/sharetarget/src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java
index 229e42c..f3f5672 100644
--- a/sharetarget/sharetarget/src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java
+++ b/sharetarget/sharetarget/src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java
@@ -29,7 +29,6 @@
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.Icon;
-import android.os.Build;
import androidx.annotation.NonNull;
import androidx.core.app.Person;
@@ -39,7 +38,6 @@
import androidx.sharetarget.test.R;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SdkSuppress;
import androidx.test.filters.SmallTest;
import com.google.common.util.concurrent.ListenableFuture;
@@ -56,7 +54,6 @@
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
@SmallTest
@RunWith(AndroidJUnit4.class)
public class ShortcutInfoCompatSaverTest {
diff --git a/slice/slice-core/src/main/java/androidx/slice/SliceProvider.java b/slice/slice-core/src/main/java/androidx/slice/SliceProvider.java
index 399ba9f..edb4a01 100644
--- a/slice/slice-core/src/main/java/androidx/slice/SliceProvider.java
+++ b/slice/slice-core/src/main/java/androidx/slice/SliceProvider.java
@@ -211,7 +211,6 @@
@Override
public final boolean onCreate() {
- if (Build.VERSION.SDK_INT < 19) return false;
return onCreateSliceProvider();
}
@@ -243,7 +242,6 @@
@Nullable
@Override
public final String getType(@NonNull Uri uri) {
- if (Build.VERSION.SDK_INT < 19) return null;
if (DEBUG) Log.d(TAG, "getFormat " + uri);
return SLICE_TYPE;
}
@@ -272,7 +270,7 @@
@Nullable
@Override
public Bundle call(@NonNull String method, @Nullable String arg, @Nullable Bundle extras) {
- if (Build.VERSION.SDK_INT < 19 || Build.VERSION.SDK_INT >= 28) return null;
+ if (Build.VERSION.SDK_INT >= 28) return null;
if (extras == null) return null;
return getSliceProviderCompat().call(method, arg, extras);
}
diff --git a/sqlite/sqlite-framework/src/androidTest/java/androidx/sqlite/db/framework/OpenHelperRecoveryTest.kt b/sqlite/sqlite-framework/src/androidTest/java/androidx/sqlite/db/framework/OpenHelperRecoveryTest.kt
index d307b12..4aaa045 100644
--- a/sqlite/sqlite-framework/src/androidTest/java/androidx/sqlite/db/framework/OpenHelperRecoveryTest.kt
+++ b/sqlite/sqlite-framework/src/androidTest/java/androidx/sqlite/db/framework/OpenHelperRecoveryTest.kt
@@ -18,7 +18,6 @@
import android.content.Context
import android.database.sqlite.SQLiteException
-import android.os.Build
import androidx.sqlite.db.SupportSQLiteDatabase
import androidx.sqlite.db.SupportSQLiteOpenHelper
import androidx.test.core.app.ApplicationProvider
@@ -40,25 +39,23 @@
}
@Test
fun delegateLaziness() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- val openHelper = FrameworkSQLiteOpenHelper(
- context,
- dbName,
- EmptyCallback(),
- false,
- false
- )
- openHelper.setWriteAheadLoggingEnabled(true)
+ val openHelper = FrameworkSQLiteOpenHelper(
+ context,
+ dbName,
+ EmptyCallback(),
+ false,
+ false
+ )
+ openHelper.setWriteAheadLoggingEnabled(true)
- val dbFileBeforeWritable = context.getDatabasePath(dbName)
- assertThat(dbFileBeforeWritable.exists()).isFalse()
+ val dbFileBeforeWritable = context.getDatabasePath(dbName)
+ assertThat(dbFileBeforeWritable.exists()).isFalse()
- val writableDb = openHelper.writableDatabase
- val dbFileAfterWritable = context.getDatabasePath(dbName)
+ val writableDb = openHelper.writableDatabase
+ val dbFileAfterWritable = context.getDatabasePath(dbName)
- assertThat(dbFileAfterWritable.exists()).isTrue()
- assertThat(writableDb.isWriteAheadLoggingEnabled).isTrue()
- }
+ assertThat(dbFileAfterWritable.exists()).isTrue()
+ assertThat(writableDb.isWriteAheadLoggingEnabled).isTrue()
}
@Test
diff --git a/stableaidl/stableaidl-gradle-plugin/src/test/java/com/android/build/gradle/internal/fixtures/FakeGradleProperty.kt b/stableaidl/stableaidl-gradle-plugin/src/test/java/com/android/build/gradle/internal/fixtures/FakeGradleProperty.kt
index aaf77af..8ca3a1e 100644
--- a/stableaidl/stableaidl-gradle-plugin/src/test/java/com/android/build/gradle/internal/fixtures/FakeGradleProperty.kt
+++ b/stableaidl/stableaidl-gradle-plugin/src/test/java/com/android/build/gradle/internal/fixtures/FakeGradleProperty.kt
@@ -17,10 +17,10 @@
package com.android.build.gradle.internal.fixtures
import java.util.function.BiFunction
-import java.util.function.Predicate
import org.gradle.api.Transformer
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
+import org.gradle.api.specs.Spec
class FakeGradleProperty<T>(private var value: T? = null) : Property<T> {
@@ -47,8 +47,7 @@
value ?: valueProvider?.get() ?: convention ?: throw IllegalStateException("Value not set")
override fun getOrNull() = value ?: valueProvider?.get() ?: convention
-
- override fun filter(predicate: Predicate<in T>): Provider<T> {
+ override fun filter(spec: Spec<in T>): Provider<T> {
throw NotImplementedError()
}
diff --git a/test/uiautomator/uiautomator/api/2.3.0-beta01.txt b/test/uiautomator/uiautomator/api/2.3.0-beta01.txt
new file mode 100644
index 0000000..bfaecd4
--- /dev/null
+++ b/test/uiautomator/uiautomator/api/2.3.0-beta01.txt
@@ -0,0 +1,467 @@
+// Signature format: 4.0
+package androidx.test.uiautomator {
+
+ public class By {
+ method public static androidx.test.uiautomator.BySelector checkable(boolean);
+ method public static androidx.test.uiautomator.BySelector checked(boolean);
+ method public static androidx.test.uiautomator.BySelector clazz(Class);
+ method public static androidx.test.uiautomator.BySelector clazz(String);
+ method public static androidx.test.uiautomator.BySelector clazz(String, String);
+ method public static androidx.test.uiautomator.BySelector clazz(java.util.regex.Pattern);
+ method public static androidx.test.uiautomator.BySelector clickable(boolean);
+ method public static androidx.test.uiautomator.BySelector copy(androidx.test.uiautomator.BySelector);
+ method public static androidx.test.uiautomator.BySelector depth(int);
+ method public static androidx.test.uiautomator.BySelector desc(String);
+ method public static androidx.test.uiautomator.BySelector desc(java.util.regex.Pattern);
+ method public static androidx.test.uiautomator.BySelector descContains(String);
+ method public static androidx.test.uiautomator.BySelector descEndsWith(String);
+ method public static androidx.test.uiautomator.BySelector descStartsWith(String);
+ method @RequiresApi(30) public static androidx.test.uiautomator.BySelector displayId(int);
+ method public static androidx.test.uiautomator.BySelector enabled(boolean);
+ method public static androidx.test.uiautomator.BySelector focusable(boolean);
+ method public static androidx.test.uiautomator.BySelector focused(boolean);
+ method public static androidx.test.uiautomator.BySelector hasAncestor(androidx.test.uiautomator.BySelector);
+ method public static androidx.test.uiautomator.BySelector hasAncestor(androidx.test.uiautomator.BySelector, @IntRange(from=1) int);
+ method public static androidx.test.uiautomator.BySelector hasChild(androidx.test.uiautomator.BySelector);
+ method public static androidx.test.uiautomator.BySelector hasDescendant(androidx.test.uiautomator.BySelector);
+ method public static androidx.test.uiautomator.BySelector hasDescendant(androidx.test.uiautomator.BySelector, int);
+ method public static androidx.test.uiautomator.BySelector hasParent(androidx.test.uiautomator.BySelector);
+ method @RequiresApi(26) public static androidx.test.uiautomator.BySelector hint(String);
+ method @RequiresApi(26) public static androidx.test.uiautomator.BySelector hint(java.util.regex.Pattern);
+ method @RequiresApi(26) public static androidx.test.uiautomator.BySelector hintContains(String);
+ method @RequiresApi(26) public static androidx.test.uiautomator.BySelector hintEndsWith(String);
+ method @RequiresApi(26) public static androidx.test.uiautomator.BySelector hintStartsWith(String);
+ method public static androidx.test.uiautomator.BySelector longClickable(boolean);
+ method public static androidx.test.uiautomator.BySelector pkg(String);
+ method public static androidx.test.uiautomator.BySelector pkg(java.util.regex.Pattern);
+ method public static androidx.test.uiautomator.BySelector res(String);
+ method public static androidx.test.uiautomator.BySelector res(String, String);
+ method public static androidx.test.uiautomator.BySelector res(java.util.regex.Pattern);
+ method public static androidx.test.uiautomator.BySelector scrollable(boolean);
+ method public static androidx.test.uiautomator.BySelector selected(boolean);
+ method public static androidx.test.uiautomator.BySelector text(String);
+ method public static androidx.test.uiautomator.BySelector text(java.util.regex.Pattern);
+ method public static androidx.test.uiautomator.BySelector textContains(String);
+ method public static androidx.test.uiautomator.BySelector textEndsWith(String);
+ method public static androidx.test.uiautomator.BySelector textStartsWith(String);
+ }
+
+ public class BySelector {
+ method public androidx.test.uiautomator.BySelector checkable(boolean);
+ method public androidx.test.uiautomator.BySelector checked(boolean);
+ method public androidx.test.uiautomator.BySelector clazz(Class);
+ method public androidx.test.uiautomator.BySelector clazz(String);
+ method public androidx.test.uiautomator.BySelector clazz(String, String);
+ method public androidx.test.uiautomator.BySelector clazz(java.util.regex.Pattern);
+ method public androidx.test.uiautomator.BySelector clickable(boolean);
+ method public androidx.test.uiautomator.BySelector depth(int);
+ method public androidx.test.uiautomator.BySelector depth(int, int);
+ method public androidx.test.uiautomator.BySelector desc(String);
+ method public androidx.test.uiautomator.BySelector desc(java.util.regex.Pattern);
+ method public androidx.test.uiautomator.BySelector descContains(String);
+ method public androidx.test.uiautomator.BySelector descEndsWith(String);
+ method public androidx.test.uiautomator.BySelector descStartsWith(String);
+ method @RequiresApi(30) public androidx.test.uiautomator.BySelector displayId(int);
+ method public androidx.test.uiautomator.BySelector enabled(boolean);
+ method public androidx.test.uiautomator.BySelector focusable(boolean);
+ method public androidx.test.uiautomator.BySelector focused(boolean);
+ method public androidx.test.uiautomator.BySelector hasAncestor(androidx.test.uiautomator.BySelector);
+ method public androidx.test.uiautomator.BySelector hasAncestor(androidx.test.uiautomator.BySelector, @IntRange(from=1) int);
+ method public androidx.test.uiautomator.BySelector hasChild(androidx.test.uiautomator.BySelector);
+ method public androidx.test.uiautomator.BySelector hasDescendant(androidx.test.uiautomator.BySelector);
+ method public androidx.test.uiautomator.BySelector hasDescendant(androidx.test.uiautomator.BySelector, int);
+ method public androidx.test.uiautomator.BySelector hasParent(androidx.test.uiautomator.BySelector);
+ method @RequiresApi(26) public androidx.test.uiautomator.BySelector hint(String);
+ method @RequiresApi(26) public androidx.test.uiautomator.BySelector hint(java.util.regex.Pattern);
+ method @RequiresApi(26) public androidx.test.uiautomator.BySelector hintContains(String);
+ method @RequiresApi(26) public androidx.test.uiautomator.BySelector hintEndsWith(String);
+ method @RequiresApi(26) public androidx.test.uiautomator.BySelector hintStartsWith(String);
+ method public androidx.test.uiautomator.BySelector longClickable(boolean);
+ method public androidx.test.uiautomator.BySelector maxDepth(int);
+ method public androidx.test.uiautomator.BySelector minDepth(int);
+ method public androidx.test.uiautomator.BySelector pkg(String);
+ method public androidx.test.uiautomator.BySelector pkg(java.util.regex.Pattern);
+ method public androidx.test.uiautomator.BySelector res(String);
+ method public androidx.test.uiautomator.BySelector res(String, String);
+ method public androidx.test.uiautomator.BySelector res(java.util.regex.Pattern);
+ method public androidx.test.uiautomator.BySelector scrollable(boolean);
+ method public androidx.test.uiautomator.BySelector selected(boolean);
+ method public androidx.test.uiautomator.BySelector text(String);
+ method public androidx.test.uiautomator.BySelector text(java.util.regex.Pattern);
+ method public androidx.test.uiautomator.BySelector textContains(String);
+ method public androidx.test.uiautomator.BySelector textEndsWith(String);
+ method public androidx.test.uiautomator.BySelector textStartsWith(String);
+ }
+
+ public interface Condition<T, U> {
+ method public U! apply(T!);
+ }
+
+ public final class Configurator {
+ method public long getActionAcknowledgmentTimeout();
+ method public static androidx.test.uiautomator.Configurator getInstance();
+ method public long getKeyInjectionDelay();
+ method public long getScrollAcknowledgmentTimeout();
+ method public int getToolType();
+ method public int getUiAutomationFlags();
+ method public long getWaitForIdleTimeout();
+ method public long getWaitForSelectorTimeout();
+ method public androidx.test.uiautomator.Configurator setActionAcknowledgmentTimeout(long);
+ method public androidx.test.uiautomator.Configurator setKeyInjectionDelay(long);
+ method public androidx.test.uiautomator.Configurator setScrollAcknowledgmentTimeout(long);
+ method public androidx.test.uiautomator.Configurator setToolType(int);
+ method public androidx.test.uiautomator.Configurator setUiAutomationFlags(int);
+ method public androidx.test.uiautomator.Configurator setWaitForIdleTimeout(long);
+ method public androidx.test.uiautomator.Configurator setWaitForSelectorTimeout(long);
+ }
+
+ public enum Direction {
+ method public static androidx.test.uiautomator.Direction reverse(androidx.test.uiautomator.Direction);
+ enum_constant public static final androidx.test.uiautomator.Direction DOWN;
+ enum_constant public static final androidx.test.uiautomator.Direction LEFT;
+ enum_constant public static final androidx.test.uiautomator.Direction RIGHT;
+ enum_constant public static final androidx.test.uiautomator.Direction UP;
+ }
+
+ public abstract class EventCondition<U> implements android.app.UiAutomation.AccessibilityEventFilter {
+ ctor public EventCondition();
+ method public abstract U! getResult();
+ }
+
+ public interface IAutomationSupport {
+ method public void sendStatus(int, android.os.Bundle);
+ }
+
+ public abstract class SearchCondition<U> implements androidx.test.uiautomator.Condition<androidx.test.uiautomator.Searchable,U> {
+ ctor public SearchCondition();
+ }
+
+ public class StaleObjectException extends java.lang.RuntimeException {
+ ctor public StaleObjectException();
+ }
+
+ @Deprecated public class UiAutomatorInstrumentationTestRunner extends android.test.InstrumentationTestRunner {
+ ctor @Deprecated public UiAutomatorInstrumentationTestRunner();
+ method @Deprecated protected android.test.AndroidTestRunner! getAndroidTestRunner();
+ method @Deprecated protected void initializeUiAutomatorTest(androidx.test.uiautomator.UiAutomatorTestCase!);
+ }
+
+ @Deprecated public class UiAutomatorTestCase extends android.test.InstrumentationTestCase {
+ ctor @Deprecated public UiAutomatorTestCase();
+ method @Deprecated public androidx.test.uiautomator.IAutomationSupport! getAutomationSupport();
+ method @Deprecated public android.os.Bundle! getParams();
+ method @Deprecated public androidx.test.uiautomator.UiDevice! getUiDevice();
+ method @Deprecated public void sleep(long);
+ }
+
+ public class UiCollection extends androidx.test.uiautomator.UiObject {
+ ctor public UiCollection(androidx.test.uiautomator.UiSelector);
+ method public androidx.test.uiautomator.UiObject getChildByDescription(androidx.test.uiautomator.UiSelector, String) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiObject getChildByInstance(androidx.test.uiautomator.UiSelector, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiObject getChildByText(androidx.test.uiautomator.UiSelector, String) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public int getChildCount(androidx.test.uiautomator.UiSelector);
+ }
+
+ public class UiDevice {
+ method public void clearLastTraversedText();
+ method public boolean click(int, int);
+ method public boolean drag(int, int, int, int, int);
+ method public void dumpWindowHierarchy(java.io.File) throws java.io.IOException;
+ method public void dumpWindowHierarchy(java.io.OutputStream) throws java.io.IOException;
+ method @Deprecated public void dumpWindowHierarchy(String);
+ method @Discouraged(message="Can be useful for simple commands, but lacks support for proper error handling, input data, or complex commands (quotes, pipes) that can be obtained from UiAutomation#executeShellCommandRwe or similar utilities.") @RequiresApi(21) public String executeShellCommand(String) throws java.io.IOException;
+ method public androidx.test.uiautomator.UiObject2! findObject(androidx.test.uiautomator.BySelector);
+ method public androidx.test.uiautomator.UiObject findObject(androidx.test.uiautomator.UiSelector);
+ method public java.util.List<androidx.test.uiautomator.UiObject2!> findObjects(androidx.test.uiautomator.BySelector);
+ method public void freezeRotation() throws android.os.RemoteException;
+ method @RequiresApi(30) public void freezeRotation(int);
+ method @Deprecated public String! getCurrentActivityName();
+ method public String! getCurrentPackageName();
+ method @Px public int getDisplayHeight();
+ method @Px public int getDisplayHeight(int);
+ method public int getDisplayRotation();
+ method public int getDisplayRotation(int);
+ method public android.graphics.Point getDisplaySizeDp();
+ method @Px public int getDisplayWidth();
+ method @Px public int getDisplayWidth(int);
+ method @Deprecated public static androidx.test.uiautomator.UiDevice getInstance();
+ method public static androidx.test.uiautomator.UiDevice getInstance(android.app.Instrumentation);
+ method public String! getLastTraversedText();
+ method public String! getLauncherPackageName();
+ method public String getProductName();
+ method public boolean hasAnyWatcherTriggered();
+ method public boolean hasObject(androidx.test.uiautomator.BySelector);
+ method public boolean hasWatcherTriggered(String?);
+ method public boolean isNaturalOrientation();
+ method public boolean isScreenOn() throws android.os.RemoteException;
+ method public boolean openNotification();
+ method public boolean openQuickSettings();
+ method public <U> U! performActionAndWait(Runnable, androidx.test.uiautomator.EventCondition<U!>, long);
+ method public boolean pressBack();
+ method public boolean pressDPadCenter();
+ method public boolean pressDPadDown();
+ method public boolean pressDPadLeft();
+ method public boolean pressDPadRight();
+ method public boolean pressDPadUp();
+ method public boolean pressDelete();
+ method public boolean pressEnter();
+ method public boolean pressHome();
+ method public boolean pressKeyCode(int);
+ method public boolean pressKeyCode(int, int);
+ method public boolean pressKeyCodes(int[]);
+ method public boolean pressKeyCodes(int[], int);
+ method public boolean pressMenu();
+ method public boolean pressRecentApps() throws android.os.RemoteException;
+ method public boolean pressSearch();
+ method public void registerWatcher(String?, androidx.test.uiautomator.UiWatcher?);
+ method public void removeWatcher(String?);
+ method public void resetWatcherTriggers();
+ method public void runWatchers();
+ method @Deprecated public void setCompressedLayoutHeirarchy(boolean);
+ method public void setCompressedLayoutHierarchy(boolean);
+ method public void setOrientationLandscape() throws android.os.RemoteException;
+ method @RequiresApi(30) public void setOrientationLandscape(int);
+ method public void setOrientationLeft() throws android.os.RemoteException;
+ method @RequiresApi(30) public void setOrientationLeft(int);
+ method public void setOrientationNatural() throws android.os.RemoteException;
+ method @RequiresApi(30) public void setOrientationNatural(int);
+ method public void setOrientationPortrait() throws android.os.RemoteException;
+ method @RequiresApi(30) public void setOrientationPortrait(int);
+ method public void setOrientationRight() throws android.os.RemoteException;
+ method @RequiresApi(30) public void setOrientationRight(int);
+ method public void sleep() throws android.os.RemoteException;
+ method public boolean swipe(android.graphics.Point![], int);
+ method public boolean swipe(int, int, int, int, int);
+ method public boolean takeScreenshot(java.io.File);
+ method public boolean takeScreenshot(java.io.File, float, int);
+ method public void unfreezeRotation() throws android.os.RemoteException;
+ method @RequiresApi(30) public void unfreezeRotation(int);
+ method public <U> U! wait(androidx.test.uiautomator.Condition<? super androidx.test.uiautomator.UiDevice,U!>, long);
+ method public <U> U! wait(androidx.test.uiautomator.SearchCondition<U!>, long);
+ method public void waitForIdle();
+ method public void waitForIdle(long);
+ method public boolean waitForWindowUpdate(String?, long);
+ method public void wakeUp() throws android.os.RemoteException;
+ }
+
+ public class UiObject {
+ ctor @Deprecated public UiObject(androidx.test.uiautomator.UiSelector!);
+ method public void clearTextField() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean click() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean clickAndWaitForNewWindow() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean clickAndWaitForNewWindow(long) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean clickBottomRight() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean clickTopLeft() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean dragTo(androidx.test.uiautomator.UiObject, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean dragTo(int, int, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean exists();
+ method protected android.view.accessibility.AccessibilityNodeInfo? findAccessibilityNodeInfo(long);
+ method public android.graphics.Rect getBounds() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiObject getChild(androidx.test.uiautomator.UiSelector) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public int getChildCount() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public String getClassName() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public String getContentDescription() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiObject getFromParent(androidx.test.uiautomator.UiSelector) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public String getPackageName() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public final androidx.test.uiautomator.UiSelector getSelector();
+ method public String getText() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public android.graphics.Rect getVisibleBounds() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isCheckable() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isChecked() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isClickable() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isEnabled() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isFocusable() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isFocused() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isLongClickable() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isScrollable() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isSelected() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean longClick() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean longClickBottomRight() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean longClickTopLeft() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean performMultiPointerGesture(android.view.MotionEvent.PointerCoords![]!...);
+ method public boolean performTwoPointerGesture(android.graphics.Point, android.graphics.Point, android.graphics.Point, android.graphics.Point, int);
+ method public boolean pinchIn(int, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean pinchOut(int, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean setText(String?) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean swipeDown(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean swipeLeft(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean swipeRight(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean swipeUp(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean waitForExists(long);
+ method public boolean waitUntilGone(long);
+ field protected static final int FINGER_TOUCH_HALF_WIDTH = 20; // 0x14
+ field protected static final int SWIPE_MARGIN_LIMIT = 5; // 0x5
+ field @Deprecated protected static final long WAIT_FOR_EVENT_TMEOUT = 3000L; // 0xbb8L
+ field protected static final long WAIT_FOR_SELECTOR_POLL = 1000L; // 0x3e8L
+ field @Deprecated protected static final long WAIT_FOR_SELECTOR_TIMEOUT = 10000L; // 0x2710L
+ field protected static final long WAIT_FOR_WINDOW_TMEOUT = 5500L; // 0x157cL
+ }
+
+ public class UiObject2 {
+ method public void clear();
+ method public void click();
+ method public void click(android.graphics.Point);
+ method public void click(android.graphics.Point, long);
+ method public void click(long);
+ method public <U> U! clickAndWait(android.graphics.Point, androidx.test.uiautomator.EventCondition<U!>, long);
+ method public <U> U! clickAndWait(androidx.test.uiautomator.EventCondition<U!>, long);
+ method public void drag(android.graphics.Point);
+ method public void drag(android.graphics.Point, int);
+ method public androidx.test.uiautomator.UiObject2! findObject(androidx.test.uiautomator.BySelector);
+ method public java.util.List<androidx.test.uiautomator.UiObject2!> findObjects(androidx.test.uiautomator.BySelector);
+ method public boolean fling(androidx.test.uiautomator.Direction);
+ method public boolean fling(androidx.test.uiautomator.Direction, int);
+ method public String! getApplicationPackage();
+ method public int getChildCount();
+ method public java.util.List<androidx.test.uiautomator.UiObject2!> getChildren();
+ method public String! getClassName();
+ method public String! getContentDescription();
+ method public int getDisplayId();
+ method @RequiresApi(24) public int getDrawingOrder();
+ method @RequiresApi(26) public String? getHint();
+ method public androidx.test.uiautomator.UiObject2! getParent();
+ method public String! getResourceName();
+ method public String! getText();
+ method public android.graphics.Rect getVisibleBounds();
+ method public android.graphics.Point getVisibleCenter();
+ method public boolean hasObject(androidx.test.uiautomator.BySelector);
+ method public boolean isCheckable();
+ method public boolean isChecked();
+ method public boolean isClickable();
+ method public boolean isEnabled();
+ method public boolean isFocusable();
+ method public boolean isFocused();
+ method public boolean isLongClickable();
+ method public boolean isScrollable();
+ method public boolean isSelected();
+ method public void longClick();
+ method public void pinchClose(float);
+ method public void pinchClose(float, int);
+ method public void pinchOpen(float);
+ method public void pinchOpen(float, int);
+ method public void recycle();
+ method public boolean scroll(androidx.test.uiautomator.Direction, float);
+ method public boolean scroll(androidx.test.uiautomator.Direction, float, int);
+ method public <U> U! scrollUntil(androidx.test.uiautomator.Direction, androidx.test.uiautomator.Condition<? super androidx.test.uiautomator.UiObject2,U!>);
+ method public <U> U! scrollUntil(androidx.test.uiautomator.Direction, androidx.test.uiautomator.EventCondition<U!>);
+ method public void setGestureMargin(int);
+ method public void setGestureMarginPercent(@FloatRange(from=0.0f, to=0.5f) float);
+ method public void setGestureMarginPercent(@FloatRange(from=0.0f, to=1.0f) float, @FloatRange(from=0.0f, to=1.0f) float, @FloatRange(from=0.0f, to=1.0f) float, @FloatRange(from=0.0f, to=1.0f) float);
+ method public void setGestureMargins(int, int, int, int);
+ method public void setText(String?);
+ method public void swipe(androidx.test.uiautomator.Direction, float);
+ method public void swipe(androidx.test.uiautomator.Direction, float, int);
+ method public <U> U! wait(androidx.test.uiautomator.Condition<? super androidx.test.uiautomator.UiObject2,U!>, long);
+ method public <U> U! wait(androidx.test.uiautomator.SearchCondition<U!>, long);
+ method public <U> U! wait(androidx.test.uiautomator.UiObject2Condition<U!>, long);
+ }
+
+ public abstract class UiObject2Condition<U> implements androidx.test.uiautomator.Condition<androidx.test.uiautomator.UiObject2,U> {
+ ctor public UiObject2Condition();
+ }
+
+ public class UiObjectNotFoundException extends java.lang.Exception {
+ ctor public UiObjectNotFoundException(String);
+ ctor public UiObjectNotFoundException(String, Throwable?);
+ ctor public UiObjectNotFoundException(Throwable?);
+ }
+
+ public class UiScrollable extends androidx.test.uiautomator.UiCollection {
+ ctor public UiScrollable(androidx.test.uiautomator.UiSelector);
+ method protected boolean exists(androidx.test.uiautomator.UiSelector);
+ method public boolean flingBackward() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean flingForward() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean flingToBeginning(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean flingToEnd(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiObject getChildByDescription(androidx.test.uiautomator.UiSelector, String, boolean) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiObject getChildByText(androidx.test.uiautomator.UiSelector, String, boolean) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public int getMaxSearchSwipes();
+ method public double getSwipeDeadZonePercentage();
+ method public boolean scrollBackward() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollBackward(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollDescriptionIntoView(String) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollForward() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollForward(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollIntoView(androidx.test.uiautomator.UiObject) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollIntoView(androidx.test.uiautomator.UiSelector) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollTextIntoView(String) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollToBeginning(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollToBeginning(int, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollToEnd(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollToEnd(int, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiScrollable setAsHorizontalList();
+ method public androidx.test.uiautomator.UiScrollable setAsVerticalList();
+ method public androidx.test.uiautomator.UiScrollable setMaxSearchSwipes(int);
+ method public androidx.test.uiautomator.UiScrollable setSwipeDeadZonePercentage(double);
+ }
+
+ public class UiSelector {
+ ctor public UiSelector();
+ method public androidx.test.uiautomator.UiSelector checkable(boolean);
+ method public androidx.test.uiautomator.UiSelector checked(boolean);
+ method public androidx.test.uiautomator.UiSelector childSelector(androidx.test.uiautomator.UiSelector);
+ method public <T> androidx.test.uiautomator.UiSelector className(Class<T!>);
+ method public androidx.test.uiautomator.UiSelector className(String);
+ method public androidx.test.uiautomator.UiSelector classNameMatches(String);
+ method public androidx.test.uiautomator.UiSelector clickable(boolean);
+ method protected androidx.test.uiautomator.UiSelector cloneSelector();
+ method public androidx.test.uiautomator.UiSelector description(String);
+ method public androidx.test.uiautomator.UiSelector descriptionContains(String);
+ method public androidx.test.uiautomator.UiSelector descriptionMatches(String);
+ method public androidx.test.uiautomator.UiSelector descriptionStartsWith(String);
+ method public androidx.test.uiautomator.UiSelector enabled(boolean);
+ method public androidx.test.uiautomator.UiSelector focusable(boolean);
+ method public androidx.test.uiautomator.UiSelector focused(boolean);
+ method public androidx.test.uiautomator.UiSelector fromParent(androidx.test.uiautomator.UiSelector);
+ method public androidx.test.uiautomator.UiSelector index(int);
+ method public androidx.test.uiautomator.UiSelector instance(int);
+ method public androidx.test.uiautomator.UiSelector longClickable(boolean);
+ method public androidx.test.uiautomator.UiSelector packageName(String);
+ method public androidx.test.uiautomator.UiSelector packageNameMatches(String);
+ method public androidx.test.uiautomator.UiSelector resourceId(String);
+ method public androidx.test.uiautomator.UiSelector resourceIdMatches(String);
+ method public androidx.test.uiautomator.UiSelector scrollable(boolean);
+ method public androidx.test.uiautomator.UiSelector selected(boolean);
+ method public androidx.test.uiautomator.UiSelector text(String);
+ method public androidx.test.uiautomator.UiSelector textContains(String);
+ method public androidx.test.uiautomator.UiSelector textMatches(String);
+ method public androidx.test.uiautomator.UiSelector textStartsWith(String);
+ }
+
+ public interface UiWatcher {
+ method public boolean checkForCondition();
+ }
+
+ public class Until {
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> checkable(boolean);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> checked(boolean);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> clickable(boolean);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> descContains(String);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> descEndsWith(String);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> descEquals(String);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> descMatches(String);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> descMatches(java.util.regex.Pattern);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> descStartsWith(String);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> enabled(boolean);
+ method public static androidx.test.uiautomator.SearchCondition<androidx.test.uiautomator.UiObject2!> findObject(androidx.test.uiautomator.BySelector);
+ method public static androidx.test.uiautomator.SearchCondition<java.util.List<androidx.test.uiautomator.UiObject2!>!> findObjects(androidx.test.uiautomator.BySelector);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> focusable(boolean);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> focused(boolean);
+ method public static androidx.test.uiautomator.SearchCondition<java.lang.Boolean!> gone(androidx.test.uiautomator.BySelector);
+ method public static androidx.test.uiautomator.SearchCondition<java.lang.Boolean!> hasObject(androidx.test.uiautomator.BySelector);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> longClickable(boolean);
+ method public static androidx.test.uiautomator.EventCondition<java.lang.Boolean!> newWindow();
+ method public static androidx.test.uiautomator.EventCondition<java.lang.Boolean!> scrollFinished(androidx.test.uiautomator.Direction);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> scrollable(boolean);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> selected(boolean);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> textContains(String);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> textEndsWith(String);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> textEquals(String);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> textMatches(String);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> textMatches(java.util.regex.Pattern);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> textNotEquals(String);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> textStartsWith(String);
+ }
+
+}
+
diff --git a/test/uiautomator/uiautomator/api/res-2.3.0-beta01.txt b/test/uiautomator/uiautomator/api/res-2.3.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/uiautomator/uiautomator/api/res-2.3.0-beta01.txt
diff --git a/test/uiautomator/uiautomator/api/restricted_2.3.0-beta01.txt b/test/uiautomator/uiautomator/api/restricted_2.3.0-beta01.txt
new file mode 100644
index 0000000..bfaecd4
--- /dev/null
+++ b/test/uiautomator/uiautomator/api/restricted_2.3.0-beta01.txt
@@ -0,0 +1,467 @@
+// Signature format: 4.0
+package androidx.test.uiautomator {
+
+ public class By {
+ method public static androidx.test.uiautomator.BySelector checkable(boolean);
+ method public static androidx.test.uiautomator.BySelector checked(boolean);
+ method public static androidx.test.uiautomator.BySelector clazz(Class);
+ method public static androidx.test.uiautomator.BySelector clazz(String);
+ method public static androidx.test.uiautomator.BySelector clazz(String, String);
+ method public static androidx.test.uiautomator.BySelector clazz(java.util.regex.Pattern);
+ method public static androidx.test.uiautomator.BySelector clickable(boolean);
+ method public static androidx.test.uiautomator.BySelector copy(androidx.test.uiautomator.BySelector);
+ method public static androidx.test.uiautomator.BySelector depth(int);
+ method public static androidx.test.uiautomator.BySelector desc(String);
+ method public static androidx.test.uiautomator.BySelector desc(java.util.regex.Pattern);
+ method public static androidx.test.uiautomator.BySelector descContains(String);
+ method public static androidx.test.uiautomator.BySelector descEndsWith(String);
+ method public static androidx.test.uiautomator.BySelector descStartsWith(String);
+ method @RequiresApi(30) public static androidx.test.uiautomator.BySelector displayId(int);
+ method public static androidx.test.uiautomator.BySelector enabled(boolean);
+ method public static androidx.test.uiautomator.BySelector focusable(boolean);
+ method public static androidx.test.uiautomator.BySelector focused(boolean);
+ method public static androidx.test.uiautomator.BySelector hasAncestor(androidx.test.uiautomator.BySelector);
+ method public static androidx.test.uiautomator.BySelector hasAncestor(androidx.test.uiautomator.BySelector, @IntRange(from=1) int);
+ method public static androidx.test.uiautomator.BySelector hasChild(androidx.test.uiautomator.BySelector);
+ method public static androidx.test.uiautomator.BySelector hasDescendant(androidx.test.uiautomator.BySelector);
+ method public static androidx.test.uiautomator.BySelector hasDescendant(androidx.test.uiautomator.BySelector, int);
+ method public static androidx.test.uiautomator.BySelector hasParent(androidx.test.uiautomator.BySelector);
+ method @RequiresApi(26) public static androidx.test.uiautomator.BySelector hint(String);
+ method @RequiresApi(26) public static androidx.test.uiautomator.BySelector hint(java.util.regex.Pattern);
+ method @RequiresApi(26) public static androidx.test.uiautomator.BySelector hintContains(String);
+ method @RequiresApi(26) public static androidx.test.uiautomator.BySelector hintEndsWith(String);
+ method @RequiresApi(26) public static androidx.test.uiautomator.BySelector hintStartsWith(String);
+ method public static androidx.test.uiautomator.BySelector longClickable(boolean);
+ method public static androidx.test.uiautomator.BySelector pkg(String);
+ method public static androidx.test.uiautomator.BySelector pkg(java.util.regex.Pattern);
+ method public static androidx.test.uiautomator.BySelector res(String);
+ method public static androidx.test.uiautomator.BySelector res(String, String);
+ method public static androidx.test.uiautomator.BySelector res(java.util.regex.Pattern);
+ method public static androidx.test.uiautomator.BySelector scrollable(boolean);
+ method public static androidx.test.uiautomator.BySelector selected(boolean);
+ method public static androidx.test.uiautomator.BySelector text(String);
+ method public static androidx.test.uiautomator.BySelector text(java.util.regex.Pattern);
+ method public static androidx.test.uiautomator.BySelector textContains(String);
+ method public static androidx.test.uiautomator.BySelector textEndsWith(String);
+ method public static androidx.test.uiautomator.BySelector textStartsWith(String);
+ }
+
+ public class BySelector {
+ method public androidx.test.uiautomator.BySelector checkable(boolean);
+ method public androidx.test.uiautomator.BySelector checked(boolean);
+ method public androidx.test.uiautomator.BySelector clazz(Class);
+ method public androidx.test.uiautomator.BySelector clazz(String);
+ method public androidx.test.uiautomator.BySelector clazz(String, String);
+ method public androidx.test.uiautomator.BySelector clazz(java.util.regex.Pattern);
+ method public androidx.test.uiautomator.BySelector clickable(boolean);
+ method public androidx.test.uiautomator.BySelector depth(int);
+ method public androidx.test.uiautomator.BySelector depth(int, int);
+ method public androidx.test.uiautomator.BySelector desc(String);
+ method public androidx.test.uiautomator.BySelector desc(java.util.regex.Pattern);
+ method public androidx.test.uiautomator.BySelector descContains(String);
+ method public androidx.test.uiautomator.BySelector descEndsWith(String);
+ method public androidx.test.uiautomator.BySelector descStartsWith(String);
+ method @RequiresApi(30) public androidx.test.uiautomator.BySelector displayId(int);
+ method public androidx.test.uiautomator.BySelector enabled(boolean);
+ method public androidx.test.uiautomator.BySelector focusable(boolean);
+ method public androidx.test.uiautomator.BySelector focused(boolean);
+ method public androidx.test.uiautomator.BySelector hasAncestor(androidx.test.uiautomator.BySelector);
+ method public androidx.test.uiautomator.BySelector hasAncestor(androidx.test.uiautomator.BySelector, @IntRange(from=1) int);
+ method public androidx.test.uiautomator.BySelector hasChild(androidx.test.uiautomator.BySelector);
+ method public androidx.test.uiautomator.BySelector hasDescendant(androidx.test.uiautomator.BySelector);
+ method public androidx.test.uiautomator.BySelector hasDescendant(androidx.test.uiautomator.BySelector, int);
+ method public androidx.test.uiautomator.BySelector hasParent(androidx.test.uiautomator.BySelector);
+ method @RequiresApi(26) public androidx.test.uiautomator.BySelector hint(String);
+ method @RequiresApi(26) public androidx.test.uiautomator.BySelector hint(java.util.regex.Pattern);
+ method @RequiresApi(26) public androidx.test.uiautomator.BySelector hintContains(String);
+ method @RequiresApi(26) public androidx.test.uiautomator.BySelector hintEndsWith(String);
+ method @RequiresApi(26) public androidx.test.uiautomator.BySelector hintStartsWith(String);
+ method public androidx.test.uiautomator.BySelector longClickable(boolean);
+ method public androidx.test.uiautomator.BySelector maxDepth(int);
+ method public androidx.test.uiautomator.BySelector minDepth(int);
+ method public androidx.test.uiautomator.BySelector pkg(String);
+ method public androidx.test.uiautomator.BySelector pkg(java.util.regex.Pattern);
+ method public androidx.test.uiautomator.BySelector res(String);
+ method public androidx.test.uiautomator.BySelector res(String, String);
+ method public androidx.test.uiautomator.BySelector res(java.util.regex.Pattern);
+ method public androidx.test.uiautomator.BySelector scrollable(boolean);
+ method public androidx.test.uiautomator.BySelector selected(boolean);
+ method public androidx.test.uiautomator.BySelector text(String);
+ method public androidx.test.uiautomator.BySelector text(java.util.regex.Pattern);
+ method public androidx.test.uiautomator.BySelector textContains(String);
+ method public androidx.test.uiautomator.BySelector textEndsWith(String);
+ method public androidx.test.uiautomator.BySelector textStartsWith(String);
+ }
+
+ public interface Condition<T, U> {
+ method public U! apply(T!);
+ }
+
+ public final class Configurator {
+ method public long getActionAcknowledgmentTimeout();
+ method public static androidx.test.uiautomator.Configurator getInstance();
+ method public long getKeyInjectionDelay();
+ method public long getScrollAcknowledgmentTimeout();
+ method public int getToolType();
+ method public int getUiAutomationFlags();
+ method public long getWaitForIdleTimeout();
+ method public long getWaitForSelectorTimeout();
+ method public androidx.test.uiautomator.Configurator setActionAcknowledgmentTimeout(long);
+ method public androidx.test.uiautomator.Configurator setKeyInjectionDelay(long);
+ method public androidx.test.uiautomator.Configurator setScrollAcknowledgmentTimeout(long);
+ method public androidx.test.uiautomator.Configurator setToolType(int);
+ method public androidx.test.uiautomator.Configurator setUiAutomationFlags(int);
+ method public androidx.test.uiautomator.Configurator setWaitForIdleTimeout(long);
+ method public androidx.test.uiautomator.Configurator setWaitForSelectorTimeout(long);
+ }
+
+ public enum Direction {
+ method public static androidx.test.uiautomator.Direction reverse(androidx.test.uiautomator.Direction);
+ enum_constant public static final androidx.test.uiautomator.Direction DOWN;
+ enum_constant public static final androidx.test.uiautomator.Direction LEFT;
+ enum_constant public static final androidx.test.uiautomator.Direction RIGHT;
+ enum_constant public static final androidx.test.uiautomator.Direction UP;
+ }
+
+ public abstract class EventCondition<U> implements android.app.UiAutomation.AccessibilityEventFilter {
+ ctor public EventCondition();
+ method public abstract U! getResult();
+ }
+
+ public interface IAutomationSupport {
+ method public void sendStatus(int, android.os.Bundle);
+ }
+
+ public abstract class SearchCondition<U> implements androidx.test.uiautomator.Condition<androidx.test.uiautomator.Searchable,U> {
+ ctor public SearchCondition();
+ }
+
+ public class StaleObjectException extends java.lang.RuntimeException {
+ ctor public StaleObjectException();
+ }
+
+ @Deprecated public class UiAutomatorInstrumentationTestRunner extends android.test.InstrumentationTestRunner {
+ ctor @Deprecated public UiAutomatorInstrumentationTestRunner();
+ method @Deprecated protected android.test.AndroidTestRunner! getAndroidTestRunner();
+ method @Deprecated protected void initializeUiAutomatorTest(androidx.test.uiautomator.UiAutomatorTestCase!);
+ }
+
+ @Deprecated public class UiAutomatorTestCase extends android.test.InstrumentationTestCase {
+ ctor @Deprecated public UiAutomatorTestCase();
+ method @Deprecated public androidx.test.uiautomator.IAutomationSupport! getAutomationSupport();
+ method @Deprecated public android.os.Bundle! getParams();
+ method @Deprecated public androidx.test.uiautomator.UiDevice! getUiDevice();
+ method @Deprecated public void sleep(long);
+ }
+
+ public class UiCollection extends androidx.test.uiautomator.UiObject {
+ ctor public UiCollection(androidx.test.uiautomator.UiSelector);
+ method public androidx.test.uiautomator.UiObject getChildByDescription(androidx.test.uiautomator.UiSelector, String) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiObject getChildByInstance(androidx.test.uiautomator.UiSelector, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiObject getChildByText(androidx.test.uiautomator.UiSelector, String) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public int getChildCount(androidx.test.uiautomator.UiSelector);
+ }
+
+ public class UiDevice {
+ method public void clearLastTraversedText();
+ method public boolean click(int, int);
+ method public boolean drag(int, int, int, int, int);
+ method public void dumpWindowHierarchy(java.io.File) throws java.io.IOException;
+ method public void dumpWindowHierarchy(java.io.OutputStream) throws java.io.IOException;
+ method @Deprecated public void dumpWindowHierarchy(String);
+ method @Discouraged(message="Can be useful for simple commands, but lacks support for proper error handling, input data, or complex commands (quotes, pipes) that can be obtained from UiAutomation#executeShellCommandRwe or similar utilities.") @RequiresApi(21) public String executeShellCommand(String) throws java.io.IOException;
+ method public androidx.test.uiautomator.UiObject2! findObject(androidx.test.uiautomator.BySelector);
+ method public androidx.test.uiautomator.UiObject findObject(androidx.test.uiautomator.UiSelector);
+ method public java.util.List<androidx.test.uiautomator.UiObject2!> findObjects(androidx.test.uiautomator.BySelector);
+ method public void freezeRotation() throws android.os.RemoteException;
+ method @RequiresApi(30) public void freezeRotation(int);
+ method @Deprecated public String! getCurrentActivityName();
+ method public String! getCurrentPackageName();
+ method @Px public int getDisplayHeight();
+ method @Px public int getDisplayHeight(int);
+ method public int getDisplayRotation();
+ method public int getDisplayRotation(int);
+ method public android.graphics.Point getDisplaySizeDp();
+ method @Px public int getDisplayWidth();
+ method @Px public int getDisplayWidth(int);
+ method @Deprecated public static androidx.test.uiautomator.UiDevice getInstance();
+ method public static androidx.test.uiautomator.UiDevice getInstance(android.app.Instrumentation);
+ method public String! getLastTraversedText();
+ method public String! getLauncherPackageName();
+ method public String getProductName();
+ method public boolean hasAnyWatcherTriggered();
+ method public boolean hasObject(androidx.test.uiautomator.BySelector);
+ method public boolean hasWatcherTriggered(String?);
+ method public boolean isNaturalOrientation();
+ method public boolean isScreenOn() throws android.os.RemoteException;
+ method public boolean openNotification();
+ method public boolean openQuickSettings();
+ method public <U> U! performActionAndWait(Runnable, androidx.test.uiautomator.EventCondition<U!>, long);
+ method public boolean pressBack();
+ method public boolean pressDPadCenter();
+ method public boolean pressDPadDown();
+ method public boolean pressDPadLeft();
+ method public boolean pressDPadRight();
+ method public boolean pressDPadUp();
+ method public boolean pressDelete();
+ method public boolean pressEnter();
+ method public boolean pressHome();
+ method public boolean pressKeyCode(int);
+ method public boolean pressKeyCode(int, int);
+ method public boolean pressKeyCodes(int[]);
+ method public boolean pressKeyCodes(int[], int);
+ method public boolean pressMenu();
+ method public boolean pressRecentApps() throws android.os.RemoteException;
+ method public boolean pressSearch();
+ method public void registerWatcher(String?, androidx.test.uiautomator.UiWatcher?);
+ method public void removeWatcher(String?);
+ method public void resetWatcherTriggers();
+ method public void runWatchers();
+ method @Deprecated public void setCompressedLayoutHeirarchy(boolean);
+ method public void setCompressedLayoutHierarchy(boolean);
+ method public void setOrientationLandscape() throws android.os.RemoteException;
+ method @RequiresApi(30) public void setOrientationLandscape(int);
+ method public void setOrientationLeft() throws android.os.RemoteException;
+ method @RequiresApi(30) public void setOrientationLeft(int);
+ method public void setOrientationNatural() throws android.os.RemoteException;
+ method @RequiresApi(30) public void setOrientationNatural(int);
+ method public void setOrientationPortrait() throws android.os.RemoteException;
+ method @RequiresApi(30) public void setOrientationPortrait(int);
+ method public void setOrientationRight() throws android.os.RemoteException;
+ method @RequiresApi(30) public void setOrientationRight(int);
+ method public void sleep() throws android.os.RemoteException;
+ method public boolean swipe(android.graphics.Point![], int);
+ method public boolean swipe(int, int, int, int, int);
+ method public boolean takeScreenshot(java.io.File);
+ method public boolean takeScreenshot(java.io.File, float, int);
+ method public void unfreezeRotation() throws android.os.RemoteException;
+ method @RequiresApi(30) public void unfreezeRotation(int);
+ method public <U> U! wait(androidx.test.uiautomator.Condition<? super androidx.test.uiautomator.UiDevice,U!>, long);
+ method public <U> U! wait(androidx.test.uiautomator.SearchCondition<U!>, long);
+ method public void waitForIdle();
+ method public void waitForIdle(long);
+ method public boolean waitForWindowUpdate(String?, long);
+ method public void wakeUp() throws android.os.RemoteException;
+ }
+
+ public class UiObject {
+ ctor @Deprecated public UiObject(androidx.test.uiautomator.UiSelector!);
+ method public void clearTextField() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean click() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean clickAndWaitForNewWindow() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean clickAndWaitForNewWindow(long) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean clickBottomRight() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean clickTopLeft() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean dragTo(androidx.test.uiautomator.UiObject, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean dragTo(int, int, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean exists();
+ method protected android.view.accessibility.AccessibilityNodeInfo? findAccessibilityNodeInfo(long);
+ method public android.graphics.Rect getBounds() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiObject getChild(androidx.test.uiautomator.UiSelector) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public int getChildCount() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public String getClassName() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public String getContentDescription() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiObject getFromParent(androidx.test.uiautomator.UiSelector) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public String getPackageName() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public final androidx.test.uiautomator.UiSelector getSelector();
+ method public String getText() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public android.graphics.Rect getVisibleBounds() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isCheckable() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isChecked() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isClickable() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isEnabled() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isFocusable() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isFocused() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isLongClickable() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isScrollable() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean isSelected() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean longClick() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean longClickBottomRight() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean longClickTopLeft() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean performMultiPointerGesture(android.view.MotionEvent.PointerCoords![]!...);
+ method public boolean performTwoPointerGesture(android.graphics.Point, android.graphics.Point, android.graphics.Point, android.graphics.Point, int);
+ method public boolean pinchIn(int, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean pinchOut(int, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean setText(String?) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean swipeDown(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean swipeLeft(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean swipeRight(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean swipeUp(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean waitForExists(long);
+ method public boolean waitUntilGone(long);
+ field protected static final int FINGER_TOUCH_HALF_WIDTH = 20; // 0x14
+ field protected static final int SWIPE_MARGIN_LIMIT = 5; // 0x5
+ field @Deprecated protected static final long WAIT_FOR_EVENT_TMEOUT = 3000L; // 0xbb8L
+ field protected static final long WAIT_FOR_SELECTOR_POLL = 1000L; // 0x3e8L
+ field @Deprecated protected static final long WAIT_FOR_SELECTOR_TIMEOUT = 10000L; // 0x2710L
+ field protected static final long WAIT_FOR_WINDOW_TMEOUT = 5500L; // 0x157cL
+ }
+
+ public class UiObject2 {
+ method public void clear();
+ method public void click();
+ method public void click(android.graphics.Point);
+ method public void click(android.graphics.Point, long);
+ method public void click(long);
+ method public <U> U! clickAndWait(android.graphics.Point, androidx.test.uiautomator.EventCondition<U!>, long);
+ method public <U> U! clickAndWait(androidx.test.uiautomator.EventCondition<U!>, long);
+ method public void drag(android.graphics.Point);
+ method public void drag(android.graphics.Point, int);
+ method public androidx.test.uiautomator.UiObject2! findObject(androidx.test.uiautomator.BySelector);
+ method public java.util.List<androidx.test.uiautomator.UiObject2!> findObjects(androidx.test.uiautomator.BySelector);
+ method public boolean fling(androidx.test.uiautomator.Direction);
+ method public boolean fling(androidx.test.uiautomator.Direction, int);
+ method public String! getApplicationPackage();
+ method public int getChildCount();
+ method public java.util.List<androidx.test.uiautomator.UiObject2!> getChildren();
+ method public String! getClassName();
+ method public String! getContentDescription();
+ method public int getDisplayId();
+ method @RequiresApi(24) public int getDrawingOrder();
+ method @RequiresApi(26) public String? getHint();
+ method public androidx.test.uiautomator.UiObject2! getParent();
+ method public String! getResourceName();
+ method public String! getText();
+ method public android.graphics.Rect getVisibleBounds();
+ method public android.graphics.Point getVisibleCenter();
+ method public boolean hasObject(androidx.test.uiautomator.BySelector);
+ method public boolean isCheckable();
+ method public boolean isChecked();
+ method public boolean isClickable();
+ method public boolean isEnabled();
+ method public boolean isFocusable();
+ method public boolean isFocused();
+ method public boolean isLongClickable();
+ method public boolean isScrollable();
+ method public boolean isSelected();
+ method public void longClick();
+ method public void pinchClose(float);
+ method public void pinchClose(float, int);
+ method public void pinchOpen(float);
+ method public void pinchOpen(float, int);
+ method public void recycle();
+ method public boolean scroll(androidx.test.uiautomator.Direction, float);
+ method public boolean scroll(androidx.test.uiautomator.Direction, float, int);
+ method public <U> U! scrollUntil(androidx.test.uiautomator.Direction, androidx.test.uiautomator.Condition<? super androidx.test.uiautomator.UiObject2,U!>);
+ method public <U> U! scrollUntil(androidx.test.uiautomator.Direction, androidx.test.uiautomator.EventCondition<U!>);
+ method public void setGestureMargin(int);
+ method public void setGestureMarginPercent(@FloatRange(from=0.0f, to=0.5f) float);
+ method public void setGestureMarginPercent(@FloatRange(from=0.0f, to=1.0f) float, @FloatRange(from=0.0f, to=1.0f) float, @FloatRange(from=0.0f, to=1.0f) float, @FloatRange(from=0.0f, to=1.0f) float);
+ method public void setGestureMargins(int, int, int, int);
+ method public void setText(String?);
+ method public void swipe(androidx.test.uiautomator.Direction, float);
+ method public void swipe(androidx.test.uiautomator.Direction, float, int);
+ method public <U> U! wait(androidx.test.uiautomator.Condition<? super androidx.test.uiautomator.UiObject2,U!>, long);
+ method public <U> U! wait(androidx.test.uiautomator.SearchCondition<U!>, long);
+ method public <U> U! wait(androidx.test.uiautomator.UiObject2Condition<U!>, long);
+ }
+
+ public abstract class UiObject2Condition<U> implements androidx.test.uiautomator.Condition<androidx.test.uiautomator.UiObject2,U> {
+ ctor public UiObject2Condition();
+ }
+
+ public class UiObjectNotFoundException extends java.lang.Exception {
+ ctor public UiObjectNotFoundException(String);
+ ctor public UiObjectNotFoundException(String, Throwable?);
+ ctor public UiObjectNotFoundException(Throwable?);
+ }
+
+ public class UiScrollable extends androidx.test.uiautomator.UiCollection {
+ ctor public UiScrollable(androidx.test.uiautomator.UiSelector);
+ method protected boolean exists(androidx.test.uiautomator.UiSelector);
+ method public boolean flingBackward() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean flingForward() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean flingToBeginning(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean flingToEnd(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiObject getChildByDescription(androidx.test.uiautomator.UiSelector, String, boolean) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiObject getChildByText(androidx.test.uiautomator.UiSelector, String, boolean) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public int getMaxSearchSwipes();
+ method public double getSwipeDeadZonePercentage();
+ method public boolean scrollBackward() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollBackward(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollDescriptionIntoView(String) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollForward() throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollForward(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollIntoView(androidx.test.uiautomator.UiObject) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollIntoView(androidx.test.uiautomator.UiSelector) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollTextIntoView(String) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollToBeginning(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollToBeginning(int, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollToEnd(int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public boolean scrollToEnd(int, int) throws androidx.test.uiautomator.UiObjectNotFoundException;
+ method public androidx.test.uiautomator.UiScrollable setAsHorizontalList();
+ method public androidx.test.uiautomator.UiScrollable setAsVerticalList();
+ method public androidx.test.uiautomator.UiScrollable setMaxSearchSwipes(int);
+ method public androidx.test.uiautomator.UiScrollable setSwipeDeadZonePercentage(double);
+ }
+
+ public class UiSelector {
+ ctor public UiSelector();
+ method public androidx.test.uiautomator.UiSelector checkable(boolean);
+ method public androidx.test.uiautomator.UiSelector checked(boolean);
+ method public androidx.test.uiautomator.UiSelector childSelector(androidx.test.uiautomator.UiSelector);
+ method public <T> androidx.test.uiautomator.UiSelector className(Class<T!>);
+ method public androidx.test.uiautomator.UiSelector className(String);
+ method public androidx.test.uiautomator.UiSelector classNameMatches(String);
+ method public androidx.test.uiautomator.UiSelector clickable(boolean);
+ method protected androidx.test.uiautomator.UiSelector cloneSelector();
+ method public androidx.test.uiautomator.UiSelector description(String);
+ method public androidx.test.uiautomator.UiSelector descriptionContains(String);
+ method public androidx.test.uiautomator.UiSelector descriptionMatches(String);
+ method public androidx.test.uiautomator.UiSelector descriptionStartsWith(String);
+ method public androidx.test.uiautomator.UiSelector enabled(boolean);
+ method public androidx.test.uiautomator.UiSelector focusable(boolean);
+ method public androidx.test.uiautomator.UiSelector focused(boolean);
+ method public androidx.test.uiautomator.UiSelector fromParent(androidx.test.uiautomator.UiSelector);
+ method public androidx.test.uiautomator.UiSelector index(int);
+ method public androidx.test.uiautomator.UiSelector instance(int);
+ method public androidx.test.uiautomator.UiSelector longClickable(boolean);
+ method public androidx.test.uiautomator.UiSelector packageName(String);
+ method public androidx.test.uiautomator.UiSelector packageNameMatches(String);
+ method public androidx.test.uiautomator.UiSelector resourceId(String);
+ method public androidx.test.uiautomator.UiSelector resourceIdMatches(String);
+ method public androidx.test.uiautomator.UiSelector scrollable(boolean);
+ method public androidx.test.uiautomator.UiSelector selected(boolean);
+ method public androidx.test.uiautomator.UiSelector text(String);
+ method public androidx.test.uiautomator.UiSelector textContains(String);
+ method public androidx.test.uiautomator.UiSelector textMatches(String);
+ method public androidx.test.uiautomator.UiSelector textStartsWith(String);
+ }
+
+ public interface UiWatcher {
+ method public boolean checkForCondition();
+ }
+
+ public class Until {
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> checkable(boolean);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> checked(boolean);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> clickable(boolean);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> descContains(String);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> descEndsWith(String);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> descEquals(String);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> descMatches(String);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> descMatches(java.util.regex.Pattern);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> descStartsWith(String);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> enabled(boolean);
+ method public static androidx.test.uiautomator.SearchCondition<androidx.test.uiautomator.UiObject2!> findObject(androidx.test.uiautomator.BySelector);
+ method public static androidx.test.uiautomator.SearchCondition<java.util.List<androidx.test.uiautomator.UiObject2!>!> findObjects(androidx.test.uiautomator.BySelector);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> focusable(boolean);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> focused(boolean);
+ method public static androidx.test.uiautomator.SearchCondition<java.lang.Boolean!> gone(androidx.test.uiautomator.BySelector);
+ method public static androidx.test.uiautomator.SearchCondition<java.lang.Boolean!> hasObject(androidx.test.uiautomator.BySelector);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> longClickable(boolean);
+ method public static androidx.test.uiautomator.EventCondition<java.lang.Boolean!> newWindow();
+ method public static androidx.test.uiautomator.EventCondition<java.lang.Boolean!> scrollFinished(androidx.test.uiautomator.Direction);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> scrollable(boolean);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> selected(boolean);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> textContains(String);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> textEndsWith(String);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> textEquals(String);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> textMatches(String);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> textMatches(java.util.regex.Pattern);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> textNotEquals(String);
+ method public static androidx.test.uiautomator.UiObject2Condition<java.lang.Boolean!> textStartsWith(String);
+ }
+
+}
+
diff --git a/testutils/testutils-ktx/src/jvmMain/kotlin/androidx/testutils/VerifyWithPolling.kt b/testutils/testutils-ktx/src/jvmMain/kotlin/androidx/testutils/VerifyWithPolling.kt
deleted file mode 100644
index 52beb96..0000000
--- a/testutils/testutils-ktx/src/jvmMain/kotlin/androidx/testutils/VerifyWithPolling.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.testutils
-
-import java.lang.SuppressWarnings
-import org.junit.Assert
-
-@SuppressWarnings("BanThreadSleep")
-fun verifyWithPolling(
- message: String,
- periodMs: Long,
- timeoutMs: Long,
- tryBlock: () -> Boolean
-): Long {
- var totalDurationMs = 0L
- while (!tryBlock()) {
- Thread.sleep(periodMs)
-
- totalDurationMs += periodMs
- if (totalDurationMs > timeoutMs) {
- Assert.fail(message)
- }
- }
- return totalDurationMs
-}
diff --git a/testutils/testutils-runtime/src/androidTest/java/androidx/testutils/LocaleTestUtilsTest.kt b/testutils/testutils-runtime/src/androidTest/java/androidx/testutils/LocaleTestUtilsTest.kt
index 5dbff64..7836624 100644
--- a/testutils/testutils-runtime/src/androidTest/java/androidx/testutils/LocaleTestUtilsTest.kt
+++ b/testutils/testutils-runtime/src/androidTest/java/androidx/testutils/LocaleTestUtilsTest.kt
@@ -18,7 +18,6 @@
import android.content.Context
import android.content.res.Configuration
-import android.os.Build
import androidx.core.os.ConfigurationCompat
import androidx.core.view.ViewCompat.LAYOUT_DIRECTION_LTR
import androidx.core.view.ViewCompat.LAYOUT_DIRECTION_RTL
@@ -115,13 +114,11 @@
configuration.language,
CoreMatchers.equalTo(lang)
)
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- assertThat(
- "Layout direction should be ${if (expectRtl) "RTL" else "LTR"}",
- configuration.layoutDirection,
- CoreMatchers.equalTo(if (expectRtl) LAYOUT_DIRECTION_RTL else LAYOUT_DIRECTION_LTR)
- )
- }
+ assertThat(
+ "Layout direction should be ${if (expectRtl) "RTL" else "LTR"}",
+ configuration.layoutDirection,
+ CoreMatchers.equalTo(if (expectRtl) LAYOUT_DIRECTION_RTL else LAYOUT_DIRECTION_LTR)
+ )
}
private fun determineDefaultLayoutDirection() {
@@ -130,8 +127,6 @@
configuration.language,
CoreMatchers.equalTo(DEFAULT_LANGUAGE)
)
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- expectRtlInDefaultLanguage = configuration.layoutDirection == LAYOUT_DIRECTION_RTL
- }
+ expectRtlInDefaultLanguage = configuration.layoutDirection == LAYOUT_DIRECTION_RTL
}
}
diff --git a/testutils/testutils-runtime/src/main/java/androidx/fragment/app/StrictFragment.kt b/testutils/testutils-runtime/src/main/java/androidx/fragment/app/StrictFragment.kt
index fe1c603..f3fa6a7 100644
--- a/testutils/testutils-runtime/src/main/java/androidx/fragment/app/StrictFragment.kt
+++ b/testutils/testutils-runtime/src/main/java/androidx/fragment/app/StrictFragment.kt
@@ -17,7 +17,6 @@
package androidx.fragment.app
import android.content.Context
-import android.os.Build
import android.os.Bundle
import android.util.AttributeSet
import androidx.annotation.LayoutRes
@@ -53,9 +52,7 @@
}
fun checkActivityNotDestroyed() {
- if (Build.VERSION.SDK_INT >= 17) {
- check(!requireActivity().isDestroyed)
- }
+ check(!requireActivity().isDestroyed)
}
fun checkState(caller: String, vararg expected: State) {
diff --git a/testutils/testutils-runtime/src/main/java/androidx/testutils/AnimationActivityTestRule.kt b/testutils/testutils-runtime/src/main/java/androidx/testutils/AnimationActivityTestRule.kt
index 288c788..6c46472 100644
--- a/testutils/testutils-runtime/src/main/java/androidx/testutils/AnimationActivityTestRule.kt
+++ b/testutils/testutils-runtime/src/main/java/androidx/testutils/AnimationActivityTestRule.kt
@@ -19,7 +19,6 @@
import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.app.Activity
-import android.os.Build
import androidx.test.runner.intercepting.SingleActivityFactory
import java.lang.RuntimeException
import java.lang.reflect.Method
@@ -73,6 +72,7 @@
launchActivity: Boolean
) : super(singleActivityFactory, initialTouchMode, launchActivity)
+ @SuppressLint("BanUncheckedReflection")
override fun afterActivityLaunched() {
// make sure "apply()" is invoked
if (!::testType.isInitialized) {
@@ -85,16 +85,14 @@
override fun apply(base: Statement, description: Description): Statement {
testType = TestType.NORMAL
- if (Build.VERSION.SDK_INT >= 16 &&
- (
- description.annotations.any { it.annotationClass == AnimationTest::class } ||
- description.testClass.annotations.any
- { it.annotationClass == AnimationTest::class }
- )
+ if (description.annotations.any { it.annotationClass == AnimationTest::class } ||
+ description.testClass.annotations.any
+ { it.annotationClass == AnimationTest::class }
) {
testType = TestType.ANIMATION
val wrappedStatement = super.apply(base, description)
return object : Statement() {
+ @SuppressLint("BanUncheckedReflection")
override fun evaluate() {
val savedScale = durationGetter.invoke(null) as Float
try {
diff --git a/testutils/testutils-runtime/src/main/java/androidx/testutils/AnimationDurationScaleRule.kt b/testutils/testutils-runtime/src/main/java/androidx/testutils/AnimationDurationScaleRule.kt
index 650354c..b8862b9 100644
--- a/testutils/testutils-runtime/src/main/java/androidx/testutils/AnimationDurationScaleRule.kt
+++ b/testutils/testutils-runtime/src/main/java/androidx/testutils/AnimationDurationScaleRule.kt
@@ -18,10 +18,8 @@
import android.animation.ValueAnimator
import android.annotation.SuppressLint
-import android.os.Build
import org.junit.rules.TestWatcher
import org.junit.runner.Description
-import org.junit.runners.model.Statement
/**
* This rule allows test to control animation duration scale for tests.
@@ -62,24 +60,11 @@
internal fun create(
forcedAnimationDurationScale: Float? = null
): AnimationDurationScaleRule {
- return if (Build.VERSION.SDK_INT >= 16) {
- AnimationDurationScaleRuleImpl(
- forcedAnimationDurationScale
- )
- } else {
- NoOpAnimationDurationScaleRule()
- }
+ return AnimationDurationScaleRuleImpl(forcedAnimationDurationScale)
}
}
}
-private class NoOpAnimationDurationScaleRule : AnimationDurationScaleRule() {
- override fun setAnimationDurationScale(animationDurationScale: Float) {
- }
-
- override fun apply(base: Statement, description: Description) = base
-}
-
private class AnimationDurationScaleRuleImpl(
/**
* The new duration scale for the test
diff --git a/testutils/testutils-runtime/src/main/java/androidx/testutils/LocaleTestUtils.kt b/testutils/testutils-runtime/src/main/java/androidx/testutils/LocaleTestUtils.kt
index 0e5bc52..648d807 100644
--- a/testutils/testutils-runtime/src/main/java/androidx/testutils/LocaleTestUtils.kt
+++ b/testutils/testutils-runtime/src/main/java/androidx/testutils/LocaleTestUtils.kt
@@ -200,11 +200,8 @@
when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ->
newConfig.setLocales(locales.unwrap() as LocaleList)
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 ->
- newConfig.setLocale(locales.get(0))
- else ->
- @Suppress("DEPRECATION")
- newConfig.locale = locales.get(0)
+
+ else -> newConfig.setLocale(locales.get(0))
}
@Suppress("DEPRECATION")
resources.updateConfiguration(newConfig, resources.displayMetrics)
diff --git a/text/text/lint-baseline.xml b/text/text/lint-baseline.xml
index 9d2be4d..2a6edab 100644
--- a/text/text/lint-baseline.xml
+++ b/text/text/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.2.0-beta01" type="baseline" client="gradle" dependencies="false" name="AGP (8.2.0-beta01)" variant="all" version="8.2.0-beta01">
+<issues format="6" by="lint 8.3.0-alpha10" type="baseline" client="gradle" dependencies="false" name="AGP (8.3.0-alpha10)" variant="all" version="8.3.0-alpha10">
<issue
id="PrimitiveInCollection"
@@ -7,7 +7,7 @@
errorLine1=" private val paragraphEnds: List<Int>"
errorLine2=" ~~~~~~~~~">
<location
- file="src/main/java/androidx/compose/ui/text/android/LayoutHelper.kt"/>
+ file="src/main/java/androidx/compose/ui/text/android/LayoutHelper.android.kt"/>
</issue>
<issue
@@ -16,7 +16,7 @@
errorLine1=" val lineFeeds = mutableListOf<Int>()"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="src/main/java/androidx/compose/ui/text/android/LayoutHelper.kt"/>
+ file="src/main/java/androidx/compose/ui/text/android/LayoutHelper.android.kt"/>
</issue>
<issue
@@ -25,7 +25,7 @@
errorLine1=" private fun breakInWords(layoutHelper: LayoutHelper): List<Int> {"
errorLine2=" ~~~~~~~~~">
<location
- file="src/main/java/androidx/compose/ui/text/android/animation/SegmentBreaker.kt"/>
+ file="src/main/java/androidx/compose/ui/text/android/animation/SegmentBreaker.android.kt"/>
</issue>
<issue
@@ -34,7 +34,7 @@
errorLine1=" val words = breakWithBreakIterator(text, BreakIterator.getLineInstance(Locale.getDefault()))"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="src/main/java/androidx/compose/ui/text/android/animation/SegmentBreaker.kt"/>
+ file="src/main/java/androidx/compose/ui/text/android/animation/SegmentBreaker.android.kt"/>
</issue>
<issue
@@ -43,7 +43,7 @@
errorLine1=" val set = TreeSet<Int>().apply {"
errorLine2=" ^">
<location
- file="src/main/java/androidx/compose/ui/text/android/animation/SegmentBreaker.kt"/>
+ file="src/main/java/androidx/compose/ui/text/android/animation/SegmentBreaker.android.kt"/>
</issue>
<issue
@@ -52,7 +52,7 @@
errorLine1=" private fun breakWithBreakIterator(text: CharSequence, breaker: BreakIterator): List<Int> {"
errorLine2=" ~~~~~~~~~">
<location
- file="src/main/java/androidx/compose/ui/text/android/animation/SegmentBreaker.kt"/>
+ file="src/main/java/androidx/compose/ui/text/android/animation/SegmentBreaker.android.kt"/>
</issue>
<issue
@@ -61,7 +61,7 @@
errorLine1=" val res = mutableListOf(0)"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="src/main/java/androidx/compose/ui/text/android/animation/SegmentBreaker.kt"/>
+ file="src/main/java/androidx/compose/ui/text/android/animation/SegmentBreaker.android.kt"/>
</issue>
<issue
@@ -70,7 +70,7 @@
errorLine1=" fun breakOffsets(layoutHelper: LayoutHelper, segmentType: SegmentType): List<Int> {"
errorLine2=" ~~~~~~~~~">
<location
- file="src/main/java/androidx/compose/ui/text/android/animation/SegmentBreaker.kt"/>
+ file="src/main/java/androidx/compose/ui/text/android/animation/SegmentBreaker.android.kt"/>
</issue>
</issues>
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/BoringLayoutFactory.kt b/text/text/src/main/java/androidx/compose/ui/text/android/BoringLayoutFactory.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/BoringLayoutFactory.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/BoringLayoutFactory.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/CharSequenceCharacterIterator.kt b/text/text/src/main/java/androidx/compose/ui/text/android/CharSequenceCharacterIterator.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/CharSequenceCharacterIterator.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/CharSequenceCharacterIterator.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/InlineClassUtils.kt b/text/text/src/main/java/androidx/compose/ui/text/android/InlineClassUtils.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/InlineClassUtils.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/InlineClassUtils.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/InternalPlatformTextApi.kt b/text/text/src/main/java/androidx/compose/ui/text/android/InternalPlatformTextApi.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/InternalPlatformTextApi.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/InternalPlatformTextApi.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/LayoutCompat.kt b/text/text/src/main/java/androidx/compose/ui/text/android/LayoutCompat.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/LayoutCompat.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/LayoutCompat.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/LayoutHelper.kt b/text/text/src/main/java/androidx/compose/ui/text/android/LayoutHelper.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/LayoutHelper.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/LayoutHelper.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/LayoutIntrinsics.kt b/text/text/src/main/java/androidx/compose/ui/text/android/LayoutIntrinsics.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/LayoutIntrinsics.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/LayoutIntrinsics.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/ListUtils.kt b/text/text/src/main/java/androidx/compose/ui/text/android/ListUtils.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/ListUtils.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/ListUtils.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/PaintExtensions.kt b/text/text/src/main/java/androidx/compose/ui/text/android/PaintExtensions.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/PaintExtensions.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/PaintExtensions.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/SpannedExtensions.kt b/text/text/src/main/java/androidx/compose/ui/text/android/SpannedExtensions.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/SpannedExtensions.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/SpannedExtensions.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/StaticLayoutFactory.kt b/text/text/src/main/java/androidx/compose/ui/text/android/StaticLayoutFactory.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/StaticLayoutFactory.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/StaticLayoutFactory.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/TextAndroidCanvas.kt b/text/text/src/main/java/androidx/compose/ui/text/android/TextAndroidCanvas.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/TextAndroidCanvas.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/TextAndroidCanvas.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/TextLayout.kt b/text/text/src/main/java/androidx/compose/ui/text/android/TextLayout.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/TextLayout.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/TextLayout.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/animation/SegmentBreaker.kt b/text/text/src/main/java/androidx/compose/ui/text/android/animation/SegmentBreaker.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/animation/SegmentBreaker.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/animation/SegmentBreaker.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/animation/SegmentType.kt b/text/text/src/main/java/androidx/compose/ui/text/android/animation/SegmentType.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/animation/SegmentType.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/animation/SegmentType.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/selection/WordBoundary.kt b/text/text/src/main/java/androidx/compose/ui/text/android/selection/WordBoundary.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/selection/WordBoundary.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/selection/WordBoundary.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/selection/WordIterator.kt b/text/text/src/main/java/androidx/compose/ui/text/android/selection/WordIterator.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/selection/WordIterator.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/selection/WordIterator.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/style/BaselineShiftSpan.kt b/text/text/src/main/java/androidx/compose/ui/text/android/style/BaselineShiftSpan.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/style/BaselineShiftSpan.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/style/BaselineShiftSpan.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/style/FontFeatureSpan.kt b/text/text/src/main/java/androidx/compose/ui/text/android/style/FontFeatureSpan.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/style/FontFeatureSpan.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/style/FontFeatureSpan.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/style/IndentationFixSpan.kt b/text/text/src/main/java/androidx/compose/ui/text/android/style/IndentationFixSpan.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/style/IndentationFixSpan.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/style/IndentationFixSpan.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/style/LetterSpacingSpanEm.kt b/text/text/src/main/java/androidx/compose/ui/text/android/style/LetterSpacingSpanEm.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/style/LetterSpacingSpanEm.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/style/LetterSpacingSpanEm.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/style/LetterSpacingSpanPx.kt b/text/text/src/main/java/androidx/compose/ui/text/android/style/LetterSpacingSpanPx.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/style/LetterSpacingSpanPx.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/style/LetterSpacingSpanPx.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/style/LineHeightSpan.kt b/text/text/src/main/java/androidx/compose/ui/text/android/style/LineHeightSpan.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/style/LineHeightSpan.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/style/LineHeightSpan.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/style/LineHeightStyleSpan.kt b/text/text/src/main/java/androidx/compose/ui/text/android/style/LineHeightStyleSpan.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/style/LineHeightStyleSpan.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/style/LineHeightStyleSpan.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/style/PlaceholderSpan.kt b/text/text/src/main/java/androidx/compose/ui/text/android/style/PlaceholderSpan.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/style/PlaceholderSpan.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/style/PlaceholderSpan.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/style/ShadowSpan.kt b/text/text/src/main/java/androidx/compose/ui/text/android/style/ShadowSpan.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/style/ShadowSpan.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/style/ShadowSpan.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/style/SkewXSpan.kt b/text/text/src/main/java/androidx/compose/ui/text/android/style/SkewXSpan.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/style/SkewXSpan.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/style/SkewXSpan.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/style/TextDecorationSpan.kt b/text/text/src/main/java/androidx/compose/ui/text/android/style/TextDecorationSpan.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/style/TextDecorationSpan.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/style/TextDecorationSpan.android.kt
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/style/TypefaceSpan.kt b/text/text/src/main/java/androidx/compose/ui/text/android/style/TypefaceSpan.android.kt
similarity index 100%
rename from text/text/src/main/java/androidx/compose/ui/text/android/style/TypefaceSpan.kt
rename to text/text/src/main/java/androidx/compose/ui/text/android/style/TypefaceSpan.android.kt
diff --git a/tracing/tracing-perfetto-binary/src/main/cpp/tracing_perfetto.cc b/tracing/tracing-perfetto-binary/src/main/cpp/tracing_perfetto.cc
index aa266f7..c7ad150 100644
--- a/tracing/tracing-perfetto-binary/src/main/cpp/tracing_perfetto.cc
+++ b/tracing/tracing-perfetto-binary/src/main/cpp/tracing_perfetto.cc
@@ -25,7 +25,7 @@
// Concept of version useful e.g. for human-readable error messages, and stable once released.
// Does not replace the need for a binary verification mechanism (e.g. checksum check).
// TODO: populate using CMake
-#define VERSION "1.0.0-beta03"
+#define VERSION "1.0.0"
namespace tracing_perfetto {
void RegisterWithPerfetto() {
diff --git a/tracing/tracing-perfetto/src/androidTest/java/androidx/tracing/perfetto/jni/test/PerfettoNativeTest.kt b/tracing/tracing-perfetto/src/androidTest/java/androidx/tracing/perfetto/jni/test/PerfettoNativeTest.kt
index ef3b214..d3ef52d 100644
--- a/tracing/tracing-perfetto/src/androidTest/java/androidx/tracing/perfetto/jni/test/PerfettoNativeTest.kt
+++ b/tracing/tracing-perfetto/src/androidTest/java/androidx/tracing/perfetto/jni/test/PerfettoNativeTest.kt
@@ -30,7 +30,7 @@
init {
PerfettoNative.loadLib()
}
- const val libraryVersion = "1.0.0-beta03" // TODO: get using reflection
+ const val libraryVersion = "1.0.0" // TODO: get using reflection
}
@Test
diff --git a/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/jni/PerfettoNative.kt b/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/jni/PerfettoNative.kt
index 3cc418e..47e3465 100644
--- a/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/jni/PerfettoNative.kt
+++ b/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/jni/PerfettoNative.kt
@@ -25,12 +25,12 @@
// TODO(224510255): load from a file produced at build time
object Metadata {
- const val version = "1.0.0-beta03"
+ const val version = "1.0.0"
val checksums = mapOf(
- "arm64-v8a" to "e11502d6fa0c949774a792c2406744a1fff112ba26e6af19a6722dd55a6061ca",
- "armeabi-v7a" to "cd286085893cc7760b658f48b436fd317493159dcbab680667c0bf01d25ffb04",
- "x86" to "2679c351d40e405e46dec58c8f63570eb29196cd9e67404cf66abe74bc933a88",
- "x86_64" to "2971a9135cd69feb2a4e3c7b42f6b52469421713331cdb7a841c1c8cc707b637",
+ "arm64-v8a" to "a152fbd7ebaa109a9c3cf6bbb6d585aa0df08f97ae022b2090b1096a8f5e2665",
+ "armeabi-v7a" to "b2821c9ddb77a3f070cce42be7cd3255d7ec92c868d7d518a99ed968d9018b9f",
+ "x86" to "4cefdc75fe41deeeb2306891c25ce4db33599698cc6fcb2e82caad5aece9aa09",
+ "x86_64" to "23daf0750238cf96bf9ea9fa1b13ae1d2eeb17644ea5439e18939ec6a8b9e5be",
)
}
diff --git a/transition/transition/src/androidTest/java/androidx/transition/ChangeBoundsTest.java b/transition/transition/src/androidTest/java/androidx/transition/ChangeBoundsTest.java
index 3c27a70..92b0821 100644
--- a/transition/transition/src/androidTest/java/androidx/transition/ChangeBoundsTest.java
+++ b/transition/transition/src/androidTest/java/androidx/transition/ChangeBoundsTest.java
@@ -26,7 +26,6 @@
import android.content.Context;
import android.graphics.Rect;
-import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.LinearInterpolator;
@@ -92,11 +91,6 @@
@Test
public void testSuppressLayoutWhileAnimating() throws Throwable {
- if (Build.VERSION.SDK_INT < 18) {
- // prior Android 4.3 suppressLayout port has another implementation which is
- // harder to test
- return;
- }
final TestSuppressLayout suppressLayout = new TestSuppressLayout(rule.getActivity());
final View testView = new View(rule.getActivity());
rule.runOnUiThread(new Runnable() {
diff --git a/transition/transition/src/androidTest/java/androidx/transition/FadeTest.java b/transition/transition/src/androidTest/java/androidx/transition/FadeTest.java
index 7aab444..1667459 100644
--- a/transition/transition/src/androidTest/java/androidx/transition/FadeTest.java
+++ b/transition/transition/src/androidTest/java/androidx/transition/FadeTest.java
@@ -146,7 +146,7 @@
verify(listenerOut, timeout(3000)).onTransitionPause(any(Transition.class));
verify(listenerIn, timeout(3000)).onTransitionStart(any(Transition.class));
assertThat(valuesOut[1], allOf(greaterThan(0f), lessThan(1f)));
- if (Build.VERSION.SDK_INT >= 19 && fadeOut.mInitialAlpha >= 0) {
+ if (fadeOut.mInitialAlpha >= 0) {
// These won't match on API levels 18 and below due to lack of Animator pause.
assertEquals(valuesOut[1], valuesIn[0], 0.01f);
}
@@ -182,7 +182,7 @@
verify(listenerIn, timeout(3000)).onTransitionPause(any(Transition.class));
verify(listenerOut, timeout(3000)).onTransitionStart(any(Transition.class));
assertThat(valuesIn[1], allOf(greaterThan(0f), lessThan(1f)));
- if (Build.VERSION.SDK_INT >= 19 && fadeIn.mInitialAlpha >= 0) {
+ if (fadeIn.mInitialAlpha >= 0) {
// These won't match on API levels 18 and below due to lack of Animator pause.
assertEquals(valuesIn[1], valuesOut[0], 0.01f);
}
diff --git a/transition/transition/src/main/java/androidx/transition/AnimatorUtils.java b/transition/transition/src/main/java/androidx/transition/AnimatorUtils.java
deleted file mode 100644
index 7ce8668..0000000
--- a/transition/transition/src/main/java/androidx/transition/AnimatorUtils.java
+++ /dev/null
@@ -1,103 +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.transition;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.os.Build;
-
-import androidx.annotation.DoNotInline;
-import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
-
-import java.util.ArrayList;
-
-class AnimatorUtils {
-
- static void addPauseListener(@NonNull Animator animator,
- @NonNull AnimatorListenerAdapter listener) {
- if (Build.VERSION.SDK_INT >= 19) {
- Api19Impl.addPauseListener(animator, listener);
- }
- }
-
- static void pause(@NonNull Animator animator) {
- if (Build.VERSION.SDK_INT >= 19) {
- Api19Impl.pause(animator);
- } else {
- final ArrayList<Animator.AnimatorListener> listeners = animator.getListeners();
- if (listeners != null) {
- for (int i = 0, size = listeners.size(); i < size; i++) {
- final Animator.AnimatorListener listener = listeners.get(i);
- if (listener instanceof AnimatorPauseListenerCompat) {
- ((AnimatorPauseListenerCompat) listener).onAnimationPause(animator);
- }
- }
- }
- }
- }
-
- static void resume(@NonNull Animator animator) {
- if (Build.VERSION.SDK_INT >= 19) {
- Api19Impl.resume(animator);
- } else {
- final ArrayList<Animator.AnimatorListener> listeners = animator.getListeners();
- if (listeners != null) {
- for (int i = 0, size = listeners.size(); i < size; i++) {
- final Animator.AnimatorListener listener = listeners.get(i);
- if (listener instanceof AnimatorPauseListenerCompat) {
- ((AnimatorPauseListenerCompat) listener).onAnimationResume(animator);
- }
- }
- }
- }
- }
-
- /**
- * Listeners can implement this interface in addition to the platform AnimatorPauseListener to
- * make them compatible with API level 18 and below. Animators will not be paused or resumed,
- * but the callbacks here are invoked.
- */
- interface AnimatorPauseListenerCompat {
-
- void onAnimationPause(Animator animation);
-
- void onAnimationResume(Animator animation);
-
- }
-
- private AnimatorUtils() { }
-
- @RequiresApi(19)
- static class Api19Impl {
- private Api19Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static void addPauseListener(Animator animator, AnimatorListenerAdapter listener) {
- animator.addPauseListener(listener);
- }
- @DoNotInline
- static void pause(Animator animator) {
- animator.pause();
- }@DoNotInline
- static void resume(Animator animator) {
- animator.resume();
- }
- }
-}
diff --git a/transition/transition/src/main/java/androidx/transition/ChangeImageTransform.java b/transition/transition/src/main/java/androidx/transition/ChangeImageTransform.java
index 1d6b6d0..a9cc6ba 100644
--- a/transition/transition/src/main/java/androidx/transition/ChangeImageTransform.java
+++ b/transition/transition/src/main/java/androidx/transition/ChangeImageTransform.java
@@ -183,7 +183,7 @@
animator = createMatrixAnimator(imageView, startMatrix, endMatrix);
Listener listener = new Listener(imageView, startMatrix, endMatrix);
animator.addListener(listener);
- AnimatorUtils.addPauseListener(animator, listener);
+ animator.addPauseListener(listener);
addListener(listener);
}
@@ -258,8 +258,7 @@
return matrix;
}
- private static class Listener extends AnimatorListenerAdapter implements TransitionListener,
- AnimatorUtils.AnimatorPauseListenerCompat {
+ private static class Listener extends AnimatorListenerAdapter implements TransitionListener {
private final ImageView mImageView;
private final Matrix mStartMatrix;
private final Matrix mEndMatrix;
diff --git a/transition/transition/src/main/java/androidx/transition/ChangeTransform.java b/transition/transition/src/main/java/androidx/transition/ChangeTransform.java
index 0d0cd09..0d5ae8f 100644
--- a/transition/transition/src/main/java/androidx/transition/ChangeTransform.java
+++ b/transition/transition/src/main/java/androidx/transition/ChangeTransform.java
@@ -330,7 +330,7 @@
handleParentChange, mUseOverlay);
animator.addListener(listener);
- AnimatorUtils.addPauseListener(animator, listener);
+ animator.addPauseListener(listener);
return animator;
}
@@ -551,8 +551,7 @@
}
}
- private static class Listener extends AnimatorListenerAdapter implements
- AnimatorUtils.AnimatorPauseListenerCompat {
+ private static class Listener extends AnimatorListenerAdapter {
private boolean mIsCanceled;
private final Matrix mTempMatrix = new Matrix();
private final boolean mHandleParentChange;
diff --git a/transition/transition/src/main/java/androidx/transition/Transition.java b/transition/transition/src/main/java/androidx/transition/Transition.java
index 36f608c..4b41fcc 100644
--- a/transition/transition/src/main/java/androidx/transition/Transition.java
+++ b/transition/transition/src/main/java/androidx/transition/Transition.java
@@ -1831,7 +1831,7 @@
for (int i = numAnimators - 1; i >= 0; i--) {
Animator animator = cache[i];
cache[i] = null;
- AnimatorUtils.pause(animator);
+ animator.pause();
}
mAnimatorCache = cache;
notifyListeners(TransitionNotification.ON_PAUSE, false);
@@ -1855,7 +1855,7 @@
for (int i = numAnimators - 1; i >= 0; i--) {
Animator animator = cache[i];
cache[i] = null;
- AnimatorUtils.resume(animator);
+ animator.resume();
}
mAnimatorCache = cache;
notifyListeners(TransitionNotification.ON_RESUME, false);
diff --git a/transition/transition/src/main/java/androidx/transition/TransitionUtils.java b/transition/transition/src/main/java/androidx/transition/TransitionUtils.java
index 960a640..3e323a0d 100644
--- a/transition/transition/src/main/java/androidx/transition/TransitionUtils.java
+++ b/transition/transition/src/main/java/androidx/transition/TransitionUtils.java
@@ -36,10 +36,6 @@
class TransitionUtils {
private static final int MAX_IMAGE_SIZE = 1024 * 1024;
- private static final boolean HAS_IS_ATTACHED_TO_WINDOW =
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
- private static final boolean HAS_OVERLAY =
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2;
private static final boolean HAS_PICTURE_BITMAP =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
@@ -94,22 +90,18 @@
ViewGroup sceneRoot) {
final boolean addToOverlay;
final boolean sceneRootIsAttached;
- if (HAS_IS_ATTACHED_TO_WINDOW) {
- addToOverlay = !Api19Impl.isAttachedToWindow(view);
- sceneRootIsAttached = sceneRoot != null && Api19Impl.isAttachedToWindow(sceneRoot);
- } else {
- addToOverlay = false;
- sceneRootIsAttached = false;
- }
+ addToOverlay = !view.isAttachedToWindow();
+ sceneRootIsAttached = sceneRoot != null && sceneRoot.isAttachedToWindow();
ViewGroup parent = null;
int indexInParent = 0;
- if (HAS_OVERLAY && addToOverlay) {
+ if (addToOverlay) {
if (!sceneRootIsAttached) {
return null;
}
parent = (ViewGroup) view.getParent();
indexInParent = parent.indexOfChild(view);
- Api18Impl.getOverlayAndAdd(sceneRoot, view);
+ ViewGroupOverlay result = sceneRoot.getOverlay();
+ result.add(view);
}
Bitmap bitmap = null;
int bitmapWidth = Math.round(bounds.width());
@@ -137,8 +129,9 @@
view.draw(canvas);
}
}
- if (HAS_OVERLAY && addToOverlay) {
- Api18Impl.getOverlayAndRemove(sceneRoot, view);
+ if (addToOverlay) {
+ ViewGroupOverlay result = sceneRoot.getOverlay();
+ result.remove(view);
parent.addView(view, indexInParent);
}
return bitmap;
@@ -180,26 +173,6 @@
private TransitionUtils() { }
- @RequiresApi(18)
- static class Api18Impl {
- private Api18Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static ViewGroupOverlay getOverlayAndAdd(ViewGroup viewGroup, View toAdd) {
- ViewGroupOverlay result = viewGroup.getOverlay();
- result.add(toAdd);
- return result;
- }
-
- @DoNotInline
- static ViewGroupOverlay getOverlayAndRemove(ViewGroup viewGroup, View toRemove) {
- ViewGroupOverlay result = viewGroup.getOverlay();
- result.remove(toRemove);
- return result;
- }
- }
@RequiresApi(28)
static class Api28Impl {
private Api28Impl() {
@@ -212,15 +185,4 @@
}
}
- @RequiresApi(19)
- static class Api19Impl {
- private Api19Impl() {
- // This class is not instantiable.
- }
-
- @DoNotInline
- static boolean isAttachedToWindow(View view) {
- return view.isAttachedToWindow();
- }
- }
}
diff --git a/transition/transition/src/main/java/androidx/transition/ViewGroupOverlayApi18.java b/transition/transition/src/main/java/androidx/transition/ViewGroupOverlayApi18.java
index 20e4282..4c5f4e8 100644
--- a/transition/transition/src/main/java/androidx/transition/ViewGroupOverlayApi18.java
+++ b/transition/transition/src/main/java/androidx/transition/ViewGroupOverlayApi18.java
@@ -22,9 +22,7 @@
import android.view.ViewGroupOverlay;
import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
-@RequiresApi(18)
class ViewGroupOverlayApi18 implements ViewGroupOverlayImpl {
private final ViewGroupOverlay mViewGroupOverlay;
diff --git a/transition/transition/src/main/java/androidx/transition/ViewGroupUtils.java b/transition/transition/src/main/java/androidx/transition/ViewGroupUtils.java
index 37126f5..52c2f97 100644
--- a/transition/transition/src/main/java/androidx/transition/ViewGroupUtils.java
+++ b/transition/transition/src/main/java/androidx/transition/ViewGroupUtils.java
@@ -44,10 +44,7 @@
* Backward-compatible {@link ViewGroup#getOverlay()}.
*/
static ViewGroupOverlayImpl getOverlay(@NonNull ViewGroup group) {
- if (Build.VERSION.SDK_INT >= 18) {
- return new ViewGroupOverlayApi18(group);
- }
- return ViewGroupOverlayApi14.createFrom(group);
+ return new ViewGroupOverlayApi18(group);
}
/**
@@ -56,14 +53,11 @@
static void suppressLayout(@NonNull ViewGroup group, boolean suppress) {
if (Build.VERSION.SDK_INT >= 29) {
Api29Impl.suppressLayout(group, suppress);
- } else if (Build.VERSION.SDK_INT >= 18) {
- hiddenSuppressLayout(group, suppress);
} else {
- ViewGroupUtilsApi14.suppressLayout(group, suppress);
+ hiddenSuppressLayout(group, suppress);
}
}
- @RequiresApi(18)
@SuppressLint("NewApi") // Lint doesn't know about the hidden method.
private static void hiddenSuppressLayout(@NonNull ViewGroup group, boolean suppress) {
if (sTryHiddenSuppressLayout) {
diff --git a/transition/transition/src/main/java/androidx/transition/ViewGroupUtilsApi14.java b/transition/transition/src/main/java/androidx/transition/ViewGroupUtilsApi14.java
deleted file mode 100644
index 2a83cc1..0000000
--- a/transition/transition/src/main/java/androidx/transition/ViewGroupUtilsApi14.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.transition;
-
-import android.animation.LayoutTransition;
-import android.annotation.SuppressLint;
-import android.util.Log;
-import android.view.ViewGroup;
-
-import androidx.annotation.NonNull;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-class ViewGroupUtilsApi14 {
-
- private static final String TAG = "ViewGroupUtilsApi14";
-
- private static final int LAYOUT_TRANSITION_CHANGING = 4;
-
- private static LayoutTransition sEmptyLayoutTransition;
-
- private static Field sLayoutSuppressedField;
- private static boolean sLayoutSuppressedFieldFetched;
-
- private static Method sCancelMethod;
- private static boolean sCancelMethodFetched;
-
- static void suppressLayout(@NonNull ViewGroup group, boolean suppress) {
- // Prepare the empty LayoutTransition
- if (sEmptyLayoutTransition == null) {
- sEmptyLayoutTransition = new LayoutTransition() {
- @Override
- public boolean isChangingLayout() {
- return true;
- }
- };
- sEmptyLayoutTransition.setAnimator(LayoutTransition.APPEARING, null);
- sEmptyLayoutTransition.setAnimator(LayoutTransition.CHANGE_APPEARING, null);
- sEmptyLayoutTransition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, null);
- sEmptyLayoutTransition.setAnimator(LayoutTransition.DISAPPEARING, null);
- sEmptyLayoutTransition.setAnimator(LAYOUT_TRANSITION_CHANGING, null);
- }
- if (suppress) {
- // Save the current LayoutTransition
- final LayoutTransition layoutTransition = group.getLayoutTransition();
- if (layoutTransition != null) {
- if (layoutTransition.isRunning()) {
- cancelLayoutTransition(layoutTransition);
- }
- if (layoutTransition != sEmptyLayoutTransition) {
- group.setTag(R.id.transition_layout_save, layoutTransition);
- }
- }
- // Suppress the layout
- group.setLayoutTransition(sEmptyLayoutTransition);
- } else {
- // Thaw the layout suppression
- group.setLayoutTransition(null);
- // Request layout if necessary
- if (!sLayoutSuppressedFieldFetched) {
- try {
- sLayoutSuppressedField = ViewGroup.class.getDeclaredField("mLayoutSuppressed");
- sLayoutSuppressedField.setAccessible(true);
- } catch (NoSuchFieldException e) {
- Log.i(TAG, "Failed to access mLayoutSuppressed field by reflection");
- }
- sLayoutSuppressedFieldFetched = true;
- }
- boolean layoutSuppressed = false;
- if (sLayoutSuppressedField != null) {
- try {
- layoutSuppressed = sLayoutSuppressedField.getBoolean(group);
- if (layoutSuppressed) {
- sLayoutSuppressedField.setBoolean(group, false);
- }
- } catch (IllegalAccessException e) {
- Log.i(TAG, "Failed to get mLayoutSuppressed field by reflection");
- }
- }
- if (layoutSuppressed) {
- group.requestLayout();
- }
- // Restore the saved LayoutTransition
- final LayoutTransition layoutTransition =
- (LayoutTransition) group.getTag(R.id.transition_layout_save);
- if (layoutTransition != null) {
- group.setTag(R.id.transition_layout_save, null);
- group.setLayoutTransition(layoutTransition);
- }
- }
- }
-
- /**
- * Note, this is only called on API 17 and older.
- */
- @SuppressLint({"SoonBlockedPrivateApi", "BanUncheckedReflection"})
- private static void cancelLayoutTransition(LayoutTransition t) {
- if (!sCancelMethodFetched) {
- try {
- sCancelMethod = LayoutTransition.class.getDeclaredMethod("cancel");
- sCancelMethod.setAccessible(true);
- } catch (NoSuchMethodException e) {
- Log.i(TAG, "Failed to access cancel method by reflection");
- }
- sCancelMethodFetched = true;
- }
- if (sCancelMethod != null) {
- try {
- sCancelMethod.invoke(t);
- } catch (IllegalAccessException e) {
- Log.i(TAG, "Failed to access cancel method by reflection");
- } catch (InvocationTargetException e) {
- Log.i(TAG, "Failed to invoke cancel method by reflection");
- }
- }
- }
-
- private ViewGroupUtilsApi14() {
- }
-}
diff --git a/transition/transition/src/main/java/androidx/transition/ViewUtils.java b/transition/transition/src/main/java/androidx/transition/ViewUtils.java
index 388c11d..1cd039c 100644
--- a/transition/transition/src/main/java/androidx/transition/ViewUtils.java
+++ b/transition/transition/src/main/java/androidx/transition/ViewUtils.java
@@ -31,7 +31,7 @@
*/
class ViewUtils {
- private static final ViewUtilsBase IMPL;
+ private static final ViewUtilsApi19 IMPL;
private static final String TAG = "ViewUtils";
static {
@@ -43,10 +43,8 @@
IMPL = new ViewUtilsApi22();
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
IMPL = new ViewUtilsApi21();
- } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- IMPL = new ViewUtilsApi19();
} else {
- IMPL = new ViewUtilsBase();
+ IMPL = new ViewUtilsApi19();
}
}
@@ -87,20 +85,14 @@
* Backward-compatible {@link View#getOverlay()}.
*/
static ViewOverlayImpl getOverlay(@NonNull View view) {
- if (Build.VERSION.SDK_INT >= 18) {
- return new ViewOverlayApi18(view);
- }
- return ViewOverlayApi14.createFrom(view);
+ return new ViewOverlayApi18(view);
}
/**
* Backward-compatible {@link View#getWindowId()}.
*/
static @NonNull WindowIdImpl getWindowId(@NonNull View view) {
- if (Build.VERSION.SDK_INT >= 18) {
- return new WindowIdApi18(view);
- }
- return new WindowIdApi14(view.getWindowToken());
+ return new WindowIdApi18(view);
}
static void setTransitionAlpha(@NonNull View view, float alpha) {
diff --git a/transition/transition/src/main/java/androidx/transition/ViewUtilsApi19.java b/transition/transition/src/main/java/androidx/transition/ViewUtilsApi19.java
index 3668345..448ba3a 100644
--- a/transition/transition/src/main/java/androidx/transition/ViewUtilsApi19.java
+++ b/transition/transition/src/main/java/androidx/transition/ViewUtilsApi19.java
@@ -17,21 +17,36 @@
package androidx.transition;
import android.annotation.SuppressLint;
+import android.graphics.Matrix;
+import android.util.Log;
import android.view.View;
+import android.view.ViewParent;
import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
-@RequiresApi(19)
-class ViewUtilsApi19 extends ViewUtilsBase {
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+class ViewUtilsApi19 {
+
+ private static final String TAG = "ViewUtilsApi19";
/**
* False when linking of the hidden set[get]TransitionAlpha method has previously failed.
*/
private static boolean sTryHiddenTransitionAlpha = true;
+ private static Method sSetFrameMethod;
+ private static boolean sSetFrameFetched;
- @Override
+ private static Field sViewFlagsField;
+ private static boolean sViewFlagsFieldFetched;
+ private static final int VISIBILITY_MASK = 0x0000000C;
+
+ private float[] mMatrixValues;
@SuppressLint("NewApi") // Lint doesn't know about the hidden method.
public void setTransitionAlpha(@NonNull View view, float alpha) {
if (sTryHiddenTransitionAlpha) {
@@ -47,7 +62,6 @@
view.setAlpha(alpha);
}
- @Override
@SuppressLint("NewApi") // Lint doesn't know about the hidden method.
public float getTransitionAlpha(@NonNull View view) {
if (sTryHiddenTransitionAlpha) {
@@ -62,16 +76,130 @@
return view.getAlpha();
}
- @Override
public void saveNonTransitionAlpha(@NonNull View view) {
// Do nothing
}
- @Override
public void clearNonTransitionAlpha(@NonNull View view) {
// Do nothing
}
+ public void transformMatrixToGlobal(@NonNull View view, @NonNull Matrix matrix) {
+ final ViewParent parent = view.getParent();
+ if (parent instanceof View) {
+ final View vp = (View) parent;
+ transformMatrixToGlobal(vp, matrix);
+ matrix.preTranslate(-vp.getScrollX(), -vp.getScrollY());
+ }
+ matrix.preTranslate(view.getLeft(), view.getTop());
+ final Matrix vm = view.getMatrix();
+ if (!vm.isIdentity()) {
+ matrix.preConcat(vm);
+ }
+ }
+
+ public void transformMatrixToLocal(@NonNull View view, @NonNull Matrix matrix) {
+ final ViewParent parent = view.getParent();
+ if (parent instanceof View) {
+ final View vp = (View) parent;
+ transformMatrixToLocal(vp, matrix);
+ matrix.postTranslate(vp.getScrollX(), vp.getScrollY());
+ }
+ matrix.postTranslate(-view.getLeft(), -view.getTop());
+ final Matrix vm = view.getMatrix();
+ if (!vm.isIdentity()) {
+ final Matrix inverted = new Matrix();
+ if (vm.invert(inverted)) {
+ matrix.postConcat(inverted);
+ }
+ }
+ }
+
+ public void setAnimationMatrix(@NonNull View view, @Nullable Matrix matrix) {
+ if (matrix == null || matrix.isIdentity()) {
+ view.setPivotX(view.getWidth() / 2);
+ view.setPivotY(view.getHeight() / 2);
+ view.setTranslationX(0);
+ view.setTranslationY(0);
+ view.setScaleX(1);
+ view.setScaleY(1);
+ view.setRotation(0);
+ } else {
+ float[] values = mMatrixValues;
+ if (values == null) {
+ mMatrixValues = values = new float[9];
+ }
+ matrix.getValues(values);
+ final float sin = values[Matrix.MSKEW_Y];
+ final float cos = (float) Math.sqrt(1 - sin * sin)
+ * (values[Matrix.MSCALE_X] < 0 ? -1 : 1);
+ final float rotation = (float) Math.toDegrees(Math.atan2(sin, cos));
+ final float scaleX = values[Matrix.MSCALE_X] / cos;
+ final float scaleY = values[Matrix.MSCALE_Y] / cos;
+ final float dx = values[Matrix.MTRANS_X];
+ final float dy = values[Matrix.MTRANS_Y];
+ view.setPivotX(0);
+ view.setPivotY(0);
+ view.setTranslationX(dx);
+ view.setTranslationY(dy);
+ view.setRotation(rotation);
+ view.setScaleX(scaleX);
+ view.setScaleY(scaleY);
+ }
+ }
+
+ @SuppressLint("BanUncheckedReflection") // This class is only used on APIs 14-18
+ public void setLeftTopRightBottom(@NonNull View v, int left, int top, int right, int bottom) {
+ fetchSetFrame();
+ if (sSetFrameMethod != null) {
+ try {
+ sSetFrameMethod.invoke(v, left, top, right, bottom);
+ } catch (IllegalAccessException e) {
+ // Do nothing
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e.getCause());
+ }
+ }
+ }
+
+ @SuppressLint("SoonBlockedPrivateApi") // Only called on API <23
+ public void setTransitionVisibility(@NonNull View view, int visibility) {
+ if (!sViewFlagsFieldFetched) {
+ try {
+ sViewFlagsField = View.class.getDeclaredField("mViewFlags");
+ sViewFlagsField.setAccessible(true);
+ } catch (NoSuchFieldException e) {
+ Log.i(TAG, "fetchViewFlagsField: ");
+ }
+ sViewFlagsFieldFetched = true;
+ }
+ if (sViewFlagsField != null) {
+ try {
+ int viewFlags = sViewFlagsField.getInt(view);
+ sViewFlagsField.setInt(view, (viewFlags & ~VISIBILITY_MASK) | visibility);
+ } catch (IllegalAccessException e) {
+ // Do nothing
+ }
+ }
+ }
+
+ /**
+ * Note, this is only called on API 18 and older.
+ */
+ @SuppressLint({"PrivateApi", "SoonBlockedPrivateApi"})
+ private void fetchSetFrame() {
+ if (!sSetFrameFetched) {
+ try {
+ sSetFrameMethod = View.class.getDeclaredMethod("setFrame",
+ int.class, int.class, int.class, int.class);
+ sSetFrameMethod.setAccessible(true);
+ } catch (NoSuchMethodException e) {
+ Log.i(TAG, "Failed to retrieve setFrame method", e);
+ }
+ sSetFrameFetched = true;
+ }
+ }
+
@RequiresApi(29)
static class Api29Impl {
private Api29Impl() {
diff --git a/transition/transition/src/main/java/androidx/transition/ViewUtilsBase.java b/transition/transition/src/main/java/androidx/transition/ViewUtilsBase.java
deleted file mode 100644
index 535f18c..0000000
--- a/transition/transition/src/main/java/androidx/transition/ViewUtilsBase.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.transition;
-
-import android.annotation.SuppressLint;
-import android.graphics.Matrix;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewParent;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-// This class is guaranteed to only be called on SDKs 14-18 due to gating
-class ViewUtilsBase {
-
- private static final String TAG = "ViewUtilsBase";
-
- private static Method sSetFrameMethod;
- private static boolean sSetFrameFetched;
-
- private static Field sViewFlagsField;
- private static boolean sViewFlagsFieldFetched;
- private static final int VISIBILITY_MASK = 0x0000000C;
-
- private float[] mMatrixValues;
-
- public void setTransitionAlpha(@NonNull View view, float alpha) {
- Float savedAlpha = (Float) view.getTag(R.id.save_non_transition_alpha);
- if (savedAlpha != null) {
- view.setAlpha(savedAlpha * alpha);
- } else {
- view.setAlpha(alpha);
- }
- }
-
- public float getTransitionAlpha(@NonNull View view) {
- Float savedAlpha = (Float) view.getTag(R.id.save_non_transition_alpha);
- if (savedAlpha != null) {
- return view.getAlpha() / savedAlpha;
- } else {
- return view.getAlpha();
- }
- }
-
- public void saveNonTransitionAlpha(@NonNull View view) {
- if (view.getTag(R.id.save_non_transition_alpha) == null) {
- view.setTag(R.id.save_non_transition_alpha, view.getAlpha());
- }
- }
-
- public void clearNonTransitionAlpha(@NonNull View view) {
- // We don't clear the saved value when the view is hidden; that's the situation we are
- // saving this value for.
- if (view.getVisibility() == View.VISIBLE) {
- view.setTag(R.id.save_non_transition_alpha, null);
- }
- }
-
- public void transformMatrixToGlobal(@NonNull View view, @NonNull Matrix matrix) {
- final ViewParent parent = view.getParent();
- if (parent instanceof View) {
- final View vp = (View) parent;
- transformMatrixToGlobal(vp, matrix);
- matrix.preTranslate(-vp.getScrollX(), -vp.getScrollY());
- }
- matrix.preTranslate(view.getLeft(), view.getTop());
- final Matrix vm = view.getMatrix();
- if (!vm.isIdentity()) {
- matrix.preConcat(vm);
- }
- }
-
- public void transformMatrixToLocal(@NonNull View view, @NonNull Matrix matrix) {
- final ViewParent parent = view.getParent();
- if (parent instanceof View) {
- final View vp = (View) parent;
- transformMatrixToLocal(vp, matrix);
- matrix.postTranslate(vp.getScrollX(), vp.getScrollY());
- }
- matrix.postTranslate(-view.getLeft(), -view.getTop());
- final Matrix vm = view.getMatrix();
- if (!vm.isIdentity()) {
- final Matrix inverted = new Matrix();
- if (vm.invert(inverted)) {
- matrix.postConcat(inverted);
- }
- }
- }
-
- public void setAnimationMatrix(@NonNull View view, @Nullable Matrix matrix) {
- if (matrix == null || matrix.isIdentity()) {
- view.setPivotX(view.getWidth() / 2);
- view.setPivotY(view.getHeight() / 2);
- view.setTranslationX(0);
- view.setTranslationY(0);
- view.setScaleX(1);
- view.setScaleY(1);
- view.setRotation(0);
- } else {
- float[] values = mMatrixValues;
- if (values == null) {
- mMatrixValues = values = new float[9];
- }
- matrix.getValues(values);
- final float sin = values[Matrix.MSKEW_Y];
- final float cos = (float) Math.sqrt(1 - sin * sin)
- * (values[Matrix.MSCALE_X] < 0 ? -1 : 1);
- final float rotation = (float) Math.toDegrees(Math.atan2(sin, cos));
- final float scaleX = values[Matrix.MSCALE_X] / cos;
- final float scaleY = values[Matrix.MSCALE_Y] / cos;
- final float dx = values[Matrix.MTRANS_X];
- final float dy = values[Matrix.MTRANS_Y];
- view.setPivotX(0);
- view.setPivotY(0);
- view.setTranslationX(dx);
- view.setTranslationY(dy);
- view.setRotation(rotation);
- view.setScaleX(scaleX);
- view.setScaleY(scaleY);
- }
- }
-
- @SuppressLint("BanUncheckedReflection") // This class is only used on APIs 14-18
- public void setLeftTopRightBottom(@NonNull View v, int left, int top, int right, int bottom) {
- fetchSetFrame();
- if (sSetFrameMethod != null) {
- try {
- sSetFrameMethod.invoke(v, left, top, right, bottom);
- } catch (IllegalAccessException e) {
- // Do nothing
- } catch (InvocationTargetException e) {
- throw new RuntimeException(e.getCause());
- }
- }
- }
-
- @SuppressLint("SoonBlockedPrivateApi") // Only called on API <23
- public void setTransitionVisibility(@NonNull View view, int visibility) {
- if (!sViewFlagsFieldFetched) {
- try {
- sViewFlagsField = View.class.getDeclaredField("mViewFlags");
- sViewFlagsField.setAccessible(true);
- } catch (NoSuchFieldException e) {
- Log.i(TAG, "fetchViewFlagsField: ");
- }
- sViewFlagsFieldFetched = true;
- }
- if (sViewFlagsField != null) {
- try {
- int viewFlags = sViewFlagsField.getInt(view);
- sViewFlagsField.setInt(view, (viewFlags & ~VISIBILITY_MASK) | visibility);
- } catch (IllegalAccessException e) {
- // Do nothing
- }
- }
- }
-
- /**
- * Note, this is only called on API 18 and older.
- */
- @SuppressLint({"PrivateApi", "SoonBlockedPrivateApi"})
- private void fetchSetFrame() {
- if (!sSetFrameFetched) {
- try {
- sSetFrameMethod = View.class.getDeclaredMethod("setFrame",
- int.class, int.class, int.class, int.class);
- sSetFrameMethod.setAccessible(true);
- } catch (NoSuchMethodException e) {
- Log.i(TAG, "Failed to retrieve setFrame method", e);
- }
- sSetFrameFetched = true;
- }
- }
-
-}
diff --git a/transition/transition/src/main/java/androidx/transition/Visibility.java b/transition/transition/src/main/java/androidx/transition/Visibility.java
index 8b3fc2e..7b42e21 100644
--- a/transition/transition/src/main/java/androidx/transition/Visibility.java
+++ b/transition/transition/src/main/java/androidx/transition/Visibility.java
@@ -441,7 +441,7 @@
startView);
animator.addListener(listener);
- AnimatorUtils.addPauseListener(animator, listener);
+ animator.addPauseListener(listener);
getRootTransition().addListener(listener);
}
}
@@ -610,8 +610,7 @@
}
}
- private class OverlayListener extends AnimatorListenerAdapter implements TransitionListener,
- AnimatorUtils.AnimatorPauseListenerCompat {
+ private class OverlayListener extends AnimatorListenerAdapter implements TransitionListener {
private final ViewGroup mOverlayHost;
private final View mOverlayView;
private final View mStartView;
diff --git a/transition/transition/src/main/java/androidx/transition/WindowIdApi14.java b/transition/transition/src/main/java/androidx/transition/WindowIdApi14.java
deleted file mode 100644
index 6a9231e..0000000
--- a/transition/transition/src/main/java/androidx/transition/WindowIdApi14.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.transition;
-
-import android.os.IBinder;
-
-class WindowIdApi14 implements WindowIdImpl {
-
- private final IBinder mToken;
-
- WindowIdApi14(IBinder token) {
- mToken = token;
- }
-
- @Override
- public boolean equals(Object o) {
- return o instanceof WindowIdApi14 && ((WindowIdApi14) o).mToken.equals(this.mToken);
- }
-
- @Override
- public int hashCode() {
- return mToken.hashCode();
- }
-}
diff --git a/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/TextField.kt b/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/TextField.kt
index de4d6e1..7c71660 100644
--- a/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/TextField.kt
+++ b/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/TextField.kt
@@ -41,7 +41,7 @@
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import androidx.tv.foundation.ExperimentalTvFoundationApi
-import androidx.tv.foundation.text.AndroidImeOptions
+import androidx.tv.foundation.text.PlatformImeOptions
import androidx.tv.foundation.text.TvKeyboardAlignment
import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.MaterialTheme
@@ -87,7 +87,7 @@
},
keyboardOptions = KeyboardOptions(
keyboardType = keyboardType,
- platformImeOptions = AndroidImeOptions(TvKeyboardAlignment.Left),
+ platformImeOptions = PlatformImeOptions(TvKeyboardAlignment.Left),
imeAction = ImeAction.Next
),
colors = OutlinedTextFieldDefaults.colors(
diff --git a/tv/tv-foundation/api/current.txt b/tv/tv-foundation/api/current.txt
index 2049638..daa9a60 100644
--- a/tv/tv-foundation/api/current.txt
+++ b/tv/tv-foundation/api/current.txt
@@ -254,8 +254,8 @@
package androidx.tv.foundation.text {
public final class TvImeOptionsKt {
- method @SuppressCompatibility @androidx.tv.foundation.ExperimentalTvFoundationApi public static androidx.compose.ui.text.input.AndroidImeOptions AndroidImeOptions(androidx.tv.foundation.text.TvKeyboardAlignment horizontalAlignment);
- method @SuppressCompatibility @androidx.tv.foundation.ExperimentalTvFoundationApi public static androidx.compose.ui.text.input.AndroidImeOptions keyboardAlignment(androidx.compose.ui.text.input.AndroidImeOptions, androidx.tv.foundation.text.TvKeyboardAlignment horizontalAlignment);
+ method @SuppressCompatibility @androidx.tv.foundation.ExperimentalTvFoundationApi public static androidx.compose.ui.text.input.PlatformImeOptions PlatformImeOptions(androidx.tv.foundation.text.TvKeyboardAlignment horizontalAlignment);
+ method @SuppressCompatibility @androidx.tv.foundation.ExperimentalTvFoundationApi public static androidx.compose.ui.text.input.PlatformImeOptions keyboardAlignment(androidx.compose.ui.text.input.PlatformImeOptions, androidx.tv.foundation.text.TvKeyboardAlignment horizontalAlignment);
}
@SuppressCompatibility @androidx.tv.foundation.ExperimentalTvFoundationApi public enum TvKeyboardAlignment {
diff --git a/tv/tv-foundation/api/restricted_current.txt b/tv/tv-foundation/api/restricted_current.txt
index 2049638..daa9a60 100644
--- a/tv/tv-foundation/api/restricted_current.txt
+++ b/tv/tv-foundation/api/restricted_current.txt
@@ -254,8 +254,8 @@
package androidx.tv.foundation.text {
public final class TvImeOptionsKt {
- method @SuppressCompatibility @androidx.tv.foundation.ExperimentalTvFoundationApi public static androidx.compose.ui.text.input.AndroidImeOptions AndroidImeOptions(androidx.tv.foundation.text.TvKeyboardAlignment horizontalAlignment);
- method @SuppressCompatibility @androidx.tv.foundation.ExperimentalTvFoundationApi public static androidx.compose.ui.text.input.AndroidImeOptions keyboardAlignment(androidx.compose.ui.text.input.AndroidImeOptions, androidx.tv.foundation.text.TvKeyboardAlignment horizontalAlignment);
+ method @SuppressCompatibility @androidx.tv.foundation.ExperimentalTvFoundationApi public static androidx.compose.ui.text.input.PlatformImeOptions PlatformImeOptions(androidx.tv.foundation.text.TvKeyboardAlignment horizontalAlignment);
+ method @SuppressCompatibility @androidx.tv.foundation.ExperimentalTvFoundationApi public static androidx.compose.ui.text.input.PlatformImeOptions keyboardAlignment(androidx.compose.ui.text.input.PlatformImeOptions, androidx.tv.foundation.text.TvKeyboardAlignment horizontalAlignment);
}
@SuppressCompatibility @androidx.tv.foundation.ExperimentalTvFoundationApi public enum TvKeyboardAlignment {
diff --git a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/grid/LazyGridTest.kt b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/grid/LazyGridTest.kt
index 13b3fde..5a30ac2 100644
--- a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/grid/LazyGridTest.kt
+++ b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/grid/LazyGridTest.kt
@@ -59,7 +59,6 @@
import androidx.tv.foundation.lazy.list.setContentWithTestViewConfiguration
import com.google.common.collect.Range
import com.google.common.truth.IntegerSubject
-import com.google.common.truth.Truth
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.runBlocking
import org.junit.Test
@@ -71,6 +70,8 @@
class LazyGridTest(
private val orientation: Orientation
) : BaseLazyGridTestWithOrientation(orientation) {
+
+ @Suppress("PrivatePropertyName")
private val LazyGridTag = "LazyGridTag"
companion object {
@@ -148,7 +149,7 @@
}
}
- rule.keyPress(3)
+ rule.keyPress(2)
rule.onNodeWithTag("4")
.assertIsDisplayed()
@@ -670,9 +671,9 @@
state.scrollToItem(50)
}
composedIndexes.forEach {
- Truth.assertThat(it).isLessThan(count)
+ assertThat(it).isLessThan(count)
}
- Truth.assertThat(state.firstVisibleItemIndex).isEqualTo(9)
+ assertThat(state.firstVisibleItemIndex).isEqualTo(9)
}
}
@@ -723,7 +724,7 @@
}
}
- rule.keyPress(3)
+ rule.keyPress(2)
rule.onNodeWithTag("1")
.assertMainAxisStartPositionInRootIsEqualTo(0.dp)
@@ -891,7 +892,7 @@
}
rule.runOnIdle {
- Truth.assertThat(exception).isInstanceOf(IllegalArgumentException::class.java)
+ assertThat(exception).isInstanceOf(IllegalArgumentException::class.java)
}
}
@@ -922,17 +923,17 @@
}
rule.runOnIdle {
- Truth.assertThat(remeasureCount).isEqualTo(1)
+ assertThat(remeasureCount).isEqualTo(1)
counter.value++
}
rule.runOnIdle {
- Truth.assertThat(remeasureCount).isEqualTo(1)
+ assertThat(remeasureCount).isEqualTo(1)
}
}
@Test
- fun scrollingALotDoesntCauseLazyLayoutRecomposition() {
+ fun scrollingALotDoesNotCauseLazyLayoutRecomposition() {
var recomposeCount = 0
lateinit var state: TvLazyGridState
@@ -953,7 +954,7 @@
}
rule.runOnIdle {
- Truth.assertThat(recomposeCount).isEqualTo(1)
+ assertThat(recomposeCount).isEqualTo(1)
runBlocking {
state.scrollToItem(100)
@@ -961,7 +962,7 @@
}
rule.runOnIdle {
- Truth.assertThat(recomposeCount).isEqualTo(1)
+ assertThat(recomposeCount).isEqualTo(1)
}
}
diff --git a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/grid/LazyGridsReverseLayoutTest.kt b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/grid/LazyGridsReverseLayoutTest.kt
index 4d8ad86..196d022 100644
--- a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/grid/LazyGridsReverseLayoutTest.kt
+++ b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/grid/LazyGridsReverseLayoutTest.kt
@@ -34,16 +34,20 @@
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
import androidx.tv.foundation.lazy.list.setContentWithTestViewConfiguration
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
import org.junit.Test
+import org.junit.runner.RunWith
+private const val ContainerTag = "ContainerTag"
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
class LazyGridsReverseLayoutTest {
-
- private val ContainerTag = "ContainerTag"
-
@get:Rule
val rule = createComposeRule()
@@ -164,7 +168,7 @@
}
// we scroll down and as the scrolling is reversed it shouldn't affect anything
- rule.keyPress(NativeKeyEvent.KEYCODE_DPAD_UP, 2)
+ rule.keyPress(NativeKeyEvent.KEYCODE_DPAD_DOWN, 2)
rule.runOnIdle {
assertThat(state.firstVisibleItemScrollOffset).isEqualTo(0)
@@ -193,7 +197,7 @@
}
}
- rule.keyPress(NativeKeyEvent.KEYCODE_DPAD_DOWN, 2)
+ rule.keyPress(NativeKeyEvent.KEYCODE_DPAD_DOWN, 1)
val scrolled = rule.runOnIdle {
assertThat(state.firstVisibleItemScrollOffset).isGreaterThan(0)
diff --git a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyListTest.kt b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyListTest.kt
index baf2ba0..4fd6a16 100644
--- a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyListTest.kt
+++ b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyListTest.kt
@@ -93,8 +93,10 @@
@LargeTest
@RunWith(Parameterized::class)
class LazyListTest(orientation: Orientation) : BaseLazyListTestWithOrientation(orientation) {
+ @Suppress("PrivatePropertyName")
private val LazyListTag = "LazyListTag"
- private val firstItemTag = "firstItemTag"
+ @Suppress("PrivatePropertyName")
+ private val FirstItemTag = "firstItemTag"
@Test
fun lazyListShowsCombinedItems() {
@@ -243,7 +245,7 @@
}
}
- rule.keyPress(3)
+ rule.keyPress(2)
rule.onNodeWithTag("1")
.assertIsDisplayed()
@@ -274,7 +276,7 @@
}
}
- rule.keyPress(3)
+ rule.keyPress(2)
rule.onNodeWithTag("1")
.assertIsNotDisplayed()
@@ -306,7 +308,7 @@
}
}
- rule.keyPress(4)
+ rule.keyPress(3)
rule.onNodeWithTag("1")
.assertIsNotDisplayed()
@@ -463,7 +465,8 @@
}
}
- rule.keyPress(3)
+ rule.waitForIdle()
+ rule.keyPress(2)
rule.onNodeWithTag(thirdTag)
.assertExists()
@@ -487,13 +490,13 @@
LazyColumnOrRow(Modifier.requiredSize(width = 100.dp, height = 150.dp)) {
items(listOf(0)) {
Spacer(
- Modifier.fillParentMaxWidth().requiredHeight(50.dp).testTag(firstItemTag)
+ Modifier.fillParentMaxWidth().requiredHeight(50.dp).testTag(FirstItemTag)
)
}
}
}
- rule.onNodeWithTag(firstItemTag)
+ rule.onNodeWithTag(FirstItemTag)
.assertWidthIsEqualTo(100.dp)
.assertHeightIsEqualTo(50.dp)
}
@@ -504,13 +507,13 @@
LazyColumnOrRow(Modifier.requiredSize(width = 100.dp, height = 150.dp)) {
items(listOf(0)) {
Spacer(
- Modifier.requiredWidth(50.dp).fillParentMaxHeight().testTag(firstItemTag)
+ Modifier.requiredWidth(50.dp).fillParentMaxHeight().testTag(FirstItemTag)
)
}
}
}
- rule.onNodeWithTag(firstItemTag)
+ rule.onNodeWithTag(FirstItemTag)
.assertWidthIsEqualTo(50.dp)
.assertHeightIsEqualTo(150.dp)
}
@@ -520,12 +523,12 @@
rule.setContentWithTestViewConfiguration {
LazyColumnOrRow(Modifier.requiredSize(width = 100.dp, height = 150.dp)) {
items(listOf(0)) {
- Spacer(Modifier.fillParentMaxSize().testTag(firstItemTag))
+ Spacer(Modifier.fillParentMaxSize().testTag(FirstItemTag))
}
}
}
- rule.onNodeWithTag(firstItemTag)
+ rule.onNodeWithTag(FirstItemTag)
.assertWidthIsEqualTo(100.dp)
.assertHeightIsEqualTo(150.dp)
}
@@ -538,13 +541,13 @@
Spacer(
Modifier.fillParentMaxWidth(0.7f)
.requiredHeight(50.dp)
- .testTag(firstItemTag)
+ .testTag(FirstItemTag)
)
}
}
}
- rule.onNodeWithTag(firstItemTag)
+ rule.onNodeWithTag(FirstItemTag)
.assertWidthIsEqualTo(70.dp)
.assertHeightIsEqualTo(50.dp)
}
@@ -557,13 +560,13 @@
Spacer(
Modifier.requiredWidth(50.dp)
.fillParentMaxHeight(0.3f)
- .testTag(firstItemTag)
+ .testTag(FirstItemTag)
)
}
}
}
- rule.onNodeWithTag(firstItemTag)
+ rule.onNodeWithTag(FirstItemTag)
.assertWidthIsEqualTo(50.dp)
.assertHeightIsEqualTo(45.dp)
}
@@ -573,12 +576,12 @@
rule.setContentWithTestViewConfiguration {
LazyColumnOrRow(Modifier.requiredSize(width = 100.dp, height = 150.dp)) {
items(listOf(0)) {
- Spacer(Modifier.fillParentMaxSize(0.5f).testTag(firstItemTag))
+ Spacer(Modifier.fillParentMaxSize(0.5f).testTag(FirstItemTag))
}
}
}
- rule.onNodeWithTag(firstItemTag)
+ rule.onNodeWithTag(FirstItemTag)
.assertWidthIsEqualTo(50.dp)
.assertHeightIsEqualTo(75.dp)
}
@@ -589,7 +592,7 @@
rule.setContentWithTestViewConfiguration {
LazyColumnOrRow(Modifier.requiredSize(parentSize)) {
items(listOf(0)) {
- Spacer(Modifier.fillParentMaxSize().testTag(firstItemTag))
+ Spacer(Modifier.fillParentMaxSize().testTag(FirstItemTag))
}
}
}
@@ -598,7 +601,7 @@
parentSize = 150.dp
}
- rule.onNodeWithTag(firstItemTag)
+ rule.onNodeWithTag(FirstItemTag)
.assertWidthIsEqualTo(150.dp)
.assertHeightIsEqualTo(150.dp)
}
@@ -752,6 +755,8 @@
}
}
+ rule.waitForIdle()
+
// getting focus to the first element
rule.keyPress(2)
// we already displaying the first item, so this should do nothing
@@ -1066,12 +1071,10 @@
) {
items(items) {
Spacer(
- if (it == 0) {
- Modifier.crossAxisSize(30.dp).mainAxisSize(itemSize / 2)
- } else if (it == 1) {
- Modifier.crossAxisSize(20.dp).mainAxisSize(itemSize / 2)
- } else {
- Modifier.crossAxisSize(20.dp).mainAxisSize(itemSize)
+ when (it) {
+ 0 -> Modifier.crossAxisSize(30.dp).mainAxisSize(itemSize / 2)
+ 1 -> Modifier.crossAxisSize(20.dp).mainAxisSize(itemSize / 2)
+ else -> Modifier.crossAxisSize(20.dp).mainAxisSize(itemSize)
}
)
}
@@ -1161,7 +1164,7 @@
}
@Test
- fun overscrollingBackwardFromNotTheFirstPosition() {
+ fun overScrollingBackwardFromNotTheFirstPosition() {
val containerTag = "container"
val itemSizePx = 10
val itemSizeDp = with(rule.density) { itemSizePx.toDp() }
@@ -1513,7 +1516,7 @@
}
}
- rule.keyPress(3)
+ rule.keyPress(2)
rule.onNodeWithTag("1")
.assertStartPositionInRootIsEqualTo(0.dp)
@@ -1687,7 +1690,7 @@
}
@Test
- fun scrollingALotDoesntCauseLazyLayoutRecomposition() {
+ fun scrollingALotDoesNotCauseLazyLayoutRecomposition() {
var recomposeCount = 0
lateinit var state: TvLazyListState
@@ -1759,8 +1762,8 @@
Box(Modifier.fillParentMaxSize())
}
}
- }) { measurables, _ ->
- val placeable = measurables.first().measure(constraints)
+ }) { measurableList, _ ->
+ val placeable = measurableList.first().measure(constraints)
layout(constraints.maxWidth, constraints.maxHeight) {
placeable.place(0, 0)
}
@@ -1789,13 +1792,13 @@
.testTag("item"))
}
}
- }) { measurables, _ ->
+ }) { measurableList, _ ->
val crossInfinityConstraints = if (vertical) {
Constraints(maxWidth = Constraints.Infinity, maxHeight = 100)
} else {
Constraints(maxWidth = 100, maxHeight = Constraints.Infinity)
}
- val placeable = measurables.first().measure(crossInfinityConstraints)
+ val placeable = measurableList.first().measure(crossInfinityConstraints)
layout(placeable.width, placeable.height) {
placeable.place(0, 0)
}
diff --git a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyListsReverseLayoutTest.kt b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyListsReverseLayoutTest.kt
index 4ec7ab7..32ee3a2 100644
--- a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyListsReverseLayoutTest.kt
+++ b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyListsReverseLayoutTest.kt
@@ -34,15 +34,22 @@
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.MediumTest
import androidx.tv.foundation.PivotOffsets
import androidx.tv.foundation.lazy.grid.keyPress
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
import org.junit.Test
+import org.junit.runner.RunWith
+@MediumTest
+@RunWith(AndroidJUnit4::class)
class LazyListsReverseLayoutTest {
+ @Suppress("PrivatePropertyName")
private val ContainerTag = "ContainerTag"
@get:Rule
@@ -151,6 +158,7 @@
.assertTopPositionInRootIsEqualTo(itemSize)
}
+ @FlakyTest(bugId = 313465577)
@Test
fun column_scrollForwardHalfWay() {
lateinit var state: TvLazyListState
@@ -167,7 +175,7 @@
}
}
- rule.keyPress(NativeKeyEvent.KEYCODE_DPAD_UP, 3)
+ rule.keyPress(NativeKeyEvent.KEYCODE_DPAD_UP, 1)
val scrolled = rule.runOnIdle {
assertThat(state.firstVisibleItemIndex).isEqualTo(0)
@@ -310,6 +318,7 @@
.assertLeftPositionInRootIsEqualTo(itemSize)
}
+ @FlakyTest(bugId = 313465577)
@Test
fun row_scrollForwardHalfWay() {
lateinit var state: TvLazyListState
@@ -326,7 +335,7 @@
}
}
- rule.keyPress(NativeKeyEvent.KEYCODE_DPAD_LEFT, 3)
+ rule.keyPress(NativeKeyEvent.KEYCODE_DPAD_LEFT, 1)
val scrolled = rule.runOnIdle {
assertThat(state.firstVisibleItemScrollOffset).isGreaterThan(0)
@@ -438,7 +447,7 @@
}
}
- rule.keyPress(NativeKeyEvent.KEYCODE_DPAD_RIGHT, 3)
+ rule.keyPress(NativeKeyEvent.KEYCODE_DPAD_RIGHT, 2)
val scrolled = rule.runOnIdle {
assertThat(state.firstVisibleItemScrollOffset).isGreaterThan(0)
diff --git a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyRowTest.kt b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyRowTest.kt
index 0817a21..8ae3f7d 100644
--- a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyRowTest.kt
+++ b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyRowTest.kt
@@ -46,6 +46,7 @@
@MediumTest
@RunWith(AndroidJUnit4::class)
class LazyRowTest {
+ @Suppress("PrivatePropertyName")
private val LazyListTag = "LazyListTag"
@get:Rule
@@ -144,7 +145,7 @@
}
}
- rule.keyPress(NativeKeyEvent.KEYCODE_DPAD_LEFT, 3)
+ rule.keyPress(NativeKeyEvent.KEYCODE_DPAD_LEFT, 2)
rule.runOnIdle {
assertThat(state.firstVisibleItemIndex).isEqualTo(1)
diff --git a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/text/TvImeOptionsTest.kt b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/text/TvImeOptionsTest.kt
index 7a29001..c77b930 100644
--- a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/text/TvImeOptionsTest.kt
+++ b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/text/TvImeOptionsTest.kt
@@ -16,7 +16,7 @@
package androidx.tv.foundation.text
-import androidx.compose.ui.text.input.AndroidImeOptions
+import androidx.compose.ui.text.input.PlatformImeOptions
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import androidx.tv.foundation.ExperimentalTvFoundationApi
@@ -32,7 +32,7 @@
fun privateImeOptions_keyboardAlignment() {
val privateImeOptions = "testOptions"
val keyboardAlignment = TvKeyboardAlignment.Left
- val imeOptions = AndroidImeOptions(privateImeOptions).keyboardAlignment(keyboardAlignment)
+ val imeOptions = PlatformImeOptions(privateImeOptions).keyboardAlignment(keyboardAlignment)
assertThat(
imeOptions.privateImeOptions == "$privateImeOptions,${keyboardAlignment.option}"
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/text/TvImeOptions.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/text/TvImeOptions.kt
index 135534a..da6e10b 100644
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/text/TvImeOptions.kt
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/text/TvImeOptions.kt
@@ -16,7 +16,7 @@
package androidx.tv.foundation.text
-import androidx.compose.ui.text.input.AndroidImeOptions
+import androidx.compose.ui.text.input.PlatformImeOptions
import androidx.tv.foundation.ExperimentalTvFoundationApi
/**
@@ -28,9 +28,9 @@
* keyboard.
*/
@ExperimentalTvFoundationApi
-fun AndroidImeOptions(
+fun PlatformImeOptions(
horizontalAlignment: TvKeyboardAlignment
-) = AndroidImeOptions(horizontalAlignment.option)
+) = PlatformImeOptions(horizontalAlignment.option)
/**
* Adds the keyboard alignment option to the private IME configuration options.
@@ -41,12 +41,12 @@
* keyboard.
*/
@ExperimentalTvFoundationApi
-fun AndroidImeOptions.keyboardAlignment(
+fun PlatformImeOptions.keyboardAlignment(
horizontalAlignment: TvKeyboardAlignment
-): AndroidImeOptions {
+): PlatformImeOptions {
val privateImeOptions =
if (!privateImeOptions.isNullOrBlank()) this.privateImeOptions + "," else ""
- return AndroidImeOptions(privateImeOptions + horizontalAlignment.option)
+ return PlatformImeOptions(privateImeOptions + horizontalAlignment.option)
}
/**
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/SurfaceTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/SurfaceTest.kt
index a39c580..e8223a2 100644
--- a/tv/tv-material/src/androidTest/java/androidx/tv/material3/SurfaceTest.kt
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/SurfaceTest.kt
@@ -21,6 +21,7 @@
import android.view.KeyEvent
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
+import androidx.compose.foundation.focusable
import androidx.compose.foundation.interaction.FocusInteraction
import androidx.compose.foundation.interaction.Interaction
import androidx.compose.foundation.interaction.MutableInteractionSource
@@ -28,13 +29,16 @@
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -516,7 +520,7 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
@Test
fun clickableSurface_onFocus_changesGlowColor() {
- rule.setContent {
+ rule.setFocusableContent {
Surface(
modifier = Modifier
.testTag("surface")
@@ -926,8 +930,8 @@
@Test
fun toggleableSurface_onCheckedChange_changesGlowColor() {
var isChecked by mutableStateOf(false)
- var focusManager: FocusManager? = null
- rule.setContent {
+ lateinit var focusManager: FocusManager
+ rule.setFocusableContent {
focusManager = LocalFocusManager.current
Surface(
checked = isChecked,
@@ -960,7 +964,7 @@
.performKeyInput { pressKey(Key.DirectionCenter) }
// Remove focused state to reveal selected state
- focusManager?.clearFocus()
+ rule.runOnUiThread { focusManager.clearFocus() }
rule.onNodeWithTag("surface")
.captureToImage()
@@ -971,8 +975,8 @@
@Test
fun toggleableSurface_onCheckedChange_changesScaleFactor() {
var isChecked by mutableStateOf(false)
- var focusManager: FocusManager? = null
- rule.setContent {
+ lateinit var focusManager: FocusManager
+ rule.setFocusableContent {
focusManager = LocalFocusManager.current
Box(
modifier = Modifier
@@ -997,7 +1001,7 @@
.performKeyInput { pressKey(Key.DirectionCenter) }
// Remove focused state to reveal selected state
- focusManager?.clearFocus()
+ rule.runOnUiThread { focusManager.clearFocus() }
rule.onRoot().captureToImage().assertDoesNotContainColor(Color.Blue)
}
@@ -1006,8 +1010,8 @@
@Test
fun toggleableSurface_onCheckedChange_showsOutline() {
var isChecked by mutableStateOf(false)
- var focusManager: FocusManager? = null
- rule.setContent {
+ lateinit var focusManager: FocusManager
+ rule.setFocusableContent {
focusManager = LocalFocusManager.current
Surface(
checked = isChecked,
@@ -1036,7 +1040,9 @@
.performKeyInput { pressKey(Key.DirectionCenter) }
// Remove focused state to reveal selected state
- focusManager?.clearFocus()
+ rule.runOnUiThread { focusManager.clearFocus() }
+
+ rule.waitForIdle()
surface.captureToImage().assertContainsColor(Color.Magenta)
}
@@ -1073,7 +1079,7 @@
val clickableItemTag = "clickable-item"
val toggleableItemTag = "toggleable-item"
val rootElementTag = "root"
- var focusManager: FocusManager? = null
+ lateinit var focusManager: FocusManager
rule.setContent {
// arrange
@@ -1147,7 +1153,7 @@
// blue border shouldn't be visible
rootEl.captureToImage().assertDoesNotContainColor(Color.Blue)
- focusManager?.moveFocus(FocusDirection.Down)
+ focusManager.moveFocus(FocusDirection.Down)
rule.waitForIdle()
// blue border should be visible
@@ -1158,7 +1164,7 @@
.performSemanticsAction(SemanticsActions.OnClick)
rule.waitForIdle()
- focusManager?.moveFocus(FocusDirection.Up)
+ focusManager.moveFocus(FocusDirection.Up)
rule.waitForIdle()
// blue border shouldn't be visible
@@ -1207,8 +1213,7 @@
rule
.onNodeWithTag(containerTag)
.captureToImage()
- .toPixelMap(0, 0, 1, 1)
- .get(0, 0) == Color.White
+ .toPixelMap(0, 0, 1, 1)[0, 0] == Color.White
)
rule.onNodeWithTag(surfaceTag).requestFocus()
@@ -1219,8 +1224,7 @@
rule
.onNodeWithTag(containerTag)
.captureToImage()
- .toPixelMap(0, 0, 1, 1)
- .get(0, 0) == Color.Red
+ .toPixelMap(0, 0, 1, 1)[0, 0] == Color.Red
)
}
}
@@ -1258,3 +1262,29 @@
}
return this
}
+
+/**
+ * This function adds a parent composable which has size.
+ * [View.requestFocus()][android.view.View.requestFocus] will not take focus if the view has no
+ * size.
+ *
+ * @param extraItemForInitialFocus Includes an extra item that takes focus initially. This is
+ * useful in cases where we need tests that could be affected by initial focus. Eg. When there is
+ * only one focusable item and we clear focus, that item could end up being focused on again by the
+ * initial focus logic.
+ */
+private fun ComposeContentTestRule.setFocusableContent(
+ extraItemForInitialFocus: Boolean = true,
+ content: @Composable () -> Unit
+) {
+ setContent {
+ if (extraItemForInitialFocus) {
+ Row {
+ Box(modifier = Modifier.requiredSize(10.dp, 10.dp).focusable())
+ Box(modifier = Modifier.requiredSize(100.dp, 100.dp)) { content() }
+ }
+ } else {
+ Box(modifier = Modifier.requiredSize(100.dp, 100.dp)) { content() }
+ }
+ }
+}
diff --git a/vectordrawable/vectordrawable/src/main/java/androidx/vectordrawable/graphics/drawable/VectorDrawableCompat.java b/vectordrawable/vectordrawable/src/main/java/androidx/vectordrawable/graphics/drawable/VectorDrawableCompat.java
index 2b8df02..2ae01e1 100644
--- a/vectordrawable/vectordrawable/src/main/java/androidx/vectordrawable/graphics/drawable/VectorDrawableCompat.java
+++ b/vectordrawable/vectordrawable/src/main/java/androidx/vectordrawable/graphics/drawable/VectorDrawableCompat.java
@@ -918,12 +918,8 @@
// We don't support RTL auto mirroring since the getLayoutDirection() is for API 17+.
private boolean needMirroring() {
- if (Build.VERSION.SDK_INT >= 17) {
- return isAutoMirrored()
- && DrawableCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL;
- } else {
- return false;
- }
+ return isAutoMirrored()
+ && DrawableCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL;
}
// Extra override functions for delegation for SDK >= 7.
diff --git a/viewpager2/integration-tests/testapp/src/main/java/androidx/viewpager2/integration/testapp/MutableCollectionBaseActivity.kt b/viewpager2/integration-tests/testapp/src/main/java/androidx/viewpager2/integration/testapp/MutableCollectionBaseActivity.kt
index 2f3ca9d..46f34c1 100644
--- a/viewpager2/integration-tests/testapp/src/main/java/androidx/viewpager2/integration/testapp/MutableCollectionBaseActivity.kt
+++ b/viewpager2/integration-tests/testapp/src/main/java/androidx/viewpager2/integration/testapp/MutableCollectionBaseActivity.kt
@@ -16,7 +16,6 @@
package androidx.viewpager2.integration.testapp
-import android.os.Build
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
@@ -61,9 +60,7 @@
itemSpinner.adapter = object : BaseAdapter() {
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View =
((convertView as TextView?) ?: TextView(parent.context)).apply {
- if (Build.VERSION.SDK_INT >= 17) {
- textDirection = View.TEXT_DIRECTION_LOCALE
- }
+ textDirection = View.TEXT_DIRECTION_LOCALE
text = getItem(position)
}
diff --git a/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AccessibilityTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AccessibilityTest.kt
index 2abc406..9e64aee 100644
--- a/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AccessibilityTest.kt
+++ b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AccessibilityTest.kt
@@ -57,10 +57,8 @@
localeUtil.resetLocale()
localeUtil.setLocale(LocaleTestUtils.RTL_LANGUAGE)
}
- if (Build.VERSION.SDK_INT >= 18) {
- // Make sure accessibility is enabled (side effect of creating a UI Automator instance)
- uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
- }
+ // Make sure accessibility is enabled (side effect of creating a UI Automator instance)
+ uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
}
override fun tearDown() {
diff --git a/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt
index aaa96c9..721e6f1 100644
--- a/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt
+++ b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt
@@ -20,7 +20,6 @@
import android.os.Build
import android.util.Log
import android.view.View
-import android.view.View.OVER_SCROLL_NEVER
import android.view.ViewConfiguration
import android.view.accessibility.AccessibilityNodeInfo
import androidx.core.view.ViewCompat
@@ -73,7 +72,6 @@
import org.hamcrest.Matchers.lessThan
import org.hamcrest.Matchers.lessThanOrEqualTo
import org.junit.After
-import org.junit.Assert.fail
import org.junit.Before
import org.junit.Rule
@@ -125,11 +123,6 @@
}
onView(withId(R.id.view_pager)).check(matches(isDisplayed()))
- // animations getting in the way on API < 16
- if (Build.VERSION.SDK_INT < 16) {
- viewPager.recyclerView.overScrollMode = OVER_SCROLL_NEVER
- }
-
return Context(activityTestRule)
}
@@ -303,13 +296,9 @@
isUserInputEnabled && isVerticalOrientation &&
currentPage < numPages - 1
- val expectScrollBackwardAction =
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && isUserInputEnabled &&
- currentPage > 0
+ val expectScrollBackwardAction = isUserInputEnabled && currentPage > 0
- val expectScrollForwardAction =
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && isUserInputEnabled &&
- currentPage < numPages - 1
+ val expectScrollForwardAction = isUserInputEnabled && currentPage < numPages - 1
assertThat(
"Left action expected: $expectPageLeftAction",
@@ -734,11 +723,7 @@
if (i < n - 1) {
Log.w(BaseTest.TAG, "Bad state, retrying block", e)
} else {
- val errorMessage = "Block hit bad state $n times"
- when {
- Build.VERSION.SDK_INT >= 19 -> throw AssertionError(errorMessage, e)
- else -> fail(errorMessage)
- }
+ throw AssertionError("Block hit bad state $n times", e)
}
resetBlock()
}
diff --git a/wear/benchmark/integration-tests/macrobenchmark-target/build.gradle b/wear/benchmark/integration-tests/macrobenchmark-target/build.gradle
index f24e3ef..54fcef0 100644
--- a/wear/benchmark/integration-tests/macrobenchmark-target/build.gradle
+++ b/wear/benchmark/integration-tests/macrobenchmark-target/build.gradle
@@ -42,5 +42,5 @@
implementation 'androidx.core:core-ktx'
implementation(libs.material)
implementation(project(":profileinstaller:profileinstaller"))
- implementation 'androidx.wear:wear:1.1.0'
+ implementation 'androidx.wear:wear:1.3.0'
}
diff --git a/wear/compose/compose-foundation/src/androidTest/kotlin/androidx/wear/compose/foundation/HierarchicalFocusCoordinatorTest.kt b/wear/compose/compose-foundation/src/androidTest/kotlin/androidx/wear/compose/foundation/HierarchicalFocusCoordinatorTest.kt
index 53be515..3d55748 100644
--- a/wear/compose/compose-foundation/src/androidTest/kotlin/androidx/wear/compose/foundation/HierarchicalFocusCoordinatorTest.kt
+++ b/wear/compose/compose-foundation/src/androidTest/kotlin/androidx/wear/compose/foundation/HierarchicalFocusCoordinatorTest.kt
@@ -170,7 +170,7 @@
val selected = mutableStateOf(0)
var focused = false
rule.setContent {
- Box {
+ Box(Modifier.focusable()) {
HierarchicalFocusCoordinator({ selected.value == 0 }) {
FocusableTestItem { focused = it }
}
diff --git a/wear/compose/compose-ui-tooling/build.gradle b/wear/compose/compose-ui-tooling/build.gradle
index c31d84f..4d68f5b 100644
--- a/wear/compose/compose-ui-tooling/build.gradle
+++ b/wear/compose/compose-ui-tooling/build.gradle
@@ -28,7 +28,7 @@
implementation(libs.kotlinStdlibCommon)
implementation(project(":compose:ui:ui-tooling-preview"))
- implementation("androidx.wear:wear-tooling-preview:1.0.0-beta01")
+ implementation("androidx.wear:wear-tooling-preview:1.0.0")
samples(project(":wear:compose:compose-material-samples"))
}
diff --git a/wear/compose/integration-tests/demos/src/androidTest/java/androidx/wear/compose/integration/demos/test/DemoTest.kt b/wear/compose/integration-tests/demos/src/androidTest/java/androidx/wear/compose/integration/demos/test/DemoTest.kt
index 79fd99f..8b9b0288 100644
--- a/wear/compose/integration-tests/demos/src/androidTest/java/androidx/wear/compose/integration/demos/test/DemoTest.kt
+++ b/wear/compose/integration-tests/demos/src/androidTest/java/androidx/wear/compose/integration/demos/test/DemoTest.kt
@@ -17,7 +17,6 @@
package androidx.wear.compose.integration.demos.test
import android.util.Log
-import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.SemanticsNodeInteractionCollection
import androidx.compose.ui.test.hasClickAction
import androidx.compose.ui.test.hasScrollToNodeAction
@@ -47,7 +46,6 @@
// given the use of ScalingLAZYColumn.
@LargeTest
@RunWith(AndroidJUnit4::class)
-@OptIn(ExperimentalTestApi::class)
class DemoTest {
// We need to provide the recompose factory first to use new clock.
@get:Rule
@@ -152,16 +150,18 @@
private fun clearFocusFromDemo() {
with(rule.activity) {
- if (hostView.hasFocus()) {
- if (hostView.isFocused) {
- // One of the Compose components has focus.
- focusManager.clearFocus(force = true)
- } else {
- // A child view has focus. (View interop scenario).
- // We could also use hostViewGroup.focusedChild?.clearFocus(), but the
- // interop views might end up being focused if one of them is marked as
- // focusedByDefault. So we clear focus by requesting focus on the owner.
- rule.runOnUiThread { hostView.requestFocus() }
+ rule.runOnUiThread {
+ if (hostView.hasFocus()) {
+ if (hostView.isFocused) {
+ // One of the Compose components has focus.
+ focusManager.clearFocus(force = true)
+ } else {
+ // A child view has focus. (View interop scenario).
+ // We could also use hostViewGroup.focusedChild?.clearFocus(), but the
+ // interop views might end up being focused if one of them is marked as
+ // focusedByDefault. So we clear focus by requesting focus on the owner.
+ hostView.requestFocus()
+ }
}
}
}
@@ -191,13 +191,13 @@
val newPath = path + this
return DemoCategory(
title,
- demos.mapNotNull {
- when (it) {
+ demos.mapNotNull { demo ->
+ when (demo) {
is DemoCategory -> {
- it.filter(newPath, predicate).let { if (it.demos.isEmpty()) null else it }
+ demo.filter(newPath, predicate).let { if (it.demos.isEmpty()) null else it }
}
else -> {
- if (predicate(newPath, it)) it else null
+ if (predicate(newPath, demo)) demo else null
}
}
}
diff --git a/wear/protolayout/protolayout-expression/api/current.txt b/wear/protolayout/protolayout-expression/api/current.txt
index ace57b9..f309942 100644
--- a/wear/protolayout/protolayout-expression/api/current.txt
+++ b/wear/protolayout/protolayout-expression/api/current.txt
@@ -200,13 +200,13 @@
method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=300) public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicInstant from(androidx.wear.protolayout.expression.DynamicDataKey<androidx.wear.protolayout.expression.DynamicBuilders.DynamicInstant!>);
method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicInstant fromByteArray(byte[]);
method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicInstant fromByteArray(byte[], int, int);
- method @RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getDayOfMonth(java.time.ZoneId);
- method @RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getDayOfWeek(java.time.ZoneId);
- method @RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getHour(java.time.ZoneId);
- method @RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getMinute(java.time.ZoneId);
- method @RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getMonth(java.time.ZoneId);
- method @RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getSecond(java.time.ZoneId);
- method @RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getYear(java.time.ZoneId);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=300) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getDayOfMonth(java.time.ZoneId);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=300) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getDayOfWeek(java.time.ZoneId);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=300) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getHour(java.time.ZoneId);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=300) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getMinute(java.time.ZoneId);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=300) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getMonth(java.time.ZoneId);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=300) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getSecond(java.time.ZoneId);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=300) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getYear(java.time.ZoneId);
method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public static androidx.wear.protolayout.expression.ConditionScopes.ConditionScope<androidx.wear.protolayout.expression.DynamicBuilders.DynamicInstant!,java.time.Instant!> onCondition(androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool);
method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicInstant platformTimeWithSecondsPrecision();
method public default byte[] toDynamicInstantByteArray();
@@ -389,7 +389,8 @@
public final class VersionBuilders {
}
- @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public static final class VersionBuilders.VersionInfo {
+ @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public static final class VersionBuilders.VersionInfo implements java.lang.Comparable<androidx.wear.protolayout.expression.VersionBuilders.VersionInfo> {
+ method public int compareTo(androidx.wear.protolayout.expression.VersionBuilders.VersionInfo);
method public int getMajor();
method public int getMinor();
}
diff --git a/wear/protolayout/protolayout-expression/api/restricted_current.txt b/wear/protolayout/protolayout-expression/api/restricted_current.txt
index ace57b9..f309942 100644
--- a/wear/protolayout/protolayout-expression/api/restricted_current.txt
+++ b/wear/protolayout/protolayout-expression/api/restricted_current.txt
@@ -200,13 +200,13 @@
method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=300) public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicInstant from(androidx.wear.protolayout.expression.DynamicDataKey<androidx.wear.protolayout.expression.DynamicBuilders.DynamicInstant!>);
method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicInstant fromByteArray(byte[]);
method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicInstant fromByteArray(byte[], int, int);
- method @RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getDayOfMonth(java.time.ZoneId);
- method @RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getDayOfWeek(java.time.ZoneId);
- method @RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getHour(java.time.ZoneId);
- method @RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getMinute(java.time.ZoneId);
- method @RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getMonth(java.time.ZoneId);
- method @RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getSecond(java.time.ZoneId);
- method @RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getYear(java.time.ZoneId);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=300) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getDayOfMonth(java.time.ZoneId);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=300) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getDayOfWeek(java.time.ZoneId);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=300) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getHour(java.time.ZoneId);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=300) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getMinute(java.time.ZoneId);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=300) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getMonth(java.time.ZoneId);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=300) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getSecond(java.time.ZoneId);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=300) public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 getYear(java.time.ZoneId);
method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public static androidx.wear.protolayout.expression.ConditionScopes.ConditionScope<androidx.wear.protolayout.expression.DynamicBuilders.DynamicInstant!,java.time.Instant!> onCondition(androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool);
method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicInstant platformTimeWithSecondsPrecision();
method public default byte[] toDynamicInstantByteArray();
@@ -389,7 +389,8 @@
public final class VersionBuilders {
}
- @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public static final class VersionBuilders.VersionInfo {
+ @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public static final class VersionBuilders.VersionInfo implements java.lang.Comparable<androidx.wear.protolayout.expression.VersionBuilders.VersionInfo> {
+ method public int compareTo(androidx.wear.protolayout.expression.VersionBuilders.VersionInfo);
method public int getMajor();
method public int getMinor();
}
diff --git a/wear/protolayout/protolayout-expression/build.gradle b/wear/protolayout/protolayout-expression/build.gradle
index 599d2a9..909c7ee 100644
--- a/wear/protolayout/protolayout-expression/build.gradle
+++ b/wear/protolayout/protolayout-expression/build.gradle
@@ -29,6 +29,9 @@
implementation("androidx.collection:collection:1.2.0")
implementation(project(path: ":wear:protolayout:protolayout-proto", configuration: "shadow"))
+ lintChecks(project(":wear:protolayout:protolayout-lint"))
+ lintPublish(project(":wear:protolayout:protolayout-lint"))
+
testImplementation(libs.testExtJunit)
testImplementation(libs.testExtTruth)
testImplementation(libs.testRunner)
diff --git a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicBuilders.java b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicBuilders.java
index cfcaa20..904183f 100644
--- a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicBuilders.java
+++ b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicBuilders.java
@@ -26,7 +26,6 @@
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
import androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec;
@@ -6832,7 +6831,7 @@
* .getYear(ZoneId.of("Europe/London"));
* </pre>
*/
- @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @RequiresSchemaVersion(major=1,minor=300)
@NonNull
default DynamicInt32 getYear(@NonNull ZoneId zoneId) {
return this.atZone(zoneId).getYear();
@@ -6847,7 +6846,7 @@
* .getMonth(ZoneId.of("Europe/London"));
* </pre>
*/
- @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @RequiresSchemaVersion(major=1,minor=300)
@NonNull
default DynamicInt32 getMonth(@NonNull ZoneId zoneId) {
return this.atZone(zoneId).getMonth();
@@ -6862,7 +6861,7 @@
* .getDayOfMonth(ZoneId.of("Europe/London"));
* </pre>
*/
- @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @RequiresSchemaVersion(major=1,minor=300)
@NonNull
default DynamicInt32 getDayOfMonth(@NonNull ZoneId zoneId) {
return this.atZone(zoneId).getDayOfMonth();
@@ -6878,7 +6877,7 @@
* .getDayOfWeek(ZoneId.of("Europe/London"));
* </pre>
*/
- @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @RequiresSchemaVersion(major=1,minor=300)
@NonNull
default DynamicInt32 getDayOfWeek(@NonNull ZoneId zoneId) {
return this.atZone(zoneId).getDayOfWeek();
@@ -6893,7 +6892,7 @@
* .getHour(ZoneId.of("Europe/London"));
* </pre>
*/
- @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @RequiresSchemaVersion(major=1,minor=300)
@NonNull
default DynamicInt32 getHour(@NonNull ZoneId zoneId) {
return this.atZone(zoneId).getHour();
@@ -6908,7 +6907,7 @@
* .getMinute(ZoneId.of("Europe/London"));
* </pre>
*/
- @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @RequiresSchemaVersion(major=1,minor=300)
@NonNull
default DynamicInt32 getMinute(@NonNull ZoneId zoneId) {
return this.atZone(zoneId).getMinute();
@@ -6923,7 +6922,7 @@
* .getSecond(ZoneId.of("Europe/London"));
* </pre>
*/
- @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @RequiresSchemaVersion(major=1,minor=300)
@NonNull
default DynamicInt32 getSecond(@NonNull ZoneId zoneId) {
return this.atZone(zoneId).getSecond();
diff --git a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/RequiresSchemaVersion.java b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/RequiresSchemaVersion.java
index e5a748e..6041b9f 100644
--- a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/RequiresSchemaVersion.java
+++ b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/RequiresSchemaVersion.java
@@ -27,7 +27,13 @@
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
-/** Indicates the minimum schema version the annotated type is supported at. */
+/**
+ * Indicates the minimum schema version the annotated type is supported at. {@link #major()} and
+ * {@link #minor()} correspond to {@link VersionBuilders.VersionInfo#getMajor()} and {@link
+ * VersionBuilders.VersionInfo#getMinor()} values reported by renderers/evaluators of ProtoLayout.
+ *
+ * <p>Note that {@link #minor()} version is usually in the form of {@code x00} such as 100, 200, ...
+ */
@MustBeDocumented
@Retention(CLASS)
@Target({TYPE, METHOD, CONSTRUCTOR, FIELD})
diff --git a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/VersionBuilders.java b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/VersionBuilders.java
index 56d8c841..7c0196c 100644
--- a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/VersionBuilders.java
+++ b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/VersionBuilders.java
@@ -22,6 +22,8 @@
import androidx.annotation.RestrictTo.Scope;
import androidx.wear.protolayout.expression.proto.VersionProto;
+import java.util.Objects;
+
/** Builders for the schema version information of a layout (or an expression). */
public final class VersionBuilders {
private VersionBuilders() {}
@@ -31,7 +33,7 @@
* layout).
*/
@RequiresSchemaVersion(major = 1, minor = 0)
- public static final class VersionInfo {
+ public static final class VersionInfo implements Comparable<VersionInfo> {
private final VersionProto.VersionInfo mImpl;
@Nullable private final Fingerprint mFingerprint;
@@ -94,6 +96,28 @@
return "VersionInfo{" + "major=" + getMajor() + ", minor=" + getMinor() + "}";
}
+ @Override
+ public int compareTo(@NonNull VersionInfo other) {
+ if (this.getMajor() == other.getMajor()) {
+ return Integer.compare(this.getMinor(), other.getMinor());
+ }
+ return Integer.compare(this.getMajor(), other.getMajor());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getMajor(), getMinor());
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (obj instanceof VersionInfo) {
+ VersionInfo that = (VersionInfo) obj;
+ return this.getMajor() == that.getMajor() && this.getMinor() == that.getMinor();
+ }
+ return false;
+ }
+
/** Builder for {@link VersionInfo} */
public static final class Builder {
private final VersionProto.VersionInfo.Builder mImpl =
diff --git a/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/VersionInfoTest.java b/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/VersionInfoTest.java
index cc5c2b8..6ae2b23 100644
--- a/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/VersionInfoTest.java
+++ b/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/VersionInfoTest.java
@@ -18,10 +18,16 @@
import static com.google.common.truth.Truth.assertThat;
+import androidx.wear.protolayout.expression.VersionBuilders.VersionInfo;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
@RunWith(RobolectricTestRunner.class)
public final class VersionInfoTest {
@Test
@@ -29,10 +35,22 @@
int major = 10;
int minor = 20;
- VersionBuilders.VersionInfo versionInfo =
- new VersionBuilders.VersionInfo.Builder().setMajor(major).setMinor(minor).build();
+ VersionInfo versionInfo = new VersionInfo.Builder().setMajor(major).setMinor(minor).build();
assertThat(versionInfo.toProto().getMajor()).isEqualTo(major);
assertThat(versionInfo.toProto().getMinor()).isEqualTo(minor);
}
+
+ @Test
+ public void versionInfoComparison() {
+ VersionInfo v1_0 = new VersionInfo.Builder().setMajor(1).setMinor(0).build();
+ VersionInfo v1_1 = new VersionInfo.Builder().setMajor(1).setMinor(1).build();
+ VersionInfo v2_0 = new VersionInfo.Builder().setMajor(2).setMinor(0).build();
+ VersionInfo v2_1 = new VersionInfo.Builder().setMajor(2).setMinor(1).build();
+ List<VersionInfo> versions = Arrays.asList(v2_1, v2_0, v1_1, v2_0, v1_0);
+
+ Collections.sort(versions);
+
+ assertThat(versions).containsExactly(v1_0, v1_1, v2_0, v2_0, v2_1).inOrder();
+ }
}
diff --git a/wear/protolayout/protolayout-lint/build.gradle b/wear/protolayout/protolayout-lint/build.gradle
index ded2b3d..dbe2777 100644
--- a/wear/protolayout/protolayout-lint/build.gradle
+++ b/wear/protolayout/protolayout-lint/build.gradle
@@ -22,7 +22,7 @@
}
dependencies {
- compileOnly(libs.androidLintMinApi)
+ compileOnly(libs.androidLintApi)
compileOnly(libs.kotlinStdlib)
testImplementation(libs.kotlinStdlib)
diff --git a/wear/protolayout/protolayout-lint/src/main/java/androidx/wear/protolayout/lint/ProtoLayoutIssueRegistry.kt b/wear/protolayout/protolayout-lint/src/main/java/androidx/wear/protolayout/lint/ProtoLayoutIssueRegistry.kt
index fe0c181..d47fe85 100644
--- a/wear/protolayout/protolayout-lint/src/main/java/androidx/wear/protolayout/lint/ProtoLayoutIssueRegistry.kt
+++ b/wear/protolayout/protolayout-lint/src/main/java/androidx/wear/protolayout/lint/ProtoLayoutIssueRegistry.kt
@@ -19,19 +19,17 @@
import com.android.tools.lint.client.api.IssueRegistry
import com.android.tools.lint.client.api.Vendor
import com.android.tools.lint.detector.api.CURRENT_API
-import com.android.tools.lint.detector.api.Issue
-/**
- * Issue Registry containing ProtoLayout specific lint Issues.
- */
+/** Issue Registry containing ProtoLayout specific lint Issues. */
@Suppress("UnstableApiUsage")
class ProtoLayoutIssueRegistry : IssueRegistry() {
override val api = 14
override val minApi = CURRENT_API
- override val issues get() = emptyList<Issue>()
- override val vendor = Vendor(
- feedbackUrl = "https://issuetracker.google.com/issues/new?component=1112273",
- identifier = "androidx.wear.protolayout",
- vendorName = "Android Open Source Project",
- )
+ override val issues = listOf(ProtoLayoutMinSchemaDetector.ISSUE)
+ override val vendor =
+ Vendor(
+ feedbackUrl = "https://issuetracker.google.com/issues/new?component=1112273",
+ identifier = "androidx.wear.protolayout",
+ vendorName = "Android Open Source Project",
+ )
}
diff --git a/wear/protolayout/protolayout-lint/src/main/java/androidx/wear/protolayout/lint/ProtoLayoutMinSchemaDetector.kt b/wear/protolayout/protolayout-lint/src/main/java/androidx/wear/protolayout/lint/ProtoLayoutMinSchemaDetector.kt
new file mode 100644
index 0000000..026b328
--- /dev/null
+++ b/wear/protolayout/protolayout-lint/src/main/java/androidx/wear/protolayout/lint/ProtoLayoutMinSchemaDetector.kt
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2023 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.
+ */
+@file:Suppress("UnstableApiUsage")
+
+package androidx.wear.protolayout.lint
+
+import com.android.tools.lint.client.api.UElementHandler
+import com.android.tools.lint.detector.api.ApiConstraint
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.ConstantEvaluator
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.VersionChecks.Companion.isPrecededByVersionCheckExit
+import com.android.tools.lint.detector.api.VersionChecks.Companion.isWithinVersionCheckConditional
+import com.intellij.psi.PsiField
+import com.intellij.psi.PsiMethod
+import com.intellij.psi.PsiModifierListOwner
+import org.jetbrains.uast.UAnnotated
+import org.jetbrains.uast.UAnnotation
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.UResolvable
+import org.jetbrains.uast.getContainingUMethod
+import org.jetbrains.uast.getContainingUVariable
+
+// TODO: b/308552481 - Add support for empty Builder construction (right now only setters are
+// annotated).
+
+/**
+ * The linter for detecting usage of ProtoLayout APIs (newer than schema 1.0) without properly
+ * checking the availability of them. Currently it relies on SDK checks that correspond to each
+ * ProtoLayout schema version.
+ *
+ * All **method** calls (where the callee has RequiresSchemaVersion annotation) are inspected to see
+ * if the call site meets the condition for the schema version. This means the caller have to either
+ * have a compatible RequiresSchemaVersion annotation (with greater than or equal version to the one
+ * needed), or the call to be within the scope of SDK version that matches the schema version. For
+ * example if the call is inside a SDK 34 version check, calls to schema versions including 1.300
+ * and below are all allowed.
+ *
+ * Note that RequiresSchemaVersion annotations on class are ignored (except for Builder classes).
+ */
+class ProtoLayoutMinSchemaDetector : Detector(), Detector.UastScanner {
+ override fun getApplicableUastTypes() = listOf(UCallExpression::class.java)
+
+ override fun createUastHandler(context: JavaContext) =
+ object : UElementHandler() {
+ override fun visitCallExpression(node: UCallExpression) {
+ val method = node.resolve() ?: return
+ checkMethodCall(context, node, method)
+ }
+ }
+
+ internal fun checkMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
+ // Does the callee have a RequiredSchemaVersion annotation?
+ val calleeAnnotation = method.getSchemaVersionAnnotation(context) ?: return
+ val callerSchemaAnnotation =
+ (node.getContainingUMethod() ?: node.getContainingUVariable())
+ ?.getSchemaVersionAnnotation(context)
+
+ if (calleeAnnotation.major <= 1 && calleeAnnotation.minor <= 100) {
+ // We only care about 1.2 and above
+ return
+ }
+
+ // Check callers RequiresSchemaVersion annotation and TargetApi/RequiresApi annotation.
+ if (
+ !calleeAnnotation.isCoveredBySchemaAnnotation(callerSchemaAnnotation) &&
+ !calleeAnnotation.isCoveredByTargetApi(context, node)
+ ) {
+ context.report(
+ issue = ISSUE,
+ location = context.getLocation(node),
+ message =
+ "This API is not guaranteed to be available on the device" +
+ " (requires schema $calleeAnnotation).",
+ )
+ }
+ }
+
+ private fun PsiModifierListOwner.getSchemaVersionAnnotation(
+ context: JavaContext
+ ): SchemaAnnotation? {
+ return if (this is UAnnotated) {
+ findAnnotation(REQUIRES_SCHEMA_ANNOTATION)?.asSchemaAnnotation(context)
+ } else {
+ context.evaluator
+ .getAnnotationInHierarchy(this, REQUIRES_SCHEMA_ANNOTATION)
+ ?.asSchemaAnnotation(context)
+ }
+ }
+
+ private fun UAnnotation.asSchemaAnnotation(context: JavaContext): SchemaAnnotation? {
+ val majorValue = attributeValue(context, "major")
+ val minorValue = attributeValue(context, "minor")
+ return if (majorValue != null && minorValue != null) {
+ SchemaAnnotation(majorValue, minorValue)
+ } else {
+ null
+ }
+ }
+
+ private fun UAnnotation.attributeValue(context: JavaContext, attrName: String): Int? {
+ val attrValue = findAttributeValue(attrName) ?: return null
+ val value =
+ ConstantEvaluator.evaluate(context, attrValue) ?: (attrValue as? UResolvable)?.resolve()
+ return when (value) {
+ is PsiField -> value.computeConstantValue() as Int?
+ is Int -> value
+ else -> null
+ }
+ }
+
+ private data class SchemaAnnotation(val major: Int, val minor: Int) {
+ fun isCoveredBySchemaAnnotation(other: SchemaAnnotation?): Boolean =
+ other != null && (major < other.major || (major == other.major && minor <= other.minor))
+
+ fun isCoveredByTargetApi(context: JavaContext, node: UCallExpression): Boolean {
+ val minSdkConstraint = ApiConstraint.get(toMinSdk() ?: return false)
+ return isWithinVersionCheckConditional(context, node, minSdkConstraint) ||
+ isPrecededByVersionCheckExit(context, node, minSdkConstraint) ||
+ hasAtLeastTargetApiAnnotation(context.evaluator, node, minSdkConstraint)
+ }
+
+ fun toMinSdk(): Int? =
+ when (minor) {
+ in Int.MIN_VALUE..100 -> null
+ in 101..200 -> 33
+ in 201..300 -> 34
+ else -> Int.MAX_VALUE
+ }
+
+ override fun toString() = "$major.$minor"
+ }
+
+ companion object {
+ @JvmField
+ val ISSUE =
+ Issue.create(
+ id = "ProtoLayoutMinSchema",
+ briefDescription =
+ "ProtoLayout feature is not guaranteed to be available " +
+ "on the target device API.",
+ explanation =
+ """
+ Using features that are not supported by an older ProtoLayout renderer/evaluator, can lead to unexpected rendering or invalid results (for expressions).
+
+ Each Wear OS platform version has a guaranteed minimum ProtoLayout schema version.
+ On API 33, all consumers for ProtoLayout support at least Schema version 1.2 (major=1, minor=200).
+ On API 34, all consumers for ProtoLayout support at least Schema version 1.3 (major=1, minor=300).
+
+ You can use those newer features through conditional Android API checks, or by increasing the minSdk for your project.
+ You can also annotate your methods with @RequiresApi or @RequiresSchemaAnnotation if you know they require the
+ corresponding version.
+ Note that @RequiresSchemaVersion annotation on classes are mostly ignored (except for Builder classes).
+ """,
+ category = Category.CORRECTNESS,
+ priority = 3,
+ severity = Severity.ERROR,
+ androidSpecific = true,
+ implementation =
+ Implementation(ProtoLayoutMinSchemaDetector::class.java, Scope.JAVA_FILE_SCOPE)
+ )
+
+ const val REQUIRES_SCHEMA_ANNOTATION =
+ "androidx.wear.protolayout.expression.RequiresSchemaVersion"
+ }
+}
diff --git a/wear/protolayout/protolayout-lint/src/main/java/androidx/wear/protolayout/lint/SdkApiChecks.kt b/wear/protolayout/protolayout-lint/src/main/java/androidx/wear/protolayout/lint/SdkApiChecks.kt
new file mode 100644
index 0000000..fce5ed8
--- /dev/null
+++ b/wear/protolayout/protolayout-lint/src/main/java/androidx/wear/protolayout/lint/SdkApiChecks.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 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.wear.protolayout.lint
+
+import com.android.tools.lint.client.api.JavaEvaluator
+import com.android.tools.lint.detector.api.ApiConstraint
+import com.android.tools.lint.detector.api.VersionChecks.Companion.getTargetApiAnnotation
+import org.jetbrains.uast.UElement
+
+/**
+ * Returns true if the element or one of its containing elements has an annotation that satisfies
+ * the [atLeast] constraint.
+ */
+internal fun hasAtLeastTargetApiAnnotation(
+ evaluator: JavaEvaluator,
+ element: UElement?,
+ atLeast: ApiConstraint
+): Boolean {
+ var curr = element ?: return false
+ while (true) {
+ val (outer, target) = getTargetApiAnnotation(evaluator, curr)
+ if (target != null && target.isAtLeast(atLeast)) {
+ return true
+ }
+ curr = outer?.uastParent?.uastParent ?: return false
+ }
+}
diff --git a/wear/protolayout/protolayout-lint/src/test/java/ProtoLayoutMinSchemaDetectorTest.kt b/wear/protolayout/protolayout-lint/src/test/java/ProtoLayoutMinSchemaDetectorTest.kt
new file mode 100644
index 0000000..dc2e8b6
--- /dev/null
+++ b/wear/protolayout/protolayout-lint/src/test/java/ProtoLayoutMinSchemaDetectorTest.kt
@@ -0,0 +1,418 @@
+/*
+ * Copyright 2023 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.
+ */
+
+@file:Suppress("UnstableApiUsage")
+
+package androidx.wear.protolayout.lint
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class ProtoLayoutMinSchemaDetectorTest : LintDetectorTest() {
+ override fun getDetector() = ProtoLayoutMinSchemaDetector()
+
+ override fun getIssues() = mutableListOf(ProtoLayoutMinSchemaDetector.ISSUE)
+
+ private val requiresSchemaAnnotationStub =
+ java(
+ """
+ package androidx.wear.protolayout.expression;
+
+ @Retention(CLASS)
+ @Target({TYPE, METHOD, CONSTRUCTOR, FIELD})
+ public @interface RequiresSchemaVersion {
+ int major();
+ int minor();
+ }
+ """
+ .trimIndent()
+ )
+ private val requiresApiAnnotationStub =
+ kotlin(
+ """
+ package androidx.annotation
+ @Retention(AnnotationRetention.BINARY)
+ @Target(
+ AnnotationTarget.ANNOTATION_CLASS,
+ AnnotationTarget.CLASS,
+ AnnotationTarget.FUNCTION,
+ AnnotationTarget.PROPERTY_GETTER,
+ AnnotationTarget.PROPERTY_SETTER,
+ AnnotationTarget.CONSTRUCTOR,
+ AnnotationTarget.FIELD,
+ AnnotationTarget.FILE
+ )
+ public actual annotation class RequiresApi(
+ val value: Int = 1,
+ val api: Int = 1
+ )
+ """
+ .trimIndent()
+ )
+
+ @Test
+ fun `calling V1_0 API doesn't`() {
+ lint()
+ .files(
+ requiresSchemaAnnotationStub,
+ kotlin(
+ """
+ package foo
+ import androidx.wear.protolayout.expression.RequiresSchemaVersion
+
+ @RequiresSchemaVersion(major=1, minor=0)
+ class WithAnnotation {
+ fun unAnnotatedMethod(){}
+ }
+ """
+ )
+ .indented(),
+ kotlin(
+ """
+ package foo
+ import androidx.wear.protolayout.expression.RequiresSchemaVersion
+
+ class Bar {
+ @RequiresSchemaVersion(major=1, minor=0)
+ fun bar() {}
+
+ fun baz() { bar() }
+ }
+ """
+ )
+ .indented()
+ )
+ .issues(ProtoLayoutMinSchemaDetector.ISSUE)
+ .run()
+ .expectClean()
+ }
+
+ @Test
+ fun `calling V1_2 API requires SDK version check`() {
+ lint()
+ .files(
+ requiresSchemaAnnotationStub,
+ kotlin(
+ """
+ package foo
+ import androidx.wear.protolayout.expression.RequiresSchemaVersion
+
+ @RequiresSchemaVersion(major=1, minor=200)
+ class WithAnnotation {
+ fun unAnnotatedMethod(){}
+
+ @RequiresSchemaVersion(major=1, minor=200)
+ fun annotatedMethod(){}
+
+ @RequiresSchemaVersion(major=1, minor=200)
+ fun unreferencedMethod(){}
+
+ companion object {
+ @RequiresSchemaVersion(major=1, minor=200)
+ const val ANNOTATED_CONST = 10
+ }
+ }
+ """
+ )
+ .indented(),
+ kotlin(
+ """
+ package foo
+ import androidx.wear.protolayout.expression.RequiresSchemaVersion
+
+ class Bar {
+ private val withAnnotation = WithAnnotation()
+ private val fieldAssignment = withAnnotation.annotatedMethod()
+
+ @RequiresSchemaVersion(major=1, minor=200)
+ fun bar() {}
+
+ fun baz() {
+ bar()
+ withAnnotation.unAnnotatedMethod()
+ withAnnotation.annotatedMethod()
+ //TODO: b/308552481 - This should fail
+ val b = withAnnotation.ANNOTATED_CONST
+ }
+ }
+ """
+ )
+ .indented()
+ )
+ .issues(ProtoLayoutMinSchemaDetector.ISSUE)
+ .run()
+ .expect(
+ """
+src/foo/Bar.kt:6: Error: This API is not guaranteed to be available on the device (requires schema 1.200). [ProtoLayoutMinSchema]
+ private val fieldAssignment = withAnnotation.annotatedMethod()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+src/foo/Bar.kt:12: Error: This API is not guaranteed to be available on the device (requires schema 1.200). [ProtoLayoutMinSchema]
+ bar()
+ ~~~~~
+src/foo/Bar.kt:14: Error: This API is not guaranteed to be available on the device (requires schema 1.200). [ProtoLayoutMinSchema]
+ withAnnotation.annotatedMethod()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+3 errors, 0 warnings
+ """
+ .trimIndent()
+ )
+
+ lint()
+ .files(
+ requiresSchemaAnnotationStub,
+ kotlin(
+ """
+ package foo
+ import androidx.wear.protolayout.expression.RequiresSchemaVersion
+
+ @RequiresSchemaVersion(major=1, minor=200)
+ class WithAnnotation {
+ fun unAnnotatedMethod(){}
+
+ @RequiresSchemaVersion(major=1, minor=200)
+ fun annotatedMethod(){}
+
+ @RequiresSchemaVersion(major=1, minor=200)
+ fun unreferencedMethod(){}
+ }
+ """
+ )
+ .indented(),
+ kotlin(
+ """
+ package foo
+ import androidx.wear.protolayout.expression.RequiresSchemaVersion
+ import android.os.Build
+
+ class Bar {
+ private val withAnnotation = WithAnnotation()
+
+ @RequiresSchemaVersion(major=1, minor=200)
+ fun bar() {}
+
+ fun baz() {
+ if (Build.VERSION.SDK_INT >= 33) {
+ bar()
+ withAnnotation.unAnnotatedMethod()
+ withAnnotation.annotatedMethod()
+ }
+ }
+ }
+ """
+ )
+ .indented()
+ )
+ .issues(ProtoLayoutMinSchemaDetector.ISSUE)
+ .run()
+ .expectClean()
+ }
+
+ @Test
+ fun `calling V1_2 API requires SDK version check (Java)`() {
+ lint()
+ .files(
+ requiresSchemaAnnotationStub,
+ java(
+ """
+ package foo;
+ import androidx.wear.protolayout.expression.RequiresSchemaVersion;
+
+ class Bar {
+ @RequiresSchemaVersion(major=1, minor=200)
+ public static final int ANNOTATED_CONSTANT = 10;
+
+ @RequiresSchemaVersion(major=1, minor=200)
+ void bar() {}
+
+ void baz() {
+ bar();
+ // TODO: b/308552481: This should fail
+ int t = ANNOTATED_CONSTANT;
+ }
+ }
+ """
+ )
+ .indented()
+ )
+ .issues(ProtoLayoutMinSchemaDetector.ISSUE)
+ .run()
+ .expect(
+ """
+src/foo/Bar.java:12: Error: This API is not guaranteed to be available on the device (requires schema 1.200). [ProtoLayoutMinSchema]
+ bar();
+ ~~~~~
+1 errors, 0 warnings
+ """
+ .trimIndent()
+ )
+
+ lint()
+ .files(
+ requiresSchemaAnnotationStub,
+ java(
+ """
+ package foo;
+ import androidx.wear.protolayout.expression.RequiresSchemaVersion;
+ import android.os.Build;
+
+ class Bar {
+ @RequiresSchemaVersion(major=1, minor=200)
+ void bar() {}
+
+ void baz() {
+ if (Build.VERSION.SDK_INT >= 33) {
+ bar();
+ }
+ }
+ }
+ """
+ )
+ .indented()
+ )
+ .issues(ProtoLayoutMinSchemaDetector.ISSUE)
+ .run()
+ .expectClean()
+ }
+
+ @Test
+ fun `annotated call-site doesn't requires SDK version check`() {
+ lint()
+ .files(
+ requiresSchemaAnnotationStub,
+ requiresApiAnnotationStub,
+ kotlin(
+ """
+ package foo
+ import androidx.wear.protolayout.expression.RequiresSchemaVersion
+
+ class BarK {
+ @RequiresSchemaVersion(major=1, minor=200)
+ private val fieldAssignment = bar()
+
+ @RequiresSchemaVersion(major=1, minor=200)
+ fun bar() = 1
+
+ @RequiresSchemaVersion(major=1, minor=200)
+ fun baz2() { bar() }
+
+ @RequiresSchemaVersion(major=1, minor=300)
+ fun baz3() { bar() }
+ }
+ """
+ )
+ .indented(),
+ java(
+ """
+ package foo;
+ import androidx.wear.protolayout.expression.RequiresSchemaVersion;
+
+ class BarJ {
+ @RequiresSchemaVersion(major=1, minor=200)
+ private static final int fieldAssignment = bar();
+
+ @RequiresSchemaVersion(major=1, minor=200)
+ public static int bar() { return 1;}
+
+ @RequiresSchemaVersion(major=1, minor=200)
+ void baz2() { bar(); }
+
+ @RequiresSchemaVersion(major=1, minor=300)
+ void baz3() { bar(); }
+ }
+ """
+ )
+ .indented(),
+ kotlin(
+ """
+ package foo
+ import androidx.wear.protolayout.expression.RequiresSchemaVersion
+ import androidx.annotation.RequiresApi
+
+ @RequiresApi(33)
+ class BazK {
+ private val fieldAssignment = bar()
+
+ @RequiresSchemaVersion(major=1, minor=200)
+ fun bar() = 1
+
+ @RequiresApi(30)
+ fun baz2() { bar() }
+
+ @RequiresApi(34)
+ fun baz3() { BarJ.baz3() }
+ }
+ """
+ )
+ .indented()
+ )
+ .issues(ProtoLayoutMinSchemaDetector.ISSUE)
+ .run()
+ .expectClean()
+ }
+
+ @Test
+ fun `project with proper minSdk doesn't requires SDK version check`() {
+ lint()
+ .files(
+ manifest().minSdk(34),
+ requiresSchemaAnnotationStub,
+ kotlin(
+ """
+ package foo
+ import androidx.wear.protolayout.expression.RequiresSchemaVersion
+
+ class BarK {
+ @RequiresSchemaVersion(major=1, minor=200)
+ private val fieldAssignment = bar()
+
+ @RequiresSchemaVersion(major=1, minor=200)
+ fun bar() = 1
+
+ @RequiresSchemaVersion(major=1, minor=200)
+ fun baz2() { bar() }
+
+ @RequiresSchemaVersion(major=1, minor=300)
+ fun baz3() { bar() }
+ }
+ """
+ )
+ .indented(),
+ java(
+ """
+ package foo;
+ import androidx.wear.protolayout.expression.RequiresSchemaVersion;
+
+ class BarJ {
+ private static final int fieldAssignment = bar();
+
+ fun bar() {}
+
+ fun baz2() { bar(); }
+
+ fun baz3() { bar(); }
+ }
+ """
+ )
+ .indented()
+ )
+ .issues(ProtoLayoutMinSchemaDetector.ISSUE)
+ .run()
+ .expectClean()
+ }
+}
diff --git a/wear/protolayout/protolayout-proto/src/main/proto/color.proto b/wear/protolayout/protolayout-proto/src/main/proto/color.proto
index ae81664..aff2220 100644
--- a/wear/protolayout/protolayout-proto/src/main/proto/color.proto
+++ b/wear/protolayout/protolayout-proto/src/main/proto/color.proto
@@ -30,7 +30,10 @@
// A color and an offset, determining a color position in a gradient.
message ColorStop {
- // The color for this stop.
+ // The color for this stop. Only opaque colors are supported. Any transparent
+ // colors will have their alpha component set to 0xFF (opaque).
+ //
+
ColorProp color = 1;
oneof optional_offset {
diff --git a/wear/protolayout/protolayout-proto/src/main/proto/layout.proto b/wear/protolayout/protolayout-proto/src/main/proto/layout.proto
index 115c73d..96fc634 100644
--- a/wear/protolayout/protolayout-proto/src/main/proto/layout.proto
+++ b/wear/protolayout/protolayout-proto/src/main/proto/layout.proto
@@ -663,7 +663,11 @@
StrokeCap value = 1;
// The stroke cap's shadow. When set, the stroke cap will be drawn with a
- // shadow, which allows it to be visible on top of other similarly colored elements.
+ // shadow, which allows it to be visible on top of other similarly colored
+ // elements.
+ //
+ // Only opaque colors are supported in ArcLine if a shadow is set. Any
+ // transparent colors will have their alpha component set to 0xFF (opaque).
Shadow shadow = 2;
}
diff --git a/wear/protolayout/protolayout-proto/src/main/proto/modifiers.proto b/wear/protolayout/protolayout-proto/src/main/proto/modifiers.proto
index 1d2a9b5..f771ea4 100644
--- a/wear/protolayout/protolayout-proto/src/main/proto/modifiers.proto
+++ b/wear/protolayout/protolayout-proto/src/main/proto/modifiers.proto
@@ -190,18 +190,20 @@
// underneath it.
AnimatedVisibility content_update_animation = 7;
- // Whether the attached element is hidden, or visible. If the element is
- // hidden, then it will still consume space in the layout, but will not render
- // any contents, nor will any children render any contents.
- //
- // Note that a hidden element also cannot be clickable (i.e. a Clickable
- // modifier would be ignored).
- //
- // Defaults to false (i.e. not hidden).
+
+ // This field is deprecated and is only kept for backward compatibility.
BoolProp hidden = 8;
// The optional identifier for the layout element.
string id = 9;
+
+ // Whether the attached element is visible, or hidden. If the element is
+ // hidden, then it will still consume space in the layout, but will not render
+ // any contents, nor will any children render any contents. Defaults to visible.
+ //
+ // Note that a hidden element also cannot be clickable (i.e. a Clickable
+ // modifier would be ignored).
+ BoolProp visible = 10;
}
// The content transition of an element. Any update to the element or its
diff --git a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflater.java b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflater.java
index bf096bb..9df108f 100644
--- a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflater.java
+++ b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflater.java
@@ -195,6 +195,7 @@
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.function.Consumer;
+import java.util.function.Function;
/**
* Renderer for ProtoLayout.
@@ -221,8 +222,7 @@
Trigger.newBuilder().setOnLoadTrigger(OnLoadTrigger.getDefaultInstance()).build();
/** The default minimal click target size, for meeting the accessibility requirement */
- @VisibleForTesting
- static final float DEFAULT_MIN_CLICKABLE_SIZE_DP = 48f;
+ @VisibleForTesting static final float DEFAULT_MIN_CLICKABLE_SIZE_DP = 48f;
/**
* Default maximum raw byte size for a bitmap drawable.
@@ -255,8 +255,7 @@
private static final int TEXT_COLOR_DEFAULT = 0xFFFFFFFF;
private static final int TEXT_MAX_LINES_DEFAULT = 1;
- @VisibleForTesting
- static final int TEXT_AUTOSIZES_LIMIT = 10;
+ @VisibleForTesting static final int TEXT_AUTOSIZES_LIMIT = 10;
private static final int TEXT_MIN_LINES = 1;
private static final ContainerDimension CONTAINER_DIMENSION_DEFAULT =
@@ -1179,9 +1178,7 @@
private float toPx(SpProp spField) {
return TypedValue.applyDimension(
- COMPLEX_UNIT_SP,
- spField.getValue(),
- mUiContext.getResources().getDisplayMetrics());
+ COMPLEX_UNIT_SP, spField.getValue(), mUiContext.getResources().getDisplayMetrics());
}
private void applyFontStyle(
@@ -1210,10 +1207,10 @@
// value.
boolean atLeastOneCorrectSize =
sizes.stream()
- .mapToInt(sp -> (int) sp.getValue())
- .filter(sp -> sp > 0)
- .distinct()
- .count()
+ .mapToInt(sp -> (int) sp.getValue())
+ .filter(sp -> sp > 0)
+ .distinct()
+ .count()
> 0;
if (atLeastOneCorrectSize) {
@@ -1244,7 +1241,9 @@
} else {
Log.w(
TAG,
- "More than " + TEXT_AUTOSIZES_LIMIT + " sizes has been added for the "
+ "More than "
+ + TEXT_AUTOSIZES_LIMIT
+ + " sizes has been added for the "
+ "text autosizing. Ignoring all other sizes and using the last"
+ "one.");
}
@@ -1524,8 +1523,21 @@
@NonNull Modifiers modifiers,
@NonNull String posId,
@NonNull Optional<ProtoLayoutDynamicDataPipeline.PipelineMaker> pipelineMaker) {
- if (modifiers.hasHidden()) {
- applyHidden(view, modifiers.getHidden(), posId, pipelineMaker);
+ if (modifiers.hasVisible()) {
+ applyVisible(
+ view,
+ modifiers.getVisible(),
+ posId,
+ pipelineMaker,
+ visible -> visible ? VISIBLE : INVISIBLE);
+ } else if (modifiers.hasHidden()) {
+ // This is a deprecated field
+ applyVisible(
+ view,
+ modifiers.getHidden(),
+ posId,
+ pipelineMaker,
+ hidden -> hidden ? INVISIBLE : VISIBLE);
}
if (modifiers.hasClickable()) {
@@ -1571,12 +1583,15 @@
return view;
}
- private void applyHidden(
- View view, BoolProp hidden, String posId,
- Optional<ProtoLayoutDynamicDataPipeline.PipelineMaker> pipelineMaker) {
+ private void applyVisible(
+ View view,
+ BoolProp visible,
+ String posId,
+ Optional<ProtoLayoutDynamicDataPipeline.PipelineMaker> pipelineMaker,
+ Function<Boolean, Integer> toViewVisibility) {
handleProp(
- hidden,
- hide -> view.setVisibility(hide ? INVISIBLE : VISIBLE),
+ visible,
+ visibility -> view.setVisibility(toViewVisibility.apply(visibility)),
posId,
pipelineMaker);
}
@@ -1863,7 +1878,7 @@
return TruncateAt.MARQUEE;
case TEXT_OVERFLOW_UNDEFINED:
case UNRECOGNIZED:
- // TODO(b/302531877): Implement ellipsize.
+ // TODO(b/302531877): Implement ellipsize.
case TEXT_OVERFLOW_ELLIPSIZE:
return TEXT_OVERFLOW_DEFAULT;
}
@@ -2126,11 +2141,7 @@
View wrappedView =
applyModifiers(
- frame,
- /* wrapper= */ null,
- box.getModifiers(),
- boxPosId,
- pipelineMaker);
+ frame, /* wrapper= */ null, box.getModifiers(), boxPosId, pipelineMaker);
parentViewWrapper.maybeAddView(wrappedView, layoutParams);
@@ -2202,9 +2213,9 @@
updateLayoutParams(
parentViewWrapper.getParentProperties(),
layoutParams,
- // This doesn't copy layout constraint for dynamic fields. That is fine, because that
- // will be later applied to the wrapper, and this layoutParams would have dimension
- // reset and put into the pipeline.
+ // This doesn't copy layout constraint for dynamic fields. That is fine,
+ // because that will be later applied to the wrapper, and this layoutParams
+ // would have dimension reset and put into the pipeline.
spacerDimensionToContainerDimension(spacer.getWidth()),
spacerDimensionToContainerDimension(spacer.getHeight()));
@@ -2247,13 +2258,17 @@
int gravity =
(spacer.getWidth().hasLinearDimension()
- ? horizontalAlignmentToGravity(
- spacer.getWidth().getLinearDimension().getHorizontalAlignmentForLayout())
- : UNSET_MASK)
+ ? horizontalAlignmentToGravity(
+ spacer.getWidth()
+ .getLinearDimension()
+ .getHorizontalAlignmentForLayout())
+ : UNSET_MASK)
| (spacer.getHeight().hasLinearDimension()
- ? verticalAlignmentToGravity(
- spacer.getHeight().getLinearDimension().getVerticalAlignmentForLayout())
- : UNSET_MASK);
+ ? verticalAlignmentToGravity(
+ spacer.getHeight()
+ .getLinearDimension()
+ .getVerticalAlignmentForLayout())
+ : UNSET_MASK);
// This layoutParams will override what we initially had and will be used for Spacer
// itself. This means that the wrapper's layout params should follow the rules for
@@ -2341,7 +2356,8 @@
handleProp(
spacer.getWidth().getLinearDimension(),
width -> {
- // We still need to update layout params in case other dimension is expand, so 0 could
+ // We still need to update layout params in case other dimension is
+ // expand, so 0 could
// be miss interpreted.
LayoutParams lp = view.getLayoutParams();
if (lp == null) {
@@ -2360,8 +2376,8 @@
handleProp(
spacer.getHeight().getLinearDimension(),
height -> {
- // We still need to update layout params in case other dimension is expand, so 0 could
- // be miss interpreted.
+ // We still need to update layout params in case other dimension is
+ // expand, so 0 could be miss interpreted.
LayoutParams lp = view.getLayoutParams();
if (lp == null) {
Log.e(TAG, "LayoutParams was null when updating spacer height");
@@ -2531,12 +2547,7 @@
// Setting colours **must** go after setting the Text Appearance, otherwise it will get
// immediately overridden.
if (text.hasFontStyle()) {
- applyFontStyle(
- text.getFontStyle(),
- textView,
- posId,
- pipelineMaker,
- isAutoSizeAllowed);
+ applyFontStyle(text.getFontStyle(), textView, posId, pipelineMaker, isAutoSizeAllowed);
} else {
applyFontStyle(
FontStyle.getDefaultInstance(),
@@ -2806,11 +2817,7 @@
ratioViewWrapper.setAspectRatio(ratio);
View wrappedImageView =
applyModifiers(
- imageView,
- ratioViewWrapper,
- image.getModifiers(),
- posId,
- pipelineMaker);
+ imageView, ratioViewWrapper, image.getModifiers(), posId, pipelineMaker);
ratioViewWrapper.addView(wrappedImageView);
parentViewWrapper.maybeAddView(ratioViewWrapper, ratioWrapperLayoutParams);
@@ -3172,10 +3179,11 @@
Log.w(
TAG,
"Font size with multiple values has been used on Span Text. Ignoring "
- + "all size except the first one.");
+ + "all size except the first one.");
}
- AbsoluteSizeSpan span = new AbsoluteSizeSpan(round(toPx(
- fontStyle.getSize(fontStyle.getSizeCount() - 1))));
+ AbsoluteSizeSpan span =
+ new AbsoluteSizeSpan(
+ round(toPx(fontStyle.getSize(fontStyle.getSizeCount() - 1))));
builder.setSpan(span, start, end, Spanned.SPAN_MARK_MARK);
}
@@ -3452,11 +3460,7 @@
View wrappedView =
applyModifiers(
- tv,
- /* wrapper= */ null,
- spannable.getModifiers(),
- posId,
- pipelineMaker);
+ tv, /* wrapper= */ null, spannable.getModifiers(), posId, pipelineMaker);
parentViewWrapper.maybeAddView(wrappedView, layoutParams);
return new InflatedView(
diff --git a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/WearCurvedLineView.java b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/WearCurvedLineView.java
index 8e99e07..4089fc5 100644
--- a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/WearCurvedLineView.java
+++ b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/WearCurvedLineView.java
@@ -73,6 +73,7 @@
private static final float DEFAULT_LINE_SWEEP_ANGLE_DEGREES = 0;
private static final int DEFAULT_LINE_STROKE_CAP = Cap.ROUND.ordinal();
@ColorInt private static final int DEFAULT_COLOR = 0xFFFFFFFF;
+ private static final int FULLY_OPAQUE_COLOR_MASK = 0xFF000000;
/**
* The base angle for drawings. The zero angle in Android corresponds to the "3 o clock"
@@ -257,6 +258,10 @@
/** Sets the color of this arc, in ARGB format. */
public void setColor(@ColorInt int color) {
+ // Force color to be fully opaque if stroke cap shadow is used.
+ if (mCapShadow != null) {
+ color = makeOpaque(color);
+ }
this.mColor = color;
updateArcDrawable();
invalidate();
@@ -290,6 +295,8 @@
/** Sets the parameters for the stroke cap shadow. */
public void setStrokeCapShadow(float blurRadius, int color) {
this.mCapShadow = new StrokeCapShadow(blurRadius, color);
+ // Re-set color.
+ this.setColor(mColor);
}
/** Clears the stroke cap shadow. */
@@ -352,6 +359,7 @@
@NonNull private final List<AngularColorStop> colorStops;
+ /** Constructor. All colors will have their alpha channel set to 0xFF (opaque). */
SweepGradientHelper(@NonNull ColorProto.SweepGradient sweepGradProto) {
int numColors = sweepGradProto.getColorStopsCount();
if (numColors < MIN_COLOR_STOPS || numColors > MAX_COLOR_STOPS) {
@@ -383,7 +391,8 @@
? stop.getOffset().getValue()
: (float) i / (numColors - 1);
float gradAngle = gradStartAngle + offset * (gradEndAngle - gradStartAngle);
- colorStops.add(new AngularColorStop(gradAngle, stop.getColor().getArgb()));
+ colorStops.add(
+ new AngularColorStop(gradAngle, makeOpaque(stop.getColor().getArgb())));
}
if (offsetsRequired) {
@@ -723,6 +732,8 @@
* elements are drawn first).
*
* <p>All other lower layers of the line are not visible so they are not drawn.
+ *
+ * <p>For a more detail explanation of the drawing method, see go/protolayout-arcline.
*/
static class ArcDrawableImpl implements ArcDrawable {
// The list of segments that compose the ArcDrawable, in the order that they should be
@@ -909,4 +920,9 @@
this.mColor = color;
}
}
+
+ /** Changes the alpha channel of the color to 0xFF (fully opaque). */
+ private static int makeOpaque(int color) {
+ return color | FULLY_OPAQUE_COLOR_MASK;
+ }
}
diff --git a/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflaterTest.java b/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflaterTest.java
index e630c9f..0a66ff6 100644
--- a/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflaterTest.java
+++ b/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflaterTest.java
@@ -4782,6 +4782,71 @@
assertThat(secondImage.getLeft()).isEqualTo(secondImageLeft);
}
+ @Test public void inflate_box_withVisibleModifier() {
+ final String protoResId = "android";
+ final String boolKey = "bool-key";
+
+ LayoutElement image = buildImage(protoResId, 30, 30);
+
+ BoolProp.Builder stateBoolPropBuilder =
+ BoolProp.newBuilder()
+ .setValue(true)
+ .setDynamicValue(
+ DynamicBool.newBuilder()
+ .setStateSource(
+ StateBoolSource.newBuilder()
+ .setSourceKey(boolKey)));
+ BoolProp.Builder alwaysTrueBoolPropBuilder =
+ BoolProp.newBuilder()
+ .setValue(true)
+ .setDynamicValue(
+ DynamicBool.newBuilder()
+ .setFixed(FixedBool.newBuilder().setValue(true)));
+ LayoutElement.Builder boxBuilder =
+ LayoutElement.newBuilder()
+ .setBox(
+ Box.newBuilder()
+ .addContents(image)
+ .setModifiers(
+ Modifiers.newBuilder()
+ .setVisible(stateBoolPropBuilder)
+ // This should be ignored
+ .setHidden(alwaysTrueBoolPropBuilder)));
+ LayoutElement root =
+ LayoutElement.newBuilder()
+ .setRow(Row.newBuilder().addContents(boxBuilder).addContents(image))
+ .build();
+
+ FrameLayout layout = renderer(fingerprintedLayout(root)).inflate();
+
+ // There should be a child ViewGroup which is a LinearLayout.
+ assertThat(layout.getChildAt(0)).isInstanceOf(ViewGroup.class);
+ ViewGroup firstChild = (ViewGroup) layout.getChildAt(0);
+ ViewGroup box = (ViewGroup) firstChild.getChildAt(0);
+ ViewGroup secondImage = (ViewGroup) firstChild.getChildAt(1);
+
+ assertThat(box.getWidth()).isGreaterThan(0);
+ assertThat(box.getVisibility()).isEqualTo(VISIBLE);
+
+ // The second image should start after the hidden (but not gone) box.
+ int secondImageLeft = secondImage.getLeft();
+ assertThat(secondImageLeft).isEqualTo(box.getWidth());
+ assertThat(box.getWidth()).isEqualTo(secondImage.getWidth());
+
+ // Try to hide the box.
+ mStateStore.setAppStateEntryValuesProto(
+ ImmutableMap.of(
+ new AppDataKey<DynamicBuilders.DynamicBool>(boolKey),
+ DynamicDataValue.newBuilder()
+ .setBoolVal(FixedBool.newBuilder().setValue(false))
+ .build()));
+
+ // The box should be hidden but still take some space (as it wraps around its inner image)
+ assertThat(box.getVisibility()).isEqualTo(INVISIBLE);
+ // The second image shouldn't move around.
+ assertThat(secondImage.getLeft()).isEqualTo(secondImageLeft);
+ }
+
@Test
public void enterTransition_noQuota_notPlayed() throws Exception {
Renderer renderer =
diff --git a/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/inflater/WearCurvedLineViewTest.java b/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/inflater/WearCurvedLineViewTest.java
index 72db5aa..532bb8e 100644
--- a/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/inflater/WearCurvedLineViewTest.java
+++ b/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/inflater/WearCurvedLineViewTest.java
@@ -180,6 +180,34 @@
assertThat(rotatedMatrix).isEqualTo(generatedMatrix);
}
+ @Test
+ public void sweepGradientHelper_colorSetToOpaque() {
+ final int color0 = 0x12666666;
+ final int color90 = 0xFD123456;
+ final int color180 = 0xFF654321;
+ final int noAlphaMask = 0x00FFFFFF;
+ SweepGradient sgProto =
+ SweepGradient.newBuilder()
+ .addColorStops(colorStop(color0))
+ .addColorStops(colorStop(color90))
+ .addColorStops(colorStop(color180))
+ .setEndAngle(degrees(180f))
+ .build();
+ SweepGradientHelper sgHelper = new SweepGradientHelper(sgProto);
+
+ int resolvedColor0 = sgHelper.getColor(0f);
+ expect.that(Color.alpha(resolvedColor0)).isEqualTo(0xFF);
+ expect.that(resolvedColor0 & noAlphaMask).isEqualTo(color0 & noAlphaMask);
+
+ int resolvedColor90 = sgHelper.getColor(90f);
+ expect.that(Color.alpha(resolvedColor90)).isEqualTo(0xFF);
+ expect.that(resolvedColor90 & noAlphaMask).isEqualTo(color90 & noAlphaMask);
+
+ int resolvedColor180 = sgHelper.getColor(180f);
+ expect.that(Color.alpha(resolvedColor180)).isEqualTo(0xFF);
+ expect.that(resolvedColor180 & noAlphaMask).isEqualTo(color180 & noAlphaMask);
+ }
+
/** Gradient with colors [Red, Blue, Green] at offsets [0, 0.5, 1] and given angles. */
private SweepGradient basicSweepGradientProto(float startAngle, float endAngle) {
return SweepGradient.newBuilder()
diff --git a/wear/protolayout/protolayout/api/current.txt b/wear/protolayout/protolayout/api/current.txt
index 4bc6a059..a4ba9ae 100644
--- a/wear/protolayout/protolayout/api/current.txt
+++ b/wear/protolayout/protolayout/api/current.txt
@@ -1009,10 +1009,10 @@
method public androidx.wear.protolayout.ModifiersBuilders.Border? getBorder();
method public androidx.wear.protolayout.ModifiersBuilders.Clickable? getClickable();
method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.ModifiersBuilders.AnimatedVisibility? getContentUpdateAnimation();
- method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.TypeBuilders.BoolProp? getHidden();
method public androidx.wear.protolayout.ModifiersBuilders.ElementMetadata? getMetadata();
method public androidx.wear.protolayout.ModifiersBuilders.Padding? getPadding();
method public androidx.wear.protolayout.ModifiersBuilders.Semantics? getSemantics();
+ method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.TypeBuilders.BoolProp isVisible();
}
public static final class ModifiersBuilders.Modifiers.Builder {
@@ -1022,10 +1022,10 @@
method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setBorder(androidx.wear.protolayout.ModifiersBuilders.Border);
method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setClickable(androidx.wear.protolayout.ModifiersBuilders.Clickable);
method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setContentUpdateAnimation(androidx.wear.protolayout.ModifiersBuilders.AnimatedVisibility);
- method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=300) public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setHidden(androidx.wear.protolayout.TypeBuilders.BoolProp);
method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setMetadata(androidx.wear.protolayout.ModifiersBuilders.ElementMetadata);
method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setPadding(androidx.wear.protolayout.ModifiersBuilders.Padding);
method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setSemantics(androidx.wear.protolayout.ModifiersBuilders.Semantics);
+ method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=300) public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setVisible(androidx.wear.protolayout.TypeBuilders.BoolProp);
}
@androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public static final class ModifiersBuilders.Padding {
diff --git a/wear/protolayout/protolayout/api/restricted_current.txt b/wear/protolayout/protolayout/api/restricted_current.txt
index 4bc6a059..a4ba9ae 100644
--- a/wear/protolayout/protolayout/api/restricted_current.txt
+++ b/wear/protolayout/protolayout/api/restricted_current.txt
@@ -1009,10 +1009,10 @@
method public androidx.wear.protolayout.ModifiersBuilders.Border? getBorder();
method public androidx.wear.protolayout.ModifiersBuilders.Clickable? getClickable();
method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.ModifiersBuilders.AnimatedVisibility? getContentUpdateAnimation();
- method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.TypeBuilders.BoolProp? getHidden();
method public androidx.wear.protolayout.ModifiersBuilders.ElementMetadata? getMetadata();
method public androidx.wear.protolayout.ModifiersBuilders.Padding? getPadding();
method public androidx.wear.protolayout.ModifiersBuilders.Semantics? getSemantics();
+ method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.TypeBuilders.BoolProp isVisible();
}
public static final class ModifiersBuilders.Modifiers.Builder {
@@ -1022,10 +1022,10 @@
method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setBorder(androidx.wear.protolayout.ModifiersBuilders.Border);
method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setClickable(androidx.wear.protolayout.ModifiersBuilders.Clickable);
method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setContentUpdateAnimation(androidx.wear.protolayout.ModifiersBuilders.AnimatedVisibility);
- method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=300) public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setHidden(androidx.wear.protolayout.TypeBuilders.BoolProp);
method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setMetadata(androidx.wear.protolayout.ModifiersBuilders.ElementMetadata);
method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setPadding(androidx.wear.protolayout.ModifiersBuilders.Padding);
method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setSemantics(androidx.wear.protolayout.ModifiersBuilders.Semantics);
+ method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=300) public androidx.wear.protolayout.ModifiersBuilders.Modifiers.Builder setVisible(androidx.wear.protolayout.TypeBuilders.BoolProp);
}
@androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public static final class ModifiersBuilders.Padding {
diff --git a/wear/protolayout/protolayout/build.gradle b/wear/protolayout/protolayout/build.gradle
index 3c2633d..8459d38 100644
--- a/wear/protolayout/protolayout/build.gradle
+++ b/wear/protolayout/protolayout/build.gradle
@@ -29,6 +29,9 @@
implementation(project(path: ":wear:protolayout:protolayout-proto", configuration: "shadow"))
api(project(":wear:protolayout:protolayout-expression"))
+ lintChecks(project(":wear:protolayout:protolayout-lint"))
+ lintPublish(project(":wear:protolayout:protolayout-lint"))
+
testImplementation(libs.testExtJunit)
testImplementation(libs.testExtTruth)
testImplementation(libs.testRunner)
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ColorBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ColorBuilders.java
index d8a5bac..c8c3b1c 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ColorBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ColorBuilders.java
@@ -195,7 +195,10 @@
this.mFingerprint = fingerprint;
}
- /** Gets the color for this stop. */
+ /**
+ * Gets the color for this stop. Only opaque colors are supported. Any transparent colors
+ * will have their alpha component set to 0xFF (opaque).
+ */
@NonNull
public ColorProp getColor() {
return ColorProp.fromProto(mImpl.getColor());
@@ -288,7 +291,8 @@
public Builder() {}
/**
- * Sets the color for this stop.
+ * Sets the color for this stop. Only opaque colors are supported. Any transparent
+ * colors will have their alpha component set to 0xFF (opaque).
*
* <p>Note that this field only supports static values.
*/
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/LayoutElementBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/LayoutElementBuilders.java
index 83ec93f..dd99305 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/LayoutElementBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/LayoutElementBuilders.java
@@ -20,6 +20,8 @@
import static androidx.wear.protolayout.expression.Preconditions.checkNotNull;
import android.annotation.SuppressLint;
+import android.graphics.Color;
+import android.util.Log;
import androidx.annotation.Dimension;
import androidx.annotation.IntDef;
@@ -57,6 +59,7 @@
import androidx.wear.protolayout.expression.ProtoLayoutExperimental;
import androidx.wear.protolayout.expression.RequiresSchemaVersion;
import androidx.wear.protolayout.proto.AlignmentProto;
+import androidx.wear.protolayout.proto.ColorProto;
import androidx.wear.protolayout.proto.DimensionProto;
import androidx.wear.protolayout.proto.FingerprintProto;
import androidx.wear.protolayout.proto.FingerprintProto.TreeFingerprint;
@@ -708,10 +711,16 @@
/**
* Sets whether the text should be rendered in a italic typeface. If not specified,
* defaults to "false".
+ *
+ * <p>Note that this field only supports static values.
*/
@RequiresSchemaVersion(major = 1, minor = 0)
@NonNull
public Builder setItalic(@NonNull BoolProp italic) {
+ if (italic.getDynamicValue() != null) {
+ throw new IllegalArgumentException(
+ "FontStyle.Builder.setItalic doesn't support dynamic values.");
+ }
mImpl.setItalic(italic.toProto());
mFingerprint.recordPropertyUpdate(
2, checkNotNull(italic.getFingerprint()).aggregateValueAsInt());
@@ -732,10 +741,16 @@
/**
* Sets whether the text should be rendered with an underline. If not specified,
* defaults to "false".
+ *
+ * <p>Note that this field only supports static values.
*/
@RequiresSchemaVersion(major = 1, minor = 0)
@NonNull
public Builder setUnderline(@NonNull BoolProp underline) {
+ if (underline.getDynamicValue() != null) {
+ throw new IllegalArgumentException(
+ "FontStyle.Builder.setUnderline doesn't support dynamic values.");
+ }
mImpl.setUnderline(underline.toProto());
mFingerprint.recordPropertyUpdate(
3, checkNotNull(underline.getFingerprint()).aggregateValueAsInt());
@@ -4451,6 +4466,24 @@
"length with dynamic value requires "
+ "layoutConstraintsForDynamicLength to be present.");
}
+
+ String onlyOpaqueMsg = "Only opaque colors are supported";
+ String alphaChangeMsg =
+ "Any transparent colors will have their alpha component set to 0xFF"
+ + " (opaque).";
+ for (ColorProto.ColorStop colorStop :
+ mImpl.getBrush().getSweepGradient().getColorStopsList()) {
+ if (Color.alpha(colorStop.getColor().getArgb()) < 0xFF) {
+ Log.w("ArcLine", onlyOpaqueMsg + " for SweepGradient. " + alphaChangeMsg);
+ break;
+ }
+ }
+ if (mImpl.getStrokeCap().hasShadow()
+ && Color.alpha(mImpl.getColor().getArgb()) < 0xFF) {
+ Log.w(
+ "ArcLine",
+ onlyOpaqueMsg + " when using StrokeCap Shadow. " + alphaChangeMsg);
+ }
return new ArcLine(mImpl.build(), mFingerprint);
}
}
@@ -4476,6 +4509,9 @@
/**
* Gets the stroke cap's shadow. When set, the stroke cap will be drawn with a shadow, which
* allows it to be visible on top of other similarly colored elements.
+ *
+ * <p>Only opaque colors are supported in {@link ArcLine} if a shadow is set. Any
+ * transparent colors will have their alpha component set to 0xFF (opaque).
*/
@Nullable
public Shadow getShadow() {
@@ -4541,6 +4577,9 @@
/**
* Sets the stroke cap's shadow. When set, the stroke cap will be drawn with a shadow,
* which allows it to be visible on top of other similarly colored elements.
+ *
+ * <p>Only opaque colors are supported in {@link ArcLine} if a shadow is set. Any
+ * transparent colors will have their alpha component set to 0xFF (opaque).
*/
@RequiresSchemaVersion(major = 1, minor = 300)
@NonNull
@@ -4821,10 +4860,16 @@
* be placed at the 3 o clock position, and will be rotated clockwise through 90
* degrees. If rotate_contents = false, the image will be placed at the 3 o clock
* position, but itself will not be rotated. If not defined, defaults to false.
+ *
+ * <p>Note that this field only supports static values.
*/
@RequiresSchemaVersion(major = 1, minor = 0)
@NonNull
public Builder setRotateContents(@NonNull BoolProp rotateContents) {
+ if (rotateContents.getDynamicValue() != null) {
+ throw new IllegalArgumentException(
+ "ArcAdapter.Builder.setRotateContents doesn't support dynamic values.");
+ }
mImpl.setRotateContents(rotateContents.toProto());
mFingerprint.recordPropertyUpdate(
2, checkNotNull(rotateContents.getFingerprint()).aggregateValueAsInt());
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ModifiersBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ModifiersBuilders.java
index 8486230..51f3c14 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ModifiersBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ModifiersBuilders.java
@@ -858,10 +858,16 @@
* start/end will follow the layout direction (i.e. start will refer to the right hand
* side of the container if the device is using an RTL locale). If false, start/end will
* always map to left/right, accordingly.
+ *
+ * <p>Note that this field only supports static values.
*/
@RequiresSchemaVersion(major = 1, minor = 0)
@NonNull
public Builder setRtlAware(@NonNull BoolProp rtlAware) {
+ if (rtlAware.getDynamicValue() != null) {
+ throw new IllegalArgumentException(
+ "Padding.Builder.setRtlAware doesn't support dynamic values.");
+ }
mImpl.setRtlAware(rtlAware.toProto());
mFingerprint.recordPropertyUpdate(
5, checkNotNull(rtlAware.getFingerprint()).aggregateValueAsInt());
@@ -1409,20 +1415,17 @@
}
/**
- * Gets whether the attached element is hidden, or visible. If the element is hidden, then
+ * Gets whether the attached element is visible, or hidden. If the element is hidden, then
* it will still consume space in the layout, but will not render any contents, nor will any
- * children render any contents.
- *
- * <p>Note that a hidden element also cannot be clickable (i.e. a {@link Clickable} modifier
- * would be ignored).
+ * children render any contents. Defaults to visible.
*/
@ProtoLayoutExperimental
- @Nullable
- public BoolProp getHidden() {
- if (mImpl.hasHidden()) {
- return BoolProp.fromProto(mImpl.getHidden());
+ @NonNull
+ public BoolProp isVisible() {
+ if (mImpl.hasVisible()) {
+ return BoolProp.fromProto(mImpl.getVisible());
} else {
- return null;
+ return new BoolProp.Builder(true).build();
}
}
@@ -1477,8 +1480,8 @@
+ getMetadata()
+ ", contentUpdateAnimation="
+ getContentUpdateAnimation()
- + ", hidden="
- + getHidden()
+ + ", visible="
+ + isVisible()
+ "}";
}
@@ -1578,22 +1581,23 @@
}
/**
- * Sets whether the attached element is hidden, or visible. If the element is hidden,
+ * Sets whether the attached element is visible, or hidden. If the element is hidden,
* then it will still consume space in the layout, but will not render any contents, nor
- * will any children render any contents.
+ * will any children render any contents. Defaults to visible.
*
* <p>Note that a hidden element also cannot be clickable (i.e. a {@link Clickable}
* modifier would be ignored).
*
- * <p>Defaults to false (i.e. not hidden).
+ * <p>This field is bindable and will use the dynamic value (if set).
*/
@RequiresSchemaVersion(major = 1, minor = 300)
@ProtoLayoutExperimental
+ @SuppressLint("MissingGetterMatchingBuilder")
@NonNull
- public Builder setHidden(@NonNull BoolProp hidden) {
- mImpl.setHidden(hidden.toProto());
+ public Builder setVisible(@NonNull BoolProp visible) {
+ mImpl.setVisible(visible.toProto());
mFingerprint.recordPropertyUpdate(
- 8, checkNotNull(hidden.getFingerprint()).aggregateValueAsInt());
+ 10, checkNotNull(visible.getFingerprint()).aggregateValueAsInt());
return this;
}
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TypeBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TypeBuilders.java
index fc814c8..96f7117 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TypeBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TypeBuilders.java
@@ -494,7 +494,11 @@
this.mFingerprint = fingerprint;
}
- /** Gets the static value. */
+ /**
+ * Gets the static value. If a dynamic value is also set and the renderer supports dynamic
+ * values for the corresponding field, this static value will be ignored. If the static
+ * value is not specified, false will be used instead.
+ */
public boolean getValue() {
return mImpl.getValue();
}
@@ -543,7 +547,12 @@
@Override
@NonNull
public String toString() {
- return "BoolProp{" + "value=" + getValue() + "}";
+ return "BoolProp{"
+ + "value="
+ + getValue()
+ + ", dynamicValue="
+ + getDynamicValue()
+ + "}";
}
/** Builder for {@link BoolProp} */
@@ -567,7 +576,11 @@
@Deprecated
public Builder() {}
- /** Sets the static value. */
+ /**
+ * Sets the static value. If a dynamic value is also set and the renderer supports
+ * dynamic values for the corresponding field, this static value will be ignored. If the
+ * static value is not specified, false will be used instead.
+ */
@RequiresSchemaVersion(major = 1, minor = 0)
@SuppressLint("MissingGetterMatchingBuilder")
@NonNull
diff --git a/wear/tiles/tiles-tooling-preview/build.gradle b/wear/tiles/tiles-tooling-preview/build.gradle
index 95af193..8e93c514 100644
--- a/wear/tiles/tiles-tooling-preview/build.gradle
+++ b/wear/tiles/tiles-tooling-preview/build.gradle
@@ -28,7 +28,7 @@
implementation(project(":wear:protolayout:protolayout-proto"))
implementation(project(":wear:tiles:tiles"))
- api("androidx.wear:wear-tooling-preview:1.0.0-alpha01")
+ api("androidx.wear:wear-tooling-preview:1.0.0")
api("androidx.annotation:annotation:1.6.0")
}
diff --git a/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/Data.kt b/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/Data.kt
index ff20104..ea4cc25 100644
--- a/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/Data.kt
+++ b/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/Data.kt
@@ -124,10 +124,10 @@
* @property dataSource The [ComponentName] of the
* [androidx.wear.watchface.complications.datasource.ComplicationDataSourceService] that provided
* the ComplicationData. This may be `null` when run on old systems.
- * @property persistencePolicy The [ComplicationPersistencePolicy] for this complication. This
- * requires the watchface to be built with a compatible library to work.
- * @property displayPolicy The [ComplicationDisplayPolicy] for this complication. This requires the
- * watchface to be built with a compatible library to work.
+ * @property persistencePolicy The [persistence policy][ComplicationPersistencePolicies] for this
+ * complication. This requires the watchface to be built with a compatible library to work.
+ * @property displayPolicy The [display policy][ComplicationDisplayPolicies] for this complication.
+ * This requires the watchface to be built with a compatible library to work.
* @property dynamicValueInvalidationFallback Used in case any dynamic value has been invalidated.
*
* IMPORTANT: This is only used when the system supports dynamic values. See each dynamic field's
@@ -255,7 +255,7 @@
return this as BuilderT
}
- /** Sets the complication's [ComplicationPersistencePolicy]. */
+ /** Sets the complication's [persistence policy][ComplicationPersistencePolicies]. */
@Suppress("UNCHECKED_CAST", "SetterReturnsThis")
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
public fun setPersistencePolicy(
@@ -265,7 +265,7 @@
return this as BuilderT
}
- /** Sets the complication's [ComplicationDisplayPolicy]. */
+ /** Sets the complication's [display policy][ComplicationDisplayPolicies]. */
@Suppress("UNCHECKED_CAST", "SetterReturnsThis")
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
public fun setDisplayPolicy(@ComplicationDisplayPolicy displayPolicy: Int): BuilderT {
diff --git a/webkit/integration-tests/instrumentation/src/androidTest/java/androidx/webkit/WebSettingsCompatDarkModeTestBase.java b/webkit/integration-tests/instrumentation/src/androidTest/java/androidx/webkit/WebSettingsCompatDarkModeTestBase.java
index 1b50075..31c4b7d 100644
--- a/webkit/integration-tests/instrumentation/src/androidTest/java/androidx/webkit/WebSettingsCompatDarkModeTestBase.java
+++ b/webkit/integration-tests/instrumentation/src/androidTest/java/androidx/webkit/WebSettingsCompatDarkModeTestBase.java
@@ -20,14 +20,12 @@
import android.graphics.Bitmap;
import android.graphics.Color;
-import android.os.Build;
import android.util.Base64;
import android.view.ViewGroup;
import android.webkit.WebSettings;
import android.webkit.WebView;
import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
@@ -42,7 +40,6 @@
/**
* Base class for dark mode related test.
*/
-@RequiresApi(Build.VERSION_CODES.KITKAT)
public class WebSettingsCompatDarkModeTestBase<T extends WebViewTestActivity> {
// The size of WebViews to use in the app.
diff --git a/webkit/integration-tests/instrumentation/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java b/webkit/integration-tests/instrumentation/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java
index d22e732..ed2df16 100644
--- a/webkit/integration-tests/instrumentation/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java
+++ b/webkit/integration-tests/instrumentation/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java
@@ -24,7 +24,6 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.net.Uri;
-import android.os.Build;
import android.os.Looper;
import android.os.SystemClock;
import android.webkit.ValueCallback;
@@ -36,7 +35,6 @@
import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
import androidx.concurrent.futures.ResolvableFuture;
import androidx.test.core.app.ApplicationProvider;
@@ -53,7 +51,6 @@
* Modifications to this class should be reflected in that class as necessary. See
* http://go/modifying-webview-cts.
*/
-@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public class WebViewOnUiThread implements AutoCloseable{
/**
* The maximum time, in milliseconds (10 seconds) to wait for a load
diff --git a/webkit/webkit/api/1.10.0-beta01.txt b/webkit/webkit/api/1.10.0-beta01.txt
new file mode 100644
index 0000000..0a06f1f
--- /dev/null
+++ b/webkit/webkit/api/1.10.0-beta01.txt
@@ -0,0 +1,417 @@
+// Signature format: 4.0
+package androidx.webkit {
+
+ public class CookieManagerCompat {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_COOKIE_INFO, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static java.util.List<java.lang.String!> getCookieInfo(android.webkit.CookieManager, String);
+ }
+
+ public final class DropDataContentProvider extends android.content.ContentProvider {
+ ctor public DropDataContentProvider();
+ method public int delete(android.net.Uri, String?, String![]?);
+ method public String? getType(android.net.Uri);
+ method public android.net.Uri? insert(android.net.Uri, android.content.ContentValues?);
+ method public boolean onCreate();
+ method public android.database.Cursor? query(android.net.Uri, String![]?, String?, String![]?, String?);
+ method public int update(android.net.Uri, android.content.ContentValues?, String?, String![]?);
+ }
+
+ public abstract class JavaScriptReplyProxy {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(byte[]);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(String);
+ }
+
+ public class ProcessGlobalConfig {
+ ctor public ProcessGlobalConfig();
+ method public static void apply(androidx.webkit.ProcessGlobalConfig);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX, enforcement="androidx.webkit.WebViewFeature#isConfigFeatureSupported(String, Context)") public androidx.webkit.ProcessGlobalConfig setDataDirectorySuffix(android.content.Context, String);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS, enforcement="androidx.webkit.WebViewFeature#isConfigFeatureSupported(String, Context)") public androidx.webkit.ProcessGlobalConfig setDirectoryBasePaths(android.content.Context, java.io.File, java.io.File);
+ }
+
+ public interface Profile {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public android.webkit.CookieManager getCookieManager();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public android.webkit.GeolocationPermissions getGeolocationPermissions();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public String getName();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public android.webkit.ServiceWorkerController getServiceWorkerController();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public android.webkit.WebStorage getWebStorage();
+ field public static final String DEFAULT_PROFILE_NAME = "Default";
+ }
+
+ @UiThread public interface ProfileStore {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public boolean deleteProfile(String);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public java.util.List<java.lang.String!> getAllProfileNames();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.ProfileStore getInstance();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public androidx.webkit.Profile getOrCreateProfile(String);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public androidx.webkit.Profile? getProfile(String);
+ }
+
+ public final class ProxyConfig {
+ method public java.util.List<java.lang.String!> getBypassRules();
+ method public java.util.List<androidx.webkit.ProxyConfig.ProxyRule!> getProxyRules();
+ method public boolean isReverseBypassEnabled();
+ field public static final String MATCH_ALL_SCHEMES = "*";
+ field public static final String MATCH_HTTP = "http";
+ field public static final String MATCH_HTTPS = "https";
+ }
+
+ public static final class ProxyConfig.Builder {
+ ctor public ProxyConfig.Builder();
+ ctor public ProxyConfig.Builder(androidx.webkit.ProxyConfig);
+ method public androidx.webkit.ProxyConfig.Builder addBypassRule(String);
+ method public androidx.webkit.ProxyConfig.Builder addDirect();
+ method public androidx.webkit.ProxyConfig.Builder addDirect(String);
+ method public androidx.webkit.ProxyConfig.Builder addProxyRule(String);
+ method public androidx.webkit.ProxyConfig.Builder addProxyRule(String, String);
+ method public androidx.webkit.ProxyConfig build();
+ method public androidx.webkit.ProxyConfig.Builder bypassSimpleHostnames();
+ method public androidx.webkit.ProxyConfig.Builder removeImplicitRules();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.PROXY_OVERRIDE_REVERSE_BYPASS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public androidx.webkit.ProxyConfig.Builder setReverseBypassEnabled(boolean);
+ }
+
+ public static final class ProxyConfig.ProxyRule {
+ method public String getSchemeFilter();
+ method public String getUrl();
+ }
+
+ public abstract class ProxyController {
+ method public abstract void clearProxyOverride(java.util.concurrent.Executor, Runnable);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.PROXY_OVERRIDE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.ProxyController getInstance();
+ method public abstract void setProxyOverride(androidx.webkit.ProxyConfig, java.util.concurrent.Executor, Runnable);
+ }
+
+ public abstract class SafeBrowsingResponseCompat {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void backToSafety(boolean);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_RESPONSE_PROCEED, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void proceed(boolean);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void showInterstitial(boolean);
+ }
+
+ public interface ScriptHandler {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.DOCUMENT_START_SCRIPT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public void remove();
+ }
+
+ public abstract class ServiceWorkerClientCompat {
+ ctor public ServiceWorkerClientCompat();
+ method @WorkerThread public abstract android.webkit.WebResourceResponse? shouldInterceptRequest(android.webkit.WebResourceRequest);
+ }
+
+ public abstract class ServiceWorkerControllerCompat {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.ServiceWorkerControllerCompat getInstance();
+ method public abstract androidx.webkit.ServiceWorkerWebSettingsCompat getServiceWorkerWebSettings();
+ method public abstract void setServiceWorkerClient(androidx.webkit.ServiceWorkerClientCompat?);
+ }
+
+ public abstract class ServiceWorkerWebSettingsCompat {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CONTENT_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract boolean getAllowContentAccess();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_FILE_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract boolean getAllowFileAccess();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract boolean getBlockNetworkLoads();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CACHE_MODE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract int getCacheMode();
+ method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract java.util.Set<java.lang.String!> getRequestedWithHeaderOriginAllowList();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CONTENT_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setAllowContentAccess(boolean);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_FILE_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setAllowFileAccess(boolean);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setBlockNetworkLoads(boolean);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CACHE_MODE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setCacheMode(int);
+ method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setRequestedWithHeaderOriginAllowList(java.util.Set<java.lang.String!>);
+ }
+
+ public class TracingConfig {
+ method public java.util.List<java.lang.String!> getCustomIncludedCategories();
+ method public int getPredefinedCategories();
+ method public int getTracingMode();
+ field public static final int CATEGORIES_ALL = 1; // 0x1
+ field public static final int CATEGORIES_ANDROID_WEBVIEW = 2; // 0x2
+ field public static final int CATEGORIES_FRAME_VIEWER = 64; // 0x40
+ field public static final int CATEGORIES_INPUT_LATENCY = 8; // 0x8
+ field public static final int CATEGORIES_JAVASCRIPT_AND_RENDERING = 32; // 0x20
+ field public static final int CATEGORIES_NONE = 0; // 0x0
+ field public static final int CATEGORIES_RENDERING = 16; // 0x10
+ field public static final int CATEGORIES_WEB_DEVELOPER = 4; // 0x4
+ field public static final int RECORD_CONTINUOUSLY = 1; // 0x1
+ field public static final int RECORD_UNTIL_FULL = 0; // 0x0
+ }
+
+ public static class TracingConfig.Builder {
+ ctor public TracingConfig.Builder();
+ method public androidx.webkit.TracingConfig.Builder addCategories(int...);
+ method public androidx.webkit.TracingConfig.Builder addCategories(java.lang.String!...);
+ method public androidx.webkit.TracingConfig.Builder addCategories(java.util.Collection<java.lang.String!>);
+ method public androidx.webkit.TracingConfig build();
+ method public androidx.webkit.TracingConfig.Builder setTracingMode(int);
+ }
+
+ public abstract class TracingController {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.TRACING_CONTROLLER_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.TracingController getInstance();
+ method public abstract boolean isTracing();
+ method public abstract void start(androidx.webkit.TracingConfig);
+ method public abstract boolean stop(java.io.OutputStream?, java.util.concurrent.Executor);
+ }
+
+ public final class UserAgentMetadata {
+ method public String? getArchitecture();
+ method public int getBitness();
+ method public java.util.List<androidx.webkit.UserAgentMetadata.BrandVersion!> getBrandVersionList();
+ method public String? getFullVersion();
+ method public String? getModel();
+ method public String? getPlatform();
+ method public String? getPlatformVersion();
+ method public boolean isMobile();
+ method public boolean isWow64();
+ field public static final int BITNESS_DEFAULT = 0; // 0x0
+ }
+
+ public static final class UserAgentMetadata.BrandVersion {
+ method public String getBrand();
+ method public String getFullVersion();
+ method public String getMajorVersion();
+ }
+
+ public static final class UserAgentMetadata.BrandVersion.Builder {
+ ctor public UserAgentMetadata.BrandVersion.Builder();
+ ctor public UserAgentMetadata.BrandVersion.Builder(androidx.webkit.UserAgentMetadata.BrandVersion);
+ method public androidx.webkit.UserAgentMetadata.BrandVersion build();
+ method public androidx.webkit.UserAgentMetadata.BrandVersion.Builder setBrand(String);
+ method public androidx.webkit.UserAgentMetadata.BrandVersion.Builder setFullVersion(String);
+ method public androidx.webkit.UserAgentMetadata.BrandVersion.Builder setMajorVersion(String);
+ }
+
+ public static final class UserAgentMetadata.Builder {
+ ctor public UserAgentMetadata.Builder();
+ ctor public UserAgentMetadata.Builder(androidx.webkit.UserAgentMetadata);
+ method public androidx.webkit.UserAgentMetadata build();
+ method public androidx.webkit.UserAgentMetadata.Builder setArchitecture(String?);
+ method public androidx.webkit.UserAgentMetadata.Builder setBitness(int);
+ method public androidx.webkit.UserAgentMetadata.Builder setBrandVersionList(java.util.List<androidx.webkit.UserAgentMetadata.BrandVersion!>);
+ method public androidx.webkit.UserAgentMetadata.Builder setFullVersion(String?);
+ method public androidx.webkit.UserAgentMetadata.Builder setMobile(boolean);
+ method public androidx.webkit.UserAgentMetadata.Builder setModel(String?);
+ method public androidx.webkit.UserAgentMetadata.Builder setPlatform(String?);
+ method public androidx.webkit.UserAgentMetadata.Builder setPlatformVersion(String?);
+ method public androidx.webkit.UserAgentMetadata.Builder setWow64(boolean);
+ }
+
+ public class WebMessageCompat {
+ ctor @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public WebMessageCompat(byte[]);
+ ctor @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public WebMessageCompat(byte[], androidx.webkit.WebMessagePortCompat![]?);
+ ctor public WebMessageCompat(String?);
+ ctor public WebMessageCompat(String?, androidx.webkit.WebMessagePortCompat![]?);
+ method public byte[] getArrayBuffer();
+ method public String? getData();
+ method public androidx.webkit.WebMessagePortCompat![]? getPorts();
+ method public int getType();
+ field public static final int TYPE_ARRAY_BUFFER = 1; // 0x1
+ field public static final int TYPE_STRING = 0; // 0x0
+ }
+
+ public abstract class WebMessagePortCompat {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_CLOSE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void close();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_POST_MESSAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(androidx.webkit.WebMessageCompat);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setWebMessageCallback(android.os.Handler?, androidx.webkit.WebMessagePortCompat.WebMessageCallbackCompat);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setWebMessageCallback(androidx.webkit.WebMessagePortCompat.WebMessageCallbackCompat);
+ }
+
+ public abstract static class WebMessagePortCompat.WebMessageCallbackCompat {
+ ctor public WebMessagePortCompat.WebMessageCallbackCompat();
+ method public void onMessage(androidx.webkit.WebMessagePortCompat, androidx.webkit.WebMessageCompat?);
+ }
+
+ public abstract class WebResourceErrorCompat {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_RESOURCE_ERROR_GET_DESCRIPTION, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract CharSequence getDescription();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_RESOURCE_ERROR_GET_CODE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract int getErrorCode();
+ }
+
+ public class WebResourceRequestCompat {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_RESOURCE_REQUEST_IS_REDIRECT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean isRedirect(android.webkit.WebResourceRequest);
+ }
+
+ public class WebSettingsCompat {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.ATTRIBUTION_REGISTRATION_BEHAVIOR, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getAttributionRegistrationBehavior(android.webkit.WebSettings);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getDisabledActionModeMenuItems(android.webkit.WebSettings);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean getEnterpriseAuthenticationAppLinkPolicyEnabled(android.webkit.WebSettings);
+ method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getForceDark(android.webkit.WebSettings);
+ method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK_STRATEGY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getForceDarkStrategy(android.webkit.WebSettings);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.OFF_SCREEN_PRERASTER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean getOffscreenPreRaster(android.webkit.WebSettings);
+ method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static java.util.Set<java.lang.String!> getRequestedWithHeaderOriginAllowList(android.webkit.WebSettings);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ENABLE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean getSafeBrowsingEnabled(android.webkit.WebSettings);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.USER_AGENT_METADATA, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.UserAgentMetadata getUserAgentMetadata(android.webkit.WebSettings);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEBVIEW_MEDIA_INTEGRITY_API_STATUS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.WebViewMediaIntegrityApiStatusConfig getWebViewMediaIntegrityApiStatus(android.webkit.WebSettings);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.ALGORITHMIC_DARKENING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean isAlgorithmicDarkeningAllowed(android.webkit.WebSettings);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.ALGORITHMIC_DARKENING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setAlgorithmicDarkeningAllowed(android.webkit.WebSettings, boolean);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.ATTRIBUTION_REGISTRATION_BEHAVIOR, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setAttributionRegistrationBehavior(android.webkit.WebSettings, int);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setDisabledActionModeMenuItems(android.webkit.WebSettings, int);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setEnterpriseAuthenticationAppLinkPolicyEnabled(android.webkit.WebSettings, boolean);
+ method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setForceDark(android.webkit.WebSettings, int);
+ method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK_STRATEGY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setForceDarkStrategy(android.webkit.WebSettings, int);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.OFF_SCREEN_PRERASTER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setOffscreenPreRaster(android.webkit.WebSettings, boolean);
+ method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setRequestedWithHeaderOriginAllowList(android.webkit.WebSettings, java.util.Set<java.lang.String!>);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ENABLE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingEnabled(android.webkit.WebSettings, boolean);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.USER_AGENT_METADATA, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setUserAgentMetadata(android.webkit.WebSettings, androidx.webkit.UserAgentMetadata);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEBVIEW_MEDIA_INTEGRITY_API_STATUS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setWebViewMediaIntegrityApiStatus(android.webkit.WebSettings, androidx.webkit.WebViewMediaIntegrityApiStatusConfig);
+ field public static final int ATTRIBUTION_BEHAVIOR_APP_SOURCE_AND_APP_TRIGGER = 3; // 0x3
+ field public static final int ATTRIBUTION_BEHAVIOR_APP_SOURCE_AND_WEB_TRIGGER = 1; // 0x1
+ field public static final int ATTRIBUTION_BEHAVIOR_DISABLED = 0; // 0x0
+ field public static final int ATTRIBUTION_BEHAVIOR_WEB_SOURCE_AND_WEB_TRIGGER = 2; // 0x2
+ field @Deprecated public static final int DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING = 2; // 0x2
+ field @Deprecated public static final int DARK_STRATEGY_USER_AGENT_DARKENING_ONLY = 0; // 0x0
+ field @Deprecated public static final int DARK_STRATEGY_WEB_THEME_DARKENING_ONLY = 1; // 0x1
+ field @Deprecated public static final int FORCE_DARK_AUTO = 1; // 0x1
+ field @Deprecated public static final int FORCE_DARK_OFF = 0; // 0x0
+ field @Deprecated public static final int FORCE_DARK_ON = 2; // 0x2
+ }
+
+ public final class WebViewAssetLoader {
+ method @WorkerThread public android.webkit.WebResourceResponse? shouldInterceptRequest(android.net.Uri);
+ field public static final String DEFAULT_DOMAIN = "appassets.androidplatform.net";
+ }
+
+ public static final class WebViewAssetLoader.AssetsPathHandler implements androidx.webkit.WebViewAssetLoader.PathHandler {
+ ctor public WebViewAssetLoader.AssetsPathHandler(android.content.Context);
+ method @WorkerThread public android.webkit.WebResourceResponse? handle(String);
+ }
+
+ public static final class WebViewAssetLoader.Builder {
+ ctor public WebViewAssetLoader.Builder();
+ method public androidx.webkit.WebViewAssetLoader.Builder addPathHandler(String, androidx.webkit.WebViewAssetLoader.PathHandler);
+ method public androidx.webkit.WebViewAssetLoader build();
+ method public androidx.webkit.WebViewAssetLoader.Builder setDomain(String);
+ method public androidx.webkit.WebViewAssetLoader.Builder setHttpAllowed(boolean);
+ }
+
+ public static final class WebViewAssetLoader.InternalStoragePathHandler implements androidx.webkit.WebViewAssetLoader.PathHandler {
+ ctor public WebViewAssetLoader.InternalStoragePathHandler(android.content.Context, java.io.File);
+ method @WorkerThread public android.webkit.WebResourceResponse handle(String);
+ }
+
+ public static interface WebViewAssetLoader.PathHandler {
+ method @WorkerThread public android.webkit.WebResourceResponse? handle(String);
+ }
+
+ public static final class WebViewAssetLoader.ResourcesPathHandler implements androidx.webkit.WebViewAssetLoader.PathHandler {
+ ctor public WebViewAssetLoader.ResourcesPathHandler(android.content.Context);
+ method @WorkerThread public android.webkit.WebResourceResponse? handle(String);
+ }
+
+ public class WebViewClientCompat extends android.webkit.WebViewClient {
+ ctor public WebViewClientCompat();
+ method @RequiresApi(23) public final void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceError);
+ method @RequiresApi(21) @UiThread public void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, androidx.webkit.WebResourceErrorCompat);
+ method @RequiresApi(27) public final void onSafeBrowsingHit(android.webkit.WebView, android.webkit.WebResourceRequest, int, android.webkit.SafeBrowsingResponse);
+ method @UiThread public void onSafeBrowsingHit(android.webkit.WebView, android.webkit.WebResourceRequest, int, androidx.webkit.SafeBrowsingResponseCompat);
+ }
+
+ public class WebViewCompat {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.DOCUMENT_START_SCRIPT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.ScriptHandler addDocumentStartJavaScript(android.webkit.WebView, String, java.util.Set<java.lang.String!>);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void addWebMessageListener(android.webkit.WebView, String, java.util.Set<java.lang.String!>, androidx.webkit.WebViewCompat.WebMessageListener);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.CREATE_WEB_MESSAGE_CHANNEL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.WebMessagePortCompat![] createWebMessageChannel(android.webkit.WebView);
+ method public static android.content.pm.PackageInfo? getCurrentWebViewPackage(android.content.Context);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static androidx.webkit.Profile getProfile(android.webkit.WebView);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_PRIVACY_POLICY_URL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_VARIATIONS_HEADER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static String getVariationsHeader();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_CHROME_CLIENT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.webkit.WebChromeClient? getWebChromeClient(android.webkit.WebView);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_VIEW_CLIENT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.webkit.WebViewClient getWebViewClient(android.webkit.WebView);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_VIEW_RENDERER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.WebViewRenderProcess? getWebViewRenderProcess(android.webkit.WebView);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.WebViewRenderProcessClient? getWebViewRenderProcessClient(android.webkit.WebView);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean isMultiProcessEnabled();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.VISUAL_STATE_CALLBACK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void postVisualStateCallback(android.webkit.WebView, long, androidx.webkit.WebViewCompat.VisualStateCallback);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.POST_WEB_MESSAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void postWebMessage(android.webkit.WebView, androidx.webkit.WebMessageCompat, android.net.Uri);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void removeWebMessageListener(android.webkit.WebView, String);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static void setProfile(android.webkit.WebView, String);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ALLOWLIST, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingAllowlist(java.util.Set<java.lang.String!>, android.webkit.ValueCallback<java.lang.Boolean!>?);
+ method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_WHITELIST, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingWhitelist(java.util.List<java.lang.String!>, android.webkit.ValueCallback<java.lang.Boolean!>?);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setWebViewRenderProcessClient(android.webkit.WebView, androidx.webkit.WebViewRenderProcessClient?);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setWebViewRenderProcessClient(android.webkit.WebView, java.util.concurrent.Executor, androidx.webkit.WebViewRenderProcessClient);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.START_SAFE_BROWSING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void startSafeBrowsing(android.content.Context, android.webkit.ValueCallback<java.lang.Boolean!>?);
+ }
+
+ public static interface WebViewCompat.VisualStateCallback {
+ method @UiThread public void onComplete(long);
+ }
+
+ public static interface WebViewCompat.WebMessageListener {
+ method @UiThread public void onPostMessage(android.webkit.WebView, androidx.webkit.WebMessageCompat, android.net.Uri, boolean, androidx.webkit.JavaScriptReplyProxy);
+ }
+
+ public class WebViewFeature {
+ method public static boolean isFeatureSupported(String);
+ method public static boolean isStartupFeatureSupported(android.content.Context, String);
+ field public static final String ALGORITHMIC_DARKENING = "ALGORITHMIC_DARKENING";
+ field public static final String ATTRIBUTION_REGISTRATION_BEHAVIOR = "ATTRIBUTION_REGISTRATION_BEHAVIOR";
+ field public static final String CREATE_WEB_MESSAGE_CHANNEL = "CREATE_WEB_MESSAGE_CHANNEL";
+ field public static final String DISABLED_ACTION_MODE_MENU_ITEMS = "DISABLED_ACTION_MODE_MENU_ITEMS";
+ field public static final String DOCUMENT_START_SCRIPT = "DOCUMENT_START_SCRIPT";
+ field public static final String ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY = "ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY";
+ field public static final String FORCE_DARK = "FORCE_DARK";
+ field public static final String FORCE_DARK_STRATEGY = "FORCE_DARK_STRATEGY";
+ field public static final String GET_COOKIE_INFO = "GET_COOKIE_INFO";
+ field public static final String GET_VARIATIONS_HEADER = "GET_VARIATIONS_HEADER";
+ field public static final String GET_WEB_CHROME_CLIENT = "GET_WEB_CHROME_CLIENT";
+ field public static final String GET_WEB_VIEW_CLIENT = "GET_WEB_VIEW_CLIENT";
+ field public static final String GET_WEB_VIEW_RENDERER = "GET_WEB_VIEW_RENDERER";
+ field public static final String MULTI_PROCESS = "MULTI_PROCESS";
+ field public static final String MULTI_PROFILE = "MULTI_PROFILE";
+ field public static final String OFF_SCREEN_PRERASTER = "OFF_SCREEN_PRERASTER";
+ field public static final String POST_WEB_MESSAGE = "POST_WEB_MESSAGE";
+ field public static final String PROXY_OVERRIDE = "PROXY_OVERRIDE";
+ field public static final String PROXY_OVERRIDE_REVERSE_BYPASS = "PROXY_OVERRIDE_REVERSE_BYPASS";
+ field public static final String RECEIVE_HTTP_ERROR = "RECEIVE_HTTP_ERROR";
+ field public static final String RECEIVE_WEB_RESOURCE_ERROR = "RECEIVE_WEB_RESOURCE_ERROR";
+ field public static final String SAFE_BROWSING_ALLOWLIST = "SAFE_BROWSING_ALLOWLIST";
+ field public static final String SAFE_BROWSING_ENABLE = "SAFE_BROWSING_ENABLE";
+ field public static final String SAFE_BROWSING_HIT = "SAFE_BROWSING_HIT";
+ field public static final String SAFE_BROWSING_PRIVACY_POLICY_URL = "SAFE_BROWSING_PRIVACY_POLICY_URL";
+ field public static final String SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY = "SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY";
+ field public static final String SAFE_BROWSING_RESPONSE_PROCEED = "SAFE_BROWSING_RESPONSE_PROCEED";
+ field public static final String SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL = "SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL";
+ field @Deprecated public static final String SAFE_BROWSING_WHITELIST = "SAFE_BROWSING_WHITELIST";
+ field public static final String SERVICE_WORKER_BASIC_USAGE = "SERVICE_WORKER_BASIC_USAGE";
+ field public static final String SERVICE_WORKER_BLOCK_NETWORK_LOADS = "SERVICE_WORKER_BLOCK_NETWORK_LOADS";
+ field public static final String SERVICE_WORKER_CACHE_MODE = "SERVICE_WORKER_CACHE_MODE";
+ field public static final String SERVICE_WORKER_CONTENT_ACCESS = "SERVICE_WORKER_CONTENT_ACCESS";
+ field public static final String SERVICE_WORKER_FILE_ACCESS = "SERVICE_WORKER_FILE_ACCESS";
+ field public static final String SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST = "SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST";
+ field public static final String SHOULD_OVERRIDE_WITH_REDIRECTS = "SHOULD_OVERRIDE_WITH_REDIRECTS";
+ field public static final String STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX = "STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX";
+ field public static final String STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS = "STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS";
+ field public static final String START_SAFE_BROWSING = "START_SAFE_BROWSING";
+ field public static final String TRACING_CONTROLLER_BASIC_USAGE = "TRACING_CONTROLLER_BASIC_USAGE";
+ field public static final String USER_AGENT_METADATA = "USER_AGENT_METADATA";
+ field public static final String VISUAL_STATE_CALLBACK = "VISUAL_STATE_CALLBACK";
+ field public static final String WEBVIEW_MEDIA_INTEGRITY_API_STATUS = "WEBVIEW_MEDIA_INTEGRITY_API_STATUS";
+ field public static final String WEB_MESSAGE_ARRAY_BUFFER = "WEB_MESSAGE_ARRAY_BUFFER";
+ field public static final String WEB_MESSAGE_CALLBACK_ON_MESSAGE = "WEB_MESSAGE_CALLBACK_ON_MESSAGE";
+ field public static final String WEB_MESSAGE_LISTENER = "WEB_MESSAGE_LISTENER";
+ field public static final String WEB_MESSAGE_PORT_CLOSE = "WEB_MESSAGE_PORT_CLOSE";
+ field public static final String WEB_MESSAGE_PORT_POST_MESSAGE = "WEB_MESSAGE_PORT_POST_MESSAGE";
+ field public static final String WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK = "WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK";
+ field public static final String WEB_RESOURCE_ERROR_GET_CODE = "WEB_RESOURCE_ERROR_GET_CODE";
+ field public static final String WEB_RESOURCE_ERROR_GET_DESCRIPTION = "WEB_RESOURCE_ERROR_GET_DESCRIPTION";
+ field public static final String WEB_RESOURCE_REQUEST_IS_REDIRECT = "WEB_RESOURCE_REQUEST_IS_REDIRECT";
+ field public static final String WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE = "WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE";
+ field public static final String WEB_VIEW_RENDERER_TERMINATE = "WEB_VIEW_RENDERER_TERMINATE";
+ }
+
+ @RequiresFeature(name=androidx.webkit.WebViewFeature.WEBVIEW_MEDIA_INTEGRITY_API_STATUS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public class WebViewMediaIntegrityApiStatusConfig {
+ ctor public WebViewMediaIntegrityApiStatusConfig(androidx.webkit.WebViewMediaIntegrityApiStatusConfig.Builder);
+ method public int getDefaultStatus();
+ method public java.util.Map<java.lang.String!,java.lang.Integer!> getOverrideRules();
+ field public static final int WEBVIEW_MEDIA_INTEGRITY_API_DISABLED = 0; // 0x0
+ field public static final int WEBVIEW_MEDIA_INTEGRITY_API_ENABLED = 2; // 0x2
+ field public static final int WEBVIEW_MEDIA_INTEGRITY_API_ENABLED_WITHOUT_APP_IDENTITY = 1; // 0x1
+ }
+
+ public static final class WebViewMediaIntegrityApiStatusConfig.Builder {
+ ctor public WebViewMediaIntegrityApiStatusConfig.Builder(int);
+ method public androidx.webkit.WebViewMediaIntegrityApiStatusConfig.Builder addOverrideRule(String, int);
+ method public androidx.webkit.WebViewMediaIntegrityApiStatusConfig build();
+ }
+
+ public abstract class WebViewRenderProcess {
+ ctor public WebViewRenderProcess();
+ method public abstract boolean terminate();
+ }
+
+ public abstract class WebViewRenderProcessClient {
+ ctor public WebViewRenderProcessClient();
+ method public abstract void onRenderProcessResponsive(android.webkit.WebView, androidx.webkit.WebViewRenderProcess?);
+ method public abstract void onRenderProcessUnresponsive(android.webkit.WebView, androidx.webkit.WebViewRenderProcess?);
+ }
+
+}
+
diff --git a/webkit/webkit/api/res-1.10.0-beta01.txt b/webkit/webkit/api/res-1.10.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/webkit/webkit/api/res-1.10.0-beta01.txt
diff --git a/webkit/webkit/api/restricted_1.10.0-beta01.txt b/webkit/webkit/api/restricted_1.10.0-beta01.txt
new file mode 100644
index 0000000..0a06f1f
--- /dev/null
+++ b/webkit/webkit/api/restricted_1.10.0-beta01.txt
@@ -0,0 +1,417 @@
+// Signature format: 4.0
+package androidx.webkit {
+
+ public class CookieManagerCompat {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_COOKIE_INFO, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static java.util.List<java.lang.String!> getCookieInfo(android.webkit.CookieManager, String);
+ }
+
+ public final class DropDataContentProvider extends android.content.ContentProvider {
+ ctor public DropDataContentProvider();
+ method public int delete(android.net.Uri, String?, String![]?);
+ method public String? getType(android.net.Uri);
+ method public android.net.Uri? insert(android.net.Uri, android.content.ContentValues?);
+ method public boolean onCreate();
+ method public android.database.Cursor? query(android.net.Uri, String![]?, String?, String![]?, String?);
+ method public int update(android.net.Uri, android.content.ContentValues?, String?, String![]?);
+ }
+
+ public abstract class JavaScriptReplyProxy {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(byte[]);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(String);
+ }
+
+ public class ProcessGlobalConfig {
+ ctor public ProcessGlobalConfig();
+ method public static void apply(androidx.webkit.ProcessGlobalConfig);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX, enforcement="androidx.webkit.WebViewFeature#isConfigFeatureSupported(String, Context)") public androidx.webkit.ProcessGlobalConfig setDataDirectorySuffix(android.content.Context, String);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS, enforcement="androidx.webkit.WebViewFeature#isConfigFeatureSupported(String, Context)") public androidx.webkit.ProcessGlobalConfig setDirectoryBasePaths(android.content.Context, java.io.File, java.io.File);
+ }
+
+ public interface Profile {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public android.webkit.CookieManager getCookieManager();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public android.webkit.GeolocationPermissions getGeolocationPermissions();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public String getName();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public android.webkit.ServiceWorkerController getServiceWorkerController();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public android.webkit.WebStorage getWebStorage();
+ field public static final String DEFAULT_PROFILE_NAME = "Default";
+ }
+
+ @UiThread public interface ProfileStore {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public boolean deleteProfile(String);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public java.util.List<java.lang.String!> getAllProfileNames();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.ProfileStore getInstance();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public androidx.webkit.Profile getOrCreateProfile(String);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public androidx.webkit.Profile? getProfile(String);
+ }
+
+ public final class ProxyConfig {
+ method public java.util.List<java.lang.String!> getBypassRules();
+ method public java.util.List<androidx.webkit.ProxyConfig.ProxyRule!> getProxyRules();
+ method public boolean isReverseBypassEnabled();
+ field public static final String MATCH_ALL_SCHEMES = "*";
+ field public static final String MATCH_HTTP = "http";
+ field public static final String MATCH_HTTPS = "https";
+ }
+
+ public static final class ProxyConfig.Builder {
+ ctor public ProxyConfig.Builder();
+ ctor public ProxyConfig.Builder(androidx.webkit.ProxyConfig);
+ method public androidx.webkit.ProxyConfig.Builder addBypassRule(String);
+ method public androidx.webkit.ProxyConfig.Builder addDirect();
+ method public androidx.webkit.ProxyConfig.Builder addDirect(String);
+ method public androidx.webkit.ProxyConfig.Builder addProxyRule(String);
+ method public androidx.webkit.ProxyConfig.Builder addProxyRule(String, String);
+ method public androidx.webkit.ProxyConfig build();
+ method public androidx.webkit.ProxyConfig.Builder bypassSimpleHostnames();
+ method public androidx.webkit.ProxyConfig.Builder removeImplicitRules();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.PROXY_OVERRIDE_REVERSE_BYPASS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public androidx.webkit.ProxyConfig.Builder setReverseBypassEnabled(boolean);
+ }
+
+ public static final class ProxyConfig.ProxyRule {
+ method public String getSchemeFilter();
+ method public String getUrl();
+ }
+
+ public abstract class ProxyController {
+ method public abstract void clearProxyOverride(java.util.concurrent.Executor, Runnable);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.PROXY_OVERRIDE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.ProxyController getInstance();
+ method public abstract void setProxyOverride(androidx.webkit.ProxyConfig, java.util.concurrent.Executor, Runnable);
+ }
+
+ public abstract class SafeBrowsingResponseCompat {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void backToSafety(boolean);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_RESPONSE_PROCEED, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void proceed(boolean);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void showInterstitial(boolean);
+ }
+
+ public interface ScriptHandler {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.DOCUMENT_START_SCRIPT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public void remove();
+ }
+
+ public abstract class ServiceWorkerClientCompat {
+ ctor public ServiceWorkerClientCompat();
+ method @WorkerThread public abstract android.webkit.WebResourceResponse? shouldInterceptRequest(android.webkit.WebResourceRequest);
+ }
+
+ public abstract class ServiceWorkerControllerCompat {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.ServiceWorkerControllerCompat getInstance();
+ method public abstract androidx.webkit.ServiceWorkerWebSettingsCompat getServiceWorkerWebSettings();
+ method public abstract void setServiceWorkerClient(androidx.webkit.ServiceWorkerClientCompat?);
+ }
+
+ public abstract class ServiceWorkerWebSettingsCompat {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CONTENT_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract boolean getAllowContentAccess();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_FILE_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract boolean getAllowFileAccess();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract boolean getBlockNetworkLoads();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CACHE_MODE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract int getCacheMode();
+ method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract java.util.Set<java.lang.String!> getRequestedWithHeaderOriginAllowList();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CONTENT_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setAllowContentAccess(boolean);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_FILE_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setAllowFileAccess(boolean);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setBlockNetworkLoads(boolean);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CACHE_MODE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setCacheMode(int);
+ method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setRequestedWithHeaderOriginAllowList(java.util.Set<java.lang.String!>);
+ }
+
+ public class TracingConfig {
+ method public java.util.List<java.lang.String!> getCustomIncludedCategories();
+ method public int getPredefinedCategories();
+ method public int getTracingMode();
+ field public static final int CATEGORIES_ALL = 1; // 0x1
+ field public static final int CATEGORIES_ANDROID_WEBVIEW = 2; // 0x2
+ field public static final int CATEGORIES_FRAME_VIEWER = 64; // 0x40
+ field public static final int CATEGORIES_INPUT_LATENCY = 8; // 0x8
+ field public static final int CATEGORIES_JAVASCRIPT_AND_RENDERING = 32; // 0x20
+ field public static final int CATEGORIES_NONE = 0; // 0x0
+ field public static final int CATEGORIES_RENDERING = 16; // 0x10
+ field public static final int CATEGORIES_WEB_DEVELOPER = 4; // 0x4
+ field public static final int RECORD_CONTINUOUSLY = 1; // 0x1
+ field public static final int RECORD_UNTIL_FULL = 0; // 0x0
+ }
+
+ public static class TracingConfig.Builder {
+ ctor public TracingConfig.Builder();
+ method public androidx.webkit.TracingConfig.Builder addCategories(int...);
+ method public androidx.webkit.TracingConfig.Builder addCategories(java.lang.String!...);
+ method public androidx.webkit.TracingConfig.Builder addCategories(java.util.Collection<java.lang.String!>);
+ method public androidx.webkit.TracingConfig build();
+ method public androidx.webkit.TracingConfig.Builder setTracingMode(int);
+ }
+
+ public abstract class TracingController {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.TRACING_CONTROLLER_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.TracingController getInstance();
+ method public abstract boolean isTracing();
+ method public abstract void start(androidx.webkit.TracingConfig);
+ method public abstract boolean stop(java.io.OutputStream?, java.util.concurrent.Executor);
+ }
+
+ public final class UserAgentMetadata {
+ method public String? getArchitecture();
+ method public int getBitness();
+ method public java.util.List<androidx.webkit.UserAgentMetadata.BrandVersion!> getBrandVersionList();
+ method public String? getFullVersion();
+ method public String? getModel();
+ method public String? getPlatform();
+ method public String? getPlatformVersion();
+ method public boolean isMobile();
+ method public boolean isWow64();
+ field public static final int BITNESS_DEFAULT = 0; // 0x0
+ }
+
+ public static final class UserAgentMetadata.BrandVersion {
+ method public String getBrand();
+ method public String getFullVersion();
+ method public String getMajorVersion();
+ }
+
+ public static final class UserAgentMetadata.BrandVersion.Builder {
+ ctor public UserAgentMetadata.BrandVersion.Builder();
+ ctor public UserAgentMetadata.BrandVersion.Builder(androidx.webkit.UserAgentMetadata.BrandVersion);
+ method public androidx.webkit.UserAgentMetadata.BrandVersion build();
+ method public androidx.webkit.UserAgentMetadata.BrandVersion.Builder setBrand(String);
+ method public androidx.webkit.UserAgentMetadata.BrandVersion.Builder setFullVersion(String);
+ method public androidx.webkit.UserAgentMetadata.BrandVersion.Builder setMajorVersion(String);
+ }
+
+ public static final class UserAgentMetadata.Builder {
+ ctor public UserAgentMetadata.Builder();
+ ctor public UserAgentMetadata.Builder(androidx.webkit.UserAgentMetadata);
+ method public androidx.webkit.UserAgentMetadata build();
+ method public androidx.webkit.UserAgentMetadata.Builder setArchitecture(String?);
+ method public androidx.webkit.UserAgentMetadata.Builder setBitness(int);
+ method public androidx.webkit.UserAgentMetadata.Builder setBrandVersionList(java.util.List<androidx.webkit.UserAgentMetadata.BrandVersion!>);
+ method public androidx.webkit.UserAgentMetadata.Builder setFullVersion(String?);
+ method public androidx.webkit.UserAgentMetadata.Builder setMobile(boolean);
+ method public androidx.webkit.UserAgentMetadata.Builder setModel(String?);
+ method public androidx.webkit.UserAgentMetadata.Builder setPlatform(String?);
+ method public androidx.webkit.UserAgentMetadata.Builder setPlatformVersion(String?);
+ method public androidx.webkit.UserAgentMetadata.Builder setWow64(boolean);
+ }
+
+ public class WebMessageCompat {
+ ctor @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public WebMessageCompat(byte[]);
+ ctor @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public WebMessageCompat(byte[], androidx.webkit.WebMessagePortCompat![]?);
+ ctor public WebMessageCompat(String?);
+ ctor public WebMessageCompat(String?, androidx.webkit.WebMessagePortCompat![]?);
+ method public byte[] getArrayBuffer();
+ method public String? getData();
+ method public androidx.webkit.WebMessagePortCompat![]? getPorts();
+ method public int getType();
+ field public static final int TYPE_ARRAY_BUFFER = 1; // 0x1
+ field public static final int TYPE_STRING = 0; // 0x0
+ }
+
+ public abstract class WebMessagePortCompat {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_CLOSE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void close();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_POST_MESSAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(androidx.webkit.WebMessageCompat);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setWebMessageCallback(android.os.Handler?, androidx.webkit.WebMessagePortCompat.WebMessageCallbackCompat);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setWebMessageCallback(androidx.webkit.WebMessagePortCompat.WebMessageCallbackCompat);
+ }
+
+ public abstract static class WebMessagePortCompat.WebMessageCallbackCompat {
+ ctor public WebMessagePortCompat.WebMessageCallbackCompat();
+ method public void onMessage(androidx.webkit.WebMessagePortCompat, androidx.webkit.WebMessageCompat?);
+ }
+
+ public abstract class WebResourceErrorCompat {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_RESOURCE_ERROR_GET_DESCRIPTION, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract CharSequence getDescription();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_RESOURCE_ERROR_GET_CODE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract int getErrorCode();
+ }
+
+ public class WebResourceRequestCompat {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_RESOURCE_REQUEST_IS_REDIRECT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean isRedirect(android.webkit.WebResourceRequest);
+ }
+
+ public class WebSettingsCompat {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.ATTRIBUTION_REGISTRATION_BEHAVIOR, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getAttributionRegistrationBehavior(android.webkit.WebSettings);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getDisabledActionModeMenuItems(android.webkit.WebSettings);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean getEnterpriseAuthenticationAppLinkPolicyEnabled(android.webkit.WebSettings);
+ method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getForceDark(android.webkit.WebSettings);
+ method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK_STRATEGY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getForceDarkStrategy(android.webkit.WebSettings);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.OFF_SCREEN_PRERASTER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean getOffscreenPreRaster(android.webkit.WebSettings);
+ method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static java.util.Set<java.lang.String!> getRequestedWithHeaderOriginAllowList(android.webkit.WebSettings);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ENABLE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean getSafeBrowsingEnabled(android.webkit.WebSettings);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.USER_AGENT_METADATA, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.UserAgentMetadata getUserAgentMetadata(android.webkit.WebSettings);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEBVIEW_MEDIA_INTEGRITY_API_STATUS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.WebViewMediaIntegrityApiStatusConfig getWebViewMediaIntegrityApiStatus(android.webkit.WebSettings);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.ALGORITHMIC_DARKENING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean isAlgorithmicDarkeningAllowed(android.webkit.WebSettings);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.ALGORITHMIC_DARKENING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setAlgorithmicDarkeningAllowed(android.webkit.WebSettings, boolean);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.ATTRIBUTION_REGISTRATION_BEHAVIOR, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setAttributionRegistrationBehavior(android.webkit.WebSettings, int);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setDisabledActionModeMenuItems(android.webkit.WebSettings, int);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setEnterpriseAuthenticationAppLinkPolicyEnabled(android.webkit.WebSettings, boolean);
+ method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setForceDark(android.webkit.WebSettings, int);
+ method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK_STRATEGY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setForceDarkStrategy(android.webkit.WebSettings, int);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.OFF_SCREEN_PRERASTER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setOffscreenPreRaster(android.webkit.WebSettings, boolean);
+ method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setRequestedWithHeaderOriginAllowList(android.webkit.WebSettings, java.util.Set<java.lang.String!>);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ENABLE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingEnabled(android.webkit.WebSettings, boolean);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.USER_AGENT_METADATA, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setUserAgentMetadata(android.webkit.WebSettings, androidx.webkit.UserAgentMetadata);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEBVIEW_MEDIA_INTEGRITY_API_STATUS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setWebViewMediaIntegrityApiStatus(android.webkit.WebSettings, androidx.webkit.WebViewMediaIntegrityApiStatusConfig);
+ field public static final int ATTRIBUTION_BEHAVIOR_APP_SOURCE_AND_APP_TRIGGER = 3; // 0x3
+ field public static final int ATTRIBUTION_BEHAVIOR_APP_SOURCE_AND_WEB_TRIGGER = 1; // 0x1
+ field public static final int ATTRIBUTION_BEHAVIOR_DISABLED = 0; // 0x0
+ field public static final int ATTRIBUTION_BEHAVIOR_WEB_SOURCE_AND_WEB_TRIGGER = 2; // 0x2
+ field @Deprecated public static final int DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING = 2; // 0x2
+ field @Deprecated public static final int DARK_STRATEGY_USER_AGENT_DARKENING_ONLY = 0; // 0x0
+ field @Deprecated public static final int DARK_STRATEGY_WEB_THEME_DARKENING_ONLY = 1; // 0x1
+ field @Deprecated public static final int FORCE_DARK_AUTO = 1; // 0x1
+ field @Deprecated public static final int FORCE_DARK_OFF = 0; // 0x0
+ field @Deprecated public static final int FORCE_DARK_ON = 2; // 0x2
+ }
+
+ public final class WebViewAssetLoader {
+ method @WorkerThread public android.webkit.WebResourceResponse? shouldInterceptRequest(android.net.Uri);
+ field public static final String DEFAULT_DOMAIN = "appassets.androidplatform.net";
+ }
+
+ public static final class WebViewAssetLoader.AssetsPathHandler implements androidx.webkit.WebViewAssetLoader.PathHandler {
+ ctor public WebViewAssetLoader.AssetsPathHandler(android.content.Context);
+ method @WorkerThread public android.webkit.WebResourceResponse? handle(String);
+ }
+
+ public static final class WebViewAssetLoader.Builder {
+ ctor public WebViewAssetLoader.Builder();
+ method public androidx.webkit.WebViewAssetLoader.Builder addPathHandler(String, androidx.webkit.WebViewAssetLoader.PathHandler);
+ method public androidx.webkit.WebViewAssetLoader build();
+ method public androidx.webkit.WebViewAssetLoader.Builder setDomain(String);
+ method public androidx.webkit.WebViewAssetLoader.Builder setHttpAllowed(boolean);
+ }
+
+ public static final class WebViewAssetLoader.InternalStoragePathHandler implements androidx.webkit.WebViewAssetLoader.PathHandler {
+ ctor public WebViewAssetLoader.InternalStoragePathHandler(android.content.Context, java.io.File);
+ method @WorkerThread public android.webkit.WebResourceResponse handle(String);
+ }
+
+ public static interface WebViewAssetLoader.PathHandler {
+ method @WorkerThread public android.webkit.WebResourceResponse? handle(String);
+ }
+
+ public static final class WebViewAssetLoader.ResourcesPathHandler implements androidx.webkit.WebViewAssetLoader.PathHandler {
+ ctor public WebViewAssetLoader.ResourcesPathHandler(android.content.Context);
+ method @WorkerThread public android.webkit.WebResourceResponse? handle(String);
+ }
+
+ public class WebViewClientCompat extends android.webkit.WebViewClient {
+ ctor public WebViewClientCompat();
+ method @RequiresApi(23) public final void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceError);
+ method @RequiresApi(21) @UiThread public void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, androidx.webkit.WebResourceErrorCompat);
+ method @RequiresApi(27) public final void onSafeBrowsingHit(android.webkit.WebView, android.webkit.WebResourceRequest, int, android.webkit.SafeBrowsingResponse);
+ method @UiThread public void onSafeBrowsingHit(android.webkit.WebView, android.webkit.WebResourceRequest, int, androidx.webkit.SafeBrowsingResponseCompat);
+ }
+
+ public class WebViewCompat {
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.DOCUMENT_START_SCRIPT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.ScriptHandler addDocumentStartJavaScript(android.webkit.WebView, String, java.util.Set<java.lang.String!>);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void addWebMessageListener(android.webkit.WebView, String, java.util.Set<java.lang.String!>, androidx.webkit.WebViewCompat.WebMessageListener);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.CREATE_WEB_MESSAGE_CHANNEL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.WebMessagePortCompat![] createWebMessageChannel(android.webkit.WebView);
+ method public static android.content.pm.PackageInfo? getCurrentWebViewPackage(android.content.Context);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static androidx.webkit.Profile getProfile(android.webkit.WebView);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_PRIVACY_POLICY_URL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_VARIATIONS_HEADER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static String getVariationsHeader();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_CHROME_CLIENT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.webkit.WebChromeClient? getWebChromeClient(android.webkit.WebView);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_VIEW_CLIENT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.webkit.WebViewClient getWebViewClient(android.webkit.WebView);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_VIEW_RENDERER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.WebViewRenderProcess? getWebViewRenderProcess(android.webkit.WebView);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.WebViewRenderProcessClient? getWebViewRenderProcessClient(android.webkit.WebView);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean isMultiProcessEnabled();
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.VISUAL_STATE_CALLBACK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void postVisualStateCallback(android.webkit.WebView, long, androidx.webkit.WebViewCompat.VisualStateCallback);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.POST_WEB_MESSAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void postWebMessage(android.webkit.WebView, androidx.webkit.WebMessageCompat, android.net.Uri);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void removeWebMessageListener(android.webkit.WebView, String);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static void setProfile(android.webkit.WebView, String);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ALLOWLIST, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingAllowlist(java.util.Set<java.lang.String!>, android.webkit.ValueCallback<java.lang.Boolean!>?);
+ method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_WHITELIST, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingWhitelist(java.util.List<java.lang.String!>, android.webkit.ValueCallback<java.lang.Boolean!>?);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setWebViewRenderProcessClient(android.webkit.WebView, androidx.webkit.WebViewRenderProcessClient?);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setWebViewRenderProcessClient(android.webkit.WebView, java.util.concurrent.Executor, androidx.webkit.WebViewRenderProcessClient);
+ method @RequiresFeature(name=androidx.webkit.WebViewFeature.START_SAFE_BROWSING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void startSafeBrowsing(android.content.Context, android.webkit.ValueCallback<java.lang.Boolean!>?);
+ }
+
+ public static interface WebViewCompat.VisualStateCallback {
+ method @UiThread public void onComplete(long);
+ }
+
+ public static interface WebViewCompat.WebMessageListener {
+ method @UiThread public void onPostMessage(android.webkit.WebView, androidx.webkit.WebMessageCompat, android.net.Uri, boolean, androidx.webkit.JavaScriptReplyProxy);
+ }
+
+ public class WebViewFeature {
+ method public static boolean isFeatureSupported(String);
+ method public static boolean isStartupFeatureSupported(android.content.Context, String);
+ field public static final String ALGORITHMIC_DARKENING = "ALGORITHMIC_DARKENING";
+ field public static final String ATTRIBUTION_REGISTRATION_BEHAVIOR = "ATTRIBUTION_REGISTRATION_BEHAVIOR";
+ field public static final String CREATE_WEB_MESSAGE_CHANNEL = "CREATE_WEB_MESSAGE_CHANNEL";
+ field public static final String DISABLED_ACTION_MODE_MENU_ITEMS = "DISABLED_ACTION_MODE_MENU_ITEMS";
+ field public static final String DOCUMENT_START_SCRIPT = "DOCUMENT_START_SCRIPT";
+ field public static final String ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY = "ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY";
+ field public static final String FORCE_DARK = "FORCE_DARK";
+ field public static final String FORCE_DARK_STRATEGY = "FORCE_DARK_STRATEGY";
+ field public static final String GET_COOKIE_INFO = "GET_COOKIE_INFO";
+ field public static final String GET_VARIATIONS_HEADER = "GET_VARIATIONS_HEADER";
+ field public static final String GET_WEB_CHROME_CLIENT = "GET_WEB_CHROME_CLIENT";
+ field public static final String GET_WEB_VIEW_CLIENT = "GET_WEB_VIEW_CLIENT";
+ field public static final String GET_WEB_VIEW_RENDERER = "GET_WEB_VIEW_RENDERER";
+ field public static final String MULTI_PROCESS = "MULTI_PROCESS";
+ field public static final String MULTI_PROFILE = "MULTI_PROFILE";
+ field public static final String OFF_SCREEN_PRERASTER = "OFF_SCREEN_PRERASTER";
+ field public static final String POST_WEB_MESSAGE = "POST_WEB_MESSAGE";
+ field public static final String PROXY_OVERRIDE = "PROXY_OVERRIDE";
+ field public static final String PROXY_OVERRIDE_REVERSE_BYPASS = "PROXY_OVERRIDE_REVERSE_BYPASS";
+ field public static final String RECEIVE_HTTP_ERROR = "RECEIVE_HTTP_ERROR";
+ field public static final String RECEIVE_WEB_RESOURCE_ERROR = "RECEIVE_WEB_RESOURCE_ERROR";
+ field public static final String SAFE_BROWSING_ALLOWLIST = "SAFE_BROWSING_ALLOWLIST";
+ field public static final String SAFE_BROWSING_ENABLE = "SAFE_BROWSING_ENABLE";
+ field public static final String SAFE_BROWSING_HIT = "SAFE_BROWSING_HIT";
+ field public static final String SAFE_BROWSING_PRIVACY_POLICY_URL = "SAFE_BROWSING_PRIVACY_POLICY_URL";
+ field public static final String SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY = "SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY";
+ field public static final String SAFE_BROWSING_RESPONSE_PROCEED = "SAFE_BROWSING_RESPONSE_PROCEED";
+ field public static final String SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL = "SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL";
+ field @Deprecated public static final String SAFE_BROWSING_WHITELIST = "SAFE_BROWSING_WHITELIST";
+ field public static final String SERVICE_WORKER_BASIC_USAGE = "SERVICE_WORKER_BASIC_USAGE";
+ field public static final String SERVICE_WORKER_BLOCK_NETWORK_LOADS = "SERVICE_WORKER_BLOCK_NETWORK_LOADS";
+ field public static final String SERVICE_WORKER_CACHE_MODE = "SERVICE_WORKER_CACHE_MODE";
+ field public static final String SERVICE_WORKER_CONTENT_ACCESS = "SERVICE_WORKER_CONTENT_ACCESS";
+ field public static final String SERVICE_WORKER_FILE_ACCESS = "SERVICE_WORKER_FILE_ACCESS";
+ field public static final String SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST = "SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST";
+ field public static final String SHOULD_OVERRIDE_WITH_REDIRECTS = "SHOULD_OVERRIDE_WITH_REDIRECTS";
+ field public static final String STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX = "STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX";
+ field public static final String STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS = "STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS";
+ field public static final String START_SAFE_BROWSING = "START_SAFE_BROWSING";
+ field public static final String TRACING_CONTROLLER_BASIC_USAGE = "TRACING_CONTROLLER_BASIC_USAGE";
+ field public static final String USER_AGENT_METADATA = "USER_AGENT_METADATA";
+ field public static final String VISUAL_STATE_CALLBACK = "VISUAL_STATE_CALLBACK";
+ field public static final String WEBVIEW_MEDIA_INTEGRITY_API_STATUS = "WEBVIEW_MEDIA_INTEGRITY_API_STATUS";
+ field public static final String WEB_MESSAGE_ARRAY_BUFFER = "WEB_MESSAGE_ARRAY_BUFFER";
+ field public static final String WEB_MESSAGE_CALLBACK_ON_MESSAGE = "WEB_MESSAGE_CALLBACK_ON_MESSAGE";
+ field public static final String WEB_MESSAGE_LISTENER = "WEB_MESSAGE_LISTENER";
+ field public static final String WEB_MESSAGE_PORT_CLOSE = "WEB_MESSAGE_PORT_CLOSE";
+ field public static final String WEB_MESSAGE_PORT_POST_MESSAGE = "WEB_MESSAGE_PORT_POST_MESSAGE";
+ field public static final String WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK = "WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK";
+ field public static final String WEB_RESOURCE_ERROR_GET_CODE = "WEB_RESOURCE_ERROR_GET_CODE";
+ field public static final String WEB_RESOURCE_ERROR_GET_DESCRIPTION = "WEB_RESOURCE_ERROR_GET_DESCRIPTION";
+ field public static final String WEB_RESOURCE_REQUEST_IS_REDIRECT = "WEB_RESOURCE_REQUEST_IS_REDIRECT";
+ field public static final String WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE = "WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE";
+ field public static final String WEB_VIEW_RENDERER_TERMINATE = "WEB_VIEW_RENDERER_TERMINATE";
+ }
+
+ @RequiresFeature(name=androidx.webkit.WebViewFeature.WEBVIEW_MEDIA_INTEGRITY_API_STATUS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public class WebViewMediaIntegrityApiStatusConfig {
+ ctor public WebViewMediaIntegrityApiStatusConfig(androidx.webkit.WebViewMediaIntegrityApiStatusConfig.Builder);
+ method public int getDefaultStatus();
+ method public java.util.Map<java.lang.String!,java.lang.Integer!> getOverrideRules();
+ field public static final int WEBVIEW_MEDIA_INTEGRITY_API_DISABLED = 0; // 0x0
+ field public static final int WEBVIEW_MEDIA_INTEGRITY_API_ENABLED = 2; // 0x2
+ field public static final int WEBVIEW_MEDIA_INTEGRITY_API_ENABLED_WITHOUT_APP_IDENTITY = 1; // 0x1
+ }
+
+ public static final class WebViewMediaIntegrityApiStatusConfig.Builder {
+ ctor public WebViewMediaIntegrityApiStatusConfig.Builder(int);
+ method public androidx.webkit.WebViewMediaIntegrityApiStatusConfig.Builder addOverrideRule(String, int);
+ method public androidx.webkit.WebViewMediaIntegrityApiStatusConfig build();
+ }
+
+ public abstract class WebViewRenderProcess {
+ ctor public WebViewRenderProcess();
+ method public abstract boolean terminate();
+ }
+
+ public abstract class WebViewRenderProcessClient {
+ ctor public WebViewRenderProcessClient();
+ method public abstract void onRenderProcessResponsive(android.webkit.WebView, androidx.webkit.WebViewRenderProcess?);
+ method public abstract void onRenderProcessUnresponsive(android.webkit.WebView, androidx.webkit.WebViewRenderProcess?);
+ }
+
+}
+
diff --git a/webkit/webkit/src/main/java/androidx/webkit/internal/WebMessageAdapter.java b/webkit/webkit/src/main/java/androidx/webkit/internal/WebMessageAdapter.java
index 1fd56c5..4c0492b 100644
--- a/webkit/webkit/src/main/java/androidx/webkit/internal/WebMessageAdapter.java
+++ b/webkit/webkit/src/main/java/androidx/webkit/internal/WebMessageAdapter.java
@@ -18,11 +18,8 @@
import static org.chromium.support_lib_boundary.WebMessagePayloadBoundaryInterface.WebMessagePayloadType;
-import android.os.Build;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
import androidx.webkit.WebMessageCompat;
import androidx.webkit.WebMessagePortCompat;
@@ -59,7 +56,6 @@
return mWebMessageCompat.getData();
}
- @RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
@Nullable
public InvocationHandler getMessagePayload() {
diff --git a/webkit/webkit/src/main/java/androidx/webkit/internal/WebViewProviderAdapter.java b/webkit/webkit/src/main/java/androidx/webkit/internal/WebViewProviderAdapter.java
index 68c1056..eae16ef7 100644
--- a/webkit/webkit/src/main/java/androidx/webkit/internal/WebViewProviderAdapter.java
+++ b/webkit/webkit/src/main/java/androidx/webkit/internal/WebViewProviderAdapter.java
@@ -18,7 +18,6 @@
import android.annotation.SuppressLint;
import android.net.Uri;
-import android.os.Build;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
@@ -56,7 +55,6 @@
/**
* Adapter method WebViewCompat.insertVisualStateCallback().
*/
- @RequiresApi(Build.VERSION_CODES.KITKAT)
public void insertVisualStateCallback(
long requestId, @NonNull WebViewCompat.VisualStateCallback callback) {
mImpl.insertVisualStateCallback(requestId,
@@ -80,7 +78,6 @@
/**
* Adapter method for {@link WebViewCompat#postWebMessage(WebView, WebMessageCompat, Uri)}.
*/
- @RequiresApi(Build.VERSION_CODES.KITKAT)
public void postWebMessage(@NonNull WebMessageCompat message, @NonNull Uri targetOrigin) {
mImpl.postMessageToMainFrame(
BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(
@@ -91,7 +88,6 @@
* Adapter method for {@link WebViewCompat#addWebMessageListener(android.webkit.WebView,
* String, List<String>, androidx.webkit.WebViewCompat.WebMessageListener)}.
*/
- @RequiresApi(Build.VERSION_CODES.KITKAT)
public void addWebMessageListener(@NonNull String jsObjectName,
@NonNull String[] allowedOriginRules,
@NonNull WebViewCompat.WebMessageListener listener) {
@@ -160,7 +156,6 @@
// WebViewRenderProcessClient is a callback class, so it should be last. See
// https://issuetracker.google.com/issues/139770271.
@SuppressLint("LambdaLast")
- @RequiresApi(Build.VERSION_CODES.KITKAT)
public void setWebViewRenderProcessClient(@Nullable Executor executor,
@Nullable WebViewRenderProcessClient webViewRenderProcessClient) {
InvocationHandler handler = webViewRenderProcessClient != null
diff --git a/window/window-core/build.gradle b/window/window-core/build.gradle
index 1462e5e..8e33dbf 100644
--- a/window/window-core/build.gradle
+++ b/window/window-core/build.gradle
@@ -46,6 +46,12 @@
implementation(libs.kotlinTestJunit)
}
}
+
+ androidInstrumentedTest {
+ dependencies {
+ implementation(libs.testRunner)
+ }
+ }
}
}
diff --git a/window/window-testing/src/androidTest/java/androidx/window/testing/layout/WindowMetricsCalculatorRuleTest.kt b/window/window-testing/src/androidTest/java/androidx/window/testing/layout/WindowMetricsCalculatorRuleTest.kt
index 95bed8b..faddb36 100644
--- a/window/window-testing/src/androidTest/java/androidx/window/testing/layout/WindowMetricsCalculatorRuleTest.kt
+++ b/window/window-testing/src/androidTest/java/androidx/window/testing/layout/WindowMetricsCalculatorRuleTest.kt
@@ -96,11 +96,9 @@
}
}
- @RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
@Test
fun testCurrentWindowMetrics_context_matchesDisplayRealSize_17to29() {
Utils.assumePlatformAtOrBelow(Build.VERSION_CODES.Q)
- Utils.assumePlatformAtOrAbove(Build.VERSION_CODES.JELLY_BEAN_MR1)
activityRule.scenario.onActivity { activity ->
val calculator = WindowMetricsCalculator.getOrCreate()
diff --git a/work/work-gcm/src/androidTest/java/androidx/work/impl/background/gcm/GcmTaskConverterTest.kt b/work/work-gcm/src/androidTest/java/androidx/work/impl/background/gcm/GcmTaskConverterTest.kt
index da05ab5..08e70ec 100644
--- a/work/work-gcm/src/androidTest/java/androidx/work/impl/background/gcm/GcmTaskConverterTest.kt
+++ b/work/work-gcm/src/androidTest/java/androidx/work/impl/background/gcm/GcmTaskConverterTest.kt
@@ -29,7 +29,6 @@
import com.google.android.gms.gcm.Task
import java.util.concurrent.TimeUnit
import org.hamcrest.MatcherAssert.assertThat
-import org.hamcrest.Matchers.greaterThan
import org.hamcrest.Matchers.lessThanOrEqualTo
import org.junit.Assert.assertEquals
import org.junit.Before
@@ -210,13 +209,15 @@
@Test
@SdkSuppress(
- minSdkVersion = 22, // b/269194015 for minSdkVersion = 22
maxSdkVersion = WorkManagerImpl.MAX_PRE_JOB_SCHEDULER_API_LEVEL
)
fun testPeriodicWorkRequest_withFlex_firstRun() {
val request = PeriodicWorkRequestBuilder<TestWorker>(
15L, TimeUnit.MINUTES, 5, TimeUnit.MINUTES
).build()
+ val now = System.currentTimeMillis()
+ `when`(mTaskConverter.now()).thenReturn(now)
+ request.workSpec.lastEnqueueTime = now
val task = mTaskConverter.convert(request.workSpec)
assertEquals(task.serviceName, WorkManagerGcmService::class.java.name)
@@ -224,12 +225,12 @@
assertEquals(task.isUpdateCurrent, true)
assertEquals(task.requiredNetwork, Task.NETWORK_STATE_ANY)
assertEquals(task.requiresCharging, false)
- assertThat(task.windowStart, greaterThan(0L)) // should be in the future
+ // should be period - flex
+ assertEquals(task.windowStart, TimeUnit.MINUTES.toSeconds(10))
}
@Test
@SdkSuppress(
- minSdkVersion = 22, // b/269194015 for minSdkVersion = 22
maxSdkVersion = WorkManagerImpl.MAX_PRE_JOB_SCHEDULER_API_LEVEL
)
fun testPeriodicWorkRequest_withFlex_nextRun() {
@@ -241,6 +242,7 @@
).build()
request.workSpec.lastEnqueueTime = now
+ request.workSpec.periodCount++
val expected = TimeUnit.MINUTES.toSeconds(15L)
val task = mTaskConverter.convert(request.workSpec)
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/workers/ConstraintTrackingWorkerTest.java b/work/work-runtime/src/androidTest/java/androidx/work/impl/workers/ConstraintTrackingWorkerTest.java
index 72a068d..72d4ff3 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/workers/ConstraintTrackingWorkerTest.java
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/workers/ConstraintTrackingWorkerTest.java
@@ -28,7 +28,6 @@
import static org.mockito.Mockito.when;
import android.content.Context;
-import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
@@ -155,9 +154,7 @@
@After
public void tearDown() {
- if (Build.VERSION.SDK_INT >= 18) {
- mHandlerThread.quitSafely();
- }
+ mHandlerThread.quitSafely();
}
@Test