Merge "Commonize RoomDatabase.Builder APIs for configuring migrations" into androidx-main
diff --git a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPlugin.kt b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPlugin.kt
index 95106f9..04dc5489 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPlugin.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPlugin.kt
@@ -40,6 +40,7 @@
import com.android.build.api.dsl.ApplicationExtension
import com.android.build.api.dsl.LibraryExtension
import com.android.build.api.variant.ApplicationVariant
+import com.android.build.api.variant.ApplicationVariantBuilder
import com.android.build.api.variant.Variant
import org.gradle.api.GradleException
import org.gradle.api.Plugin
@@ -154,6 +155,38 @@
)
}
+ override fun onApplicationBeforeVariants(variantBuilder: ApplicationVariantBuilder) {
+
+ // Note that the lifecycle is for each variant `beforeVariant`, `onVariant`. This means
+ // that the `onVariant` for the base variants of the module (for example `release`) will
+ // run before `beforeVariant` of `benchmarkRelease` and `nonMinifiedRelease`.
+ // Since we schedule some callbacks in for benchmark and nonMinified variants in the
+ // onVariant callback for the base variants, this is the place where we can remove them,
+ // in case the benchmark and nonMinified variants have been disabled.
+
+ val isBaselineProfilePluginCreatedBuildType = variantBuilder.buildType?.let {
+ it.startsWith(BUILD_TYPE_BASELINE_PROFILE_PREFIX) ||
+ it.startsWith(BUILD_TYPE_BENCHMARK_PREFIX)
+ } ?: false
+
+ // Note that the callback should be remove at the end, after all the variants
+ // have been processed. This is because the benchmark and nonMinified variants can be
+ // disabled at any point AFTER the plugin has been applied. So checking immediately here
+ // would tell us that the variant is enabled, while it could be disabled later.
+ afterVariants {
+ if (!variantBuilder.enable && isBaselineProfilePluginCreatedBuildType) {
+ removeOnVariantCallback(variantBuilder.name)
+ logger.info(
+ "Variant `${variantBuilder.name}` is disabled. If this " +
+ "is not intentional, please check your gradle configuration " +
+ "for beforeVariants blocks. For more information on variant " +
+ "filters checkout the docs at https://developer.android.com/" +
+ "build/build-variants#filter-variants."
+ )
+ }
+ }
+ }
+
@Suppress("UnstableApiUsage")
override fun onVariants(variant: Variant) {
@@ -378,46 +411,30 @@
if (isApplicationModule()) {
// Defines a function to apply the baseline profile source sets to a variant.
- fun applySourceSets(variantName: String, variantBuildType: String?) {
+ fun applySourceSets(variantName: String) {
val taskName = camelCase("merge", variantName, "artProfile")
project
.tasks
.namedOrNull<Task>(taskName)
?.configure { t ->
-
- // TODO: this causes a circular task dependency when the producer points
- // to a consumer that does not have the appTarget plugin. (b/272851616)
+ // This causes a circular task dependency when the producer points to
+ // a consumer that does not have the appTarget plugin. (b/272851616)
if (automaticGeneration) {
t.dependsOn(copyTaskProvider)
} else {
t.mustRunAfter(copyTaskProvider)
}
}
- ?: throw IllegalStateException(
- "The task `$taskName` doesn't exist. This may be related to a " +
- "`beforeVariants` block filtering variants and disabling" +
- "`$variantName`. Please check your gradle configuration and make " +
- "sure variants with build type `$variantBuildType` are " +
- "enabled. For more information on variant filters check out the " +
- "docs at https://developer.android.com/build/build-variants#" +
- "filter-variants."
- )
}
afterVariants {
// Apply the source sets to the variant.
- applySourceSets(
- variant.name,
- variant.buildType
- )
+ applySourceSets(variant.name)
// Apply the source sets to the benchmark variant if supported.
if (supportsFeature(AgpFeature.TEST_MODULE_SUPPORTS_MULTIPLE_BUILD_TYPES)) {
- applySourceSets(
- variant.benchmarkVariantName,
- variant.benchmarkBuildType
- )
+ applySourceSets(variant.benchmarkVariantName)
}
}
}
diff --git a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/Agp.kt b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/Agp.kt
index 9f8caaf..5b2b40b 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/Agp.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/Agp.kt
@@ -86,8 +86,11 @@
@Suppress("UnstableApiUsage")
internal object TestedApksAgp83 {
fun getTargetAppApplicationId(variant: TestVariant): Provider<String> {
+ // Note that retrieving the BuildArtifactsLoader from within the lambda causes an issue
+ // with serialization (see b/325886853#comment13).
+ val buildArtifactLoader = variant.artifacts.getBuiltArtifactsLoader()
return variant.testedApks.map {
- variant.artifacts.getBuiltArtifactsLoader().load(it)?.applicationId ?: ""
+ buildArtifactLoader.load(it)?.applicationId ?: ""
}
}
}
diff --git a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/AgpPlugin.kt b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/AgpPlugin.kt
index 583f424..fd7ee6a 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/AgpPlugin.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/AgpPlugin.kt
@@ -222,6 +222,13 @@
protected fun onVariant(variantName: String, block: (TestVariant) -> (Unit)) =
onTestVariantBlockScheduler.executeOrScheduleOnVariantBlock(variantName, block)
+ protected fun removeOnVariantCallback(variantName: String) {
+ onVariantBlockScheduler.removeOnVariantCallback(variantName)
+ onAppVariantBlockScheduler.removeOnVariantCallback(variantName)
+ onLibraryVariantBlockScheduler.removeOnVariantCallback(variantName)
+ onTestVariantBlockScheduler.removeOnVariantCallback(variantName)
+ }
+
protected fun agpVersion() = project.agpVersion()
private fun checkAgpVersion() {
@@ -372,6 +379,10 @@
}
}
+ fun removeOnVariantCallback(variantName: String) {
+ onVariantBlocks.remove(variantName)
+ }
+
fun onVariant(variant: T) {
// This error cannot be thrown because of a user configuration but only an error when
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 d296d1e..92750a7 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
@@ -1308,7 +1308,7 @@
}
@Test
- fun whenBenchmarkVariantsAreDisabledShouldThrowException() {
+ fun whenBenchmarkVariantsAreDisabledShouldNotify() {
// Note that this test doesn't works only on AGP > 8.0.0 because in previous versions
// the benchmark variant is not created.
assumeTrue(agpVersion != TEST_AGP_VERSION_8_0_0)
@@ -1341,15 +1341,8 @@
)
)
- gradleRunner.buildAndFailAndAssertThatOutput("generateBaselineProfile") {
- contains(
- "java.lang.IllegalStateException: The task `mergeBenchmarkReleaseArtProfile` " +
- "doesn't exist. This may be related to a `beforeVariants` block filtering " +
- "variants and disabling`benchmarkRelease`. Please check your gradle " +
- "configuration and make sure variants with build type `benchmarkRelease` are " +
- "enabled. For more information on variant filters check out the docs at " +
- "https://developer.android.com/build/build-variants#filter-variants."
- )
+ gradleRunner.buildAndAssertThatOutput("tasks", "--info") {
+ contains("Variant `benchmarkRelease` is disabled.")
}
}
}
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt
index 7eda4fc..538cba8 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt
@@ -108,8 +108,44 @@
)
}
}
+
+ /**
+ * Only used by group-internal tests
+ *
+ * Most minimal config possible
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ class MinimalTest(
+ private val appTagPackages: List<String>
+ ) : PerfettoConfig(isTextProto = false) {
+ @RequiresApi(23)
+ override fun writeTo(file: File) {
+ file.writeBytes(
+ configOf(
+ listOf(
+ minimalAtraceDataSource(atraceApps = appTagPackages)
+ )
+ ).validateAndEncode()
+ )
+ }
+ }
}
+private fun minimalAtraceDataSource(
+ atraceApps: List<String>
+) = TraceConfig.DataSource(
+ config = DataSourceConfig(
+ name = "linux.ftrace",
+ target_buffer = 0,
+ ftrace_config = FtraceConfig(
+ ftrace_events = emptyList(),
+ atrace_categories = emptyList(),
+ atrace_apps = atraceApps,
+ compact_sched = null
+ )
+ )
+)
+
private fun ftraceDataSource(
atraceApps: List<String>
) = TraceConfig.DataSource(
@@ -315,6 +351,27 @@
return sources
}
+private fun configOf(
+ dataSources: List<TraceConfig.DataSource>
+) = TraceConfig(
+ buffers = listOf(
+ BufferConfig(size_kb = 32768, FillPolicy.RING_BUFFER),
+ BufferConfig(size_kb = 4096, FillPolicy.RING_BUFFER)
+ ),
+ data_sources = dataSources,
+ // periodically dump to file, so we don't overrun our ring buffer
+ // buffers are expected to be big enough for 5 seconds, so conservatively set 2.5 dump
+ write_into_file = true,
+ file_write_period_ms = 2500,
+
+ // multiple of file_write_period_ms, enables trace processor to work in batches
+ flush_period_ms = 5000,
+
+ // reduce timeout to reduce trace capture overhead when devices have data source issues
+ // See b/323601788 and b/307649002.
+ data_source_stop_timeout_ms = 2500,
+)
+
/**
* Config for perfetto.
*
@@ -346,24 +403,7 @@
config = stackSamplingConfig
)
}
- return TraceConfig(
- buffers = listOf(
- BufferConfig(size_kb = 32768, FillPolicy.RING_BUFFER),
- BufferConfig(size_kb = 4096, FillPolicy.RING_BUFFER)
- ),
- data_sources = dataSources,
- // periodically dump to file, so we don't overrun our ring buffer
- // buffers are expected to be big enough for 5 seconds, so conservatively set 2.5 dump
- write_into_file = true,
- file_write_period_ms = 2500,
-
- // multiple of file_write_period_ms, enables trace processor to work in batches
- flush_period_ms = 5000,
-
- // reduce timeout to reduce trace capture overhead when devices have data source issues
- // See b/323601788 and b/307649002.
- data_source_stop_timeout_ms = 2500,
- )
+ return configOf(dataSources)
}
@RequiresApi(21) // needed for shell access
diff --git a/benchmark/benchmark-macro-junit4/api/current.txt b/benchmark/benchmark-macro-junit4/api/current.txt
index d4c3495..e06bf57 100644
--- a/benchmark/benchmark-macro-junit4/api/current.txt
+++ b/benchmark/benchmark-macro-junit4/api/current.txt
@@ -19,6 +19,10 @@
method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, optional androidx.benchmark.macro.CompilationMode compilationMode, optional androidx.benchmark.macro.StartupMode? startupMode, @IntRange(from=1L) int iterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, optional androidx.benchmark.macro.CompilationMode compilationMode, optional androidx.benchmark.macro.StartupMode? startupMode, @IntRange(from=1L) int iterations, optional kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> setupBlock, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, optional androidx.benchmark.macro.CompilationMode compilationMode, @IntRange(from=1L) int iterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
+ method @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1L) int iterations, androidx.benchmark.perfetto.PerfettoConfig perfettoConfig, optional androidx.benchmark.macro.CompilationMode compilationMode, optional androidx.benchmark.macro.StartupMode? startupMode, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
+ method @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1L) int iterations, androidx.benchmark.perfetto.PerfettoConfig perfettoConfig, optional androidx.benchmark.macro.CompilationMode compilationMode, optional androidx.benchmark.macro.StartupMode? startupMode, optional kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> setupBlock, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
+ method @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1L) int iterations, androidx.benchmark.perfetto.PerfettoConfig perfettoConfig, optional androidx.benchmark.macro.CompilationMode compilationMode, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
+ method @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1L) int iterations, androidx.benchmark.perfetto.PerfettoConfig perfettoConfig, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1L) int iterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
}
diff --git a/benchmark/benchmark-macro-junit4/api/restricted_current.txt b/benchmark/benchmark-macro-junit4/api/restricted_current.txt
index d4c3495..e06bf57 100644
--- a/benchmark/benchmark-macro-junit4/api/restricted_current.txt
+++ b/benchmark/benchmark-macro-junit4/api/restricted_current.txt
@@ -19,6 +19,10 @@
method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, optional androidx.benchmark.macro.CompilationMode compilationMode, optional androidx.benchmark.macro.StartupMode? startupMode, @IntRange(from=1L) int iterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, optional androidx.benchmark.macro.CompilationMode compilationMode, optional androidx.benchmark.macro.StartupMode? startupMode, @IntRange(from=1L) int iterations, optional kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> setupBlock, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, optional androidx.benchmark.macro.CompilationMode compilationMode, @IntRange(from=1L) int iterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
+ method @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1L) int iterations, androidx.benchmark.perfetto.PerfettoConfig perfettoConfig, optional androidx.benchmark.macro.CompilationMode compilationMode, optional androidx.benchmark.macro.StartupMode? startupMode, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
+ method @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1L) int iterations, androidx.benchmark.perfetto.PerfettoConfig perfettoConfig, optional androidx.benchmark.macro.CompilationMode compilationMode, optional androidx.benchmark.macro.StartupMode? startupMode, optional kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> setupBlock, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
+ method @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1L) int iterations, androidx.benchmark.perfetto.PerfettoConfig perfettoConfig, optional androidx.benchmark.macro.CompilationMode compilationMode, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
+ method @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1L) int iterations, androidx.benchmark.perfetto.PerfettoConfig perfettoConfig, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1L) int iterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
}
diff --git a/benchmark/benchmark-macro-junit4/build.gradle b/benchmark/benchmark-macro-junit4/build.gradle
index c99550b..f2f45e0 100644
--- a/benchmark/benchmark-macro-junit4/build.gradle
+++ b/benchmark/benchmark-macro-junit4/build.gradle
@@ -59,6 +59,17 @@
// DexMaker has it"s own MockMaker
}
+tasks.withType(KotlinCompile).configureEach {
+ kotlinOptions {
+ // Enable using experimental APIs from within same version group
+ freeCompilerArgs += [
+ "-opt-in=androidx.benchmark.macro.ExperimentalMetricApi",
+ "-opt-in=androidx.benchmark.perfetto.ExperimentalPerfettoTraceProcessorApi",
+ "-opt-in=androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi"
+ ]
+ }
+}
+
androidx {
name = "Benchmark - Macrobenchmark JUnit4"
publish = Publish.SNAPSHOT_AND_RELEASE
diff --git a/benchmark/benchmark-macro-junit4/src/main/java/androidx/benchmark/macro/junit4/MacrobenchmarkRule.kt b/benchmark/benchmark-macro-junit4/src/main/java/androidx/benchmark/macro/junit4/MacrobenchmarkRule.kt
index d8a01b7..6ca8df5 100644
--- a/benchmark/benchmark-macro-junit4/src/main/java/androidx/benchmark/macro/junit4/MacrobenchmarkRule.kt
+++ b/benchmark/benchmark-macro-junit4/src/main/java/androidx/benchmark/macro/junit4/MacrobenchmarkRule.kt
@@ -24,6 +24,8 @@
import androidx.benchmark.macro.Metric
import androidx.benchmark.macro.StartupMode
import androidx.benchmark.macro.macrobenchmarkWithStartupMode
+import androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi
+import androidx.benchmark.perfetto.PerfettoConfig
import androidx.test.rule.GrantPermissionRule
import org.junit.Assume.assumeTrue
import org.junit.rules.RuleChain
@@ -94,7 +96,7 @@
* @param measureBlock The block performing app actions to benchmark each iteration.
*/
@JvmOverloads
- public fun measureRepeated(
+ fun measureRepeated(
packageName: String,
metrics: List<Metric>,
compilationMode: CompilationMode = CompilationMode.DEFAULT,
@@ -113,6 +115,78 @@
compilationMode = compilationMode,
iterations = iterations,
startupMode = startupMode,
+ perfettoConfig = null,
+ setupBlock = setupBlock,
+ measureBlock = measureBlock
+ )
+ }
+
+ /**
+ * Measure behavior of the specified [packageName] given a set of [metrics], with a custom
+ * [PerfettoConfig].
+ *
+ * This performs a macrobenchmark with the below control flow:
+ * ```
+ * resetAppCompilation()
+ * compile(compilationMode)
+ * repeat(iterations) {
+ * setupBlock()
+ * captureTraceAndMetrics {
+ * measureBlock()
+ * }
+ * }
+ * ```
+ *
+ * Note that a custom [PerfettoConfig]s may result in built-in [Metric]s not working.
+ *
+ * You can see the PerfettoConfig used by a trace (as a text proto) by opening the trace in
+ * [ui.perfetto.dev](http://ui.perfetto.dev), and selecting `Info and Stats` view on the left
+ * panel. You can also generate a custom text proto config by selecting `Record new trace` on
+ * the same panel, selecting recording options, and then clicking `Recording command` to access
+ * the generated text proto.
+ *
+ * @param packageName ApplicationId / Application manifest package name of the app for
+ * which profiles are generated.
+ * @param metrics List of metrics to measure.
+ * @param compilationMode Mode of compilation used before capturing measurement, such as
+ * [CompilationMode.Partial], defaults to [CompilationMode.DEFAULT].
+ * @param startupMode Optional mode to force app launches performed with
+ * [MacrobenchmarkScope.startActivityAndWait] (and similar variants) to be of the assigned
+ * type. For example, `COLD` launches kill the process before the measureBlock, to ensure
+ * startups will go through full process creation. Generally, leave as null for non-startup
+ * benchmarks.
+ * @param iterations Number of times the [measureBlock] will be run during measurement. Note
+ * that total iteration count may not match, due to warmup iterations needed for the
+ * [compilationMode].
+ * @param perfettoConfig Configuration for Perfetto trace capture during each iteration. Note
+ * that insufficient or invalid configs may result in built-in [Metric]s not working.
+ * @param setupBlock The block performing app actions each iteration, prior to the
+ * [measureBlock]. For example, navigating to a UI where scrolling will be measured.
+ * @param measureBlock The block performing app actions to benchmark each iteration.
+ */
+ @ExperimentalPerfettoCaptureApi
+ @JvmOverloads
+ fun measureRepeated(
+ packageName: String,
+ metrics: List<Metric>,
+ @IntRange(from = 1)
+ iterations: Int,
+ perfettoConfig: PerfettoConfig,
+ compilationMode: CompilationMode = CompilationMode.DEFAULT,
+ startupMode: StartupMode? = null,
+ setupBlock: MacrobenchmarkScope.() -> Unit = {},
+ measureBlock: MacrobenchmarkScope.() -> Unit,
+ ) {
+ macrobenchmarkWithStartupMode(
+ uniqueName = currentDescription.toUniqueName(),
+ className = currentDescription.className,
+ testName = currentDescription.methodName,
+ packageName = packageName,
+ metrics = metrics,
+ compilationMode = compilationMode,
+ iterations = iterations,
+ perfettoConfig = perfettoConfig,
+ startupMode = startupMode,
setupBlock = setupBlock,
measureBlock = measureBlock
)
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkTest.kt
index 09a6c7d..50b1662 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkTest.kt
@@ -16,8 +16,10 @@
package androidx.benchmark.macro
+import android.annotation.SuppressLint
import androidx.annotation.RequiresApi
import androidx.benchmark.DeviceInfo
+import androidx.benchmark.perfetto.PerfettoConfig
import androidx.benchmark.perfetto.PerfettoHelper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
@@ -55,6 +57,7 @@
compilationMode = CompilationMode.Ignore(),
iterations = 1,
startupMode = null,
+ perfettoConfig = null,
setupBlock = {},
measureBlock = {}
)
@@ -74,6 +77,7 @@
compilationMode = CompilationMode.Ignore(),
iterations = 0, // invalid
startupMode = null,
+ perfettoConfig = null,
setupBlock = {},
measureBlock = {}
)
@@ -101,6 +105,7 @@
compilationMode = CompilationMode.DEFAULT,
iterations = 2,
startupMode = startupMode,
+ perfettoConfig = null,
setupBlock = {
opOrder += Block.Setup
setupIterations += iteration
@@ -157,6 +162,49 @@
@Test
fun callbackBehavior_hot() = validateCallbackBehavior(StartupMode.HOT)
+ @SuppressLint("BanThreadSleep") // need non-zero duration to assert sum, regardless of clock
+ private fun validateSlicesCustomConfig(includeMacroAppTag: Boolean) {
+ val atraceApps = if (includeMacroAppTag) {
+ listOf(Packages.TEST)
+ } else {
+ emptyList()
+ }
+ val measurements = macrobenchmarkWithStartupMode(
+ uniqueName = "MacrobenchmarkTest#validateSlicesCustomConfig",
+ className = "MacrobenchmarkTest",
+ testName = "validateCallbackBehavior",
+ packageName = Packages.TARGET,
+ // disable targetPackageOnly filter, since this process emits the event
+ metrics = listOf(TraceSectionMetric(TRACE_LABEL, targetPackageOnly = false)),
+ compilationMode = CompilationMode.DEFAULT,
+ iterations = 3,
+ startupMode = null,
+ perfettoConfig = PerfettoConfig.MinimalTest(atraceApps),
+ setupBlock = { },
+ measureBlock = {
+ trace(TRACE_LABEL) {
+ Thread.sleep(2)
+ }
+ }
+ ).metrics[TRACE_LABEL + "SumMs"]!!.runs
+
+ assertEquals(3, measurements.size)
+
+ if (includeMacroAppTag) {
+ assertTrue(measurements.all { it > 0.0 })
+ } else {
+ assertEquals(listOf(0.0, 0.0, 0.0), measurements)
+ }
+ }
+
+ @LargeTest
+ @Test
+ fun customConfig_thisProcess() = validateSlicesCustomConfig(includeMacroAppTag = true)
+
+ @LargeTest
+ @Test
+ fun customConfig_noProcess() = validateSlicesCustomConfig(includeMacroAppTag = false)
+
companion object {
const val TRACE_LABEL = "MacrobencharkTestTraceLabel"
}
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt
index 8203ef7..92eecb5 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt
@@ -35,6 +35,7 @@
import androidx.benchmark.conditionalError
import androidx.benchmark.inMemoryTrace
import androidx.benchmark.json.BenchmarkData
+import androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi
import androidx.benchmark.perfetto.PerfettoCapture.PerfettoSdkConfig
import androidx.benchmark.perfetto.PerfettoCapture.PerfettoSdkConfig.InitialProcessState
import androidx.benchmark.perfetto.PerfettoCaptureWrapper
@@ -190,6 +191,7 @@
*
* This function is a building block for public testing APIs
*/
+@ExperimentalPerfettoCaptureApi
private fun macrobenchmark(
uniqueName: String,
className: String,
@@ -200,10 +202,11 @@
iterations: Int,
launchWithClearTask: Boolean,
startupModeMetricHint: StartupMode?,
+ perfettoConfig: PerfettoConfig?,
perfettoSdkConfig: PerfettoSdkConfig?,
setupBlock: MacrobenchmarkScope.() -> Unit,
measureBlock: MacrobenchmarkScope.() -> Unit
-) {
+): BenchmarkData.TestResult {
require(iterations > 0) {
"Require iterations > 0 (iterations = $iterations)"
}
@@ -276,7 +279,7 @@
val fileLabel = "${uniqueName}_iter$iterString"
val tracePath = perfettoCollector.record(
fileLabel = fileLabel,
- config = PerfettoConfig.Benchmark(
+ config = perfettoConfig ?: PerfettoConfig.Benchmark(
/**
* Prior to API 24, every package name was joined into a single setprop
* which can overflow, and disable *ALL* app level tracing.
@@ -405,18 +408,18 @@
} + methodTracingResultFiles).map {
BenchmarkData.TestResult.ProfilerOutput(it)
}
- ResultWriter.appendTestResult(
- BenchmarkData.TestResult(
- className = className,
- name = testName,
- totalRunTimeNs = System.nanoTime() - startTime,
- metrics = measurements.singleMetrics + measurements.sampledMetrics,
- repeatIterations = iterations,
- thermalThrottleSleepSeconds = 0,
- warmupIterations = warmupIterations,
- profilerOutputs = mergedProfilerOutputs
- )
+ val testResult = BenchmarkData.TestResult(
+ className = className,
+ name = testName,
+ totalRunTimeNs = System.nanoTime() - startTime,
+ metrics = measurements.singleMetrics + measurements.sampledMetrics,
+ repeatIterations = iterations,
+ thermalThrottleSleepSeconds = 0,
+ warmupIterations = warmupIterations,
+ profilerOutputs = mergedProfilerOutputs
)
+ ResultWriter.appendTestResult(testResult)
+ return testResult
} finally {
scope.killProcess()
}
@@ -426,6 +429,7 @@
* Run a macrobenchmark with the specified StartupMode
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@ExperimentalPerfettoCaptureApi
fun macrobenchmarkWithStartupMode(
uniqueName: String,
className: String,
@@ -434,10 +438,11 @@
metrics: List<Metric>,
compilationMode: CompilationMode,
iterations: Int,
+ perfettoConfig: PerfettoConfig?,
startupMode: StartupMode?,
setupBlock: MacrobenchmarkScope.() -> Unit,
measureBlock: MacrobenchmarkScope.() -> Unit
-) {
+): BenchmarkData.TestResult {
val perfettoSdkConfig =
if (Arguments.perfettoSdkTracingEnable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
PerfettoSdkConfig(
@@ -449,7 +454,7 @@
}
)
} else null
- macrobenchmark(
+ return macrobenchmark(
uniqueName = uniqueName,
className = className,
testName = testName,
@@ -458,6 +463,7 @@
compilationMode = compilationMode,
iterations = iterations,
startupModeMetricHint = startupMode,
+ perfettoConfig = perfettoConfig,
perfettoSdkConfig = perfettoSdkConfig,
setupBlock = {
if (startupMode == StartupMode.COLD) {
diff --git a/biometric/biometric/src/main/res/values-ja/strings.xml b/biometric/biometric/src/main/res/values-ja/strings.xml
index 8fb1180..b0742f2 100644
--- a/biometric/biometric/src/main/res/values-ja/strings.xml
+++ b/biometric/biometric/src/main/res/values-ja/strings.xml
@@ -23,7 +23,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="7520712796891883488">"指紋が登録されていません。"</string>
<string name="fingerprint_error_hw_not_present" msgid="6306988885793029438">"このデバイスには指紋認証センサーがありません"</string>
<string name="fingerprint_error_user_canceled" msgid="7627716295344353987">"指紋認証操作がユーザーによりキャンセルされました。"</string>
- <string name="fingerprint_error_lockout" msgid="7291787166416782245">"入力回数が上限を超えました。しばらくしてからもう一度お試しください。"</string>
+ <string name="fingerprint_error_lockout" msgid="7291787166416782245">"試行回数が上限に達しました。しばらくしてからもう一度お試しください。"</string>
<string name="default_error_msg" msgid="4776854077120974966">"不明なエラーです"</string>
<string name="generic_error_user_canceled" msgid="7309881387583143581">"認証はユーザーによりキャンセルされました。"</string>
<string name="confirm_device_credential_password" msgid="5912733858573823945">"パスワードを使用"</string>
diff --git a/buildSrc-tests/lint-baseline.xml b/buildSrc-tests/lint-baseline.xml
index e3a6f65..46f896e 100644
--- a/buildSrc-tests/lint-baseline.xml
+++ b/buildSrc-tests/lint-baseline.xml
@@ -85,15 +85,6 @@
<issue
id="EagerGradleConfiguration"
message="Use configureEach instead of all"
- errorLine1=" buildTypes.all { buildType ->"
- errorLine2=" ~~~">
- <location
- file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/AndroidXImplPlugin.kt"/>
- </issue>
-
- <issue
- id="EagerGradleConfiguration"
- message="Use configureEach instead of all"
errorLine1=" project.configurations.all { configuration ->"
errorLine2=" ~~~">
<location
@@ -121,24 +112,6 @@
<issue
id="EagerGradleConfiguration"
message="Use configureEach instead of all"
- errorLine1=" kotlinTarget.compilations.all {"
- errorLine2=" ~~~">
- <location
- file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/AndroidXImplPlugin.kt"/>
- </issue>
-
- <issue
- id="EagerGradleConfiguration"
- message="Use configureEach instead of all"
- errorLine1=" project.configurations.all { config ->"
- errorLine2=" ~~~">
- <location
- file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/AndroidXImplPlugin.kt"/>
- </issue>
-
- <issue
- id="EagerGradleConfiguration"
- message="Use configureEach instead of all"
errorLine1=" configurations.all { configuration ->"
errorLine2=" ~~~">
<location
@@ -291,18 +264,9 @@
<issue
id="EagerGradleConfiguration"
- message="Use configureEach instead of all"
- errorLine1=" libraryVariants.all { variant ->"
- errorLine2=" ~~~">
- <location
- file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/Release.kt"/>
- </issue>
-
- <issue
- id="EagerGradleConfiguration"
message="Use configureEach instead of whenObjectAdded"
- errorLine1=" configurations.whenObjectAdded {"
- errorLine2=" ~~~~~~~~~~~~~~~">
+ errorLine1=" configurations.whenObjectAdded {"
+ errorLine2=" ~~~~~~~~~~~~~~~">
<location
file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/SourceJarTaskHelper.kt"/>
</issue>
@@ -310,8 +274,8 @@
<issue
id="EagerGradleConfiguration"
message="Use configureEach instead of whenObjectAdded"
- errorLine1=" it.artifacts.whenObjectAdded { _ ->"
- errorLine2=" ~~~~~~~~~~~~~~~">
+ errorLine1=" it.artifacts.whenObjectAdded { _ ->"
+ errorLine2=" ~~~~~~~~~~~~~~~">
<location
file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/SourceJarTaskHelper.kt"/>
</issue>
@@ -373,8 +337,17 @@
<issue
id="GradleProjectIsolation"
message="Use providers.gradleProperty instead of findProperty"
- errorLine1=" override val compileSdk: String by lazy { project.findProperty(COMPILE_SDK_VERSION).toString() }"
- errorLine2=" ~~~~~~~~~~~~">
+ errorLine1=" override val compileSdk: Int by lazy { project.findProperty(COMPILE_SDK).toString().toInt() }"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*3}/androidx/build/AndroidXConfig.kt"/>
+ </issue>
+
+ <issue
+ id="GradleProjectIsolation"
+ message="Use providers.gradleProperty instead of findProperty"
+ errorLine1=" project.findProperty(COMPILE_SDK_EXTENSION) as Int?"
+ errorLine2=" ~~~~~~~~~~~~">
<location
file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*3}/androidx/build/AndroidXConfig.kt"/>
</issue>
@@ -685,13 +658,4 @@
file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/AndroidXImplPlugin.kt"/>
</issue>
- <issue
- id="WithTypeWithoutConfigureEach"
- message="Avoid passing a closure to withType, use withType().configureEach instead"
- errorLine1=" project.tasks.withType(Test::class.java) { task -> configureJvmTestTask(project, task) }"
- errorLine2=" ~~~~~~~~">
- <location
- file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/AndroidXImplPlugin.kt"/>
- </issue>
-
</issues>
diff --git a/buildSrc-tests/src/test/java/androidx/build/AndroidXImplPluginTest.kt b/buildSrc-tests/src/test/java/androidx/build/AndroidXImplPluginTest.kt
deleted file mode 100644
index d3b6f57..0000000
--- a/buildSrc-tests/src/test/java/androidx/build/AndroidXImplPluginTest.kt
+++ /dev/null
@@ -1,89 +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.build
-
-import org.junit.Assert
-import org.junit.Test
-
-class AndroidXImplPluginTest {
-
- @Test
- fun testRemoveTargetSdkVersion() {
- /* ktlint-disable max-line-length */
- val manifest = """
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="androidx.core" >
-
- <uses-sdk
- android:minSdkVersion="14"
- android:targetSdkVersion="31" />
-
- <application android:appComponentFactory="androidx.core.app.CoreComponentFactory" />
-
-</manifest>
- """
-
- // Expect that the android:targetSdkVersion element is removed.
- val expected = """
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="androidx.core" >
-
- <uses-sdk
- android:minSdkVersion="14" />
-
- <application android:appComponentFactory="androidx.core.app.CoreComponentFactory" />
-
-</manifest>
- """
- /* ktlint-enable max-line-length */
-
- val actual = removeTargetSdkVersion(manifest)
- Assert.assertEquals(expected, actual)
- }
-}
diff --git a/buildSrc-tests/src/test/java/androidx/build/SdkResourceGeneratorTest.kt b/buildSrc-tests/src/test/java/androidx/build/SdkResourceGeneratorTest.kt
index 37ad297..7c78075 100644
--- a/buildSrc-tests/src/test/java/androidx/build/SdkResourceGeneratorTest.kt
+++ b/buildSrc-tests/src/test/java/androidx/build/SdkResourceGeneratorTest.kt
@@ -46,6 +46,7 @@
project.setSupportRootFolder(File("files/support"))
val extension = project.rootProject.property("ext") as ExtraPropertiesExtension
extension.set("prebuiltsRoot", project.projectDir.resolve("relative/prebuilts"))
+ extension.set("androidx.compileSdk", 33)
val taskProvider = SdkResourceGenerator.registerSdkResourceGeneratorTask(project)
val tasks = project.getTasksByName(SdkResourceGenerator.TASK_NAME, false)
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AarManifestTransformerTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/AarManifestTransformerTask.kt
deleted file mode 100644
index 6dde7c7..0000000
--- a/buildSrc/private/src/main/kotlin/androidx/build/AarManifestTransformerTask.kt
+++ /dev/null
@@ -1,102 +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.build
-
-import java.io.File
-import java.nio.file.Files
-import java.nio.file.attribute.FileTime
-import org.apache.tools.zip.ZipEntry
-import org.apache.tools.zip.ZipFile
-import org.apache.tools.zip.ZipOutputStream
-import org.gradle.api.DefaultTask
-import org.gradle.api.file.RegularFileProperty
-import org.gradle.api.tasks.CacheableTask
-import org.gradle.api.tasks.InputFile
-import org.gradle.api.tasks.OutputFile
-import org.gradle.api.tasks.PathSensitive
-import org.gradle.api.tasks.PathSensitivity
-import org.gradle.api.tasks.TaskAction
-
-/** Transforms an AAR by removing the `android:targetSdkVersion` element from the manifest. */
-@CacheableTask
-abstract class AarManifestTransformerTask : DefaultTask() {
- @get:InputFile
- @get:PathSensitive(PathSensitivity.RELATIVE)
- abstract val aarFile: RegularFileProperty
-
- @get:OutputFile abstract val updatedAarFile: RegularFileProperty
-
- @TaskAction
- fun taskAction() {
- val aar = aarFile.get().asFile
- val updatedAar = updatedAarFile.get().asFile
- val tempDir = Files.createTempDirectory("${name}Unzip").toFile()
- tempDir.deleteOnExit()
-
- ZipFile(aar).use { aarFile -> aarFile.unzipTo(tempDir) }
-
- val manifestFile = File(tempDir, "AndroidManifest.xml")
- manifestFile.writeText(removeTargetSdkVersion(manifestFile.readText()))
-
- tempDir.zipTo(updatedAar)
- tempDir.deleteRecursively()
- }
-}
-
-/** Removes the `android:targetSdkVersion` element from the [manifest]. */
-fun removeTargetSdkVersion(manifest: String): String =
- manifest.replace("\\s*android:targetSdkVersion=\".+?\"".toRegex(), "")
-
-private fun ZipFile.unzipTo(tempDir: File) {
- entries.iterator().forEach { entry ->
- if (entry.isDirectory) {
- File(tempDir, entry.name).mkdirs()
- } else {
- val file = File(tempDir, entry.name)
- file.parentFile.mkdirs()
- getInputStream(entry).use { stream -> file.writeBytes(stream.readBytes()) }
- }
- }
-}
-
-private fun File.zipTo(outZip: File) {
- ZipOutputStream(outZip.outputStream()).use { stream ->
- listFiles()!!.forEach { file -> stream.addFileRecursive(null, file) }
- }
-}
-
-private fun ZipOutputStream.addFileRecursive(parentPath: String?, file: File) {
- val entryPath = if (parentPath != null) "$parentPath/${file.name}" else file.name
- val entry = ZipEntry(file, entryPath)
-
- // Reset creation time of entry to make it deterministic.
- entry.time = 0
- entry.creationTime = FileTime.fromMillis(0)
-
- if (file.isFile) {
- putNextEntry(entry)
- file.inputStream().use { stream -> stream.copyTo(this) }
- closeEntry()
- } else if (file.isDirectory) {
- val listFiles = file.listFiles()
- if (!listFiles.isNullOrEmpty()) {
- putNextEntry(entry)
- closeEntry()
- listFiles.forEach { containedFile -> addFileRecursive(entryPath, containedFile) }
- }
- }
-}
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXComposeImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXComposeImplPlugin.kt
index dbbc781..51df347 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXComposeImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXComposeImplPlugin.kt
@@ -340,6 +340,6 @@
SourceOption(ComposePluginId, "sourceInformation"),
MetricsOption(ComposePluginId, "metricsDestination"),
ReportsOption(ComposePluginId, "reportsDestination"),
- StrongSkippingOption(ComposePluginId, "experimentalStrongSkipping"),
+ StrongSkippingOption(ComposePluginId, "strongSkipping"),
NonSkippingGroupOption(ComposePluginId, "nonSkippingGroupOptimization")
}
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
index 571be0f..c6337e0 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
@@ -39,13 +39,14 @@
import androidx.build.testConfiguration.configureTestConfigGeneration
import androidx.build.uptodatedness.TaskUpToDateValidator
import androidx.build.uptodatedness.cacheEvenIfNoOutputs
-import com.android.build.api.artifact.Artifacts
import com.android.build.api.artifact.SingleArtifact
import com.android.build.api.dsl.ApplicationExtension
+import com.android.build.api.dsl.CommonExtension
import com.android.build.api.dsl.KotlinMultiplatformAndroidTarget
import com.android.build.api.dsl.KotlinMultiplatformAndroidTestOnDeviceCompilation
import com.android.build.api.dsl.KotlinMultiplatformAndroidTestOnJvmCompilation
import com.android.build.api.dsl.PrivacySandboxSdkExtension
+import com.android.build.api.dsl.TestExtension
import com.android.build.api.variant.AndroidComponentsExtension
import com.android.build.api.variant.ApplicationAndroidComponentsExtension
import com.android.build.api.variant.HasDeviceTests
@@ -53,12 +54,9 @@
import com.android.build.api.variant.KotlinMultiplatformAndroidComponentsExtension
import com.android.build.api.variant.LibraryAndroidComponentsExtension
import com.android.build.api.variant.Variant
-import com.android.build.gradle.AppExtension
import com.android.build.gradle.AppPlugin
-import com.android.build.gradle.BaseExtension
import com.android.build.gradle.LibraryExtension
import com.android.build.gradle.LibraryPlugin
-import com.android.build.gradle.TestExtension
import com.android.build.gradle.TestPlugin
import com.android.build.gradle.TestedExtension
import com.android.build.gradle.api.KotlinMultiplatformAndroidPlugin
@@ -185,7 +183,10 @@
project.tasks.withType(AbstractTestTask::class.java) { task ->
configureTestTask(project, task, allHostTests)
}
- project.tasks.withType(Test::class.java) { task -> configureJvmTestTask(project, task) }
+
+ project.tasks.withType(Test::class.java).configureEach { task ->
+ configureJvmTestTask(project, task)
+ }
project.configureTaskTimeouts()
project.configureMavenArtifactUpload(
@@ -219,7 +220,6 @@
project.workaroundPrebuiltTakingPrecedenceOverProject()
}
-
private fun Project.registerProjectOrArtifact() {
// Add a method for each sub project where they can declare an optional
// dependency on a project or its latest snapshot artifact.
@@ -572,13 +572,18 @@
}
private fun configureWithAppPlugin(project: Project, androidXExtension: AndroidXExtension) {
- project.extensions.getByType<AppExtension>().apply {
- configureAndroidBaseOptions(project, androidXExtension)
- excludeVersionFiles(packagingOptions.resources)
- }
-
project.extensions.getByType<ApplicationExtension>().apply {
+ configureAndroidBaseOptions(project, androidXExtension)
+ defaultConfig.targetSdk = project.defaultAndroidConfig.targetSdk
+ val debugSigningConfig = signingConfigs.getByName("debug")
+ // Use a local debug keystore to avoid build server issues.
+ debugSigningConfig.storeFile = project.getKeystore()
+ buildTypes.configureEach { buildType ->
+ // Sign all the builds (including release) with debug key
+ buildType.signingConfig = debugSigningConfig
+ }
configureAndroidApplicationOptions(project, androidXExtension)
+ excludeVersionFiles(packaging.resources)
}
project.extensions.getByType<ApplicationAndroidComponentsExtension>().apply {
@@ -602,12 +607,17 @@
private fun configureWithTestPlugin(project: Project, androidXExtension: AndroidXExtension) {
project.extensions.getByType<TestExtension>().apply {
configureAndroidBaseOptions(project, androidXExtension)
- excludeVersionFiles(packagingOptions.resources)
- }
-
- project.extensions.getByType<com.android.build.api.dsl.TestExtension>().apply {
+ defaultConfig.targetSdk = project.defaultAndroidConfig.targetSdk
+ val debugSigningConfig = signingConfigs.getByName("debug")
+ // Use a local debug keystore to avoid build server issues.
+ debugSigningConfig.storeFile = project.getKeystore()
+ buildTypes.configureEach { buildType ->
+ // Sign all the builds (including release) with debug key
+ buildType.signingConfig = debugSigningConfig
+ }
project.configureTestConfigGeneration(this)
project.addAppApkToTestConfigGeneration(androidXExtension)
+ excludeVersionFiles(packaging.resources)
}
project.configureJavaCompilationWarnings(androidXExtension)
@@ -637,10 +647,6 @@
androidXExtension
)
- kotlinMultiplatformAndroidComponentsExtension.onVariant { variant ->
- project.createVariantAarManifestTransformerTask(variant.name, variant.artifacts)
- }
-
kotlinMultiplatformAndroidComponentsExtension.onVariant {
it.configureTests()
}
@@ -802,54 +808,63 @@
experimentalProperties.put(ASB_SIGNING_CONFIG_PROPERTY_NAME, keyStore.absolutePath)
}
- @Suppress("DEPRECATION") // AGP DSL APIs
private fun configureWithLibraryPlugin(project: Project, androidXExtension: AndroidXExtension) {
- project.extensions.getByType<LibraryExtension>().apply {
- configureAndroidBaseOptions(project, androidXExtension)
- configureAndroidLibraryOptions(project, androidXExtension)
+ project.extensions.getByType<com.android.build.api.dsl.LibraryExtension>().apply {
+ publishing { singleVariant(DEFAULT_PUBLISH_CONFIG) }
- // Make sure the main Kotlin source set doesn't contain anything under
- // src/main/kotlin.
- val mainKotlinSrcDir =
- (sourceSets.findByName("main")?.kotlin
- as com.android.build.gradle.api.AndroidSourceDirectorySet)
- .srcDirs
- .filter { it.name == "kotlin" }
- .getOrNull(0)
- if (mainKotlinSrcDir?.isDirectory == true) {
- throw GradleException(
- "Invalid project structure! AndroidX does not support \"kotlin\" as a " +
- "top-level source directory for libraries, use \"java\" instead: " +
- mainKotlinSrcDir.path
- )
+ configureAndroidBaseOptions(project, androidXExtension)
+ project.defaultAndroidConfig.targetSdk.let {
+ lint.targetSdk = it
+ testOptions.targetSdk = it
}
+ val debugSigningConfig = signingConfigs.getByName("debug")
+ // Use a local debug keystore to avoid build server issues.
+ debugSigningConfig.storeFile = project.getKeystore()
+ buildTypes.configureEach { buildType ->
+ // Sign all the builds (including release) with debug key
+ buildType.signingConfig = debugSigningConfig
+ }
+ project.configureTestConfigGeneration(this)
+ project.addAppApkToTestConfigGeneration(androidXExtension)
}
val libraryAndroidComponentsExtension =
project.extensions.getByType<LibraryAndroidComponentsExtension>()
- // Remove the android:targetSdkVersion element from the manifest used for AARs.
- libraryAndroidComponentsExtension.onVariants { variant ->
- project.createVariantAarManifestTransformerTask(variant.name, variant.artifacts)
- }
-
- project.extensions.getByType<com.android.build.api.dsl.LibraryExtension>().apply {
- publishing { singleVariant(DEFAULT_PUBLISH_CONFIG) }
- project.configureTestConfigGeneration(this)
- project.addAppApkToTestConfigGeneration(androidXExtension)
- }
-
libraryAndroidComponentsExtension.apply {
- beforeVariants(selector().withBuildType("release")) { variant ->
- variant.enableUnitTest = false
+ finalizeDsl {
+ // Propagate the compileSdk value into minCompileSdk. Don't propagate
+ // compileSdkExtension, since only one library actually depends on the extension
+ // APIs and they can explicitly declare that in their build.gradle. Note that when
+ // we're using a preview SDK, the value for compileSdk will be null and the
+ // resulting AAR metadata won't have a minCompileSdk --
+ // this is okay because AGP automatically embeds forceCompileSdkPreview in the AAR
+ // metadata and uses it instead of minCompileSdk.
+ it.defaultConfig.aarMetadata.minCompileSdk = it.compileSdk
}
- onVariants {
- it.configureTests()
- it.aotCompileMicrobenchmarks(project)
- it.enableLongMethodTracingInMicrobenchmark(project)
+ beforeVariants(selector().withBuildType("release")) { variant ->
+ (variant as HasUnitTestBuilder).enableUnitTest = false
+ }
+ onVariants { variant ->
+ // Make sure the main Kotlin source set doesn't contain anything under
+ // src/main/kotlin.
+ val mainKotlinSrcDir = variant.sources.kotlin?.static?.get()?.map { it.asFile }
+ ?.filter { it.path.contains("src/main/kotlin") }?.getOrNull(0)
+ if (mainKotlinSrcDir?.isDirectory == true) {
+ throw GradleException(
+ "Invalid project structure! AndroidX does not support \"kotlin\" as a " +
+ "top-level source directory for libraries, use \"java\" instead: " +
+ mainKotlinSrcDir.path
+ )
+ }
+ variant.configureTests()
+ variant.aotCompileMicrobenchmarks(project)
+ variant.enableLongMethodTracingInMicrobenchmark(project)
}
}
+ project.disableStrictVersionConstraints()
+ project.setPublishProperty(androidXExtension)
project.configureVersionFileWriter(libraryAndroidComponentsExtension, androidXExtension)
project.configureJavaCompilationWarnings(androidXExtension)
@@ -1022,7 +1037,7 @@
afterEvaluate { androidXExtension.validateMavenVersion() }
}
- private fun BaseExtension.configureAndroidBaseOptions(
+ private fun CommonExtension<*, *, *, *, *, *>.configureAndroidBaseOptions(
project: Project,
androidXExtension: AndroidXExtension
) {
@@ -1032,20 +1047,18 @@
}
project.disableJava8TargetObsoleteWarnings()
- val defaultMinSdkVersion = project.defaultAndroidConfig.minSdk
- val defaultCompileSdkVersion = project.defaultAndroidConfig.compileSdk
+ val defaultMinSdk = project.defaultAndroidConfig.minSdk
+ val defaultCompileSdk = project.defaultAndroidConfig.compileSdk
// Suppress output of android:compileSdkVersion and related attributes (b/277836549).
- aaptOptions.additionalParameters += "--no-compile-sdk-metadata"
+ androidResources.additionalParameters += "--no-compile-sdk-metadata"
- // Specify default values. The client may attempt to override these in their build.gradle,
- // so we'll need to perform validation in afterEvaluate().
- compileSdkVersion(defaultCompileSdkVersion)
+ compileSdk = project.defaultAndroidConfig.compileSdk
+
buildToolsVersion = project.defaultAndroidConfig.buildToolsVersion
ndkVersion = project.defaultAndroidConfig.ndkVersion
- defaultConfig.minSdk = defaultMinSdkVersion
- defaultConfig.targetSdk = project.defaultAndroidConfig.targetSdk
+ defaultConfig.minSdk = defaultMinSdk
defaultConfig.testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
testOptions.animationsDisabled = !project.isMacrobenchmark()
@@ -1059,14 +1072,15 @@
project.afterEvaluate {
val minSdkVersion = defaultConfig.minSdk!!
- check(minSdkVersion >= defaultMinSdkVersion) {
- "minSdkVersion $minSdkVersion lower than the default of $defaultMinSdkVersion"
+ check(minSdkVersion >= defaultMinSdk) {
+ "minSdkVersion $minSdkVersion lower than the default of $defaultMinSdk"
}
check(
- compileSdkVersion == defaultCompileSdkVersion || project.isCustomCompileSdkAllowed()
+ compileSdk == defaultCompileSdk || project.isCustomCompileSdkAllowed()
) {
- "compileSdkVersion must not be explicitly specified, was \"$compileSdkVersion\""
+ "compileSdk must not be explicitly specified, was \"$compileSdk\""
}
+
project.enforceBanOnVersionRanges()
if (androidXExtension.type.compilationTarget != CompilationTarget.DEVICE) {
@@ -1077,14 +1091,6 @@
}
}
- val debugSigningConfig = signingConfigs.getByName("debug")
- // Use a local debug keystore to avoid build server issues.
- debugSigningConfig.storeFile = project.getKeystore()
- buildTypes.all { buildType ->
- // Sign all the builds (including release) with debug key
- buildType.signingConfig = debugSigningConfig
- }
-
project.configureErrorProneForAndroid()
// workaround for b/120487939
@@ -1118,9 +1124,9 @@
componentsExtension: KotlinMultiplatformAndroidComponentsExtension
) {
val defaultMinSdkVersion = project.defaultAndroidConfig.minSdk
- val defaultCompileSdkVersion = project.defaultAndroidConfig.compileSdkInt()
+ val defaultCompileSdk = project.defaultAndroidConfig.compileSdk
- compileSdk = defaultCompileSdkVersion
+ compileSdk = defaultCompileSdk
buildToolsVersion = project.defaultAndroidConfig.buildToolsVersion
minSdk = defaultMinSdkVersion
@@ -1151,9 +1157,9 @@
"minSdkVersion $minSdkVersion lower than the default of $defaultMinSdkVersion"
}
check(
- compileSdk == defaultCompileSdkVersion || project.isCustomCompileSdkAllowed()
+ compileSdk == defaultCompileSdk || project.isCustomCompileSdkAllowed()
) {
- "compileSdkVersion must not be explicitly specified, was \"$compileSdk\""
+ "compileSdk must not be explicitly specified, was \"$compileSdk\""
}
project.enforceBanOnVersionRanges()
}
@@ -1165,24 +1171,6 @@
project.configureFtlRunner(componentsExtension)
}
- @Suppress("UnstableApiUsage") // finalizeDsl, minCompileSdkExtension
- private fun LibraryExtension.configureAndroidLibraryOptions(
- project: Project,
- androidXExtension: AndroidXExtension
- ) {
- // Propagate the compileSdk value into minCompileSdk. Don't propagate compileSdkExtension,
- // since only one library actually depends on the extension APIs and they can explicitly
- // declare that in their build.gradle. Note that when we're using a preview SDK, the value
- // for compileSdk will be null and the resulting AAR metadata won't have a minCompileSdk --
- // this is okay because AGP automatically embeds forceCompileSdkPreview in the AAR metadata
- // and uses it instead of minCompileSdk.
- project.extensions.findByType<LibraryAndroidComponentsExtension>()!!.finalizeDsl {
- it.defaultConfig.aarMetadata.minCompileSdk = it.compileSdk
- }
- project.disableStrictVersionConstraints()
- project.setPublishProperty(androidXExtension)
- }
-
private fun KotlinMultiplatformAndroidTarget.configureAndroidLibraryOptions(
project: Project,
androidXExtension: AndroidXExtension
@@ -1270,7 +1258,7 @@
// Configure all KMP targets to allow expect/actual classes that are not stable.
// (see https://youtrack.jetbrains.com/issue/KT-61573)
kmpExtension.targets.all { kotlinTarget ->
- kotlinTarget.compilations.all {
+ kotlinTarget.compilations.configureEach {
it.compilerOptions.options.freeCompilerArgs.add("-Xexpect-actual-classes")
}
}
@@ -1381,11 +1369,11 @@
}
// disallow duplicate constraints
- project.configurations.all { config ->
+ project.configurations.configureEach { config ->
// Allow duplicate constraints in test configurations. This is partially a
// workaround for duplication due to downgrading strict-type dependencies to
// required-type, but also we don't care if tests have duplicate constraints.
- if (config.isTest()) return@all
+ if (config.isTest()) return@configureEach
// find all constraints contributed by this Configuration and its ancestors
val configurationConstraints: MutableSet<String> = mutableSetOf()
@@ -1427,27 +1415,6 @@
return true
}
- private fun Project.createVariantAarManifestTransformerTask(
- variantName: String,
- artifacts: Artifacts
- ) {
- // Remove the android:targetSdkVersion element from the manifest used for AARs.
- tasks
- .register(
- variantName + "AarManifestTransformer",
- AarManifestTransformerTask::class.java
- )
- .let { taskProvider ->
- artifacts
- .use(taskProvider)
- .wiredWithFiles(
- AarManifestTransformerTask::aarFile,
- AarManifestTransformerTask::updatedAarFile
- )
- .toTransform(SingleArtifact.AAR)
- }
- }
-
companion object {
const val CREATE_LIBRARY_BUILD_INFO_FILES_TASK = "createLibraryBuildInfoFiles"
const val GENERATE_TEST_CONFIGURATION_TASK = "GenerateTestConfiguration"
@@ -1683,8 +1650,6 @@
}
}
-private fun AndroidConfig.compileSdkInt() = compileSdk.removePrefix("android-").toInt()
-
private fun Test.configureForRobolectric() {
// https://github.com/robolectric/robolectric/issues/7456
jvmArgs =
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/dackka/DackkaTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/dackka/DackkaTask.kt
index 3eaafa9..ccc74a1 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/dackka/DackkaTask.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/dackka/DackkaTask.kt
@@ -67,9 +67,18 @@
@get:[InputFiles PathSensitive(PathSensitivity.RELATIVE)]
abstract val frameworkSamplesDir: DirectoryProperty
- // Directory containing the code samples
+ // Directory containing the code samples derived via the old method. This will be removed
+ // as soon as all libraries have been published with samples. b/329424152
@get:[InputFiles PathSensitive(PathSensitivity.RELATIVE)]
- abstract val samplesDir: DirectoryProperty
+ abstract val samplesDeprecatedDir: DirectoryProperty
+
+ // Directory containing the code samples for non-KMP libraries
+ @get:[InputFiles PathSensitive(PathSensitivity.RELATIVE)]
+ abstract val samplesJvmDir: DirectoryProperty
+
+ // Directory containing the code samples for KMP libraries
+ @get:[InputFiles PathSensitive(PathSensitivity.RELATIVE)]
+ abstract val samplesKmpDir: DirectoryProperty
// Directory containing the JVM source code for Dackka to process
@get:[InputFiles PathSensitive(PathSensitivity.RELATIVE)]
@@ -153,7 +162,9 @@
// samples are in common
samples = if (analysisPlatform == DokkaAnalysisPlatform.COMMON) {
objects.fileCollection().from(
- samplesDir,
+ samplesDeprecatedDir,
+ samplesJvmDir,
+ samplesKmpDir,
frameworkSamplesDir.get().asFile
)
} else {
@@ -179,7 +190,9 @@
analysisPlatform = "jvm",
sourceRoots = objects.fileCollection().from(jvmSourcesDir),
samples = objects.fileCollection().from(
- samplesDir,
+ samplesDeprecatedDir,
+ samplesJvmDir,
+ samplesKmpDir,
frameworkSamplesDir.get().asFile
),
includes = objects.fileCollection().from(includesFiles(jvmSourcesDir.get().asFile)),
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/docs/AndroidXDocsImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/docs/AndroidXDocsImplPlugin.kt
index 4cd160c..c73c126 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/docs/AndroidXDocsImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/docs/AndroidXDocsImplPlugin.kt
@@ -32,13 +32,14 @@
import androidx.build.versionCatalog
import androidx.build.workaroundPrebuiltTakingPrecedenceOverProject
import com.android.build.api.attributes.BuildTypeAttr
-import com.android.build.gradle.LibraryExtension
+import com.android.build.api.dsl.LibraryExtension
import com.android.build.gradle.LibraryPlugin
import com.google.gson.GsonBuilder
import java.io.File
import java.io.FileNotFoundException
import java.time.Duration
import java.time.LocalDateTime
+import java.util.concurrent.TimeUnit
import javax.inject.Inject
import org.gradle.api.DefaultTask
import org.gradle.api.Plugin
@@ -103,7 +104,7 @@
when (plugin) {
is LibraryPlugin -> {
val libraryExtension = project.extensions.getByType<LibraryExtension>()
- libraryExtension.compileSdkVersion = project.defaultAndroidConfig.compileSdk
+ libraryExtension.compileSdk = project.defaultAndroidConfig.compileSdk
libraryExtension.buildToolsVersion =
project.defaultAndroidConfig.buildToolsVersion
@@ -126,15 +127,19 @@
distributionDirectory = project.getDistributionDirectory()
}
- val unzippedSamplesSources = project.layout.buildDirectory.dir("unzippedSampleSources")
- val unzipSamplesTask =
+ val unzippedDeprecatedSamplesSources =
+ project.layout.buildDirectory.dir("unzippedDeprecatedSampleSources")
+ val deprecatedUnzipSamplesTask =
configureUnzipTask(
project,
- "unzipSampleSources",
- unzippedSamplesSources,
+ "unzipSampleSourcesDeprecated",
+ unzippedDeprecatedSamplesSources,
samplesSourcesConfiguration
)
-
+ val unzippedKmpSamplesSourcesDirectory =
+ project.layout.buildDirectory.dir("unzippedMultiplatformSampleSources")
+ val unzippedJvmSamplesSourcesDirectory =
+ project.layout.buildDirectory.dir("unzippedJvmSampleSources")
val unzippedJvmSourcesDirectory = project.layout.buildDirectory.dir("unzippedJvmSources")
val unzippedMultiplatformSourcesDirectory =
project.layout.buildDirectory.dir("unzippedMultiplatformSources")
@@ -142,33 +147,38 @@
project.layout.buildDirectory.file(
"project_metadata/$PROJECT_STRUCTURE_METADATA_FILENAME"
)
- val unzipJvmSourcesTask =
+ val (unzipJvmSourcesTask, unzipJvmSamplesTask) =
configureUnzipJvmSourcesTasks(
project,
unzippedJvmSourcesDirectory,
+ unzippedJvmSamplesSourcesDirectory,
docsSourcesConfiguration
)
val configureMultiplatformSourcesTask =
configureMultiplatformInputsTasks(
project,
unzippedMultiplatformSourcesDirectory,
+ unzippedKmpSamplesSourcesDirectory,
multiplatformDocsSourcesConfiguration,
mergedProjectMetadata
)
configureDackka(
- project,
- unzippedJvmSourcesDirectory,
- unzippedMultiplatformSourcesDirectory,
- unzipJvmSourcesTask,
- configureMultiplatformSourcesTask,
- unzippedSamplesSources,
- unzipSamplesTask,
- dependencyClasspath,
- buildOnServer,
- docsSourcesConfiguration,
- multiplatformDocsSourcesConfiguration,
- mergedProjectMetadata
+ project = project,
+ unzippedJvmSourcesDirectory = unzippedJvmSourcesDirectory,
+ unzippedMultiplatformSourcesDirectory = unzippedMultiplatformSourcesDirectory,
+ unzipJvmSourcesTask = unzipJvmSourcesTask,
+ configureMultiplatformSourcesTask = configureMultiplatformSourcesTask,
+ unzippedDeprecatedSamplesSources = unzippedDeprecatedSamplesSources,
+ unzipDeprecatedSamplesTask = deprecatedUnzipSamplesTask,
+ unzippedJvmSamplesSources = unzippedJvmSamplesSourcesDirectory,
+ unzipJvmSamplesTask = unzipJvmSamplesTask,
+ unzippedKmpSamplesSources = unzippedKmpSamplesSourcesDirectory,
+ dependencyClasspath = dependencyClasspath,
+ buildOnServer = buildOnServer,
+ docsConfiguration = docsSourcesConfiguration,
+ multiplatformDocsConfiguration = multiplatformDocsSourcesConfiguration,
+ mergedProjectMetadata = mergedProjectMetadata
)
project.configureTaskTimeouts()
@@ -214,36 +224,45 @@
}
/**
- * Creates and configures a task that will build a list of select sources from jars and places
- * them in [destinationDirectory].
+ * Creates and configures a task that builds a list of select sources from jars and places them
+ * in [sourcesDestinationDirectory], partitioning samples into [samplesDestinationDirectory].
*
* This is a modified version of [configureUnzipTask], customized for Dackka usage.
*/
private fun configureUnzipJvmSourcesTasks(
project: Project,
- destinationDirectory: Provider<Directory>,
+ sourcesDestinationDirectory: Provider<Directory>,
+ samplesDestinationDirectory: Provider<Directory>,
docsConfiguration: Configuration
- ): TaskProvider<Sync> {
+ ): Pair<TaskProvider<Sync>, TaskProvider<Sync>> {
+ val pairProvider = docsConfiguration.incoming.artifactView {}.files.elements.map {
+ it.map { it.asFile }.toSortedSet().partition { "samples" !in it.toString() }
+ }
return project.tasks.register("unzipJvmSources", Sync::class.java) { task ->
- val sources = docsConfiguration.incoming.artifactView {}.files
-
// Store archiveOperations into a local variable to prevent access to the plugin
// during the task execution, as that breaks configuration caching.
val localVar = archiveOperations
- task.into(destinationDirectory)
+ task.into(sourcesDestinationDirectory)
task.from(
- sources.elements.map { jars ->
- // Now that we publish sample jars, they can get confused with normal source
- // jars. We want to handle sample jars separately, so filter by the name.
- jars.filter { "samples" !in it.toString() }
- .map { it.asFile }.toSortedSet().map { jar ->
- localVar.zipTree(jar).matching { it.exclude("**/META-INF/MANIFEST.MF") }
- }
- }
+ pairProvider.map { it.first }.map { it.map { jar ->
+ localVar.zipTree(jar).matching { it.exclude("**/META-INF/MANIFEST.MF") }
+ } }
)
// Files with the same path in different source jars of the same library will lead to
// some classes/methods not appearing in the docs.
task.duplicatesStrategy = DuplicatesStrategy.WARN
+ } to project.tasks.register("unzipSampleSources", Sync::class.java) { task ->
+ // Store archiveOperations into a local variable to prevent access to the plugin
+ // during the task execution, as that breaks configuration caching.
+ val localVar = archiveOperations
+ task.into(samplesDestinationDirectory)
+ task.from(
+ pairProvider.map { it.second }.map { it.map { jar ->
+ localVar.zipTree(jar).matching { it.exclude("**/META-INF/MANIFEST.MF") }
+ } }
+ )
+ // We expect this to happen when multiple libraries use the same sample, e.g. paging.
+ task.duplicatesStrategy = DuplicatesStrategy.INCLUDE
}
}
@@ -254,6 +273,7 @@
private fun configureMultiplatformInputsTasks(
project: Project,
unzippedMultiplatformSourcesDirectory: Provider<Directory>,
+ unzippedMultiplatformSamplesDirectory: Provider<Directory>,
multiplatformDocsSourcesConfiguration: Configuration,
mergedProjectMetadata: Provider<RegularFile>
): TaskProvider<MergeMultiplatformMetadataTask> {
@@ -270,6 +290,7 @@
)
it.metadataOutput.set(tempMultiplatformMetadataDirectory)
it.sourceOutput.set(unzippedMultiplatformSourcesDirectory)
+ it.samplesOutput.set(unzippedMultiplatformSamplesDirectory)
}
// merge all the metadata files from the individual project dirs
return project.tasks.register(
@@ -457,8 +478,11 @@
unzippedMultiplatformSourcesDirectory: Provider<Directory>,
unzipJvmSourcesTask: TaskProvider<Sync>,
configureMultiplatformSourcesTask: TaskProvider<MergeMultiplatformMetadataTask>,
- unzippedSamplesSources: Provider<Directory>,
- unzipSamplesTask: TaskProvider<Sync>,
+ unzippedDeprecatedSamplesSources: Provider<Directory>,
+ unzipDeprecatedSamplesTask: TaskProvider<Sync>,
+ unzippedJvmSamplesSources: Provider<Directory>,
+ unzipJvmSamplesTask: TaskProvider<Sync>,
+ unzippedKmpSamplesSources: Provider<Directory>,
dependencyClasspath: FileCollection,
buildOnServer: TaskProvider<*>,
docsConfiguration: Configuration,
@@ -506,7 +530,8 @@
// Use samplesDir.set(unzipSamplesTask.flatMap { it.destinationDirectory })
// https://github.com/gradle/gradle/issues/25824
dependsOn(unzipJvmSourcesTask)
- dependsOn(unzipSamplesTask)
+ dependsOn(unzipJvmSamplesTask)
+ dependsOn(unzipDeprecatedSamplesTask)
dependsOn(configureMultiplatformSourcesTask)
description =
@@ -519,7 +544,9 @@
frameworkSamplesDir.set(
project.rootProject.layout.projectDirectory.dir("samples")
)
- samplesDir.set(unzippedSamplesSources)
+ samplesDeprecatedDir.set(unzippedDeprecatedSamplesSources)
+ samplesJvmDir.set(unzippedJvmSamplesSources)
+ samplesKmpDir.set(unzippedKmpSamplesSources)
jvmSourcesDir.set(unzippedJvmSourcesDirectory)
multiplatformSourcesDir.set(unzippedMultiplatformSourcesDirectory)
projectListsDirectory.set(
@@ -551,6 +578,18 @@
)
task.doFirst { taskStartTime = LocalDateTime.now() }
task.doLast {
+ val cpus = try {
+ ProcessBuilder("lscpu").start()
+ .apply { waitFor(100L, TimeUnit.MILLISECONDS) }
+ .inputStream.bufferedReader().readLines()
+ .filter { it.startsWith("CPU(s):") }.singleOrNull()
+ ?.split(" ")?.last()?.toInt()
+ } catch (e: java.io.IOException) { null } // not running on linux
+ if (cpus != 64) { // Keep stddev of build metrics low b/334867245
+ println("$cpus cpus, so not storing build metrics.")
+ return@doLast
+ }
+ println("$cpus cpus, so storing build metrics.")
val taskEndTime = LocalDateTime.now()
val duration = Duration.between(taskStartTime, taskEndTime).toMillis()
metricsFile
@@ -759,24 +798,33 @@
@get:OutputDirectory abstract val metadataOutput: DirectoryProperty
@get:OutputDirectory abstract val sourceOutput: DirectoryProperty
+ @get:OutputDirectory abstract val samplesOutput: DirectoryProperty
@get:Inject abstract val fileSystemOperations: FileSystemOperations
@get:Inject abstract val archiveOperations: ArchiveOperations
@TaskAction
fun execute() {
- val sources = inputJars.get()
+ val (sources, samples) = inputJars.get()
+ .associate { it.name to archiveOperations.zipTree(it) }.toSortedMap()
// Now that we publish sample jars, they can get confused with normal source
// jars. We want to handle sample jars separately, so filter by the name.
- .filter { "samples" !in it.toString() }
- .associate { it.name to archiveOperations.zipTree(it) }
- .toSortedMap()
+ .partition { name -> "samples" !in name }
fileSystemOperations.sync {
it.duplicatesStrategy = DuplicatesStrategy.FAIL
it.from(sources.values)
it.into(sourceOutput)
it.exclude("META-INF/*")
}
+ fileSystemOperations.sync {
+ // Some libraries share samples, e.g. paging. This can be an issue if and only if the
+ // consumer libraries have pinned samples version or are not in an atomic group.
+ // We don't have anything matching this case now, but should enforce better. b/334825580
+ it.duplicatesStrategy = DuplicatesStrategy.INCLUDE
+ it.from(samples.values)
+ it.into(samplesOutput)
+ it.exclude("META-INF/*")
+ }
sources.forEach { (name, fileTree) ->
fileSystemOperations.sync {
it.from(fileTree)
@@ -786,6 +834,8 @@
}
}
}
+private fun <K, V> Map<K, V>.partition(condition: (K) -> Boolean): Pair<Map<K, V>, Map<K, V>> =
+ this.toList().partition { (k, _) -> condition(k) }.let { it.first.toMap() to it.second.toMap() }
/** Merges multiplatform metadata files created by [CreateMultiplatformMetadata] */
@CacheableTask
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/docs/CheckTipOfTreeDocsTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/docs/CheckTipOfTreeDocsTask.kt
index 46685ce..1d52976 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/docs/CheckTipOfTreeDocsTask.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/docs/CheckTipOfTreeDocsTask.kt
@@ -138,7 +138,6 @@
* unless opted-out with [AndroidXExtension.doNotDocumentReason]
*/
fun AndroidXExtension.requiresDocs() =
- (shouldConfigureApiTasks() || type == LibraryType.SAMPLES) &&
- doNotDocumentReason == null
+ shouldConfigureApiTasks() && doNotDocumentReason == null
}
}
diff --git a/buildSrc/public/src/main/kotlin/androidx/build/AndroidXConfig.kt b/buildSrc/public/src/main/kotlin/androidx/build/AndroidXConfig.kt
index 32459f5..4556a22 100644
--- a/buildSrc/public/src/main/kotlin/androidx/build/AndroidXConfig.kt
+++ b/buildSrc/public/src/main/kotlin/androidx/build/AndroidXConfig.kt
@@ -26,7 +26,7 @@
abstract class AndroidConfigImpl(private val project: Project) : AndroidConfig {
override val buildToolsVersion: String = "35.0.0-rc1"
- override val compileSdk: String by lazy { project.findProperty(COMPILE_SDK_VERSION).toString() }
+ override val compileSdk: Int by lazy { project.findProperty(COMPILE_SDK).toString().toInt() }
override val minSdk: Int = 19
override val ndkVersion: String = "25.2.9519653"
@@ -36,7 +36,7 @@
}
companion object {
- private const val COMPILE_SDK_VERSION = "androidx.compileSdkVersion"
+ private const val COMPILE_SDK = "androidx.compileSdk"
private const val TARGET_SDK_VERSION = "androidx.targetSdkVersion"
/**
@@ -45,7 +45,7 @@
*/
val GRADLE_PROPERTIES =
listOf(
- COMPILE_SDK_VERSION,
+ COMPILE_SDK,
TARGET_SDK_VERSION,
)
}
@@ -53,7 +53,7 @@
/**
* Configuration values for various aspects of the AndroidX plugin, including default values for
- * [com.android.build.gradle.BaseExtension].
+ * [com.android.build.api.dsl.CommonExtension].
*/
interface AndroidConfig {
/** Build tools version used for AndroidX projects. */
@@ -62,9 +62,9 @@
/**
* Default compile SDK version used for AndroidX projects.
*
- * This may be specified in `gradle.properties` using `androidx.compileSdkVersion`.
+ * This may be specified in `gradle.properties` using `androidx.compileSdk`.
*/
- val compileSdk: String
+ val compileSdk: Int
/** Default minimum SDK version used for AndroidX projects. */
val minSdk: Int
@@ -100,7 +100,7 @@
/** @return the project's Android SDK stub JAR as a File. */
fun Project.getAndroidJar(): FileCollection {
- val compileSdk = project.defaultAndroidConfig.compileSdk
+ val compileSdk = "android-${project.defaultAndroidConfig.compileSdk}"
return files(
arrayOf(
File(getSdkPath(), "platforms/$compileSdk/android.jar"),
diff --git a/buildSrc/public/src/main/kotlin/androidx/build/SdkHelper.kt b/buildSrc/public/src/main/kotlin/androidx/build/SdkHelper.kt
index 447a6f1..393b5db 100644
--- a/buildSrc/public/src/main/kotlin/androidx/build/SdkHelper.kt
+++ b/buildSrc/public/src/main/kotlin/androidx/build/SdkHelper.kt
@@ -43,7 +43,7 @@
/** Returns a file tree representing the platform SDK suitable for use as a dependency. */
fun Project.getSdkDependency(): FileTree =
- fileTree("${getSdkPath()}/platforms/${project.defaultAndroidConfig.compileSdk}/") {
+ fileTree("${getSdkPath()}/platforms/android-${project.defaultAndroidConfig.compileSdk}/") {
it.include("android.jar")
}
diff --git a/buildSrc/public/src/main/kotlin/androidx/build/SdkResourceGenerator.kt b/buildSrc/public/src/main/kotlin/androidx/build/SdkResourceGenerator.kt
index 0621449..210112c 100644
--- a/buildSrc/public/src/main/kotlin/androidx/build/SdkResourceGenerator.kt
+++ b/buildSrc/public/src/main/kotlin/androidx/build/SdkResourceGenerator.kt
@@ -46,7 +46,7 @@
@get:[InputFile PathSensitive(PathSensitivity.NONE)]
abstract val debugKeystore: RegularFileProperty
- @get:Input abstract val compileSdkVersion: Property<String>
+ @get:Input abstract val compileSdk: Property<Int>
@get:Input abstract val buildToolsVersion: Property<String>
@@ -101,7 +101,7 @@
writer.write("agpDependency=$agpDependency\n")
writer.write("navigationRuntime=$navigationRuntime\n")
writer.write("kotlinStdlib=${kotlinStdlib.get()}\n")
- writer.write("compileSdkVersion=${compileSdkVersion.get()}\n")
+ writer.write("compileSdk=${compileSdk.get()}\n")
writer.write("buildToolsVersion=${buildToolsVersion.get()}\n")
writer.write("minSdkVersion=${minSdkVersion.get()}\n")
writer.write("kgpVersion=${kgpVersion.get()}\n")
@@ -135,7 +135,7 @@
project.provider { project.defaultAndroidConfig.buildToolsVersion }
)
it.minSdkVersion.set(project.defaultAndroidConfig.minSdk)
- it.compileSdkVersion.set(project.defaultAndroidConfig.compileSdk)
+ it.compileSdk.set(project.defaultAndroidConfig.compileSdk)
it.kotlinStdlib.set(
project.androidXConfiguration.kotlinBomVersion.map { version ->
"org.jetbrains.kotlin:kotlin-stdlib:$version"
diff --git a/busytown/androidx_incremental.sh b/busytown/androidx_incremental.sh
index fa615c8..810d4e4 100755
--- a/busytown/androidx_incremental.sh
+++ b/busytown/androidx_incremental.sh
@@ -10,7 +10,7 @@
if [ "$DIST_DIR" == "" ]; then
DIST_DIR="$OUT_DIR/dist"
fi
-if [ "$MANIFEST" == "" ]; then
+if [ "$MANIFEST" == "" -a "$CHANGE_INFO" != "" ]; then
export MANIFEST="$DIST_DIR/manifest_${BUILD_NUMBER}.xml"
fi
# move OUT_DIR and DIST_DIR into subdirectories so that if anything deletes them, it doesn't interfere with any files generated by buildbot code
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/ApiCompat.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/ApiCompat.kt
new file mode 100644
index 0000000..8278f79
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/ApiCompat.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2024 The Android Open 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.camera2.pipe.integration.compat
+
+import android.hardware.camera2.CameraCaptureSession
+import android.hardware.camera2.CaptureRequest
+import android.os.Build
+import android.view.Surface
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresApi
+
+@RequiresApi(Build.VERSION_CODES.N)
+internal object Api24Compat {
+ @DoNotInline
+ @JvmStatic
+ fun onCaptureBufferLost(
+ callback: CameraCaptureSession.CaptureCallback,
+ session: CameraCaptureSession,
+ request: CaptureRequest,
+ surface: Surface,
+ frameNumber: Long
+ ) {
+ callback.onCaptureBufferLost(
+ session, request, surface, frameNumber
+ )
+ }
+}
+
+@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+internal object Api34Compat {
+ @DoNotInline
+ @JvmStatic
+ fun onReadoutStarted(
+ callback: CameraCaptureSession.CaptureCallback,
+ session: CameraCaptureSession,
+ request: CaptureRequest,
+ timestamp: Long,
+ frameNumber: Long
+ ) {
+ callback.onReadoutStarted(
+ session, request, timestamp, frameNumber
+ )
+ }
+}
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/CameraCallbackMap.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/CameraCallbackMap.kt
index 10ac90e..534e582 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/CameraCallbackMap.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/CameraCallbackMap.kt
@@ -23,7 +23,6 @@
import android.hardware.camera2.TotalCaptureResult
import android.os.Build
import android.view.Surface
-import androidx.annotation.DoNotInline
import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.CameraTimestamp
import androidx.camera.camera2.pipe.FrameInfo
@@ -32,9 +31,12 @@
import androidx.camera.camera2.pipe.Request
import androidx.camera.camera2.pipe.RequestFailure
import androidx.camera.camera2.pipe.RequestMetadata
+import androidx.camera.camera2.pipe.SensorTimestamp
import androidx.camera.camera2.pipe.StreamId
import androidx.camera.camera2.pipe.integration.adapter.CameraUseCaseAdapter
import androidx.camera.camera2.pipe.integration.adapter.CaptureResultAdapter
+import androidx.camera.camera2.pipe.integration.compat.Api24Compat
+import androidx.camera.camera2.pipe.integration.compat.Api34Compat
import androidx.camera.camera2.pipe.integration.config.CameraScope
import androidx.camera.core.impl.CameraCaptureCallback
import androidx.camera.core.impl.CameraCaptureFailure
@@ -85,7 +87,7 @@
val surface: Surface? = requestMetadata.streams[stream]
if (session != null && request != null && surface != null) {
executor.execute {
- Api24CompatImpl.onCaptureBufferLost(
+ Api24Compat.onCaptureBufferLost(
callback.captureCallback, session, request, surface, frameNumber.value
)
}
@@ -253,20 +255,31 @@
}
}
- @RequiresApi(24)
- private object Api24CompatImpl {
- @DoNotInline
- @JvmStatic
- fun onCaptureBufferLost(
- callback: CameraCaptureSession.CaptureCallback,
- session: CameraCaptureSession,
- request: CaptureRequest,
- surface: Surface,
- frameNumber: Long
- ) {
- callback.onCaptureBufferLost(
- session, request, surface, frameNumber
- )
+ override fun onReadoutStarted(
+ requestMetadata: RequestMetadata,
+ frameNumber: FrameNumber,
+ timestamp: SensorTimestamp
+ ) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
+ return
+ }
+ for ((callback, executor) in callbacks) {
+ if (callback is CameraUseCaseAdapter.CaptureCallbackContainer) {
+ val session: CameraCaptureSession? =
+ requestMetadata.unwrapAs(CameraCaptureSession::class)
+ val request: CaptureRequest? = requestMetadata.unwrapAs(CaptureRequest::class)
+ if (session != null && request != null) {
+ executor.execute {
+ Api34Compat.onReadoutStarted(
+ callback.captureCallback,
+ session,
+ request,
+ timestamp.value,
+ frameNumber.value
+ )
+ }
+ }
+ }
}
}
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/Requests.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/Requests.kt
index 6e00d10..502465c 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/Requests.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/Requests.kt
@@ -164,6 +164,23 @@
}
/**
+ * onReadoutStarted occurs when the camera device has started reading out the output image
+ * for the request, at the beginning of the sensor image readout. Concretely, it is invoked
+ * right after onCaptureStarted.
+ *
+ * @param requestMetadata the data about the camera2 request that was sent to the camera.
+ * @param frameNumber the android frame number for this capture.
+ * @param timestamp the android timestamp in nanos at the start of camera data readout.
+ * @see android.hardware.camera2.CameraCaptureSession.CaptureCallback.onReadoutStarted
+ */
+ fun onReadoutStarted(
+ requestMetadata: RequestMetadata,
+ frameNumber: FrameNumber,
+ timestamp: SensorTimestamp
+ ) {
+ }
+
+ /**
* onBufferLost occurs when a CaptureRequest failed to create an image for a given output
* stream. This method may be invoked multiple times per frame if multiple buffers were
* lost. This method may not be invoked when an image is lost in some situations.
@@ -362,6 +379,14 @@
@JvmInline
value class CameraTimestamp(val value: Long)
+/**
+ * This is a timestamp happen at start of readout for a regular request, or the timestamp at the
+ * input image's start of readout for a reprocess request, in nanoseconds.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@JvmInline
+value class SensorTimestamp(val value: Long)
+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun <T> Request.getOrDefault(key: Metadata.Key<T>, default: T): T = this[key] ?: default
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequence.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequence.kt
index 5fd7fcc..a6a1629 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequence.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequence.kt
@@ -33,6 +33,7 @@
import androidx.camera.camera2.pipe.RequestFailure
import androidx.camera.camera2.pipe.RequestMetadata
import androidx.camera.camera2.pipe.RequestNumber
+import androidx.camera.camera2.pipe.SensorTimestamp
import androidx.camera.camera2.pipe.StreamId
import kotlinx.coroutines.CompletableDeferred
@@ -127,6 +128,23 @@
invokeOnRequest(request) { it.onPartialCaptureResult(request, frameNumber, frameMetadata) }
}
+ override fun onReadoutStarted(
+ session: CameraCaptureSession,
+ captureRequest: CaptureRequest,
+ captureTimestamp: Long,
+ captureFrameNumber: Long
+ ) {
+ val requestNumber = readRequestNumber(captureRequest)
+ val readoutTimestamp = SensorTimestamp(captureTimestamp)
+ val frameNumber = FrameNumber(captureFrameNumber)
+
+ // Load the request and throw if we are not able to find an associated request. Under
+ // normal circumstances this should never happen.
+ val request = readRequestMetadata(requestNumber)
+
+ invokeOnRequest(request) { it.onReadoutStarted(request, frameNumber, readoutTimestamp) }
+ }
+
override fun onCaptureCompleted(
captureSession: CameraCaptureSession,
captureRequest: CaptureRequest,
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequenceTest.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequenceTest.kt
index b408819..e40b8d4 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequenceTest.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequenceTest.kt
@@ -32,6 +32,7 @@
import androidx.camera.camera2.pipe.RequestFailure
import androidx.camera.camera2.pipe.RequestMetadata
import androidx.camera.camera2.pipe.RequestNumber
+import androidx.camera.camera2.pipe.SensorTimestamp
import androidx.camera.camera2.pipe.StreamId
import androidx.camera.camera2.pipe.testing.FakeRequestMetadata
import androidx.camera.camera2.pipe.testing.RobolectricCameraPipeTestRunner
@@ -88,6 +89,16 @@
}
@Test
+ fun onReadoutStartedTest() {
+ val timestamp: Long = 123456789
+ camera2CaptureSequence.onReadoutStarted(
+ captureSession, captureRequest, timestamp, frameNumber
+ )
+ assertThat(listener.lastFrameNumber?.value).isEqualTo(frameNumber)
+ assertThat(listener.lastSensorTimeStamp?.value).isEqualTo(timestamp)
+ }
+
+ @Test
fun onCaptureCompletedTest() {
val totalCaptureResult: TotalCaptureResult = mock()
whenever(totalCaptureResult.frameNumber).thenReturn(frameNumber)
@@ -119,6 +130,7 @@
var lastTimeStamp: CameraTimestamp? = null
var lastFrameInfo: FrameInfo? = null
var lastRequestFailure: RequestFailure? = null
+ var lastSensorTimeStamp: SensorTimestamp? = null
override fun onStarted(
requestMetadata: RequestMetadata,
@@ -146,5 +158,14 @@
lastFrameNumber = frameNumber
lastRequestFailure = requestFailure
}
+
+ override fun onReadoutStarted(
+ requestMetadata: RequestMetadata,
+ frameNumber: FrameNumber,
+ timestamp: SensorTimestamp
+ ) {
+ lastFrameNumber = frameNumber
+ lastSensorTimeStamp = timestamp
+ }
}
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraValidator.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraValidator.java
index 43242b4..5a33d24 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraValidator.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraValidator.java
@@ -113,9 +113,9 @@
try {
// Verifies the EXTERNAL camera.
EXTERNAL_LENS_FACING.select(cameraRepository.getCameras());
+ Logger.d(TAG, "Found a LENS_FACING_EXTERNAL camera");
availableCameraCount++;
} catch (IllegalArgumentException e) {
- Logger.d(TAG, "No camera with LENS_FACING_EXTERNAL characteristic detected", e);
}
if (exception != null) {
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 c77e1e9..315107f 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
@@ -42,6 +42,7 @@
import androidx.camera.testing.impl.ExifUtil
import androidx.camera.testing.impl.SurfaceTextureProvider
import androidx.camera.testing.impl.SurfaceTextureProvider.SurfaceTextureCallback
+import androidx.camera.testing.impl.WakelockEmptyActivityRule
import androidx.camera.testing.impl.fakes.FakeLifecycleOwner
import androidx.test.core.app.ApplicationProvider
import androidx.test.filters.LargeTest
@@ -59,7 +60,6 @@
import org.junit.Assert.assertTrue
import org.junit.Assume.assumeTrue
import org.junit.Before
-import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
@@ -91,6 +91,9 @@
)
@get:Rule
+ var wakelockEmptyActivityRule = WakelockEmptyActivityRule()
+
+ @get:Rule
val temporaryFolder = TemporaryFolder(context.cacheDir)
private lateinit var cameraProvider: ProcessCameraProvider
@@ -158,7 +161,6 @@
}
@Test
- @Ignore("b/331617278")
fun canBindToLifeCycleAndTakePicture(): Unit = runBlocking {
val mockOnImageCapturedCallback = Mockito.mock(
ImageCapture.OnImageCapturedCallback::class.java
@@ -302,7 +304,6 @@
}
@Test
- @Ignore("b/331617278")
fun canBindToLifeCycleAndTakePicture_diskIo(): Unit = runBlocking {
val mockOnImageSavedCallback = Mockito.mock(
ImageCapture.OnImageSavedCallback::class.java
@@ -488,7 +489,6 @@
}
@Test
- @Ignore("b/331617278")
fun canBindToLifeCycleAndTakePictureWithCaptureProcessProgress(): Unit = runBlocking {
assumeTrue(isCaptureProcessProgressSupported())
@@ -525,7 +525,6 @@
}
@Test
- @Ignore("b/331617278")
fun canBindToLifeCycleAndTakePictureWithCaptureProcessProgress_diskIo(): Unit = runBlocking {
assumeTrue(isCaptureProcessProgressSupported())
@@ -564,7 +563,6 @@
ExifRotationAvailability().isRotationOptionSupported
@Test
- @Ignore("b/331617278")
fun canBindToLifeCycleAndTakePictureWithPostview(): Unit = runBlocking {
assumeTrue(isPostviewSupported())
@@ -618,7 +616,6 @@
}
@Test
- @Ignore("b/331617278")
fun canBindToLifeCycleAndTakePictureWithPostview_diskIo(): Unit = runBlocking {
assumeTrue(isPostviewSupported())
@@ -665,7 +662,6 @@
}
@Test
- @Ignore("b/331617278")
fun highResolutionDisabled_whenExtensionsEnabled(): Unit = runBlocking {
val imageCapture = ImageCapture.Builder().build()
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/AdvancedSessionProcessorTest.kt b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/AdvancedSessionProcessorTest.kt
index 4cfc33f..3114f4b 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/AdvancedSessionProcessorTest.kt
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/AdvancedSessionProcessorTest.kt
@@ -90,7 +90,6 @@
import org.junit.Assume.assumeFalse
import org.junit.Assume.assumeTrue
import org.junit.Before
-import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -171,7 +170,6 @@
}
@Test
- @Ignore("b/331617278")
fun useCasesCanWork_directlyUseOutputSurface() = runBlocking {
val fakeSessionProcessImpl = FakeSessionProcessImpl(
// Directly use output surface
@@ -201,7 +199,6 @@
}
@Test
- @Ignore("b/331617278")
fun canInvokeStartTrigger() = runBlocking {
assumeTrue(ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_3))
val fakeSessionProcessImpl = FakeSessionProcessImpl()
@@ -227,7 +224,6 @@
}
@Test
- @Ignore("b/331617278")
fun getRealtimeLatencyEstimate_advancedSessionProcessorInvokesSessionProcessorImpl() =
runBlocking {
assumeTrue(ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
@@ -248,7 +244,6 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
@Test
- @Ignore("b/331617278")
fun isCurrentExtensionTypeAvailableReturnsCorrectFalseValue() =
runBlocking {
assumeTrue(ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
@@ -266,7 +261,6 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
@Suppress("UNCHECKED_CAST")
@Test
- @Ignore("b/331617278")
fun isCurrentExtensionTypeAvailableReturnsCorrectTrueValue() =
runBlocking {
assumeTrue(ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
@@ -289,7 +283,6 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
@Test
- @Ignore("b/331617278")
fun isExtensionStrengthAvailableReturnsCorrectFalseValue() =
runBlocking {
assumeTrue(ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
@@ -307,7 +300,6 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
@Suppress("UNCHECKED_CAST")
@Test
- @Ignore("b/331617278")
fun isExtensionStrengthAvailableReturnsCorrectTrueValue() =
runBlocking {
assumeTrue(ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
@@ -372,7 +364,6 @@
@Test
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
- @Ignore("b/331617278")
fun getCurrentExtensionType_advancedSessionProcessorMonitorSessionProcessorImplResults(): Unit =
runBlocking {
assumeTrue(ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
@@ -429,7 +420,6 @@
@Test
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
- @Ignore("b/331617278")
fun setExtensionStrength_advancedSessionProcessorInvokesSessionProcessorImpl() =
runBlocking {
assumeTrue(ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
@@ -511,7 +501,6 @@
// Surface sharing of YUV format is supported after API 28.
@SdkSuppress(minSdkVersion = 28)
@Test
- @Ignore("b/331617278")
fun useCasesCanWork_hasSharedSurfaceOutput() = runBlocking {
assumeAllowsSharedSurface()
var sharedConfigId = -1
@@ -568,7 +557,6 @@
// Test if physicalCameraId is set and returned in the image received in the image processor.
@SdkSuppress(minSdkVersion = 28) // physical camera id is supported in API28+
@Test
- @Ignore("b/331617278")
fun useCasesCanWork_setPhysicalCameraId() = runBlocking {
assumeAllowsSharedSurface()
val physicalCameraIdList = getPhysicalCameraId(cameraSelector)
@@ -643,7 +631,6 @@
}
@Test
- @Ignore("b/331617278")
fun canSetSessionTypeFromOemImpl() {
assumeTrue(ClientVersion.isMinimumCompatibleVersion(Version.VERSION_1_4) &&
ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
@@ -668,7 +655,6 @@
}
@Test
- @Ignore("b/331617278")
fun defaultSessionType() {
// 1. Arrange.
val fakeSessionProcessImpl = FakeSessionProcessImpl()
@@ -690,7 +676,6 @@
}
@Test
- @Ignore("b/331617278")
fun getSupportedPostviewSizeIsCorrect() {
// 1. Arrange
val postviewSizes = mutableMapOf(
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/sessionprocessor/BasicExtenderSessionProcessorTest.kt b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/sessionprocessor/BasicExtenderSessionProcessorTest.kt
index 301af04..ee5937f 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/sessionprocessor/BasicExtenderSessionProcessorTest.kt
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/sessionprocessor/BasicExtenderSessionProcessorTest.kt
@@ -101,7 +101,6 @@
import org.junit.Assume.assumeFalse
import org.junit.Assume.assumeTrue
import org.junit.Before
-import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -206,7 +205,6 @@
}
@Test
- @Ignore("b/331617278")
fun canOutputCorrectly(): Unit = runBlocking {
val preview = Preview.Builder().build()
val imageCapture = ImageCapture.Builder().build()
@@ -228,7 +226,6 @@
}
@Test
- @Ignore("b/331617278")
fun canSetSessionTypeFromOem() {
assumeTrue(ClientVersion.isMinimumCompatibleVersion(Version.VERSION_1_4) &&
ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
@@ -249,7 +246,6 @@
}
@Test
- @Ignore("b/331617278")
fun setDifferentSessionTypes_throwException() {
assumeTrue(ClientVersion.isMinimumCompatibleVersion(Version.VERSION_1_4) &&
ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
@@ -269,7 +265,6 @@
}
@Test
- @Ignore("b/331617278")
fun defaultSessionType() {
assumeTrue(ClientVersion.isMinimumCompatibleVersion(Version.VERSION_1_4) &&
ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
@@ -289,7 +284,6 @@
}
@Test
- @Ignore("b/331617278")
fun imageCaptureError(): Unit = runBlocking {
assumeTrue(hasCaptureProcessor)
fakeCaptureExtenderImpl = FakeImageCaptureExtenderImpl(
@@ -309,7 +303,6 @@
}
@Test
- @Ignore("b/331617278")
fun canOutputCorrectly_withoutAnalysis(): Unit = runBlocking {
val preview = Preview.Builder().build()
val imageCapture = ImageCapture.Builder().build()
@@ -329,7 +322,6 @@
}
@Test
- @Ignore("b/331617278")
fun canOutputCorrectly_setTargetRotation(): Unit = runBlocking {
assumeTrue(hasCaptureProcessor)
val preview = Preview.Builder().build()
@@ -346,7 +338,6 @@
}
@Test
- @Ignore("b/331617278")
fun canOutputCorrectlyAfterStopStart(): Unit = runBlocking {
val preview = Preview.Builder().build()
val imageCapture = ImageCapture.Builder().build()
@@ -378,7 +369,6 @@
verifyStillCapture(imageCapture)
}
- @Ignore("b/331617278")
@Test
fun canInvokeEventsInOrder(): Unit = runBlocking {
val preview = Preview.Builder().build()
@@ -431,7 +421,6 @@
}
@Test
- @Ignore("b/331617278")
fun getRealtimeCaptureLatencyEstimate_invokesCaptureExtenderImpl(): Unit = runBlocking {
assumeTrue(hasCaptureProcessor)
assumeTrue(ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
@@ -473,7 +462,6 @@
}
@Test
- @Ignore("b/331617278")
fun repeatingRequest_containsPreviewCaptureStagesParameters(): Unit = runBlocking {
val previewBuilder = Preview.Builder()
val resultMonitor = ResultMonitor()
@@ -516,7 +504,6 @@
}
@Test
- @Ignore("b/331617278")
fun processorRequestUpdateOnly_canUpdateRepeating(): Unit = runBlocking {
assumeTrue(previewProcessorType == PROCESSOR_TYPE_REQUEST_UPDATE_ONLY)
val previewBuilder = Preview.Builder()
@@ -562,7 +549,6 @@
}
@Test
- @Ignore("b/331617278")
fun imageCapture_captureRequestParametersAreCorrect(): Unit = runBlocking {
initBasicExtenderSessionProcessor().use {
fakeCaptureExtenderImpl.captureStages = listOf(
@@ -616,7 +602,6 @@
}
@Test
- @Ignore("b/331617278")
fun onEnableDisableRequestsAreSent(): Unit = runBlocking {
initBasicExtenderSessionProcessor().use {
// Verify onEnableSession
@@ -672,7 +657,6 @@
}
@Test
- @Ignore("b/331617278")
fun getSupportedPostviewSizeIsCorrect() {
assumeTrue(ClientVersion.isMinimumCompatibleVersion(Version.VERSION_1_4) &&
ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/sessionprocessor/PreviewProcessor.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/sessionprocessor/PreviewProcessor.java
index 337a01e..ab4a264 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/sessionprocessor/PreviewProcessor.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/sessionprocessor/PreviewProcessor.java
@@ -96,29 +96,33 @@
Logger.d(TAG, "Ignore image in closed or paused state");
return;
}
- if (ClientVersion.isMinimumCompatibleVersion(Version.VERSION_1_3)
- && ExtensionVersion
- .isMinimumCompatibleVersion(Version.VERSION_1_3)) {
- mPreviewImageProcessor.process(imageReference.get(), totalCaptureResult,
- new ProcessResultImpl() {
- @Override
- public void onCaptureCompleted(long shutterTimestamp,
- @NonNull List<Pair<CaptureResult.Key, Object>>
- result) {
- onResultCallback.onCaptureResult(shutterTimestamp,
- result);
- }
+ try {
+ if (ClientVersion.isMinimumCompatibleVersion(Version.VERSION_1_3)
+ && ExtensionVersion
+ .isMinimumCompatibleVersion(Version.VERSION_1_3)) {
+ mPreviewImageProcessor.process(imageReference.get(),
+ totalCaptureResult,
+ new ProcessResultImpl() {
+ @Override
+ public void onCaptureCompleted(long shutterTimestamp,
+ @NonNull List<Pair<CaptureResult.Key, Object>>
+ result) {
+ onResultCallback.onCaptureResult(shutterTimestamp,
+ result);
+ }
- @Override
- public void onCaptureProcessProgressed(int progress) {
+ @Override
+ public void onCaptureProcessProgressed(int progress) {
- }
- }, CameraXExecutors.ioExecutor());
- } else {
- mPreviewImageProcessor.process(imageReference.get(),
- totalCaptureResult);
+ }
+ }, CameraXExecutors.ioExecutor());
+ } else {
+ mPreviewImageProcessor.process(imageReference.get(),
+ totalCaptureResult);
+ }
+ } finally {
+ imageReference.decrement();
}
- imageReference.decrement();
}
});
}
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/GLImage2SurfaceRenderer.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/GLImage2SurfaceRenderer.java
index f35a47c..4a98977 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/GLImage2SurfaceRenderer.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/GLImage2SurfaceRenderer.java
@@ -79,6 +79,7 @@
private EGLContext mEGLContext;
private EGLSurface mEGLPbufferSurface;
private EGLSurface mWindowSurface;
+ private int mTextureId;
private int mProgram;
private int mPositionHandle;
@@ -187,7 +188,7 @@
int[] textureIds = new int[1];
GLES20.glGenTextures(1, textureIds, 0);
-
+ mTextureId = textureIds[0];
GLES20.glUniform1i(mTextureYHandle, 0);
initVertexBuffer();
@@ -242,6 +243,15 @@
GLES20.glEnableVertexAttribArray(mPositionHandle);
}
+ public static ByteBuffer clone(ByteBuffer original) {
+ ByteBuffer clone = ByteBuffer.allocate(original.capacity());
+ original.rewind();
+ clone.put(original);
+ original.rewind();
+ clone.flip();
+ return clone;
+ }
+
void renderTexture(Image image) {
GLES20.glUseProgram(mProgram);
GLES20.glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
@@ -249,10 +259,13 @@
// Bind Y texture
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureId);
+
+ // ByteBuffer needs to be cloned otherwise it might cause failure in emulator.
+ ByteBuffer clonedBuffer = clone(image.getPlanes()[0].getBuffer());
GLES20.glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, mInputSize.getWidth(),
mInputSize.getHeight(), 0, GL_LUMINANCE, GL_UNSIGNED_BYTE,
- image.getPlanes()[0].getBuffer());
+ clonedBuffer);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java b/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java
index 34e5bb3..56bba47 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java
@@ -1356,10 +1356,10 @@
// Get corresponded resolutions for the target aspect ratio.
int aspectRatio = videoSpec.getAspectRatio();
- Map<Quality, Size> sizeMap = getQualityToResolutionMap(videoCapabilities,
+ Map<Quality, Size> supportedQualityToSizeMap = getQualityToResolutionMap(videoCapabilities,
requestedDynamicRange);
QualityRatioToResolutionsTable qualityRatioTable = new QualityRatioToResolutionsTable(
- cameraInfo.getSupportedResolutions(getImageFormat()), sizeMap);
+ cameraInfo.getSupportedResolutions(getImageFormat()), supportedQualityToSizeMap);
List<Size> customOrderedResolutions = new ArrayList<>();
for (Quality selectedQuality : selectedQualities) {
customOrderedResolutions.addAll(
@@ -1367,7 +1367,8 @@
}
List<Size> filteredCustomOrderedResolutions = filterOutEncoderUnsupportedResolutions(
(VideoCaptureConfig<T>) builder.getUseCaseConfig(), mediaSpec,
- requestedDynamicRange, videoCapabilities, customOrderedResolutions);
+ requestedDynamicRange, videoCapabilities, customOrderedResolutions,
+ supportedQualityToSizeMap);
Logger.d(TAG, "Set custom ordered resolutions = " + filteredCustomOrderedResolutions);
builder.getMutableConfig().insertOption(OPTION_CUSTOM_ORDERED_RESOLUTIONS,
filteredCustomOrderedResolutions);
@@ -1379,7 +1380,8 @@
@NonNull MediaSpec mediaSpec,
@NonNull DynamicRange dynamicRange,
@NonNull VideoCapabilities videoCapabilities,
- @NonNull List<Size> resolutions
+ @NonNull List<Size> resolutions,
+ @NonNull Map<Quality, Size> supportedQualityToSizeMap
) {
if (resolutions.isEmpty()) {
return resolutions;
@@ -1388,6 +1390,11 @@
Iterator<Size> iterator = resolutions.iterator();
while (iterator.hasNext()) {
Size resolution = iterator.next();
+ // To improve performance, there is no need to check for supported qualities'
+ // resolutions because the encoder should support them.
+ if (supportedQualityToSizeMap.containsValue(resolution)) {
+ continue;
+ }
// We must find EncoderProfiles for each resolution because the EncoderProfiles found
// by resolution may contain different video mine type which leads to different codec.
VideoValidatedEncoderProfilesProxy encoderProfiles =
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/RenderInTransitionOverlayNodeElement.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/RenderInTransitionOverlayNodeElement.kt
index 74e4d20..e9118d6 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/RenderInTransitionOverlayNodeElement.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/RenderInTransitionOverlayNodeElement.kt
@@ -66,9 +66,9 @@
override fun equals(other: Any?): Boolean {
if (other is RenderInTransitionOverlayNodeElement) {
return sharedTransitionScope == other.sharedTransitionScope &&
- renderInOverlay == other.renderInOverlay &&
+ renderInOverlay === other.renderInOverlay &&
zIndexInOverlay == other.zIndexInOverlay &&
- clipInOverlay == other.clipInOverlay
+ clipInOverlay === other.clipInOverlay
}
return false
}
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt
index 324e4b7..6d1df04 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt
@@ -261,7 +261,7 @@
pluginContext,
symbolRemapper,
metrics,
- idSignatureBuilder!!,
+ idSignatureBuilder,
stabilityInferencer,
decoysEnabled
).lower(moduleFragment)
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 4be9688..c445253 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
@@ -166,9 +166,16 @@
allowMultipleOccurrences = false
)
val STRONG_SKIPPING_OPTION = CliOption(
+ "strongSkipping",
+ "<true|false>",
+ "Enable strong skipping mode",
+ required = false,
+ allowMultipleOccurrences = false
+ )
+ val EXPERIMENTAL_STRONG_SKIPPING_OPTION = CliOption(
"experimentalStrongSkipping",
"<true|false>",
- "Enable experimental strong skipping mode",
+ "Deprecated - Use strongSkipping instead",
required = false,
allowMultipleOccurrences = false
)
@@ -200,6 +207,7 @@
NON_SKIPPING_GROUP_OPTIMIZATION_ENABLED_OPTION,
SUPPRESS_KOTLIN_VERSION_CHECK_ENABLED_OPTION,
DECOYS_ENABLED_OPTION,
+ EXPERIMENTAL_STRONG_SKIPPING_OPTION,
STRONG_SKIPPING_OPTION,
STABLE_CONFIG_PATH_OPTION,
TRACE_MARKERS_OPTION,
@@ -250,6 +258,18 @@
ComposeConfiguration.DECOYS_ENABLED_KEY,
value == "true"
)
+ EXPERIMENTAL_STRONG_SKIPPING_OPTION -> {
+ val msgCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
+ msgCollector?.report(
+ CompilerMessageSeverity.WARNING,
+ "${EXPERIMENTAL_STRONG_SKIPPING_OPTION.optionName} is deprecated." +
+ " Use ${STRONG_SKIPPING_OPTION.optionName} instead."
+ )
+ configuration.put(
+ ComposeConfiguration.STRONG_SKIPPING_ENABLED_KEY,
+ value == "true"
+ )
+ }
STRONG_SKIPPING_OPTION -> configuration.put(
ComposeConfiguration.STRONG_SKIPPING_ENABLED_KEY,
value == "true"
@@ -473,6 +493,7 @@
)
val useK2 = configuration.languageVersionSettings.languageVersion.usesK2
+
val strongSkippingEnabled = configuration.get(
ComposeConfiguration.STRONG_SKIPPING_ENABLED_KEY,
false
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/WrapJsComposableLambdaLowering.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/WrapJsComposableLambdaLowering.kt
index 27386ba..af87015 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/WrapJsComposableLambdaLowering.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/WrapJsComposableLambdaLowering.kt
@@ -20,7 +20,6 @@
import androidx.compose.compiler.plugins.kotlin.ComposeClassIds
import androidx.compose.compiler.plugins.kotlin.ModuleMetrics
import androidx.compose.compiler.plugins.kotlin.analysis.StabilityInferencer
-import androidx.compose.compiler.plugins.kotlin.lower.decoys.AbstractDecoysLowering
import androidx.compose.compiler.plugins.kotlin.lower.decoys.CreateDecoysTransformer
import androidx.compose.compiler.plugins.kotlin.lower.decoys.isDecoy
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
@@ -85,15 +84,14 @@
context: IrPluginContext,
symbolRemapper: DeepCopySymbolRemapper,
metrics: ModuleMetrics,
- signatureBuilder: IdSignatureSerializer,
+ signatureBuilder: IdSignatureSerializer?,
stabilityInferencer: StabilityInferencer,
private val decoysEnabled: Boolean
-) : AbstractDecoysLowering(
+) : AbstractComposeLowering(
context,
symbolRemapper,
metrics,
stabilityInferencer,
- signatureBuilder
) {
private val rememberFunSymbol by lazy {
val composerParamTransformer = ComposerParamTransformer(
@@ -104,21 +102,25 @@
it.valueParameters.size == 2 && !it.valueParameters.first().isVararg
}.symbol
).owner.let {
- if (!decoysEnabled) {
+ if (!decoysEnabled || signatureBuilder == null) {
composerParamTransformer.visitSimpleFunction(it) as IrSimpleFunction
- } else if (!it.isDecoy()) {
+ } else {
// If a module didn't have any explicit remember calls,
// so `fun remember` wasn't transformed yet, then we have to transform it now.
val createDecoysTransformer = CreateDecoysTransformer(
context, symbolRemapper, signatureBuilder, stabilityInferencer, metrics
)
- createDecoysTransformer.visitSimpleFunction(it) as IrSimpleFunction
- createDecoysTransformer.updateParents()
- composerParamTransformer.visitSimpleFunction(
- it.getComposableForDecoy().owner as IrSimpleFunction
- ) as IrSimpleFunction
- } else {
- it.getComposableForDecoy().owner as IrSimpleFunction
+ with(createDecoysTransformer) {
+ if (!it.isDecoy()) {
+ visitSimpleFunction(it) as IrSimpleFunction
+ updateParents()
+ composerParamTransformer.visitSimpleFunction(
+ it.getComposableForDecoy().owner as IrSimpleFunction
+ ) as IrSimpleFunction
+ } else {
+ it.getComposableForDecoy().owner as IrSimpleFunction
+ }
+ }
}
}.symbol
}
diff --git a/compose/compiler/compiler/integration-tests/src/test/kotlin/androidx/compose/compiler/test/CompilerPluginRuntimeVersionCheckTest.kt b/compose/compiler/compiler/integration-tests/src/test/kotlin/androidx/compose/compiler/test/CompilerPluginRuntimeVersionCheckTest.kt
index 79b0f58..efb35c5 100644
--- a/compose/compiler/compiler/integration-tests/src/test/kotlin/androidx/compose/compiler/test/CompilerPluginRuntimeVersionCheckTest.kt
+++ b/compose/compiler/compiler/integration-tests/src/test/kotlin/androidx/compose/compiler/test/CompilerPluginRuntimeVersionCheckTest.kt
@@ -154,7 +154,7 @@
android {
namespace "androidx.compose.compiler.test"
- compileSdkVersion ${projectSetup.props.compileSdkVersion}
+ compileSdk ${projectSetup.props.compileSdk}
buildToolsVersion "${projectSetup.props.buildToolsVersion}"
defaultConfig {
minSdkVersion 21
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Offset.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Offset.kt
index 4fa34b4..3fc7a65 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Offset.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Offset.kt
@@ -217,7 +217,7 @@
if (this === other) return true
val otherModifier = other as? OffsetPxElement ?: return false
- return offset == otherModifier.offset &&
+ return offset === otherModifier.offset &&
rtlAware == otherModifier.rtlAware
}
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnImpl.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnImpl.kt
index e011e59..7467caf 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnImpl.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnImpl.kt
@@ -559,7 +559,7 @@
override fun equals(other: Any?): Boolean {
if (this === other) return true
val otherModifier = other as? WithAlignmentLineBlockElement ?: return false
- return block == otherModifier.block
+ return block === otherModifier.block
}
override fun hashCode(): Int = block.hashCode()
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/WindowInsetsPadding.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/WindowInsetsPadding.kt
index 2a93e7a..e35dd4b 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/WindowInsetsPadding.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/WindowInsetsPadding.kt
@@ -249,7 +249,7 @@
return false
}
- return other.block == block
+ return other.block === block
}
override fun hashCode(): Int = block.hashCode()
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/WindowInsetsSize.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/WindowInsetsSize.kt
index 9c83dd3..4d2cc98 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/WindowInsetsSize.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/WindowInsetsSize.kt
@@ -161,7 +161,7 @@
if (other !is DerivedWidthModifier) {
return false
}
- return insets == other.insets && widthCalc == other.widthCalc
+ return insets == other.insets && widthCalc === other.widthCalc
}
override fun hashCode(): Int = 31 * insets.hashCode() + widthCalc.hashCode()
@@ -206,7 +206,7 @@
if (other !is DerivedHeightModifier) {
return false
}
- return insets == other.insets && heightCalc == other.heightCalc
+ return insets == other.insets && heightCalc === other.heightCalc
}
override fun hashCode(): Int = 31 * insets.hashCode() + heightCalc.hashCode()
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/LongScreenshotsDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/LongScreenshotsDemos.kt
index 15d9452..f40115d 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/LongScreenshotsDemos.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/LongScreenshotsDemos.kt
@@ -32,6 +32,7 @@
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
@@ -79,6 +80,7 @@
ComposableDemo("TextField in scrollable") { TextFieldInScrollableDemo() },
ComposableDemo("Single giant text field") { SingleGiantTextFieldDemo() },
ComposableDemo("Lazy list with sticky headers") { LazyListWithStickiesDemo() },
+ ComposableDemo("Reverse layout") { ReverseScrollingCaptureDemo() },
)
@Composable
@@ -170,17 +172,15 @@
@Composable
private fun SingleFullScreenListDemo() {
- Column {
- LazyColumn(Modifier.fillMaxSize()) {
- items(50) { index ->
- Button(
- onClick = {},
- Modifier
- .padding(8.dp)
- .fillMaxWidth()
- ) {
- Text("Button $index")
- }
+ LazyColumn(Modifier.fillMaxSize()) {
+ items(50) { index ->
+ Button(
+ onClick = {},
+ Modifier
+ .padding(8.dp)
+ .fillMaxWidth()
+ ) {
+ Text("Button $index")
}
}
}
@@ -188,39 +188,37 @@
@Composable
private fun LazyListContentPaddingDemo() {
- Column {
- Scaffold(
+ Scaffold(
+ modifier = Modifier
+ .padding(8.dp)
+ .border(1.dp, Color.Black),
+ topBar = {
+ TopAppBar(
+ title = { Text("Top bar") },
+ backgroundColor = MaterialTheme.colors.primarySurface.copy(alpha = 0.5f)
+ )
+ },
+ bottomBar = {
+ BottomAppBar(
+ backgroundColor = MaterialTheme.colors.primarySurface.copy(alpha = 0.5f)
+ ) { Text("Bottom bar") }
+ }
+ ) { contentPadding ->
+ LazyColumn(
modifier = Modifier
- .padding(8.dp)
- .border(1.dp, Color.Black),
- topBar = {
- TopAppBar(
- title = { Text("Top bar") },
- backgroundColor = MaterialTheme.colors.primarySurface.copy(alpha = 0.5f)
- )
- },
- bottomBar = {
- BottomAppBar(
- backgroundColor = MaterialTheme.colors.primarySurface.copy(alpha = 0.5f)
- ) { Text("Bottom bar") }
- }
- ) { contentPadding ->
- LazyColumn(
- modifier = Modifier
- .fillMaxSize()
- .background(Color.Red),
- contentPadding = contentPadding
- ) {
- items(15) { index ->
- Button(
- onClick = {},
- Modifier
- .background(Color.LightGray)
- .padding(8.dp)
- .fillMaxWidth()
- ) {
- Text("Button $index")
- }
+ .fillMaxSize()
+ .background(Color.Red),
+ contentPadding = contentPadding
+ ) {
+ items(15) { index ->
+ Button(
+ onClick = {},
+ Modifier
+ .background(Color.LightGray)
+ .padding(8.dp)
+ .fillMaxWidth()
+ ) {
+ Text("Button $index")
}
}
}
@@ -505,3 +503,22 @@
}
}
}
+
+@Composable
+private fun ReverseScrollingCaptureDemo() {
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ modifier = Modifier
+ .fillMaxSize()
+ .verticalScroll(rememberScrollState(), reverseScrolling = true)
+ ) {
+ repeat(50) { index ->
+ Text(
+ "Row $index",
+ Modifier
+ .heightIn(min = 40.dp)
+ .padding(8.dp)
+ )
+ }
+ }
+}
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 90f9d1e..7a75d11 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
@@ -28,6 +28,7 @@
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.PressInteraction
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.requiredWidth
@@ -36,6 +37,8 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.key
+import androidx.compose.runtime.movableContentOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
@@ -69,9 +72,11 @@
import androidx.compose.ui.platform.isDebugInspectorInfoEnabled
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.SemanticsActions
import androidx.compose.ui.semantics.SemanticsProperties
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.SemanticsMatcher
+import androidx.compose.ui.test.SemanticsNodeInteraction
import androidx.compose.ui.test.assert
import androidx.compose.ui.test.assertHasClickAction
import androidx.compose.ui.test.assertHeightIsEqualTo
@@ -3527,6 +3532,44 @@
rule.onNodeWithTag(tag).requestFocus()
rule.onNodeWithTag(tag).assertIsFocused()
}
+
+ // Regression test for b/332814226
+ @Test
+ fun movableContentWithSubcomposition_updatingSemanticsShouldNotCrash() {
+ var moveContent by mutableStateOf(false)
+ rule.setContent {
+ val content = remember {
+ movableContentOf {
+ BoxWithConstraints {
+ BasicText("ClickableText",
+ modifier = Modifier
+ .testTag("clickable")
+ .clickable(
+ role = if (moveContent) Role.Button else Role.Checkbox,
+ onClickLabel = moveContent.toString()
+ ) {}
+ )
+ }
+ }
+ }
+
+ key(moveContent) {
+ content()
+ }
+ }
+
+ rule.onNodeWithTag("clickable")
+ .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Checkbox))
+ .assertOnClickLabelMatches("false")
+
+ rule.runOnIdle {
+ moveContent = true
+ }
+
+ rule.onNodeWithTag("clickable")
+ .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+ .assertOnClickLabelMatches("true")
+ }
}
/**
@@ -3585,3 +3628,10 @@
return onAttach.hashCode()
}
}
+
+internal fun SemanticsNodeInteraction.assertOnClickLabelMatches(expectedValue: String):
+ SemanticsNodeInteraction {
+ return assert(SemanticsMatcher("onClickLabel = '$expectedValue'") {
+ it.config.getOrElseNullable(SemanticsActions.OnClick) { null }?.label == expectedValue
+ })
+ }
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 4b0debf..b67d4b3 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
@@ -26,6 +26,7 @@
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.PressInteraction
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.requiredWidth
@@ -33,6 +34,8 @@
import androidx.compose.foundation.text.BasicText
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.key
+import androidx.compose.runtime.movableContentOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
@@ -59,10 +62,12 @@
import androidx.compose.ui.platform.LocalInputModeManager
import androidx.compose.ui.platform.isDebugInspectorInfoEnabled
import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.SemanticsActions
import androidx.compose.ui.semantics.SemanticsProperties
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.SemanticsMatcher
+import androidx.compose.ui.test.SemanticsNodeInteraction
import androidx.compose.ui.test.assert
import androidx.compose.ui.test.assertHasClickAction
import androidx.compose.ui.test.assertHeightIsEqualTo
@@ -2429,4 +2434,53 @@
assertThat(pressInteractions.last()).isInstanceOf(PressInteraction.Cancel::class.java)
}
}
+
+ // Regression test for b/332814226
+ @Test
+ fun movableContentWithSubcomposition_updatingSemanticsShouldNotCrash() {
+ var moveContent by mutableStateOf(false)
+ rule.setContent {
+ val content = remember {
+ movableContentOf {
+ BoxWithConstraints {
+ BasicText("ClickableText",
+ modifier = Modifier
+ .testTag("clickable")
+ .combinedClickable(
+ role = if (moveContent) Role.Button else Role.Checkbox,
+ onClickLabel = moveContent.toString(),
+ onLongClick = {},
+ onLongClickLabel = moveContent.toString()
+ ) {}
+ )
+ }
+ }
+ }
+
+ key(moveContent) {
+ content()
+ }
+ }
+
+ rule.onNodeWithTag("clickable")
+ .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Checkbox))
+ .assertOnClickLabelMatches("false")
+ .assertOnLongClickLabelMatches("false")
+
+ rule.runOnIdle {
+ moveContent = true
+ }
+
+ rule.onNodeWithTag("clickable")
+ .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+ .assertOnClickLabelMatches("true")
+ .assertOnLongClickLabelMatches("true")
+ }
+}
+
+private fun SemanticsNodeInteraction.assertOnLongClickLabelMatches(expectedValue: String):
+ SemanticsNodeInteraction {
+ return assert(SemanticsMatcher("onLongClickLabel = '$expectedValue'") {
+ it.config.getOrElseNullable(SemanticsActions.OnLongClick) { null }?.label == expectedValue
+ })
}
diff --git a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text/CoreTextFieldHandwritingTest.kt b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text/CoreTextFieldHandwritingTest.kt
index 2f008d6..3dc1a55 100644
--- a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text/CoreTextFieldHandwritingTest.kt
+++ b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text/CoreTextFieldHandwritingTest.kt
@@ -26,11 +26,14 @@
import androidx.compose.foundation.text.input.internal.inputMethodManagerFactory
import androidx.compose.foundation.text.matchers.isZero
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalWindowInfo
+import androidx.compose.ui.platform.WindowInfo
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.SemanticsNodeInteraction
import androidx.compose.ui.test.junit4.createComposeRule
@@ -201,6 +204,42 @@
performHandwritingAndExpect(stylusHandwritingStarted = true)
}
+ @Test
+ fun coreTextField_toggleWindowFocus_startStylusHandwriting() {
+ inputMethodManagerFactory = { fakeImm }
+
+ val focusWindow = mutableStateOf(true)
+ fun createWindowInfo(focused: Boolean) = object : WindowInfo {
+ override val isWindowFocused: Boolean
+ get() = focused
+ }
+
+ setContent {
+ CompositionLocalProvider(
+ LocalWindowInfo provides createWindowInfo(focusWindow.value)
+ ) {
+ val value = remember { TextFieldValue() }
+ CoreTextField(
+ value = value,
+ onValueChange = { },
+ modifier = Modifier
+ .fillMaxSize()
+ .testTag(Tag),
+ )
+ }
+ }
+
+ performHandwritingAndExpect(stylusHandwritingStarted = true)
+
+ focusWindow.value = false
+ rule.waitForIdle()
+ performHandwritingAndExpect(stylusHandwritingStarted = false)
+
+ focusWindow.value = true
+ rule.waitForIdle()
+ performHandwritingAndExpect(stylusHandwritingStarted = true)
+ }
+
private fun testStylusHandwriting(
stylusHandwritingStarted: Boolean,
interaction: SemanticsNodeInteraction.() -> Unit
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 e3f3e01..ba05692 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
@@ -42,7 +42,9 @@
import androidx.compose.ui.graphics.toComposeIntRect
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
+import androidx.compose.ui.platform.LocalWindowInfo
import androidx.compose.ui.platform.SoftwareKeyboardController
+import androidx.compose.ui.platform.WindowInfo
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
@@ -519,6 +521,48 @@
}
}
+ @Test
+ fun textField_stopAndStartInput_whenToggleWindowFocus() {
+ val value = TextFieldValue("abc")
+ val focusRequester = FocusRequester()
+
+ val focusWindow = mutableStateOf(true)
+ fun createWindowInfo(focused: Boolean) = object : WindowInfo {
+ override val isWindowFocused: Boolean
+ get() = focused
+ }
+
+ setContent {
+ CompositionLocalProvider(
+ LocalWindowInfo provides createWindowInfo(focusWindow.value)
+ ) {
+ CoreTextField(
+ value = value,
+ onValueChange = {},
+ modifier = Modifier.focusRequester(focusRequester)
+ )
+ }
+ }
+
+ rule.runOnUiThread {
+ focusRequester.requestFocus()
+ }
+
+ rule.runOnIdle {
+ inputMethodInterceptor.assertSessionActive()
+ }
+
+ focusWindow.value = false
+ rule.runOnIdle {
+ inputMethodInterceptor.assertNoSessionActive()
+ }
+
+ focusWindow.value = true
+ rule.runOnIdle {
+ inputMethodInterceptor.assertSessionActive()
+ }
+ }
+
private fun setContent(
extraItemForInitialFocus: Boolean = true,
content: @Composable () -> Unit
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/Magnifier.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/Magnifier.android.kt
index 59e1459..186bdd2 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/Magnifier.android.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/Magnifier.android.kt
@@ -199,15 +199,15 @@
if (this === other) return true
if (other !is MagnifierElement) return false
- if (sourceCenter != other.sourceCenter) return false
- if (magnifierCenter != other.magnifierCenter) return false
+ if (sourceCenter !== other.sourceCenter) return false
+ if (magnifierCenter !== other.magnifierCenter) return false
if (zoom != other.zoom) return false
if (useTextDefault != other.useTextDefault) return false
if (size != other.size) return false
if (cornerRadius != other.cornerRadius) return false
if (elevation != other.elevation) return false
if (clippingEnabled != other.clippingEnabled) return false
- if (onSizeChanged != other.onSizeChanged) return false
+ if (onSizeChanged !== other.onSizeChanged) return false
if (platformMagnifierFactory != other.platformMagnifierFactory) return false
return true
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/PreferKeepClear.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/PreferKeepClear.android.kt
index 346ba634b..e6bd917 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/PreferKeepClear.android.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/PreferKeepClear.android.kt
@@ -84,7 +84,7 @@
override fun equals(other: Any?): Boolean {
if (other !is PreferKeepClearNode) return false
- return clearRect == other.rect
+ return clearRect === other.rect
}
override fun InspectorInfo.inspectableProperties() {
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/SystemGestureExclusion.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/SystemGestureExclusion.android.kt
index a9b7f5d..77699fa 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/SystemGestureExclusion.android.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/SystemGestureExclusion.android.kt
@@ -84,7 +84,7 @@
override fun equals(other: Any?): Boolean {
if (other !is ExcludeFromSystemGestureElement) return false
- return exclusion == other.exclusion
+ return exclusion === other.exclusion
}
override fun InspectorInfo.inspectableProperties() {
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/contextmenu/ContextMenuArea.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/contextmenu/ContextMenuArea.android.kt
index d585346..bb0792d 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/contextmenu/ContextMenuArea.android.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/contextmenu/ContextMenuArea.android.kt
@@ -22,12 +22,7 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.IntOffset
-import androidx.compose.ui.unit.IntRect
-import androidx.compose.ui.unit.IntSize
-import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.round
-import androidx.compose.ui.window.PopupPositionProvider
/**
* Wraps [content] with the necessary components to show a context menu in it.
@@ -67,7 +62,9 @@
val status = state.status
if (status !is Status.Open) return
- val popupPositionProvider = remember(status) { StaticPositionProvider(status.offset.round()) }
+ val popupPositionProvider = remember(status) {
+ ContextMenuPopupPositionProvider(status.offset.round())
+ }
ContextMenuPopup(
modifier = modifier,
@@ -76,18 +73,3 @@
contextMenuBuilderBlock = contextMenuBuilderBlock,
)
}
-
-// TODO(b/331958453) Create a smarter provider that will handle
-// moving the menu outside of the click position when
-// the menu is in the bottom right corner.
-private class StaticPositionProvider(
- // The position should be local to the layout the popup is attached to.
- private val localPosition: IntOffset,
-) : PopupPositionProvider {
- override fun calculatePosition(
- anchorBounds: IntRect,
- windowSize: IntSize,
- layoutDirection: LayoutDirection,
- popupContentSize: IntSize
- ): IntOffset = anchorBounds.topLeft + localPosition
-}
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/contextmenu/ContextMenuPopupPositionProvider.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/contextmenu/ContextMenuPopupPositionProvider.android.kt
new file mode 100644
index 0000000..82dbe14
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/contextmenu/ContextMenuPopupPositionProvider.android.kt
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2024 The Android Open 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.contextmenu
+
+import androidx.annotation.VisibleForTesting
+import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.IntRect
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.window.PopupPositionProvider
+
+/**
+ * A [PopupPositionProvider] which places the context menu fully within the window,
+ * aligning a corner of the popup menu with the cursor. For each x/y dimension it will:
+ *
+ * * In cases where the popup length is too small for the window length, it aligns the
+ * start edges of the popup and the window.
+ * * In cases where there is enough length between the click position and the end of
+ * the window for entire popup length, it will align the start edge of the popup with the
+ * [localPosition].
+ * * In cases where there is not enough length between the click position and the end of
+ * the window for entire popup length, but there is between the click position and the
+ * start of the window, it will align the end edge of the popup with the [localPosition].
+ * * In the final case: the window length is wide enough for the popup, but there isn't enough
+ * length on either side of click position to fit an edge of the popup with the click position.
+ * It will align the end edges of the popup and window.
+ *
+ * @param localPosition The [IntOffset] to align to. This should be in the same coordinates that
+ * the `Popup` is anchored to.
+ */
+internal class ContextMenuPopupPositionProvider(
+ private val localPosition: IntOffset,
+) : PopupPositionProvider {
+ // TODO(b/256233441) anchorBounds should be positioned within the window that
+ // windowSize is derived from. However, it seems that windowSize's
+ // bounds do not include the top decoration, while the window anchorBounds
+ // is derived from does include the top decoration. This causes the
+ // resulting calculation to be off when approaching the bottom of the screen.
+ override fun calculatePosition(
+ anchorBounds: IntRect,
+ windowSize: IntSize,
+ layoutDirection: LayoutDirection,
+ popupContentSize: IntSize
+ ): IntOffset = IntOffset(
+ x = alignPopupAxis(
+ position = anchorBounds.left + localPosition.x,
+ popupLength = popupContentSize.width,
+ windowLength = windowSize.width,
+ closeAffinity = layoutDirection == LayoutDirection.Ltr
+ ),
+ y = alignPopupAxis(
+ position = anchorBounds.top + localPosition.y,
+ popupLength = popupContentSize.height,
+ windowLength = windowSize.height,
+ )
+ )
+}
+
+/**
+ * Align the popup to the position along an axis.
+ *
+ * @param position The position to align to along the window's axis
+ * @param popupLength The length of the popup along this axis
+ * @param windowLength The length of the window along this axis
+ * @param closeAffinity Whether the start side is the close edge (`0`)
+ * or the far edge ([windowLength])
+ * @return the coordinate along this axis that best aligns the popup to the position
+ */
+@VisibleForTesting
+internal fun alignPopupAxis(
+ position: Int,
+ popupLength: Int,
+ windowLength: Int,
+ closeAffinity: Boolean = true,
+): Int = when {
+ popupLength >= windowLength -> alignStartEdges(popupLength, windowLength, closeAffinity)
+
+ popupFitsBetweenPositionAndEndEdge(position, popupLength, windowLength, closeAffinity) ->
+ alignPopupStartEdgeToPosition(position, popupLength, closeAffinity)
+
+ popupFitsBetweenPositionAndStartEdge(position, popupLength, windowLength, closeAffinity) ->
+ alignPopupEndEdgeToPosition(position, popupLength, closeAffinity)
+
+ else -> alignEndEdges(popupLength, windowLength, closeAffinity)
+}
+
+private fun popupFitsBetweenPositionAndStartEdge(
+ position: Int,
+ popupLength: Int,
+ windowLength: Int,
+ closeAffinity: Boolean,
+): Boolean = if (closeAffinity) {
+ popupLength <= position
+} else {
+ windowLength - popupLength > position
+}
+
+private fun popupFitsBetweenPositionAndEndEdge(
+ position: Int,
+ popupLength: Int,
+ windowLength: Int,
+ closeAffinity: Boolean,
+): Boolean =
+ popupFitsBetweenPositionAndStartEdge(position, popupLength, windowLength, !closeAffinity)
+
+private fun alignPopupStartEdgeToPosition(
+ position: Int,
+ popupLength: Int,
+ closeAffinity: Boolean,
+): Int = if (closeAffinity) position else position - popupLength
+
+private fun alignPopupEndEdgeToPosition(
+ position: Int,
+ popupLength: Int,
+ closeAffinity: Boolean,
+): Int = alignPopupStartEdgeToPosition(position, popupLength, !closeAffinity)
+
+private fun alignStartEdges(popupLength: Int, windowLength: Int, closeAffinity: Boolean): Int =
+ if (closeAffinity) 0 else windowLength - popupLength
+
+private fun alignEndEdges(popupLength: Int, windowLength: Int, closeAffinity: Boolean): Int =
+ alignStartEdges(popupLength, windowLength, !closeAffinity)
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/handwriting/HandwritingDelegator.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/handwriting/HandwritingDelegator.android.kt
index b4a18c5..4545e0a 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/handwriting/HandwritingDelegator.android.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/handwriting/HandwritingDelegator.android.kt
@@ -65,7 +65,7 @@
override fun hashCode() = 31 * callback.hashCode()
override fun equals(other: Any?) =
- (this === other) or ((other is HandwritingDelegatorElement) && callback == other.callback)
+ (this === other) or ((other is HandwritingDelegatorElement) && callback === other.callback)
override fun InspectorInfo.inspectableProperties() {
name = "handwritingDelegator"
diff --git a/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/contextmenu/ContextMenuPopupPositionProviderTest.kt b/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/contextmenu/ContextMenuPopupPositionProviderTest.kt
new file mode 100644
index 0000000..e762655
--- /dev/null
+++ b/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/contextmenu/ContextMenuPopupPositionProviderTest.kt
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2024 The Android Open 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.contextmenu
+
+import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.IntRect
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.LayoutDirection
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+class ContextMenuPopupPositionProviderTest {
+ //region ContextMenuPopupPositionProvider Tests
+ @Test
+ fun calculatePosition_onlyFitsInXDirection() {
+ val layoutDirection = LayoutDirection.Ltr
+ val windowSize = IntSize(width = 100, height = 100)
+ val anchorBounds = IntRect(left = 10, top = 20, right = 90, bottom = 80)
+ val position = IntOffset(x = 40, y = 30) // 50, 50 when translated to window
+ val popupContentSize = IntSize(width = 10, height = 200)
+
+ val subject = ContextMenuPopupPositionProvider(position)
+ val actual =
+ subject.calculatePosition(anchorBounds, windowSize, layoutDirection, popupContentSize)
+
+ assertThat(actual).isEqualTo(IntOffset(50, 0))
+ }
+
+ @Test
+ fun calculatePosition_onlyFitsInYDirection() {
+ val layoutDirection = LayoutDirection.Ltr
+ val windowSize = IntSize(width = 100, height = 100)
+ val anchorBounds = IntRect(left = 10, top = 20, right = 90, bottom = 80)
+ val position = IntOffset(x = 40, y = 30) // 50, 50 when translated to window
+ val popupContentSize = IntSize(width = 200, height = 10)
+
+ val subject = ContextMenuPopupPositionProvider(position)
+ val actual =
+ subject.calculatePosition(anchorBounds, windowSize, layoutDirection, popupContentSize)
+
+ assertThat(actual).isEqualTo(IntOffset(0, 50))
+ }
+
+ @Test
+ fun calculatePosition_windowIsAccountedFor_ltr() {
+ val layoutDirection = LayoutDirection.Ltr
+ val windowSize = IntSize(width = 100, height = 100)
+ val anchorBounds = IntRect(left = 10, top = 20, right = 90, bottom = 80)
+ val position = IntOffset(x = 40, y = 30) // 50, 50 when translated to window
+ val popupContentSize = IntSize(width = 10, height = 10)
+
+ val subject = ContextMenuPopupPositionProvider(position)
+ val actual =
+ subject.calculatePosition(anchorBounds, windowSize, layoutDirection, popupContentSize)
+
+ assertThat(actual).isEqualTo(IntOffset(50, 50))
+ }
+
+ @Test
+ fun calculatePosition_windowIsAccountedFor_rtl() {
+ val layoutDirection = LayoutDirection.Rtl
+ val windowSize = IntSize(width = 100, height = 100)
+ val anchorBounds = IntRect(left = 10, top = 20, right = 90, bottom = 80)
+ val position = IntOffset(x = 40, y = 30) // 50, 50 when translated to window
+ val popupContentSize = IntSize(width = 10, height = 10)
+
+ val subject = ContextMenuPopupPositionProvider(position)
+ val actual =
+ subject.calculatePosition(anchorBounds, windowSize, layoutDirection, popupContentSize)
+
+ assertThat(actual).isEqualTo(IntOffset(40, 50))
+ }
+ //endregion ContextMenuPopupPositionProvider Tests
+
+ //region alignPopupAxis Tests
+ @Test
+ fun alignPopupAxis_closeAffinity_popupLargerThanWindow() = alignPopupAxisTest(
+ position = 50,
+ popupLength = 200,
+ closeAffinity = true,
+ expected = 0
+ )
+
+ @Test
+ fun alignPopupAxis_closeAffinity_popupFitsNeitherSide() = alignPopupAxisTest(
+ position = 50,
+ popupLength = 75,
+ closeAffinity = true,
+ expected = 25
+ )
+
+ @Test
+ fun alignPopupAxis_closeAffinity_popupFitsCloseSide() = alignPopupAxisTest(
+ position = 90,
+ popupLength = 30,
+ closeAffinity = true,
+ expected = 60
+ )
+
+ @Test
+ fun alignPopupAxis_closeAffinity_popupFitsFarSide() = alignPopupAxisTest(
+ position = 20,
+ popupLength = 30,
+ closeAffinity = true,
+ expected = 20
+ )
+
+ @Test
+ fun alignPopupAxis_closeAffinity_popupFitsEitherSide() = alignPopupAxisTest(
+ position = 50,
+ popupLength = 10,
+ closeAffinity = true,
+ expected = 50
+ )
+
+ @Test
+ fun alignPopupAxis_farAffinity_popupLargerThanWindow() = alignPopupAxisTest(
+ position = 50,
+ popupLength = 200,
+ closeAffinity = false,
+ expected = -100
+ )
+
+ @Test
+ fun alignPopupAxis_farAffinity_popupFitsNeitherSide() = alignPopupAxisTest(
+ position = 50,
+ popupLength = 75,
+ closeAffinity = false,
+ expected = 0
+ )
+
+ @Test
+ fun alignPopupAxis_farAffinity_popupFitsCloseSide() = alignPopupAxisTest(
+ position = 90,
+ popupLength = 30,
+ closeAffinity = false,
+ expected = 60
+ )
+
+ @Test
+ fun alignPopupAxis_farAffinity_popupFitsFarSide() = alignPopupAxisTest(
+ position = 20,
+ popupLength = 30,
+ closeAffinity = false,
+ expected = 20
+ )
+
+ @Test
+ fun alignPopupAxis_farAffinity_popupFitsEitherSide() = alignPopupAxisTest(
+ position = 50,
+ popupLength = 10,
+ closeAffinity = false,
+ expected = 40
+ )
+
+ private fun alignPopupAxisTest(
+ position: Int,
+ popupLength: Int,
+ closeAffinity: Boolean,
+ expected: Int
+ ) {
+ val actual = alignPopupAxis(
+ position = position,
+ popupLength = popupLength,
+ windowLength = 100,
+ closeAffinity = closeAffinity
+ )
+ assertThat(actual).isEqualTo(expected)
+ }
+
+ @Test
+ fun alignPopupAxis_popupBarelyFitsInAfterSpace() {
+ val actual = alignPopupAxis(
+ position = 74,
+ popupLength = 25,
+ windowLength = 100,
+ )
+ assertThat(actual).isEqualTo(74)
+ }
+
+ @Test
+ fun alignPopupAxis_popupBarelyDoesNotFitInAfterSpace() {
+ val actual = alignPopupAxis(
+ position = 75,
+ popupLength = 25,
+ windowLength = 100,
+ )
+ assertThat(actual).isEqualTo(50)
+ }
+
+ @Test
+ fun alignPopupAxis_popupBarelyFitsInBeforeSpace() {
+ val actual = alignPopupAxis(
+ position = 25,
+ popupLength = 25,
+ windowLength = 100,
+ closeAffinity = false
+ )
+ assertThat(actual).isEqualTo(0)
+ }
+
+ @Test
+ fun alignPopupAxis_popupBarelyDoesNotFitInBeforeSpace() {
+ val actual = alignPopupAxis(
+ position = 24,
+ popupLength = 25,
+ windowLength = 100,
+ closeAffinity = false
+ )
+ assertThat(actual).isEqualTo(24)
+ }
+ //endregion alignPopupAxis Tests
+}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Clickable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Clickable.kt
index 3981ac6..2cea5ef 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Clickable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Clickable.kt
@@ -514,7 +514,7 @@
if (enabled != other.enabled) return false
if (onClickLabel != other.onClickLabel) return false
if (role != other.role) return false
- if (onClick != other.onClick) return false
+ if (onClick !== other.onClick) return false
return true
}
@@ -592,10 +592,10 @@
if (enabled != other.enabled) return false
if (onClickLabel != other.onClickLabel) return false
if (role != other.role) return false
- if (onClick != other.onClick) return false
+ if (onClick !== other.onClick) return false
if (onLongClickLabel != other.onLongClickLabel) return false
- if (onLongClick != other.onLongClick) return false
- if (onDoubleClick != other.onDoubleClick) return false
+ if (onLongClick !== other.onLongClick) return false
+ if (onDoubleClick !== other.onDoubleClick) return false
return true
}
@@ -826,7 +826,7 @@
resetPointerInputHandling = true
}
- if (this.onLongClick != onLongClick) {
+ if (this.onLongClick !== onLongClick) {
this.onLongClick = onLongClick
invalidateSemantics()
}
@@ -1225,9 +1225,9 @@
if (enabled != other.enabled) return false
if (role != other.role) return false
if (onLongClickLabel != other.onLongClickLabel) return false
- if (onLongClick != other.onLongClick) return false
+ if (onLongClick !== other.onLongClick) return false
if (onClickLabel != other.onClickLabel) return false
- if (onClick != other.onClick) return false
+ if (onClick !== other.onClick) return false
return true
}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/FocusedBounds.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/FocusedBounds.kt
index 01f5f64..df7af80 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/FocusedBounds.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/FocusedBounds.kt
@@ -55,7 +55,7 @@
override fun equals(other: Any?): Boolean {
if (this === other) return true
val otherModifier = other as? FocusedBoundsObserverElement ?: return false
- return onPositioned == otherModifier.onPositioned
+ return onPositioned === otherModifier.onPositioned
}
override fun InspectorInfo.inspectableProperties() {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/draganddrop/DragAndDropTarget.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/draganddrop/DragAndDropTarget.kt
index 2a082d1..2a14342 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/draganddrop/DragAndDropTarget.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/draganddrop/DragAndDropTarget.kt
@@ -79,7 +79,7 @@
if (other !is DropTargetElement) return false
if (target != other.target) return false
- return shouldStartDragAndDrop == other.shouldStartDragAndDrop
+ return shouldStartDragAndDrop === other.shouldStartDragAndDrop
}
override fun hashCode(): Int {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Transformable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Transformable.kt
index 1e4abd9..297c21c 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Transformable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Transformable.kt
@@ -116,7 +116,7 @@
other as TransformableElement
if (state != other.state) return false
- if (canPan != other.canPan) return false
+ if (canPan !== other.canPan) return false
if (lockRotationOnZoomPan != other.lockRotationOnZoomPan) return false
if (enabled != other.enabled) return false
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutSemantics.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutSemantics.kt
index 18a65d3..1920744 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutSemantics.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutSemantics.kt
@@ -89,7 +89,7 @@
if (this === other) return true
if (other !is LazyLayoutSemanticsModifier) return false
- if (itemProviderLambda != other.itemProviderLambda) return false
+ if (itemProviderLambda !== other.itemProviderLambda) return false
if (state != other.state) return false
if (orientation != other.orientation) return false
if (userScrollEnabled != other.userScrollEnabled) return false
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Selectable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Selectable.kt
index caa756a..70d94a9 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Selectable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Selectable.kt
@@ -203,7 +203,7 @@
if (indicationNodeFactory != other.indicationNodeFactory) return false
if (enabled != other.enabled) return false
if (role != other.role) return false
- if (onClick != other.onClick) return false
+ if (onClick !== other.onClick) return false
return true
}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Toggleable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Toggleable.kt
index b75e3c1..bcaa2ed 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Toggleable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Toggleable.kt
@@ -197,7 +197,7 @@
if (indicationNodeFactory != other.indicationNodeFactory) return false
if (enabled != other.enabled) return false
if (role != other.role) return false
- if (onValueChange != other.onValueChange) return false
+ if (onValueChange !== other.onValueChange) return false
return true
}
@@ -433,7 +433,7 @@
if (indicationNodeFactory != other.indicationNodeFactory) return false
if (enabled != other.enabled) return false
if (role != other.role) return false
- if (onClick != other.onClick) return false
+ if (onClick !== other.onClick) return false
return true
}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/shape/GenericShape.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/shape/GenericShape.kt
index e3a65a3..79ca230 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/shape/GenericShape.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/shape/GenericShape.kt
@@ -46,7 +46,7 @@
override fun equals(other: Any?): Boolean {
if (this === other) return true
- return (other as? GenericShape)?.builder == builder
+ return (other as? GenericShape)?.builder === builder
}
override fun hashCode(): Int {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
index ccd7d9f..5b64b4b 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
@@ -349,7 +349,7 @@
}
// Hide the keyboard if made disabled or read-only while focused (b/237308379).
- val writeable by rememberUpdatedState(enabled && !readOnly)
+ val writeable by rememberUpdatedState(enabled && !readOnly && windowInfo.isWindowFocused)
LaunchedEffect(Unit) {
try {
snapshotFlow { writeable }.collect { writeable ->
@@ -405,8 +405,8 @@
.pointerHoverIcon(textPointerIcon)
.then(
if (isStylusHandwritingSupported) {
- Modifier.pointerInput(enabled, readOnly) {
- if (enabled && !readOnly) {
+ Modifier.pointerInput(writeable) {
+ if (writeable) {
detectStylusHandwriting {
if (!state.hasFocus) {
focusRequester.requestFocus()
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardActions.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardActions.kt
index d5112f2..428c7b8 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardActions.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardActions.kt
@@ -74,12 +74,12 @@
if (this === other) return true
if (other !is KeyboardActions) return false
- return onDone == other.onDone &&
- onGo == other.onGo &&
- onNext == other.onNext &&
- onPrevious == other.onPrevious &&
- onSearch == other.onSearch &&
- onSend == other.onSend
+ return onDone === other.onDone &&
+ onGo === other.onGo &&
+ onNext === other.onNext &&
+ onPrevious === other.onPrevious &&
+ onSearch === other.onSearch &&
+ onSend === other.onSend
}
override fun hashCode(): Int {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/SelectableTextAnnotatedStringElement.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/SelectableTextAnnotatedStringElement.kt
index fd739d6..7a1cd33 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/SelectableTextAnnotatedStringElement.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/SelectableTextAnnotatedStringElement.kt
@@ -93,14 +93,14 @@
// these are equally unlikely to change
if (fontFamilyResolver != other.fontFamilyResolver) return false
- if (onTextLayout != other.onTextLayout) return false
+ if (onTextLayout !== other.onTextLayout) return false
if (overflow != other.overflow) return false
if (softWrap != other.softWrap) return false
if (maxLines != other.maxLines) return false
if (minLines != other.minLines) return false
// these never change, but check anyway for correctness
- if (onPlaceholderLayout != other.onPlaceholderLayout) return false
+ if (onPlaceholderLayout !== other.onPlaceholderLayout) return false
if (selectionController != other.selectionController) return false
return true
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextAnnotatedStringElement.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextAnnotatedStringElement.kt
index f8853ad..6525c51 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextAnnotatedStringElement.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextAnnotatedStringElement.kt
@@ -102,15 +102,15 @@
// these are equally unlikely to change
if (fontFamilyResolver != other.fontFamilyResolver) return false
- if (onTextLayout != other.onTextLayout) return false
- if (onShowTranslation != other.onShowTranslation) return false
+ if (onTextLayout !== other.onTextLayout) return false
+ if (onShowTranslation !== other.onShowTranslation) return false
if (overflow != other.overflow) return false
if (softWrap != other.softWrap) return false
if (maxLines != other.maxLines) return false
if (minLines != other.minLines) return false
// these never change, but check anyway for correctness
- if (onPlaceholderLayout != other.onPlaceholderLayout) return false
+ if (onPlaceholderLayout !== other.onPlaceholderLayout) return false
if (selectionController != other.selectionController) return false
return true
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextAnnotatedStringNode.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextAnnotatedStringNode.kt
index aa99015..9c3e8a6 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextAnnotatedStringNode.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextAnnotatedStringNode.kt
@@ -209,12 +209,12 @@
): Boolean {
var changed = false
- if (this.onTextLayout != onTextLayout) {
+ if (this.onTextLayout !== onTextLayout) {
this.onTextLayout = onTextLayout
changed = true
}
- if (this.onPlaceholderLayout != onPlaceholderLayout) {
+ if (this.onPlaceholderLayout !== onPlaceholderLayout) {
this.onPlaceholderLayout = onPlaceholderLayout
changed = true
}
@@ -224,7 +224,7 @@
changed = true
}
- if (this.onShowTranslation != onShowTranslation) {
+ if (this.onShowTranslation !== onShowTranslation) {
this.onShowTranslation = onShowTranslation
changed = true
}
diff --git a/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/ComposeIssueRegistry.kt b/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/ComposeIssueRegistry.kt
index 43f6253..36ecaff 100644
--- a/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/ComposeIssueRegistry.kt
+++ b/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/ComposeIssueRegistry.kt
@@ -37,6 +37,7 @@
CommonModuleIncompatibilityDetector.REFERENCE_ISSUE,
CommonModuleIncompatibilityDetector.EXTENDS_LAMBDA_ISSUE,
PrimitiveInCollectionDetector.ISSUE,
+ LambdaStructuralEqualityDetector.ISSUE
)
}
override val vendor = Vendor(
diff --git a/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/LambdaStructuralEqualityDetector.kt b/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/LambdaStructuralEqualityDetector.kt
new file mode 100644
index 0000000..6d7c0c0
--- /dev/null
+++ b/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/LambdaStructuralEqualityDetector.kt
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2024 The Android Open 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.lint
+
+import com.android.tools.lint.client.api.UElementHandler
+import com.android.tools.lint.detector.api.Category
+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.LintFix
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import java.util.EnumSet
+import org.jetbrains.kotlin.analysis.api.analyze
+import org.jetbrains.kotlin.psi.KtExpression
+import org.jetbrains.uast.UBinaryExpression
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.UastBinaryOperator
+
+/**
+ * Lint [Detector] to ensure that lambda instances are compared referentially, instead of
+ * structurally.
+ *
+ * This is needed as function references (::lambda) do not consider their capture scope in their
+ * equals implementation. This means that structural equality can return true, even if the lambdas
+ * are different references with a different capture scope. Instead, lambdas should be compared
+ * referentially (=== or !==) to avoid this issue.
+ */
+class LambdaStructuralEqualityDetector : Detector(), SourceCodeScanner {
+ override fun getApplicableUastTypes() = listOf(
+ UBinaryExpression::class.java,
+ UCallExpression::class.java
+ )
+
+ override fun createUastHandler(context: JavaContext) = object : UElementHandler() {
+ override fun visitBinaryExpression(node: UBinaryExpression) {
+ val op = node.operator
+ if (op == UastBinaryOperator.EQUALS ||
+ op == UastBinaryOperator.NOT_EQUALS) {
+ val left = node.leftOperand.sourcePsi as? KtExpression ?: return
+ val right = node.rightOperand.sourcePsi as? KtExpression ?: return
+ if (left.isFunctionType() && right.isFunctionType()) {
+ val replacement = if (op == UastBinaryOperator.EQUALS) "===" else "!=="
+ context.report(
+ ISSUE,
+ node.operatorIdentifier,
+ context.getNameLocation(node.operatorIdentifier ?: node),
+ BriefDescription,
+ LintFix.create()
+ .replace()
+ .name("Change to $replacement")
+ .text(op.text)
+ .with(replacement)
+ .autoFix()
+ .build()
+ )
+ }
+ }
+ }
+
+ override fun visitCallExpression(node: UCallExpression) {
+ if (node.methodName == "equals") {
+ val left = node.receiver?.sourcePsi as? KtExpression ?: return
+ val right = node.valueArguments.firstOrNull()?.sourcePsi as? KtExpression ?: return
+ if (left.isFunctionType() && right.isFunctionType()) {
+ context.report(
+ ISSUE,
+ node,
+ context.getNameLocation(node),
+ BriefDescription
+ )
+ }
+ }
+ }
+ }
+
+ private fun KtExpression.isFunctionType(): Boolean = analyze(this) {
+ getKtType()?.isFunctionType == true
+ }
+
+ companion object {
+ private const val BriefDescription = "Checking lambdas for structural equality, instead " +
+ "of checking for referential equality"
+ private const val Explanation =
+ "Checking structural equality on lambdas can lead to issues, as function references " +
+ "(::lambda) do not consider their capture scope in their equals implementation. " +
+ "This means that structural equality can return true, even if the lambdas are " +
+ "different references with a different capture scope. Instead, lambdas should be" +
+ "compared referentially (=== or !==) to avoid this issue."
+
+ val ISSUE = Issue.create(
+ "LambdaStructuralEquality",
+ BriefDescription,
+ Explanation,
+ Category.CORRECTNESS, 5, Severity.ERROR,
+ Implementation(
+ LambdaStructuralEqualityDetector::class.java,
+ EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES)
+ )
+ )
+ }
+}
diff --git a/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/LambdaStructuralEqualityDetectorTest.kt b/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/LambdaStructuralEqualityDetectorTest.kt
new file mode 100644
index 0000000..0206fd9
--- /dev/null
+++ b/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/LambdaStructuralEqualityDetectorTest.kt
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2024 The Android Open 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.compose.lint
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+/* ktlint-disable max-line-length */
+@RunWith(JUnit4::class)
+class LambdaStructuralEqualityDetectorTest : LintDetectorTest() {
+ override fun getDetector(): Detector = LambdaStructuralEqualityDetector()
+
+ override fun getIssues(): MutableList<Issue> = mutableListOf(
+ LambdaStructuralEqualityDetector.ISSUE
+ )
+
+ @Test
+ fun noErrors() {
+ lint().files(
+ kotlin(
+ """
+ package test
+
+ val lambda1 = { 1 }
+ val lambda2 = { 2 }
+
+ fun test() {
+ lambda1 === lambda2
+ lambda1 !== lambda2
+ }
+ """
+ )
+ )
+ .run()
+ .expectClean()
+ }
+
+ @Test
+ fun errors() {
+ lint().files(
+ kotlin(
+ """
+ package test
+
+ val lambda1 = { 1 }
+ val lambda2 = { 2 }
+ val lambda3: (() -> Unit)? = null
+
+ fun test() {
+ lambda1 == lambda2
+ lambda1 != lambda2
+ lambda1.equals(lambda2)
+ lambda3?.equals(lambda2)
+ }
+ """
+ )
+ )
+ .run()
+ .expect(
+ """
+src/test/test.kt:9: Error: Checking lambdas for structural equality, instead of checking for referential equality [LambdaStructuralEquality]
+ lambda1 == lambda2
+ ~~
+src/test/test.kt:10: Error: Checking lambdas for structural equality, instead of checking for referential equality [LambdaStructuralEquality]
+ lambda1 != lambda2
+ ~~
+src/test/test.kt:11: Error: Checking lambdas for structural equality, instead of checking for referential equality [LambdaStructuralEquality]
+ lambda1.equals(lambda2)
+ ~~~~~~
+src/test/test.kt:12: Error: Checking lambdas for structural equality, instead of checking for referential equality [LambdaStructuralEquality]
+ lambda3?.equals(lambda2)
+ ~~~~~~
+4 errors, 0 warnings
+ """
+ )
+ .expectFixDiffs(
+ """
+Autofix for src/test/test.kt line 9: Change to ===:
+@@ -9 +9
+- lambda1 == lambda2
++ lambda1 === lambda2
+Autofix for src/test/test.kt line 10: Change to !==:
+@@ -10 +10
+- lambda1 != lambda2
++ lambda1 !== lambda2
+ """
+ )
+ }
+}
+/* ktlint-enable max-line-length */
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AnchoredDraggable.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AnchoredDraggable.kt
index d90d9b3..307d512 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AnchoredDraggable.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AnchoredDraggable.kt
@@ -838,7 +838,7 @@
if (other !is DraggableAnchorsElement<*>) return false
if (state != other.state) return false
- if (anchors != other.anchors) return false
+ if (anchors !== other.anchors) return false
if (orientation != other.orientation) return false
return true
diff --git a/compose/material3/adaptive/adaptive-navigation/api/current.txt b/compose/material3/adaptive/adaptive-navigation/api/current.txt
index 4a99882..3388cc4 100644
--- a/compose/material3/adaptive/adaptive-navigation/api/current.txt
+++ b/compose/material3/adaptive/adaptive-navigation/api/current.txt
@@ -2,24 +2,32 @@
package androidx.compose.material3.adaptive.navigation {
public final class AndroidThreePaneScaffold_androidKt {
- method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void NavigableListDetailPaneScaffold(androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<java.lang.Object> navigator, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> listPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> detailPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit>? extraPane, optional androidx.compose.material3.adaptive.navigation.BackNavigationBehavior defaultBackBehavior);
- method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void NavigableSupportingPaneScaffold(androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<java.lang.Object> navigator, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> mainPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> supportingPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit>? extraPane, optional androidx.compose.material3.adaptive.navigation.BackNavigationBehavior defaultBackBehavior);
+ method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void NavigableListDetailPaneScaffold(androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<java.lang.Object> navigator, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> listPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> detailPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit>? extraPane, optional String defaultBackBehavior);
+ method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void NavigableSupportingPaneScaffold(androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<java.lang.Object> navigator, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> mainPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> supportingPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit>? extraPane, optional String defaultBackBehavior);
}
- @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public enum BackNavigationBehavior {
- enum_constant public static final androidx.compose.material3.adaptive.navigation.BackNavigationBehavior PopLatest;
- enum_constant public static final androidx.compose.material3.adaptive.navigation.BackNavigationBehavior PopUntilContentChange;
- enum_constant public static final androidx.compose.material3.adaptive.navigation.BackNavigationBehavior PopUntilCurrentDestinationChange;
- enum_constant public static final androidx.compose.material3.adaptive.navigation.BackNavigationBehavior PopUntilScaffoldValueChange;
+ @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @kotlin.jvm.JvmInline public final value class BackNavigationBehavior {
+ field public static final androidx.compose.material3.adaptive.navigation.BackNavigationBehavior.Companion Companion;
+ }
+
+ public static final class BackNavigationBehavior.Companion {
+ method public String getPopLatest();
+ method public String getPopUntilContentChange();
+ method public String getPopUntilCurrentDestinationChange();
+ method public String getPopUntilScaffoldValueChange();
+ property public final String PopLatest;
+ property public final String PopUntilContentChange;
+ property public final String PopUntilCurrentDestinationChange;
+ property public final String PopUntilScaffoldValueChange;
}
@SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Stable public interface ThreePaneScaffoldNavigator<T> {
- method public boolean canNavigateBack(optional androidx.compose.material3.adaptive.navigation.BackNavigationBehavior backNavigationBehavior);
+ method public boolean canNavigateBack(optional String backNavigationBehavior);
method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldDestinationItem<T>? getCurrentDestination();
method public androidx.compose.material3.adaptive.layout.PaneScaffoldDirective getScaffoldDirective();
method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue getScaffoldValue();
method public boolean isDestinationHistoryAware();
- method public boolean navigateBack(optional androidx.compose.material3.adaptive.navigation.BackNavigationBehavior backNavigationBehavior);
+ method public boolean navigateBack(optional String backNavigationBehavior);
method public void navigateTo(androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole pane, optional T? content);
method public void setDestinationHistoryAware(boolean);
property public abstract androidx.compose.material3.adaptive.layout.ThreePaneScaffoldDestinationItem<T>? currentDestination;
diff --git a/compose/material3/adaptive/adaptive-navigation/api/restricted_current.txt b/compose/material3/adaptive/adaptive-navigation/api/restricted_current.txt
index 4a99882..3388cc4 100644
--- a/compose/material3/adaptive/adaptive-navigation/api/restricted_current.txt
+++ b/compose/material3/adaptive/adaptive-navigation/api/restricted_current.txt
@@ -2,24 +2,32 @@
package androidx.compose.material3.adaptive.navigation {
public final class AndroidThreePaneScaffold_androidKt {
- method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void NavigableListDetailPaneScaffold(androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<java.lang.Object> navigator, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> listPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> detailPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit>? extraPane, optional androidx.compose.material3.adaptive.navigation.BackNavigationBehavior defaultBackBehavior);
- method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void NavigableSupportingPaneScaffold(androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<java.lang.Object> navigator, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> mainPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> supportingPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit>? extraPane, optional androidx.compose.material3.adaptive.navigation.BackNavigationBehavior defaultBackBehavior);
+ method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void NavigableListDetailPaneScaffold(androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<java.lang.Object> navigator, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> listPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> detailPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit>? extraPane, optional String defaultBackBehavior);
+ method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void NavigableSupportingPaneScaffold(androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<java.lang.Object> navigator, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> mainPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> supportingPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit>? extraPane, optional String defaultBackBehavior);
}
- @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public enum BackNavigationBehavior {
- enum_constant public static final androidx.compose.material3.adaptive.navigation.BackNavigationBehavior PopLatest;
- enum_constant public static final androidx.compose.material3.adaptive.navigation.BackNavigationBehavior PopUntilContentChange;
- enum_constant public static final androidx.compose.material3.adaptive.navigation.BackNavigationBehavior PopUntilCurrentDestinationChange;
- enum_constant public static final androidx.compose.material3.adaptive.navigation.BackNavigationBehavior PopUntilScaffoldValueChange;
+ @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @kotlin.jvm.JvmInline public final value class BackNavigationBehavior {
+ field public static final androidx.compose.material3.adaptive.navigation.BackNavigationBehavior.Companion Companion;
+ }
+
+ public static final class BackNavigationBehavior.Companion {
+ method public String getPopLatest();
+ method public String getPopUntilContentChange();
+ method public String getPopUntilCurrentDestinationChange();
+ method public String getPopUntilScaffoldValueChange();
+ property public final String PopLatest;
+ property public final String PopUntilContentChange;
+ property public final String PopUntilCurrentDestinationChange;
+ property public final String PopUntilScaffoldValueChange;
}
@SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Stable public interface ThreePaneScaffoldNavigator<T> {
- method public boolean canNavigateBack(optional androidx.compose.material3.adaptive.navigation.BackNavigationBehavior backNavigationBehavior);
+ method public boolean canNavigateBack(optional String backNavigationBehavior);
method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldDestinationItem<T>? getCurrentDestination();
method public androidx.compose.material3.adaptive.layout.PaneScaffoldDirective getScaffoldDirective();
method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue getScaffoldValue();
method public boolean isDestinationHistoryAware();
- method public boolean navigateBack(optional androidx.compose.material3.adaptive.navigation.BackNavigationBehavior backNavigationBehavior);
+ method public boolean navigateBack(optional String backNavigationBehavior);
method public void navigateTo(androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole pane, optional T? content);
method public void setDestinationHistoryAware(boolean);
property public abstract androidx.compose.material3.adaptive.layout.ThreePaneScaffoldDestinationItem<T>? currentDestination;
diff --git a/compose/material3/adaptive/adaptive-navigation/src/commonMain/kotlin/androidx/compose/material3/adaptive/navigation/BackNavigationBehavior.kt b/compose/material3/adaptive/adaptive-navigation/src/commonMain/kotlin/androidx/compose/material3/adaptive/navigation/BackNavigationBehavior.kt
index 3ae80e2..6d0a096 100644
--- a/compose/material3/adaptive/adaptive-navigation/src/commonMain/kotlin/androidx/compose/material3/adaptive/navigation/BackNavigationBehavior.kt
+++ b/compose/material3/adaptive/adaptive-navigation/src/commonMain/kotlin/androidx/compose/material3/adaptive/navigation/BackNavigationBehavior.kt
@@ -25,34 +25,42 @@
* A class to control how back navigation should behave in a [ThreePaneScaffoldNavigator].
*/
@ExperimentalMaterial3AdaptiveApi
-enum class BackNavigationBehavior {
- /** Pop the latest destination from the backstack. */
- PopLatest,
+@JvmInline
+value class BackNavigationBehavior private constructor(private val description: String) {
+ override fun toString(): String = this.description
- /**
- * Pop destinations from the backstack until there is a change in the scaffold value.
- *
- * For example, in a single-pane layout, this will skip entries until the current destination
- * is a different [ThreePaneScaffoldRole]. In a multi-pane layout, this will skip entries until
- * the [PaneAdaptedValue] of any pane changes.
- */
- PopUntilScaffoldValueChange,
+ companion object {
+ /** Pop the latest destination from the backstack. */
+ val PopLatest = BackNavigationBehavior("PopLatest")
- /**
- * Pop destinations from the backstack until there is a change in the current destination pane.
- *
- * In a single-pane layout, this should behave similarly to [PopUntilScaffoldValueChange]. In a
- * multi-pane layout, it is possible for both the current destination and previous destination
- * to be showing at the same time, so this may not result in a visual change in the scaffold.
- */
- PopUntilCurrentDestinationChange,
+ /**
+ * Pop destinations from the backstack until there is a change in the scaffold value.
+ *
+ * For example, in a single-pane layout, this will skip entries until the current
+ * destination is a different [ThreePaneScaffoldRole]. In a multi-pane layout, this will
+ * skip entries until the [PaneAdaptedValue] of any pane changes.
+ */
+ val PopUntilScaffoldValueChange = BackNavigationBehavior("PopUntilScaffoldValueChange")
- /**
- * Pop destinations from the backstack until there is a content change.
- *
- * A "content change" is defined as either a change in the content of the current
- * [ThreePaneScaffoldDestinationItem], or a change in the scaffold value (similar to
- * [PopUntilScaffoldValueChange]).
- */
- PopUntilContentChange,
+ /**
+ * Pop destinations from the backstack until there is a change in the current destination
+ * pane.
+ *
+ * In a single-pane layout, this should behave similarly to [PopUntilScaffoldValueChange].
+ * In a multi-pane layout, it is possible for both the current destination and previous
+ * destination to be showing at the same time, so this may not result in a visual change
+ * in the scaffold.
+ */
+ val PopUntilCurrentDestinationChange =
+ BackNavigationBehavior("PopUntilCurrentDestinationChange")
+
+ /**
+ * Pop destinations from the backstack until there is a content change.
+ *
+ * A "content change" is defined as either a change in the content of the current
+ * [ThreePaneScaffoldDestinationItem], or a change in the scaffold value (similar to
+ * [PopUntilScaffoldValueChange]).
+ */
+ val PopUntilContentChange = BackNavigationBehavior("PopUntilContentChange")
+ }
}
diff --git a/compose/material3/adaptive/adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/Posture.kt b/compose/material3/adaptive/adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/Posture.kt
index 6455c51..efbd340 100644
--- a/compose/material3/adaptive/adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/Posture.kt
+++ b/compose/material3/adaptive/adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/Posture.kt
@@ -47,6 +47,7 @@
if (this === other) return true
if (other !is Posture) return false
if (isTabletop != other.isTabletop) return false
+ if (hingeList != other.hingeList) return false
return true
}
diff --git a/compose/material3/material3-common/build.gradle b/compose/material3/material3-common/build.gradle
index 32cbf10..f41127b 100644
--- a/compose/material3/material3-common/build.gradle
+++ b/compose/material3/material3-common/build.gradle
@@ -112,7 +112,6 @@
name = "Compose Material 3 Common"
mavenVersion = LibraryVersions.COMPOSE_MATERIAL3_COMMON
type = LibraryType.PUBLISHED_KOTLIN_ONLY_LIBRARY
- publish = Publish.SNAPSHOT_AND_RELEASE
inceptionYear = "2023"
description = "Compose Material 3 Common Library. This library contains foundational, themeless " +
"components that can be shared between different Material libraries or used by app" +
diff --git a/compose/material3/material3-window-size-class/build.gradle b/compose/material3/material3-window-size-class/build.gradle
index f3d4c53..28239af 100644
--- a/compose/material3/material3-window-size-class/build.gradle
+++ b/compose/material3/material3-window-size-class/build.gradle
@@ -122,6 +122,7 @@
type = LibraryType.PUBLISHED_KOTLIN_ONLY_LIBRARY
inceptionYear = "2022"
description = "Provides window size classes for building responsive UIs"
+ samples(project(":compose:material3:material3-window-size-class:material3-window-size-class-samples"))
}
android {
diff --git a/compose/material3/material3/src/androidMain/res/values-be/strings.xml b/compose/material3/material3/src/androidMain/res/values-be/strings.xml
index ae2754d..e434ece 100644
--- a/compose/material3/material3/src/androidMain/res/values-be/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-be/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Дыялогавае акно"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Разгорнута"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Згорнута"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Уключыць (выключыць) выпадное меню"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Закрыць"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Пошук"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Прапановы ўнізе"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-bg/strings.xml b/compose/material3/material3/src/androidMain/res/values-bg/strings.xml
index 4558f92..124dad0 100644
--- a/compose/material3/material3/src/androidMain/res/values-bg/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-bg/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Диалогов прозорец"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Разгънато"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Свито"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Превключване на падащото меню"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Отхвърляне"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Лента за търсене"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Предложенията са по-долу"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-bn/strings.xml b/compose/material3/material3/src/androidMain/res/values-bn/strings.xml
index 9b9a91a..b74dd78 100644
--- a/compose/material3/material3/src/androidMain/res/values-bn/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-bn/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"ডায়ালগ"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"বড় করা হয়েছে"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"আড়াল করা হয়েছে"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"ড্রপডাউন মেনু টগল করুন"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"বাতিল করুন"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"সার্চ করুন"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"নিচে দেওয়া সাজেশন"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-bs/strings.xml b/compose/material3/material3/src/androidMain/res/values-bs/strings.xml
index e6cc97c..5d5d633 100644
--- a/compose/material3/material3/src/androidMain/res/values-bs/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-bs/strings.xml
@@ -20,7 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Dijaloški okvir"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Prošireno"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Suženo"</string>
- <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Prekidač za padajući izbornik"</string>
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Uključivanje/isključivanje padajućeg menija"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Odbacivanje"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Pretraživanje"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Prijedlozi su u nastavku"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-ca/strings.xml b/compose/material3/material3/src/androidMain/res/values-ca/strings.xml
index 3c04f34..ef12ec8 100644
--- a/compose/material3/material3/src/androidMain/res/values-ca/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-ca/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Quadre de diàleg"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"S\'ha desplegat"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"S\'ha replegat"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Commuta el menú desplegable"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Ignora"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Cerca"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Suggeriments a continuació"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-cs/strings.xml b/compose/material3/material3/src/androidMain/res/values-cs/strings.xml
index 5a82875..3e7d316 100644
--- a/compose/material3/material3/src/androidMain/res/values-cs/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-cs/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Dialogové okno"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Rozbaleno"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Sbaleno"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Přepnout rozbalovací nabídku"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Zavřít"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Vyhledávání"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Níže jsou k dispozici návrhy"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-da/strings.xml b/compose/material3/material3/src/androidMain/res/values-da/strings.xml
index a45b72a..d4032f7 100644
--- a/compose/material3/material3/src/androidMain/res/values-da/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-da/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Dialogboks"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Udvidet"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Skjult"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Skift visningen af rullemenuen"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Afvis"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Søg"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Forslag nedenfor"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-de/strings.xml b/compose/material3/material3/src/androidMain/res/values-de/strings.xml
index 57b1135..f5a97c9 100644
--- a/compose/material3/material3/src/androidMain/res/values-de/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-de/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Dialogfeld"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Maximiert"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Minimiert"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Drop-down-Menü maximieren/minimieren"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Schließen"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Suche"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Vorschläge unten"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-el/strings.xml b/compose/material3/material3/src/androidMain/res/values-el/strings.xml
index be85d0b..aa67f3f 100644
--- a/compose/material3/material3/src/androidMain/res/values-el/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-el/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Παράθυρο διαλόγου"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Αναπτυγμένο"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Συμπτυγμένο"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Εναλλαγή αναπτυσσόμενου μενού"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Παράβλεψη"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Αναζήτηση"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Προτάσεις παρακάτω"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-en-rAU/strings.xml b/compose/material3/material3/src/androidMain/res/values-en-rAU/strings.xml
index 2a911184..f95be07 100644
--- a/compose/material3/material3/src/androidMain/res/values-en-rAU/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-en-rAU/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Dialogue"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Expanded"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Collapsed"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Toggle drop-down menu"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Dismiss"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Search"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Suggestions below"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-en-rGB/strings.xml b/compose/material3/material3/src/androidMain/res/values-en-rGB/strings.xml
index 2a911184..f95be07 100644
--- a/compose/material3/material3/src/androidMain/res/values-en-rGB/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-en-rGB/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Dialogue"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Expanded"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Collapsed"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Toggle drop-down menu"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Dismiss"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Search"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Suggestions below"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-en-rIN/strings.xml b/compose/material3/material3/src/androidMain/res/values-en-rIN/strings.xml
index 2a911184..f95be07 100644
--- a/compose/material3/material3/src/androidMain/res/values-en-rIN/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-en-rIN/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Dialogue"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Expanded"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Collapsed"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Toggle drop-down menu"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Dismiss"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Search"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Suggestions below"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-es-rUS/strings.xml b/compose/material3/material3/src/androidMain/res/values-es-rUS/strings.xml
index 64be6ea..5f613de 100644
--- a/compose/material3/material3/src/androidMain/res/values-es-rUS/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-es-rUS/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Diálogo"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Expandido"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Contraído"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Activar o desactivar menú desplegable"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Descartar"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Buscar"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Sugerencias a continuación"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-es/strings.xml b/compose/material3/material3/src/androidMain/res/values-es/strings.xml
index a770326..063f711 100644
--- a/compose/material3/material3/src/androidMain/res/values-es/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-es/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Cuadro de diálogo"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Desplegado"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Contraído"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Mostrar/ocultar menú desplegable"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Cerrar"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Buscar"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Sugerencias a continuación"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-et/strings.xml b/compose/material3/material3/src/androidMain/res/values-et/strings.xml
index dface1c..512cc41 100644
--- a/compose/material3/material3/src/androidMain/res/values-et/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-et/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Dialoog"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Laiendatud"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Ahendatud"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Rippmenüü lülitamine"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Loobu"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Otsing"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Soovitused on allpool"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-eu/strings.xml b/compose/material3/material3/src/androidMain/res/values-eu/strings.xml
index 2487d99..5353c99 100644
--- a/compose/material3/material3/src/androidMain/res/values-eu/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-eu/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Leihoa"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Zabalduta"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Tolestuta"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Zabaldu/Tolestu goitibeherako menua"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Baztertu"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Bilatu"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Iradokizunak daude behean"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-fi/strings.xml b/compose/material3/material3/src/androidMain/res/values-fi/strings.xml
index e3fb5e9..ca77732 100644
--- a/compose/material3/material3/src/androidMain/res/values-fi/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-fi/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Valintaikkuna"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Laajennettu"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Tiivistetty"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Laita avattava valikko päälle"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Ohita"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Hae"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Ehdotuksia alla"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-fr-rCA/strings.xml b/compose/material3/material3/src/androidMain/res/values-fr-rCA/strings.xml
index 57254bf..5548120 100644
--- a/compose/material3/material3/src/androidMain/res/values-fr-rCA/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-fr-rCA/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Dialogue"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Développé"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Réduit"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Ouvrir ou fermer le menu déroulant"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Fermer"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Recherche"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Suggestions ci-dessous"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-fr/strings.xml b/compose/material3/material3/src/androidMain/res/values-fr/strings.xml
index aeedebb..9c4fdfc 100644
--- a/compose/material3/material3/src/androidMain/res/values-fr/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-fr/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Boîte de dialogue"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Développé"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Réduit"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Activer/désactiver le menu déroulant"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Fermer"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Rechercher"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Suggestions ci-dessous"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-gl/strings.xml b/compose/material3/material3/src/androidMain/res/values-gl/strings.xml
index bb49fe7..5e96091 100644
--- a/compose/material3/material3/src/androidMain/res/values-gl/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-gl/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Cadro de diálogo"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Despregado"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Contraído"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Activa ou desactiva o menú despregable"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Pechar"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Buscar"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Hai suxestións abaixo"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-hu/strings.xml b/compose/material3/material3/src/androidMain/res/values-hu/strings.xml
index 558e144..28d4863 100644
--- a/compose/material3/material3/src/androidMain/res/values-hu/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-hu/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Párbeszédpanel"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Kibontva"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Összecsukva"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Legördülő menü átváltása"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Elvetés"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Keresés"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Javaslatok alább"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-hy/strings.xml b/compose/material3/material3/src/androidMain/res/values-hy/strings.xml
index c7111b0..bb0ef84 100644
--- a/compose/material3/material3/src/androidMain/res/values-hy/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-hy/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Երկխոսության պատուհան"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Ծավալված է"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Ծալված է"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Բացել/փակել իջնող ցանկը"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Փակել"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Որոնում"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Առաջարկները հասանելի են ստորև"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-it/strings.xml b/compose/material3/material3/src/androidMain/res/values-it/strings.xml
index dca7866..c3f0b06 100644
--- a/compose/material3/material3/src/androidMain/res/values-it/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-it/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Finestra di dialogo"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Espanso"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Compresso"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Attiva/disattiva menu a discesa"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Chiudi"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Cerca"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Suggerimenti sotto"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-iw/strings.xml b/compose/material3/material3/src/androidMain/res/values-iw/strings.xml
index 0bf5c61..4ce0a71 100644
--- a/compose/material3/material3/src/androidMain/res/values-iw/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-iw/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"תיבת דו-שיח"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"התפריט הנפתח מורחב"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"התפריט הנפתח מכווץ"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"החלפת המצב של התפריט הנפתח"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"סגירה"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"חיפוש"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"הצעות מופיעות למטה"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-ja/strings.xml b/compose/material3/material3/src/androidMain/res/values-ja/strings.xml
index 0a3593c..15894b9 100644
--- a/compose/material3/material3/src/androidMain/res/values-ja/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-ja/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"ダイアログ"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"開いています"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"閉じています"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"プルダウン メニューを切り替えます"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"閉じる"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"検索"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"検索候補は次のとおりです"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-ka/strings.xml b/compose/material3/material3/src/androidMain/res/values-ka/strings.xml
index acc03b8..bf58b02 100644
--- a/compose/material3/material3/src/androidMain/res/values-ka/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-ka/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"დიალოგი"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"გაფართოებული"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"ჩაკეცილი"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"გადართეთ ჩამოსაშლელი მენიუ"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"დახურვა"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"ძიება"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"შემოთავაზებები იხილეთ ქვემოთ"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-kk/strings.xml b/compose/material3/material3/src/androidMain/res/values-kk/strings.xml
index 8187675..8a1b7861 100644
--- a/compose/material3/material3/src/androidMain/res/values-kk/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-kk/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Диалогтік терезе"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Жайылды"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Жиылды"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Ашылмалы мәзірді ауыстыру"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Жабу"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Іздеу"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Төмендегі ұсыныстар"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-kn/strings.xml b/compose/material3/material3/src/androidMain/res/values-kn/strings.xml
index 85008b6..5962fab 100644
--- a/compose/material3/material3/src/androidMain/res/values-kn/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-kn/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"ಡೈಲಾಗ್"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"ವಿಸ್ತರಿಸಲಾಗಿದೆ"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"ಕುಗ್ಗಿಸಲಾಗಿದೆ"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"ಡ್ರಾಪ್ಡೌನ್ ಮೆನುವನ್ನು ಟಾಗಲ್ ಮಾಡಿ"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"ವಜಾಗೊಳಿಸಿ"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"ಹುಡುಕಿ"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"ಸಲಹೆಗಳನ್ನು ಕೆಳಗೆ ನೀಡಲಾಗಿದೆ"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-ko/strings.xml b/compose/material3/material3/src/androidMain/res/values-ko/strings.xml
index bfdfeb2..e39a2e2 100644
--- a/compose/material3/material3/src/androidMain/res/values-ko/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-ko/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"대화상자"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"펼침"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"접힘"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"전환 드롭다운 메뉴"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"닫기"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"검색"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"아래의 추천 검색어"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-lt/strings.xml b/compose/material3/material3/src/androidMain/res/values-lt/strings.xml
index 9a96cc5..4157437 100644
--- a/compose/material3/material3/src/androidMain/res/values-lt/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-lt/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Dialogo langas"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Išskleista"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Sutraukta"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Perjungti išskleidžiamąjį meniu"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Atsisakyti"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Paieška"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Pasiūlymai pateikti toliau"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-lv/strings.xml b/compose/material3/material3/src/androidMain/res/values-lv/strings.xml
index 7aaf2d9..fec1a52 100644
--- a/compose/material3/material3/src/androidMain/res/values-lv/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-lv/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Dialoglodziņš"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Izvērsta"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Sakļauta"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Pārslēgt nolaižamo izvēlni"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Nerādīt"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Meklēšana"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Tālāk ir sniegti ieteikumi"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-mk/strings.xml b/compose/material3/material3/src/androidMain/res/values-mk/strings.xml
index 6d5f51b..87aeea6 100644
--- a/compose/material3/material3/src/androidMain/res/values-mk/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-mk/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Дијалог"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Проширено"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Собрано"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Вклучување/исклучување паѓачко мени"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Отфрли"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Пребарување"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Предлозите се наведени подолу"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-mn/strings.xml b/compose/material3/material3/src/androidMain/res/values-mn/strings.xml
index 8df6c2d..419bc71 100644
--- a/compose/material3/material3/src/androidMain/res/values-mn/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-mn/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Харилцах цонх"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Дэлгэсэн"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Хураасан"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Унадаг цэсийг асаах/унтраах"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Хаах"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Хайх"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Доорх зөвлөмжүүд"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-mr/strings.xml b/compose/material3/material3/src/androidMain/res/values-mr/strings.xml
index 141f0bb..70e68f9 100644
--- a/compose/material3/material3/src/androidMain/res/values-mr/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-mr/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"डायलॉग"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"विस्तारित केला आहे"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"कोलॅप्स केला आहे"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"ड्रॉपडाउन मेनू टॉगल करा"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"डिसमिस करा"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"शोधा"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"सूचना खाली आहेत"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-my/strings.xml b/compose/material3/material3/src/androidMain/res/values-my/strings.xml
index 9bca021..a94a4b3 100644
--- a/compose/material3/material3/src/androidMain/res/values-my/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-my/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"ဒိုင်ယာလော့"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"ချဲ့ထားသည်"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"ချုံ့ထားသည်"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"ဆွဲချမီနူးကို ပြောင်းရန်"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"ပယ်ရန်"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"ရှာရန်"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"အကြံပြုချက်များသည် အောက်တွင်ရှိသည်"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-nb/strings.xml b/compose/material3/material3/src/androidMain/res/values-nb/strings.xml
index f18afdb5..7b79658 100644
--- a/compose/material3/material3/src/androidMain/res/values-nb/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-nb/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Dialogboks"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Vises"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Skjules"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Slå rullegardinmeny av/på"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Lukk"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Søk"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Du finner forslag nedenfor"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-nl/strings.xml b/compose/material3/material3/src/androidMain/res/values-nl/strings.xml
index 0dc1cb0..1070dab 100644
--- a/compose/material3/material3/src/androidMain/res/values-nl/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-nl/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Dialoogvenster"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Uitgevouwen"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Samengevouwen"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Dropdownmenu aan-/uitzetten"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Sluiten"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Zoeken"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Suggesties hieronder"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-pa/strings.xml b/compose/material3/material3/src/androidMain/res/values-pa/strings.xml
index b70e23d..037b577 100644
--- a/compose/material3/material3/src/androidMain/res/values-pa/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-pa/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"ਡਾਇਲੌਗ"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"ਵਿਸਤਾਰ ਕੀਤਾ ਗਿਆ"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"ਸਮੇਟਿਆ ਗਿਆ"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"ਡ੍ਰੌਪ-ਡਾਊਨ ਮੀਨੂ ਨੂੰ ਟੌਗਲ ਕਰੋ"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"ਖਾਰਜ ਕਰੋ"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"ਖੋਜੋ"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"ਸੁਝਾਅ ਹੇਠਾਂ ਹਨ"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-pt-rBR/strings.xml b/compose/material3/material3/src/androidMain/res/values-pt-rBR/strings.xml
index bb753a8..828b251 100644
--- a/compose/material3/material3/src/androidMain/res/values-pt-rBR/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-pt-rBR/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Caixa de diálogo"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Aberto"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Fechado"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Ativar/desativar o menu suspenso"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Dispensar"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Pesquisar"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Sugestões abaixo"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-pt/strings.xml b/compose/material3/material3/src/androidMain/res/values-pt/strings.xml
index bb753a8..828b251 100644
--- a/compose/material3/material3/src/androidMain/res/values-pt/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-pt/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Caixa de diálogo"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Aberto"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Fechado"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Ativar/desativar o menu suspenso"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Dispensar"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Pesquisar"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Sugestões abaixo"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-ro/strings.xml b/compose/material3/material3/src/androidMain/res/values-ro/strings.xml
index 077bd43..2045997 100644
--- a/compose/material3/material3/src/androidMain/res/values-ro/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-ro/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Dialog"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Extins"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Restrâns"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Comută meniul drop-down"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Închide"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Caută"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Sugestii mai jos"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-si/strings.xml b/compose/material3/material3/src/androidMain/res/values-si/strings.xml
index c638936..2dc21c0 100644
--- a/compose/material3/material3/src/androidMain/res/values-si/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-si/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"සංවාදය"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"දිග හරින ලදි"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"හකුළන ලදි"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"පතන මෙනුව ටොගල් කරන්න"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"අස් කරන්න"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"සෙවීම"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"පහත යෝජනා"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-sq/strings.xml b/compose/material3/material3/src/androidMain/res/values-sq/strings.xml
index 0465363..c76613d 100644
--- a/compose/material3/material3/src/androidMain/res/values-sq/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-sq/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Dialogu"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Zgjeruar"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Palosur"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Zgjero/palos menynë me lëshim poshtë"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Hiq"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Kërkimi"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Sugjerimet më poshtë"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-sv/strings.xml b/compose/material3/material3/src/androidMain/res/values-sv/strings.xml
index 45a0038..59d9068 100644
--- a/compose/material3/material3/src/androidMain/res/values-sv/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-sv/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Dialogruta"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Utökad"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Komprimerad"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Utöka/komprimera rullgardinsmeny"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Stäng"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Sök"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Se förslag nedan"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-ta/strings.xml b/compose/material3/material3/src/androidMain/res/values-ta/strings.xml
index cd65b2c..8ff4dbb 100644
--- a/compose/material3/material3/src/androidMain/res/values-ta/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-ta/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"உரையாடல்"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"விரிவாக்கப்பட்டது"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"சுருக்கப்பட்டது"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"கீழ்த்தோன்றல் மெனுவை நிலைமாற்றும்"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"நிராகரிக்கும்"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"தேடல்"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"பரிந்துரைகள் கீழே கிடைக்கும்"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-tr/strings.xml b/compose/material3/material3/src/androidMain/res/values-tr/strings.xml
index f5d84bf..110d0eb 100644
--- a/compose/material3/material3/src/androidMain/res/values-tr/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-tr/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Dialog"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Genişletildi"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Daraltıldı"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Açılır menüyü açın/kapatın"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Kapat"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Arama"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Önerileri aşağıda bulabilirsiniz"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-uk/strings.xml b/compose/material3/material3/src/androidMain/res/values-uk/strings.xml
index 3f4fca4..3ce4e58 100644
--- a/compose/material3/material3/src/androidMain/res/values-uk/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-uk/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Вікно"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Розгорнуто"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Згорнуто"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Згорнути або розгорнути спадне меню"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Закрити"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Пошук"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Підказки внизу"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-uz/strings.xml b/compose/material3/material3/src/androidMain/res/values-uz/strings.xml
index 36b567e..95be160 100644
--- a/compose/material3/material3/src/androidMain/res/values-uz/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-uz/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Muloqot oynasi"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Yoyilgan"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Yigʻilgan"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Pastga ochiluvchi menyuni koʻrsatish/yashirish"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Yopish"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Qidiruv"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Takliflar quyida"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-vi/strings.xml b/compose/material3/material3/src/androidMain/res/values-vi/strings.xml
index cb322a4..33eb1a6 100644
--- a/compose/material3/material3/src/androidMain/res/values-vi/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-vi/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Hộp thoại"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Đã mở rộng"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Đã thu gọn"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Bật/tắt trình đơn thả xuống"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Đóng"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Tìm kiếm"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Các đề xuất ở bên dưới"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-zh-rCN/strings.xml b/compose/material3/material3/src/androidMain/res/values-zh-rCN/strings.xml
index c2b04c2..839fc1b 100644
--- a/compose/material3/material3/src/androidMain/res/values-zh-rCN/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-zh-rCN/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"对话框"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"已展开"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"已收起"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"展开/收起下拉菜单"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"关闭"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"搜索"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"以下是搜索建议"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-zh-rHK/strings.xml b/compose/material3/material3/src/androidMain/res/values-zh-rHK/strings.xml
index 51b6d1c..d1e43fb 100644
--- a/compose/material3/material3/src/androidMain/res/values-zh-rHK/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-zh-rHK/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"對話框"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"已展開"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"已收合"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"切換下拉式選單"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"關閉"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"搜尋"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"建議如下"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-zh-rTW/strings.xml b/compose/material3/material3/src/androidMain/res/values-zh-rTW/strings.xml
index 39ce414..2c2dc9b 100644
--- a/compose/material3/material3/src/androidMain/res/values-zh-rTW/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-zh-rTW/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"對話方塊"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"已展開"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"已收合"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"切換鈕下拉式選單"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"關閉"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"搜尋"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"建議如下"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-zu/strings.xml b/compose/material3/material3/src/androidMain/res/values-zu/strings.xml
index ac7b6fa..cb3f162 100644
--- a/compose/material3/material3/src/androidMain/res/values-zu/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-zu/strings.xml
@@ -20,8 +20,7 @@
<string name="m3c_dialog" msgid="7617233117134790350">"Ibhokisi"</string>
<string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Kunwetshiwe"</string>
<string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Kugoqiwe"</string>
- <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
- <skip />
+ <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Guqula imenyu yokwehlayo"</string>
<string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Chitha"</string>
<string name="m3c_search_bar_search" msgid="6152806324422087846">"Sesha"</string>
<string name="m3c_suggestions_available" msgid="7655536806087401899">"Iziphakamiso ngezansi"</string>
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/NavigationItem.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/NavigationItem.kt
index e3d9b77..ccb4c3a 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/NavigationItem.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/NavigationItem.kt
@@ -68,6 +68,7 @@
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.offset
import androidx.compose.ui.util.fastFirst
+import androidx.compose.ui.util.fastFirstOrNull
import kotlin.math.max
import kotlin.math.roundToInt
@@ -474,11 +475,10 @@
): Int {
val iconHeight = measurables.fastFirst { it.layoutId == IconLayoutIdTag }
.maxIntrinsicHeight(width)
- val labelHeight = measurables.fastFirst { it.layoutId == LabelLayoutIdTag }
- .maxIntrinsicHeight(width)
- val paddings =
- (topIconItemVerticalPadding * 2 + indicatorVerticalPadding * 2 +
- indicatorToLabelVerticalPadding).roundToPx()
+ val labelHeight = measurables.fastFirstOrNull { it.layoutId == LabelLayoutIdTag }
+ ?.maxIntrinsicHeight(width) ?: 0
+ val paddings = (topIconItemVerticalPadding * 2 + indicatorVerticalPadding * 2 +
+ indicatorToLabelVerticalPadding).roundToPx()
return iconHeight + labelHeight + paddings
}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/AnchoredDraggable.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/AnchoredDraggable.kt
index cf714ea..7941e5a 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/AnchoredDraggable.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/AnchoredDraggable.kt
@@ -823,7 +823,7 @@
if (other !is DraggableAnchorsElement<*>) return false
if (state != other.state) return false
- if (anchors != other.anchors) return false
+ if (anchors !== other.anchors) return false
if (orientation != other.orientation) return false
return true
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLocal.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLocal.kt
index 5cf1202..0efe678 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLocal.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLocal.kt
@@ -155,7 +155,7 @@
previous
else null
is ComputedValueHolder ->
- if (value.compute == previous.compute)
+ if (value.compute === previous.compute)
previous
else null
else -> null
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
index 6e6bb2b..28e609f 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
@@ -1794,7 +1794,7 @@
): ((Any) -> Unit)? {
@Suppress("NAME_SHADOWING")
val parentObserver = if (mergeReadObserver) parentObserver else null
- return if (readObserver != null && parentObserver != null && readObserver != parentObserver) {
+ return if (readObserver != null && parentObserver != null && readObserver !== parentObserver) {
{ state: Any ->
readObserver(state)
parentObserver(state)
@@ -1806,7 +1806,7 @@
writeObserver: ((Any) -> Unit)?,
parentObserver: ((Any) -> Unit)?
): ((Any) -> Unit)? =
- if (writeObserver != null && parentObserver != null && writeObserver != parentObserver) {
+ if (writeObserver != null && parentObserver != null && writeObserver !== parentObserver) {
{ state: Any ->
writeObserver(state)
parentObserver(state)
diff --git a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/LayerManager.android.kt b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/LayerManager.android.kt
index 1b87de9..23b14d9 100644
--- a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/LayerManager.android.kt
+++ b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/LayerManager.android.kt
@@ -74,8 +74,12 @@
).also { imageReader = it }
val surface = reader.surface
val canvas = LockHardwareCanvasHelper.lockHardwareCanvas(surface)
- canvasHolder.drawInto(canvas) {
- layers.forEach { layer -> layer.draw(this, null) }
+ // on Robolectric even this canvas is not hardware accelerated and drawing render nodes
+ // are not supported
+ if (canvas.isHardwareAccelerated) {
+ canvasHolder.drawInto(canvas) {
+ layers.forEach { layer -> layer.draw(this, null) }
+ }
}
surface.unlockCanvasAndPost(canvas)
}
diff --git a/compose/ui/ui-inspection/generate-packages/compose_packages_list.txt b/compose/ui/ui-inspection/generate-packages/compose_packages_list.txt
index 46618a9..36c9a44 100644
--- a/compose/ui/ui-inspection/generate-packages/compose_packages_list.txt
+++ b/compose/ui/ui-inspection/generate-packages/compose_packages_list.txt
@@ -13,22 +13,26 @@
androidx.compose.foundation.lazy.staggeredgrid
androidx.compose.foundation.pager
androidx.compose.foundation.text
+androidx.compose.foundation.text.input
androidx.compose.foundation.text.selection
-androidx.compose.foundation.text2
-androidx.compose.foundation.text2.input
androidx.compose.foundation.window
androidx.compose.material
androidx.compose.material.internal
+androidx.compose.material.navigation
androidx.compose.material.pullrefresh
androidx.compose.material.ripple
androidx.compose.material3
androidx.compose.material3.adaptive
-androidx.compose.material3.adaptive.navigation.suite
+androidx.compose.material3.adaptive.layout
+androidx.compose.material3.adaptive.navigation
+androidx.compose.material3.adaptive.navigationsuite
+androidx.compose.material3.carousel
androidx.compose.material3.common
androidx.compose.material3.internal
androidx.compose.material3.pulltorefresh
androidx.compose.material3.windowsizeclass
androidx.compose.runtime
+androidx.compose.runtime.internal
androidx.compose.runtime.livedata
androidx.compose.runtime.mock
androidx.compose.runtime.reflect
@@ -37,6 +41,8 @@
androidx.compose.runtime.saveable
androidx.compose.ui
androidx.compose.ui.awt
+androidx.compose.ui.draw
+androidx.compose.ui.graphics
androidx.compose.ui.graphics.benchmark
androidx.compose.ui.graphics.vector
androidx.compose.ui.layout
diff --git a/compose/ui/ui-inspection/generate-packages/generate_compose_packages.py b/compose/ui/ui-inspection/generate-packages/generate_compose_packages.py
index 371c02b..2a8df1b 100755
--- a/compose/ui/ui-inspection/generate-packages/generate_compose_packages.py
+++ b/compose/ui/ui-inspection/generate-packages/generate_compose_packages.py
@@ -107,6 +107,7 @@
package = 'package androidx.compose.ui.inspection.inspector\n\n'
imports = (
'import androidx.annotation.VisibleForTesting\n'
+ 'import androidx.collection.intSetOf\n'
'import kotlin.math.absoluteValue\n\n'
)
package_name_hash_function = (
@@ -115,7 +116,7 @@
' packageName.fold(0) { hash, char -> hash * 31 + char.code }.absoluteValue\n\n'
)
system_packages_val = (
- 'val systemPackages = setOf(\n'
+ 'val systemPackages = intSetOf(\n'
' -1,\n'
'%s\n'
')\n' % (
diff --git a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/PackageHashes.kt b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/PackageHashes.kt
index df3b3cf..6bdbd8a 100644
--- a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/PackageHashes.kt
+++ b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/PackageHashes.kt
@@ -27,22 +27,26 @@
packageNameHash("androidx.compose.foundation.lazy.staggeredgrid"),
packageNameHash("androidx.compose.foundation.pager"),
packageNameHash("androidx.compose.foundation.text"),
+ packageNameHash("androidx.compose.foundation.text.input"),
packageNameHash("androidx.compose.foundation.text.selection"),
- packageNameHash("androidx.compose.foundation.text2"),
- packageNameHash("androidx.compose.foundation.text2.input"),
packageNameHash("androidx.compose.foundation.window"),
packageNameHash("androidx.compose.material"),
packageNameHash("androidx.compose.material.internal"),
+ packageNameHash("androidx.compose.material.navigation"),
packageNameHash("androidx.compose.material.pullrefresh"),
packageNameHash("androidx.compose.material.ripple"),
packageNameHash("androidx.compose.material3"),
packageNameHash("androidx.compose.material3.adaptive"),
- packageNameHash("androidx.compose.material3.adaptive.navigation.suite"),
+ packageNameHash("androidx.compose.material3.adaptive.layout"),
+ packageNameHash("androidx.compose.material3.adaptive.navigation"),
+ packageNameHash("androidx.compose.material3.adaptive.navigationsuite"),
+ packageNameHash("androidx.compose.material3.carousel"),
packageNameHash("androidx.compose.material3.common"),
packageNameHash("androidx.compose.material3.internal"),
packageNameHash("androidx.compose.material3.pulltorefresh"),
packageNameHash("androidx.compose.material3.windowsizeclass"),
packageNameHash("androidx.compose.runtime"),
+ packageNameHash("androidx.compose.runtime.internal"),
packageNameHash("androidx.compose.runtime.livedata"),
packageNameHash("androidx.compose.runtime.mock"),
packageNameHash("androidx.compose.runtime.reflect"),
@@ -51,6 +55,8 @@
packageNameHash("androidx.compose.runtime.saveable"),
packageNameHash("androidx.compose.ui"),
packageNameHash("androidx.compose.ui.awt"),
+ packageNameHash("androidx.compose.ui.draw"),
+ packageNameHash("androidx.compose.ui.graphics"),
packageNameHash("androidx.compose.ui.graphics.benchmark"),
packageNameHash("androidx.compose.ui.graphics.vector"),
packageNameHash("androidx.compose.ui.layout"),
diff --git a/compose/ui/ui-test/api/current.txt b/compose/ui/ui-test/api/current.txt
index 1ba2f23..e374fff 100644
--- a/compose/ui/ui-test/api/current.txt
+++ b/compose/ui/ui-test/api/current.txt
@@ -389,13 +389,18 @@
method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void animateAlong(androidx.compose.ui.test.MouseInjectionScope, kotlin.jvm.functions.Function1<? super java.lang.Long,androidx.compose.ui.geometry.Offset> curve, optional long durationMillis);
method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void animateBy(androidx.compose.ui.test.MouseInjectionScope, long delta, optional long durationMillis);
method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void animateTo(androidx.compose.ui.test.MouseInjectionScope, long position, optional long durationMillis);
- method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void click(androidx.compose.ui.test.MouseInjectionScope, optional long position);
- method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void doubleClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
- method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void dragAndDrop(androidx.compose.ui.test.MouseInjectionScope, long start, long end, optional long durationMillis);
- method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void longClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
+ method @Deprecated @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void click(androidx.compose.ui.test.MouseInjectionScope, optional long position);
+ method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void click(androidx.compose.ui.test.MouseInjectionScope, optional long position, optional int button);
+ method @Deprecated @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void doubleClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
+ method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void doubleClick(androidx.compose.ui.test.MouseInjectionScope, optional long position, optional int button);
+ method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void dragAndDrop(androidx.compose.ui.test.MouseInjectionScope, long start, long end, optional int button, optional long durationMillis);
+ method @Deprecated @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void dragAndDrop(androidx.compose.ui.test.MouseInjectionScope, long start, long end, optional long durationMillis);
+ method @Deprecated @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void longClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
+ method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void longClick(androidx.compose.ui.test.MouseInjectionScope, optional long position, optional int button);
method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void rightClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void smoothScroll(androidx.compose.ui.test.MouseInjectionScope, float scrollAmount, optional long durationMillis, optional int scrollWheel);
- method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void tripleClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
+ method @Deprecated @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void tripleClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
+ method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void tripleClick(androidx.compose.ui.test.MouseInjectionScope, optional long position, optional int button);
}
public sealed interface MultiModalInjectionScope extends androidx.compose.ui.test.InjectionScope {
diff --git a/compose/ui/ui-test/api/restricted_current.txt b/compose/ui/ui-test/api/restricted_current.txt
index e482d77..fb5c367 100644
--- a/compose/ui/ui-test/api/restricted_current.txt
+++ b/compose/ui/ui-test/api/restricted_current.txt
@@ -390,13 +390,18 @@
method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void animateAlong(androidx.compose.ui.test.MouseInjectionScope, kotlin.jvm.functions.Function1<? super java.lang.Long,androidx.compose.ui.geometry.Offset> curve, optional long durationMillis);
method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void animateBy(androidx.compose.ui.test.MouseInjectionScope, long delta, optional long durationMillis);
method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void animateTo(androidx.compose.ui.test.MouseInjectionScope, long position, optional long durationMillis);
- method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void click(androidx.compose.ui.test.MouseInjectionScope, optional long position);
- method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void doubleClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
- method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void dragAndDrop(androidx.compose.ui.test.MouseInjectionScope, long start, long end, optional long durationMillis);
- method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void longClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
+ method @Deprecated @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void click(androidx.compose.ui.test.MouseInjectionScope, optional long position);
+ method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void click(androidx.compose.ui.test.MouseInjectionScope, optional long position, optional int button);
+ method @Deprecated @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void doubleClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
+ method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void doubleClick(androidx.compose.ui.test.MouseInjectionScope, optional long position, optional int button);
+ method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void dragAndDrop(androidx.compose.ui.test.MouseInjectionScope, long start, long end, optional int button, optional long durationMillis);
+ method @Deprecated @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void dragAndDrop(androidx.compose.ui.test.MouseInjectionScope, long start, long end, optional long durationMillis);
+ method @Deprecated @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void longClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
+ method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void longClick(androidx.compose.ui.test.MouseInjectionScope, optional long position, optional int button);
method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void rightClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void smoothScroll(androidx.compose.ui.test.MouseInjectionScope, float scrollAmount, optional long durationMillis, optional int scrollWheel);
- method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void tripleClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
+ method @Deprecated @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void tripleClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
+ method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void tripleClick(androidx.compose.ui.test.MouseInjectionScope, optional long position, optional int button);
}
public sealed interface MultiModalInjectionScope extends androidx.compose.ui.test.InjectionScope {
diff --git a/compose/ui/ui-test/samples/src/main/java/androidx/compose/ui/test/samples/MouseInjectionScopeSamples.kt b/compose/ui/ui-test/samples/src/main/java/androidx/compose/ui/test/samples/MouseInjectionScopeSamples.kt
index 2535abb..f162158 100644
--- a/compose/ui/ui-test/samples/src/main/java/androidx/compose/ui/test/samples/MouseInjectionScopeSamples.kt
+++ b/compose/ui/ui-test/samples/src/main/java/androidx/compose/ui/test/samples/MouseInjectionScopeSamples.kt
@@ -17,31 +17,90 @@
package androidx.compose.ui.test.samples
import androidx.annotation.Sampled
+import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.ScrollWheel
+import androidx.compose.ui.test.animateAlong
+import androidx.compose.ui.test.animateTo
import androidx.compose.ui.test.click
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performMouseInput
+import androidx.compose.ui.test.smoothScroll
+import kotlin.math.PI
+import kotlin.math.cos
+import kotlin.math.sin
@OptIn(ExperimentalTestApi::class)
@Sampled
fun mouseInputClick() {
composeTestRule.onNodeWithTag("myComponent")
.performMouseInput {
+ // Click in the middle of the node
click(center)
}
}
@OptIn(ExperimentalTestApi::class)
@Sampled
-fun mouseInputScrollWhileDown() {
+fun mouseInputAnimateTo() {
composeTestRule.onNodeWithTag("myComponent")
.performMouseInput {
+ // Hover over the node, making an X shape
+ moveTo(topLeft)
+ animateTo(bottomRight)
+ // Note that an actual user wouldn't be able to instantly
+ // move from the bottom right to the top right
+ moveTo(topRight)
+ animateTo(bottomLeft)
+ }
+}
+
+@OptIn(ExperimentalTestApi::class)
+@Sampled
+fun mouseInputAnimateAlong() {
+ composeTestRule.onNodeWithTag("myComponent")
+ .performMouseInput {
+ // Hover over the node, making a full circle with a radius of 100px
+ val r = 100f
+ animateAlong(
+ curve = {
+ val angle = 2 * PI * it / 1000
+ center + Offset(r * cos(angle).toFloat(), r * sin(angle).toFloat())
+ },
+ durationMillis = 1000L
+ )
+ }
+}
+
+@OptIn(ExperimentalTestApi::class)
+@Sampled
+fun mouseInputScrollWhileDown() {
+ composeTestRule.onNodeWithTag("verticalScrollable")
+ // Scroll downwards while keeping a button pressed:
+ .performMouseInput {
+ // Presses the primary mouse button
press()
+ // Scroll the scroll wheel by 6 units
repeat(6) {
advanceEventTime()
- scroll(-1f)
+ scroll(1f)
}
+ // And release the mouse button
advanceEventTime()
release()
}
}
+
+@OptIn(ExperimentalTestApi::class)
+@Sampled
+fun mouseInputSmoothScroll() {
+ composeTestRule.onNodeWithTag("horizontalScrollable")
+ .performMouseInput {
+ // Scroll forwards horizontally, which is rightwards
+ // unless scroll direction is reversed
+ smoothScroll(100f, durationMillis = 500L, ScrollWheel.Horizontal)
+ // The 100f scroll delta is equally divided into smaller scrolls,
+ // such that the time in between two scroll events is more or less
+ // equal to the default time between events, 16ms.
+ }
+}
diff --git a/compose/ui/ui-test/src/androidCommonTest/kotlin/androidx/compose/ui/test/util/Verifications.kt b/compose/ui/ui-test/src/androidCommonTest/kotlin/androidx/compose/ui/test/util/Verifications.kt
index 489ecf0..f0a814a 100644
--- a/compose/ui/ui-test/src/androidCommonTest/kotlin/androidx/compose/ui/test/util/Verifications.kt
+++ b/compose/ui/ui-test/src/androidCommonTest/kotlin/androidx/compose/ui/test/util/Verifications.kt
@@ -223,9 +223,14 @@
* Verifies that the [Offset] is equal to the given position with some tolerance. The default
* tolerance is 0.001.
*/
-fun Offset.isAlmostEqualTo(position: Offset, tolerance: Float = 1e-3f) {
- assertThat(x).isAlmostEqualTo(position.x, tolerance)
- assertThat(y).isAlmostEqualTo(position.y, tolerance)
+fun Offset.isAlmostEqualTo(position: Offset, tolerance: Float = 1e-3f, message: String? = null) {
+ if (message != null) {
+ assertWithMessage(message).that(x).isAlmostEqualTo(position.x, tolerance)
+ assertWithMessage(message).that(y).isAlmostEqualTo(position.y, tolerance)
+ } else {
+ assertThat(x).isAlmostEqualTo(position.x, tolerance)
+ assertThat(y).isAlmostEqualTo(position.y, tolerance)
+ }
}
/**
diff --git a/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/injectionscope/mouse/ClickTest.kt b/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/injectionscope/mouse/ClickTest.kt
index 822384e..2881f1e 100644
--- a/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/injectionscope/mouse/ClickTest.kt
+++ b/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/injectionscope/mouse/ClickTest.kt
@@ -16,22 +16,54 @@
package androidx.compose.ui.test.injectionscope.mouse
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.background
+import androidx.compose.foundation.gestures.draggable2D
+import androidx.compose.foundation.gestures.rememberDraggable2DState
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.offset
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
import androidx.compose.testutils.expectError
+import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.PointerEventType.Companion.Enter
import androidx.compose.ui.input.pointer.PointerEventType.Companion.Exit
import androidx.compose.ui.input.pointer.PointerEventType.Companion.Move
import androidx.compose.ui.input.pointer.PointerEventType.Companion.Press
import androidx.compose.ui.input.pointer.PointerEventType.Companion.Release
+import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.InputDispatcher
import androidx.compose.ui.test.MouseButton
+import androidx.compose.ui.test.click
+import androidx.compose.ui.test.doubleClick
+import androidx.compose.ui.test.dragAndDrop
+import androidx.compose.ui.test.injectionscope.mouse.Common.ClickDuration
+import androidx.compose.ui.test.injectionscope.mouse.Common.DefaultDoubleClickTimeMillis
+import androidx.compose.ui.test.injectionscope.mouse.Common.DefaultLongClickTimeMillis
import androidx.compose.ui.test.injectionscope.mouse.Common.PrimaryButton
import androidx.compose.ui.test.injectionscope.mouse.Common.PrimarySecondaryButton
+import androidx.compose.ui.test.injectionscope.mouse.Common.SecondaryButton
import androidx.compose.ui.test.injectionscope.mouse.Common.runMouseInputInjectionTest
import androidx.compose.ui.test.injectionscope.mouse.Common.verifyMouseEvent
+import androidx.compose.ui.test.longClick
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performMouseInput
+import androidx.compose.ui.test.rightClick
+import androidx.compose.ui.test.runComposeUiTest
+import androidx.compose.ui.test.tripleClick
+import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.dp
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
+import com.google.common.truth.Truth.assertWithMessage
+import kotlin.math.roundToInt
import org.junit.Test
import org.junit.runner.RunWith
@@ -45,6 +77,7 @@
private val positionMove1 = Offset(2f, 2f)
private val positionMove2 = Offset(3f, 3f)
private val positionOut = Offset(101f, 101f)
+ private val positionCenter = Offset(50f, 50f)
}
@Test
@@ -190,4 +223,130 @@
{ verifyMouseEvent(1 * T, Press, true, positionIn, PrimaryButton) },
)
)
+
+ @Test
+ fun clickTest() = runMouseInputInjectionTest(
+ mouseInput = {
+ click()
+ },
+ eventVerifiers = arrayOf(
+ // t = 0, because click() presses immediately
+ { verifyMouseEvent(0, Enter, false, positionCenter) },
+ { verifyMouseEvent(0, Press, true, positionCenter, PrimaryButton) },
+ { verifyMouseEvent(ClickDuration, Release, false, positionCenter) },
+ )
+ )
+
+ @Test
+ fun rightClickTest() = runMouseInputInjectionTest(
+ mouseInput = {
+ rightClick()
+ },
+ eventVerifiers = arrayOf(
+ // t = 0, because click() presses immediately
+ { verifyMouseEvent(0, Enter, false, positionCenter) },
+ { verifyMouseEvent(0, Press, true, positionCenter, SecondaryButton) },
+ { verifyMouseEvent(ClickDuration, Release, false, positionCenter) },
+ )
+ )
+
+ @Test
+ fun doubleClickTest() {
+ // Time starts at 0, because doubleClick() presses immediately
+ val press1 = 0L
+ val release1 = press1 + ClickDuration
+ val press2 = release1 + DefaultDoubleClickTimeMillis
+ val release2 = press2 + ClickDuration
+
+ runMouseInputInjectionTest(
+ mouseInput = {
+ doubleClick()
+ },
+ eventVerifiers = arrayOf(
+ { verifyMouseEvent(press1, Enter, false, positionCenter) },
+ { verifyMouseEvent(press1, Press, true, positionCenter, PrimaryButton) },
+ { verifyMouseEvent(release1, Release, false, positionCenter) },
+ { verifyMouseEvent(press2, Press, true, positionCenter, PrimaryButton) },
+ { verifyMouseEvent(release2, Release, false, positionCenter) },
+ )
+ )
+ }
+
+ @Test
+ fun tripleClickTest() {
+ // Time starts at 0, because tripleClick() presses immediately
+ val press1 = 0L
+ val release1 = press1 + ClickDuration
+ val press2 = release1 + DefaultDoubleClickTimeMillis
+ val release2 = press2 + ClickDuration
+ val press3 = release2 + DefaultDoubleClickTimeMillis
+ val release3 = press3 + ClickDuration
+
+ runMouseInputInjectionTest(
+ mouseInput = {
+ tripleClick()
+ },
+ eventVerifiers = arrayOf(
+ { verifyMouseEvent(press1, Enter, false, positionCenter) },
+ { verifyMouseEvent(press1, Press, true, positionCenter, PrimaryButton) },
+ { verifyMouseEvent(release1, Release, false, positionCenter) },
+ { verifyMouseEvent(press2, Press, true, positionCenter, PrimaryButton) },
+ { verifyMouseEvent(release2, Release, false, positionCenter) },
+ { verifyMouseEvent(press3, Press, true, positionCenter, PrimaryButton) },
+ { verifyMouseEvent(release3, Release, false, positionCenter) },
+ )
+ )
+ }
+
+ @Test
+ fun longClickTest() = runMouseInputInjectionTest(
+ mouseInput = {
+ longClick()
+ },
+ eventVerifiers = arrayOf(
+ // t = 0, because longClick() presses immediately
+ { verifyMouseEvent(0L, Enter, false, positionCenter) },
+ { verifyMouseEvent(0L, Press, true, positionCenter, PrimaryButton) },
+ // longClick adds 100ms to the minimum required time, just to be sure
+ { verifyMouseEvent(DefaultLongClickTimeMillis + 100, Release, false, positionCenter) },
+ )
+ )
+
+ // Rather than checking the events sent on, for this more complex mouse gesture we
+ // check if the events actually lead to the expected outcome.
+ @Test
+ fun dragAndDropTest() = runComposeUiTest {
+ val sizeDp = 50.dp
+ val sizePx = with(density) { sizeDp.toPx() }
+ val marginPx = with(density) { 0.5.dp.toPx() }
+
+ var xOffsetPx by mutableStateOf(0f)
+ var yOffsetPx by mutableStateOf(0f)
+
+ setContent {
+ @OptIn(ExperimentalFoundationApi::class)
+ Box(Modifier.padding(16.dp).fillMaxSize()) {
+ Box(
+ Modifier
+ .testTag("draggable-box")
+ .offset { IntOffset(xOffsetPx.roundToInt(), yOffsetPx.roundToInt()) }
+ .size(sizeDp)
+ .background(Color.Red)
+ .draggable2D(
+ rememberDraggable2DState {
+ xOffsetPx += it.x
+ yOffsetPx += it.y
+ }
+ )
+ )
+ }
+ }
+
+ onNodeWithTag("draggable-box").performMouseInput {
+ dragAndDrop(center, center + Offset(2f * width, 4f * height))
+ }
+ waitForIdle()
+ assertWithMessage("xOffset").that(xOffsetPx).isWithin(marginPx).of(2 * sizePx)
+ assertWithMessage("yOffset").that(yOffsetPx).isWithin(marginPx).of(4 * sizePx)
+ }
}
diff --git a/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/injectionscope/mouse/Common.kt b/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/injectionscope/mouse/Common.kt
index 1612be4..fa93172 100644
--- a/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/injectionscope/mouse/Common.kt
+++ b/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/injectionscope/mouse/Common.kt
@@ -16,6 +16,8 @@
package androidx.compose.ui.test.injectionscope.mouse
+import androidx.compose.testutils.TestViewConfiguration
+import androidx.compose.testutils.WithViewConfiguration
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.pointer.PointerButtons
import androidx.compose.ui.input.pointer.PointerEventType
@@ -38,6 +40,18 @@
val PrimarySecondaryButton = PointerButtons(
MouseButton.Primary.buttonId or MouseButton.Secondary.buttonId
)
+ val SecondaryButton = PointerButtons(MouseButton.Secondary.buttonId)
+
+ const val ClickDuration = 60L // MouseInjectionScope.SingleClickDelayMillis
+ private const val DoubleClickMin = 40L
+ private const val DoubleClickMax = 200L
+ const val DefaultDoubleClickTimeMillis = (DoubleClickMin + DoubleClickMax) / 2
+ const val DefaultLongClickTimeMillis = 300L
+ private val testViewConfiguration = TestViewConfiguration(
+ doubleTapMinTimeMillis = DoubleClickMin,
+ doubleTapTimeoutMillis = DoubleClickMax,
+ longPressTimeoutMillis = DefaultLongClickTimeMillis
+ )
fun runMouseInputInjectionTest(
mouseInput: MouseInjectionScope.() -> Unit,
@@ -46,7 +60,9 @@
mainClock.autoAdvance = false
val recorder = SinglePointerInputRecorder()
setContent {
- ClickableTestBox(recorder)
+ WithViewConfiguration(testViewConfiguration) {
+ ClickableTestBox(recorder)
+ }
}
onNodeWithTag(ClickableTestBox.defaultTag).performMouseInput(mouseInput)
runOnIdle { recorder.verifyEvents(*eventVerifiers) }
diff --git a/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/util/PointerInputs.kt b/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/util/PointerInputs.kt
index ce31fd62..9e47232 100644
--- a/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/util/PointerInputs.kt
+++ b/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/util/PointerInputs.kt
@@ -198,19 +198,20 @@
expectedButtons: PointerButtons = PointerButtons(0),
expectedKeyboardModifiers: PointerKeyboardModifiers = PointerKeyboardModifiers(0),
) {
+ val s = " of $this"
if (expectedTimestamp != null) {
- assertWithMessage("timestamp").that(timestamp).isEqualTo(expectedTimestamp)
+ assertWithMessage("timestamp$s").that(timestamp).isEqualTo(expectedTimestamp)
}
if (expectedId != null) {
- assertWithMessage("pointerId").that(id).isEqualTo(expectedId)
+ assertWithMessage("pointerId$s").that(id).isEqualTo(expectedId)
}
- assertWithMessage("isDown").that(down).isEqualTo(expectedDown)
- assertWithMessage("position").that(position).isEqualTo(expectedPosition)
- assertWithMessage("pointerType").that(pointerType).isEqualTo(expectedPointerType)
- assertWithMessage("eventType").that(eventType).isEqualTo(expectedEventType)
- assertWithMessage("scrollDelta").that(scrollDelta).isEqualTo(expectedScrollDelta)
- assertWithMessage("buttonsDown").that(buttons).isEqualTo(expectedButtons)
- assertWithMessage("keyModifiers").that(keyboardModifiers).isEqualTo(expectedKeyboardModifiers)
+ assertWithMessage("isDown$s").that(down).isEqualTo(expectedDown)
+ position.isAlmostEqualTo(expectedPosition, message = "position$s")
+ assertWithMessage("pointerType$s").that(pointerType).isEqualTo(expectedPointerType)
+ assertWithMessage("eventType$s").that(eventType).isEqualTo(expectedEventType)
+ scrollDelta.isAlmostEqualTo(expectedScrollDelta, message = "scrollDelta$s")
+ assertWithMessage("buttonsDown$s").that(buttons).isEqualTo(expectedButtons)
+ assertWithMessage("keyModifiers$s").that(keyboardModifiers).isEqualTo(expectedKeyboardModifiers)
}
/**
diff --git a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/MouseInjectionScope.kt b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/MouseInjectionScope.kt
index 36c5fbc..5261179 100644
--- a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/MouseInjectionScope.kt
+++ b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/MouseInjectionScope.kt
@@ -173,12 +173,8 @@
fun cancel(delayMillis: Long = eventPeriodMillis)
/**
- * Sends a hover enter event at the given [position], [delayMillis] after the last sent event.
- *
- * Note that it is discouraged to manually send a hover enter event followed by a [moveTo]
- * event. [moveTo] does this for you automatically, making sure the event times of the two
- * events are in sync. Only use this method for special scenarios where the hover enter event
- * is not sent as a side effect of another event.
+ * Sends a hover enter event at the given [position], [delayMillis] after the last sent event,
+ * without sending a hover move event.
*
* An [IllegalStateException] will be thrown when mouse buttons are down, or if the mouse is
* already hovering.
@@ -186,6 +182,12 @@
* The [position] is in the node's local coordinate system, where (0, 0) is the top left
* corner of the node.
*
+ * __Note__: enter and exit events are already sent as a side effect of [movement][moveTo]
+ * when necessary. Whether or not this is part of the contract of mouse events is platform
+ * dependent, so it is highly discouraged to manually send enter or exit events.
+ * Only use this method for tests that need to make assertions about a component's state
+ * _in between_ the enter/exit and move event.
+ *
* @param position The new position of the mouse, in the node's local coordinate system.
* [currentPosition] by default.
* @param delayMillis The time between the last sent event and this event.
@@ -194,19 +196,20 @@
fun enter(position: Offset = currentPosition, delayMillis: Long = eventPeriodMillis)
/**
- * Sends a hover exit event at the given [position], [delayMillis] after the last sent event.
- *
- * Note that it is discouraged to manually send a hover exit event followed by a [moveTo]
- * that is outside the boundaries of the Compose root or [press]ing a button. These methods
- * do this for you automatically, making sure the event times of the two events are in sync.
- * Only use this method for special scenarios where the hover exit event is not sent as a
- * side effect of another event.
+ * Sends a hover exit event at the given [position], [delayMillis] after the last sent event,
+ * without sending a hover move event.
*
* An [IllegalStateException] will be thrown if the mouse was not hovering.
*
* The [position] is in the node's local coordinate system, where (0, 0) is the top left
* corner of the node.
*
+ * __Note__: enter and exit events are already sent as a side effect of [movement][moveTo]
+ * when necessary. Whether or not this is part of the contract of mouse events is platform
+ * dependent, so it is highly discouraged to manually send enter or exit events.
+ * Only use this method for tests that need to make assertions about a component's state
+ * _in between_ the enter/exit and move event.
+ *
* @param position The new position of the mouse, in the node's local coordinate system
* [currentPosition] by default.
* @param delayMillis The time between the last sent event and this event.
@@ -227,6 +230,9 @@
* of `64.dp`. However, on any platform, this conversion factor could change in the
* future to improve the mouse scroll experience.
*
+ * Example of how scroll could be used:
+ * @sample androidx.compose.ui.test.samples.mouseInputScrollWhileDown
+ *
* @param delta The amount of scroll
* @param scrollWheel Which scroll wheel to rotate. Can be either [ScrollWheel.Vertical] (the
* default) or [ScrollWheel.Horizontal].
@@ -285,23 +291,37 @@
}
}
+@Deprecated(
+ message = "Replaced by an overload that takes a button parameter",
+ replaceWith = ReplaceWith("click(position)"),
+ level = DeprecationLevel.HIDDEN
+)
+@ExperimentalTestApi
+fun MouseInjectionScope.click(position: Offset = center) = click(position)
+
/**
- * Click on [position], or on the current mouse position if [position] is
+ * Use [button] to click on [position], or on the current mouse position if [position] is
* [unspecified][Offset.Unspecified]. The [position] is in the node's local coordinate system,
- * where (0, 0) is the top left corner of the node.
+ * where (0, 0) is the top left corner of the node. The default [button] is the
+ * [primary][MouseButton.Primary] button. There is a small 60ms delay between the press and
+ * release events to have a realistic simulation.
*
* @param position The position where to click, in the node's local coordinate system. If
* omitted, the [center] of the node will be used. If [unspecified][Offset.Unspecified], clicks
* on the current mouse position.
+ * @param button The button to click with. Uses the [primary][MouseButton.Primary] by default.
*/
@ExperimentalTestApi
-fun MouseInjectionScope.click(position: Offset = center) {
+fun MouseInjectionScope.click(
+ position: Offset = center,
+ button: MouseButton = MouseButton.Primary
+) {
if (position.isSpecified) {
updatePointerTo(position)
}
- press(MouseButton.Primary)
+ press(button)
advanceEventTime(SingleClickDelayMillis)
- release(MouseButton.Primary)
+ release(button)
}
/**
@@ -316,70 +336,103 @@
* on the current mouse position.
*/
@ExperimentalTestApi
-fun MouseInjectionScope.rightClick(position: Offset = center) {
- if (position.isSpecified) {
- updatePointerTo(position)
- }
- press(MouseButton.Secondary)
- advanceEventTime(SingleClickDelayMillis)
- release(MouseButton.Secondary)
-}
+fun MouseInjectionScope.rightClick(position: Offset = center) =
+ click(position, MouseButton.Secondary)
// The average of min and max is a safe default
private val ViewConfiguration.defaultDoubleTapDelayMillis: Long
get() = (doubleTapMinTimeMillis + doubleTapTimeoutMillis) / 2
-/**
- * Double-click on [position], or on the current mouse position if [position] is
- * [unspecified][Offset.Unspecified]. The [position] is in the node's local coordinate system,
- * where (0, 0) is the top left corner of the node.
- *
- * @param position The position where to click, in the node's local coordinate system. If
- * omitted, the [center] of the node will be used. If [unspecified][Offset.Unspecified], clicks
- * on the current mouse position.
- */
+@Deprecated(
+ message = "Replaced by an overload that takes a button parameter",
+ replaceWith = ReplaceWith("doubleClick(position)"),
+ level = DeprecationLevel.HIDDEN
+)
@ExperimentalTestApi
-fun MouseInjectionScope.doubleClick(position: Offset = center) {
- click(position)
- advanceEventTime(viewConfiguration.defaultDoubleTapDelayMillis)
- click(position)
-}
+fun MouseInjectionScope.doubleClick(position: Offset = center) = doubleClick(position)
/**
- * Triple-click on [position], or on the current mouse position if [position] is
+ * Use [button] to double-click on [position], or on the current mouse position if [position] is
* [unspecified][Offset.Unspecified]. The [position] is in the node's local coordinate system,
- * where (0, 0) is the top left corner of the node.
+ * where (0, 0) is the top left corner of the node. The default [button] is the
+ * [primary][MouseButton.Primary] button.
*
* @param position The position where to click, in the node's local coordinate system. If
* omitted, the [center] of the node will be used. If [unspecified][Offset.Unspecified], clicks
* on the current mouse position.
+ * @param button The button to click with. Uses the [primary][MouseButton.Primary] by default.
*/
@ExperimentalTestApi
-fun MouseInjectionScope.tripleClick(position: Offset = center) {
- click(position)
+fun MouseInjectionScope.doubleClick(
+ position: Offset = center,
+ button: MouseButton = MouseButton.Primary
+) {
+ click(position, button)
advanceEventTime(viewConfiguration.defaultDoubleTapDelayMillis)
- click(position)
- advanceEventTime(viewConfiguration.defaultDoubleTapDelayMillis)
- click(position)
+ click(position, button)
}
+@Deprecated(
+ message = "Replaced by an overload that takes a button parameter",
+ replaceWith = ReplaceWith("tripleClick(position)"),
+ level = DeprecationLevel.HIDDEN
+)
+@ExperimentalTestApi
+fun MouseInjectionScope.tripleClick(position: Offset = center) = tripleClick(position)
+
/**
- * Long-click on [position], or on the current mouse position if [position] is
+ * Use [button] to triple-click on [position], or on the current mouse position if [position] is
* [unspecified][Offset.Unspecified]. The [position] is in the node's local coordinate system,
- * where (0, 0) is the top left corner of the node.
+ * where (0, 0) is the top left corner of the node. The default [button] is the
+ * [primary][MouseButton.Primary] button.
*
* @param position The position where to click, in the node's local coordinate system. If
* omitted, the [center] of the node will be used. If [unspecified][Offset.Unspecified], clicks
* on the current mouse position.
+ * @param button The button to click with. Uses the [primary][MouseButton.Primary] by default.
*/
@ExperimentalTestApi
-fun MouseInjectionScope.longClick(position: Offset = center) {
+fun MouseInjectionScope.tripleClick(
+ position: Offset = center,
+ button: MouseButton = MouseButton.Primary
+) {
+ click(position, button)
+ advanceEventTime(viewConfiguration.defaultDoubleTapDelayMillis)
+ click(position, button)
+ advanceEventTime(viewConfiguration.defaultDoubleTapDelayMillis)
+ click(position, button)
+}
+
+@Deprecated(
+ message = "Replaced by an overload that takes a button parameter",
+ replaceWith = ReplaceWith("longClick(position)"),
+ level = DeprecationLevel.HIDDEN
+)
+@ExperimentalTestApi
+fun MouseInjectionScope.longClick(position: Offset = center) = longClick(position)
+
+/**
+ * Use [button] to long-click on [position], or on the current mouse position if [position] is
+ * [unspecified][Offset.Unspecified]. The [position] is in the node's local coordinate system,
+ * where (0, 0) is the top left corner of the node. The default [button] is the
+ * [primary][MouseButton.Primary] button.
+ *
+ * @param position The position where to click, in the node's local coordinate system. If
+ * omitted, the [center] of the node will be used. If [unspecified][Offset.Unspecified], clicks
+ * on the current mouse position.
+ * @param button The button to click with. Uses the [primary][MouseButton.Primary] by default.
+ */
+@ExperimentalTestApi
+fun MouseInjectionScope.longClick(
+ position: Offset = center,
+ button: MouseButton = MouseButton.Primary
+) {
if (position.isSpecified) {
updatePointerTo(position)
}
- press(MouseButton.Primary)
+ press(button)
advanceEventTime(viewConfiguration.longPressTimeoutMillis + 100L)
- release(MouseButton.Primary)
+ release(button)
}
/**
@@ -389,6 +442,9 @@
* a different position. The [position] is in the node's local coordinate system, where (0, 0) is
* the top left corner of the node.
*
+ * Example of moving the mouse along a line:
+ * @sample androidx.compose.ui.test.samples.mouseInputAnimateTo
+ *
* @param position The position where to move the mouse to, in the node's local coordinate system
* @param durationMillis The duration of the gesture. By default 300 milliseconds.
*/
@@ -429,6 +485,9 @@
* path, `curve(0)`, if it is not already there. The positions defined by the [curve] are in the
* node's local coordinate system, where (0, 0) is the top left corner of the node.
*
+ * Example of moving the mouse along a curve:
+ * @sample androidx.compose.ui.test.samples.mouseInputAnimateAlong
+ *
* @param curve The function that defines the position of the mouse over time for this gesture,
* in the node's local coordinate system.
* @param durationMillis The duration of the gesture. By default 300 milliseconds.
@@ -461,29 +520,42 @@
}
}
+@Deprecated(
+ message = "Replaced by an overload that takes a button parameter",
+ replaceWith = ReplaceWith("dragAndDrop(start, end, durationMillis = durationMillis)"),
+ level = DeprecationLevel.HIDDEN
+)
+@ExperimentalTestApi
+fun MouseInjectionScope.dragAndDrop(
+ start: Offset,
+ end: Offset,
+ durationMillis: Long = DefaultMouseGestureDurationMillis
+) = dragAndDrop(start, end, durationMillis = durationMillis)
+
/**
- * Drag and drop something from [start] to [end] in [durationMillis] milliseconds. This gesture
- * uses the primary mouse button to drag with, and does not reset any mouse buttons prior to
- * starting the gesture. The mouse position is [updated][MouseInjectionScope.updatePointerTo] to
- * the start position before starting the gesture. The positions defined by the [start] and [end]
- * are in the node's local coordinate system, where (0, 0) is the top left corner of the node.
+ * Use [button] to drag and drop something from [start] to [end] in [durationMillis] milliseconds.
+ * The mouse position is [updated][MouseInjectionScope.updatePointerTo] to the start position
+ * before starting the gesture. The positions defined by the [start] and [end] are in the node's
+ * local coordinate system, where (0, 0) is the top left corner of the node.
*
* @param start The position where to press the primary mouse button and initiate the drag, in
* the node's local coordinate system.
* @param end The position where to release the primary mouse button and end the drag, in the
* node's local coordinate system.
+ * @param button The button to drag with. Uses the [primary][MouseButton.Primary] by default.
* @param durationMillis The duration of the gesture. By default 300 milliseconds.
*/
@ExperimentalTestApi
fun MouseInjectionScope.dragAndDrop(
start: Offset,
end: Offset,
+ button: MouseButton = MouseButton.Primary,
durationMillis: Long = DefaultMouseGestureDurationMillis
) {
updatePointerTo(start)
- press(MouseButton.Primary)
+ press(button)
animateTo(end, durationMillis)
- release(MouseButton.Primary)
+ release(button)
}
/**
@@ -494,6 +566,9 @@
* bottom of a column, or at the end of a row), negative values correspond to scrolling backward
* (new content appears at the top of a column, or at the start of a row).
*
+ * Example of a horizontal smooth scroll:
+ * @sample androidx.compose.ui.test.samples.mouseInputSmoothScroll
+ *
* @param scrollAmount The total delta to scroll the [scrollWheel] by
* @param durationMillis The duration of the gesture. By default 300 milliseconds.
* @param scrollWheel Which scroll wheel will be rotated. By default [ScrollWheel.Vertical].
diff --git a/compose/ui/ui-tooling/build.gradle b/compose/ui/ui-tooling/build.gradle
index cb5c42f..98f9161 100644
--- a/compose/ui/ui-tooling/build.gradle
+++ b/compose/ui/ui-tooling/build.gradle
@@ -138,7 +138,7 @@
description = "Compose tooling library. This library exposes information to our tools for better IDE support."
legacyDisableKotlinStrictApiMode = true
samples(project(":compose:animation:animation:animation-samples"))
- // samples(project(":compose:animation:animation-core:animation-core-samples"))TODO(b/318840087)
+ // samples(project(":compose:animation:animation-core:animation-core-samples")) TODO(b/318840087)
}
android {
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt
index ce24620..2ca13db 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt
@@ -391,7 +391,7 @@
Executors.newFixedThreadPool(3).asCoroutineDispatcher()
),
ViewLayerContainer(activity),
- {},
+ { _, _ -> },
{}).apply {
val scope = ReusableGraphicsLayerScope()
scope.cameraDistance = cameraDistance
@@ -431,7 +431,7 @@
Executors.newFixedThreadPool(3).asCoroutineDispatcher()
),
ViewLayerContainer(activity),
- {},
+ { _, _ -> },
{}
).apply {
val scope = ReusableGraphicsLayerScope()
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/draw/DrawingPrebuiltGraphicsLayerTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/draw/DrawingPrebuiltGraphicsLayerTest.kt
index a2ae451..868bf43 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/draw/DrawingPrebuiltGraphicsLayerTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/draw/DrawingPrebuiltGraphicsLayerTest.kt
@@ -48,7 +48,6 @@
import androidx.test.filters.SdkSuppress
import com.google.common.truth.Truth.assertThat
import org.junit.After
-import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -259,7 +258,9 @@
.assertPixels(expectedSize) { Color.Red }
}
- @Ignore("remove annotation when Modifier.graphicsLayer() will use the same layer mechanism")
+ // TODO remove sdk suppress when we start using new layers as Modifier.graphicsLayer() on
+ // older versions.
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
@Test
fun keepDrawingNestedLayers_graphicsLayerModifier() {
rule.setContent {
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/AndroidPointerInputTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/AndroidPointerInputTest.kt
index b20ed84..e9bd13b 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/AndroidPointerInputTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/AndroidPointerInputTest.kt
@@ -92,7 +92,6 @@
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
-import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -537,13 +536,7 @@
}
}
- // Currently ignored because it fails when run via command line. Runs successfully in Android
- // Studio.
@Test
- // TODO(b/158099918): For some reason, this test fails when run from command line but passes
- // when run from Android Studio. This seems to be caused by b/158099918. Once that is
- // fixed, @Ignore can be removed.
- @Ignore
fun dispatchTouchEvent_throughLayersOfAndroidAndCompose_hitsChildWithCorrectCoords() {
// Arrange
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/HitPathTrackerTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/HitPathTrackerTest.kt
index ae09d76..d1b40df 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/HitPathTrackerTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/HitPathTrackerTest.kt
@@ -4167,7 +4167,7 @@
}
override fun createLayer(
- drawBlock: (Canvas) -> Unit,
+ drawBlock: (Canvas, GraphicsLayer?) -> Unit,
invalidateParentLayer: () -> Unit,
explicitLayer: GraphicsLayer?
): OwnedLayer {
@@ -4188,7 +4188,7 @@
}
override fun drawLayer(canvas: Canvas, parentLayer: GraphicsLayer?) {
- drawBlock(canvas)
+ drawBlock(canvas, parentLayer)
}
override fun updateDisplayList() {
@@ -4204,7 +4204,7 @@
}
override fun reuseLayer(
- drawBlock: (Canvas) -> Unit,
+ drawBlock: (Canvas, GraphicsLayer?) -> Unit,
invalidateParentLayer: () -> Unit
) {
}
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessorTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessorTest.kt
index 80c407a..5e072bd 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessorTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessorTest.kt
@@ -3421,7 +3421,7 @@
}
override fun createLayer(
- drawBlock: (Canvas) -> Unit,
+ drawBlock: (Canvas, GraphicsLayer?) -> Unit,
invalidateParentLayer: () -> Unit,
explicitLayer: GraphicsLayer?
): OwnedLayer {
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 d015749..84b683c 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
@@ -25,6 +25,7 @@
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue
+import androidx.compose.testutils.assertModifierIsPure
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.node.DelegatingNode
@@ -35,6 +36,7 @@
import androidx.compose.ui.test.assertHeightIsEqualTo
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performTouchInput
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
@@ -45,6 +47,7 @@
import com.google.common.truth.Truth.assertThat
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
+import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.map
@@ -597,6 +600,28 @@
}
@Test
+ @SmallTest
+ fun testEquality_key() {
+ val block: suspend PointerInputScope.() -> Unit = {}
+
+ assertModifierIsPure { toggleInput ->
+ Modifier.pointerInput(toggleInput, block = block)
+ }
+ }
+
+ @Test
+ @SmallTest
+ fun testEquality_block() {
+ val block1: suspend PointerInputScope.() -> Unit = {}
+ val block2: suspend PointerInputScope.() -> Unit = {}
+
+ assertModifierIsPure { toggleInput ->
+ val block = if (toggleInput) block1 else block2
+ Modifier.pointerInput(Unit, block = block)
+ }
+ }
+
+ @Test
@MediumTest
fun testRestartPointerInputWithTouchEvent() {
val emitter = PointerInputChangeEmitter()
@@ -931,34 +956,145 @@
}
@Test
- fun pointerInput_badStartingSinglePointer_composeIgnores() {
- val events = mutableListOf<PointerEventType>()
- val tag = "input rect"
+ @MediumTest
+ fun testUpdatingKey1RestartsPointerInput() {
+ val tag = "box"
+ var key1 by mutableStateOf(false)
+ var cancelled = false
+
rule.setContent {
Box(
- Modifier.fillMaxSize()
+ Modifier
.testTag(tag)
- .pointerInput(Unit) {
- awaitPointerEventScope {
- while (true) {
- val event = awaitPointerEvent()
- events += event.type
- }
+ .fillMaxSize()
+ .pointerInput(key1 = key1) {
+ try {
+ suspendCancellableCoroutine<Unit> {}
+ } catch (e: CancellationException) {
+ cancelled = true
}
}
)
}
- rule.onNodeWithTag(tag).performTouchInput {
- // Starts gestures 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(Offset(Float.NaN, Float.NaN)) // Compose ignores
- moveBy(0, Offset(10f, 10f)) // Compose ignores because first was invalid
- up() // Compose ignores because first was invalid
+ rule.onNodeWithTag(tag).performClick()
+
+ rule.runOnIdle {
+ assertThat(cancelled).isFalse()
}
- assertThat(events).hasSize(0)
- assertThat(events).containsExactly()
+
+ key1 = true
+
+ rule.runOnIdle {
+ assertThat(cancelled).isTrue()
+ }
+ }
+
+ @Test
+ @MediumTest
+ fun testUpdatingKey2RestartsPointerInput() {
+ val tag = "box"
+ var key2 by mutableStateOf(false)
+ var cancelled = false
+
+ rule.setContent {
+ Box(
+ Modifier
+ .testTag(tag)
+ .fillMaxSize()
+ .pointerInput(key1 = Unit, key2 = key2) {
+ try {
+ suspendCancellableCoroutine<Unit> {}
+ } catch (e: CancellationException) {
+ cancelled = true
+ }
+ }
+ )
+ }
+
+ rule.onNodeWithTag(tag).performClick()
+
+ rule.runOnIdle {
+ assertThat(cancelled).isFalse()
+ }
+
+ key2 = true
+
+ rule.runOnIdle {
+ assertThat(cancelled).isTrue()
+ }
+ }
+
+ @Test
+ @MediumTest
+ fun testUpdatingKeysRestartsPointerInput() {
+ val tag = "box"
+ var keys by mutableStateOf(arrayOf(false))
+ var cancelled = false
+
+ rule.setContent {
+ Box(
+ Modifier
+ .testTag(tag)
+ .fillMaxSize()
+ .pointerInput(keys = keys) {
+ try {
+ suspendCancellableCoroutine<Unit> {}
+ } catch (e: CancellationException) {
+ cancelled = true
+ }
+ }
+ )
+ }
+
+ rule.onNodeWithTag(tag).performClick()
+
+ rule.runOnIdle {
+ assertThat(cancelled).isFalse()
+ }
+
+ keys = arrayOf(true)
+
+ rule.runOnIdle {
+ assertThat(cancelled).isTrue()
+ }
+ }
+
+ @Test
+ @MediumTest
+ fun testUpdatingBlockDoesNotRestartPointerInput() {
+ val tag = "box"
+ var cancelled = false
+ val lambda1: suspend PointerInputScope.() -> Unit = {
+ try {
+ suspendCancellableCoroutine<Unit> {}
+ } catch (e: CancellationException) {
+ cancelled = true
+ }
+ }
+ val lambda2: suspend PointerInputScope.() -> Unit = {}
+ var block by mutableStateOf(lambda1)
+
+ rule.setContent {
+ Box(
+ Modifier
+ .testTag(tag)
+ .fillMaxSize()
+ .pointerInput(key1 = Unit, key2 = Unit, block = block)
+ )
+ }
+
+ rule.onNodeWithTag(tag).performClick()
+
+ rule.runOnIdle {
+ assertThat(cancelled).isFalse()
+ }
+
+ block = lambda2
+
+ rule.runOnIdle {
+ assertThat(cancelled).isFalse()
+ }
}
// Tests pointerInput with bad pointer data
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/Helpers.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/Helpers.kt
index 316e860..e8557cf 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/Helpers.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/Helpers.kt
@@ -211,7 +211,7 @@
get() = TODO("Not yet implemented")
override fun createLayer(
- drawBlock: (Canvas) -> Unit,
+ drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit,
invalidateParentLayer: () -> Unit,
explicitLayer: GraphicsLayer?
) = createLayer()
@@ -601,7 +601,7 @@
}
override fun reuseLayer(
- drawBlock: (Canvas) -> Unit,
+ drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit,
invalidateParentLayer: () -> Unit
) {
}
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/node/NodeChainTester.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/node/NodeChainTester.kt
index 0b4ff31..c2ec417 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/node/NodeChainTester.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/node/NodeChainTester.kt
@@ -484,7 +484,7 @@
TODO("Not yet implemented")
}
override fun createLayer(
- drawBlock: (Canvas) -> Unit,
+ drawBlock: (Canvas, GraphicsLayer?) -> Unit,
invalidateParentLayer: () -> Unit,
explicitLayer: GraphicsLayer?
): OwnedLayer {
@@ -495,7 +495,7 @@
override fun move(position: IntOffset) {}
override fun resize(size: IntSize) {}
override fun drawLayer(canvas: Canvas, parentLayer: GraphicsLayer?) {
- drawBlock(canvas)
+ drawBlock(canvas, parentLayer)
}
override fun updateDisplayList() {}
override fun invalidate() { invalidatedLayers.add(this) }
@@ -505,7 +505,7 @@
override fun inverseTransform(matrix: Matrix) { matrix.timesAssign(inverseTransform) }
override fun mapOffset(point: Offset, inverse: Boolean) = point
override fun reuseLayer(
- drawBlock: (Canvas) -> Unit,
+ drawBlock: (Canvas, GraphicsLayer?) -> Unit,
invalidateParentLayer: () -> Unit
) {}
override fun updateLayerProperties(
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/node/NodeChainTests.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/node/NodeChainTests.kt
index 6d74a3a..99d5b96 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/node/NodeChainTests.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/node/NodeChainTests.kt
@@ -50,8 +50,8 @@
val a = AttachedStateDebuggerNode()
val b = AttachedStateDebuggerNode()
chainTester()
- .withModifierNodes(a, b)
.attach()
+ .withModifierNodes(a, b)
.validateAttached()
check(a.localIsAttached)
@@ -67,8 +67,8 @@
val c = object : NodeModifierElementNode(AttachedStateDebuggerNode()) {}
chainTester()
- .withModifiers(a)
.attach()
+ .withModifiers(a)
.validateAttached()
.withModifiers(c, a, b)
.validateAttached()
@@ -196,8 +196,8 @@
val a = modifierA()
val b = modifierB()
val modifierInfo = chainTester()
- .withModifiers(a, b)
.attach()
+ .withModifiers(a, b)
.chain
.getModifierInfo()
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/scrollcapture/ScrollCaptureDrawTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/scrollcapture/ScrollCaptureDrawTest.kt
index 17d7a57..fcaecc7 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/scrollcapture/ScrollCaptureDrawTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/scrollcapture/ScrollCaptureDrawTest.kt
@@ -34,14 +34,14 @@
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.core.graphics.applyCanvas
import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.MediumTest
+import androidx.test.filters.LargeTest
import androidx.test.filters.SdkSuppress
import com.google.common.truth.Truth.assertThat
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-@MediumTest
+@LargeTest
@RunWith(AndroidJUnit4::class)
@SdkSuppress(minSdkVersion = 31)
class ScrollCaptureDrawTest {
@@ -186,13 +186,99 @@
assertThat(scrollState.value).isEqualTo(5)
}
+ @Test
+ fun capture_drawsScrollContents_fromTop_withCaptureHeightFullViewport_reverseScrolling() =
+ captureTester.runTest {
+ val scrollState = ScrollState(0)
+ captureTester.setContent {
+ TestContent(scrollState, reverseScrolling = true)
+ }
+ val target = captureTester.findCaptureTargets().single()
+ val bitmaps = captureTester.captureBitmapsVertically(target, captureHeight = 10)
+ assertThat(bitmaps).hasSize(3)
+ bitmaps.joinVerticallyToBitmap().use { joined ->
+ joined.assertRect(Rect(0, 0, 10, 9), Color.Red)
+ joined.assertRect(Rect(0, 10, 10, 18), Color.Blue)
+ joined.assertRect(Rect(0, 19, 10, 27), Color.Green)
+ }
+ }
+
+ @Test
+ fun capture_drawsScrollContents_fromMiddle_withCaptureHeightFullViewport_reverseScrolling() =
+ captureTester.runTest {
+ val scrollState = ScrollState(0)
+ captureTester.setContent {
+ TestContent(scrollState, reverseScrolling = true)
+ }
+
+ scrollState.scrollTo(scrollState.maxValue / 2)
+
+ val target = captureTester.findCaptureTargets().single()
+ val bitmaps = captureTester.captureBitmapsVertically(target, captureHeight = 10)
+ assertThat(bitmaps).hasSize(3)
+ bitmaps.joinVerticallyToBitmap().use { joined ->
+ joined.assertRect(Rect(0, 0, 10, 9), Color.Red)
+ joined.assertRect(Rect(0, 10, 10, 18), Color.Blue)
+ joined.assertRect(Rect(0, 19, 10, 27), Color.Green)
+ }
+ }
+
+ @Test
+ fun capture_drawsScrollContents_fromBottom_withCaptureHeightFullViewport_reverseScrolling() =
+ captureTester.runTest {
+ val scrollState = ScrollState(0)
+ captureTester.setContent {
+ TestContent(scrollState, reverseScrolling = true)
+ }
+
+ scrollState.scrollTo(scrollState.maxValue)
+
+ val target = captureTester.findCaptureTargets().single()
+ val bitmaps = captureTester.captureBitmapsVertically(target, captureHeight = 10)
+ assertThat(bitmaps).hasSize(3)
+ bitmaps.joinVerticallyToBitmap().use { joined ->
+ joined.assertRect(Rect(0, 0, 10, 9), Color.Red)
+ joined.assertRect(Rect(0, 10, 10, 18), Color.Blue)
+ joined.assertRect(Rect(0, 19, 10, 27), Color.Green)
+ }
+ }
+
+ @Test
+ fun capture_resetsScrollPosition_from0_reverseScrolling() = captureTester.runTest {
+ val scrollState = ScrollState(0)
+ captureTester.setContent {
+ TestContent(scrollState, reverseScrolling = true)
+ }
+ val target = captureTester.findCaptureTargets().single()
+ val bitmaps = captureTester.captureBitmapsVertically(target, captureHeight = 10)
+ bitmaps.forEach { it.recycle() }
+ rule.awaitIdle()
+ assertThat(scrollState.value).isEqualTo(0)
+ }
+
+ @Test
+ fun capture_resetsScrollPosition_fromNonZero_reverseScrolling() = captureTester.runTest {
+ val scrollState = ScrollState(5)
+ captureTester.setContent {
+ TestContent(scrollState, reverseScrolling = true)
+ }
+ val target = captureTester.findCaptureTargets().single()
+ val bitmaps = captureTester.captureBitmapsVertically(target, captureHeight = 10)
+ bitmaps.forEach { it.recycle() }
+ rule.awaitIdle()
+ assertThat(scrollState.value).isEqualTo(5)
+ }
+
@Composable
- private fun TestContent(scrollState: ScrollState) {
+ private fun TestContent(
+ scrollState: ScrollState,
+ reverseScrolling: Boolean = false,
+ ) {
with(LocalDensity.current) {
Column(
Modifier
.size(10.toDp())
- .verticalScroll(scrollState)
+ .verticalScroll(scrollState, reverseScrolling = reverseScrolling)
) {
Box(
Modifier
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/scrollcapture/ScrollCaptureTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/scrollcapture/ScrollCaptureTest.kt
index f805517..9232f12 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/scrollcapture/ScrollCaptureTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/scrollcapture/ScrollCaptureTest.kt
@@ -372,6 +372,56 @@
}
@Test
+ fun callbackOnImageCapture_scrollsBackwardsThenForwards_reverseScrolling() =
+ captureTester.runTest {
+ expectingScrolls(rule) {
+ val size = 10
+ val captureHeight = size / 2
+ captureTester.setContent {
+ TestVerticalScrollable(
+ reverseScrolling = true,
+ size = size,
+ // Can't be a reference, see https://youtrack.jetbrains.com/issue/KT-49665
+ onScrollByOffset = { respondToScrollExpectation(it) }
+ )
+ }
+
+ val target = captureTester.findCaptureTargets().single()
+ captureTester.capture(target, captureHeight) {
+ // First request is at origin, no scrolling required.
+ assertThat(performCaptureDiscardingBitmap()).isEqualTo(Rect(0, 0, 10, 5))
+ assertNoPendingScrollRequests()
+
+ // Back one half-page, but only respond to part of it.
+ expectScrollRequest(Offset(0f, 5f), consume = Offset(0f, 4f))
+ shiftWindowBy(-5)
+ assertThat(performCaptureDiscardingBitmap()).isEqualTo(Rect(0, -4, 10, 0))
+
+ // Forward one half-page – already in viewport, no scrolling required.
+ shiftWindowBy(5)
+ assertThat(performCaptureDiscardingBitmap()).isEqualTo(Rect(0, 0, 10, 5))
+ assertNoPendingScrollRequests()
+
+ // Forward another half-page. This time we need to scroll.
+ expectScrollRequest(Offset(0f, -4f))
+ shiftWindowBy(5)
+ assertThat(performCaptureDiscardingBitmap()).isEqualTo(Rect(0, 5, 10, 10))
+
+ // Forward another half-page, scroll again so now we're past the original
+ // viewport.
+ expectScrollRequest(Offset(0f, -5f))
+ shiftWindowBy(5)
+ assertThat(performCaptureDiscardingBitmap()).isEqualTo(Rect(0, 10, 10, 15))
+
+ // When capture ends expect one last scroll request to reset to original offset.
+ // Note that this request will be made _after_ this capture{} lambda returns.
+ expectScrollRequest(Offset(0f, 5f))
+ }
+ assertNoPendingScrollRequests()
+ }
+ }
+
+ @Test
fun captureSession_setsScrollCaptureInProgress_inSameComposition() = captureTester.runTest {
var isScrollCaptureInProgressValue = false
captureTester.setContent {
@@ -429,6 +479,7 @@
size: Int = 10,
maxValue: Float = 1f,
onScrollByOffset: suspend (Offset) -> Offset = { Offset.Zero },
+ reverseScrolling: Boolean = false,
content: (@Composable () -> Unit)? = null
) {
with(LocalDensity.current) {
@@ -437,6 +488,7 @@
ScrollAxisRange(
value = { 0f },
maxValue = { updatedMaxValue },
+ reverseScrolling = reverseScrolling,
)
}
Box(
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/AndroidViewTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/AndroidViewTest.kt
index 3e56cd1..d8bee52 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/AndroidViewTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/AndroidViewTest.kt
@@ -179,9 +179,8 @@
.inflate(R.layout.test_multiple_invalidation_layout, null)
customView = view.findViewById<InvalidatedTextView>(R.id.custom_draw_view)
customView!!.timesToInvalidate = timesToInvalidate
- view.viewTreeObserver?.addOnPreDrawListener {
+ customView!!.onDraw = {
++drawCount
- true
}
view
})
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/InvalidatedTextView.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/InvalidatedTextView.kt
index 4b2583a1..08276eb 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/InvalidatedTextView.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/InvalidatedTextView.kt
@@ -31,6 +31,7 @@
class InvalidatedTextView : TextView {
var timesDrawn: Int = 0
var timesToInvalidate: Int = 0
+ var onDraw: () -> Unit = {}
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
@@ -46,5 +47,6 @@
}
super.draw(canvas)
++timesDrawn
+ onDraw()
}
}
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 5e9e671..4013394 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
@@ -175,6 +175,7 @@
import androidx.compose.ui.platform.coreshims.ViewCompatShims
import androidx.compose.ui.scrollcapture.ScrollCapture
import androidx.compose.ui.semantics.EmptySemanticsElement
+import androidx.compose.ui.semantics.EmptySemanticsModifier
import androidx.compose.ui.semantics.SemanticsOwner
import androidx.compose.ui.semantics.findClosestParentNode
import androidx.compose.ui.text.font.Font
@@ -248,7 +249,8 @@
override var density by mutableStateOf(Density(context), referentialEqualityPolicy())
private set
- private val semanticsModifier = EmptySemanticsElement
+ private val rootSemanticsNode = EmptySemanticsModifier()
+ private val semanticsModifier = EmptySemanticsElement(rootSemanticsNode)
override val focusOwner: FocusOwner = FocusOwnerImpl(
onRequestApplyChangesListener = ::registerOnEndApplyChangesListener,
@@ -408,7 +410,7 @@
override val rootForTest: RootForTest = this
- override val semanticsOwner: SemanticsOwner = SemanticsOwner(root)
+ override val semanticsOwner: SemanticsOwner = SemanticsOwner(root, rootSemanticsNode)
private val composeAccessibilityDelegate =
AndroidComposeViewAccessibilityDelegateCompat(this)
internal var contentCaptureManager = AndroidContentCaptureManager(
@@ -1404,12 +1406,18 @@
}
override fun createLayer(
- drawBlock: (Canvas) -> Unit,
+ drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit,
invalidateParentLayer: () -> Unit,
explicitLayer: GraphicsLayer?
): OwnedLayer {
if (explicitLayer != null) {
- return GraphicsLayerOwnerLayer(explicitLayer, this, drawBlock, invalidateParentLayer)
+ return GraphicsLayerOwnerLayer(
+ graphicsLayer = explicitLayer,
+ context = null,
+ ownerView = this,
+ drawBlock = drawBlock,
+ invalidateParentLayer = invalidateParentLayer
+ )
}
// First try the layer cache
val layer = layerCache.pop()
@@ -1423,6 +1431,15 @@
// the ViewLayer implementation. We'll try even on on P devices, but it will fail
// until ART allows things on the unsupported list on P.
if (isHardwareAccelerated && SDK_INT >= M && isRenderNodeCompatible) {
+ if (SDK_INT >= Q) {
+ return GraphicsLayerOwnerLayer(
+ graphicsLayer = graphicsContext.createGraphicsLayer(),
+ context = graphicsContext,
+ ownerView = this,
+ drawBlock = drawBlock,
+ invalidateParentLayer = invalidateParentLayer
+ )
+ }
try {
return RenderNodeLayer(
this,
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/GraphicsLayerOwnerLayer.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/GraphicsLayerOwnerLayer.android.kt
index cecabef..12737fd 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/GraphicsLayerOwnerLayer.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/GraphicsLayerOwnerLayer.android.kt
@@ -16,18 +16,30 @@
package androidx.compose.ui.platform
+import android.os.Build
import androidx.compose.ui.geometry.MutableRect
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.isUnspecified
import androidx.compose.ui.graphics.Canvas
+import androidx.compose.ui.graphics.CompositingStrategy as OldCompositingStrategy
+import androidx.compose.ui.graphics.Fields
+import androidx.compose.ui.graphics.GraphicsContext
import androidx.compose.ui.graphics.Matrix
+import androidx.compose.ui.graphics.Outline
+import androidx.compose.ui.graphics.Paint
import androidx.compose.ui.graphics.Path
+import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.ReusableGraphicsLayerScope
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.graphics.drawscope.CanvasDrawScope
import androidx.compose.ui.graphics.drawscope.draw
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
+import androidx.compose.ui.graphics.layer.CompositingStrategy
import androidx.compose.ui.graphics.layer.GraphicsLayer
import androidx.compose.ui.graphics.layer.drawLayer
+import androidx.compose.ui.graphics.layer.setOutline
+import androidx.compose.ui.graphics.nativeCanvas
import androidx.compose.ui.internal.throwIllegalStateException
import androidx.compose.ui.layout.GraphicLayerInfo
import androidx.compose.ui.node.OwnedLayer
@@ -41,18 +53,21 @@
internal class GraphicsLayerOwnerLayer(
private val graphicsLayer: GraphicsLayer,
+ // when we have a context it means the object is created by us and we need to release it
+ private val context: GraphicsContext?,
private val ownerView: AndroidComposeView,
- drawBlock: (Canvas) -> Unit,
+ drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit,
invalidateParentLayer: () -> Unit
) : OwnedLayer, GraphicLayerInfo {
- private var drawBlock: ((Canvas) -> Unit)? = drawBlock
+ private var drawBlock: ((canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit)? = drawBlock
private var invalidateParentLayer: (() -> Unit)? = invalidateParentLayer
- private var size: IntSize = IntSize.Zero
+ private var size: IntSize = IntSize(Int.MAX_VALUE, Int.MAX_VALUE)
private var isDestroyed = false
private val matrixCache = Matrix()
+ private var inverseMatrixCache: Matrix? = null
- private var isDirty = true
+ private var isDirty = false
set(value) {
if (value != field) {
field = value
@@ -63,19 +78,127 @@
private var density = Density(1f)
private var layoutDirection = LayoutDirection.Ltr
private val scope = CanvasDrawScope()
-
- private var tmpTouchPointPath: Path? = null
- private var tmpOpPath: Path? = null
+ private var mutatedFields: Int = 0
+ private var transformOrigin: TransformOrigin = TransformOrigin.Center
+ private var shape: Shape = RectangleShape
+ private var tmpPath: Path? = null
+ /**
+ * Optional paint used when the RenderNode is rendered on a software backed
+ * canvas and is somewhat transparent (i.e. alpha less than 1.0f)
+ */
+ private var softwareLayerPaint: Paint? = null
override fun updateLayerProperties(
scope: ReusableGraphicsLayerScope,
layoutDirection: LayoutDirection,
density: Density,
) {
- throwIllegalStateException(
- "Current apis doesn't allow for both GraphicsLayer and GraphicsLayerScope to be " +
- "used together"
- )
+ var maybeChangedFields = scope.mutatedFields or mutatedFields
+ if (this.layoutDirection != layoutDirection || this.density != density) {
+ this.layoutDirection = layoutDirection
+ this.density = density
+ maybeChangedFields = maybeChangedFields or Fields.Shape
+ }
+ if (maybeChangedFields and Fields.TransformOrigin != 0) {
+ this.transformOrigin = scope.transformOrigin
+ }
+ if (maybeChangedFields and Fields.ScaleX != 0) {
+ graphicsLayer.scaleX = scope.scaleX
+ }
+ if (maybeChangedFields and Fields.ScaleY != 0) {
+ graphicsLayer.scaleY = scope.scaleY
+ }
+ if (maybeChangedFields and Fields.Alpha != 0) {
+ graphicsLayer.alpha = scope.alpha
+ }
+ if (maybeChangedFields and Fields.TranslationX != 0) {
+ graphicsLayer.translationX = scope.translationX
+ }
+ if (maybeChangedFields and Fields.TranslationY != 0) {
+ graphicsLayer.translationY = scope.translationY
+ }
+ if (maybeChangedFields and Fields.ShadowElevation != 0) {
+ graphicsLayer.shadowElevation = scope.shadowElevation
+ // TODO We should somehow move it into the android specific GraphicsLayer
+ // implementation where the code enabling Z is located. It is not yet clear how we
+ // can trigger the full layer invalidation from there when such changes happen, but
+ // seems like we have to figure it out. This issue is tracked in b/333862760
+ if (scope.shadowElevation > 0f && !drawnWithEnabledZ) {
+ // we need to redraw with enabling Z
+ invalidateParentLayer?.invoke()
+ }
+ }
+ if (maybeChangedFields and Fields.AmbientShadowColor != 0) {
+ graphicsLayer.ambientShadowColor = scope.ambientShadowColor
+ }
+ if (maybeChangedFields and Fields.SpotShadowColor != 0) {
+ graphicsLayer.spotShadowColor = scope.spotShadowColor
+ }
+ if (maybeChangedFields and Fields.RotationZ != 0) {
+ graphicsLayer.rotationZ = scope.rotationZ
+ }
+ if (maybeChangedFields and Fields.RotationX != 0) {
+ graphicsLayer.rotationX = scope.rotationX
+ }
+ if (maybeChangedFields and Fields.RotationY != 0) {
+ graphicsLayer.rotationY = scope.rotationY
+ }
+ if (maybeChangedFields and Fields.CameraDistance != 0) {
+ graphicsLayer.cameraDistance = scope.cameraDistance
+ }
+ if (maybeChangedFields and Fields.TransformOrigin != 0) {
+ graphicsLayer.pivotOffset = Offset(
+ transformOrigin.pivotFractionX * size.width,
+ transformOrigin.pivotFractionY * size.height
+ )
+ }
+ if (maybeChangedFields and Fields.Shape != 0) {
+ this.shape = scope.shape
+ updateOutline()
+ }
+ if (maybeChangedFields and Fields.Clip != 0) {
+ graphicsLayer.clip = scope.clip
+ }
+ if (maybeChangedFields and Fields.RenderEffect != 0) {
+ graphicsLayer.renderEffect = scope.renderEffect
+ }
+ if (maybeChangedFields and Fields.CompositingStrategy != 0) {
+ graphicsLayer.compositingStrategy = when (scope.compositingStrategy) {
+ OldCompositingStrategy.Auto -> CompositingStrategy.Auto
+ OldCompositingStrategy.Offscreen -> CompositingStrategy.Offscreen
+ OldCompositingStrategy.ModulateAlpha -> CompositingStrategy.ModulateAlpha
+ else -> throw IllegalStateException("Not supported composition strategy")
+ }
+ }
+
+ mutatedFields = scope.mutatedFields
+ if (maybeChangedFields != 0) {
+ triggerRepaint()
+ }
+ }
+
+ // TODO: GraphicsLayer api should be doing it on its own every time any layer property
+ // has been updated. This issue is tracked in b/329417380.
+ private fun triggerRepaint() {
+ // onDescendantInvalidated is only supported on O+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ WrapperRenderNodeLayerHelperMethods.onDescendantInvalidated(ownerView)
+ } else {
+ ownerView.invalidate()
+ }
+ }
+
+ private fun updateOutline() {
+ val outline = shape.createOutline(size.toSize(), layoutDirection, density)
+ graphicsLayer.setOutline(outline)
+ if (outline is Outline.Generic && Build.VERSION.SDK_INT < 33) {
+ // before 33 many of the paths are not clipping by rendernode. instead we have to
+ // manually clip on a canvas. it means we have redraw the parent layer when it changes
+ // TODO We should somehow move it into the android specific GraphicsLayer
+ // implementation where the clipping logic is located.
+ // This issue is tracked in b/333862760
+ invalidateParentLayer?.invoke()
+ }
}
override fun isInLayer(position: Offset): Boolean {
@@ -83,8 +206,7 @@
val y = position.y
if (graphicsLayer.clip) {
- val outline = graphicsLayer.outline
- return isInOutline(outline, x, y, tmpTouchPointPath, tmpOpPath)
+ return isInOutline(graphicsLayer.outline, x, y)
}
return true
@@ -101,18 +223,72 @@
}
}
+ private var drawnWithEnabledZ = false
+
override fun drawLayer(canvas: Canvas, parentLayer: GraphicsLayer?) {
- updateDisplayList()
- scope.draw(density, layoutDirection, canvas, size.toSize(), parentLayer) {
- drawLayer(graphicsLayer)
+ val androidCanvas = canvas.nativeCanvas
+ if (androidCanvas.isHardwareAccelerated) {
+ updateDisplayList()
+ drawnWithEnabledZ = graphicsLayer.shadowElevation > 0
+ scope.draw(density, layoutDirection, canvas, size.toSize(), parentLayer) {
+ drawLayer(graphicsLayer)
+ }
+ } else {
+ // TODO ideally there should be some solution for drawing a layer on a software
+ // accelerated canvas built in right into GraphicsLayer, as this workaround is not
+ // solving all the use cases. For example, some one can use layers directly via
+ // drawWithContent {
+ // layer.record {
+ // this@drawWithContent.drawContent()
+ // }
+ // drawLayer(layer)
+ // }
+ // and if someone would try to draw the whole ComposeView on software accelerated
+ // canvas it will just crash saying RenderNodes can't be drawn into this canvas.
+ // This issue is tracked in b/333866398
+ val left = graphicsLayer.topLeft.x.toFloat()
+ val top = graphicsLayer.topLeft.y.toFloat()
+ val right = left + size.width
+ val bottom = top + size.height
+ // If there is alpha applied, we must render into an offscreen buffer to
+ // properly blend the contents of this layer against the background content
+ if (graphicsLayer.alpha < 1.0f) {
+ val paint = (softwareLayerPaint ?: Paint().also { softwareLayerPaint = it })
+ .apply { alpha = graphicsLayer.alpha }
+ androidCanvas.saveLayer(
+ left,
+ top,
+ right,
+ bottom,
+ paint.asFrameworkPaint()
+ )
+ } else {
+ canvas.save()
+ }
+ // If we are software rendered we must translate the canvas based on the offset provided
+ // in the move call which operates directly on the RenderNode
+ canvas.translate(left, top)
+ canvas.concat(getMatrix())
+ if (graphicsLayer.clip) {
+ clipManually(canvas)
+ }
+ drawBlock?.invoke(canvas, null)
+ canvas.restore()
}
}
override fun updateDisplayList() {
if (isDirty) {
+ if (graphicsLayer.size != size) {
+ graphicsLayer.pivotOffset = Offset(
+ transformOrigin.pivotFractionX * size.width,
+ transformOrigin.pivotFractionY * size.height
+ )
+ updateOutline()
+ }
graphicsLayer.record(density, layoutDirection, size) {
drawIntoCanvas { canvas ->
- drawBlock?.let { it(canvas) }
+ drawBlock?.let { it(canvas, drawContext.graphicsLayer) }
}
}
isDirty = false
@@ -131,26 +307,46 @@
invalidateParentLayer = null
isDestroyed = true
isDirty = false
+ context?.releaseGraphicsLayer(graphicsLayer)
}
override fun mapOffset(point: Offset, inverse: Boolean): Offset {
- return getMatrix(inverse).map(point)
+ return if (inverse) {
+ getInverseMatrix()?.map(point) ?: Offset.Infinite
+ } else {
+ getMatrix().map(point)
+ }
}
override fun mapBounds(rect: MutableRect, inverse: Boolean) {
- getMatrix(inverse).map(rect)
+ if (inverse) {
+ val matrix = getInverseMatrix()
+ if (matrix == null) {
+ rect.set(0f, 0f, 0f, 0f)
+ } else {
+ matrix.map(rect)
+ }
+ } else {
+ getMatrix().map(rect)
+ }
}
- override fun reuseLayer(drawBlock: (Canvas) -> Unit, invalidateParentLayer: () -> Unit) {
+ override fun reuseLayer(
+ drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit,
+ invalidateParentLayer: () -> Unit
+ ) {
throwIllegalStateException("reuseLayer is not supported yet")
}
override fun transform(matrix: Matrix) {
- matrix.timesAssign(getMatrix(inverse = false))
+ matrix.timesAssign(getMatrix())
}
override fun inverseTransform(matrix: Matrix) {
- matrix.timesAssign(getMatrix(inverse = true))
+ val inverse = getInverseMatrix()
+ if (inverse != null) {
+ matrix.timesAssign(inverse)
+ }
}
override val layerId: Long
@@ -159,14 +355,21 @@
override val ownerViewId: Long
get() = graphicsLayer.ownerViewId
- private fun getMatrix(inverse: Boolean = false): Matrix {
+ private fun getMatrix(): Matrix {
updateMatrix()
- if (inverse) {
- matrixCache.invert()
- }
return matrixCache
}
+ private fun getInverseMatrix(): Matrix? {
+ val matrix = getMatrix()
+ val inverseMatrix = inverseMatrixCache ?: Matrix().also { inverseMatrixCache = it }
+ return if (matrix.invertTo(inverseMatrix)) {
+ inverseMatrix
+ } else {
+ null
+ }
+ }
+
private fun updateMatrix() = with(graphicsLayer) {
val pivot = if (pivotOffset.isUnspecified) size.center.toOffset() else pivotOffset
@@ -185,4 +388,27 @@
translate(x = pivot.x, y = pivot.y)
}
}
+
+ /**
+ * Manually clips the content of the RenderNodeLayer in the provided canvas.
+ * This is used only in software rendered use cases
+ */
+ private fun clipManually(canvas: Canvas) {
+ if (graphicsLayer.clip) {
+ when (val outline = graphicsLayer.outline) {
+ is Outline.Rectangle -> {
+ canvas.clipRect(outline.rect)
+ }
+ is Outline.Rounded -> {
+ val path = tmpPath ?: Path().also { tmpPath = it }
+ path.reset()
+ path.addRoundRect(outline.roundRect)
+ canvas.clipPath(path)
+ }
+ is Outline.Generic -> {
+ canvas.clipPath(outline.path)
+ }
+ }
+ }
+ }
}
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/RenderNodeLayer.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/RenderNodeLayer.android.kt
index 7e258ec..b1c7718 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/RenderNodeLayer.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/RenderNodeLayer.android.kt
@@ -47,10 +47,10 @@
@RequiresApi(Build.VERSION_CODES.M)
internal class RenderNodeLayer(
val ownerView: AndroidComposeView,
- drawBlock: (Canvas) -> Unit,
+ drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit,
invalidateParentLayer: () -> Unit
) : OwnedLayer, GraphicLayerInfo {
- private var drawBlock: ((Canvas) -> Unit)? = drawBlock
+ private var drawBlock: ((canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit)? = drawBlock
private var invalidateParentLayer: (() -> Unit)? = invalidateParentLayer
/**
@@ -314,7 +314,7 @@
canvas.translate(left, top)
canvas.concat(matrixCache.calculateMatrix(renderNode))
clipRenderNode(canvas)
- drawBlock?.invoke(canvas)
+ drawBlock?.invoke(canvas, null)
canvas.restore()
isDirty = false
}
@@ -337,8 +337,10 @@
} else {
null
}
- drawBlock?.let {
- renderNode.record(canvasHolder, clipPath, it)
+ drawBlock?.let { drawBlock ->
+ renderNode.record(canvasHolder, clipPath) {
+ drawBlock(it, null)
+ }
}
isDirty = false
}
@@ -377,7 +379,10 @@
}
}
- override fun reuseLayer(drawBlock: (Canvas) -> Unit, invalidateParentLayer: () -> Unit) {
+ override fun reuseLayer(
+ drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit,
+ invalidateParentLayer: () -> Unit
+ ) {
isDirty = false
isDestroyed = false
drawnWithZ = false
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ViewLayer.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ViewLayer.android.kt
index 4ef277e..0ccc913 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ViewLayer.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ViewLayer.android.kt
@@ -52,10 +52,10 @@
internal class ViewLayer(
val ownerView: AndroidComposeView,
val container: DrawChildContainer,
- drawBlock: (Canvas) -> Unit,
+ drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit,
invalidateParentLayer: () -> Unit
) : View(ownerView.context), OwnedLayer, GraphicLayerInfo {
- private var drawBlock: ((Canvas) -> Unit)? = drawBlock
+ private var drawBlock: ((canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit)? = drawBlock
private var invalidateParentLayer: (() -> Unit)? = invalidateParentLayer
private val outlineResolver = Snapshot.withoutReadObservation {
@@ -329,7 +329,7 @@
save()
outlineResolver.clipToOutline(this)
}
- drawBlock?.invoke(this)
+ drawBlock?.invoke(this, null)
if (didClip) {
restore()
}
@@ -401,7 +401,10 @@
}
}
- override fun reuseLayer(drawBlock: (Canvas) -> Unit, invalidateParentLayer: () -> Unit) {
+ override fun reuseLayer(
+ drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit,
+ invalidateParentLayer: () -> Unit
+ ) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M || shouldUseDispatchDraw) {
container.addView(this)
} else {
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/scrollcapture/ComposeScrollCaptureCallback.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/scrollcapture/ComposeScrollCaptureCallback.android.kt
index ad00863..66ad43f 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/scrollcapture/ComposeScrollCaptureCallback.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/scrollcapture/ComposeScrollCaptureCallback.android.kt
@@ -22,6 +22,7 @@
import android.graphics.Paint
import android.graphics.Rect as AndroidRect
import android.os.CancellationSignal
+import android.util.Log
import android.view.ScrollCaptureCallback
import android.view.ScrollCaptureSession
import androidx.annotation.RequiresApi
@@ -35,6 +36,7 @@
import androidx.compose.ui.internal.checkPreconditionNotNull
import androidx.compose.ui.semantics.SemanticsActions.ScrollByOffset
import androidx.compose.ui.semantics.SemanticsNode
+import androidx.compose.ui.semantics.SemanticsProperties.VerticalScrollAxisRange
import androidx.compose.ui.unit.IntRect
import java.util.function.Consumer
import kotlin.math.roundToInt
@@ -46,6 +48,7 @@
import kotlinx.coroutines.plus
private const val DEBUG = false
+private const val TAG = "ScrollCapture"
/**
* Implementation of [ScrollCaptureCallback] that captures Compose scroll containers.
@@ -67,15 +70,26 @@
private val scrollTracker = RelativeScroller(
viewportSize = viewportBoundsInWindow.height,
- scrollBy = { amount ->
+ scrollBy = { delta ->
val scrollByOffset = checkPreconditionNotNull(node.scrollCaptureScrollByAction)
+ val reverseScrolling = node.unmergedConfig[VerticalScrollAxisRange].reverseScrolling
+
+ val actualDelta = if (reverseScrolling) -delta else delta
+ if (DEBUG) Log.d(
+ TAG, "scrolling by delta $actualDelta " +
+ "(reverseScrolling=$reverseScrolling, requested delta=$delta)"
+ )
+
// This action may animate, ensure any calls to this RelativeScroll are done with a
// coroutine context that disables animations.
- val consumed = scrollByOffset(Offset(0f, amount))
- consumed.y
+ val consumed = scrollByOffset(Offset(0f, actualDelta))
+ if (reverseScrolling) -consumed.y else consumed.y
}
)
+ /** Only used when [DEBUG] is true. */
+ private var requestCount = 0
+
override fun onScrollCaptureSearch(signal: CancellationSignal, onReady: Consumer<AndroidRect>) {
val bounds = viewportBoundsInWindow
onReady.accept(bounds.toAndroidRect())
@@ -87,6 +101,7 @@
onReady: Runnable
) {
scrollTracker.reset()
+ requestCount = 0
listener.onSessionStarted()
onReady.run()
}
@@ -110,6 +125,7 @@
// Scroll the requested capture area into the viewport so we can draw it.
val targetMin = captureArea.top
val targetMax = captureArea.bottom
+ if (DEBUG) Log.d(TAG, "capture request for $targetMin..$targetMax")
scrollTracker.scrollRangeIntoView(targetMin, targetMax)
// Wait a frame to allow layout to respond to the scroll.
@@ -119,6 +135,7 @@
// the viewport.
val viewportClippedMin = scrollTracker.mapOffsetToViewport(targetMin)
val viewportClippedMax = scrollTracker.mapOffsetToViewport(targetMax)
+ if (DEBUG) Log.d(TAG, "drawing viewport $viewportClippedMin..$viewportClippedMax")
val viewportClippedRect = captureArea.copy(
top = viewportClippedMin,
bottom = viewportClippedMax
@@ -164,6 +181,7 @@
// Translate back to "original" coordinates to report.
val resultRect = viewportClippedRect.translate(0, scrollTracker.scrollAmount.roundToInt())
+ if (DEBUG) Log.d(TAG, "captured rectangle $resultRect")
return resultRect
}
@@ -190,6 +208,7 @@
val circleRadius = 20f
val circlePaint = Paint().apply {
color = Color.RED
+ textSize = 48f
}
drawCircle(0f, 0f, circleRadius, circlePaint)
drawCircle(width.toFloat(), 0f, circleRadius, circlePaint)
@@ -200,6 +219,9 @@
circlePaint
)
drawCircle(0f, height.toFloat(), circleRadius, circlePaint)
+
+ drawText(requestCount.toString(), width / 2f, height / 2f, circlePaint)
+ requestCount++
}
interface ScrollCaptureSessionListener {
@@ -244,6 +266,7 @@
* viewport.
*/
suspend fun scrollRangeIntoView(min: Int, max: Int) {
+ if (DEBUG) Log.d(TAG, "scrollRangeIntoView(min=$min, max=$max)")
require(min <= max) { "Expected min=$min ≤ max=$max" }
require(max - min <= viewportSize) {
"Expected range (${max - min}) to be ≤ viewportSize=$viewportSize"
@@ -251,11 +274,13 @@
if (min >= scrollAmount && max <= scrollAmount + viewportSize) {
// Already visible, no need to scroll.
+ if (DEBUG) Log.d(TAG, "requested range already in view, not scrolling")
return
}
// Scroll to the nearest edge.
val target = if (min < scrollAmount) min else max - viewportSize
+ if (DEBUG) Log.d(TAG, "scrolling to $target")
scrollTo(target.toFloat())
}
@@ -273,12 +298,17 @@
/**
* Try to scroll to [offset] pixels past the original scroll position.
*/
- suspend fun scrollTo(offset: Float): Float = scrollBy(offset - scrollAmount)
+ suspend fun scrollTo(offset: Float) {
+ scrollBy(offset - scrollAmount)
+ }
- private suspend fun scrollBy(delta: Float): Float {
+ private suspend fun scrollBy(delta: Float) {
val consumed = scrollBy.invoke(delta)
scrollAmount += consumed
- return consumed
+ if (DEBUG) Log.d(
+ TAG,
+ "scrolled $consumed of requested $delta, after scrollAmount=$scrollAmount"
+ )
}
}
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/scrollcapture/ScrollCapture.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/scrollcapture/ScrollCapture.android.kt
index 2a3afd0..1062dbc 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/scrollcapture/ScrollCapture.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/scrollcapture/ScrollCapture.android.kt
@@ -134,7 +134,7 @@
) {
fromNode.visitDescendants { node ->
// Invisible/disabled nodes can't be candidates, nor can any of their descendants.
- if (!node.isVisible || Disabled in node.config) {
+ if (!node.isVisible || Disabled in node.unmergedConfig) {
return@visitDescendants false
}
@@ -178,7 +178,8 @@
}
}
-internal val SemanticsNode.scrollCaptureScrollByAction get() = config.getOrNull(ScrollByOffset)
+internal val SemanticsNode.scrollCaptureScrollByAction
+ get() = unmergedConfig.getOrNull(ScrollByOffset)
// TODO(mnuzen): Port this back to the SemanticsUtil file
@OptIn(ExperimentalComposeUiApi::class)
@@ -188,7 +189,7 @@
private val SemanticsNode.canScrollVertically: Boolean
get() {
val scrollByOffset = scrollCaptureScrollByAction
- val verticalScrollAxisRange = config.getOrNull(VerticalScrollAxisRange)
+ val verticalScrollAxisRange = unmergedConfig.getOrNull(VerticalScrollAxisRange)
return scrollByOffset != null &&
verticalScrollAxisRange != null &&
verticalScrollAxisRange.maxValue() > 0f
diff --git a/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/DelegatingNodeTest.kt b/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/DelegatingNodeTest.kt
index 0f54238..30c59065 100644
--- a/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/DelegatingNodeTest.kt
+++ b/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/DelegatingNodeTest.kt
@@ -792,22 +792,17 @@
): NodeChain {
val owner = MockOwner()
val root = LayoutNode()
- val ln = unattachedLayout(*modifiers)
- LayoutScopeImpl(ln).block()
+ val ln = LayoutNode()
root.insertAt(0, ln)
root.attach(owner)
- root.innerCoordinator.updateLayerBlock({})
- return ln.nodes
-}
-
-private fun unattachedLayout(vararg modifiers: Modifier.Node): LayoutNode {
- val ln = LayoutNode()
var m: Modifier = Modifier
for (node in modifiers) {
m = m.then(NodeElement(node))
}
ln.nodes.updateFrom(m)
- return ln
+ LayoutScopeImpl(ln).block()
+ root.innerCoordinator.updateLayerBlock({})
+ return ln.nodes
}
internal data class NodeElement(val node: Modifier.Node) : ModifierNodeElement<Modifier.Node>() {
@@ -823,9 +818,14 @@
}
internal class LayoutScopeImpl(val layout: LayoutNode) : LayoutScope {
override fun layout(vararg modifiers: Modifier.Node, block: LayoutScope.() -> Unit) {
- val ln = unattachedLayout(*modifiers)
- LayoutScopeImpl(ln).block()
+ val ln = LayoutNode()
layout.insertAt(layout.children.size, ln)
+ var m: Modifier = Modifier
+ for (node in modifiers) {
+ m = m.then(NodeElement(node))
+ }
+ ln.nodes.updateFrom(m)
+ LayoutScopeImpl(ln).block()
}
}
interface LayoutScope {
diff --git a/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt b/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt
index 14e60cb..bb76634 100644
--- a/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt
+++ b/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt
@@ -81,6 +81,7 @@
import com.google.common.truth.Truth.assertThat
import java.util.concurrent.Executors
import kotlin.coroutines.CoroutineContext
+import kotlin.test.assertNotSame
import kotlinx.coroutines.asCoroutineDispatcher
import org.junit.Assert
import org.junit.Assert.assertEquals
@@ -695,6 +696,40 @@
assertEquals(0, node.children.size)
}
+ // Modifiers set before the layout node is attached should not be applied until after attach
+ @Test
+ fun modifierSetBeforeLayoutNodeAttached() {
+ val layoutNode = LayoutNode()
+ val layoutModifier = Modifier.graphicsLayer { }
+
+ layoutNode.modifier = layoutModifier
+ // Changes should not be applied yet
+ assertNotSame(layoutNode.modifier, layoutModifier)
+ assertFalse(layoutNode.outerCoordinator.isAttached)
+ assertFalse(layoutNode.nodes.has(Nodes.Any))
+
+ layoutNode.attach(MockOwner())
+ // Changes should now be applied
+ assertSame(layoutNode.modifier, layoutModifier)
+ assertTrue(layoutNode.outerCoordinator.isAttached)
+ assertTrue(layoutNode.nodes.has(Nodes.Any))
+ }
+
+ // Modifiers set after the layout node is attached should be applied immediately
+ @Test
+ fun modifierSetAfterLayoutNodeAttached() {
+ val layoutNode = LayoutNode()
+ val layoutModifier = Modifier.graphicsLayer { }
+ layoutNode.attach(MockOwner())
+
+ layoutNode.modifier = layoutModifier
+
+ // Changes should be applied
+ assertSame(layoutNode.modifier, layoutModifier)
+ assertTrue(layoutNode.outerCoordinator.isAttached)
+ assertTrue(layoutNode.nodes.has(Nodes.Any))
+ }
+
// The layout coordinates of a LayoutNode should be attached when
// the layout node is attached.
@Test
@@ -716,13 +751,11 @@
@Test
fun nodeCoordinatorSameWithReplacementModifier() {
val layoutNode = LayoutNode()
+ layoutNode.attach(MockOwner())
val layoutModifier = Modifier.graphicsLayer { }
layoutNode.modifier = layoutModifier
val oldNodeCoordinator = layoutNode.outerCoordinator
- assertFalse(oldNodeCoordinator.isAttached)
-
- layoutNode.attach(MockOwner())
assertTrue(oldNodeCoordinator.isAttached)
layoutNode.modifier = Modifier.graphicsLayer { }
@@ -767,14 +800,17 @@
.graphicsLayer { }
layoutNode.modifier = layoutModifier
- val oldNodeCoordinator = layoutNode.outerCoordinator
- val oldInnerNodeCoordinator = oldNodeCoordinator.wrapped
+ var oldNodeCoordinator = layoutNode.outerCoordinator
+ var oldInnerNodeCoordinator = oldNodeCoordinator.wrapped
assertFalse(oldNodeCoordinator.isAttached)
- assertNotNull(oldInnerNodeCoordinator)
- assertFalse(oldInnerNodeCoordinator!!.isAttached)
+ assertNull(oldInnerNodeCoordinator)
layoutNode.attach(MockOwner())
+ oldNodeCoordinator = layoutNode.outerCoordinator
+ oldInnerNodeCoordinator = oldNodeCoordinator.wrapped
assertTrue(oldNodeCoordinator.isAttached)
+ assertNotNull(oldInnerNodeCoordinator)
+ assertTrue(oldInnerNodeCoordinator!!.isAttached)
// only 1 modifier now, so one should be detached and the other can be reused
layoutNode.modifier = Modifier.graphicsLayer()
@@ -2349,6 +2385,7 @@
val modifier2 = Modifier.layout(measureLambda2)
val root = LayoutNode()
+ root.attach(MockOwner())
root.modifier = modifier1.then(modifier2)
assertEquals(
@@ -2644,7 +2681,7 @@
val invalidatedLayers = mutableListOf<OwnedLayer>()
override fun createLayer(
- drawBlock: (Canvas) -> Unit,
+ drawBlock: (Canvas, GraphicsLayer?) -> Unit,
invalidateParentLayer: () -> Unit,
explicitLayer: GraphicsLayer?
): OwnedLayer {
@@ -2673,7 +2710,7 @@
}
override fun drawLayer(canvas: Canvas, parentLayer: GraphicsLayer?) {
- drawBlock(canvas)
+ drawBlock(canvas, null)
}
override fun updateDisplayList() {
@@ -2690,7 +2727,7 @@
}
override fun reuseLayer(
- drawBlock: (Canvas) -> Unit,
+ drawBlock: (Canvas, GraphicsLayer?) -> Unit,
invalidateParentLayer: () -> Unit
) {
}
diff --git a/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/ModifierLocalConsumerEntityTest.kt b/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/ModifierLocalConsumerEntityTest.kt
index 1c7c4c2..fe6890b 100644
--- a/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/ModifierLocalConsumerEntityTest.kt
+++ b/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/ModifierLocalConsumerEntityTest.kt
@@ -388,7 +388,7 @@
get() = TODO("Not yet implemented")
override fun createLayer(
- drawBlock: (Canvas) -> Unit,
+ drawBlock: (Canvas, GraphicsLayer?) -> Unit,
invalidateParentLayer: () -> Unit,
explicitLayer: GraphicsLayer?
) = TODO("Not yet implemented")
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/autofill/Autofill.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/autofill/Autofill.kt
index d1db594..13d2354 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/autofill/Autofill.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/autofill/Autofill.kt
@@ -90,7 +90,7 @@
if (autofillTypes != other.autofillTypes) return false
if (boundingBox != other.boundingBox) return false
- if (onFill != other.onFill) return false
+ if (onFill !== other.onFill) return false
return true
}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/SuspendingPointerInputFilter.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/SuspendingPointerInputFilter.kt
index 66497b3..421f11a 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/SuspendingPointerInputFilter.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/SuspendingPointerInputFilter.kt
@@ -330,11 +330,11 @@
}
override fun create(): SuspendingPointerInputModifierNodeImpl {
- return SuspendingPointerInputModifierNodeImpl(pointerInputHandler)
+ return SuspendingPointerInputModifierNodeImpl(key1, key2, keys, pointerInputHandler)
}
override fun update(node: SuspendingPointerInputModifierNodeImpl) {
- node.pointerInputHandler = pointerInputHandler
+ node.update(key1, key2, keys, pointerInputHandler)
}
override fun equals(other: Any?): Boolean {
@@ -348,13 +348,14 @@
if (!keys.contentEquals(other.keys)) return false
} else if (other.keys != null) return false
- return true
+ return pointerInputHandler === other.pointerInputHandler
}
override fun hashCode(): Int {
var result = key1?.hashCode() ?: 0
result = 31 * result + (key2?.hashCode() ?: 0)
result = 31 * result + (keys?.contentHashCode() ?: 0)
+ result = 31 * result + pointerInputHandler.hashCode()
return result
}
}
@@ -370,7 +371,7 @@
fun SuspendingPointerInputModifierNode(
pointerInputHandler: suspend PointerInputScope.() -> Unit
): SuspendingPointerInputModifierNode {
- return SuspendingPointerInputModifierNodeImpl(pointerInputHandler)
+ return SuspendingPointerInputModifierNodeImpl(null, null, null, pointerInputHandler)
}
/**
@@ -412,17 +413,55 @@
* first event is fired (making it more efficient) and is cancelled via resetPointerInputHandler().
*/
internal class SuspendingPointerInputModifierNodeImpl(
+ private var key1: Any? = null,
+ private var key2: Any? = null,
+ private var keys: Array<out Any?>? = null,
pointerInputHandler: suspend PointerInputScope.() -> Unit
) : Modifier.Node(),
SuspendingPointerInputModifierNode,
PointerInputScope,
Density {
- override var pointerInputHandler = pointerInputHandler
+ internal fun update(
+ key1: Any?,
+ key2: Any?,
+ keys: Array<out Any?>?,
+ pointerInputHandler: suspend PointerInputScope.() -> Unit
+ ) {
+ var needsReset = false
+ if (this.key1 != key1) {
+ needsReset = true
+ }
+ this.key1 = key1
+ if (this.key2 != key2) {
+ needsReset = true
+ }
+ this.key2 = key2
+ if (this.keys != null && keys == null) {
+ needsReset = true
+ }
+ if (this.keys == null && keys != null) {
+ needsReset = true
+ }
+ if (this.keys != null && keys != null && !keys.contentEquals(this.keys)) {
+ needsReset = true
+ }
+ this.keys = keys
+ if (needsReset) {
+ resetPointerInputHandler()
+ }
+ // Avoids calling resetPointerInputHandler when setting this if no keys have changed
+ _pointerInputHandler = pointerInputHandler
+ }
+
+ private var _pointerInputHandler = pointerInputHandler
+
+ override var pointerInputHandler
set(value) {
resetPointerInputHandler()
- field = value
+ _pointerInputHandler = value
}
+ get() = _pointerInputHandler
override val density: Float
get() = requireLayoutNode().density.density
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/OnGloballyPositionedModifier.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/OnGloballyPositionedModifier.kt
index d6ee7f8..065c55e 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/OnGloballyPositionedModifier.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/OnGloballyPositionedModifier.kt
@@ -54,7 +54,7 @@
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is OnGloballyPositionedElement) return false
- return onGloballyPositioned == other.onGloballyPositioned
+ return onGloballyPositioned === other.onGloballyPositioned
}
override fun hashCode(): Int {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/OnRemeasuredModifier.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/OnRemeasuredModifier.kt
index 91fe684..a6b2e22 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/OnRemeasuredModifier.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/OnRemeasuredModifier.kt
@@ -59,7 +59,7 @@
if (this === other) return true
if (other !is OnSizeChangedModifier) return false
- return onSizeChanged == other.onSizeChanged
+ return onSizeChanged === other.onSizeChanged
}
override fun hashCode(): Int {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/modifier/ModifierLocalConsumer.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/modifier/ModifierLocalConsumer.kt
index 6d291ff..e7bb4b1 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/modifier/ModifierLocalConsumer.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/modifier/ModifierLocalConsumer.kt
@@ -67,7 +67,7 @@
}
override fun equals(other: Any?): Boolean {
- return other is ModifierLocalConsumerImpl && other.consumer == consumer
+ return other is ModifierLocalConsumerImpl && other.consumer === consumer
}
override fun hashCode() = consumer.hashCode()
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 b541297..fc363d0 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
@@ -465,6 +465,10 @@
this.owner = owner
this.depth = (parent?.depth ?: -1) + 1
+
+ pendingModifier?.let { applyModifier(it) }
+ pendingModifier = null
+
if (nodes.has(Nodes.Semantics)) {
invalidateSemantics()
}
@@ -878,10 +882,15 @@
}
}
+ private var _modifier: Modifier = Modifier
+ private var pendingModifier: Modifier? = null
+ internal val applyingModifierOnAttach get() = pendingModifier != null
+
/**
* The [Modifier] currently applied to this node.
*/
- override var modifier: Modifier = Modifier
+ override var modifier: Modifier
+ get() = _modifier
set(value) {
requirePrecondition(!isVirtual || modifier === Modifier) {
"Modifiers are not supported on virtual LayoutNodes"
@@ -889,14 +898,22 @@
requirePrecondition(!isDeactivated) {
"modifier is updated when deactivated"
}
- field = value
- nodes.updateFrom(value)
- layoutDelegate.updateParentData()
- if (lookaheadRoot == null && nodes.has(Nodes.ApproachMeasure)) {
- lookaheadRoot = this
+ if (isAttached) {
+ applyModifier(value)
+ } else {
+ pendingModifier = value
}
}
+ private fun applyModifier(modifier: Modifier) {
+ _modifier = modifier
+ nodes.updateFrom(modifier)
+ layoutDelegate.updateParentData()
+ if (lookaheadRoot == null && nodes.has(Nodes.ApproachMeasure)) {
+ lookaheadRoot = this
+ }
+ }
+
private fun resetModifierState() {
nodes.resetState()
}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeChain.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeChain.kt
index 4fbe097..ba32617 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeChain.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeChain.kt
@@ -23,7 +23,6 @@
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.areObjectsOfSameType
-import androidx.compose.ui.input.pointer.SuspendPointerInputElement
import androidx.compose.ui.internal.checkPrecondition
import androidx.compose.ui.internal.checkPreconditionNotNull
import androidx.compose.ui.layout.ModifierInfo
@@ -165,15 +164,15 @@
before,
after,
node,
- layoutNode.isAttached,
+ !layoutNode.applyingModifierOnAttach,
)
}
- } else if (!layoutNode.isAttached && beforeSize == 0) {
+ } else if (layoutNode.applyingModifierOnAttach && beforeSize == 0) {
// common case where we are initializing the chain and the previous size is zero. In
// this case we just do all inserts. Since this is so common, we add a fast path here
- // for this condition. Since the layout node is not attached, the inserted nodes will
- // not get eagerly attached, which means we can avoid dealing with the coordinator sync
- // until the end, which keeps this code path much simpler.
+ // for this condition. Since the layout node is currently attaching, the inserted nodes
+ // will not get eagerly attached, which means we can avoid dealing with the coordinator
+ // sync until the end, which keeps this code path much simpler.
coordinatorSyncNeeded = true
var node = paddedHead
while (i < after.size) {
@@ -203,7 +202,7 @@
before,
after,
paddedHead,
- layoutNode.isAttached,
+ !layoutNode.applyingModifierOnAttach,
)
}
current = after
@@ -223,16 +222,6 @@
tailToHead {
if (it.isAttached) it.reset()
}
- current?.let { elements ->
- elements.forEachIndexed { i, element ->
- // we need to make sure the suspending pointer input modifier node is updated after
- // being reset so we use the latest lambda, even if the keys provided as input
- // didn't change.
- if (element is SuspendPointerInputElement) {
- elements[i] = ForceUpdateElement(element)
- }
- }
- }
runDetachLifecycle()
markAsDetached()
}
@@ -814,9 +803,7 @@
internal fun actionForModifiers(prev: Modifier.Element, next: Modifier.Element): Int {
return if (prev == next) {
ActionReuse
- } else if (areObjectsOfSameType(prev, next) ||
- (prev is ForceUpdateElement && areObjectsOfSameType(prev.original, next))
- ) {
+ } else if (areObjectsOfSameType(prev, next)) {
ActionUpdate
} else {
ActionReplace
@@ -853,15 +840,3 @@
}
return result
}
-
-@Suppress("ModifierNodeInspectableProperties")
-private data class ForceUpdateElement(val original: ModifierNodeElement<*>) :
- ModifierNodeElement<Modifier.Node>() {
- override fun create(): Modifier.Node {
- throw IllegalStateException("Shouldn't be called")
- }
-
- override fun update(node: Modifier.Node) {
- throw IllegalStateException("Shouldn't be called")
- }
-}
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 64e839f..f797a9c 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
@@ -447,10 +447,10 @@
// implementation of draw block passed to the OwnedLayer
@Suppress("LiftReturnOrAssignment")
- private val drawBlock: (Canvas) -> Unit = { canvas ->
- if (layoutNode.isPlaced) {
- snapshotObserver.observeReads(this, onCommitAffectingLayer) {
- drawContainedDrawModifiers(canvas, explicitLayer)
+ private val drawBlock: (Canvas, GraphicsLayer?) -> Unit = { canvas, parentLayer ->
+ if (layoutNode.isPlaced) {
+ snapshotObserver.observeReads(this, onCommitAffectingLayer) {
+ drawContainedDrawModifiers(canvas, parentLayer)
}
lastLayerDrawingWasSkipped = false
} else {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OwnedLayer.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OwnedLayer.kt
index 23fdbd4..f68b387 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OwnedLayer.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OwnedLayer.kt
@@ -103,7 +103,10 @@
* [drawBlock] and [invalidateParentLayer] values. The layer will be reinitialized
* as new after this call.
*/
- fun reuseLayer(drawBlock: (Canvas) -> Unit, invalidateParentLayer: () -> Unit)
+ fun reuseLayer(
+ drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit,
+ invalidateParentLayer: () -> Unit
+ )
/**
* Calculates the transform from the parent to the local coordinates and multiplies
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt
index dbc9f47..789cefc 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt
@@ -256,7 +256,7 @@
* Creates an [OwnedLayer] which will be drawing the passed [drawBlock].
*/
fun createLayer(
- drawBlock: (Canvas) -> Unit,
+ drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit,
invalidateParentLayer: () -> Unit,
explicitLayer: GraphicsLayer? = null
): OwnedLayer
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsModifier.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsModifier.kt
index dd4decb..40bf53c 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsModifier.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsModifier.kt
@@ -46,9 +46,9 @@
val semanticsConfiguration: SemanticsConfiguration
}
-internal object EmptySemanticsElement :
+internal class EmptySemanticsElement(private val node: EmptySemanticsModifier) :
ModifierNodeElement<EmptySemanticsModifier>() {
- override fun create() = EmptySemanticsModifier()
+ override fun create() = node
override fun update(node: EmptySemanticsModifier) {}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsOwner.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsOwner.kt
index ec5a18f..b1e955a 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsOwner.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsOwner.kt
@@ -18,7 +18,6 @@
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.node.LayoutNode
-import androidx.compose.ui.node.Nodes
import androidx.compose.ui.util.fastForEach
/**
@@ -26,7 +25,10 @@
* semantics tree
*/
@OptIn(ExperimentalComposeUiApi::class)
-class SemanticsOwner internal constructor(private val rootNode: LayoutNode) {
+class SemanticsOwner internal constructor(
+ private val rootNode: LayoutNode,
+ private val outerSemanticsNode: EmptySemanticsModifier
+) {
/**
* The root node of the semantics tree. Does not contain any unmerged data.
* May contain merged data.
@@ -39,7 +41,7 @@
val unmergedRootSemanticsNode: SemanticsNode
get() {
return SemanticsNode(
- outerSemanticsNode = rootNode.nodes.head(Nodes.Semantics)!!.node,
+ outerSemanticsNode = outerSemanticsNode,
layoutNode = rootNode,
mergingEnabled = false,
// Forcing an empty SemanticsConfiguration here since the root node will always
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.kt
index 50dffd3..0d60bb9 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.kt
@@ -620,7 +620,7 @@
if (other !is CustomAccessibilityAction) return false
if (label != other.label) return false
- if (action != other.action) return false
+ if (action !== other.action) return false
return true
}
diff --git a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/platform/SkiaLayerTest.kt b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/platform/SkiaLayerTest.kt
index 5293ba2..082fff8 100644
--- a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/platform/SkiaLayerTest.kt
+++ b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/platform/SkiaLayerTest.kt
@@ -374,7 +374,7 @@
private fun TestSkiaLayer() = SkiaLayer(
Density(1f, 1f),
invalidateParentLayer = {},
- drawBlock = {}
+ drawBlock = { _, _ -> }
)
private fun SkiaLayer.updateProperties(
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 bc03008..dda9f9f 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
@@ -78,6 +78,7 @@
import androidx.compose.ui.node.OwnerSnapshotObserver
import androidx.compose.ui.node.RootForTest
import androidx.compose.ui.semantics.EmptySemanticsElement
+import androidx.compose.ui.semantics.EmptySemanticsModifier
import androidx.compose.ui.semantics.SemanticsOwner
import androidx.compose.ui.text.font.createFontFamilyResolver
import androidx.compose.ui.text.input.TextInputService
@@ -125,7 +126,8 @@
override val sharedDrawScope = LayoutNodeDrawScope()
- private val semanticsModifier = EmptySemanticsElement
+ private val rootSemanticsNode = EmptySemanticsModifier()
+ private val semanticsModifier = EmptySemanticsElement(rootSemanticsNode)
override val focusOwner: FocusOwner = FocusOwnerImpl(
onRequestApplyChangesListener = ::registerOnEndApplyChangesListener,
@@ -237,7 +239,7 @@
override val textToolbar = DefaultTextToolbar()
- override val semanticsOwner: SemanticsOwner = SemanticsOwner(root)
+ override val semanticsOwner: SemanticsOwner = SemanticsOwner(root, rootSemanticsNode)
override val dragAndDropManager: DragAndDropManager get() = TODO("Not yet implemented")
@@ -376,7 +378,7 @@
}
override fun createLayer(
- drawBlock: (Canvas) -> Unit,
+ drawBlock: (Canvas, GraphicsLayer?) -> Unit,
invalidateParentLayer: () -> Unit,
explicitLayer: GraphicsLayer?
) = SkiaLayer(
diff --git a/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/platform/SkiaLayer.skiko.kt b/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/platform/SkiaLayer.skiko.kt
index 5f8b1e8..41bffb8 100644
--- a/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/platform/SkiaLayer.skiko.kt
+++ b/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/platform/SkiaLayer.skiko.kt
@@ -59,7 +59,7 @@
internal class SkiaLayer(
private var density: Density,
private val invalidateParentLayer: () -> Unit,
- private val drawBlock: (Canvas) -> Unit,
+ private val drawBlock: (Canvas, GraphicsLayer?) -> Unit,
private val onDestroy: () -> Unit = {}
) : OwnedLayer {
private var size = IntSize.Zero
@@ -95,7 +95,10 @@
onDestroy()
}
- override fun reuseLayer(drawBlock: (Canvas) -> Unit, invalidateParentLayer: () -> Unit) {
+ override fun reuseLayer(
+ drawBlock: (Canvas, GraphicsLayer?) -> Unit,
+ invalidateParentLayer: () -> Unit
+ ) {
// TODO: in destroy, call recycle, and reconfigure this layer to be ready to use here.
}
@@ -274,7 +277,7 @@
skiaCanvas.alphaMultiplier = 1.0f
}
- drawBlock(canvas)
+ drawBlock(canvas, null)
canvas.restore()
if (clip) {
canvas.restore()
diff --git a/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/ConstraintLayout.kt b/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/ConstraintLayout.kt
index 04f1c6d..32ac6ba 100644
--- a/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/ConstraintLayout.kt
+++ b/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/ConstraintLayout.kt
@@ -957,7 +957,7 @@
override fun hashCode() = constrainBlock.hashCode()
override fun equals(other: Any?) =
- constrainBlock == (other as? ConstrainAsModifier)?.constrainBlock
+ constrainBlock === (other as? ConstrainAsModifier)?.constrainBlock
}
}
@@ -1064,7 +1064,7 @@
override val layoutId: Any = ref.id
override fun equals(other: Any?) = other is ConstraintLayoutParentData &&
- ref.id == other.ref.id && constrain == other.constrain
+ ref.id == other.ref.id && constrain === other.constrain
override fun hashCode() = ref.id.hashCode() * 31 + constrain.hashCode()
}
diff --git a/datastore/datastore-core/src/commonJvmMain/kotlin/androidx/datastore/core/Serializer.kt b/datastore/datastore-core/src/commonJvmMain/kotlin/androidx/datastore/core/Serializer.kt
index b39e56d..5fc0640 100644
--- a/datastore/datastore-core/src/commonJvmMain/kotlin/androidx/datastore/core/Serializer.kt
+++ b/datastore/datastore-core/src/commonJvmMain/kotlin/androidx/datastore/core/Serializer.kt
@@ -44,7 +44,7 @@
* Marshal object to a stream. Closing the provided OutputStream is a no-op.
*
* @param t the data to write to output
- * @output the OutputStream to serialize data to
+ * @param output the OutputStream to serialize data to
*/
public suspend fun writeTo(t: T, output: OutputStream)
}
diff --git a/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/command/Diff.kt b/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/command/Diff.kt
index 48ed373..ecf3682 100644
--- a/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/command/Diff.kt
+++ b/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/command/Diff.kt
@@ -43,11 +43,13 @@
val before: File = when {
before == null -> promptProvideFile("Provide the 'before' path",
+ excludePattern = ".*\\.json$",
defaultSrcDir = Paths.savedTracesDir.toFile())
else -> checkNotNull(before)
}
val after: File = when {
after == null -> promptProvideFile("Provide the 'after' path",
+ excludePattern = ".*\\.json$",
defaultSrcDir = Paths.savedTracesDir.toFile())
else -> checkNotNull(after)
}
@@ -73,6 +75,18 @@
log("Opened '${indexHtml.canonicalPath}' in the browser.", isStdErr = true)
}
+ private fun fetchBenchmarkResultForTrace(traceFile: File): String {
+ val file = traceFile.parentFile.resolve(traceFile.nameWithoutExtension + ".json")
+ if (!file.exists()) {
+ log(
+ "Could not locate benchmark result file for trace: ${traceFile.name} ",
+ isStdErr = true
+ )
+ return ""
+ }
+ return file.readText()
+ }
+
private fun createDiffHtmlPage(beforeRaw: File, afterRaw: File, diffDir: File): File {
val beforeRawFolded = diffDir.resolve("before-raw.folded")
val afterRawFolded = diffDir.resolve("after-raw.folded")
@@ -96,8 +110,20 @@
createFlameGraph(afterDiffFolded, afterDiffSvg)
createFlameGraph(beforeDiffFolded, beforeDiffSvg, negate = true)
+ // fetch benchmark result data
+ val benchmarkResultBefore = fetchBenchmarkResultForTrace(beforeRaw)
+ val benchmarkResultAfter = fetchBenchmarkResultForTrace(afterRaw)
createIndexHtml(
- TraceDiffResult(beforeRawSvg, beforeDiffSvg, afterRawSvg, afterDiffSvg), indexHtml
+ TraceDiffResult(
+ beforeRawSvg,
+ beforeDiffSvg,
+ afterRawSvg,
+ afterDiffSvg,
+ benchmarkResultBefore,
+ benchmarkResultAfter,
+ beforeRaw.name,
+ afterRaw.name
+ ), indexHtml
)
for (tmpFile in listOf(beforeRawFolded, afterRawFolded, beforeDiffFolded, afterDiffFolded))
@@ -109,7 +135,11 @@
val beforeRawGraph: File,
val beforeDiffGraph: File,
val afterRawGraph: File,
- val afterDiffGraph: File
+ val afterDiffGraph: File,
+ val beforeBenchmarkResult: String,
+ val afterBenchmarkResult: String,
+ val beforeTraceFileName: String,
+ val afterTraceFileName: String
)
private fun fileOption(role: String): MutuallyExclusiveOptions<File, File?> {
@@ -191,6 +221,10 @@
.replace("%before_diff_name%", "diff base vs curr")
.replace("%after_raw_name%", "show curr")
.replace("%after_diff_name%", "diff curr vs base")
- dstFile.bufferedWriter().use { writer -> writer.write(content) }
+ .replace("%benchmark_result_before_raw%", src.beforeBenchmarkResult)
+ .replace("%benchmark_result_after_raw%", src.afterBenchmarkResult)
+ .replace("%before_trace_file_name%", src.beforeTraceFileName)
+ .replace("%after_trace_file_name%", src.afterTraceFileName)
+ dstFile.writeText(content)
}
}
diff --git a/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/command/List.kt b/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/command/List.kt
index ccda04a..cb5d5ba 100644
--- a/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/command/List.kt
+++ b/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/command/List.kt
@@ -44,13 +44,14 @@
companion object {
/** Returns a list of saved traces sorted by 'most recently modified first' */
- internal fun savedTraces(savedTracesDir: File): List<FileWithId> {
- val files: Array<File> = when {
- !savedTracesDir.exists() -> emptyArray<File>()
- else -> savedTracesDir.listFiles() ?: emptyArray<File>()
- }
- files.sortWith(compareBy { f: File -> -f.lastModified() })
- return files.asSequence().withId().toList()
- }
+ internal fun savedTraces(savedTracesDir: File): List<FileWithId> =
+ savedTracesDir
+ .listFiles()
+ .let { it ?: return emptyList() }
+ .filter { !it.name.lowercase().endsWith(".json") }
+ .sortedBy { -it.lastModified() }
+ .asSequence()
+ .withId()
+ .toList()
}
}
diff --git a/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/command/Save.kt b/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/command/Save.kt
index 70fec93..8b95718 100644
--- a/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/command/Save.kt
+++ b/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/command/Save.kt
@@ -46,21 +46,40 @@
.default(Paths.traceFileNamePattern)
override fun run() {
+ // determine the source trace file location
val src = src // allows for smart casts
- val srcFile: File = when {
+ val srcTraceFile: File = when {
src != null && src.isFile -> src
- else -> promptProvideFile("Provide trace source", pattern, src, Paths.outDir.toFile())
+ else -> promptProvideFile(
+ "Provide trace source", pattern,
+ excludePattern = null, src, Paths.outDir.toFile()
+ )
}
- check(srcFile.exists() && srcFile.isFile)
+ check(srcTraceFile.exists() && srcTraceFile.isFile)
- val dstFile: File =
- Paths.savedTracesDir.resolve(dst ?: promptDestinationName(srcFile.name)).toFile()
- if (dstFile.exists()) promptOverwriteFile(dstFile).let { overwrite ->
+ // copy the source trace file to the destination
+ val dstTraceFile: File =
+ Paths.savedTracesDir.resolve(dst ?: promptDestinationName(srcTraceFile.name)).toFile()
+ if (dstTraceFile.exists()) promptOverwriteFile(dstTraceFile).let { overwrite ->
if (!overwrite) return
}
+ dstTraceFile.parentFile.mkdirs() // ensure destination dir is present
+ srcTraceFile.copyTo(dstTraceFile, overwrite = true)
- dstFile.parentFile.mkdirs() // ensure destination dir is present
- srcFile.copyTo(dstFile, overwrite = true)
+ // Determine the test result file corresponding to the trace (if present). JSON file will
+ // have the trace name in profileResults section. Trace files are guaranteed unique.
+ val srcTestResultFile = srcTraceFile.parentFile.walkTopDown().filter {
+ it.name.lowercase().endsWith("json") && it.readText().contains(srcTraceFile.name)
+ }.singleOrNull()
+
+ // copy the test result file to the destination
+ srcTestResultFile?.let {
+ val dstTestResultFileName = dstTraceFile.nameWithoutExtension + ".json"
+ val dstTestResultFile = dstTraceFile.parentFile.resolve(dstTestResultFileName)
+ // If we are changing the name of the trace file, we also need to reflect that in JSON.
+ val updatedJsonFile = it.readText().replace(srcTraceFile.name, dstTraceFile.name)
+ dstTestResultFile.writeText(updatedJsonFile)
+ }
}
private fun promptDestinationName(default: String? = null): String =
diff --git a/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/ui/Terminal.kt b/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/ui/Terminal.kt
index b78f809..e4bd356 100644
--- a/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/ui/Terminal.kt
+++ b/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/ui/Terminal.kt
@@ -62,7 +62,8 @@
internal fun CliktCommand.promptProvideFile(
prompt: String,
- pattern: String = ".*",
+ includePattern: String = ".*",
+ excludePattern: String? = null,
srcDir: File? = null,
defaultSrcDir: File? = null
): File {
@@ -80,11 +81,20 @@
}
check(baseDir.isDirectory)
- echo("Looking for files in '${baseDir.absolutePath}' matching '$pattern'...")
- val candidates = baseDir.walkTopDown().filter { it.isFile && it.name.matches(Regex(pattern)) }
- .sortedBy { -it.lastModified() }.withId().toList()
+ echo("Looking for files in '${baseDir.absolutePath}' matching '$includePattern'...")
+ val candidates = baseDir.walkTopDown()
+ .filter { it.isFile }
+ .filter { it.name.matches(Regex(includePattern)) }
+ .filter { if (excludePattern == null) true else !it.name.matches(Regex(excludePattern)) }
+ .sortedBy { -it.lastModified() }
+ .withId()
+ .toList()
- if (candidates.isEmpty()) exitProcessWithError("No files matching '$pattern' in '$baseDir'")
+ if (candidates.isEmpty()) exitProcessWithError(
+ "No files matching '$includePattern'" +
+ (if (excludePattern == null) "" else " (and excluding $excludePattern)") +
+ " in '$baseDir'"
+ )
return promptPickFile(candidates, baseDir)
}
diff --git a/development/bench-flame-diff/app/src/main/resources/templates/index.html b/development/bench-flame-diff/app/src/main/resources/templates/index.html
index 90ee7c4..fd2899e 100644
--- a/development/bench-flame-diff/app/src/main/resources/templates/index.html
+++ b/development/bench-flame-diff/app/src/main/resources/templates/index.html
@@ -37,6 +37,7 @@
<div class="spacer">|</div>
<button class="button" onclick="window.open('http://go/bench-flame-diff-readme')">help</button>
</div>
+ <div id="results"></div>
<div id="%before_raw_name%" class="svg">
<object type="image/svg+xml" data="%before_raw_file%">Failed to display the file: %before_raw_file%</object>
</div>
@@ -51,6 +52,15 @@
</div>
</div>
+ <!-- Note: 'application/json' ensures the content is treated as data (i.e. not executed) -->
+ <script type="application/json" id="result-before-raw">
+ %benchmark_result_before_raw%
+ </script>
+
+ <script type="application/json" id="result-after-raw">
+ %benchmark_result_after_raw%
+ </script>
+
<script>
mdc.ripple.MDCRipple.attachTo(document.querySelector(".button"));
@@ -60,6 +70,31 @@
document.getElementById(tabName).style.display = "block";
}
+ function populateBenchmarkResult(stage, traceFileName) {
+ const dataString = document.getElementById(`result-${stage}-raw`).textContent.trim()
+ if (!dataString) return // no benchmark result data
+
+ const benchmark = JSON.parse(dataString).benchmarks.find(b =>
+ b.profilerOutputs &&
+ b.profilerOutputs.some(po => po.filename === traceFileName)
+ ) || undefined;
+ if (!benchmark || !benchmark.metrics) return // no benchmark matching the trace file name
+ const metrics = benchmark.metrics
+
+ let outputString = "";
+ Object.entries(metrics).forEach(([metricName, metricResult], ix) => {
+ const {minimum, maximum, median} = metricResult;
+ const resultString = JSON.stringify({minimum, maximum, median});
+ outputString += `${metricName}: ${resultString} `;
+ if (ix !== metrics.length - 1) outputString += " | "
+ })
+ document.querySelector(`#results`).innerHTML += "<div><span>" +
+ `${stage}: <code>${outputString}</code>` +
+ "</span></div>"
+ }
+
+ populateBenchmarkResult("before", "%before_trace_file_name%")
+ populateBenchmarkResult("after", "%after_trace_file_name%")
openTab("%after_diff_name%");
</script>
</body>
diff --git a/development/build_log_simplifier/messages.ignore b/development/build_log_simplifier/messages.ignore
index e00a5f7..840b4f0 100644
--- a/development/build_log_simplifier/messages.ignore
+++ b/development/build_log_simplifier/messages.ignore
@@ -245,6 +245,8 @@
WARN: .*\/unzippedJvmSources\/androidx\/cursoradapter\/widget\/ResourceCursorAdapter\.java:UnknownLine Missing @param tag for parameter `c` in DFunction ResourceCursorAdapter
WARN: .*\/unzippedJvmSources\/androidx\/customview\/poolingcontainer\/PoolingContainer\.kt:[0-9]+ Missing @param tag for parameter `listener` in DFunction addPoolingContainerListener
WARN: .*\/unzippedJvmSources\/androidx\/customview\/widget\/ViewDragHelper\.java:[0-9]+ Missing @param tag for parameter `pointerId` in DFunction isEdgeTouched
+WARN: \$OUT_DIR/androidx/docs\-public/build/unzippedJvmSources/commonJvmMain/androidx/datastore/core/Serializer\.kt:[0-9]+ Missing @param tag for parameter `output` in DFunction writeTo
+WARN: \$OUT_DIR/androidx/docs\-public/build/unzippedJvmSources/commonMain/androidx/datastore/preferences/core/Preferences\.kt:[0-9]+ Missing @param tag for parameter `value` in DFunction set
WARN: .*\/unzippedJvmSources\/androidx\/datastore\/rxjava2\/RxDataStoreDelegate\.kt:UnknownLine Missing @param tag for parameter `serializer` in DFunction rxDataStore
WARN: .*\/unzippedJvmSources\/androidx\/datastore\/rxjava3\/RxDataStoreDelegate\.kt:UnknownLine Missing @param tag for parameter `serializer` in DFunction rxDataStore
WARN: .*\/unzippedJvmSources\/androidx\/documentfile\/provider\/DocumentFile\.java:[0-9]+ Missing @param tag for parameter `context` in DFunction fromSingleUri
@@ -285,7 +287,6 @@
WARN: .*\/unzippedJvmSources\/androidx\/paging\/compose\/LazyPagingItems\.kt:[0-9]+ Failed to resolve See PagingSource\.invalidate in DFunction refresh\. Did you mean PagingSource#invalidate\?
WARN: .*\/unzippedJvmSources\/androidx\/paging\/LoadStateAdapter\.kt:[0-9]+ Missing @param tag for parameter `holder` in DFunction onBindViewHolder
WARN: .*\/unzippedJvmSources\/androidx\/palette\/graphics\/Palette\.java:[0-9]+ Missing @param tag for parameter `target` in DFunction getColorForTarget
-WARN\: \$OUT_DIR\/androidx\/docs\-tip\-of\-tree\/build\/unzippedMultiplatformSources\/nativeMain\/androidx\/room\/RoomDatabase\.native\.kt\:UnknownLine Link does not resolve for \@throws kotlin\.IllegalArgumentException in DFunction valueOf\. Is it from a package that the containing file does not import\? Are docs inherited by an un\-documented override function\, but the exception class is not in scope in the inheriting class\? The general fix for these is to fully qualify the exception name\, e\.g\. \`\@throws java\.io\.IOException under some conditions\`\.
WARN: .*\/unzippedJvmSources\/androidx\/recyclerview\/widget\/BatchingListUpdateCallback\.java:[0-9]+ Missing @param tag for parameter `payload` in DFunction onChanged
WARN: .*\/unzippedJvmSources\/androidx\/recyclerview\/widget\/DefaultItemAnimator\.java:[0-9]+ Missing @param tag for parameter `fromX` in DFunction animateMove
WARN: .*\/unzippedJvmSources\/androidx\/recyclerview\/widget\/DefaultItemAnimator\.java:[0-9]+ Missing @param tag for parameter `fromY` in DFunction animateMove
@@ -503,12 +504,10 @@
WARN: .*\/unzippedMultiplatformSources\/jvmMain\/androidx\/datastore\/core\/Serializer\.kt:[0-9]+ Missing @param tag for parameter `output` in DFunction writeTo
WARN: .*\/unzippedMultiplatformSources\/commonJvmMain\/androidx\/datastore\/core\/Serializer\.kt:[0-9]+ Missing @param tag for parameter `output` in DFunction writeTo
WARN: .*\/unzippedMultiplatformSources\/nonJvmMain\/androidx\/annotation\/RestrictTo\.nonJvm\.kt:UnknownLine Link does not resolve for @throws kotlin\.IllegalArgumentException in DFunction valueOf\. Is it from a package that the containing file does not import\? Are docs inherited by an un-documented override function, but the exception class is not in scope in the inheriting class\? The general fix for these is to fully qualify the exception name, e\.g\. `@throws java\.io\.IOException under some conditions`\.
+WARN: .*\/unzippedMultiplatformSources\/.*Main\/androidx\/room\/RoomDatabase.*\.kt:UnknownLine Link does not resolve for @throws kotlin\.IllegalArgumentException in DFunction valueOf\. Is it from a package that the containing file does not import\? Are docs inherited by an un-documented override function, but the exception class is not in scope in the inheriting class\? The general fix for these is to fully qualify the exception name, e\.g\. `@throws java\.io\.IOException under some conditions`\.
WARN: File location could not be determined\. Failed to resolve See <a href="https:\/\/developer\.android\.com\/training\/transitions">Transition API Guide<\/a> in DPackage androidx\.transition
-# Task docs-*:unzipJvmSources
-# paging and wear have multiple libraries depending on the same samples library, which can cause the samples library to be unzipped multiple times
-Encountered duplicate path "androidx/paging/samples/.*
-Encountered duplicate path "androidx/wear/compose/material/samples/.*
-Encountered duplicate path "androidx/wear/watchface/samples/.*
+[0-9]+ cpus, so not storing build metrics.
+64 cpus, so storing build metrics.
# > Task :compose:ui:ui-tooling:processDebugAndroidTestManifest
\$SUPPORT/compose/ui/ui\-tooling/src/androidInstrumentedTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
# ./gradlew tasks warns as we have warnings present
@@ -608,4 +607,4 @@
# > Task :room:integration-tests:room-testapp-multiplatform:ksp.*
i: \[ksp\] loaded provider\(s\): \[androidx\.room\.RoomKspProcessor\$Provider\]
# buildPrivacySandboxSdkApksForDebug (b/329101823)
-Extracted sandbox SDK APK for.*
+Extracted sandbox SDK APK for.*
\ No newline at end of file
diff --git a/docs-public/build.gradle b/docs-public/build.gradle
index 7a6119e..e1972be 100644
--- a/docs-public/build.gradle
+++ b/docs-public/build.gradle
@@ -15,15 +15,14 @@
}
dependencies {
- docs("androidx.activity:activity:1.9.0-rc01")
- docs("androidx.activity:activity-compose:1.9.0-rc01")
- samples("androidx.activity:activity-compose-samples:1.9.0-rc01")
- docs("androidx.activity:activity-ktx:1.9.0-rc01")
+ docs("androidx.activity:activity:1.9.0")
+ docs("androidx.activity:activity-compose:1.9.0")
+ docs("androidx.activity:activity-ktx:1.9.0")
// ads-identifier is deprecated
docsWithoutApiSince("androidx.ads:ads-identifier:1.0.0-alpha05")
docsWithoutApiSince("androidx.ads:ads-identifier-common:1.0.0-alpha05")
docsWithoutApiSince("androidx.ads:ads-identifier-provider:1.0.0-alpha05")
- kmpDocs("androidx.annotation:annotation:1.8.0-beta01")
+ kmpDocs("androidx.annotation:annotation:1.8.0-beta02")
docs("androidx.annotation:annotation-experimental:1.4.1")
docs("androidx.appcompat:appcompat:1.7.0-alpha03")
docs("androidx.appcompat:appcompat-resources:1.7.0-alpha03")
@@ -39,94 +38,87 @@
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.3.0-alpha02")
- docs("androidx.benchmark:benchmark-junit4:1.3.0-alpha02")
- docs("androidx.benchmark:benchmark-macro:1.3.0-alpha02")
- docs("androidx.benchmark:benchmark-macro-junit4:1.3.0-alpha02")
+ docs("androidx.benchmark:benchmark-common:1.3.0-alpha03")
+ docs("androidx.benchmark:benchmark-junit4:1.3.0-alpha03")
+ docs("androidx.benchmark:benchmark-macro:1.3.0-alpha03")
+ docs("androidx.benchmark:benchmark-macro-junit4:1.3.0-alpha03")
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")
docs("androidx.bluetooth:bluetooth:1.0.0-alpha02")
docs("androidx.bluetooth:bluetooth-testing:1.0.0-alpha02")
docs("androidx.browser:browser:1.8.0")
- docs("androidx.camera:camera-camera2:1.4.0-alpha04")
- docs("androidx.camera:camera-core:1.4.0-alpha04")
- docs("androidx.camera:camera-effects:1.4.0-alpha04")
- docs("androidx.camera:camera-extensions:1.4.0-alpha04")
+ docs("androidx.camera:camera-camera2:1.4.0-alpha05")
+ docs("androidx.camera:camera-core:1.4.0-alpha05")
+ docs("androidx.camera:camera-effects:1.4.0-alpha05")
+ docs("androidx.camera:camera-extensions:1.4.0-alpha05")
stubs(fileTree(dir: "../camera/camera-extensions-stub", include: ["camera-extensions-stub.jar"]))
docs("androidx.camera:camera-lifecycle:1.4.0-alpha04")
- docs("androidx.camera:camera-mlkit-vision:1.4.0-alpha04")
- docs("androidx.camera:camera-video:1.4.0-alpha04")
- docs("androidx.camera:camera-view:1.4.0-alpha04")
- docs("androidx.camera:camera-viewfinder:1.4.0-alpha04")
+ docs("androidx.camera:camera-mlkit-vision:1.4.0-alpha05")
+ docs("androidx.camera:camera-video:1.4.0-alpha05")
+ docs("androidx.camera:camera-view:1.4.0-alpha05")
+ docs("androidx.camera:camera-viewfinder:1.4.0-alpha05")
docs("androidx.camera:camera-viewfinder-compose:1.4.0-alpha03")
- docs("androidx.camera:camera-viewfinder-core:1.4.0-alpha04")
- samples("androidx.camera:camera-viewfinder-core-samples:1.4.0-alpha04")
- docs("androidx.car.app:app:1.7.0-alpha01")
- docs("androidx.car.app:app-automotive:1.7.0-alpha01")
- docs("androidx.car.app:app-projected:1.7.0-alpha01")
- docs("androidx.car.app:app-testing:1.7.0-alpha01")
+ docs("androidx.camera:camera-viewfinder-core:1.4.0-alpha05")
+ docs("androidx.car.app:app:1.7.0-alpha02")
+ docs("androidx.car.app:app-automotive:1.7.0-alpha02")
+ docs("androidx.car.app:app-projected:1.7.0-alpha02")
+ docs("androidx.car.app:app-testing:1.7.0-alpha02")
docs("androidx.cardview:cardview:1.0.0")
kmpDocs("androidx.collection:collection:1.4.0")
docs("androidx.collection:collection-ktx:1.4.0-rc01")
- kmpDocs("androidx.compose.animation:animation:1.7.0-alpha06")
- kmpDocs("androidx.compose.animation:animation-core:1.7.0-alpha06")
- kmpDocs("androidx.compose.animation:animation-graphics:1.7.0-alpha06")
- samples("androidx.compose.animation:animation-samples:1.7.0-alpha06")
- samples("androidx.compose.animation:animation-core-samples:1.7.0-alpha06")
- samples("androidx.compose.animation:animation-graphics-samples:1.7.0-alpha06")
- kmpDocs("androidx.compose.foundation:foundation:1.7.0-alpha06")
- kmpDocs("androidx.compose.foundation:foundation-layout:1.7.0-alpha06")
- samples("androidx.compose.foundation:foundation-layout-samples:1.7.0-alpha06")
- samples("androidx.compose.foundation:foundation-samples:1.7.0-alpha06")
- kmpDocs("androidx.compose.material3.adaptive:adaptive:1.0.0-alpha10")
- kmpDocs("androidx.compose.material3.adaptive:adaptive-layout:1.0.0-alpha10")
- docs("androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-alpha10")
- samples("androidx.compose.material3.adaptive:adaptive-samples:1.0.0-alpha10")
- kmpDocs("androidx.compose.material3:material3:1.3.0-alpha04")
- kmpDocs("androidx.compose.material3:material3-adaptive-navigation-suite:1.0.0-alpha05")
+ kmpDocs("androidx.compose.animation:animation:1.7.0-alpha07")
+ kmpDocs("androidx.compose.animation:animation-core:1.7.0-alpha07")
+ kmpDocs("androidx.compose.animation:animation-graphics:1.7.0-alpha07")
+ samples("androidx.compose.animation:animation-samples:1.7.0-alpha07")
+ samples("androidx.compose.animation:animation-core-samples:1.7.0-alpha07")
+ samples("androidx.compose.animation:animation-graphics-samples:1.7.0-alpha07")
+ kmpDocs("androidx.compose.foundation:foundation:1.7.0-alpha07")
+ kmpDocs("androidx.compose.foundation:foundation-layout:1.7.0-alpha07")
+ samples("androidx.compose.foundation:foundation-layout-samples:1.7.0-alpha07")
+ samples("androidx.compose.foundation:foundation-samples:1.7.0-alpha07")
+ kmpDocs("androidx.compose.material3.adaptive:adaptive:1.0.0-alpha11")
+ kmpDocs("androidx.compose.material3.adaptive:adaptive-layout:1.0.0-alpha11")
+ kmpDocs("androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-alpha11")
+ samples("androidx.compose.material3.adaptive:adaptive-samples:1.0.0-alpha11")
+ kmpDocs("androidx.compose.material3:material3:1.3.0-alpha05")
+ kmpDocs("androidx.compose.material3:material3-adaptive-navigation-suite:1.0.0-alpha06")
samples("androidx.compose.material3:material3-adaptive-navigation-suite-samples:1.3.0-alpha04")
docs("androidx.compose.material3:material3-common:1.0.0-alpha01")
- samples("androidx.compose.material3:material3-samples:1.3.0-alpha04")
- kmpDocs("androidx.compose.material3:material3-window-size-class:1.3.0-alpha04")
+ samples("androidx.compose.material3:material3-common-samples:1.3.0-alpha05")
+ samples("androidx.compose.material3:material3-samples:1.3.0-alpha05")
+ kmpDocs("androidx.compose.material3:material3-window-size-class:1.3.0-alpha05")
samples("androidx.compose.material3:material3-window-size-class-samples:1.3.0-alpha04")
- kmpDocs("androidx.compose.material:material:1.7.0-alpha06")
- kmpDocs("androidx.compose.material:material-icons-core:1.7.0-alpha06")
- samples("androidx.compose.material:material-icons-core-samples:1.7.0-alpha06")
- docs("androidx.compose.material:material-navigation:1.7.0-alpha06")
- samples("androidx.compose.material:material-navigation-samples:1.7.0-alpha06")
- kmpDocs("androidx.compose.material:material-ripple:1.7.0-alpha06")
- samples("androidx.compose.material:material-samples:1.7.0-alpha06")
- kmpDocs("androidx.compose.runtime:runtime:1.7.0-alpha06")
- docs("androidx.compose.runtime:runtime-livedata:1.7.0-alpha06")
- samples("androidx.compose.runtime:runtime-livedata-samples:1.7.0-alpha06")
- docs("androidx.compose.runtime:runtime-rxjava2:1.7.0-alpha06")
- samples("androidx.compose.runtime:runtime-rxjava2-samples:1.7.0-alpha06")
- docs("androidx.compose.runtime:runtime-rxjava3:1.7.0-alpha06")
- samples("androidx.compose.runtime:runtime-rxjava3-samples:1.7.0-alpha06")
- kmpDocs("androidx.compose.runtime:runtime-saveable:1.7.0-alpha06")
- samples("androidx.compose.runtime:runtime-saveable-samples:1.7.0-alpha06")
- samples("androidx.compose.runtime:runtime-samples:1.7.0-alpha06")
+ kmpDocs("androidx.compose.material:material:1.7.0-alpha07")
+ kmpDocs("androidx.compose.material:material-icons-core:1.7.0-alpha07")
+ samples("androidx.compose.material:material-icons-core-samples:1.7.0-alpha07")
+ docs("androidx.compose.material:material-navigation:1.7.0-alpha07")
+ samples("androidx.compose.material:material-navigation-samples:1.7.0-alpha07")
+ kmpDocs("androidx.compose.material:material-ripple:1.7.0-alpha07")
+ kmpDocs("androidx.compose.runtime:runtime:1.7.0-alpha07")
+ docs("androidx.compose.runtime:runtime-livedata:1.7.0-alpha07")
+ docs("androidx.compose.runtime:runtime-rxjava2:1.7.0-alpha07")
+ docs("androidx.compose.runtime:runtime-rxjava3:1.7.0-alpha07")
+ kmpDocs("androidx.compose.runtime:runtime-saveable:1.7.0-alpha07")
docs("androidx.compose.runtime:runtime-tracing:1.0.0-beta01")
- kmpDocs("androidx.compose.ui:ui:1.7.0-alpha06")
- kmpDocs("androidx.compose.ui:ui-geometry:1.7.0-alpha06")
- kmpDocs("androidx.compose.ui:ui-graphics:1.7.0-alpha06")
- samples("androidx.compose.ui:ui-graphics-samples:1.7.0-alpha06")
- kmpDocs("androidx.compose.ui:ui-test:1.7.0-alpha06")
- kmpDocs("androidx.compose.ui:ui-test-junit4:1.7.0-alpha06")
- samples("androidx.compose.ui:ui-test-samples:1.7.0-alpha06")
- kmpDocs("androidx.compose.ui:ui-text:1.7.0-alpha06")
- docs("androidx.compose.ui:ui-text-google-fonts:1.7.0-alpha06")
- samples("androidx.compose.ui:ui-text-samples:1.7.0-alpha06")
- kmpDocs("androidx.compose.ui:ui-tooling:1.7.0-alpha06")
- kmpDocs("androidx.compose.ui:ui-tooling-data:1.7.0-alpha06")
- kmpDocs("androidx.compose.ui:ui-tooling-preview:1.7.0-alpha06")
- kmpDocs("androidx.compose.ui:ui-unit:1.7.0-alpha06")
- samples("androidx.compose.ui:ui-unit-samples:1.7.0-alpha06")
- kmpDocs("androidx.compose.ui:ui-util:1.7.0-alpha06")
- docs("androidx.compose.ui:ui-viewbinding:1.7.0-alpha06")
- samples("androidx.compose.ui:ui-viewbinding-samples:1.7.0-alpha06")
- samples("androidx.compose.ui:ui-samples:1.7.0-alpha06")
+ kmpDocs("androidx.compose.ui:ui:1.7.0-alpha07")
+ docs("androidx.compose.ui:ui-android-stubs:1.7.0-alpha07")
+ kmpDocs("androidx.compose.ui:ui-geometry:1.7.0-alpha07")
+ kmpDocs("androidx.compose.ui:ui-graphics:1.7.0-alpha07")
+ samples("androidx.compose.ui:ui-graphics-samples:1.7.0-alpha07")
+ kmpDocs("androidx.compose.ui:ui-test:1.7.0-alpha07")
+ kmpDocs("androidx.compose.ui:ui-test-junit4:1.7.0-alpha07")
+ samples("androidx.compose.ui:ui-test-samples:1.7.0-alpha07")
+ kmpDocs("androidx.compose.ui:ui-text:1.7.0-alpha07")
+ docs("androidx.compose.ui:ui-text-google-fonts:1.7.0-alpha07")
+ samples("androidx.compose.ui:ui-text-samples:1.7.0-alpha07")
+ kmpDocs("androidx.compose.ui:ui-tooling:1.7.0-alpha07")
+ kmpDocs("androidx.compose.ui:ui-tooling-data:1.7.0-alpha07")
+ kmpDocs("androidx.compose.ui:ui-tooling-preview:1.7.0-alpha07")
+ kmpDocs("androidx.compose.ui:ui-unit:1.7.0-alpha07")
+ kmpDocs("androidx.compose.ui:ui-util:1.7.0-alpha07")
+ docs("androidx.compose.ui:ui-viewbinding:1.7.0-alpha07")
+ samples("androidx.compose.ui:ui-samples:1.7.0-alpha07")
docs("androidx.concurrent:concurrent-futures:1.2.0-alpha03")
docs("androidx.concurrent:concurrent-futures-ktx:1.2.0-alpha03")
docs("androidx.constraintlayout:constraintlayout:2.2.0-alpha13")
@@ -146,31 +138,31 @@
docs("androidx.core:core-performance-play-services:1.0.0")
samples("androidx.core:core-performance-samples:1.0.0")
docs("androidx.core:core-performance-testing:1.0.0")
- docs("androidx.core:core-remoteviews:1.1.0-beta01")
+ docs("androidx.core:core-remoteviews:1.1.0-beta02")
docs("androidx.core:core-role:1.2.0-alpha01")
- docs("androidx.core:core-splashscreen:1.1.0-alpha02")
- docs("androidx.core:core-telecom:1.0.0-alpha02")
+ docs("androidx.core:core-splashscreen:1.2.0-alpha01")
+ docs("androidx.core:core-telecom:1.0.0-alpha03")
docs("androidx.core:core-testing:1.13.0")
docs("androidx.core.uwb:uwb:1.0.0-alpha08")
docs("androidx.core.uwb:uwb-rxjava3:1.0.0-alpha08")
- docs("androidx.credentials:credentials:1.3.0-alpha02")
- docs("androidx.credentials:credentials-e2ee:1.0.0-alpha01")
+ docs("androidx.credentials:credentials:1.3.0-alpha03")
+ docs("androidx.credentials:credentials-e2ee:1.0.0-alpha02")
docs("androidx.credentials:credentials-fido:1.0.0-alpha02")
- docs("androidx.credentials:credentials-play-services-auth:1.3.0-alpha02")
- samples("androidx.credentials:credentials-samples:1.3.0-alpha02")
+ docs("androidx.credentials:credentials-play-services-auth:1.3.0-alpha03")
+ samples("androidx.credentials:credentials-samples:1.3.0-alpha03")
docs("androidx.cursoradapter:cursoradapter:1.0.0")
docs("androidx.customview:customview:1.2.0-alpha02")
// TODO(b/294531403): Turn on apiSince for customview-poolingcontainer when it releases as alpha
docsWithoutApiSince("androidx.customview:customview-poolingcontainer:1.0.0-rc01")
- kmpDocs("androidx.datastore:datastore:1.1.0-rc01")
- kmpDocs("androidx.datastore:datastore-core:1.1.0-rc01")
- kmpDocs("androidx.datastore:datastore-core-okio:1.1.0-rc01")
- kmpDocs("androidx.datastore:datastore-preferences:1.1.0-rc01")
- kmpDocs("androidx.datastore:datastore-preferences-core:1.1.0-rc01")
- docs("androidx.datastore:datastore-preferences-rxjava2:1.1.0-rc01")
- docs("androidx.datastore:datastore-preferences-rxjava3:1.1.0-rc01")
- docs("androidx.datastore:datastore-rxjava2:1.1.0-rc01")
- docs("androidx.datastore:datastore-rxjava3:1.1.0-rc01")
+ docs("androidx.datastore:datastore:1.1.0")
+ docs("androidx.datastore:datastore-core:1.1.0")
+ docs("androidx.datastore:datastore-core-okio:1.1.0")
+ docs("androidx.datastore:datastore-preferences:1.1.0")
+ docs("androidx.datastore:datastore-preferences-core:1.1.0")
+ docs("androidx.datastore:datastore-preferences-rxjava2:1.1.0")
+ docs("androidx.datastore:datastore-preferences-rxjava3:1.1.0")
+ docs("androidx.datastore:datastore-rxjava2:1.1.0")
+ docs("androidx.datastore:datastore-rxjava3:1.1.0")
docs("androidx.documentfile:documentfile:1.1.0-alpha01")
docs("androidx.draganddrop:draganddrop:1.0.0")
docs("androidx.drawerlayout:drawerlayout:1.2.0")
@@ -187,25 +179,22 @@
docs("androidx.enterprise:enterprise-feedback:1.1.0")
docs("androidx.enterprise:enterprise-feedback-testing:1.1.0")
docs("androidx.exifinterface:exifinterface:1.3.6")
- docs("androidx.fragment:fragment:1.8.0-alpha01")
- docs("androidx.fragment:fragment-compose:1.8.0-alpha01")
- samples("androidx.fragment:fragment-compose-samples:1.8.0-alpha01")
- docs("androidx.fragment:fragment-ktx:1.8.0-alpha01")
- docs("androidx.fragment:fragment-testing:1.8.0-alpha01")
- docs("androidx.glance:glance:1.1.0-beta01")
- docs("androidx.glance:glance-appwidget:1.1.0-beta01")
- samples("androidx.glance:glance-appwidget-samples:1.1.0-beta01")
+ docs("androidx.fragment:fragment:1.8.0-alpha02")
+ docs("androidx.fragment:fragment-compose:1.8.0-alpha02")
+ docs("androidx.fragment:fragment-ktx:1.8.0-alpha02")
+ docs("androidx.fragment:fragment-testing:1.8.0-alpha02")
+ docs("androidx.glance:glance:1.1.0-beta02")
+ docs("androidx.glance:glance-appwidget:1.1.0-beta02")
docs("androidx.glance:glance-appwidget-preview:1.0.0-alpha06")
- docs("androidx.glance:glance-appwidget-testing:1.1.0-beta01")
- samples("androidx.glance:glance-appwidget-testing-samples:1.1.0-beta01")
- docs("androidx.glance:glance-material:1.1.0-beta01")
- docs("androidx.glance:glance-material3:1.1.0-beta01")
+ docs("androidx.glance:glance-appwidget-testing:1.1.0-beta02")
+ docs("androidx.glance:glance-material:1.1.0-beta02")
+ docs("androidx.glance:glance-material3:1.1.0-beta02")
docs("androidx.glance:glance-preview:1.0.0-alpha06")
docs("androidx.glance:glance-template:1.0.0-alpha06")
- docs("androidx.glance:glance-testing:1.1.0-beta01")
+ docs("androidx.glance:glance-testing:1.1.0-beta02")
docs("androidx.glance:glance-wear-tiles:1.0.0-alpha06")
- docs("androidx.graphics:graphics-core:1.0.0-beta01")
- samples("androidx.graphics:graphics-core-samples:1.0.0-beta01")
+ docs("androidx.graphics:graphics-core:1.0.0-rc01")
+ samples("androidx.graphics:graphics-core-samples:1.0.0-rc01")
docs("androidx.graphics:graphics-path:1.0.0")
kmpDocs("androidx.graphics:graphics-shapes:1.0.0-alpha05")
docs("androidx.gridlayout:gridlayout:1.1.0-beta01")
@@ -216,7 +205,6 @@
docs("androidx.hilt:hilt-common:1.2.0")
docs("androidx.hilt:hilt-navigation:1.2.0")
docs("androidx.hilt:hilt-navigation-compose:1.2.0")
- samples("androidx.hilt:hilt-navigation-compose-samples:1.2.0")
docs("androidx.hilt:hilt-navigation-fragment:1.2.0")
docs("androidx.hilt:hilt-work:1.2.0")
docs("androidx.input:input-motionprediction:1.0.0-beta03")
@@ -227,27 +215,26 @@
docs("androidx.leanback:leanback-paging:1.1.0-alpha11")
docs("androidx.leanback:leanback-preference:1.2.0-alpha04")
docs("androidx.leanback:leanback-tab:1.1.0-beta01")
- kmpDocs("androidx.lifecycle:lifecycle-common:2.8.0-alpha04")
- docs("androidx.lifecycle:lifecycle-common-java8:2.8.0-alpha04")
+ kmpDocs("androidx.lifecycle:lifecycle-common:2.8.0-beta01")
+ docs("androidx.lifecycle:lifecycle-common-java8:2.8.0-beta01")
docs("androidx.lifecycle:lifecycle-extensions:2.2.0")
- docs("androidx.lifecycle:lifecycle-livedata:2.8.0-alpha04")
- docs("androidx.lifecycle:lifecycle-livedata-core:2.8.0-alpha04")
- docs("androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.0-alpha04")
- docs("androidx.lifecycle:lifecycle-livedata-ktx:2.8.0-alpha04")
- docs("androidx.lifecycle:lifecycle-process:2.8.0-alpha04")
- docs("androidx.lifecycle:lifecycle-reactivestreams:2.8.0-alpha04")
- docs("androidx.lifecycle:lifecycle-reactivestreams-ktx:2.8.0-alpha04")
- kmpDocs("androidx.lifecycle:lifecycle-runtime:2.8.0-alpha04")
- docs("androidx.lifecycle:lifecycle-runtime-compose:2.8.0-alpha04")
- samples("androidx.lifecycle:lifecycle-runtime-compose-samples:2.8.0-alpha04")
- kmpDocs("androidx.lifecycle:lifecycle-runtime-ktx:2.8.0-alpha04")
- docs("androidx.lifecycle:lifecycle-runtime-testing:2.8.0-alpha04")
- docs("androidx.lifecycle:lifecycle-service:2.8.0-alpha04")
- kmpDocs("androidx.lifecycle:lifecycle-viewmodel:2.8.0-alpha04")
- docs("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.0-alpha04")
- samples("androidx.lifecycle:lifecycle-viewmodel-compose-samples:2.8.0-alpha04")
- docs("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0-alpha04")
- docs("androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.0-alpha04")
+ docs("androidx.lifecycle:lifecycle-livedata:2.8.0-beta01")
+ docs("androidx.lifecycle:lifecycle-livedata-core:2.8.0-beta01")
+ docs("androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.0-beta01")
+ docs("androidx.lifecycle:lifecycle-livedata-ktx:2.8.0-beta01")
+ docs("androidx.lifecycle:lifecycle-process:2.8.0-beta01")
+ docs("androidx.lifecycle:lifecycle-reactivestreams:2.8.0-beta01")
+ docs("androidx.lifecycle:lifecycle-reactivestreams-ktx:2.8.0-beta01")
+ kmpDocs("androidx.lifecycle:lifecycle-runtime:2.8.0-beta01")
+ kmpDocs("androidx.lifecycle:lifecycle-runtime-compose:2.8.0-beta01")
+ kmpDocs("androidx.lifecycle:lifecycle-runtime-ktx:2.8.0-beta01")
+ docs("androidx.lifecycle:lifecycle-runtime-testing:2.8.0-beta01")
+ docs("androidx.lifecycle:lifecycle-service:2.8.0-beta01")
+ kmpDocs("androidx.lifecycle:lifecycle-viewmodel:2.8.0-beta01")
+ kmpDocs("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.0-beta01")
+ samples("androidx.lifecycle:lifecycle-viewmodel-compose-samples:2.8.0-beta01")
+ docs("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0-beta01")
+ docs("androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.0-beta01")
docs("androidx.loader:loader:1.1.0")
// localbroadcastmanager is deprecated
docsWithoutApiSince("androidx.localbroadcastmanager:localbroadcastmanager:1.1.0")
@@ -285,31 +272,29 @@
docs("androidx.mediarouter:mediarouter:1.7.0")
docs("androidx.mediarouter:mediarouter-testing:1.7.0")
docs("androidx.metrics:metrics-performance:1.0.0-beta01")
- docs("androidx.navigation:navigation-common:2.8.0-alpha06")
- docs("androidx.navigation:navigation-common-ktx:2.8.0-alpha06")
- docs("androidx.navigation:navigation-compose:2.8.0-alpha06")
- samples("androidx.navigation:navigation-compose-samples:2.8.0-alpha06")
- docs("androidx.navigation:navigation-dynamic-features-fragment:2.8.0-alpha06")
- docs("androidx.navigation:navigation-dynamic-features-runtime:2.8.0-alpha06")
- docs("androidx.navigation:navigation-fragment:2.8.0-alpha06")
- docs("androidx.navigation:navigation-fragment-ktx:2.8.0-alpha06")
- docs("androidx.navigation:navigation-runtime:2.8.0-alpha06")
- docs("androidx.navigation:navigation-runtime-ktx:2.8.0-alpha06")
- docs("androidx.navigation:navigation-testing:2.8.0-alpha06")
- docs("androidx.navigation:navigation-ui:2.8.0-alpha06")
- docs("androidx.navigation:navigation-ui-ktx:2.8.0-alpha06")
- kmpDocs("androidx.paging:paging-common:3.3.0-beta01")
- docs("androidx.paging:paging-common-ktx:3.3.0-beta01")
- kmpDocs("androidx.paging:paging-compose:3.3.0-beta01")
- samples("androidx.paging:paging-compose-samples:3.3.0-beta01")
- docs("androidx.paging:paging-guava:3.3.0-beta01")
- docs("androidx.paging:paging-runtime:3.3.0-beta01")
- docs("androidx.paging:paging-runtime-ktx:3.3.0-beta01")
- docs("androidx.paging:paging-rxjava2:3.3.0-beta01")
- docs("androidx.paging:paging-rxjava2-ktx:3.3.0-beta01")
- docs("androidx.paging:paging-rxjava3:3.3.0-beta01")
- samples("androidx.paging:paging-samples:3.3.0-beta01")
- kmpDocs("androidx.paging:paging-testing:3.3.0-beta01")
+ docs("androidx.navigation:navigation-common:2.8.0-alpha07")
+ docs("androidx.navigation:navigation-common-ktx:2.8.0-alpha07")
+ docs("androidx.navigation:navigation-compose:2.8.0-alpha07")
+ docs("androidx.navigation:navigation-dynamic-features-fragment:2.8.0-alpha07")
+ docs("androidx.navigation:navigation-dynamic-features-runtime:2.8.0-alpha07")
+ docs("androidx.navigation:navigation-fragment:2.8.0-alpha07")
+ docs("androidx.navigation:navigation-fragment-compose:2.8.0-alpha07")
+ docs("androidx.navigation:navigation-fragment-ktx:2.8.0-alpha07")
+ docs("androidx.navigation:navigation-runtime:2.8.0-alpha07")
+ docs("androidx.navigation:navigation-runtime-ktx:2.8.0-alpha07")
+ docs("androidx.navigation:navigation-testing:2.8.0-alpha07")
+ docs("androidx.navigation:navigation-ui:2.8.0-alpha07")
+ docs("androidx.navigation:navigation-ui-ktx:2.8.0-alpha07")
+ kmpDocs("androidx.paging:paging-common:3.3.0-rc01")
+ docs("androidx.paging:paging-common-ktx:3.3.0-rc01")
+ kmpDocs("androidx.paging:paging-compose:3.3.0-rc01")
+ docs("androidx.paging:paging-guava:3.3.0-rc01")
+ docs("androidx.paging:paging-runtime:3.3.0-rc01")
+ docs("androidx.paging:paging-runtime-ktx:3.3.0-rc01")
+ docs("androidx.paging:paging-rxjava2:3.3.0-rc01")
+ docs("androidx.paging:paging-rxjava2-ktx:3.3.0-rc01")
+ docs("androidx.paging:paging-rxjava3:3.3.0-rc01")
+ kmpDocs("androidx.paging:paging-testing:3.3.0-rc01")
docs("androidx.palette:palette:1.0.0")
docs("androidx.palette:palette-ktx:1.0.0")
docs("androidx.percentlayout:percentlayout:1.0.1")
@@ -319,8 +304,8 @@
docs("androidx.privacysandbox.activity:activity-client:1.0.0-alpha01")
docs("androidx.privacysandbox.activity:activity-core:1.0.0-alpha01")
docs("androidx.privacysandbox.activity:activity-provider:1.0.0-alpha01")
- docs("androidx.privacysandbox.ads:ads-adservices:1.1.0-beta05")
- docs("androidx.privacysandbox.ads:ads-adservices-java:1.1.0-beta05")
+ docs("androidx.privacysandbox.ads:ads-adservices:1.1.0-beta06")
+ docs("androidx.privacysandbox.ads:ads-adservices-java:1.1.0-beta06")
docs("androidx.privacysandbox.sdkruntime:sdkruntime-client:1.0.0-alpha13")
docs("androidx.privacysandbox.sdkruntime:sdkruntime-core:1.0.0-alpha13")
docs("androidx.privacysandbox.sdkruntime:sdkruntime-provider:1.0.0-alpha13")
@@ -393,8 +378,8 @@
// TODO(243405142) clean-up
docsWithoutApiSince("androidx.tracing:tracing-perfetto-common:1.0.0-alpha16")
docs("androidx.tracing:tracing-perfetto-handshake:1.0.0")
- docs("androidx.transition:transition:1.5.0-rc01")
- docs("androidx.transition:transition-ktx:1.5.0-rc01")
+ docs("androidx.transition:transition:1.5.0-rc02")
+ docs("androidx.transition:transition-ktx:1.5.0-rc02")
docs("androidx.tv:tv-foundation:1.0.0-alpha10")
docs("androidx.tv:tv-material:1.0.0-alpha10")
samples("androidx.tv:tv-samples:1.0.0-alpha10")
@@ -405,16 +390,13 @@
docs("androidx.versionedparcelable:versionedparcelable:1.2.0")
docs("androidx.viewpager2:viewpager2:1.1.0-beta02")
docs("androidx.viewpager:viewpager:1.1.0-alpha01")
- docs("androidx.wear.compose:compose-foundation:1.4.0-alpha06")
- samples("androidx.wear.compose:compose-foundation-samples:1.4.0-alpha06")
- docs("androidx.wear.compose:compose-material:1.4.0-alpha06")
- docs("androidx.wear.compose:compose-material-core:1.4.0-alpha06")
- samples("androidx.wear.compose:compose-material-samples:1.4.0-alpha06")
- docs("androidx.wear.compose:compose-material3:1.0.0-alpha20")
- samples("androidx.wear.compose:compose-material3-samples:1.4.0-alpha06")
- docs("androidx.wear.compose:compose-navigation:1.4.0-alpha06")
- samples("androidx.wear.compose:compose-navigation-samples:1.4.0-alpha06")
- docs("androidx.wear.compose:compose-ui-tooling:1.4.0-alpha06")
+ docs("androidx.wear.compose:compose-foundation:1.4.0-alpha07")
+ docs("androidx.wear.compose:compose-material:1.4.0-alpha07")
+ docs("androidx.wear.compose:compose-material-core:1.4.0-alpha07")
+ docs("androidx.wear.compose:compose-material3:1.0.0-alpha21")
+ samples("androidx.wear.compose:compose-material3-samples:1.4.0-alpha07")
+ docs("androidx.wear.compose:compose-navigation:1.4.0-alpha07")
+ docs("androidx.wear.compose:compose-ui-tooling:1.4.0-alpha07")
docs("androidx.wear.protolayout:protolayout:1.2.0-alpha01")
docs("androidx.wear.protolayout:protolayout-expression:1.2.0-alpha01")
docs("androidx.wear.protolayout:protolayout-expression-pipeline:1.2.0-alpha01")
@@ -427,22 +409,19 @@
docs("androidx.wear.tiles:tiles-testing:1.4.0-alpha01")
docs("androidx.wear.tiles:tiles-tooling:1.4.0-alpha01")
docs("androidx.wear.tiles:tiles-tooling-preview:1.4.0-alpha01")
- docs("androidx.wear.watchface:watchface:1.3.0-alpha02")
- docs("androidx.wear.watchface:watchface-client:1.3.0-alpha02")
- docs("androidx.wear.watchface:watchface-client-guava:1.3.0-alpha02")
- docs("androidx.wear.watchface:watchface-complications:1.3.0-alpha02")
- docs("androidx.wear.watchface:watchface-complications-data:1.3.0-alpha02")
- docs("androidx.wear.watchface:watchface-complications-data-source:1.3.0-alpha02")
- docs("androidx.wear.watchface:watchface-complications-data-source-ktx:1.3.0-alpha02")
- samples("androidx.wear.watchface:watchface-complications-permission-dialogs-sample:1.3.0-alpha02")
- docs("androidx.wear.watchface:watchface-complications-rendering:1.3.0-alpha02")
- docs("androidx.wear.watchface:watchface-data:1.3.0-alpha02")
- docs("androidx.wear.watchface:watchface-editor:1.3.0-alpha02")
- docs("androidx.wear.watchface:watchface-editor-guava:1.3.0-alpha02")
- samples("androidx.wear.watchface:watchface-editor-samples:1.3.0-alpha02")
- docs("androidx.wear.watchface:watchface-guava:1.3.0-alpha02")
- samples("androidx.wear.watchface:watchface-samples:1.3.0-alpha02")
- docs("androidx.wear.watchface:watchface-style:1.3.0-alpha02")
+ docs("androidx.wear.watchface:watchface:1.3.0-alpha03")
+ docs("androidx.wear.watchface:watchface-client:1.3.0-alpha03")
+ docs("androidx.wear.watchface:watchface-client-guava:1.3.0-alpha03")
+ docs("androidx.wear.watchface:watchface-complications:1.3.0-alpha03")
+ docs("androidx.wear.watchface:watchface-complications-data:1.3.0-alpha03")
+ docs("androidx.wear.watchface:watchface-complications-data-source:1.3.0-alpha03")
+ docs("androidx.wear.watchface:watchface-complications-data-source-ktx:1.3.0-alpha03")
+ docs("androidx.wear.watchface:watchface-complications-rendering:1.3.0-alpha03")
+ docs("androidx.wear.watchface:watchface-data:1.3.0-alpha03")
+ docs("androidx.wear.watchface:watchface-editor:1.3.0-alpha03")
+ docs("androidx.wear.watchface:watchface-editor-guava:1.3.0-alpha03")
+ docs("androidx.wear.watchface:watchface-guava:1.3.0-alpha03")
+ docs("androidx.wear.watchface:watchface-style:1.3.0-alpha03")
docs("androidx.wear:wear:1.4.0-alpha01")
stubs(fileTree(dir: "../wear/wear_stubs/", include: ["com.google.android.wearable-stubs.jar"]))
docs("androidx.wear:wear-input:1.2.0-alpha02")
@@ -454,7 +433,7 @@
docs("androidx.wear:wear-remote-interactions:1.1.0-alpha02")
samples("androidx.wear:wear-remote-interactions-samples:1.1.0-alpha02")
docs("androidx.wear:wear-tooling-preview:1.0.0")
- docs("androidx.webkit:webkit:1.11.0-rc01")
+ docs("androidx.webkit:webkit:1.12.0-alpha01")
docs("androidx.window.extensions.core:core:1.0.0")
docs("androidx.window:window:1.3.0-beta01")
stubs(fileTree(dir: "../window/stubs/", include: ["window-sidecar-release-0.1.0-alpha01.aar"]))
@@ -465,16 +444,13 @@
docs("androidx.window:window-rxjava3:1.3.0-beta01")
samples("androidx.window:window-samples:1.3.0-beta01")
docs("androidx.window:window-testing:1.3.0-beta01")
- docs("androidx.work:work-gcm:2.10.0-alpha01")
- docs("androidx.work:work-multiprocess:2.10.0-alpha01")
- docs("androidx.work:work-runtime:2.10.0-alpha01")
- docs("androidx.work:work-runtime-ktx:2.10.0-alpha01")
- docs("androidx.work:work-rxjava2:2.10.0-alpha01")
- docs("androidx.work:work-rxjava3:2.10.0-alpha01")
- docs("androidx.work:work-testing:2.10.0-alpha01")
-
- // Force upgrade to jsoup 1.16.2 (b/309773103)
- stubs("org.jsoup:jsoup:1.16.2")
+ docs("androidx.work:work-gcm:2.10.0-alpha02")
+ docs("androidx.work:work-multiprocess:2.10.0-alpha02")
+ docs("androidx.work:work-runtime:2.10.0-alpha02")
+ docs("androidx.work:work-runtime-ktx:2.10.0-alpha02")
+ docs("androidx.work:work-rxjava2:2.10.0-alpha02")
+ docs("androidx.work:work-rxjava3:2.10.0-alpha02")
+ docs("androidx.work:work-testing:2.10.0-alpha02")
}
afterEvaluate {
diff --git a/docs-tip-of-tree/build.gradle b/docs-tip-of-tree/build.gradle
index fd5648d..96f3018 100644
--- a/docs-tip-of-tree/build.gradle
+++ b/docs-tip-of-tree/build.gradle
@@ -17,16 +17,17 @@
}
dependencies {
+ // If there is not at least one samples dependency, DocsImplPlugin breaks. b/332262321
+ samples("androidx.window:window-samples:1.3.0-alpha03")
+
docsForOptionalProject(":xr:xr")
docs(project(":activity:activity"))
docs(project(":activity:activity-compose"))
- samples(project(":activity:activity-compose:activity-compose-samples"))
docs(project(":activity:activity-ktx"))
// ads-identifier is deprecated
kmpDocs(project(":annotation:annotation"))
docs(project(":annotation:annotation-experimental"))
docs(project(":appactions:builtintypes:builtintypes"))
- samples(project(":appactions:builtintypes:builtintypes:builtintypes-samples"))
docs(project(":appactions:interaction:interaction-capabilities-communication"))
docs(project(":appactions:interaction:interaction-capabilities-core"))
docs(project(":appactions:interaction:interaction-capabilities-productivity"))
@@ -56,7 +57,6 @@
docs(project(":benchmark:benchmark-macro-junit4"))
docs(project(":biometric:biometric"))
docs(project(":biometric:biometric-ktx"))
- samples(project(":biometric:biometric-ktx-samples"))
docs(project(":bluetooth:bluetooth"))
docs(project(":bluetooth:bluetooth-testing"))
docs(project(":browser:browser"))
@@ -75,75 +75,49 @@
docs(project(":camera:camera-viewfinder"))
docs(project(":camera:camera-viewfinder-compose"))
docs(project(":camera:camera-viewfinder-core"))
- samples(project(":camera:camera-viewfinder-core:camera-viewfinder-core-samples"))
docs(project(":car:app:app"))
docs(project(":car:app:app-automotive"))
docs(project(":car:app:app-projected"))
docs(project(":car:app:app-testing"))
- samples(project(":car:app:app-samples:navigation-common"))
docs(project(":cardview:cardview"))
kmpDocs(project(":collection:collection"))
docs(project(":collection:collection-ktx"))
kmpDocs(project(":compose:animation:animation"))
kmpDocs(project(":compose:animation:animation-core"))
kmpDocs(project(":compose:animation:animation-graphics"))
- samples(project(":compose:animation:animation-core:animation-core-samples"))
- samples(project(":compose:animation:animation:animation-samples"))
- samples(project(":compose:animation:animation-graphics:animation-graphics-samples"))
kmpDocs(project(":compose:foundation:foundation"))
kmpDocs(project(":compose:foundation:foundation-layout"))
- samples(project(":compose:foundation:foundation-layout:foundation-layout-samples"))
- samples(project(":compose:foundation:foundation:foundation-samples"))
kmpDocs(project(":compose:material3:adaptive:adaptive"))
kmpDocs(project(":compose:material3:adaptive:adaptive-layout"))
kmpDocs(project(":compose:material3:adaptive:adaptive-navigation"))
- samples(project(":compose:material3:adaptive:adaptive-samples"))
kmpDocs(project(":compose:material3:material3"))
- samples(project(":compose:material3:material3:material3-samples"))
kmpDocs(project(":compose:material3:material3-adaptive-navigation-suite"))
- samples(project(":compose:material3:material3-adaptive-navigation-suite:material3-adaptive-navigation-suite-samples"))
kmpDocs(project(":compose:material3:material3-common"))
- samples(project(":compose:material3:material3-common:material3-common-samples"))
kmpDocs(project(":compose:material3:material3-window-size-class"))
- samples(project(":compose:material3:material3-window-size-class:material3-window-size-class-samples"))
kmpDocs(project(":compose:material:material"))
kmpDocs(project(":compose:material:material-icons-core"))
- samples(project(":compose:material:material-icons-core:material-icons-core-samples"))
kmpDocs(project(":compose:material:material-ripple"))
docs(project(":compose:material:material-navigation"))
- samples(project(":compose:material:material-navigation-samples"))
- samples(project(":compose:material:material:material-samples"))
kmpDocs(project(":compose:runtime:runtime"))
- samples(project(":compose:runtime:runtime:runtime-samples"))
docs(project(":compose:runtime:runtime-livedata"))
- samples(project(":compose:runtime:runtime-livedata:runtime-livedata-samples"))
docs(project(":compose:runtime:runtime-rxjava2"))
- samples(project(":compose:runtime:runtime-rxjava2:runtime-rxjava2-samples"))
docs(project(":compose:runtime:runtime-rxjava3"))
- samples(project(":compose:runtime:runtime-rxjava3:runtime-rxjava3-samples"))
kmpDocs(project(":compose:runtime:runtime-saveable"))
- samples(project(":compose:runtime:runtime-saveable:runtime-saveable-samples"))
docs(project(":compose:runtime:runtime-tracing"))
kmpDocs(project(":compose:ui:ui"))
docs(project(":compose:ui:ui-android-stubs"))
kmpDocs(project(":compose:ui:ui-geometry"))
kmpDocs(project(":compose:ui:ui-graphics"))
- samples(project(":compose:ui:ui-graphics:ui-graphics-samples"))
kmpDocs(project(":compose:ui:ui-test"))
- samples(project(":compose:ui:ui-test:ui-test-samples"))
kmpDocs(project(":compose:ui:ui-test-junit4"))
kmpDocs(project(":compose:ui:ui-text"))
- samples(project(":compose:ui:ui-text:ui-text-samples"))
docs(project(":compose:ui:ui-text-google-fonts"))
kmpDocs(project(":compose:ui:ui-tooling"))
kmpDocs(project(":compose:ui:ui-tooling-data"))
kmpDocs(project(":compose:ui:ui-tooling-preview"))
kmpDocs(project(":compose:ui:ui-unit"))
- samples(project(":compose:ui:ui-unit:ui-unit-samples"))
kmpDocs(project(":compose:ui:ui-util"))
docs(project(":compose:ui:ui-viewbinding"))
- samples(project(":compose:ui:ui-viewbinding:ui-viewbinding-samples"))
- samples(project(":compose:ui:ui:ui-samples"))
docs(project(":concurrent:concurrent-futures"))
docs(project(":concurrent:concurrent-futures-ktx"))
docs(project(":constraintlayout:constraintlayout"))
@@ -157,14 +131,12 @@
docs(project(":core:core-appdigest"))
docs(project(":core:core-google-shortcuts"))
docs(project(":core:haptics:haptics"))
- samples(project(":core:haptics:haptics-samples"))
docs(project(":core:core-i18n"))
docs(project(":core:core-ktx"))
docs(project(":core:core-location-altitude"))
docs(project(":core:core-performance"))
docs(project(":core:core-performance-play-services"))
docs(project(":core:core-performance-testing"))
- samples(project(":core:core-performance:core-performance-samples"))
docs(project(":core:core-remoteviews"))
docs(project(":core:core-role"))
docs(project(":core:core-splashscreen"))
@@ -174,7 +146,6 @@
docs(project(":core:uwb:uwb-rxjava3"))
docs(project(":credentials:credentials"))
docs(project(":credentials:credentials-fido"))
- samples(project(":credentials:credentials-samples"))
docs(project(":credentials:credentials-play-services-auth"))
docs(project(":credentials:credentials-e2ee"))
docs(project(":cursoradapter:cursoradapter"))
@@ -207,14 +178,11 @@
docs(project(":exifinterface:exifinterface"))
docs(project(":fragment:fragment"))
docs(project(":fragment:fragment-compose"))
- samples(project(":fragment:fragment-compose:fragment-compose-samples"))
docs(project(":fragment:fragment-ktx"))
docs(project(":fragment:fragment-testing"))
docs(project(":glance:glance"))
docs(project(":glance:glance-appwidget"))
docs(project(":glance:glance-appwidget-testing"))
- samples(project(":glance:glance-appwidget:glance-appwidget-samples"))
- samples(project(":glance:glance-appwidget-testing:glance-appwidget-testing-samples"))
docs(project(":glance:glance-appwidget-preview"))
docs(project(":glance:glance-material"))
docs(project(":glance:glance-material3"))
@@ -224,18 +192,15 @@
docs(project(":glance:glance-wear-tiles"))
docs(project(":graphics:filters:filters"))
docs(project(":graphics:graphics-core"))
- samples(project(":graphics:graphics-core:graphics-core-samples"))
docs(project(":graphics:graphics-path"))
kmpDocs(project(":graphics:graphics-shapes"))
docs(project(":gridlayout:gridlayout"))
docs(project(":health:connect:connect-client"))
- samples(project(":health:connect:connect-client-samples"))
docs(project(":health:health-services-client"))
docs(project(":heifwriter:heifwriter"))
docs(project(":hilt:hilt-common"))
docs(project(":hilt:hilt-navigation"))
docs(project(":hilt:hilt-navigation-compose"))
- samples(project(":hilt:hilt-navigation-compose-samples"))
docs(project(":hilt:hilt-navigation-fragment"))
docs(project(":hilt:hilt-work"))
docs(project(":input:input-motionprediction"))
@@ -258,13 +223,11 @@
docs(project(":lifecycle:lifecycle-reactivestreams-ktx"))
kmpDocs(project(":lifecycle:lifecycle-runtime"))
kmpDocs(project(":lifecycle:lifecycle-runtime-compose"))
- samples(project(":lifecycle:lifecycle-runtime-compose:lifecycle-runtime-compose-samples"))
kmpDocs(project(":lifecycle:lifecycle-runtime-ktx"))
docs(project(":lifecycle:lifecycle-runtime-testing"))
docs(project(":lifecycle:lifecycle-service"))
kmpDocs(project(":lifecycle:lifecycle-viewmodel"))
kmpDocs(project(":lifecycle:lifecycle-viewmodel-compose"))
- samples(project(":lifecycle:lifecycle-viewmodel-compose:lifecycle-viewmodel-compose-samples"))
docs(project(":lifecycle:lifecycle-viewmodel-ktx"))
docs(project(":lifecycle:lifecycle-viewmodel-savedstate"))
docs(project(":loader:loader"))
@@ -278,7 +241,6 @@
docs(project(":navigation:navigation-common"))
docs(project(":navigation:navigation-common-ktx"))
docs(project(":navigation:navigation-compose"))
- samples(project(":navigation:navigation-compose:navigation-compose-samples"))
docs(project(":navigation:navigation-dynamic-features-fragment"))
docs(project(":navigation:navigation-dynamic-features-runtime"))
docs(project(":navigation:navigation-fragment"))
@@ -292,14 +254,12 @@
kmpDocs(project(":paging:paging-common"))
docs(project(":paging:paging-common-ktx"))
kmpDocs(project(":paging:paging-compose"))
- samples(project(":paging:paging-compose:paging-compose-samples"))
docs(project(":paging:paging-guava"))
docs(project(":paging:paging-runtime"))
docs(project(":paging:paging-runtime-ktx"))
docs(project(":paging:paging-rxjava2"))
docs(project(":paging:paging-rxjava2-ktx"))
docs(project(":paging:paging-rxjava3"))
- samples(project(":paging:paging-samples"))
kmpDocs(project(":paging:paging-testing"))
docs(project(":palette:palette"))
docs(project(":palette:palette-ktx"))
@@ -374,7 +334,6 @@
docs(project(":transition:transition-ktx"))
docs(project(":tv:tv-foundation"))
docs(project(":tv:tv-material"))
- samples(project(":tv:tv-samples"))
docs(project(":tvprovider:tvprovider"))
docs(project(":vectordrawable:vectordrawable"))
docs(project(":vectordrawable:vectordrawable-animated"))
@@ -383,14 +342,10 @@
docs(project(":viewpager2:viewpager2"))
docs(project(":viewpager:viewpager"))
docs(project(":wear:compose:compose-foundation"))
- samples(project(":wear:compose:compose-foundation-samples"))
docs(project(":wear:compose:compose-material"))
docs(project(":wear:compose:compose-material-core"))
- samples(project(":wear:compose:compose-material-samples"))
docs(project(":wear:compose:compose-material3"))
- samples(project(":wear:compose:compose-material3-samples"))
docs(project(":wear:compose:compose-navigation"))
- samples(project(":wear:compose:compose-navigation-samples"))
docs(project(":wear:compose:compose-ui-tooling"))
docs(project(":wear:protolayout:protolayout"))
docs(project(":wear:protolayout:protolayout-expression"))
@@ -411,26 +366,20 @@
docs(project(":wear:watchface:watchface-complications-data"))
docs(project(":wear:watchface:watchface-complications-data-source"))
docs(project(":wear:watchface:watchface-complications-data-source-ktx"))
- samples(project(":wear:watchface:watchface-complications-permission-dialogs-sample"))
docs(project(":wear:watchface:watchface-complications-rendering"))
docs(project(":wear:watchface:watchface-data"))
docs(project(":wear:watchface:watchface-editor"))
docs(project(":wear:watchface:watchface-editor-guava"))
- samples(project(":wear:watchface:watchface-editor-samples"))
docs(project(":wear:watchface:watchface-guava"))
- samples(project(":wear:watchface:watchface-samples"))
docs(project(":wear:watchface:watchface-style"))
docs(project(":wear:wear"))
docs(project(":wear:wear-core"))
stubs(fileTree(dir: "../wear/wear_stubs/", include: ["com.google.android.wearable-stubs.jar"]))
docs(project(":wear:wear-input"))
- samples(project(":wear:wear-input-samples"))
docs(project(":wear:wear-input-testing"))
docs(project(":wear:wear-ongoing"))
docs(project(":wear:wear-phone-interactions"))
- samples(project(":wear:wear-phone-interactions-samples"))
docs(project(":wear:wear-remote-interactions"))
- samples(project(":wear:wear-remote-interactions-samples"))
docs(project(":wear:wear-tooling-preview"))
docs(project(":webkit:webkit"))
docs(project(":window:window"))
@@ -441,7 +390,6 @@
docs(project(":window:window-java"))
docs(project(":window:window-rxjava2"))
docs(project(":window:window-rxjava3"))
- samples(project(":window:window-samples"))
docs(project(":window:window-testing"))
docs(project(":work:work-gcm"))
docs(project(":work:work-multiprocess"))
diff --git a/docs/macrobenchmarking.md b/docs/macrobenchmarking.md
index 612cd7e..7084c39 100644
--- a/docs/macrobenchmarking.md
+++ b/docs/macrobenchmarking.md
@@ -1,4 +1,4 @@
-# Benchmarking in AndroidX
+# MACRObenchmarking in AndroidX
[TOC]
@@ -10,7 +10,7 @@
<td><strong>Benchmark</strong></td>
</tr>
<tr>
- <td>Measure high-level entry points(Activity launch / Scrolling a list)</td>
+ <td>Measure high-level entry points (Activity launch / Scrolling a list)</td>
<td>Measure individual functions</td>
</tr>
<tr>
@@ -22,12 +22,12 @@
<td>Fast iteration speed (Often less than 10 seconds)</td>
</tr>
<tr>
- <td>Configure compilation with CompilationMode</td>
+ <td>Configure compilation with <a href="https://developer.android.com/reference/androidx/benchmark/macro/CompilationMode">CompilationMode</a></td>
<td>Always fully AOT (<code>speed</code>) compiled.</td>
</tr>
<tr>
<td>Min API 23</td>
- <td>Min API 14</td>
+ <td>Min API 19</td>
</tr>
<tr>
<td>Relatively lower stability measurements</td>
@@ -122,7 +122,7 @@
* [`:compose:integration-tests:macrobenchmark`](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/integration-tests/macrobenchmark/)
-Note: Compose macrobenchmarks are generally duplicated with View system
+Note: Compose macrobenchmarks are ideally duplicated with View system
counterparts, defined in `:benchmark:integration-tests:macrobenchmark-target`.
This is how we compare performance of the two systems.
diff --git a/enterprise/OWNERS b/enterprise/OWNERS
index 8f42a2b..a1bb741 100644
--- a/enterprise/OWNERS
+++ b/enterprise/OWNERS
@@ -1,3 +1,3 @@
# Bug component: 606793
-alexkershaw@google.com
-scottjonathan@google.com
+sandness@google.com
+sinduran@google.com
diff --git a/glance/glance-appwidget/integration-tests/demos/src/main/AndroidManifest.xml b/glance/glance-appwidget/integration-tests/demos/src/main/AndroidManifest.xml
index 9b09378..56c5b6d 100644
--- a/glance/glance-appwidget/integration-tests/demos/src/main/AndroidManifest.xml
+++ b/glance/glance-appwidget/integration-tests/demos/src/main/AndroidManifest.xml
@@ -17,10 +17,10 @@
xmlns:tools="http://schemas.android.com/tools">
<application
+ android:name=".DemoApplication"
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/demos_label"
- android:name=".DemoApplication"
android:supportsRtl="true">
<activity
@@ -38,7 +38,7 @@
android:name=".SimpleWidgetViewer"
android:exported="true"
android:label="@string/demo_widget_viewer"
- android:theme="@android:style/Theme.Material.Light.NoActionBar" >
+ android:theme="@android:style/Theme.Material.Light.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
@@ -46,19 +46,24 @@
</activity>
<activity android:name=".ActionDemoActivity" />
- <service
- android:name=".ActionDemoService"
- tools:ignore="MissingServiceExportedEqualsTrue" />
- <activity android:name=".ListClickDestinationActivity" android:exported="false" />
- <activity android:name=".ErrorUiAppWidgetConfigurationActivity"
- android:exported="false"
- >
+ <activity
+ android:name=".ListClickDestinationActivity"
+ android:exported="false" />
+
+ <activity
+ android:name=".ErrorUiAppWidgetConfigurationActivity"
+ android:exported="false">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
+ <provider
+ android:name="androidx.glance.appwidget.demos.ImageAppWidgetImageContentProvider"
+ android:authorities="androidx.glance.appwidget.demos"
+ android:enabled="true"
+ android:exported="true" />
<receiver
android:name="androidx.glance.appwidget.demos.ResponsiveAppWidgetReceiver"
@@ -131,9 +136,9 @@
<receiver
android:name="androidx.glance.appwidget.demos.ErrorUiAppWidgetReceiver"
- android:label="@string/error_widget_name"
android:enabled="@bool/glance_appwidget_available"
- android:exported="false">
+ android:exported="false"
+ android:label="@string/error_widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.intent.action.LOCALE_CHANGED" />
@@ -145,9 +150,9 @@
<receiver
android:name="androidx.glance.appwidget.demos.FontDemoAppWidgetReceiver"
- android:label="@string/font_widget_name"
android:enabled="@bool/glance_appwidget_available"
- android:exported="false">
+ android:exported="false"
+ android:label="@string/font_widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.intent.action.LOCALE_CHANGED" />
@@ -159,9 +164,9 @@
<receiver
android:name="androidx.glance.appwidget.demos.TypographyDemoAppWidgetReceiver"
- android:label="@string/typography_widget_name"
android:enabled="@bool/glance_appwidget_available"
- android:exported="false">
+ android:exported="false"
+ android:label="@string/typography_widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
@@ -172,9 +177,9 @@
<receiver
android:name="androidx.glance.appwidget.demos.ScrollableAppWidgetReceiver"
- android:label="@string/scrollable_widget_name"
android:enabled="@bool/glance_appwidget_available"
- android:exported="false">
+ android:exported="false"
+ android:label="@string/scrollable_widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
@@ -185,9 +190,9 @@
<receiver
android:name="androidx.glance.appwidget.demos.ImageAppWidgetReceiver"
- android:label="@string/image_widget_name"
android:enabled="@bool/glance_appwidget_available"
- android:exported="false">
+ android:exported="false"
+ android:label="@string/image_widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
@@ -198,9 +203,9 @@
<receiver
android:name="androidx.glance.appwidget.demos.RippleAppWidgetReceiver"
- android:label="@string/ripple_widget_name"
android:enabled="@bool/glance_appwidget_available"
- android:exported="false">
+ android:exported="false"
+ android:label="@string/ripple_widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
@@ -211,9 +216,9 @@
<receiver
android:name="androidx.glance.appwidget.demos.RemoteViewsWidgetReceiver"
- android:label="@string/remote_views_widget_name"
android:enabled="@bool/glance_appwidget_available"
- android:exported="false">
+ android:exported="false"
+ android:label="@string/remote_views_widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
@@ -224,9 +229,9 @@
<receiver
android:name="androidx.glance.appwidget.demos.VerticalGridAppWidgetReceiver"
- android:label="@string/grid_widget_name"
android:enabled="@bool/glance_appwidget_available"
- android:exported="false">
+ android:exported="false"
+ android:label="@string/grid_widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
@@ -237,9 +242,9 @@
<receiver
android:name="androidx.glance.appwidget.demos.DefaultStateAppWidgetReceiver"
- android:label="@string/default_state_widget_name"
android:enabled="@bool/glance_appwidget_available"
- android:exported="false">
+ android:exported="false"
+ android:label="@string/default_state_widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
@@ -250,9 +255,9 @@
<receiver
android:name="androidx.glance.appwidget.demos.ProgressIndicatorAppWidgetReceiver"
- android:label="@string/progress_indicator_widget_name"
android:enabled="@bool/glance_appwidget_available"
- android:exported="false">
+ android:exported="false"
+ android:label="@string/progress_indicator_widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
@@ -263,9 +268,9 @@
<receiver
android:name="androidx.glance.appwidget.demos.DefaultColorsAppWidgetReceiver"
- android:label="@string/default_color_widget_name"
android:enabled="@bool/glance_appwidget_available"
- android:exported="false">
+ android:exported="false"
+ android:label="@string/default_color_widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
@@ -290,9 +295,9 @@
<receiver
android:name="androidx.glance.appwidget.demos.BackgroundTintWidgetBroadcastReceiver"
- android:label="@string/tint_widget"
android:enabled="@bool/glance_appwidget_available"
- android:exported="false">
+ android:exported="false"
+ android:label="@string/tint_widget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
@@ -303,9 +308,9 @@
<receiver
android:name="androidx.glance.appwidget.demos.TitleBarWidgetBroadcastReceiver"
- android:label="@string/title_bar_widget"
android:enabled="@bool/glance_appwidget_available"
- android:exported="false">
+ android:exported="false"
+ android:label="@string/title_bar_widget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
@@ -316,9 +321,9 @@
<receiver
android:name="androidx.glance.appwidget.demos.ContentDescriptionAppWidgetReceiver"
- android:label="@string/content_description_widget_name"
android:enabled="@bool/glance_appwidget_available"
- android:exported="false">
+ android:exported="false"
+ android:label="@string/content_description_widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
@@ -326,5 +331,9 @@
android:name="android.appwidget.provider"
android:resource="@xml/default_app_widget_info" />
</receiver>
+
+ <service
+ android:name=".ActionDemoService"
+ android:exported="true" />
</application>
</manifest>
diff --git a/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/ImageAppWidget.kt b/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/ImageAppWidget.kt
index bc136c1..a794006 100644
--- a/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/ImageAppWidget.kt
+++ b/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/ImageAppWidget.kt
@@ -16,13 +16,24 @@
package androidx.glance.appwidget.demos
+import android.content.ContentProvider
+import android.content.ContentValues
import android.content.Context
+import android.database.Cursor
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.graphics.drawable.Icon
+import android.net.Uri
+import android.os.Build
+import android.os.ParcelFileDescriptor
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.graphics.Color
+import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.unit.dp
import androidx.glance.Button
import androidx.glance.ColorFilter
@@ -34,11 +45,17 @@
import androidx.glance.action.clickable
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.GlanceAppWidgetReceiver
+import androidx.glance.appwidget.ImageProvider
import androidx.glance.appwidget.SizeMode
+import androidx.glance.appwidget.components.Scaffold
+import androidx.glance.appwidget.demos.ShareableImageUtils.getShareableImageUri
+import androidx.glance.appwidget.demos.ShareableImageUtils.uriImageFile
+import androidx.glance.appwidget.lazy.LazyColumn
import androidx.glance.appwidget.provideContent
import androidx.glance.background
import androidx.glance.color.ColorProvider
import androidx.glance.layout.Alignment
+import androidx.glance.layout.Box
import androidx.glance.layout.Column
import androidx.glance.layout.ContentScale
import androidx.glance.layout.Row
@@ -48,6 +65,11 @@
import androidx.glance.layout.padding
import androidx.glance.layout.size
import androidx.glance.text.Text
+import java.io.File
+
+class ImageAppWidgetReceiver : GlanceAppWidgetReceiver() {
+ override val glanceAppWidget: GlanceAppWidget = ImageAppWidget()
+}
/**
* Sample AppWidget that showcase the [ContentScale] options for [Image]
@@ -58,73 +80,324 @@
override suspend fun provideGlance(
context: Context,
id: GlanceId
- ) = provideContent {
- var type by remember { mutableStateOf(ContentScale.Fit) }
- Column(modifier = GlanceModifier.fillMaxSize().padding(8.dp)) {
- Header()
- Spacer(GlanceModifier.size(4.dp))
- Button(
- text = "Content Scale: ${type.asString()}",
- modifier = GlanceModifier.fillMaxWidth(),
- onClick = {
- type = when (type) {
- ContentScale.Crop -> ContentScale.FillBounds
- ContentScale.FillBounds -> ContentScale.Fit
- else -> ContentScale.Crop
- }
- }
- )
- Spacer(GlanceModifier.size(4.dp))
- Image(
- provider = ImageProvider(R.drawable.compose),
- contentDescription = "Content Scale image sample (value: ${type.asString()})",
- contentScale = type,
- modifier = GlanceModifier.fillMaxSize().background(Color.DarkGray)
+ ) {
+ val imageUri: Uri = getShareableImageUri(context)
+
+ provideContent {
+ Scaffold(
+ titleBar = { Header() },
+ content = { BodyContent(imageUri = imageUri) }
)
}
}
-
- @Composable
- private fun Header() {
- val context = LocalContext.current
- var shouldTintHeaderIcon by remember { mutableStateOf(true) }
-
- Row(
- horizontalAlignment = Alignment.CenterHorizontally,
- verticalAlignment = Alignment.CenterVertically,
- modifier = GlanceModifier.fillMaxWidth().background(Color.White)
- ) {
- // Demonstrates toggling application of color filter on an image
- Image(
- provider = ImageProvider(R.drawable.ic_android),
- contentDescription = null,
- colorFilter = if (shouldTintHeaderIcon) {
- ColorFilter.tint(
- ColorProvider(day = Color.Green, night = Color.Blue)
- )
- } else {
- null
- },
- modifier = GlanceModifier.clickable {
- shouldTintHeaderIcon = !shouldTintHeaderIcon
- }
- )
- Text(
- text = context.getString(R.string.image_widget_name),
- modifier = GlanceModifier.padding(8.dp),
- )
- }
- }
-
- private fun ContentScale.asString(): String =
- when (this) {
- ContentScale.Fit -> "Fit"
- ContentScale.FillBounds -> "Fill Bounds"
- ContentScale.Crop -> "Crop"
- else -> "Unknown content scale"
- }
}
-class ImageAppWidgetReceiver : GlanceAppWidgetReceiver() {
- override val glanceAppWidget: GlanceAppWidget = ImageAppWidget()
+@Composable
+private fun Header() {
+ val context = LocalContext.current
+ var shouldTintHeaderIcon by remember { mutableStateOf(true) }
+
+ Row(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = GlanceModifier.fillMaxWidth().background(Color.White)
+ ) {
+ // Demonstrates toggling application of color filter on an image
+ Image(
+ provider = ImageProvider(R.drawable.ic_android),
+ contentDescription = null,
+ colorFilter = if (shouldTintHeaderIcon) {
+ ColorFilter.tint(
+ ColorProvider(day = Color.Green, night = Color.Blue)
+ )
+ } else {
+ null
+ },
+ modifier = GlanceModifier.clickable {
+ shouldTintHeaderIcon = !shouldTintHeaderIcon
+ }
+ )
+ Text(
+ text = context.getString(R.string.image_widget_name),
+ modifier = GlanceModifier.padding(8.dp),
+ )
+ }
+}
+
+@Composable
+private fun BodyContent(imageUri: Uri) {
+ var type by remember { mutableStateOf(ContentScale.Fit) }
+ Column(modifier = GlanceModifier.fillMaxSize().padding(8.dp)) {
+ Spacer(GlanceModifier.size(4.dp))
+ Button(
+ text = "Content Scale: ${type.asString()}",
+ modifier = GlanceModifier.fillMaxWidth(),
+ onClick = {
+ type = when (type) {
+ ContentScale.Crop -> ContentScale.FillBounds
+ ContentScale.FillBounds -> ContentScale.Fit
+ else -> ContentScale.Crop
+ }
+ }
+ )
+ Spacer(GlanceModifier.size(4.dp))
+
+ val itemModifier = GlanceModifier.fillMaxWidth().padding(vertical = 4.dp)
+
+ LazyColumn(GlanceModifier.fillMaxSize()) {
+ val textModifier = GlanceModifier.padding(bottom = 8.dp)
+ item {
+ Column {
+ // An image who's provider uses a resource.
+ ResourceImage(contentScale = type, modifier = itemModifier)
+ Text("ImageProvider(resourceId)", textModifier)
+ }
+ }
+ item {
+ Column {
+ // An image who's provider uses a content uri. This uri will be passed through
+ // the remote views to the AppWidget's host. The host will query our app via
+ // content provider to resolve the Uri into a bitmap.
+ UriImage(uri = imageUri, contentScale = type, modifier = itemModifier)
+ Text("ImageProvider(uri)", textModifier)
+ }
+ }
+
+ item {
+ Column {
+ // An image who's provider holds an in-memory bitmap.
+ BitmapImage(contentScale = type, modifier = itemModifier)
+ Text("ImageProvider(bitmap)", textModifier)
+ }
+ }
+
+ item {
+ Column {
+ // An image who's provider uses the Icon api.
+ IconImage(contentScale = type, modifier = itemModifier)
+ Text("ImageProvider(icon)", textModifier)
+ }
+ }
+ }
+ }
+}
+
+@Composable
+private fun ResourceImage(contentScale: ContentScale, modifier: GlanceModifier = GlanceModifier) {
+ Image(
+ provider = ImageProvider(R.drawable.compose),
+ contentDescription = "Content Scale image sample (value: ${contentScale.asString()})",
+ contentScale = contentScale,
+ modifier = modifier
+ )
+}
+
+/**
+ * Demonstrates using the Uri image provider in `androidx.glance.appwidget`. This image will be
+ * sent to the RemoteViews as a uri. In the AppWidgetHost, the uri will be resolved by querying
+ * back to this app's [ContentProvider], see [ImageAppWidgetImageContentProvider]. There are several
+ * drawbacks to this approach. Consider them before going this route.
+ * - Images that are within the app's private directories can only be exposed via ContentProvider;
+ * a direct reference via file:// uri will not work.
+ * - The ContentProvider approach will not work across user/work profiles.
+ * - Any time the image is loaded, the AppWidget's process will be started, consuming battery
+ * and memory.
+ * - FileProvider cannot be used due to a permissions issue.
+ */
+@Composable
+private fun UriImage(
+ contentScale: ContentScale,
+ modifier: GlanceModifier = GlanceModifier,
+ uri: Uri
+) {
+ Image(
+ provider = ImageProvider(uri),
+ contentDescription = "Content Scale image sample (value: ${contentScale.asString()})",
+ contentScale = contentScale,
+ modifier = modifier
+ )
+}
+
+/**
+ * Bitmaps are passed in memory from the appwidget provider's process to the appwidget host's
+ * process. Be careful to not use too many or too large bitmaps. See [android.widget.RemoteViews]
+ * for more info.
+ */
+@Composable
+private fun BitmapImage(contentScale: ContentScale, modifier: GlanceModifier = GlanceModifier) {
+ fun makeBitmap(): Bitmap {
+ val w = 100f
+ val h = 100f
+ val bmp = Bitmap.createBitmap(w.toInt(), h.toInt(), Bitmap.Config.ARGB_8888)
+ val canvas = Canvas(bmp)
+ val paint = Paint()
+
+ paint.setColor(Color.Black.toArgb()) // transparent
+ canvas.drawRect(0f, 0f, w, h, paint)
+ paint.setColor(Color.White.toArgb()) // Opaque
+ canvas.drawCircle(w / 2f, h / 2f, w / 3f, paint)
+
+ return bmp
+ }
+
+ Image(
+ provider = ImageProvider(makeBitmap()),
+ contentDescription = "An image with an in-memory bitmap provider",
+ contentScale = contentScale,
+ modifier = modifier
+ )
+}
+
+/**
+ * For displaying [Image]s backed by [android.graphics.drawable.Icon]s. Despite the name, an
+ * [Icon] does not need to represent a literal icon.
+ */
+@Composable
+private fun IconImage(contentScale: ContentScale, modifier: GlanceModifier) {
+ if (Build.VERSION.SDK_INT < 23) {
+ Text("The Icon api requires api >= 23")
+ return
+ }
+
+ val bitmap = canvasBitmap(200, circleColor = Color.Red)
+
+ Box {
+ Image(
+ provider = ImageProvider(bitmap),
+ contentDescription = "An image with an in-memory bitmap provider",
+ contentScale = contentScale,
+ modifier = modifier
+ )
+ }
+}
+
+private fun canvasBitmap(outputCanvasSize: Int, circleColor: Color): Bitmap {
+ val bitmap = Bitmap.createBitmap(
+ outputCanvasSize,
+ outputCanvasSize,
+ Bitmap.Config.ARGB_8888
+ )
+ val padding = outputCanvasSize * .05f
+ val canvas = Canvas(bitmap)
+
+ fun drawBlueSquare(canvas: Canvas) {
+ val squareSize = outputCanvasSize * (2f / 3f)
+
+ val x0 = padding
+ val x1 = x0 + squareSize
+ val y0 = (outputCanvasSize - squareSize - padding)
+ val y1 = y0 + squareSize
+ val paint = Paint().apply { setColor(Color.Blue.toArgb()) }
+ canvas.drawRect(x0, y0, x1, y1, paint)
+ }
+
+ fun drawCircle(canvas: Canvas) {
+ val r = outputCanvasSize * (1f / 3f)
+ val cx = outputCanvasSize - r - padding
+ val cy = r + padding
+
+ val paint = Paint().apply { setColor(circleColor.toArgb()) }
+ canvas.drawCircle(cx, cy, r, paint)
+ }
+
+ drawBlueSquare(canvas)
+ drawCircle(canvas)
+
+ return bitmap
+}
+
+private fun ContentScale.asString(): String =
+ when (this) {
+ ContentScale.Fit -> "Fit"
+ ContentScale.FillBounds -> "Fill Bounds"
+ ContentScale.Crop -> "Crop"
+ else -> "Unknown content scale"
+ }
+
+private object ShareableImageUtils {
+ private val fileProviderDirectory = "imageAppWidget"
+ private val fileName = "imageToBeLoadedFromUri.png"
+
+ private fun uri(context: Context, filename: String): Uri {
+ val packageName = context.packageName
+ return Uri.parse("content://$packageName/$filename")
+ }
+
+ val Context.uriImageFile: File
+ get() = File(
+ this.filesDir, "$fileProviderDirectory/$fileName"
+ )
+
+ /**
+ * Create a Uri to share and ensure the file we want to return exists.
+ */
+ fun getShareableImageUri(context: Context): Uri {
+
+ val file: File = context.uriImageFile
+ file.parentFile?.mkdir()
+ val success = if (file.exists()) {
+ true
+ } else {
+ val bitmap = canvasBitmap(300, circleColor = Color.Green)
+ file.outputStream().use { out ->
+ bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)
+ }
+ }
+
+ if (success) {
+ return uri(context, file.name)
+ } else {
+ throw IllegalStateException("Failed to write bitmap")
+ }
+ }
+}
+
+/**
+ * Expose an image file via content:// uri.
+ */
+class ImageAppWidgetImageContentProvider : ContentProvider() {
+ override fun onCreate(): Boolean {
+ return true
+ }
+
+ /**
+ * A simplified version of [openFile] for example only. This version does not validate the
+ * uri and always returns the same file.
+ */
+ override fun openFile(uri: Uri, mode: String): ParcelFileDescriptor? {
+ val context = context ?: return null
+ val file = context.uriImageFile
+ return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY)
+ }
+
+ override fun query(
+ uri: Uri,
+ projection: Array<out String>?,
+ selection: String?,
+ selectionArgs: Array<out String>?,
+ sortOrder: String?
+ ): Cursor? {
+ return null // unused
+ }
+
+ override fun getType(uri: Uri): String? {
+ return "image/png"
+ }
+
+ override fun insert(uri: Uri, values: ContentValues?): Uri? {
+ return null // unused
+ }
+
+ override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
+ return 0 // unused
+ }
+
+ override fun update(
+ uri: Uri,
+ values: ContentValues?,
+ selection: String?,
+ selectionArgs: Array<out String>?
+ ): Int {
+ return 0 // unused
+ }
}
diff --git a/glance/glance-appwidget/src/androidTest/kotlin/androidx/glance/appwidget/GlanceAppWidgetReceiverScreenshotTest.kt b/glance/glance-appwidget/src/androidTest/kotlin/androidx/glance/appwidget/GlanceAppWidgetReceiverScreenshotTest.kt
index eb7c74f9..c14bf11 100644
--- a/glance/glance-appwidget/src/androidTest/kotlin/androidx/glance/appwidget/GlanceAppWidgetReceiverScreenshotTest.kt
+++ b/glance/glance-appwidget/src/androidTest/kotlin/androidx/glance/appwidget/GlanceAppWidgetReceiverScreenshotTest.kt
@@ -24,6 +24,7 @@
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.glance.Button
+import androidx.glance.ButtonColors
import androidx.glance.ButtonDefaults
import androidx.glance.GlanceModifier
import androidx.glance.GlanceTheme
@@ -643,6 +644,76 @@
mScreenshotRule.checkScreenshot(mHostRule.mHostView, "buttonTests_buttonDefaultColors")
}
+ /**
+ * Button should ignore [androidx.glance.BackgroundModifier]. It does not support background
+ * images, and background color should be set via [androidx.glance.ButtonColors].
+ */
+ @Test
+ fun buttonTests_buttonShouldIgnoreBackgroundModifiers() {
+ @Composable
+ fun Ui() {
+ Column {
+ // the bg image modifier should be stripped.
+ Button(
+ text = "Button w/incorrect bg modifier: image",
+ onClick = { },
+ modifier =
+ GlanceModifier.background(
+ imageProvider = ImageProvider(R.drawable.compose),
+ ),
+ )
+ Spacer(GlanceModifier.size(4.dp))
+
+ // Bg modifiers should be stripped
+ Button(
+ text = "Button w/incorrect modifiers: Image, Color",
+ onClick = { },
+ modifier =
+ GlanceModifier.background(
+ Color.Cyan
+ ).background(
+ imageProvider = ImageProvider(R.drawable.compose),
+ ),
+ )
+ Spacer(GlanceModifier.size(4.dp))
+
+ // Bg color modifier should be stripped.
+ Button(
+ text = "Button w/incorrect bg modifier: color",
+ onClick = { },
+ modifier =
+ GlanceModifier.background(
+ Color.Cyan
+ ),
+ )
+ Spacer(GlanceModifier.size(4.dp))
+
+ Button(
+ text = "Button with no modifier",
+ onClick = { },
+ )
+ Spacer(GlanceModifier.size(4.dp))
+ Button(
+ text = "Button with proper color",
+ colors = ButtonDefaults.buttonColors(
+ backgroundColor = ColorProvider(Color.Cyan),
+ contentColor = ColorProvider(Color.Magenta)
+ ),
+ onClick = { },
+ )
+ }
+ }
+
+ TestGlanceAppWidget.uiDefinition = {
+ Ui()
+ }
+ mHostRule.startHost()
+ mScreenshotRule.checkScreenshot(
+ mHostRule.mHostView,
+ "buttonTests_buttonIgnoresBgImageModifier"
+ )
+ }
+
@Test
fun topbarTests_createBarWithIconTextTwoActions() {
TestGlanceAppWidget.uiDefinition = {
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/NormalizeCompositionTree.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/NormalizeCompositionTree.kt
index 7a1f57e..9d22cd6 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/NormalizeCompositionTree.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/NormalizeCompositionTree.kt
@@ -198,6 +198,34 @@
var target = this
val isButton = target is EmittableButton
+ // Button ignores background modifiers.
+ if (isButton && Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
+ // Buttons cannot have a background image modifier. Remove BackgroundModifier.Image from
+ // the button if it exists.
+ val (maybeBgImageModifier, modifiersMinusBgImage) =
+ target.modifier.extractModifier<BackgroundModifier.Image>()
+ if (maybeBgImageModifier != null) {
+ Log.w(
+ GlanceAppWidgetTag,
+ "Glance Buttons should not have a background image modifier. " +
+ "Consider an image with a clickable modifier."
+ )
+ target.modifier = modifiersMinusBgImage
+ }
+
+ // Buttons ignore background color modifier. Remove it.
+ val (maybeBgColorModifier, modifiersMinusBgColor) =
+ target.modifier.extractModifier<BackgroundModifier.Image>()
+ if (maybeBgColorModifier != null) {
+ Log.w(
+ GlanceAppWidgetTag,
+ "Glance Buttons should not have a background color modifier. " +
+ "Consider a tinted image with a clickable modifier"
+ )
+ target.modifier = modifiersMinusBgColor
+ }
+ }
+
val shouldWrapTargetInABox = target.modifier.any {
// Background images (i.e. BitMap or drawable resources) are emulated by placing the image
// before the target in the wrapper box. This allows us to support content scale as well as
@@ -219,6 +247,7 @@
var rippleImage: EmittableImage? = null
val (bgModifier, targetModifiersMinusBg) = target.modifier.extractModifier<BackgroundModifier>()
+
if (bgModifier != null) {
if (isButton) {
// Emulate rounded corners (fixed radius) using a drawable and apply background colors
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/translators/ImageTranslator.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/translators/ImageTranslator.kt
index 2055f35..9ce6d8b 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/translators/ImageTranslator.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/translators/ImageTranslator.kt
@@ -142,8 +142,11 @@
rv.setImageViewColorFilter(viewDef.mainViewId, color)
rv.setImageViewImageAlpha(viewDef.mainViewId, android.graphics.Color.alpha(color))
} else {
- throw IllegalStateException(
- "There is no use case yet to support this colorFilter in S+ versions."
+ val trace = Throwable()
+ Log.e(
+ GlanceAppWidgetTag,
+ "There is no use case yet to support this colorFilter in S+ versions.",
+ trace
)
}
}
diff --git a/gradle.properties b/gradle.properties
index 241307e..7a42aa7 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -42,7 +42,7 @@
# Don't warn about needing to update AGP
android.suppressUnsupportedCompileSdk=UpsideDownCake,VanillaIceCream,33,34
-androidx.compileSdkVersion=android-34
+androidx.compileSdk=34
androidx.targetSdkVersion=34
androidx.allowCustomCompileSdk=true
androidx.includeOptionalProjects=false
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 7745cc6..425cf58 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -24,7 +24,7 @@
atomicFu = "0.17.0"
autoService = "1.0-rc6"
autoValue = "1.6.3"
-binaryCompatibilityValidator = "0.14.0"
+binaryCompatibilityValidator = "0.15.0-Beta.2"
byteBuddy = "1.14.9"
asm = "9.3"
cmake = "3.22.1"
diff --git a/health/connect/connect-client/build.gradle b/health/connect/connect-client/build.gradle
index 1dd21ba..9717548 100644
--- a/health/connect/connect-client/build.gradle
+++ b/health/connect/connect-client/build.gradle
@@ -86,7 +86,8 @@
}
testOptions.unitTests.includeAndroidResources = true
namespace "androidx.health.connect.client"
- compileSdkVersion = "android-34-ext10"
+ compileSdk = 34
+ compileSdkExtension = 10
}
androidx {
diff --git a/lifecycle/integration-tests/incrementality/src/test/kotlin/androidx/lifecycle/IncrementalAnnotationProcessingTest.kt b/lifecycle/integration-tests/incrementality/src/test/kotlin/androidx/lifecycle/IncrementalAnnotationProcessingTest.kt
index eafa782..0e028ea 100644
--- a/lifecycle/integration-tests/incrementality/src/test/kotlin/androidx/lifecycle/IncrementalAnnotationProcessingTest.kt
+++ b/lifecycle/integration-tests/incrementality/src/test/kotlin/androidx/lifecycle/IncrementalAnnotationProcessingTest.kt
@@ -237,7 +237,7 @@
android {
namespace "androidx.lifecycle.incap"
- compileSdkVersion ${projectSetup.props.compileSdkVersion}
+ compileSdk ${projectSetup.props.compileSdk}
buildToolsVersion "${projectSetup.props.buildToolsVersion}"
defaultConfig {
diff --git a/lifecycle/lifecycle-common/src/jvmMain/baseline-prof.txt b/lifecycle/lifecycle-common/src/jvmMain/baseline-prof.txt
deleted file mode 100644
index 041b060..0000000
--- a/lifecycle/lifecycle-common/src/jvmMain/baseline-prof.txt
+++ /dev/null
@@ -1,44 +0,0 @@
-# Baseline Profiles for lifecycle-common
-
-HPLandroidx/lifecycle/Lifecycle$Event;->downFrom(Landroidx/lifecycle/Lifecycle$State;)Landroidx/lifecycle/Lifecycle$Event;
-HSPLandroidx/lifecycle/ClassesInfoCache$CallbackInfo;-><init>(Ljava/util/Map;)V
-HSPLandroidx/lifecycle/ClassesInfoCache$CallbackInfo;->invokeCallbacks(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;Ljava/lang/Object;)V
-HSPLandroidx/lifecycle/ClassesInfoCache$CallbackInfo;->invokeMethodsForEvent(Ljava/util/List;Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;Ljava/lang/Object;)V
-HSPLandroidx/lifecycle/ClassesInfoCache$MethodReference;-><init>(ILjava/lang/reflect/Method;)V
-HSPLandroidx/lifecycle/ClassesInfoCache$MethodReference;->hashCode()I
-HSPLandroidx/lifecycle/ClassesInfoCache$MethodReference;->invokeCallback(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;Ljava/lang/Object;)V
-HSPLandroidx/lifecycle/ClassesInfoCache;-><clinit>()V
-HSPLandroidx/lifecycle/ClassesInfoCache;-><init>()V
-HSPLandroidx/lifecycle/ClassesInfoCache;->createInfo(Ljava/lang/Class;[Ljava/lang/reflect/Method;)Landroidx/lifecycle/ClassesInfoCache$CallbackInfo;
-HSPLandroidx/lifecycle/ClassesInfoCache;->getDeclaredMethods(Ljava/lang/Class;)[Ljava/lang/reflect/Method;
-HSPLandroidx/lifecycle/ClassesInfoCache;->getInfo(Ljava/lang/Class;)Landroidx/lifecycle/ClassesInfoCache$CallbackInfo;
-HSPLandroidx/lifecycle/ClassesInfoCache;->hasLifecycleMethods(Ljava/lang/Class;)Z
-HSPLandroidx/lifecycle/ClassesInfoCache;->verifyAndPutHandler(Ljava/util/Map;Landroidx/lifecycle/ClassesInfoCache$MethodReference;Landroidx/lifecycle/Lifecycle$Event;Ljava/lang/Class;)V
-HSPLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onCreate(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V
-HSPLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onResume(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V
-HSPLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onStart(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V
-HSPLandroidx/lifecycle/FullLifecycleObserverAdapter$1;-><clinit>()V
-HSPLandroidx/lifecycle/FullLifecycleObserverAdapter;-><init>(Landroidx/lifecycle/FullLifecycleObserver;Landroidx/lifecycle/LifecycleEventObserver;)V
-HSPLandroidx/lifecycle/FullLifecycleObserverAdapter;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
-HSPLandroidx/lifecycle/Lifecycle$1;-><clinit>()V
-HSPLandroidx/lifecycle/Lifecycle$Event;-><clinit>()V
-HSPLandroidx/lifecycle/Lifecycle$Event;-><init>(Ljava/lang/String;I)V
-HSPLandroidx/lifecycle/Lifecycle$Event;->getTargetState()Landroidx/lifecycle/Lifecycle$State;
-HSPLandroidx/lifecycle/Lifecycle$Event;->upFrom(Landroidx/lifecycle/Lifecycle$State;)Landroidx/lifecycle/Lifecycle$Event;
-HSPLandroidx/lifecycle/Lifecycle$Event;->values()[Landroidx/lifecycle/Lifecycle$Event;
-HSPLandroidx/lifecycle/Lifecycle$State;-><clinit>()V
-HSPLandroidx/lifecycle/Lifecycle$State;-><init>(Ljava/lang/String;I)V
-HSPLandroidx/lifecycle/Lifecycle$State;->isAtLeast(Landroidx/lifecycle/Lifecycle$State;)Z
-HSPLandroidx/lifecycle/Lifecycle$State;->values()[Landroidx/lifecycle/Lifecycle$State;
-HSPLandroidx/lifecycle/Lifecycle;-><init>()V
-HSPLandroidx/lifecycle/Lifecycling;-><clinit>()V
-HSPLandroidx/lifecycle/Lifecycling;->generatedConstructor(Ljava/lang/Class;)Ljava/lang/reflect/Constructor;
-HSPLandroidx/lifecycle/Lifecycling;->getAdapterName(Ljava/lang/String;)Ljava/lang/String;
-HSPLandroidx/lifecycle/Lifecycling;->getObserverConstructorType(Ljava/lang/Class;)I
-HSPLandroidx/lifecycle/Lifecycling;->lifecycleEventObserver(Ljava/lang/Object;)Landroidx/lifecycle/LifecycleEventObserver;
-HSPLandroidx/lifecycle/Lifecycling;->resolveObserverCallbackType(Ljava/lang/Class;)I
-HSPLandroidx/lifecycle/ReflectiveGenericLifecycleObserver;-><init>(Ljava/lang/Object;)V
-HSPLandroidx/lifecycle/ReflectiveGenericLifecycleObserver;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
-PLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onDestroy(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V
-PLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onPause(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V
-PLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onStop(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V
diff --git a/lifecycle/lifecycle-runtime/build.gradle b/lifecycle/lifecycle-runtime/build.gradle
index 323d017..b8503f9 100644
--- a/lifecycle/lifecycle-runtime/build.gradle
+++ b/lifecycle/lifecycle-runtime/build.gradle
@@ -14,6 +14,7 @@
plugins {
id("AndroidXPlugin")
id("com.android.library")
+ id("androidx.baselineprofile")
}
androidXMultiplatform {
android()
@@ -56,6 +57,12 @@
dependsOn(jvmMain)
}
+ desktopTest {
+ dependencies {
+ implementation(libs.kotlinCoroutinesSwing)
+ }
+ }
+
androidMain {
dependsOn(jvmMain)
dependencies {
diff --git a/lifecycle/lifecycle-runtime/src/androidMain/baseline-prof.txt b/lifecycle/lifecycle-runtime/src/androidMain/baseline-prof.txt
index 47d4f10..e60ad60 100644
--- a/lifecycle/lifecycle-runtime/src/androidMain/baseline-prof.txt
+++ b/lifecycle/lifecycle-runtime/src/androidMain/baseline-prof.txt
@@ -48,3 +48,48 @@
PLandroidx/lifecycle/ReportFragment;->onDestroy()V
PLandroidx/lifecycle/ReportFragment;->onPause()V
PLandroidx/lifecycle/ReportFragment;->onStop()V
+
+# Baseline Profiles for lifecycle-common
+
+HPLandroidx/lifecycle/Lifecycle$Event;->downFrom(Landroidx/lifecycle/Lifecycle$State;)Landroidx/lifecycle/Lifecycle$Event;
+HSPLandroidx/lifecycle/ClassesInfoCache$CallbackInfo;-><init>(Ljava/util/Map;)V
+HSPLandroidx/lifecycle/ClassesInfoCache$CallbackInfo;->invokeCallbacks(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;Ljava/lang/Object;)V
+HSPLandroidx/lifecycle/ClassesInfoCache$CallbackInfo;->invokeMethodsForEvent(Ljava/util/List;Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;Ljava/lang/Object;)V
+HSPLandroidx/lifecycle/ClassesInfoCache$MethodReference;-><init>(ILjava/lang/reflect/Method;)V
+HSPLandroidx/lifecycle/ClassesInfoCache$MethodReference;->hashCode()I
+HSPLandroidx/lifecycle/ClassesInfoCache$MethodReference;->invokeCallback(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;Ljava/lang/Object;)V
+HSPLandroidx/lifecycle/ClassesInfoCache;-><clinit>()V
+HSPLandroidx/lifecycle/ClassesInfoCache;-><init>()V
+HSPLandroidx/lifecycle/ClassesInfoCache;->createInfo(Ljava/lang/Class;[Ljava/lang/reflect/Method;)Landroidx/lifecycle/ClassesInfoCache$CallbackInfo;
+HSPLandroidx/lifecycle/ClassesInfoCache;->getDeclaredMethods(Ljava/lang/Class;)[Ljava/lang/reflect/Method;
+HSPLandroidx/lifecycle/ClassesInfoCache;->getInfo(Ljava/lang/Class;)Landroidx/lifecycle/ClassesInfoCache$CallbackInfo;
+HSPLandroidx/lifecycle/ClassesInfoCache;->hasLifecycleMethods(Ljava/lang/Class;)Z
+HSPLandroidx/lifecycle/ClassesInfoCache;->verifyAndPutHandler(Ljava/util/Map;Landroidx/lifecycle/ClassesInfoCache$MethodReference;Landroidx/lifecycle/Lifecycle$Event;Ljava/lang/Class;)V
+HSPLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onCreate(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V
+HSPLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onResume(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V
+HSPLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onStart(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V
+HSPLandroidx/lifecycle/FullLifecycleObserverAdapter$1;-><clinit>()V
+HSPLandroidx/lifecycle/FullLifecycleObserverAdapter;-><init>(Landroidx/lifecycle/FullLifecycleObserver;Landroidx/lifecycle/LifecycleEventObserver;)V
+HSPLandroidx/lifecycle/FullLifecycleObserverAdapter;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/lifecycle/Lifecycle$1;-><clinit>()V
+HSPLandroidx/lifecycle/Lifecycle$Event;-><clinit>()V
+HSPLandroidx/lifecycle/Lifecycle$Event;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/lifecycle/Lifecycle$Event;->getTargetState()Landroidx/lifecycle/Lifecycle$State;
+HSPLandroidx/lifecycle/Lifecycle$Event;->upFrom(Landroidx/lifecycle/Lifecycle$State;)Landroidx/lifecycle/Lifecycle$Event;
+HSPLandroidx/lifecycle/Lifecycle$Event;->values()[Landroidx/lifecycle/Lifecycle$Event;
+HSPLandroidx/lifecycle/Lifecycle$State;-><clinit>()V
+HSPLandroidx/lifecycle/Lifecycle$State;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/lifecycle/Lifecycle$State;->isAtLeast(Landroidx/lifecycle/Lifecycle$State;)Z
+HSPLandroidx/lifecycle/Lifecycle$State;->values()[Landroidx/lifecycle/Lifecycle$State;
+HSPLandroidx/lifecycle/Lifecycle;-><init>()V
+HSPLandroidx/lifecycle/Lifecycling;-><clinit>()V
+HSPLandroidx/lifecycle/Lifecycling;->generatedConstructor(Ljava/lang/Class;)Ljava/lang/reflect/Constructor;
+HSPLandroidx/lifecycle/Lifecycling;->getAdapterName(Ljava/lang/String;)Ljava/lang/String;
+HSPLandroidx/lifecycle/Lifecycling;->getObserverConstructorType(Ljava/lang/Class;)I
+HSPLandroidx/lifecycle/Lifecycling;->lifecycleEventObserver(Ljava/lang/Object;)Landroidx/lifecycle/LifecycleEventObserver;
+HSPLandroidx/lifecycle/Lifecycling;->resolveObserverCallbackType(Ljava/lang/Class;)I
+HSPLandroidx/lifecycle/ReflectiveGenericLifecycleObserver;-><init>(Ljava/lang/Object;)V
+HSPLandroidx/lifecycle/ReflectiveGenericLifecycleObserver;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+PLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onDestroy(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V
+PLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onPause(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V
+PLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onStop(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V
diff --git a/lifecycle/lifecycle-runtime/src/desktopMain/kotlin/androidx/lifecycle/MainDispatcherChecker.desktop.kt b/lifecycle/lifecycle-runtime/src/desktopMain/kotlin/androidx/lifecycle/MainDispatcherChecker.desktop.kt
index b2088bf..6d4407c 100644
--- a/lifecycle/lifecycle-runtime/src/desktopMain/kotlin/androidx/lifecycle/MainDispatcherChecker.desktop.kt
+++ b/lifecycle/lifecycle-runtime/src/desktopMain/kotlin/androidx/lifecycle/MainDispatcherChecker.desktop.kt
@@ -16,30 +16,45 @@
package androidx.lifecycle
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
internal object MainDispatcherChecker {
- private val isMainDispatcherAvailable: Boolean
- private var isMainDispatcherThread = ThreadLocal.withInitial { false }
+ private var isMainDispatcherAvailable: Boolean = true
+ @Volatile
+ private var mainDispatcherThread: Thread? = null
- init {
- isMainDispatcherAvailable = try {
- runBlocking {
- launch(Dispatchers.Main.immediate) {
- isMainDispatcherThread.set(true)
- }
+ private fun updateMainDispatcherThread() {
+ try {
+ runBlocking(Dispatchers.Main.immediate) {
+ mainDispatcherThread = Thread.currentThread()
}
- true
} catch (_: IllegalStateException) {
// No main dispatchers are present in the classpath
- false
+ isMainDispatcherAvailable = false
}
}
- fun isMainDispatcherThread(): Boolean = if (isMainDispatcherAvailable) {
- isMainDispatcherThread.get()
- } else {
- true
+ fun isMainDispatcherThread(): Boolean {
+ if (!isMainDispatcherAvailable) {
+ // If we know there's no main dispatcher, assume we're on it.
+ return true
+ }
+
+ val currentThread = Thread.currentThread()
+ // If the thread has already been retrieved,
+ // we can just check whether we are currently running on the same thread
+ if (currentThread === mainDispatcherThread) {
+ return true
+ }
+
+ // If the current thread doesn't match the stored main dispatcher thread, is is either:
+ // * The field may not have been initialized yet.
+ // * The Swing Event Dispatch Thread (EDT) may have changed (if applicable).
+ // * We're genuinely not executing on the main thread.
+ // Let's recheck to obtain the most up-to-date dispatcher reference. The recheck can
+ // be time-consuming, but should only occur in less common scenarios.
+ updateMainDispatcherThread()
+
+ return !isMainDispatcherAvailable || currentThread === mainDispatcherThread
}
}
diff --git a/lifecycle/lifecycle-runtime/src/desktopTest/kotlin/MainDispatcherCheckerTest.kt b/lifecycle/lifecycle-runtime/src/desktopTest/kotlin/MainDispatcherCheckerTest.kt
new file mode 100644
index 0000000..9ecaacf
--- /dev/null
+++ b/lifecycle/lifecycle-runtime/src/desktopTest/kotlin/MainDispatcherCheckerTest.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import androidx.lifecycle.MainDispatcherChecker
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+import kotlin.coroutines.CoroutineContext
+import kotlin.test.Test
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.MainCoroutineDispatcher
+import kotlinx.coroutines.Runnable
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.resetMain
+import kotlinx.coroutines.test.setMain
+
+class MainDispatcherCheckerTest {
+ @Test
+ fun checkMainDispatcher() {
+ runBlocking(Dispatchers.Main) {
+ assertTrue(MainDispatcherChecker.isMainDispatcherThread())
+ }
+ runBlocking(Dispatchers.Main.immediate) {
+ assertTrue(MainDispatcherChecker.isMainDispatcherThread())
+ }
+ }
+
+ @Test
+ fun checkNonMainDispatcher() {
+ runBlocking(Dispatchers.IO) {
+ assertFalse(MainDispatcherChecker.isMainDispatcherThread())
+ }
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ fun checkMainDispatcherChanged() {
+ try {
+ Dispatchers.setMain(ThreadChangingMainDispatcher)
+ runBlocking(Dispatchers.Main) {
+ assertTrue(MainDispatcherChecker.isMainDispatcherThread())
+ }
+ ThreadChangingMainDispatcher.changeThread()
+ runBlocking(Dispatchers.Main) {
+ assertTrue(MainDispatcherChecker.isMainDispatcherThread())
+ }
+ } finally {
+ Dispatchers.resetMain()
+ }
+ }
+
+ private object ThreadChangingMainDispatcher : MainCoroutineDispatcher() {
+ private var thread: Thread? = null
+ private var executor = newExecutorService()
+
+ override val immediate: MainCoroutineDispatcher
+ get() = this
+
+ override fun dispatch(context: CoroutineContext, block: Runnable) {
+ // support reentrancy
+ if (Thread.currentThread() == thread) {
+ block.run()
+ } else {
+ executor.submit(block)
+ }
+ }
+
+ fun changeThread() {
+ executor.shutdown()
+ executor = newExecutorService()
+ }
+
+ private fun newExecutorService(): ExecutorService =
+ Executors.newSingleThreadExecutor {
+ thread = Thread(it)
+ thread
+ }
+ }
+}
diff --git a/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/ViewModel.kt b/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/ViewModel.kt
index cb1bb1a..10913aa 100644
--- a/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/ViewModel.kt
+++ b/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/ViewModel.kt
@@ -145,10 +145,7 @@
* prevent a memory leak, as the subscriptions might hold a reference to the [ViewModel] even
* after it is no longer needed.
*
- * **Clearing Sequence:**
- * 1. [AutoCloseable.close] resources added **without** a key via [addCloseable].
- * 2. [AutoCloseable.close] resources added **with** a key via [addCloseable].
- * 3. Invoke the [onCleared] callback.
+ * For specifics about the clearing sequence, refer to the [clear] method.
*/
protected open fun onCleared()
@@ -159,9 +156,10 @@
* immediately closed.
*
* **Clearing Sequence:**
- * 1. [AutoCloseable.close] resources added **without** a key via [addCloseable].
- * 2. [AutoCloseable.close] resources added **with** a key via [addCloseable].
- * 3. Invoke the [onCleared] callback.
+ * 1. [Close][AutoCloseable.close] resources added **with** a key via [addCloseable].
+ * 2. [Close][AutoCloseable.close] resources added via `constructor`.
+ * 3. [Close][AutoCloseable.close] resources added **without** a key via [addCloseable].
+ * 4. Invoke the [onCleared] callback.
*/
@MainThread
internal fun clear()
diff --git a/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/internal/ViewModelImpl.kt b/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/internal/ViewModelImpl.kt
index dd79e0c..00efd4b 100644
--- a/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/internal/ViewModelImpl.kt
+++ b/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/internal/ViewModelImpl.kt
@@ -42,13 +42,10 @@
* The associated resources will be [AutoCloseable.close] right before the [ViewModel.onCleared]
* is called. This provides automatic resource cleanup upon [ViewModel] release.
*
- * The clearing order is:
- * 1. [keyToCloseables][AutoCloseable.close]
- * 2. [closeables][AutoCloseable.close]
- * 3. [ViewModel.onCleared]
+ * For specifics about the clearing sequence, refer to the [ViewModel.clear] method.
*
- * **Note:** Manually [SynchronizedObject] is necessary to prevent issues on Android API 21 and 22.
- * This avoids potential problems found in older versions of `ConcurrentHashMap`.
+ * **Note:** Manually [SynchronizedObject] is necessary to prevent issues on Android API 21
+ * and 22. This avoids potential problems found in older versions of `ConcurrentHashMap`.
*
* @see <a href="https://issuetracker.google.com/37042460">b/37042460</a>
*/
@@ -84,9 +81,10 @@
isCleared = true
synchronized(lock) {
- // 1. Closes resources added without a key.
- // 2. Closes resources added with a key.
- for (closeable in closeables + keyToCloseables.values) {
+ for (closeable in keyToCloseables.values) {
+ closeWithRuntimeException(closeable)
+ }
+ for (closeable in closeables) {
closeWithRuntimeException(closeable)
}
// Clear only resources without keys to prevent accidental recreation of resources.
diff --git a/lifecycle/lifecycle-viewmodel/src/commonTest/kotlin/androidx/lifecycle/ViewModelTest.kt b/lifecycle/lifecycle-viewmodel/src/commonTest/kotlin/androidx/lifecycle/ViewModelTest.kt
index 570bf8e..fc82ddb 100644
--- a/lifecycle/lifecycle-viewmodel/src/commonTest/kotlin/androidx/lifecycle/ViewModelTest.kt
+++ b/lifecycle/lifecycle-viewmodel/src/commonTest/kotlin/androidx/lifecycle/ViewModelTest.kt
@@ -154,12 +154,50 @@
}
//endregion
+ @Test
+ fun clear_closesResources_inCleaningSequenceOrder() {
+ val clearedInOrderCloseables = mutableListOf<AutoCloseable>()
+ val closeableInConstructor1 = CloseableResource { clearedInOrderCloseables += this }
+ val closeableInConstructor2 = CloseableResource { clearedInOrderCloseables += this }
+ val closeableWithoutKey1 = CloseableResource { clearedInOrderCloseables += this }
+ val closeableWithoutKey2 = CloseableResource { clearedInOrderCloseables += this }
+ val closeableWithKey1 = CloseableResource { clearedInOrderCloseables += this }
+ val closeableWithKey2 = CloseableResource { clearedInOrderCloseables += this }
+
+ val viewModel = TestViewModel(closeableInConstructor1, closeableInConstructor2)
+ viewModel.addCloseable(closeableWithoutKey1)
+ viewModel.addCloseable(key = "customKey1", closeableWithKey1)
+ viewModel.addCloseable(closeableWithoutKey2)
+ viewModel.addCloseable(key = "customKey2", closeableWithKey2)
+ viewModel.clear()
+
+ // The clearing order is:
+ val expectedCloseables = listOf(
+ // 1. Resources added **with** a key via `addCloseable`.
+ closeableWithKey1,
+ closeableWithKey2,
+
+ // 2. Resources added **without** a key via `constructor`.
+ closeableInConstructor1,
+ closeableInConstructor2,
+
+ // 3. Resources added **without** a key via `addCloseable`.
+ closeableWithoutKey1,
+ closeableWithoutKey2,
+ )
+ assertThat(clearedInOrderCloseables).isEqualTo(expectedCloseables)
+ }
+
//region test helpers
private class TestViewModel(vararg closeables: AutoCloseable) : ViewModel(*closeables)
- private class CloseableResource(var isClosed: Boolean = false) : AutoCloseable {
+ private class CloseableResource(
+ var isClosed: Boolean = false,
+ val onClose: CloseableResource.() -> Unit = {},
+ ) : AutoCloseable {
override fun close() {
isClosed = true
+ onClose(this)
}
}
//endregion
diff --git a/navigation/navigation-common/api/current.txt b/navigation/navigation-common/api/current.txt
index 54e9664..fcb454f 100644
--- a/navigation/navigation-common/api/current.txt
+++ b/navigation/navigation-common/api/current.txt
@@ -183,6 +183,7 @@
}
public final class NavDeepLinkDslBuilderKt {
+ method @SuppressCompatibility @androidx.navigation.ExperimentalSafeArgsApi public static inline <reified T> androidx.navigation.NavDeepLink navDeepLink(optional java.util.Map<kotlin.reflect.KType,androidx.navigation.NavType<?>> typeMap, kotlin.jvm.functions.Function1<? super androidx.navigation.NavDeepLinkDslBuilder,kotlin.Unit> deepLinkBuilder);
method public static androidx.navigation.NavDeepLink navDeepLink(kotlin.jvm.functions.Function1<? super androidx.navigation.NavDeepLinkDslBuilder,kotlin.Unit> deepLinkBuilder);
}
@@ -454,16 +455,21 @@
property public boolean isNullableAllowed;
property public String name;
field public static final androidx.navigation.NavType<boolean[]?> BoolArrayType;
+ field public static final androidx.navigation.NavType<java.util.List<java.lang.Boolean>?> BoolListType;
field public static final androidx.navigation.NavType<java.lang.Boolean> BoolType;
field public static final androidx.navigation.NavType.Companion Companion;
field public static final androidx.navigation.NavType<float[]?> FloatArrayType;
+ field public static final androidx.navigation.NavType<java.util.List<java.lang.Float>?> FloatListType;
field public static final androidx.navigation.NavType<java.lang.Float> FloatType;
field public static final androidx.navigation.NavType<int[]?> IntArrayType;
+ field public static final androidx.navigation.NavType<java.util.List<java.lang.Integer>?> IntListType;
field public static final androidx.navigation.NavType<java.lang.Integer> IntType;
field public static final androidx.navigation.NavType<long[]?> LongArrayType;
+ field public static final androidx.navigation.NavType<java.util.List<java.lang.Long>?> LongListType;
field public static final androidx.navigation.NavType<java.lang.Long> LongType;
field public static final androidx.navigation.NavType<java.lang.Integer> ReferenceType;
field public static final androidx.navigation.NavType<java.lang.String[]?> StringArrayType;
+ field public static final androidx.navigation.NavType<java.util.List<java.lang.String>?> StringListType;
field public static final androidx.navigation.NavType<java.lang.String?> StringType;
}
diff --git a/navigation/navigation-common/api/restricted_current.txt b/navigation/navigation-common/api/restricted_current.txt
index 54e9664..fcb454f 100644
--- a/navigation/navigation-common/api/restricted_current.txt
+++ b/navigation/navigation-common/api/restricted_current.txt
@@ -183,6 +183,7 @@
}
public final class NavDeepLinkDslBuilderKt {
+ method @SuppressCompatibility @androidx.navigation.ExperimentalSafeArgsApi public static inline <reified T> androidx.navigation.NavDeepLink navDeepLink(optional java.util.Map<kotlin.reflect.KType,androidx.navigation.NavType<?>> typeMap, kotlin.jvm.functions.Function1<? super androidx.navigation.NavDeepLinkDslBuilder,kotlin.Unit> deepLinkBuilder);
method public static androidx.navigation.NavDeepLink navDeepLink(kotlin.jvm.functions.Function1<? super androidx.navigation.NavDeepLinkDslBuilder,kotlin.Unit> deepLinkBuilder);
}
@@ -454,16 +455,21 @@
property public boolean isNullableAllowed;
property public String name;
field public static final androidx.navigation.NavType<boolean[]?> BoolArrayType;
+ field public static final androidx.navigation.NavType<java.util.List<java.lang.Boolean>?> BoolListType;
field public static final androidx.navigation.NavType<java.lang.Boolean> BoolType;
field public static final androidx.navigation.NavType.Companion Companion;
field public static final androidx.navigation.NavType<float[]?> FloatArrayType;
+ field public static final androidx.navigation.NavType<java.util.List<java.lang.Float>?> FloatListType;
field public static final androidx.navigation.NavType<java.lang.Float> FloatType;
field public static final androidx.navigation.NavType<int[]?> IntArrayType;
+ field public static final androidx.navigation.NavType<java.util.List<java.lang.Integer>?> IntListType;
field public static final androidx.navigation.NavType<java.lang.Integer> IntType;
field public static final androidx.navigation.NavType<long[]?> LongArrayType;
+ field public static final androidx.navigation.NavType<java.util.List<java.lang.Long>?> LongListType;
field public static final androidx.navigation.NavType<java.lang.Long> LongType;
field public static final androidx.navigation.NavType<java.lang.Integer> ReferenceType;
field public static final androidx.navigation.NavType<java.lang.String[]?> StringArrayType;
+ field public static final androidx.navigation.NavType<java.util.List<java.lang.String>?> StringListType;
field public static final androidx.navigation.NavType<java.lang.String?> StringType;
}
diff --git a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDeepLinkBuilderTest.kt b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDeepLinkBuilderTest.kt
index a04bdab..bae7b4e 100644
--- a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDeepLinkBuilderTest.kt
+++ b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDeepLinkBuilderTest.kt
@@ -16,10 +16,12 @@
package androidx.navigation
+import androidx.navigation.NavOptionsTest.TestClass
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
+import kotlinx.serialization.Serializable
import org.junit.Assert.fail
import org.junit.Test
import org.junit.runner.RunWith
@@ -91,4 +93,137 @@
.that(navDeepLink.action)
.isNull()
}
+
+ @OptIn(ExperimentalSafeArgsApi::class)
+ @Test
+ fun buildDeepLinkAllSetKClass() {
+ val expectedUri = "example.com"
+ val expectedAction = "test.action"
+ val expectedMimeType = "test/type"
+ val navDeepLink = navDeepLink<TestClass> {
+ uriPattern = expectedUri
+ action = expectedAction
+ mimeType = expectedMimeType
+ }
+ assertWithMessage("NavDeepLink should have uri pattern set")
+ .that(navDeepLink.uriPattern)
+ .isEqualTo(expectedUri)
+ assertWithMessage("NavDeepLink should have action set")
+ .that(navDeepLink.action)
+ .isEqualTo(expectedAction)
+ assertWithMessage("NavDeepLink should have mimeType set")
+ .that(navDeepLink.mimeType)
+ .isEqualTo(expectedMimeType)
+ }
+
+ @OptIn(ExperimentalSafeArgsApi::class)
+ @Test
+ fun buildDeepLinkAllSetKClassWithPathArgs() {
+ @Serializable
+ class TestClass(val arg: Int, val arg2: String)
+
+ val expectedUri = "example.com"
+ val expectedAction = "test.action"
+ val expectedMimeType = "test/type"
+ val navDeepLink = navDeepLink<TestClass> {
+ uriPattern = expectedUri
+ action = expectedAction
+ mimeType = expectedMimeType
+ }
+ assertWithMessage("NavDeepLink should have uri pattern set")
+ .that(navDeepLink.uriPattern)
+ .isEqualTo("$expectedUri/{arg}/{arg2}")
+ assertWithMessage("NavDeepLink should have action set")
+ .that(navDeepLink.action)
+ .isEqualTo(expectedAction)
+ assertWithMessage("NavDeepLink should have mimeType set")
+ .that(navDeepLink.mimeType)
+ .isEqualTo(expectedMimeType)
+ }
+
+ @OptIn(ExperimentalSafeArgsApi::class)
+ @Test
+ fun buildDeepLinkAllSetKClassWithQueryArgs() {
+ @Serializable
+ class TestClass(val arg: Int, val arg2: String = "default")
+
+ val expectedUri = "example.com"
+ val expectedAction = "test.action"
+ val expectedMimeType = "test/type"
+ val navDeepLink = navDeepLink<TestClass> {
+ uriPattern = expectedUri
+ action = expectedAction
+ mimeType = expectedMimeType
+ }
+ assertWithMessage("NavDeepLink should have uri pattern set")
+ .that(navDeepLink.uriPattern)
+ .isEqualTo("$expectedUri/{arg}?arg2={arg2}")
+ assertWithMessage("NavDeepLink should have action set")
+ .that(navDeepLink.action)
+ .isEqualTo(expectedAction)
+ assertWithMessage("NavDeepLink should have mimeType set")
+ .that(navDeepLink.mimeType)
+ .isEqualTo(expectedMimeType)
+ }
+
+ @OptIn(ExperimentalSafeArgsApi::class)
+ @Test
+ fun buildDeepLinkNoneSetKClass() {
+ var exception: IllegalStateException? = null
+ try {
+ navDeepLink<TestClass> {}
+ fail("NavDeepLink must throw when attempting to build an empty builder.")
+ } catch (e: IllegalStateException) {
+ exception = e
+ }
+ assertThat(exception?.message)
+ .isEqualTo("The NavDeepLink must have an uri, action, and/or mimeType.")
+ }
+
+ @OptIn(ExperimentalSafeArgsApi::class)
+ @Test
+ fun buildDeepLinkNoUriKClass() {
+ var exception: IllegalStateException? = null
+ try {
+ navDeepLink<TestClass> { action = "action" }
+ fail("NavDeepLink must throw when attempting to build an empty builder.")
+ } catch (e: IllegalStateException) {
+ exception = e
+ }
+ assertThat(exception?.message)
+ .isEqualTo("Failed to build NavDeepLink from KClass. Ensure base path is " +
+ "set through uriPattern.")
+ }
+
+ @OptIn(ExperimentalSafeArgsApi::class)
+ @Test
+ fun buildDeepLinkEmptyActionKClass() {
+ var exception: IllegalArgumentException? = null
+ try {
+ navDeepLink<TestClass> { action = "" }
+ fail("NavDeepLink must throw when attempting to build with an empty action.")
+ } catch (e: IllegalArgumentException) {
+ exception = e
+ }
+ assertThat(exception?.message)
+ .isEqualTo("The NavDeepLink cannot have an empty action.")
+ }
+
+ @OptIn(ExperimentalSafeArgsApi::class)
+ @Test
+ fun buildDeepLinkDoubleActionSetNullKClass() {
+ val expectedUri = "www.example.com"
+ val navDeepLink = navDeepLink<TestClass> {
+ uriPattern = expectedUri
+ action = "blah"
+ action = null
+ }
+
+ assertWithMessage("NavDeepLink should have uri pattern set")
+ .that(navDeepLink.uriPattern)
+ .isEqualTo(expectedUri)
+ assertWithMessage("NavDeepLink should have action set")
+ .that(navDeepLink.action)
+ .isNull()
+ }
}
diff --git a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavTypeTest.kt b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavTypeTest.kt
index c92982f..82dd11c 100644
--- a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavTypeTest.kt
+++ b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavTypeTest.kt
@@ -38,14 +38,24 @@
companion object {
private const val i = 1
private val ints = intArrayOf(0, 1)
+ private val intList = listOf(0, 1)
+ private val intArrayList = arrayListOf(0, 1)
private const val l = 1L
private val longs = longArrayOf(0L, 1L)
+ private val longList = listOf(0L, 1L)
+ private val longArrayList = arrayListOf(0L, 1L)
private const val fl = 1.5f
private val floats = floatArrayOf(1f, 2.5f)
+ private val floatList = listOf(1f, 2.5f)
+ private val floatArrayList = arrayListOf(1f, 2.5f)
private const val b = true
private val booleans = booleanArrayOf(b, false)
+ private val boolList = listOf(b, false)
+ private val booArrayList = arrayListOf(b, false)
private const val s = "a_string"
private val strings = arrayOf("aa", "bb")
+ private val stringList = listOf("aa", "bb")
+ private val stringArrayList = arrayListOf("aa", "bb")
private val reference = R.id.nav_id_reference
private val referenceHex = "0x" + R.id.nav_id_reference.toString(16)
private val parcelable = ActivityInfo()
@@ -71,22 +81,32 @@
.isEqualTo(NavType.IntType)
assertThat(NavType.fromArgType("integer[]", null))
.isEqualTo(NavType.IntArrayType)
+ assertThat(NavType.fromArgType("List<Int>", null))
+ .isEqualTo(NavType.IntListType)
assertThat(NavType.fromArgType("long", null))
.isEqualTo(NavType.LongType)
assertThat(NavType.fromArgType("long[]", null))
.isEqualTo(NavType.LongArrayType)
+ assertThat(NavType.fromArgType("List<Long>", null))
+ .isEqualTo(NavType.LongListType)
assertThat(NavType.fromArgType("float", null))
.isEqualTo(NavType.FloatType)
assertThat(NavType.fromArgType("float[]", null))
.isEqualTo(NavType.FloatArrayType)
+ assertThat(NavType.fromArgType("List<Float>", null))
+ .isEqualTo(NavType.FloatListType)
assertThat(NavType.fromArgType("boolean", null))
.isEqualTo(NavType.BoolType)
assertThat(NavType.fromArgType("boolean[]", null))
.isEqualTo(NavType.BoolArrayType)
+ assertThat(NavType.fromArgType("List<Boolean>", null))
+ .isEqualTo(NavType.BoolListType)
assertThat(NavType.fromArgType("string", null))
.isEqualTo(NavType.StringType)
assertThat(NavType.fromArgType("string[]", null))
.isEqualTo(NavType.StringArrayType)
+ assertThat(NavType.fromArgType("List<String>", null))
+ .isEqualTo(NavType.StringListType)
assertThat(NavType.fromArgType("reference", null))
.isEqualTo(NavType.ReferenceType)
assertThat(NavType.fromArgType("android.content.pm.ActivityInfo", null))
@@ -169,6 +189,16 @@
.isEqualTo(ints)
bundle.clear()
+ NavType.IntListType.put(bundle, key, intList)
+ assertThat(NavType.IntListType[bundle, key])
+ .isEqualTo(intList)
+ bundle.clear()
+
+ NavType.IntListType.put(bundle, key, intArrayList)
+ assertThat(NavType.IntListType[bundle, key])
+ .isEqualTo(intArrayList)
+ bundle.clear()
+
NavType.LongType.put(bundle, key, l)
assertThat(NavType.LongType[bundle, key])
.isEqualTo(l)
@@ -179,6 +209,16 @@
.isEqualTo(longs)
bundle.clear()
+ NavType.LongListType.put(bundle, key, longList)
+ assertThat(NavType.LongListType[bundle, key])
+ .isEqualTo(longList)
+ bundle.clear()
+
+ NavType.LongListType.put(bundle, key, longArrayList)
+ assertThat(NavType.LongListType[bundle, key])
+ .isEqualTo(longArrayList)
+ bundle.clear()
+
NavType.FloatType.put(bundle, key, fl)
assertThat(NavType.FloatType[bundle, key])
.isEqualTo(fl)
@@ -189,6 +229,16 @@
.isEqualTo(floats)
bundle.clear()
+ NavType.FloatListType.put(bundle, key, floatList)
+ assertThat(NavType.FloatListType[bundle, key])
+ .isEqualTo(floatList)
+ bundle.clear()
+
+ NavType.FloatListType.put(bundle, key, floatArrayList)
+ assertThat(NavType.FloatListType[bundle, key])
+ .isEqualTo(floatArrayList)
+ bundle.clear()
+
NavType.BoolType.put(bundle, key, b)
assertThat(NavType.BoolType[bundle, key])
.isEqualTo(b)
@@ -199,6 +249,16 @@
.isEqualTo(booleans)
bundle.clear()
+ NavType.BoolListType.put(bundle, key, boolList)
+ assertThat(NavType.BoolListType[bundle, key])
+ .isEqualTo(boolList)
+ bundle.clear()
+
+ NavType.BoolListType.put(bundle, key, booArrayList)
+ assertThat(NavType.BoolListType[bundle, key])
+ .isEqualTo(booArrayList)
+ bundle.clear()
+
NavType.StringType.put(bundle, key, s)
assertThat(NavType.StringType[bundle, key])
.isEqualTo(s)
@@ -209,6 +269,16 @@
.isEqualTo(strings)
bundle.clear()
+ NavType.StringListType.put(bundle, key, stringList)
+ assertThat(NavType.StringListType[bundle, key])
+ .isEqualTo(stringList)
+ bundle.clear()
+
+ NavType.StringListType.put(bundle, key, stringArrayList)
+ assertThat(NavType.StringListType[bundle, key])
+ .isEqualTo(stringArrayList)
+ bundle.clear()
+
NavType.ReferenceType.put(bundle, key, reference)
assertThat(NavType.ReferenceType[bundle, key])
.isEqualTo(reference)
@@ -302,18 +372,48 @@
assertThat((NavType.IntArrayType as CollectionNavType).serializeAsValues(
intArrayOf(0, 1))
).containsExactly("0", "1").inOrder()
+ assertThat((NavType.IntListType as CollectionNavType).serializeAsValues(
+ listOf(0, 1))
+ ).containsExactly("0", "1").inOrder()
+ assertThat((NavType.IntListType as CollectionNavType).serializeAsValues(
+ arrayListOf(0, 1))
+ ).containsExactly("0", "1").inOrder()
assertThat((NavType.BoolArrayType as CollectionNavType).serializeAsValues(
booleanArrayOf(true, false))
).containsExactly("true", "false").inOrder()
+ assertThat((NavType.BoolListType as CollectionNavType).serializeAsValues(
+ listOf(true, false))
+ ).containsExactly("true", "false").inOrder()
+ assertThat((NavType.BoolListType as CollectionNavType).serializeAsValues(
+ arrayListOf(true, false))
+ ).containsExactly("true", "false").inOrder()
assertThat((NavType.StringArrayType as CollectionNavType).serializeAsValues(
arrayOf("test", "test2"))
).containsExactly("test", "test2").inOrder()
+ assertThat((NavType.StringListType as CollectionNavType).serializeAsValues(
+ listOf("test", "test2"))
+ ).containsExactly("test", "test2").inOrder()
+ assertThat((NavType.StringListType as CollectionNavType).serializeAsValues(
+ arrayListOf("test", "test2"))
+ ).containsExactly("test", "test2").inOrder()
assertThat((NavType.FloatArrayType as CollectionNavType).serializeAsValues(
floatArrayOf(1F, 2F))
).containsExactly("1.0", "2.0").inOrder()
+ assertThat((NavType.FloatListType as CollectionNavType).serializeAsValues(
+ listOf(1F, 2F))
+ ).containsExactly("1.0", "2.0").inOrder()
+ assertThat((NavType.FloatListType as CollectionNavType).serializeAsValues(
+ arrayListOf(1F, 2F))
+ ).containsExactly("1.0", "2.0").inOrder()
assertThat((NavType.LongArrayType as CollectionNavType).serializeAsValues(
longArrayOf(1L, 2L))
).containsExactly("1", "2").inOrder()
+ assertThat((NavType.LongListType as CollectionNavType).serializeAsValues(
+ listOf(1L, 2L))
+ ).containsExactly("1", "2").inOrder()
+ assertThat((NavType.LongListType as CollectionNavType).serializeAsValues(
+ arrayListOf(1L, 2L))
+ ).containsExactly("1", "2").inOrder()
}
@Test
diff --git a/navigation/navigation-common/src/androidTest/java/androidx/navigation/serialization/RouteDecoderTest.kt b/navigation/navigation-common/src/androidTest/java/androidx/navigation/serialization/RouteDecoderTest.kt
index c07082f..6905a17 100644
--- a/navigation/navigation-common/src/androidTest/java/androidx/navigation/serialization/RouteDecoderTest.kt
+++ b/navigation/navigation-common/src/androidTest/java/androidx/navigation/serialization/RouteDecoderTest.kt
@@ -379,6 +379,17 @@
assertThat(result.custom.arg).isNull()
}
+ @Test
+ fun decodeCollectionNavType() {
+ val arg = listOf(CustomType(1), CustomType(3), CustomType(5))
+ val bundle = bundleOf("list" to arg)
+ val result = decode<TestClassCollectionArg>(
+ bundle,
+ listOf(navArgument("list") { type = collectionNavType })
+ )
+ assertThat(result.list).containsExactlyElementsIn(arg).inOrder()
+ }
+
private inline fun <reified T : Any> decode(
bundle: Bundle,
args: List<NamedNavArgument> = emptyList()
diff --git a/navigation/navigation-common/src/androidTest/java/androidx/navigation/serialization/RouteFilledTest.kt b/navigation/navigation-common/src/androidTest/java/androidx/navigation/serialization/RouteFilledTest.kt
index 7f1ac4a..9bb4d25 100644
--- a/navigation/navigation-common/src/androidTest/java/androidx/navigation/serialization/RouteFilledTest.kt
+++ b/navigation/navigation-common/src/androidTest/java/androidx/navigation/serialization/RouteFilledTest.kt
@@ -17,6 +17,7 @@
package androidx.navigation.serialization
import android.os.Bundle
+import androidx.navigation.CollectionNavType
import androidx.navigation.NamedNavArgument
import androidx.navigation.NavType
import androidx.navigation.navArgument
@@ -401,6 +402,23 @@
}
@Test
+ fun routeListArgs() {
+ @Serializable
+ @SerialName(PATH_SERIAL_NAME)
+ class IntList(val list: List<Int>)
+ assertThatRouteFilledFrom(
+ IntList(listOf(1, 2)),
+ listOf(
+ navArgument("list") {
+ type = NavType.IntListType
+ nullable = false
+ unknownDefaultValuePresent = false
+ }
+ )
+ ).isEqualTo("$PATH_SERIAL_NAME?list=1&list=2")
+ }
+
+ @Test
fun withSecondaryConstructor() {
@Serializable
@SerialName(PATH_SERIAL_NAME)
@@ -548,6 +566,67 @@
}
@Test
+ fun customTypeParam() {
+ @Serializable
+ open class TypeParam
+ @Serializable
+ class CustomType<T : TypeParam>
+ @Serializable
+ @SerialName(PATH_SERIAL_NAME)
+ class TestClass(val custom: CustomType<TypeParam>)
+
+ val navType = object : NavType<CustomType<TypeParam>>(false) {
+ override val name: String
+ get() = "CustomType"
+ override fun put(bundle: Bundle, key: String, value: CustomType<TypeParam>) { }
+ override fun get(bundle: Bundle, key: String): CustomType<TypeParam>? = null
+ override fun parseValue(value: String): CustomType<TypeParam> = CustomType()
+ override fun serializeAsValue(value: CustomType<TypeParam>) = "customValue"
+ }
+ assertThatRouteFilledFrom(
+ TestClass(CustomType()),
+ listOf(navArgument("custom") { type = navType })
+ ).isEqualTo(
+ "$PATH_SERIAL_NAME/customValue"
+ )
+ }
+
+ @Test
+ fun customTypeParamNested() {
+ @Serializable
+ open class TypeParamNested
+ @Serializable
+ open class TypeParam<K : TypeParamNested>
+ @Serializable
+ class CustomType<T : TypeParam<TypeParamNested>>
+ @Serializable
+ @SerialName(PATH_SERIAL_NAME)
+ class TestClass(val custom: CustomType<TypeParam<TypeParamNested>>)
+
+ val navType = object : NavType<CustomType<TypeParam<TypeParamNested>>>(false) {
+ override val name: String
+ get() = "CustomType"
+ override fun put(
+ bundle: Bundle,
+ key: String,
+ value: CustomType<TypeParam<TypeParamNested>>
+ ) { }
+ override fun get(bundle: Bundle, key: String): CustomType<TypeParam<TypeParamNested>>? =
+ null
+ override fun parseValue(value: String): CustomType<TypeParam<TypeParamNested>> =
+ CustomType()
+ override fun serializeAsValue(value: CustomType<TypeParam<TypeParamNested>>) =
+ "customValue"
+ }
+ assertThatRouteFilledFrom(
+ TestClass(CustomType()),
+ listOf(navArgument("custom") { type = navType })
+ ).isEqualTo(
+ "$PATH_SERIAL_NAME/customValue"
+ )
+ }
+
+ @Test
fun paramWithNoBackingField() {
@Serializable
@SerialName(PATH_SERIAL_NAME)
@@ -684,6 +763,16 @@
PATH_SERIAL_NAME
)
}
+
+ @Test
+ fun collectionNavType() {
+ assertThatRouteFilledFrom(
+ TestClassCollectionArg(listOf(CustomType(1), CustomType(3), CustomType(5))),
+ listOf(navArgument("list") { type = collectionNavType })
+ ).isEqualTo(
+ "$PATH_SERIAL_NAME?list=1&list=3&list=5"
+ )
+ }
}
private fun <T : Any> assertThatRouteFilledFrom(
@@ -748,6 +837,25 @@
CustomSerializerClass(decoder.decodeLong())
}
+@Serializable
+data class CustomType(val id: Int)
+
+@Serializable
+@SerialName(PATH_SERIAL_NAME)
+class TestClassCollectionArg(val list: List<CustomType>)
+
+val collectionNavType = object : CollectionNavType<List<CustomType>>(false) {
+ override fun put(bundle: Bundle, key: String, value: List<CustomType>) { }
+ override fun serializeAsValues(value: List<CustomType>): List<String> =
+ value.map { it.id.toString() }
+ @Suppress("UNCHECKED_CAST", "DEPRECATION")
+ override fun get(bundle: Bundle, key: String): List<CustomType> {
+ return bundle[key] as List<CustomType>
+ }
+ override fun parseValue(value: String): List<CustomType> = listOf()
+ override fun serializeAsValue(value: List<CustomType>) = "customValue"
+}
+
private interface TestInterface
internal fun stringArgument(
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NavDeepLinkDslBuilder.kt b/navigation/navigation-common/src/main/java/androidx/navigation/NavDeepLinkDslBuilder.kt
index 9472414..475a888 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavDeepLinkDslBuilder.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavDeepLinkDslBuilder.kt
@@ -16,24 +16,79 @@
package androidx.navigation
+import androidx.annotation.RestrictTo
+import kotlin.reflect.KClass
+import kotlin.reflect.KType
+
@DslMarker
public annotation class NavDeepLinkDsl
/**
* Construct a new [NavDeepLink]
+ *
+ * @param deepLinkBuilder the builder used to construct the deeplink
*/
public fun navDeepLink(deepLinkBuilder: NavDeepLinkDslBuilder.() -> Unit): NavDeepLink =
NavDeepLinkDslBuilder().apply(deepLinkBuilder).build()
/**
+ * Construct a new [NavDeepLink]
+ *
+ * @param T The route from KClass to extract deeplink arguments from
+ * @param typeMap map of destination arguments' kotlin type [KType] to its respective custom
+ * [NavType]. May be empty if [T] does not use custom NavTypes.
+ * @param deepLinkBuilder the builder used to construct the deeplink
+ */
+@ExperimentalSafeArgsApi
+public inline fun <reified T : Any> navDeepLink(
+ typeMap: Map<KType, @JvmSuppressWildcards NavType<*>> = emptyMap(),
+ noinline deepLinkBuilder: NavDeepLinkDslBuilder.() -> Unit
+): NavDeepLink = navDeepLink(T::class, typeMap, deepLinkBuilder)
+
+// public delegation for reified version to call internal build()
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public fun <T : Any> navDeepLink(
+ route: KClass<T>,
+ typeMap: Map<KType, @JvmSuppressWildcards NavType<*>>,
+ deepLinkBuilder: NavDeepLinkDslBuilder.() -> Unit
+): NavDeepLink = NavDeepLinkDslBuilder(route, typeMap).apply(deepLinkBuilder).build()
+
+/**
* DSL for constructing a new [NavDeepLink]
*/
@NavDeepLinkDsl
public class NavDeepLinkDslBuilder {
private val builder = NavDeepLink.Builder()
+ private var route: KClass<*>? = null
+ private var typeMap: Map<KType, NavType<*>> = emptyMap()
+
+ constructor()
+
+ /**
+ * DSl for constructing a new [NavDeepLink] with a route
+ *
+ * Extracts deeplink arguments from [route] and appends it to the base uri path. The base
+ * uri path should be set with [uriPattern].
+ *
+ * @param route The route from KClass to extract deeplink arguments from
+ * @param typeMap map of destination arguments' kotlin type [KType] to its respective custom
+ * [NavType]. May be empty if [route] does not use custom NavTypes.
+ */
+ internal constructor(
+ route: KClass<*>,
+ typeMap: Map<KType, @JvmSuppressWildcards NavType<*>>
+ ) {
+ this.route = route
+ this.typeMap = typeMap
+ }
+
/**
* The uri pattern of the deep link
+ *
+ * If used with safe args, this forms the base uri to which arguments are appended. See docs on
+ * the safe args version of [NavDeepLink.Builder.setUriPattern] for the final uriPattern's
+ * generation logic.
*/
public var uriPattern: String? = null
@@ -60,7 +115,15 @@
check(!(uriPattern == null && action == null && mimeType == null)) {
("The NavDeepLink must have an uri, action, and/or mimeType.")
}
- uriPattern?.let { setUriPattern(it) }
+ if (route != null) {
+ checkNotNull(uriPattern) {
+ "Failed to build NavDeepLink from KClass. Ensure base path is set " +
+ "through uriPattern."
+ }
+ setUriPattern(uriPattern!!, route!!, typeMap)
+ } else {
+ uriPattern?.let { setUriPattern(it) }
+ }
action?.let { setAction(it) }
mimeType?.let { setMimeType(it) }
}.build()
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NavType.kt b/navigation/navigation-common/src/main/java/androidx/navigation/NavType.kt
index 878d6a4..3f09a49 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavType.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavType.kt
@@ -175,14 +175,19 @@
when {
IntType.name == type -> return IntType
IntArrayType.name == type -> return IntArrayType
+ IntListType.name == type -> return IntListType
LongType.name == type -> return LongType
LongArrayType.name == type -> return LongArrayType
+ LongListType.name == type -> return LongListType
BoolType.name == type -> return BoolType
BoolArrayType.name == type -> return BoolArrayType
+ BoolListType.name == type -> return BoolListType
StringType.name == type -> return StringType
StringArrayType.name == type -> return StringArrayType
+ StringListType.name == type -> return StringListType
FloatType.name == type -> return FloatType
FloatArrayType.name == type -> return FloatArrayType
+ FloatListType.name == type -> return FloatListType
ReferenceType.name == type -> return ReferenceType
!type.isNullOrEmpty() -> {
try {
@@ -411,6 +416,46 @@
}
/**
+ * NavType for storing list of Ints.
+ *
+ * Null values are supported.
+ * List NavTypes in Navigation XML files are not supported.
+ */
+ @JvmField
+ public val IntListType: NavType<List<Int>?> = object : CollectionNavType<List<Int>?>(
+ true
+ ) {
+ override val name: String
+ get() = "List<Int>"
+
+ override fun put(bundle: Bundle, key: String, value: List<Int>?) {
+ bundle.putIntArray(key, value?.toIntArray())
+ }
+
+ @Suppress("DEPRECATION")
+ override fun get(bundle: Bundle, key: String): List<Int>? {
+ return (bundle[key] as IntArray?)?.toList()
+ }
+
+ override fun parseValue(value: String): List<Int> {
+ return listOf(IntType.parseValue(value))
+ }
+
+ override fun parseValue(value: String, previousValue: List<Int>?): List<Int>? {
+ return previousValue?.plus(IntType.parseValue(value)) ?: parseValue(value)
+ }
+
+ override fun valueEquals(value: List<Int>?, other: List<Int>?): Boolean {
+ val valueArray = value?.toTypedArray()
+ val otherArray = other?.toTypedArray()
+ return valueArray.contentDeepEquals(otherArray)
+ }
+
+ override fun serializeAsValues(value: List<Int>?): List<String> =
+ value?.map { it.toString() } ?: emptyList()
+ }
+
+ /**
* NavType for storing long values,
* corresponding with the "long" type in a Navigation XML file.
*
@@ -490,6 +535,46 @@
}
/**
+ * NavType for storing list of Longs.
+ *
+ * Null values are supported.
+ * List NavTypes in Navigation XML files are not supported.
+ */
+ @JvmField
+ public val LongListType: NavType<List<Long>?> = object : CollectionNavType<List<Long>?>(
+ true
+ ) {
+ override val name: String
+ get() = "List<Long>"
+
+ override fun put(bundle: Bundle, key: String, value: List<Long>?) {
+ bundle.putLongArray(key, value?.toLongArray())
+ }
+
+ @Suppress("DEPRECATION")
+ override fun get(bundle: Bundle, key: String): List<Long>? {
+ return (bundle[key] as LongArray?)?.toList()
+ }
+
+ override fun parseValue(value: String): List<Long> {
+ return listOf(LongType.parseValue(value))
+ }
+
+ override fun parseValue(value: String, previousValue: List<Long>?): List<Long>? {
+ return previousValue?.plus(LongType.parseValue(value)) ?: parseValue(value)
+ }
+
+ override fun valueEquals(value: List<Long>?, other: List<Long>?): Boolean {
+ val valueArray = value?.toTypedArray()
+ val otherArray = other?.toTypedArray()
+ return valueArray.contentDeepEquals(otherArray)
+ }
+
+ override fun serializeAsValues(value: List<Long>?): List<String> =
+ value?.map { it.toString() } ?: emptyList()
+ }
+
+ /**
* NavType for storing float values,
* corresponding with the "float" type in a Navigation XML file.
*
@@ -556,6 +641,46 @@
}
/**
+ * NavType for storing list of Floats.
+ *
+ * Null values are supported.
+ * List NavTypes in Navigation XML files are not supported.
+ */
+ @JvmField
+ public val FloatListType: NavType<List<Float>?> = object : CollectionNavType<List<Float>?>(
+ true
+ ) {
+ override val name: String
+ get() = "List<Float>"
+
+ override fun put(bundle: Bundle, key: String, value: List<Float>?) {
+ bundle.putFloatArray(key, value?.toFloatArray())
+ }
+
+ @Suppress("DEPRECATION")
+ override fun get(bundle: Bundle, key: String): List<Float>? {
+ return (bundle[key] as FloatArray?)?.toList()
+ }
+
+ override fun parseValue(value: String): List<Float> {
+ return listOf(FloatType.parseValue(value))
+ }
+
+ override fun parseValue(value: String, previousValue: List<Float>?): List<Float>? {
+ return previousValue?.plus(FloatType.parseValue(value)) ?: parseValue(value)
+ }
+
+ override fun valueEquals(value: List<Float>?, other: List<Float>?): Boolean {
+ val valueArray = value?.toTypedArray()
+ val otherArray = other?.toTypedArray()
+ return valueArray.contentDeepEquals(otherArray)
+ }
+
+ override fun serializeAsValues(value: List<Float>?): List<String> =
+ value?.map { it.toString() } ?: emptyList()
+ }
+
+ /**
* NavType for storing boolean values,
* corresponding with the "boolean" type in a Navigation XML file.
*
@@ -629,6 +754,45 @@
}
/**
+ * NavType for storing list of Booleans.
+ *
+ * Null values are supported.
+ * List NavTypes in Navigation XML files are not supported.
+ */
+ @JvmField
+ public val BoolListType: NavType<List<Boolean>?> =
+ object : CollectionNavType<List<Boolean>?>(true) {
+ override val name: String
+ get() = "List<Boolean>"
+
+ override fun put(bundle: Bundle, key: String, value: List<Boolean>?) {
+ bundle.putBooleanArray(key, value?.toBooleanArray())
+ }
+
+ @Suppress("DEPRECATION")
+ override fun get(bundle: Bundle, key: String): List<Boolean>? {
+ return (bundle[key] as BooleanArray?)?.toList()
+ }
+
+ override fun parseValue(value: String): List<Boolean> {
+ return listOf(BoolType.parseValue(value))
+ }
+
+ override fun parseValue(value: String, previousValue: List<Boolean>?): List<Boolean>? {
+ return previousValue?.plus(BoolType.parseValue(value)) ?: parseValue(value)
+ }
+
+ override fun valueEquals(value: List<Boolean>?, other: List<Boolean>?): Boolean {
+ val valueArray = value?.toTypedArray()
+ val otherArray = other?.toTypedArray()
+ return valueArray.contentDeepEquals(otherArray)
+ }
+
+ override fun serializeAsValues(value: List<Boolean>?): List<String> =
+ value?.map { it.toString() } ?: emptyList()
+ }
+
+ /**
* NavType for storing String values,
* corresponding with the "string" type in a Navigation XML file.
*
@@ -704,8 +868,50 @@
value.contentDeepEquals(other)
override fun serializeAsValues(value: Array<String>?): List<String> =
- value?.toList() ?: emptyList()
+ value?.map { Uri.encode(it) } ?: emptyList()
}
+
+ /**
+ * NavType for storing list of Strings.
+ *
+ * Null values are supported.
+ * List NavTypes in Navigation XML files are not supported.
+ */
+ @JvmField
+ public val StringListType: NavType<List<String>?> =
+ object : CollectionNavType<List<String>?>(true) {
+ override val name: String
+ get() = "List<String>"
+
+ override fun put(bundle: Bundle, key: String, value: List<String>?) {
+ bundle.putStringArray(key, value?.toTypedArray())
+ }
+
+ @Suppress("UNCHECKED_CAST", "DEPRECATION")
+ override fun get(bundle: Bundle, key: String): List<String>? {
+ return (bundle[key] as Array<String>?)?.toList()
+ }
+
+ override fun parseValue(value: String): List<String> {
+ return listOf(value)
+ }
+
+ override fun parseValue(
+ value: String,
+ previousValue: List<String>?
+ ): List<String>? {
+ return previousValue?.plus(value) ?: parseValue(value)
+ }
+
+ override fun valueEquals(value: List<String>?, other: List<String>?): Boolean {
+ val valueArray = value?.toTypedArray()
+ val otherArray = other?.toTypedArray()
+ return valueArray.contentDeepEquals(otherArray)
+ }
+
+ override fun serializeAsValues(value: List<String>?): List<String> =
+ value?.map { Uri.encode(it) } ?: emptyList()
+ }
}
/**
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/serialization/NavTypeConverter.kt b/navigation/navigation-common/src/main/java/androidx/navigation/serialization/NavTypeConverter.kt
index a626a74..7f7b754 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/serialization/NavTypeConverter.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/serialization/NavTypeConverter.kt
@@ -23,13 +23,12 @@
import kotlin.reflect.KType
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.descriptors.SerialDescriptor
-
-private interface InternalCommonType
+import kotlinx.serialization.serializer
/**
- * Marker for Native Kotlin Primitives and Collections
+ * Marker for Native Kotlin types with either full or partial built-in NavType support
*/
-private enum class Native : InternalCommonType {
+private enum class InternalType {
INT,
BOOL,
FLOAT,
@@ -40,162 +39,83 @@
FLOAT_ARRAY,
LONG_ARRAY,
ARRAY,
- ARRAY_LIST,
- SET,
- HASHSET,
- MAP,
- HASH_MAP,
+ LIST,
UNKNOWN
}
/**
- * Marker for custom classes, objects, enums, and other Native Kotlin types that are not
- * included in [Native]
- */
-private data class Custom(val className: String) : InternalCommonType
-
-/**
- * Converts an argument type to a native NavType.
+ * Converts an argument type to a built-in NavType.
*
- * Native NavTypes includes NavType objects declared within [NavType.Companion], or types that are
- * either java Serializable, Parcelable, or Enum.
+ * Built-in NavTypes include NavType objects declared within [NavType.Companion], such as
+ * [NavType.IntType], [NavType.BoolArrayType] etc.
*
- * Returns [UNKNOWN] type if the argument does not belong to any of the above.
+ * Returns [UNKNOWN] type if the argument does not have built-in NavType support.
*/
-@Suppress("UNCHECKED_CAST")
-internal fun SerialDescriptor.getNavType(): NavType<Any?> {
+internal fun SerialDescriptor.getNavType(): NavType<*> {
val type = when (this.toInternalType()) {
- Native.INT -> NavType.IntType
- Native.BOOL -> NavType.BoolType
- Native.FLOAT -> NavType.FloatType
- Native.LONG -> NavType.LongType
- Native.STRING -> NavType.StringType
- Native.INT_ARRAY -> NavType.IntArrayType
- Native.BOOL_ARRAY -> NavType.BoolArrayType
- Native.FLOAT_ARRAY -> NavType.FloatArrayType
- Native.LONG_ARRAY -> NavType.LongArrayType
- Native.ARRAY -> {
+ InternalType.INT -> NavType.IntType
+ InternalType.BOOL -> NavType.BoolType
+ InternalType.FLOAT -> NavType.FloatType
+ InternalType.LONG -> NavType.LongType
+ InternalType.STRING -> NavType.StringType
+ InternalType.INT_ARRAY -> NavType.IntArrayType
+ InternalType.BOOL_ARRAY -> NavType.BoolArrayType
+ InternalType.FLOAT_ARRAY -> NavType.FloatArrayType
+ InternalType.LONG_ARRAY -> NavType.LongArrayType
+ InternalType.ARRAY -> {
val typeParameter = getElementDescriptor(0).toInternalType()
- if (typeParameter == Native.STRING) NavType.StringArrayType else UNKNOWN
+ if (typeParameter == InternalType.STRING) NavType.StringArrayType else UNKNOWN
+ }
+ InternalType.LIST -> {
+ val typeParameter = getElementDescriptor(0).toInternalType()
+ when (typeParameter) {
+ InternalType.INT -> NavType.IntListType
+ InternalType.BOOL -> NavType.BoolListType
+ InternalType.FLOAT -> NavType.FloatListType
+ InternalType.LONG -> NavType.LongListType
+ InternalType.STRING -> NavType.StringListType
+ else -> UNKNOWN
+ }
}
else -> UNKNOWN
}
- return type as NavType<Any?>
-}
-
-/**
- * Convert KType to an [InternalCommonType].
- *
- * Conversion is based on KType name. The KType could be any of the native Kotlin types that
- * are supported in [Native], or it could be a custom KType (custom class, object or enum).
- */
-private fun KType.toInternalType(): InternalCommonType {
- // first we need to parse KType name to the right format
- // extract base class without type parameters
- val typeParamRegex = Regex(pattern = "^[^<]*", options = setOf(RegexOption.IGNORE_CASE))
- val trimmedTypeParam = typeParamRegex.find(this.toString())
- // remove the warning that was appended to KType name due to missing kotlin reflect library
- val trimEndingRegex = Regex("(\\S+)")
- val trimmedEnding = trimEndingRegex.find(trimmedTypeParam!!.value)
- val finalName = trimmedEnding?.value
- // we assert the nullability directly with isNullable properties so its more reliable
- ?.replace("?", "")
- // we also replace the delimiter `$` with `.` for child classes to match the format of
- // serial names
- ?.replace("$", ".")
-
- return when (finalName) {
- null -> Native.UNKNOWN
- "int" -> Native.INT
- "java.lang.Integer" -> Native.INT
- "boolean" -> Native.BOOL
- "java.lang.Boolean" -> Native.BOOL
- "float" -> Native.FLOAT
- "java.lang.Float" -> Native.FLOAT
- "long" -> Native.LONG
- "java.lang.Long" -> Native.LONG
- "java.lang.String" -> Native.STRING
- "kotlin.IntArray" -> Native.INT_ARRAY
- "kotlin.BooleanArray" -> Native.BOOL_ARRAY
- "kotlin.FloatArray" -> Native.FLOAT_ARRAY
- "kotlin.LongArray" -> Native.LONG_ARRAY
- "kotlin.Array" -> Native.ARRAY
- "java.util.ArrayList" -> Native.ARRAY_LIST
- // KType List mapped to ArrayList because serialized name does not differentiate them
- "java.util.List" -> Native.ARRAY_LIST
- "java.util.Set" -> Native.SET
- "java.util.HashSet" -> Native.HASHSET
- "java.util.Map" -> Native.MAP
- "java.util.HashMap" -> Native.HASH_MAP
- else -> Custom(finalName)
- }
+ return type
}
/**
* Convert SerialDescriptor to an InternalCommonType.
*
- * The descriptor's associated argument could be any of the native Kotlin types that
- * are supported in [Native], or it could be a custom type (custom class, object or enum).
+ * The descriptor's associated argument could be any of the native Kotlin types supported
+ * in [InternalType], or it could be an unsupported type (custom class, object or enum).
*/
-private fun SerialDescriptor.toInternalType(): InternalCommonType {
+private fun SerialDescriptor.toInternalType(): InternalType {
val serialName = serialName.replace("?", "")
return when {
- serialName == "kotlin.Int" -> Native.INT
- serialName == "kotlin.Boolean" -> Native.BOOL
- serialName == "kotlin.Float" -> Native.FLOAT
- serialName == "kotlin.Long" -> Native.LONG
- serialName == "kotlin.String" -> Native.STRING
- serialName == "kotlin.IntArray" -> Native.INT_ARRAY
- serialName == "kotlin.BooleanArray" -> Native.BOOL_ARRAY
- serialName == "kotlin.FloatArray" -> Native.FLOAT_ARRAY
- serialName == "kotlin.LongArray" -> Native.LONG_ARRAY
- serialName == "kotlin.Array" -> Native.ARRAY
+ serialName == "kotlin.Int" -> InternalType.INT
+ serialName == "kotlin.Boolean" -> InternalType.BOOL
+ serialName == "kotlin.Float" -> InternalType.FLOAT
+ serialName == "kotlin.Long" -> InternalType.LONG
+ serialName == "kotlin.String" -> InternalType.STRING
+ serialName == "kotlin.IntArray" -> InternalType.INT_ARRAY
+ serialName == "kotlin.BooleanArray" -> InternalType.BOOL_ARRAY
+ serialName == "kotlin.FloatArray" -> InternalType.FLOAT_ARRAY
+ serialName == "kotlin.LongArray" -> InternalType.LONG_ARRAY
+ serialName == "kotlin.Array" -> InternalType.ARRAY
// serial name for both List and ArrayList
- serialName.startsWith("kotlin.collections.ArrayList") -> Native.ARRAY_LIST
- serialName.startsWith("kotlin.collections.LinkedHashSet") -> Native.SET
- serialName.startsWith("kotlin.collections.HashSet") -> Native.HASHSET
- serialName.startsWith("kotlin.collections.LinkedHashMap") -> Native.MAP
- serialName.startsWith("kotlin.collections.HashMap") -> Native.HASH_MAP
- else -> Custom(serialName)
+ serialName.startsWith("kotlin.collections.ArrayList") -> InternalType.LIST
+ // custom classes or other types without built-in NavTypes
+ else -> InternalType.UNKNOWN
}
}
/**
- * Returns true if a serialized argument type matches the given KType.
+ * Match the [SerialDescriptor] of a type to a KType
*
- * Matching starts by matching the base class of the type and then matching type parameters
- * in their declared order. Nested TypeParameters are matched recursively in the same manner.
- *
- * Limitation: For custom Types, TypeParameters are erased in serialization by default.
- * The type is preserved only if there is a class field of type T, and even then we cannot know
- * that this type is in fact the TypeParameter. Therefore, matching custom types with
- * type parameters only works under two conditions:
- *
- * 1. A class field of that type must be declared for each generic type
- * 2. These class fields must be declared in primary constructor in same order
- *
- * For example, this declaration will work:
- * `class TestClass<T: Any, K: Any>(val arg: T, val arg2: K)`
- * and these variations will not work:
- * `class TestClass<T: Any, K: Any>(val arg: K, val arg2: T)`
- * `class TestClass<T: Any, K: Any>(val other: Int, val arg: K, val arg2: T)`
- *
- * If TypeParameters of custom classes cannot be matched, the custom class will be matched to
- * a KType purely based on the class's fully qualified name and will not be able to differentiate
- * between different TypeParameters. This can lead to indeterminate matching behavior.
+ * Returns true match, false otherwise.
*/
internal fun SerialDescriptor.matchKType(kType: KType): Boolean {
if (this.isNullable != kType.isMarkedNullable) return false
- if (this.toInternalType() != kType.toInternalType()) return false
- var index = 0
- // recursive match nested TypeParameters
- while (index < elementsCount && index < kType.arguments.size) {
- val descriptor = getElementDescriptor(index)
- val childKType = kType.arguments.getOrNull(index)?.type ?: return false
- val result = descriptor.matchKType(childKType)
- if (!result) return false
- index++
- }
+ if (this.hashCode() != serializer(kType).descriptor.hashCode()) return false
return true
}
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/serialization/RouteSerializer.kt b/navigation/navigation-common/src/main/java/androidx/navigation/serialization/RouteSerializer.kt
index b18469c..38923ce 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/serialization/RouteSerializer.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/serialization/RouteSerializer.kt
@@ -58,7 +58,7 @@
val map = mutableMapOf<String, NavType<Any?>>()
for (i in 0 until descriptor.elementsCount) {
val argName = descriptor.getElementName(i)
- val type = descriptor.getElementDescriptor(i).computeNavType(typeMap)
+ val type = descriptor.getElementDescriptor(i).computeNavType(argName, typeMap)
map[argName] = type
}
val builder = if (path != null) {
@@ -110,13 +110,7 @@
navArgument(name) {
val element = descriptor.getElementDescriptor(index)
val isNullable = element.isNullable
- type = element.computeNavType(typeMap)
- if (type == UNKNOWN) {
- throw IllegalArgumentException(
- "Cannot cast $name of type ${element.serialName} to a NavType. Make sure " +
- "to provide custom NavType for this argument."
- )
- }
+ type = element.computeNavType(name, typeMap)
nullable = isNullable
if (descriptor.isElementOptional(index)) {
// Navigation mostly just cares about defaultValuePresent state for
@@ -153,12 +147,27 @@
}
}
+/**
+ * Computes and return the [NavType] based on the SerialDescriptor of a class type.
+ *
+ * Match priority:
+ * 1. Match with custom NavType provided in [typeMap]
+ * 2. Match to a built-in NavType such as [NavType.IntType], [NavType.BoolArrayType] etc.
+ */
@Suppress("UNCHECKED_CAST")
private fun SerialDescriptor.computeNavType(
+ name: String,
typeMap: Map<KType, NavType<*>>
): NavType<Any?> {
val customType = typeMap.keys
.find { kType -> matchKType(kType) }
?.let { typeMap[it] } as? NavType<Any?>
- return customType ?: getNavType()
+ val result = customType ?: getNavType()
+ if (result == UNKNOWN) {
+ throw IllegalArgumentException(
+ "Cannot cast $name of type $serialName to a NavType. Make sure " +
+ "to provide custom NavType for this argument."
+ )
+ }
+ return result as NavType<Any?>
}
diff --git a/navigation/navigation-common/src/test/java/androidx/navigation/serialization/NavArgumentGeneratorTest.kt b/navigation/navigation-common/src/test/java/androidx/navigation/serialization/NavArgumentGeneratorTest.kt
index 391d320..c0c9214 100644
--- a/navigation/navigation-common/src/test/java/androidx/navigation/serialization/NavArgumentGeneratorTest.kt
+++ b/navigation/navigation-common/src/test/java/androidx/navigation/serialization/NavArgumentGeneratorTest.kt
@@ -183,6 +183,45 @@
}
@Test
+ fun convertToIntList() {
+ @Serializable class TestClass(val arg: List<Int>)
+
+ val converted = serializer<TestClass>().generateNavArguments()
+ val expected = navArgument("arg") {
+ type = NavType.IntListType
+ nullable = false
+ }
+ assertThat(converted).containsExactlyInOrder(expected)
+ assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+ }
+
+ @Test
+ fun convertArrayListToIntList() {
+ @Serializable class TestClass(val arg: ArrayList<Int>)
+
+ val converted = serializer<TestClass>().generateNavArguments()
+ val expected = navArgument("arg") {
+ type = NavType.IntListType
+ nullable = false
+ }
+ assertThat(converted).containsExactlyInOrder(expected)
+ assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+ }
+
+ @Test
+ fun convertToIntListNullable() {
+ @Serializable class TestClass(val arg: List<Int>?)
+
+ val converted = serializer<TestClass>().generateNavArguments()
+ val expected = navArgument("arg") {
+ type = NavType.IntListType
+ nullable = true
+ }
+ assertThat(converted).containsExactlyInOrder(expected)
+ assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+ }
+
+ @Test
fun convertToLongArray() {
@Serializable class TestClass(val arg: LongArray)
@@ -209,6 +248,45 @@
}
@Test
+ fun convertToLongList() {
+ @Serializable class TestClass(val arg: List<Long>)
+
+ val converted = serializer<TestClass>().generateNavArguments()
+ val expected = navArgument("arg") {
+ type = NavType.LongListType
+ nullable = false
+ }
+ assertThat(converted).containsExactlyInOrder(expected)
+ assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+ }
+
+ @Test
+ fun convertArrayListToLongList() {
+ @Serializable class TestClass(val arg: ArrayList<Long>)
+
+ val converted = serializer<TestClass>().generateNavArguments()
+ val expected = navArgument("arg") {
+ type = NavType.LongListType
+ nullable = false
+ }
+ assertThat(converted).containsExactlyInOrder(expected)
+ assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+ }
+
+ @Test
+ fun convertToLongListNullable() {
+ @Serializable class TestClass(val arg: List<Long>?)
+
+ val converted = serializer<TestClass>().generateNavArguments()
+ val expected = navArgument("arg") {
+ type = NavType.LongListType
+ nullable = true
+ }
+ assertThat(converted).containsExactlyInOrder(expected)
+ assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+ }
+
+ @Test
fun convertToFloatArray() {
@Serializable class TestClass(val arg: FloatArray)
@@ -235,6 +313,45 @@
}
@Test
+ fun convertToFloatList() {
+ @Serializable class TestClass(val arg: List<Float>)
+
+ val converted = serializer<TestClass>().generateNavArguments()
+ val expected = navArgument("arg") {
+ type = NavType.FloatListType
+ nullable = false
+ }
+ assertThat(converted).containsExactlyInOrder(expected)
+ assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+ }
+
+ @Test
+ fun convertArrayListToFloatList() {
+ @Serializable class TestClass(val arg: ArrayList<Float>)
+
+ val converted = serializer<TestClass>().generateNavArguments()
+ val expected = navArgument("arg") {
+ type = NavType.FloatListType
+ nullable = false
+ }
+ assertThat(converted).containsExactlyInOrder(expected)
+ assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+ }
+
+ @Test
+ fun convertToFloatListNullable() {
+ @Serializable class TestClass(val arg: List<Float>?)
+
+ val converted = serializer<TestClass>().generateNavArguments()
+ val expected = navArgument("arg") {
+ type = NavType.FloatListType
+ nullable = true
+ }
+ assertThat(converted).containsExactlyInOrder(expected)
+ assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+ }
+
+ @Test
fun convertToBoolArray() {
@Serializable class TestClass(val arg: BooleanArray)
@@ -261,6 +378,45 @@
}
@Test
+ fun convertToBooleanList() {
+ @Serializable class TestClass(val arg: List<Boolean>)
+
+ val converted = serializer<TestClass>().generateNavArguments()
+ val expected = navArgument("arg") {
+ type = NavType.BoolListType
+ nullable = false
+ }
+ assertThat(converted).containsExactlyInOrder(expected)
+ assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+ }
+
+ @Test
+ fun convertArrayListToBooleanList() {
+ @Serializable class TestClass(val arg: ArrayList<Boolean>)
+
+ val converted = serializer<TestClass>().generateNavArguments()
+ val expected = navArgument("arg") {
+ type = NavType.BoolListType
+ nullable = false
+ }
+ assertThat(converted).containsExactlyInOrder(expected)
+ assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+ }
+
+ @Test
+ fun convertToBooleanListNullable() {
+ @Serializable class TestClass(val arg: List<Boolean>?)
+
+ val converted = serializer<TestClass>().generateNavArguments()
+ val expected = navArgument("arg") {
+ type = NavType.BoolListType
+ nullable = true
+ }
+ assertThat(converted).containsExactlyInOrder(expected)
+ assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+ }
+
+ @Test
fun convertToStringArray() {
@Serializable class TestClass(val arg: Array<String>)
@@ -287,6 +443,45 @@
}
@Test
+ fun convertToStringList() {
+ @Serializable class TestClass(val arg: List<String>)
+
+ val converted = serializer<TestClass>().generateNavArguments()
+ val expected = navArgument("arg") {
+ type = NavType.StringListType
+ nullable = false
+ }
+ assertThat(converted).containsExactlyInOrder(expected)
+ assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+ }
+
+ @Test
+ fun convertArrayListToStringList() {
+ @Serializable class TestClass(val arg: ArrayList<String>)
+
+ val converted = serializer<TestClass>().generateNavArguments()
+ val expected = navArgument("arg") {
+ type = NavType.StringListType
+ nullable = false
+ }
+ assertThat(converted).containsExactlyInOrder(expected)
+ assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+ }
+
+ @Test
+ fun convertToStringListNullable() {
+ @Serializable class TestClass(val arg: List<String>?)
+
+ val converted = serializer<TestClass>().generateNavArguments()
+ val expected = navArgument("arg") {
+ type = NavType.StringListType
+ nullable = true
+ }
+ assertThat(converted).containsExactlyInOrder(expected)
+ assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+ }
+
+ @Test
fun convertToParcelable() {
@Serializable
class TestParcelable : Parcelable {
@@ -599,14 +794,14 @@
@Test
fun convertIllegalCustomType() {
- @Serializable class TestClass(val arg: ArrayList<String>)
+ @Serializable class TestClass(val arg: Set<String>)
val exception = assertFailsWith<IllegalArgumentException> {
serializer<TestClass>().generateNavArguments()
}
assertThat(exception.message).isEqualTo(
- "Cannot cast arg of type kotlin.collections.ArrayList to a NavType. " +
+ "Cannot cast arg of type kotlin.collections.LinkedHashSet to a NavType. " +
"Make sure to provide custom NavType for this argument."
)
}
diff --git a/navigation/navigation-common/src/test/java/androidx/navigation/serialization/NavTypeConverterTest.kt b/navigation/navigation-common/src/test/java/androidx/navigation/serialization/NavTypeConverterTest.kt
index ec47b98..dba8173 100644
--- a/navigation/navigation-common/src/test/java/androidx/navigation/serialization/NavTypeConverterTest.kt
+++ b/navigation/navigation-common/src/test/java/androidx/navigation/serialization/NavTypeConverterTest.kt
@@ -22,8 +22,8 @@
import com.google.common.truth.Truth.assertThat
import kotlin.reflect.typeOf
import kotlin.test.Test
-import kotlin.test.assertFails
import kotlinx.serialization.Serializable
+import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.serializer
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -376,21 +376,21 @@
}
@Test
- fun matchWrongTypeParameter() {
+ fun matchWrongTypeParam() {
val descriptor = serializer<Set<Int>>().descriptor
val kType = typeOf<Set<Boolean>>()
assertThat(descriptor.matchKType(kType)).isFalse()
}
@Test
- fun matchWrongOrderTypeParameter() {
+ fun matchWrongOrderTypeParam() {
val descriptor = serializer<Map<String, Int>>().descriptor
val kType = typeOf<Map<Int, String>>()
assertThat(descriptor.matchKType(kType)).isFalse()
}
@Test
- fun matchNestedTypeParameter() {
+ fun matchNestedTypeParam() {
val descriptor = serializer<List<List<Int>>>().descriptor
val kType = typeOf<List<List<Int>>>()
assertThat(descriptor.matchKType(kType)).isTrue()
@@ -400,7 +400,7 @@
}
@Test
- fun matchMultiNestedTypeParameter() {
+ fun matchMultiNestedTypeParam() {
val descriptor = serializer<Map<List<Int>, Set<Boolean>>>().descriptor
val kType = typeOf<Map<List<Int>, Set<Boolean>>>()
assertThat(descriptor.matchKType(kType)).isTrue()
@@ -410,14 +410,14 @@
}
@Test
- fun matchThriceNestedTypeParameter() {
+ fun matchThriceNestedTypeParam() {
val descriptor = serializer<List<Set<List<Boolean>>>>().descriptor
val kType = typeOf<List<Set<List<Boolean>>>>()
assertThat(descriptor.matchKType(kType)).isTrue()
}
@Test
- fun matchNativeClassWithCustomTypeParameter() {
+ fun matchNativeTypeCustomTypeParam() {
@Serializable
class TestClass(val arg: Int, val arg2: String)
@@ -427,7 +427,14 @@
}
@Test
- fun matchNativeClassWithNestedCustomTypeParameter() {
+ fun matchNativeTypeCustomTypeParamCustomSerializer() {
+ val descriptor = serializer<List<CustomSerializerClass>>().descriptor
+ val kType = typeOf<List<CustomSerializerClass>>()
+ assertThat(descriptor.matchKType(kType)).isTrue()
+ }
+
+ @Test
+ fun matchNativeTypeCustomTypeParamNested() {
@Serializable
open class Nested(val arg: Int)
@@ -440,7 +447,17 @@
}
@Test
- fun matchCustomClass() {
+ fun matchNativeTypeCustomTypeParamNestedCustomSerializer() {
+ @Serializable
+ class TestClass<T : CustomSerializerClass>(val arg: Int)
+
+ val descriptor = serializer<List<TestClass<CustomSerializerClass>>>().descriptor
+ val kType = typeOf<List<TestClass<CustomSerializerClass>>>()
+ assertThat(descriptor.matchKType(kType)).isTrue()
+ }
+
+ @Test
+ fun matchCustomType() {
@Serializable
class TestClass(val arg: Int, val arg2: String)
@@ -464,45 +481,142 @@
}
@Test
- fun matchCustomClassTypeParameterWithSingleArg() {
+ fun matchCustomTypeNativeTypeParam() {
@Serializable
- class TestClass<T : Any>(val arg: T)
+ class TestClass<T : SerialDescriptor>
- val descriptor = serializer<TestClass<String>>().descriptor
- val kType = typeOf<TestClass<String>>()
+ val descriptor = serializer<TestClass<SerialDescriptor>>().descriptor
+ val kType = typeOf<TestClass<SerialDescriptor>>()
assertThat(descriptor.matchKType(kType)).isTrue()
-
- val descriptor2 = serializer<TestClass<Int>>().descriptor
- assertThat(descriptor2.matchKType(kType)).isFalse()
}
@Test
- fun matchCustomClassTypeParameterWithMultipleArg() {
+ fun matchCustomTypeArgNativeTypeParam() {
@Serializable
- class TestClass<T : Any, K : Any>(val arg: T, val arg2: K, val arg3: Int)
+ class TestClass<T : SerialDescriptor>(val arg: Int)
- val descriptor = serializer<TestClass<String, Int>>().descriptor
- val kType = typeOf<TestClass<String, Int>>()
+ val descriptor = serializer<TestClass<SerialDescriptor>>().descriptor
+ val kType = typeOf<TestClass<SerialDescriptor>>()
assertThat(descriptor.matchKType(kType)).isTrue()
-
- val descriptor2 = serializer<TestClass<Int, String>>().descriptor
- assertThat(descriptor2.matchKType(kType)).isFalse()
}
@Test
- fun matchCustomClassTypeParameterWithNoArgFails() {
+ fun matchCustomTypeCustomArgNativeTypeParam() {
+ @Serializable
+ class MyArg(val name: String)
+
+ @Serializable
+ class TestClass<T : SerialDescriptor>(val arg: MyArg)
+
+ val descriptor = serializer<TestClass<SerialDescriptor>>().descriptor
+ val kType = typeOf<TestClass<SerialDescriptor>>()
+ assertThat(descriptor.matchKType(kType)).isTrue()
+ }
+
+ @Test
+ fun matchCustomTypeMultiArgNativeTypeParam() {
+ @Serializable
+ class MyArg(val name: String)
+
+ @Serializable
+ class TestClass<T : SerialDescriptor>(val arg: Int, val arg2: MyArg)
+
+ val descriptor = serializer<TestClass<SerialDescriptor>>().descriptor
+ val kType = typeOf<TestClass<SerialDescriptor>>()
+ assertThat(descriptor.matchKType(kType)).isTrue()
+ }
+
+ @Test
+ fun matchCustomTypeNativeTypeParamMismatch() {
@Serializable
class TestClass<T : Any>
val descriptor = serializer<TestClass<Int>>().descriptor
val kType = typeOf<TestClass<String>>()
- // type T is erased in serialization so we cannot differentiate between Int/String
val isMatch = descriptor.matchKType(kType)
- val result = assertFails {
- assertThat(isMatch).isFalse()
- }
- assertThat(result.message).isEqualTo("expected to be false")
+ assertThat(isMatch).isFalse()
+ }
+
+ @Test
+ fun matchCustomTypeCustomTypeParam() {
+ @Serializable
+ open class Param
+
+ @Serializable
+ class TestClass<T : Param>
+
+ val descriptor = serializer<TestClass<Param>>().descriptor
+ val kType = typeOf<TestClass<Param>>()
+
+ val isMatch = descriptor.matchKType(kType)
+ assertThat(isMatch).isTrue()
+ }
+
+ @Test
+ fun matchCustomTypeCustomTypeParamCustomSerializer() {
+ @Serializable
+ class TestClass<T : CustomSerializerClass>
+
+ val descriptor = serializer<TestClass<CustomSerializerClass>>().descriptor
+ val kType = typeOf<TestClass<CustomSerializerClass>>()
+
+ val isMatch = descriptor.matchKType(kType)
+ assertThat(isMatch).isTrue()
+ }
+
+ @Test
+ fun matchCustomTypeMultiCustomTypeParam() {
+ @Serializable
+ open class ParamTwo
+
+ @Serializable
+ open class Param
+
+ @Serializable
+ class TestClass<T : Param, K : ParamTwo>
+
+ val descriptor = serializer<TestClass<Param, ParamTwo>>().descriptor
+ val kType = typeOf<TestClass<Param, ParamTwo>>()
+
+ val isMatch = descriptor.matchKType(kType)
+ assertThat(isMatch).isTrue()
+ }
+
+ @Test
+ fun matchCustomTypeCustomTypeParamNested() {
+ @Serializable
+ class TestClass<T : Param>
+
+ val descriptor = serializer<TestClass<ParamDerived>>().descriptor
+ val kType = typeOf<TestClass<ParamDerived>>()
+
+ val isMatch = descriptor.matchKType(kType)
+ assertThat(isMatch).isTrue()
+ }
+
+ @Test
+ fun matchCustomTypeMultiCustomTypeParamNested() {
+ @Serializable
+ class TestClass<T : Param, K : Param>
+
+ val descriptor = serializer<TestClass<ParamDerived, ParamDerivedTwo>>().descriptor
+ val kType = typeOf<TestClass<ParamDerived, ParamDerivedTwo>>()
+
+ val isMatch = descriptor.matchKType(kType)
+ assertThat(isMatch).isTrue()
+ }
+
+ @Test
+ fun matchCustomTypeCustomTypeParamNestedMismatch() {
+ @Serializable
+ class TestClass<T : Param>
+
+ val descriptor = serializer<TestClass<ParamDerived>>().descriptor
+ val kType = typeOf<TestClass<ParamDerivedTwo>>()
+
+ val isMatch = descriptor.matchKType(kType)
+ assertThat(isMatch).isFalse()
}
@Test
@@ -635,6 +749,15 @@
}
@Serializable
+ class ParamDerivedTwo : Param()
+
+ @Serializable
+ class ParamDerived : Param()
+
+ @Serializable
+ open class Param
+
+ @Serializable
class TestParcelable(val arg: Int, val arg2: String) : Parcelable {
override fun describeContents() = 0
override fun writeToParcel(dest: Parcel, flags: Int) { }
diff --git a/navigation/navigation-common/src/test/java/androidx/navigation/serialization/RoutePatternTest.kt b/navigation/navigation-common/src/test/java/androidx/navigation/serialization/RoutePatternTest.kt
index 92a5b66..dee4366 100644
--- a/navigation/navigation-common/src/test/java/androidx/navigation/serialization/RoutePatternTest.kt
+++ b/navigation/navigation-common/src/test/java/androidx/navigation/serialization/RoutePatternTest.kt
@@ -16,7 +16,12 @@
package androidx.navigation.serialization
+import android.os.Bundle
+import androidx.navigation.CollectionNavType
+import androidx.navigation.NavType
import com.google.common.truth.Truth.assertThat
+import kotlin.reflect.KType
+import kotlin.reflect.typeOf
import kotlin.test.assertFailsWith
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
@@ -250,7 +255,16 @@
@SerialName(PATH_SERIAL_NAME)
class TestClass(val custom: CustomType)
- assertThatRoutePatternFrom(serializer<TestClass>()).isEqualTo(
+ val type = object : NavType<CustomType>(false) {
+ override val name: String
+ get() = "CustomType"
+ override fun put(bundle: Bundle, key: String, value: CustomType) { }
+ override fun get(bundle: Bundle, key: String): CustomType? = null
+ override fun parseValue(value: String): CustomType = CustomType()
+ override fun serializeAsValue(value: CustomType) = "customValue"
+ }
+ val map = mapOf(typeOf<CustomType>() to type)
+ assertThatRoutePatternFrom(serializer<TestClass>(), map).isEqualTo(
"$PATH_SERIAL_NAME/{custom}"
)
}
@@ -267,7 +281,16 @@
@SerialName(PATH_SERIAL_NAME)
class TestClass(val custom: CustomType)
- assertThatRoutePatternFrom(serializer<TestClass>()).isEqualTo(
+ val type = object : NavType<CustomType>(false) {
+ override val name: String
+ get() = "CustomType"
+ override fun put(bundle: Bundle, key: String, value: CustomType) { }
+ override fun get(bundle: Bundle, key: String): CustomType? = null
+ override fun parseValue(value: String): CustomType = CustomType(NestedCustomType())
+ override fun serializeAsValue(value: CustomType) = "customValue"
+ }
+ val map = mapOf(typeOf<CustomType>() to type)
+ assertThatRoutePatternFrom(serializer<TestClass>(), map).isEqualTo(
"$PATH_SERIAL_NAME/{custom}"
)
}
@@ -276,19 +299,81 @@
fun customSerializerParamType() {
@Serializable
@SerialName(PATH_SERIAL_NAME)
- class TestClass(
- val arg: Int,
- @Serializable(with = CustomSerializer::class)
- val arg2: NonSerializedClass
- )
+ class TestClass(val arg: Int, val arg2: CustomSerializerClass)
- // args will be duplicated
- assertThatRoutePatternFrom(serializer<TestClass>()).isEqualTo(
+ val type = object : NavType<CustomSerializerClass>(false) {
+ override val name: String
+ get() = "CustomType"
+ override fun put(bundle: Bundle, key: String, value: CustomSerializerClass) { }
+ override fun get(bundle: Bundle, key: String): CustomSerializerClass? = null
+ override fun parseValue(value: String): CustomSerializerClass =
+ CustomSerializerClass(1L)
+ override fun serializeAsValue(value: CustomSerializerClass) = "customValue"
+ }
+ val map = mapOf(typeOf<CustomSerializerClass>() to type)
+ assertThatRoutePatternFrom(serializer<TestClass>(), map).isEqualTo(
"$PATH_SERIAL_NAME/{arg}/{arg2}"
)
}
@Test
+ fun customTypeParam() {
+ @Serializable
+ open class TypeParam
+ @Serializable
+ class CustomType<T : TypeParam>
+ @Serializable
+ @SerialName(PATH_SERIAL_NAME)
+ class TestClass(val custom: CustomType<TypeParam>)
+
+ val type = object : NavType<CustomType<TypeParam>>(false) {
+ override val name: String
+ get() = "CustomType"
+ override fun put(bundle: Bundle, key: String, value: CustomType<TypeParam>) { }
+ override fun get(bundle: Bundle, key: String): CustomType<TypeParam>? = null
+ override fun parseValue(value: String): CustomType<TypeParam> = CustomType()
+ override fun serializeAsValue(value: CustomType<TypeParam>) = "customValue"
+ }
+ val map = mapOf(typeOf<CustomType<TypeParam>>() to type)
+ assertThatRoutePatternFrom(serializer<TestClass>(), map).isEqualTo(
+ "$PATH_SERIAL_NAME/{custom}"
+ )
+ }
+
+ @Test
+ fun customTypeParamNested() {
+ @Serializable
+ open class TypeParamNested
+ @Serializable
+ open class TypeParam<K : TypeParamNested>
+ @Serializable
+ class CustomType<T : TypeParam<TypeParamNested>>
+ @Serializable
+ @SerialName(PATH_SERIAL_NAME)
+ class TestClass(val custom: CustomType<TypeParam<TypeParamNested>>)
+
+ val type = object : NavType<CustomType<TypeParam<TypeParamNested>>>(false) {
+ override val name: String
+ get() = "CustomType"
+ override fun put(
+ bundle: Bundle,
+ key: String,
+ value: CustomType<TypeParam<TypeParamNested>>
+ ) { }
+ override fun get(bundle: Bundle, key: String): CustomType<TypeParam<TypeParamNested>>? =
+ null
+ override fun parseValue(value: String): CustomType<TypeParam<TypeParamNested>> =
+ CustomType()
+ override fun serializeAsValue(value: CustomType<TypeParam<TypeParamNested>>) =
+ "customValue"
+ }
+ val map = mapOf(typeOf<CustomType<TypeParam<TypeParamNested>>>() to type)
+ assertThatRoutePatternFrom(serializer<TestClass>(), map).isEqualTo(
+ "$PATH_SERIAL_NAME/{custom}"
+ )
+ }
+
+ @Test
fun paramWithNoBackingField() {
@Serializable
@SerialName(PATH_SERIAL_NAME)
@@ -326,7 +411,16 @@
lateinit var arg: CustomType
}
- assertThatRoutePatternFrom(serializer<TestClass>()).isEqualTo(
+ val type = object : NavType<CustomType>(false) {
+ override val name: String
+ get() = "CustomType"
+ override fun put(bundle: Bundle, key: String, value: CustomType) { }
+ override fun get(bundle: Bundle, key: String): CustomType? = null
+ override fun parseValue(value: String): CustomType = CustomType()
+ override fun serializeAsValue(value: CustomType) = "customValue"
+ }
+ val map = mapOf(typeOf<CustomType>() to type)
+ assertThatRoutePatternFrom(serializer<TestClass>(), map).isEqualTo(
"$PATH_SERIAL_NAME/{arg}"
)
}
@@ -419,10 +513,34 @@
PATH_SERIAL_NAME
)
}
+
+ @Test
+ fun collectionNavType() {
+ @Serializable
+ class CustomType
+
+ @Serializable
+ @SerialName(PATH_SERIAL_NAME)
+ class TestClass(val list: List<CustomType>)
+
+ val type = object : CollectionNavType<List<CustomType>>(false) {
+ override fun put(bundle: Bundle, key: String, value: List<CustomType>) { }
+ override fun serializeAsValues(value: List<CustomType>): List<String> = emptyList()
+ override fun get(bundle: Bundle, key: String): List<CustomType>? = null
+ override fun parseValue(value: String): List<CustomType> = listOf()
+ override fun serializeAsValue(value: List<CustomType>) = "customValue"
+ }
+ val map = mapOf(typeOf<List<CustomType>>() to type)
+ assertThatRoutePatternFrom(serializer<TestClass>(), map).isEqualTo(
+ "$PATH_SERIAL_NAME?list={list}"
+ )
+ }
}
-private fun <T> assertThatRoutePatternFrom(serializer: KSerializer<T>) =
- serializer.generateRoutePattern()
+private fun <T> assertThatRoutePatternFrom(
+ serializer: KSerializer<T>,
+ map: Map<KType, NavType<*>> = emptyMap()
+) = serializer.generateRoutePattern(map)
private fun String.isEqualTo(other: String) {
assertThat(this).isEqualTo(other)
@@ -465,16 +583,17 @@
}
}
-private class NonSerializedClass(val longArg: Long)
+@Serializable(with = CustomSerializer::class)
+internal open class CustomSerializerClass(val longArg: Long)
-private class CustomSerializer : KSerializer<NonSerializedClass> {
+internal class CustomSerializer : KSerializer<CustomSerializerClass> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(
"Date", PrimitiveKind.LONG
)
- override fun serialize(encoder: Encoder, value: NonSerializedClass) =
+ override fun serialize(encoder: Encoder, value: CustomSerializerClass) =
encoder.encodeLong(value.longArg)
- override fun deserialize(decoder: Decoder): NonSerializedClass =
- NonSerializedClass(decoder.decodeLong())
+ override fun deserialize(decoder: Decoder): CustomSerializerClass =
+ CustomSerializerClass(decoder.decodeLong())
}
private interface TestInterface
diff --git a/navigation/navigation-fragment-compose/api/current.txt b/navigation/navigation-fragment-compose/api/current.txt
index fc044e2..d598ace 100644
--- a/navigation/navigation-fragment-compose/api/current.txt
+++ b/navigation/navigation-fragment-compose/api/current.txt
@@ -28,5 +28,10 @@
method public androidx.navigation.fragment.compose.ComposableNavHostFragment create(@NavigationRes int graphResId, optional android.os.Bundle? startDestinationArgs);
}
+ public final class LocalFragmentKt {
+ method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.fragment.app.Fragment> getLocalFragment();
+ property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.fragment.app.Fragment> LocalFragment;
+ }
+
}
diff --git a/navigation/navigation-fragment-compose/api/restricted_current.txt b/navigation/navigation-fragment-compose/api/restricted_current.txt
index fc044e2..d598ace 100644
--- a/navigation/navigation-fragment-compose/api/restricted_current.txt
+++ b/navigation/navigation-fragment-compose/api/restricted_current.txt
@@ -28,5 +28,10 @@
method public androidx.navigation.fragment.compose.ComposableNavHostFragment create(@NavigationRes int graphResId, optional android.os.Bundle? startDestinationArgs);
}
+ public final class LocalFragmentKt {
+ method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.fragment.app.Fragment> getLocalFragment();
+ property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.fragment.app.Fragment> LocalFragment;
+ }
+
}
diff --git a/navigation/navigation-fragment-compose/src/androidTest/java/androidx/navigation/fragment/compose/ComposableFragmentTest.kt b/navigation/navigation-fragment-compose/src/androidTest/java/androidx/navigation/fragment/compose/ComposableFragmentTest.kt
index 7955fe4..a122a75 100644
--- a/navigation/navigation-fragment-compose/src/androidTest/java/androidx/navigation/fragment/compose/ComposableFragmentTest.kt
+++ b/navigation/navigation-fragment-compose/src/androidTest/java/androidx/navigation/fragment/compose/ComposableFragmentTest.kt
@@ -54,6 +54,25 @@
testRule.onNodeWithText("ComposableFragment").assertIsDisplayed()
}
+
+ @Test
+ fun showContentWithArgs() {
+ val composableFragment = ComposableFragment(
+ "androidx.navigation.fragment.compose.ComposableFragmentTestKt\$ContentWithArgs"
+ ).apply {
+ requireArguments().putString("test", "argument")
+ }
+ val fragmentManager = testRule.activity.supportFragmentManager
+ testRule.runOnUiThread {
+ fragmentManager.commitNow {
+ add(R.id.fragment_container, composableFragment)
+ }
+ }
+
+ testRule.waitForIdle()
+
+ testRule.onNodeWithText("ComposableFragment: argument").assertIsDisplayed()
+ }
}
@Suppress("TestFunctionName")
@@ -61,3 +80,11 @@
fun Content() {
Text("ComposableFragment")
}
+
+@Suppress("TestFunctionName")
+@Composable
+fun ContentWithArgs() {
+ val args = LocalFragment.current.requireArguments()
+ val testArgument = args.getString("test")
+ Text("ComposableFragment: $testArgument")
+}
diff --git a/navigation/navigation-fragment-compose/src/main/java/androidx/navigation/fragment/compose/ComposableFragment.kt b/navigation/navigation-fragment-compose/src/main/java/androidx/navigation/fragment/compose/ComposableFragment.kt
index 79a452f..4e616cd 100644
--- a/navigation/navigation-fragment-compose/src/main/java/androidx/navigation/fragment/compose/ComposableFragment.kt
+++ b/navigation/navigation-fragment-compose/src/main/java/androidx/navigation/fragment/compose/ComposableFragment.kt
@@ -20,6 +20,7 @@
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.currentComposer
import androidx.compose.runtime.reflect.getDeclaredComposableMethod
import androidx.compose.ui.platform.ComposeView
@@ -29,7 +30,8 @@
/**
* This class provides a [Fragment] wrapper around a composable function that is loaded via
- * reflection.
+ * reflection. The composable function has access to this fragment instance via
+ * [LocalFragment].
*
* This class is constructed via a factory method: make sure you add
* `import androidx.navigation.fragment.compose.ComposableFragment.Companion.ComposableFragment`
@@ -56,7 +58,9 @@
return ComposeView(requireContext()).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
- composableMethod.invoke(currentComposer, null)
+ CompositionLocalProvider(LocalFragment provides this@ComposableFragment) {
+ composableMethod.invoke(currentComposer, null)
+ }
}
}
}
diff --git a/navigation/navigation-fragment-compose/src/main/java/androidx/navigation/fragment/compose/LocalFragment.kt b/navigation/navigation-fragment-compose/src/main/java/androidx/navigation/fragment/compose/LocalFragment.kt
new file mode 100644
index 0000000..de9543e
--- /dev/null
+++ b/navigation/navigation-fragment-compose/src/main/java/androidx/navigation/fragment/compose/LocalFragment.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2024 The Android Open 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.navigation.fragment.compose
+
+import androidx.compose.runtime.staticCompositionLocalOf
+import androidx.fragment.app.Fragment
+
+/**
+ * The CompositionLocal containing the containing [Fragment]. This is sett by default for
+ * composables created within a [ComposableFragment].
+ */
+val LocalFragment = staticCompositionLocalOf<Fragment> {
+ error("CompositionLocal Fragment not present: are you sure your composable is within a " +
+ "navigation-fragment-compose provided ComposableFragment?")
+}
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerRouteTest.kt b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerRouteTest.kt
index 5ce5551..31d714e 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerRouteTest.kt
+++ b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerRouteTest.kt
@@ -54,6 +54,7 @@
import com.google.common.truth.Truth.assertWithMessage
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
+import kotlin.reflect.typeOf
import kotlin.test.assertFailsWith
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@@ -261,7 +262,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = TestClass::class) {
- test(route = TestClass::class)
+ test<TestClass>()
}
assertThat(navController.currentDestination?.route).isEqualTo("test")
assertThat(navController.currentDestination?.id).isEqualTo(
@@ -278,7 +279,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = TestClass::class) {
- test(route = TestClass::class)
+ test<TestClass>()
}
assertThat(navController.currentDestination?.route).isEqualTo("test/{arg}")
assertThat(navController.currentDestination?.id).isEqualTo(
@@ -301,7 +302,7 @@
startDestination = NestedGraph::class
) {
navigation<NestedGraph>(startDestination = TestClass::class) {
- test(route = TestClass::class)
+ test<TestClass>()
}
}
assertThat(navController.currentDestination?.route).isEqualTo("test")
@@ -319,7 +320,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = TestClass()) {
- test(route = TestClass::class)
+ test<TestClass>()
}
assertThat(navController.currentDestination?.route).isEqualTo("test")
assertThat(navController.currentDestination?.id).isEqualTo(
@@ -338,7 +339,7 @@
navController.graph = navController.createGraph(
startDestination = TestClass(0)
) {
- test(route = TestClass::class)
+ test<TestClass>()
}
assertThat(navController.currentDestination?.route).isEqualTo(
"test/{arg}"
@@ -362,7 +363,7 @@
navController.graph = navController.createGraph(
startDestination = TestClass(false)
) {
- test(route = TestClass::class)
+ test<TestClass>()
}
assertThat(navController.currentDestination?.route).isEqualTo(
"test?arg={arg}"
@@ -467,7 +468,7 @@
startDestination = NestedGraph(0)
) {
navigation<NestedGraph>(startDestination = TestClass(1)) {
- test(route = TestClass::class)
+ test<TestClass>()
}
}
assertThat(navController.currentDestination?.route).isEqualTo(
@@ -710,7 +711,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = "start") {
test("start")
- test(TestClass::class)
+ test<TestClass>()
}
assertThat(navController.currentDestination?.route).isEqualTo("start")
assertThat(navController.currentBackStack.value.size).isEqualTo(2)
@@ -726,7 +727,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = "start") {
test("start")
- test(TestClassPathArg::class)
+ test<TestClassPathArg>()
}
assertThat(navController.currentDestination?.route).isEqualTo("start")
assertThat(navController.currentBackStack.value.size).isEqualTo(2)
@@ -747,7 +748,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = "start") {
test("start")
- test(TestClass::class)
+ test<TestClass>()
}
assertThat(navController.currentDestination?.route).isEqualTo("start")
assertThat(navController.currentBackStack.value.size).isEqualTo(2)
@@ -771,7 +772,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = "start") {
test("start")
- test(TestClass::class)
+ test<TestClass>()
}
assertThat(navController.currentDestination?.route).isEqualTo("start")
assertThat(navController.currentBackStack.value.size).isEqualTo(2)
@@ -790,6 +791,56 @@
@UiThreadTest
@Test
+ fun testNavigateWithObjectCollectionNavType() {
+ val navController = createNavController()
+ @Serializable
+ data class CustomType(val id: Int)
+ @Serializable
+ class TestClass(val list: List<CustomType>)
+
+ val collectionNavType = object : CollectionNavType<List<CustomType>>(false) {
+ override fun put(bundle: Bundle, key: String, value: List<CustomType>) {
+ val array = value.map { it.id }.toIntArray()
+ bundle.putIntArray(key, array)
+ }
+ override fun serializeAsValues(value: List<CustomType>) = value.map { it.id.toString() }
+ override fun get(bundle: Bundle, key: String): List<CustomType> {
+ return bundle.getIntArray(key)!!.map { CustomType(it) }
+ }
+ override fun parseValue(value: String) = listOf(CustomType(value.toInt()))
+ override fun parseValue(
+ value: String,
+ previousValue: List<CustomType>
+ ): List<CustomType> {
+ val list = mutableListOf<CustomType>()
+ list.addAll(previousValue)
+ list.add(CustomType(value.toInt()))
+ return list
+ }
+ }
+
+ navController.graph = navController.createGraph(startDestination = "start") {
+ test("start")
+ test<TestClass>(mapOf(typeOf<List<CustomType>>() to collectionNavType))
+ }
+
+ assertThat(navController.currentDestination?.route).isEqualTo("start")
+ assertThat(navController.currentBackStack.value.size).isEqualTo(2)
+
+ val list = listOf(CustomType(1), CustomType(3), CustomType(5))
+ navController.navigate(TestClass(list))
+ assertThat(navController.currentDestination?.route).isEqualTo(
+ "androidx.navigation.NavControllerRouteTest." +
+ "testNavigateWithObjectCollectionNavType.TestClass?list={list}"
+ )
+ assertThat(navController.currentBackStack.value.size).isEqualTo(3)
+ assertThat(
+ navController.currentBackStackEntry!!.toRoute<TestClass>().list
+ ).containsExactlyElementsIn(list).inOrder()
+ }
+
+ @UiThreadTest
+ @Test
fun testNavigateWithObjectInvalidObject() {
@Serializable
class WrongTestClass
@@ -797,7 +848,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = "start") {
test("start")
- test(TestClass::class)
+ test<TestClass>()
}
assertThat(navController.currentDestination?.route).isEqualTo("start")
assertThat(navController.currentBackStack.value.size).isEqualTo(2)
@@ -813,7 +864,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = "start") {
test("start")
- test(TestClass::class)
+ test<TestClass>()
}
assertThat(navController.currentDestination?.route).isEqualTo("start")
assertThat(navController.currentBackStack.value.size).isEqualTo(2)
@@ -831,7 +882,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = "start") {
test("start")
- test(TestClassPathArg::class)
+ test<TestClassPathArg>()
}
assertThat(navController.currentDestination?.route).isEqualTo("start")
assertThat(navController.currentBackStack.value.size).isEqualTo(2)
@@ -862,7 +913,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = "start") {
test("start")
- test(TestClassPathArg::class)
+ test<TestClassPathArg>()
}
assertThat(navController.currentDestination?.route).isEqualTo("start")
assertThat(navController.currentBackStack.value.size).isEqualTo(2)
@@ -1403,7 +1454,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = "start") {
test("start")
- test(TestClass::class)
+ test<TestClass>()
}
navController.navigate(TEST_CLASS_ROUTE)
@@ -1421,7 +1472,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = "start") {
test("start")
- test(TestClassPathArg::class)
+ test<TestClassPathArg>()
}
navController.navigate(TEST_CLASS_PATH_ARG_ROUTE.replace("{arg}", "0"))
@@ -1439,7 +1490,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = "start") {
test("start")
- test(TestClass::class)
+ test<TestClass>()
}
navController.navigate(TEST_CLASS_ROUTE)
@@ -1459,7 +1510,7 @@
route = TestGraph::class,
startDestination = TestClass::class
) {
- test(TestClass::class)
+ test<TestClass>()
}
assertThat(navController.currentBackStack.value.size).isEqualTo(2)
@@ -1479,7 +1530,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = "start") {
test("start")
- test(TestClassPathArg::class)
+ test<TestClassPathArg>()
}
navController.navigate(TEST_CLASS_PATH_ARG_ROUTE.replace("{arg}", "0"))
@@ -1497,7 +1548,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = "start") {
test("start")
- test(TestClassPathArg::class)
+ test<TestClassPathArg>()
}
navController.navigate(TEST_CLASS_PATH_ARG_ROUTE.replace("{arg}", "0"))
@@ -1727,7 +1778,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = "start") {
test("start")
- test(TestClass::class)
+ test<TestClass>()
}
// first nav
@@ -1752,7 +1803,7 @@
route = TestGraph::class,
startDestination = TestClass::class
) {
- test(TestClass::class)
+ test<TestClass>()
}
assertThat(navController.currentBackStack.value.size).isEqualTo(2)
@@ -1773,7 +1824,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = "start") {
test("start")
- test(TestClassPathArg::class)
+ test<TestClassPathArg>()
}
// first nav
@@ -1796,7 +1847,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = "start") {
test("start")
- test(TestClass::class)
+ test<TestClass>()
}
// first nav
@@ -1821,7 +1872,7 @@
route = TestGraph::class,
startDestination = TestClass::class
) {
- test(TestClass::class)
+ test<TestClass>()
}
assertThat(navController.currentBackStack.value.size).isEqualTo(2)
@@ -1842,7 +1893,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = "start") {
test("start")
- test(TestClassPathArg::class)
+ test<TestClassPathArg>()
}
// first nav
@@ -1865,7 +1916,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = "start") {
test("start")
- test(TestClassPathArg::class)
+ test<TestClassPathArg>()
}
// first nav
@@ -2217,7 +2268,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = "start") {
test("start")
- test(TestClass::class)
+ test<TestClass>()
}
navController.navigate(TEST_CLASS_ROUTE)
@@ -2236,7 +2287,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = "start") {
test("start")
- test(TestClass::class)
+ test<TestClass>()
}
navController.navigate(TEST_CLASS_ROUTE)
@@ -2255,7 +2306,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = "start") {
test("start")
- test(TestClassPathArg::class)
+ test<TestClassPathArg>()
}
navController.navigate(TEST_CLASS_PATH_ARG_ROUTE.replace("{arg}", "0"))
@@ -2274,7 +2325,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = "start") {
test("start")
- test(TestClass::class)
+ test<TestClass>()
}
navController.navigate(TEST_CLASS_ROUTE)
@@ -2293,7 +2344,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = "start") {
test("start")
- test(TestClass::class)
+ test<TestClass>()
}
navController.navigate(TEST_CLASS_ROUTE)
@@ -2312,7 +2363,7 @@
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = "start") {
test("start")
- test(TestClassPathArg::class)
+ test<TestClassPathArg>()
}
// second nav
@@ -2331,7 +2382,113 @@
@UiThreadTest
@Test
- fun testNavigateViaDeepLinkDefaultArgs() {
+ fun testNavigateViaDeepLinkKClass() {
+ val baseUri = "www.example.com"
+ @Serializable
+ class TestClass(val arg: Int)
+
+ val navController = createNavController()
+ navController.graph = navController.createGraph(startDestination = "start") {
+ test("start")
+ test<TestClass> {
+ deepLink(
+ navDeepLink<TestClass> { uriPattern = baseUri }
+ )
+ }
+ }
+ val navigator = navController.navigatorProvider.getNavigator(TestNavigator::class.java)
+ val deepLink = Uri.parse("http://$baseUri/1")
+
+ navController.navigate(deepLink)
+
+ assertThat(navigator.backStack.size).isEqualTo(2)
+ assertThat(navController.currentBackStackEntry!!.arguments!!.getInt("arg"))
+ .isEqualTo(1)
+ }
+
+ @UiThreadTest
+ @Test
+ fun testNavigateViaDeepLinkKClassDefaultArg() {
+ val baseUri = "www.example.com"
+ @Serializable
+ class TestClass(val arg: Int = 1)
+
+ val navController = createNavController()
+ navController.graph = navController.createGraph(startDestination = "start") {
+ test("start")
+ test<TestClass> {
+ deepLink(
+ navDeepLink<TestClass> { uriPattern = baseUri }
+ )
+ }
+ }
+ val navigator = navController.navigatorProvider.getNavigator(TestNavigator::class.java)
+ val deepLink = Uri.parse("http://$baseUri")
+
+ navController.navigate(deepLink)
+
+ assertThat(navigator.backStack.size).isEqualTo(2)
+ val dest = navController.currentBackStackEntry?.toRoute<TestClass>()
+ assertThat(dest?.arg).isEqualTo(1)
+ }
+
+ @UiThreadTest
+ @Test
+ fun testNavigateViaDeepLinkKClassDefaultArgOverride() {
+ val baseUri = "www.example.com"
+ @Serializable
+ class TestClass(val arg: Int = 1)
+
+ val navController = createNavController()
+ navController.graph = navController.createGraph(startDestination = "start") {
+ test("start")
+ test<TestClass> {
+ deepLink(
+ navDeepLink<TestClass> { uriPattern = baseUri }
+ )
+ }
+ }
+ val navigator = navController.navigatorProvider.getNavigator(TestNavigator::class.java)
+ val deepLink = Uri.parse("http://$baseUri?arg=2")
+
+ navController.navigate(deepLink)
+
+ assertThat(navigator.backStack.size).isEqualTo(2)
+ val dest = navController.currentBackStackEntry?.toRoute<TestClass>()
+ assertThat(dest?.arg).isEqualTo(2)
+ }
+
+ @UiThreadTest
+ @Test
+ fun testNavigateViaDeepLinkKClassPopUpTo() {
+ val baseUri = "www.example.com"
+ @Serializable
+ class TestClass(val arg: Int)
+
+ val navController = createNavController()
+ navController.graph = navController.createGraph(startDestination = "start") {
+ test("start")
+ test<TestClass> {
+ deepLink(
+ navDeepLink<TestClass> { uriPattern = baseUri }
+ )
+ }
+ }
+ val navigator = navController.navigatorProvider.getNavigator(TestNavigator::class.java)
+ val deepLink = Uri.parse("http://$baseUri/1")
+
+ navController.navigate(deepLink, navOptions {
+ popUpTo("start") { inclusive = true }
+ })
+
+ assertThat(navigator.backStack.size).isEqualTo(1)
+ assertThat(navController.currentBackStackEntry!!.arguments!!.getInt("arg"))
+ .isEqualTo(1)
+ }
+
+ @UiThreadTest
+ @Test
+ fun testNavigateViaDeepLinkDefaultArg() {
val navController = createNavController()
navController.graph = nav_simple_route_graph
val navigator = navController.navigatorProvider.getNavigator(TestNavigator::class.java)
@@ -3082,7 +3239,7 @@
fun testNavigateWithPopKClassInclusive() {
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = TestClass::class) {
- test(TestClass::class)
+ test<TestClass>()
test("second")
}
@@ -3106,7 +3263,7 @@
fun testNavigateWithPopKClassNotInclusive() {
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = TestClass::class) {
- test(TestClass::class)
+ test<TestClass>()
test("second")
test("third")
}
@@ -3135,7 +3292,7 @@
fun testNavigateWithPopObjectInclusive() {
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = TestClass::class) {
- test(TestClass::class)
+ test<TestClass>()
test("second")
}
@@ -3159,7 +3316,7 @@
fun testNavigateWithPopObjectNotInclusive() {
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = TestClass::class) {
- test(TestClass::class)
+ test<TestClass>()
test("second")
test("third")
}
@@ -3188,7 +3345,7 @@
fun testNavigateWithPopObjectArg() {
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = TestClassPathArg(0)) {
- test(TestClassPathArg::class)
+ test<TestClassPathArg>()
test("second")
}
@@ -3212,7 +3369,7 @@
fun testNavigateWithPopObjectWrongArg() {
val navController = createNavController()
navController.graph = navController.createGraph(startDestination = TestClassPathArg(0)) {
- test(TestClassPathArg::class)
+ test<TestClassPathArg>()
test("second")
}
@@ -3233,6 +3390,27 @@
@UiThreadTest
@Test
+ fun testNavigateWithObjectListArg() {
+ @Serializable
+ class TestClass(val arg: MutableList<Boolean>)
+
+ val navController = createNavController()
+ navController.graph = navController.createGraph(
+ startDestination = TestClass(mutableListOf(true, false, true))
+ ) {
+ test<TestClass>()
+ }
+ assertThat(navController.currentDestination?.route).isEqualTo(
+ "androidx.navigation.NavControllerRouteTest.testNavigateWithObjectListArg" +
+ ".TestClass?arg={arg}"
+ )
+ val route = navController.currentBackStackEntry?.toRoute<TestClass>()
+ assertThat(route?.arg is MutableList).isTrue()
+ assertThat(route?.arg).containsExactly(true, false, true).inOrder()
+ }
+
+ @UiThreadTest
+ @Test
fun testDeepLinkFromNavGraph() {
val navController = createNavController()
navController.graph = nav_simple_route_graph
diff --git a/navigation/navigation-safe-args-gradle-plugin/src/test/kotlin/androidx/navigation/safeargs/gradle/BasePluginTest.kt b/navigation/navigation-safe-args-gradle-plugin/src/test/kotlin/androidx/navigation/safeargs/gradle/BasePluginTest.kt
index 5f0e351..187dc0e 100644
--- a/navigation/navigation-safe-args-gradle-plugin/src/test/kotlin/androidx/navigation/safeargs/gradle/BasePluginTest.kt
+++ b/navigation/navigation-safe-args-gradle-plugin/src/test/kotlin/androidx/navigation/safeargs/gradle/BasePluginTest.kt
@@ -115,7 +115,7 @@
projectSetup.buildFile.writeText(
"""
buildscript {
- ext.compileSdk = ${props.compileSdkVersion}
+ ext.compileSdk = ${props.compileSdk}
ext.buildTools = "${props.buildToolsVersion}"
ext.minSdk = ${props.minSdkVersion}
ext.debugKeystoreFile = "${props.debugKeystore}"
diff --git a/paging/integration-tests/testapp/build.gradle b/paging/integration-tests/testapp/build.gradle
index 8b420e1..f198a5e 100644
--- a/paging/integration-tests/testapp/build.gradle
+++ b/paging/integration-tests/testapp/build.gradle
@@ -67,3 +67,7 @@
tasks.withType(JavaCompile) {
options.compilerArgs << "-parameters"
}
+
+ksp {
+ arg('room.generateKotlin', 'false')
+}
diff --git a/pdf/pdf-viewer/src/main/res/values-be/strings.xml b/pdf/pdf-viewer/src/main/res/values-be/strings.xml
index 11d3a42..192a70e 100644
--- a/pdf/pdf-viewer/src/main/res/values-be/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-be/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Тып файла"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Гэты файл абаронены"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Пароль"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Няправільны пароль"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Скасаваць"</string>
+ <string name="button_open" msgid="5445014062438566842">"Адкрыць"</string>
+ <string name="desc_password" msgid="6636473611443746739">"поле ўводу пароля"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"няправільны пароль"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"няправільны пароль"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> з <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"старонка <xliff:g id="PAGE">%1$d</xliff:g> з <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"маштаб <xliff:g id="FIRST">%1$d</xliff:g>%%"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"На старонку <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"старонка <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Выберыце тэкст, каб змясціць свой каментарый"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Націсніце там, дзе будзеце каментаваць"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Скасаваць"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Не ўдаецца паказаць PDF-файл \"<xliff:g id="TITLE">%1$s</xliff:g>\" (няправільны фармат)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Немагчыма адлюстраваць старонку <xliff:g id="PAGE">%1$d</xliff:g> (памылка файла)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Не ўдаецца загрузіць рэжым анатацый для гэтага элемента."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Спасылка: вэб-старонка <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Спасылка: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Адрас электроннай пошты: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Тэлефон: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"пачатак вылучэння"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"канец вылучэння"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> з <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-bg/strings.xml b/pdf/pdf-viewer/src/main/res/values-bg/strings.xml
index b1af046..71a21a7 100644
--- a/pdf/pdf-viewer/src/main/res/values-bg/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-bg/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Файлов тип"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Този файл е защитен"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Парола"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Неправилна парола"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Отказ"</string>
+ <string name="button_open" msgid="5445014062438566842">"Отваряне"</string>
+ <string name="desc_password" msgid="6636473611443746739">"поле за парола"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"неправилна парола"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"неправилна парола"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"страница <xliff:g id="PAGE">%1$d</xliff:g> от <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"Процент на промяна на мащаба: <xliff:g id="FIRST">%1$d</xliff:g>"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Към страница <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"страница <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Изберете текст, за да поставите коментара си"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Докоснете област, която да коментирате"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Отказ"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF файлът <xliff:g id="TITLE">%1$s</xliff:g> не може да се покаже (форматът е невалиден)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Страница <xliff:g id="PAGE">%1$d</xliff:g> не може да се покаже (грешка във файла)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Режимът за пояснения не може да се зареди за този елемент."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Връзка: уеб страница от <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Връзка: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Имейл адрес: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Телефон: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"начало на избраното"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"край на избраното"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> – <xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-bn/strings.xml b/pdf/pdf-viewer/src/main/res/values-bn/strings.xml
index f4df82a..ec56333 100644
--- a/pdf/pdf-viewer/src/main/res/values-bn/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-bn/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"ফাইলের ধরন"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"এই ফাইল সুরক্ষিত আছে"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"পাসওয়ার্ড"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"পাসওয়ার্ড সঠিক নয়"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"বাতিল করুন"</string>
+ <string name="button_open" msgid="5445014062438566842">"খুলুন"</string>
+ <string name="desc_password" msgid="6636473611443746739">"পাসওয়ার্ড ফিল্ড"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"পাসওয়ার্ড সঠিক নয়"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"পাসওয়ার্ড সঠিক নয়"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="TOTAL">%2$d</xliff:g>টির মধ্যে <xliff:g id="PAGE">%1$d</xliff:g> নম্বর পৃষ্ঠা"</string>
<string name="desc_zoom" msgid="7318480946145947242">"<xliff:g id="FIRST">%1$d</xliff:g> শতাংশ জুম করুন"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"<xliff:g id="PAGE_NUMBER">%1$d</xliff:g> নম্বর পৃষ্ঠায় যান"</string>
<string name="desc_page" msgid="5684226167093594168">"পৃষ্ঠা <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"আপনার কমেন্ট করতে টেক্সট বেছে নিন"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"কমেন্ট করতে কোনও একটি অংশে ট্যাপ করুন"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"বাতিল করুন"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"পিডিএফ দেখানো যাবে না (<xliff:g id="TITLE">%1$s</xliff:g> ভুল ফর্ম্যাটে আছে)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"<xliff:g id="PAGE">%1$d</xliff:g> পৃষ্ঠা দেখানো যাবে না (ফাইলে সমস্যা)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"এই আইটেমের জন্য অ্যানোটেশন মোড লোড করা যায়নি।"</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"লিঙ্ক: <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>-এ ওয়েবপেজ"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"লিঙ্ক: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"ইমেল: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"ফোন: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"বেছে নেওয়া টেক্সটের শুরু"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"বেছে নেওয়া টেক্সটের শেষ"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-bs/strings.xml b/pdf/pdf-viewer/src/main/res/values-bs/strings.xml
index cc94c57..6f0cfa1 100644
--- a/pdf/pdf-viewer/src/main/res/values-bs/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-bs/strings.xml
@@ -18,29 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Vrsta fajla"</string>
- <string name="title_dialog_password" msgid="2018068413709926925">"Datoteka je zaštićena"</string>
- <string name="label_password_first" msgid="4456258714097111908">"Zaporka"</string>
- <string name="label_password_incorrect" msgid="8449142641187704667">"Zaporka nije točna"</string>
- <string name="button_cancel" msgid="5855794576957267334">"Odustani"</string>
+ <string name="title_dialog_password" msgid="2018068413709926925">"Fajl je zaštićen"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Lozinka"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Pogrešna lozinka"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Otkaži"</string>
<string name="button_open" msgid="5445014062438566842">"Otvori"</string>
- <string name="desc_password" msgid="6636473611443746739">"polje zaporke"</string>
- <string name="desc_password_incorrect" msgid="4718823067483963845">"zaporka nije točna"</string>
- <string name="desc_password_incorrect_message" msgid="4849541619951023025">"zaporka nije točna"</string>
+ <string name="desc_password" msgid="6636473611443746739">"polje za lozinku"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"pogrešna lozinka"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"pogrešna lozinka"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="PAGE">%1$d</xliff:g>. stranica od <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"zumiranje <xliff:g id="FIRST">%1$d</xliff:g> posto"</string>
- <string name="desc_goto_link" msgid="2461368384824849714">"Idite na stranicu <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
+ <string name="desc_goto_link" msgid="2461368384824849714">"Odlazak na <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>. stranicu"</string>
<string name="desc_page" msgid="5684226167093594168">"<xliff:g id="PAGE">%1$d</xliff:g>. stranica"</string>
- <string name="message_select_text_to_comment" msgid="5725327644007067522">"Odaberite tekst za postavljanje komentara"</string>
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Odaberite tekst da unesete komentar"</string>
<string name="message_tap_to_comment" msgid="7820801719181709999">"Dodirnite područje koje ćete komentirati"</string>
- <string name="action_cancel" msgid="5494417739210197522">"Odustani"</string>
- <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF se ne može prikazati (format <xliff:g id="TITLE">%1$s</xliff:g> nije važeći)"</string>
- <string name="error_on_page" msgid="1592475819957182385">"Stranica <xliff:g id="PAGE">%1$d</xliff:g> ne može se prikazati (pogreška datoteke)"</string>
- <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Način za napomene za tu stavku ne može se učitati."</string>
- <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Veza: web-stranica na domeni <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
- <string name="desc_web_link" msgid="2776023299237058419">"Veza: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
- <string name="desc_email_link" msgid="7027325672358507448">"E-adresa: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
- <string name="desc_phone_link" msgid="4986414958429253135">"Telefonski broj: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Otkaži"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Nije moguće prikazati PDF (fajl <xliff:g id="TITLE">%1$s</xliff:g> ima nevažeći format)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Nije moguće prikazati <xliff:g id="PAGE">%1$d</xliff:g>. stranicu (greška fajla)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Nije moguće učitati način rada za bilješke za ovu stavku."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: web stranica na <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Adresa e-pošte: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Broj telefona: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"početak odabira"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"kraj odabira"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>.–<xliff:g id="LAST">%2$d</xliff:g>. / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ca/strings.xml b/pdf/pdf-viewer/src/main/res/values-ca/strings.xml
index 8318f9e..0c26917 100644
--- a/pdf/pdf-viewer/src/main/res/values-ca/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ca/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Tipus de fitxer"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Aquest fitxer està protegit"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Contrasenya"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Contrasenya incorrecta"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Cancel·la"</string>
+ <string name="button_open" msgid="5445014062438566842">"Obre"</string>
+ <string name="desc_password" msgid="6636473611443746739">"camp de contrasenya"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"contrasenya incorrecta"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"contrasenya incorrecta"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"pàgina <xliff:g id="PAGE">%1$d</xliff:g> de <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> per cent"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Ves a la pàgina <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"pàgina <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Selecciona text per escriure un comentari"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Toca una zona per comentar-la"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Cancel·la"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"No es pot mostrar el PDF (<xliff:g id="TITLE">%1$s</xliff:g> no és un format vàlid)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"No es pot mostrar la pàgina <xliff:g id="PAGE">%1$d</xliff:g> (error del fitxer)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"No es pot carregar el mode d\'anotació per a aquest element."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Enllaç: pàgina web a <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Enllaç: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Adreça electrònica: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Telèfon: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"inici de la selecció"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"final de la selecció"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-cs/strings.xml b/pdf/pdf-viewer/src/main/res/values-cs/strings.xml
index 2bb8adc..baf857b 100644
--- a/pdf/pdf-viewer/src/main/res/values-cs/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-cs/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Typ souboru"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Tento soubor je chráněn"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Heslo"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Nesprávné heslo"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Zrušit"</string>
+ <string name="button_open" msgid="5445014062438566842">"Otevřít"</string>
+ <string name="desc_password" msgid="6636473611443746739">"pole hesla"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"nesprávné heslo"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"nesprávné heslo"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"stránka <xliff:g id="PAGE">%1$d</xliff:g> z <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"lupa <xliff:g id="FIRST">%1$d</xliff:g> procent"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Přejít na stránku <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"stránka <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Vyberte text k umístění komentáře"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Klepněte na oblast k okomentování"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Zrušit"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF nelze zobrazit (<xliff:g id="TITLE">%1$s</xliff:g> má neplatný formát)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Stránku <xliff:g id="PAGE">%1$d</xliff:g> nelze zobrazit (chyba souboru)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Pro tuto položku nelze načíst režim poznámek."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Odkaz: stránka na webu <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Odkaz: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"E‑mail: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Telefon: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"začátek výběru"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"konec výběru"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-da/strings.xml b/pdf/pdf-viewer/src/main/res/values-da/strings.xml
index fea00587..d4aa7e3 100644
--- a/pdf/pdf-viewer/src/main/res/values-da/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-da/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Filtype"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Denne fil er beskyttet"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Adgangskode"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Adgangskoden er forkert"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Annuller"</string>
+ <string name="button_open" msgid="5445014062438566842">"Åbn"</string>
+ <string name="desc_password" msgid="6636473611443746739">"felt til adgangskode"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"adgangskoden er forkert"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"adgangskoden er forkert"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"side <xliff:g id="PAGE">%1$d</xliff:g> af <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> %%"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Gå til side <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"side <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Markér tekst for at indsætte din kommentar"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Tryk på et område, du vil kommentere"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Annuller"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF kan ikke vises (<xliff:g id="TITLE">%1$s</xliff:g> er i et ugyldigt format)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Side <xliff:g id="PAGE">%1$d</xliff:g> kan ikke vises (filfejl)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Annoteringstilstanden for dette element kan ikke indlæses."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: webside på <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Mailadresse: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Telefonnummer: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"start på markering"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"slut på markering"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-de/strings.xml b/pdf/pdf-viewer/src/main/res/values-de/strings.xml
index fcfc0f1..b341d91 100644
--- a/pdf/pdf-viewer/src/main/res/values-de/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-de/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Dateityp"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Diese Datei ist geschützt"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Passwort"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Falsches Passwort"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Abbrechen"</string>
+ <string name="button_open" msgid="5445014062438566842">"Öffnen"</string>
+ <string name="desc_password" msgid="6636473611443746739">"Passwortfeld"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"Falsches Passwort"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"Falsches Passwort"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"Seite <xliff:g id="PAGE">%1$d</xliff:g> von <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"Zoom: <xliff:g id="FIRST">%1$d</xliff:g> %%"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Gehe zu Seite <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"Seite <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Zum Einfügen des Kommentars Text auswählen"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Auf Bereich tippen, um zu kommentieren"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Abbrechen"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Anzeige von PDF nicht möglich („<xliff:g id="TITLE">%1$s</xliff:g>“ hat ungültiges Dateiformat)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Anzeige von Seite <xliff:g id="PAGE">%1$d</xliff:g> nicht möglich (Dateifehler)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Anmerkungsmodus für dieses Element kann nicht geladen werden."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: Webseite unter <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"E-Mail-Adresse: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Telefonnummer: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"Beginn der Auswahl"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"Ende der Auswahl"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-el/strings.xml b/pdf/pdf-viewer/src/main/res/values-el/strings.xml
index 20a3d0d..14926d4 100644
--- a/pdf/pdf-viewer/src/main/res/values-el/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-el/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Τύπος αρχείου"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Αυτό το αρχείο είναι προστατευμένο"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Κωδικός πρόσβασης"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Εσφαλμένος κωδικός πρόσβασης"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Ακύρωση"</string>
+ <string name="button_open" msgid="5445014062438566842">"Άνοιγμα"</string>
+ <string name="desc_password" msgid="6636473611443746739">"πεδίο κωδικού πρόσβασης"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"εσφαλμένος κωδικός πρόσβασης"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"εσφαλμένος κωδικός πρόσβασης"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"σελίδα <xliff:g id="PAGE">%1$d</xliff:g> από <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"εστίαση <xliff:g id="FIRST">%1$d</xliff:g> τοις εκατό"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Μετάβαση στη σελίδα <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"σελίδα <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Επιλέξτε κείμενο για να τοποθετήσετε σχόλιο"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Πατήστε μια περιοχή για να σχολιάσετε"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Ακύρωση"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Δεν είναι δυνατή η προβολή του PDF (μη έγκυρη μορφή του <xliff:g id="TITLE">%1$s</xliff:g>)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Δεν είναι δυνατή η προβολή της σελίδας <xliff:g id="PAGE">%1$d</xliff:g> (σφάλμα αρχείου)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Δεν είναι δυνατή η φόρτωση της λειτουργίας σχολιασμού για αυτό το στοιχείο."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Σύνδεσμος: ιστοσελίδα στη διεύθυνση <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Σύνδεσμος: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Διεύθυνση ηλεκτρονικού ταχυδρομείου: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Τηλέφωνο: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"αρχή επιλογής"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"τέλος επιλογής"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-en-rAU/strings.xml b/pdf/pdf-viewer/src/main/res/values-en-rAU/strings.xml
index abd87b6..dcb8ff3 100644
--- a/pdf/pdf-viewer/src/main/res/values-en-rAU/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-en-rAU/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"File type"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"This file is protected"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Password"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Password incorrect"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Cancel"</string>
+ <string name="button_open" msgid="5445014062438566842">"Open"</string>
+ <string name="desc_password" msgid="6636473611443746739">"password field"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"password incorrect"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"password incorrect"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"page <xliff:g id="PAGE">%1$d</xliff:g> of <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> per cent"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Go to page <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"page <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Select text to place your comment"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Tap an area to comment on it"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Cancel"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Cannot display PDF (<xliff:g id="TITLE">%1$s</xliff:g> is of invalid format)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Cannot display page <xliff:g id="PAGE">%1$d</xliff:g> (file error)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Can\'t load annotation mode for this item."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: web page at <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Email: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Phone: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"selection start"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"selection end"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-en-rGB/strings.xml b/pdf/pdf-viewer/src/main/res/values-en-rGB/strings.xml
index abd87b6..dcb8ff3 100644
--- a/pdf/pdf-viewer/src/main/res/values-en-rGB/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-en-rGB/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"File type"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"This file is protected"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Password"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Password incorrect"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Cancel"</string>
+ <string name="button_open" msgid="5445014062438566842">"Open"</string>
+ <string name="desc_password" msgid="6636473611443746739">"password field"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"password incorrect"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"password incorrect"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"page <xliff:g id="PAGE">%1$d</xliff:g> of <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> per cent"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Go to page <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"page <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Select text to place your comment"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Tap an area to comment on it"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Cancel"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Cannot display PDF (<xliff:g id="TITLE">%1$s</xliff:g> is of invalid format)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Cannot display page <xliff:g id="PAGE">%1$d</xliff:g> (file error)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Can\'t load annotation mode for this item."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: web page at <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Email: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Phone: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"selection start"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"selection end"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-en-rIN/strings.xml b/pdf/pdf-viewer/src/main/res/values-en-rIN/strings.xml
index abd87b6..dcb8ff3 100644
--- a/pdf/pdf-viewer/src/main/res/values-en-rIN/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-en-rIN/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"File type"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"This file is protected"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Password"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Password incorrect"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Cancel"</string>
+ <string name="button_open" msgid="5445014062438566842">"Open"</string>
+ <string name="desc_password" msgid="6636473611443746739">"password field"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"password incorrect"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"password incorrect"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"page <xliff:g id="PAGE">%1$d</xliff:g> of <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> per cent"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Go to page <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"page <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Select text to place your comment"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Tap an area to comment on it"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Cancel"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Cannot display PDF (<xliff:g id="TITLE">%1$s</xliff:g> is of invalid format)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Cannot display page <xliff:g id="PAGE">%1$d</xliff:g> (file error)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Can\'t load annotation mode for this item."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: web page at <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Email: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Phone: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"selection start"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"selection end"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-es-rUS/strings.xml b/pdf/pdf-viewer/src/main/res/values-es-rUS/strings.xml
index 4bca430..0db6b02 100644
--- a/pdf/pdf-viewer/src/main/res/values-es-rUS/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-es-rUS/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Tipo de archivo"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Este archivo está protegido"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Contraseña"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"La contraseña es incorrecta"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Cancelar"</string>
+ <string name="button_open" msgid="5445014062438566842">"Abrir"</string>
+ <string name="desc_password" msgid="6636473611443746739">"campo de contraseña"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"contraseña incorrecta"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"contraseña incorrecta"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> de <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"página <xliff:g id="PAGE">%1$d</xliff:g> de <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> por ciento"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Ir a la página <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"página <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Selecciona texto para colocar tu comentario"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Presiona un área para comentar"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Cancelar"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"No se puede mostrar el PDF (<xliff:g id="TITLE">%1$s</xliff:g> tiene un formato no válido)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"No se puede mostrar la página <xliff:g id="PAGE">%1$d</xliff:g> (error de archivo)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"No se puede cargar el modo de anotación para este elemento."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Vínculo: página web en <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Vínculo: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Correo electrónico: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Teléfono: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"inicio de la selección"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"fin de la selección"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> a <xliff:g id="LAST">%2$d</xliff:g> de <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-es/strings.xml b/pdf/pdf-viewer/src/main/res/values-es/strings.xml
index 4f07b38..a416a41 100644
--- a/pdf/pdf-viewer/src/main/res/values-es/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-es/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Tipo de archivo"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Este archivo está protegido"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Contraseña"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Contraseña incorrecta"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Cancelar"</string>
+ <string name="button_open" msgid="5445014062438566842">"Abrir"</string>
+ <string name="desc_password" msgid="6636473611443746739">"campo de contraseña"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"contraseña incorrecta"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"contraseña incorrecta"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"página <xliff:g id="PAGE">%1$d</xliff:g> de <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> por ciento"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Ir a la página <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"página <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Selecciona el texto para añadir tu comentario"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Toca una zona para dejar un comentario"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Cancelar"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"No se puede mostrar el PDF (el formato de <xliff:g id="TITLE">%1$s</xliff:g> no es válido)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"No se puede mostrar la página <xliff:g id="PAGE">%1$d</xliff:g> (error de archivo)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"No se puede cargar el modo de anotación en este elemento."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Enlace: página web en <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Enlace: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Correo: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Teléfono: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"inicio de la selección"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"final de la selección"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-et/strings.xml b/pdf/pdf-viewer/src/main/res/values-et/strings.xml
index 18e68f0..88b7755 100644
--- a/pdf/pdf-viewer/src/main/res/values-et/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-et/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Faili tüüp"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Fail on kaitstud"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Parool"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Parool on vale"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Tühista"</string>
+ <string name="button_open" msgid="5445014062438566842">"Ava"</string>
+ <string name="desc_password" msgid="6636473611443746739">"parooliväli"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"parool on vale"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"parool on vale"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"lk <xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"suum <xliff:g id="FIRST">%1$d</xliff:g> protsenti"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Mine lehele <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"lk <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Valige tekst, millele kommentaar lisada"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Puudutage ala, millele kommentaar lisada"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Tühista"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF-i ei saa kuvada (<xliff:g id="TITLE">%1$s</xliff:g> on vales vormingus)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Lehekülge <xliff:g id="PAGE">%1$d</xliff:g> ei saa kuvada (viga failis)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Selle üksuse jaoks ei saa märkuste lisamise režiimi laadida."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: veebileht aadressil <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"E-posti aadress: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Telefon: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"valiku algus"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"valiku lõpp"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-eu/strings.xml b/pdf/pdf-viewer/src/main/res/values-eu/strings.xml
index dd0b571..1f0b66d 100644
--- a/pdf/pdf-viewer/src/main/res/values-eu/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-eu/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Fitxategi mota"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Fitxategi hau babestuta dago"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Pasahitza"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Pasahitza okerra da"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Utzi"</string>
+ <string name="button_open" msgid="5445014062438566842">"Ireki"</string>
+ <string name="desc_password" msgid="6636473611443746739">"pasahitzaren eremua"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"pasahitza okerra da"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"pasahitza okerra da"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="TOTAL">%2$d</xliff:g> orritatik <xliff:g id="PAGE">%1$d</xliff:g>garrena"</string>
<string name="desc_zoom" msgid="7318480946145947242">"zooma ehuneko <xliff:g id="FIRST">%1$d</xliff:g>"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Joan <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>. orrira"</string>
<string name="desc_page" msgid="5684226167093594168">"<xliff:g id="PAGE">%1$d</xliff:g>garren orria"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Iruzkina egiteko, hautatu testua"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Sakatu iruzkindu beharreko eremua"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Utzi"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Ezin da erakutsi PDFa (<xliff:g id="TITLE">%1$s</xliff:g> fitxategiaren formatuak ez du balio)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Ezin da erakutsi <xliff:g id="PAGE">%1$d</xliff:g> orria (fitxategi-errorea)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Ezin da kargatu oharpenen modua elementu honetarako."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Esteka: <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> domeinuko web-orria"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Esteka: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Helbide elektronikoa: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Telefono-zenbakia: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"hautapenaren hasiera"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"hautapenaren amaiera"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-fi/strings.xml b/pdf/pdf-viewer/src/main/res/values-fi/strings.xml
index 482722b..c1ad329 100644
--- a/pdf/pdf-viewer/src/main/res/values-fi/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-fi/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Tiedostotyyppi"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Tämä tiedosto on suojattu"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Salasana"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Väärä salasana"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Peruuta"</string>
+ <string name="button_open" msgid="5445014062438566842">"Avaa"</string>
+ <string name="desc_password" msgid="6636473611443746739">"salasanakenttä"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"väärä salasana"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"väärä salasana"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"sivu <xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"zoomaus <xliff:g id="FIRST">%1$d</xliff:g> prosenttia"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Siirry sivulle <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"sivu <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Valitse teksti, johon haluat lisätä kommentin"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Napauta kommentoitavaa aluetta"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Peruuta"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF:ää ei voi näyttää (<xliff:g id="TITLE">%1$s</xliff:g> on virheellinen muoto)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Sivua <xliff:g id="PAGE">%1$d</xliff:g> ei voi näyttää (tiedostovirhe)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Kohteen muistiinpanotilaa ei voi ladata."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Linkki: verkkosivu osoitteessa <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Linkki: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Sähköpostiosoite: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Puhelinnumero: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"valinnan alku"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"valinnan loppu"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-fr-rCA/strings.xml b/pdf/pdf-viewer/src/main/res/values-fr-rCA/strings.xml
index bb4469d..d1cf1e2 100644
--- a/pdf/pdf-viewer/src/main/res/values-fr-rCA/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-fr-rCA/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Type de fichier"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Ce fichier est protégé"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Mot de passe"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Mot de passe incorrect"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Annuler"</string>
+ <string name="button_open" msgid="5445014062438566842">"Ouvrir"</string>
+ <string name="desc_password" msgid="6636473611443746739">"champ du mot de passe"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"mot de passe incorrect"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"mot de passe incorrect"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"page <xliff:g id="PAGE">%1$d</xliff:g> sur <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> pour cent"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Accéder à la page <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"page <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Sélect. du texte pour placer le commentaire"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Touchez une zone à commenter"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Annuler"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Impossible d\'afficher le PDF (format de <xliff:g id="TITLE">%1$s</xliff:g> non valide)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Impossible d\'afficher la page <xliff:g id="PAGE">%1$d</xliff:g> (erreur de fichier)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Impossible de charger le mode d\'annotation pour cet élément."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Lien : page Web sur <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Lien : <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Adresse de courriel : <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Numéro de téléphone : <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"début de la sélection"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"fin de la sélection"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-fr/strings.xml b/pdf/pdf-viewer/src/main/res/values-fr/strings.xml
index 37ae617..9ea14c1 100644
--- a/pdf/pdf-viewer/src/main/res/values-fr/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-fr/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Type de fichier"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Ce fichier est protégé"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Mot de passe"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Mot de passe incorrect"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Annuler"</string>
+ <string name="button_open" msgid="5445014062438566842">"Ouvrir"</string>
+ <string name="desc_password" msgid="6636473611443746739">"champ de mot de passe"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"mot de passe incorrect"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"mot de passe incorrect"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"page <xliff:g id="PAGE">%1$d</xliff:g> sur <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"zoom : <xliff:g id="FIRST">%1$d</xliff:g> pour cent"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Accéder à la page <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"page <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Sélectionnez le texte à commenter"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Appuyez sur la zone à commenter"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Annuler"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Impossible d\'afficher le PDF (format non valide pour <xliff:g id="TITLE">%1$s</xliff:g>)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Impossible d\'afficher la page <xliff:g id="PAGE">%1$d</xliff:g> (erreur de fichier)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Impossible de charger le mode Annotation pour cet élément."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Lien : page Web du domaine <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Lien : <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Adresse e-mail : <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Téléphone : <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"début de la sélection"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"fin de la sélection"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-gl/strings.xml b/pdf/pdf-viewer/src/main/res/values-gl/strings.xml
index ce8c6b3..4a85719 100644
--- a/pdf/pdf-viewer/src/main/res/values-gl/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-gl/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Tipo de ficheiro"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Este ficheiro está protexido"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Contrasinal"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Contrasinal incorrecto"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Cancelar"</string>
+ <string name="button_open" msgid="5445014062438566842">"Abrir"</string>
+ <string name="desc_password" msgid="6636473611443746739">"campo do contrasinal"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"contrasinal incorrecto"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"contrasinal incorrecto"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"páxina <xliff:g id="PAGE">%1$d</xliff:g> de <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"zoom ao <xliff:g id="FIRST">%1$d</xliff:g> por cento"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Vai á páxina <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"páxina <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Selecciona o texto para engadir un comentario"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Toca a zona na que engadir un comentario"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Cancelar"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Non se puido mostrar o PDF (<xliff:g id="TITLE">%1$s</xliff:g> ten un formato non válido)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Non se puido mostrar a páxina <xliff:g id="PAGE">%1$d</xliff:g> (hai un erro no ficheiro)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Non se puido cargar o modo de anotación para este elemento."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Ligazón: páxina web en <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Ligazón: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Correo electrónico: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Teléfono: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"inicio da selección"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"fin da selección"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-hu/strings.xml b/pdf/pdf-viewer/src/main/res/values-hu/strings.xml
index 618d6b0..72c88d9 100644
--- a/pdf/pdf-viewer/src/main/res/values-hu/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-hu/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Fájltípus"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"A fájl védett"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Jelszó"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Helytelen jelszó"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Mégse"</string>
+ <string name="button_open" msgid="5445014062438566842">"Megnyitás"</string>
+ <string name="desc_password" msgid="6636473611443746739">"jelszómező"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"helytelen jelszó"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"helytelen jelszó"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="TOTAL">%2$d</xliff:g>/<xliff:g id="PAGE">%1$d</xliff:g>."</string>
<string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="TOTAL">%2$d</xliff:g>/<xliff:g id="PAGE">%1$d</xliff:g>. oldal"</string>
<string name="desc_zoom" msgid="7318480946145947242">"<xliff:g id="FIRST">%1$d</xliff:g> százalékos nagyítás"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Ugrás erre az oldalra: <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"<xliff:g id="PAGE">%1$d</xliff:g>. oldal"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Válassza ki a szöveget a megjegyzéshez"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Koppintson arra a területre, amelyhez megjegyzést szeretne fűzni"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Mégse"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Nem sikerült megjeleníteni a PDF-et (<xliff:g id="TITLE">%1$s</xliff:g> formátuma érvénytelen)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Nem sikerült megjeleníteni a(z) <xliff:g id="PAGE">%1$d</xliff:g> oldalt (fájlhiba)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Az elemhez nem lehet betölteni kommentár módot."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: weboldal helye: <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"E-mail-cím: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Telefon: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"kijelölés kezdete"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"kijelölés vége"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="TOTAL">%3$d</xliff:g>/<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>."</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-hy/strings.xml b/pdf/pdf-viewer/src/main/res/values-hy/strings.xml
index 376f583..bcf72be 100644
--- a/pdf/pdf-viewer/src/main/res/values-hy/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-hy/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Ֆայլի տեսակը"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Այս ֆայլը պաշտպանված է"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Գաղտնաբառ"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Գաղտնաբառը սխալ է"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Չեղարկել"</string>
+ <string name="button_open" msgid="5445014062438566842">"Բացել"</string>
+ <string name="desc_password" msgid="6636473611443746739">"գաղտնաբառի դաշտ"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"գաղտնաբառը սխալ է"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"գաղտնաբառը սխալ է"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"Էջ <xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"մասշտաբը՝ <xliff:g id="FIRST">%1$d</xliff:g> տոկոս"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Անցեք <xliff:g id="PAGE_NUMBER">%1$d</xliff:g> էջ"</string>
<string name="desc_page" msgid="5684226167093594168">"էջ <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Նշեք տեքստը՝ մեկնաբանություն տեղադրելու համար"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Հպեք՝ մեկնաբանություն ավելացնելու համար"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Չեղարկել"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Հնարավոր չէ ցուցադրել PDF-ը (<xliff:g id="TITLE">%1$s</xliff:g> ֆայլը անվավեր ձևաչափ ունի)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Հնարավոր չէ ցուցադրել էջ <xliff:g id="PAGE">%1$d</xliff:g>-ը (ֆայլի սխալ)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Չհաջողվեց բեռնել ծանոթագրության ռեժիմն այս տարրի համար։"</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Հղում՝ կայքէջ <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>-ում"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Հղում՝ <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Էլ․ հասցե՝ <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Հեռախոս՝ <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"ընտրվածքի սկիզբ"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"ընտրվածքի վերջ"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-it/strings.xml b/pdf/pdf-viewer/src/main/res/values-it/strings.xml
index a6bc398..fb24fa5 100644
--- a/pdf/pdf-viewer/src/main/res/values-it/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-it/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Tipo di file"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Questo file è protetto"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Password"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Password errata"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Annulla"</string>
+ <string name="button_open" msgid="5445014062438566842">"Apri"</string>
+ <string name="desc_password" msgid="6636473611443746739">"campo password"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"password errata"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"password errata"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"pagina <xliff:g id="PAGE">%1$d</xliff:g> di <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g>%%"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Vai alla pagina <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"pagina <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Seleziona il testo da inserire nel commento"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Tocca un\'area per inserire un commento"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Annulla"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Impossibile visualizzare PDF (<xliff:g id="TITLE">%1$s</xliff:g> è in un formato non valido)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Impossibile visualizzare la pagina <xliff:g id="PAGE">%1$d</xliff:g> (errore del file)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Impossibile caricare la modalità di annotazione per questo elemento."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: pagina web all\'indirizzo <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Email: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Telefono: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"inizio selezione"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"fine selezione"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-iw/strings.xml b/pdf/pdf-viewer/src/main/res/values-iw/strings.xml
index c7b0d79..411301a 100644
--- a/pdf/pdf-viewer/src/main/res/values-iw/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-iw/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"סוג הקובץ"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"הקובץ הזה מוגן"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"סיסמה"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"הסיסמה שגויה"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"ביטול"</string>
+ <string name="button_open" msgid="5445014062438566842">"פתיחה"</string>
+ <string name="desc_password" msgid="6636473611443746739">"שדה הסיסמה"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"הסיסמה שגויה"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"הסיסמה שגויה"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"דף <xliff:g id="PAGE">%1$d</xliff:g> מתוך <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"שינוי מרחק התצוגה ב-<xliff:g id="FIRST">%1$d</xliff:g> אחוזים"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"מעבר לדף <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"עמוד <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"צריך לבחור את הטקסט לתגובה"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"אפשר להקיש על אזור כדי להגיב עליו"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"ביטול"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"אי אפשר להציג קובץ PDF (<xliff:g id="TITLE">%1$s</xliff:g> בפורמט לא תקין)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"לא ניתן להציג את הדף <xliff:g id="PAGE">%1$d</xliff:g> (שגיאת קובץ)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"אי אפשר לטעון את מצב ההערות בפריט הזה."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"קישור: דף אינטרנט בדומיין <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"קישור: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"אימייל: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"טלפון: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"התחלת הבחירה"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"סיום הבחירה"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ja/strings.xml b/pdf/pdf-viewer/src/main/res/values-ja/strings.xml
index 34f3ae5..13cb183 100644
--- a/pdf/pdf-viewer/src/main/res/values-ja/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ja/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"ファイル形式"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"このファイルは保護されています"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"パスワード"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"パスワードが正しくありません"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"キャンセル"</string>
+ <string name="button_open" msgid="5445014062438566842">"開く"</string>
+ <string name="desc_password" msgid="6636473611443746739">"パスワードを入力する項目です"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"パスワードが正しくありません"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"パスワードが正しくありません"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g> ページ"</string>
<string name="desc_zoom" msgid="7318480946145947242">"ズーム <xliff:g id="FIRST">%1$d</xliff:g> %%"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"<xliff:g id="PAGE_NUMBER">%1$d</xliff:g> ページに移動します"</string>
<string name="desc_page" msgid="5684226167093594168">"<xliff:g id="PAGE">%1$d</xliff:g> ページ"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"コメントを配置するテキストを選択してください"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"コメント対象の範囲をタップしてください"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"キャンセル"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF を表示できません(<xliff:g id="TITLE">%1$s</xliff:g> の形式が無効です)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"<xliff:g id="PAGE">%1$d</xliff:g> ページを表示できません(ファイルエラー)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"このアイテムのアノテーション モードを読み込めません。"</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"リンク: ウェブページ(<xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>)"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"リンク: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"メールアドレス: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"電話番号: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"選択範囲の最初"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"選択範囲の最後"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>~<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ka/strings.xml b/pdf/pdf-viewer/src/main/res/values-ka/strings.xml
index dc8c626..115eceb 100644
--- a/pdf/pdf-viewer/src/main/res/values-ka/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ka/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"ფაილის ტიპი"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"ეს ფაილი დაცულია"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"პაროლი"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"პაროლი არასწორია"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"გაუქმება"</string>
+ <string name="button_open" msgid="5445014062438566842">"გახსნა"</string>
+ <string name="desc_password" msgid="6636473611443746739">"პაროლის ველი"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"პაროლი არასწორია"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"პაროლი არასწორია"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>-დან"</string>
<string name="desc_page_single" msgid="8459583146661044094">"გვერდი <xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>-დან"</string>
<string name="desc_zoom" msgid="7318480946145947242">"მასშტაბი <xliff:g id="FIRST">%1$d</xliff:g> პროცენტი"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"<xliff:g id="PAGE_NUMBER">%1$d</xliff:g>-ე გვერდზე გადასვლა"</string>
<string name="desc_page" msgid="5684226167093594168">"გვერდი <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"კომენტარის განსათავსებლად მონიშნეთ ტექსტი"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"შეეხეთ ველს კომენტარის დასატოვებლად"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"გაუქმება"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF-ის ჩვენება შეუძლებელია (<xliff:g id="TITLE">%1$s</xliff:g> არასწორ ფორმატშია)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"გვერდის ჩვენება შეუძლებელია <xliff:g id="PAGE">%1$d</xliff:g> (ფაილის შეცდომა)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"ამ ერთეულისთვის ანოტაციის რეჟიმის ჩატვირთვა არ არის შესაძლებელი."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"ბმული: ვებგვერდი <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"ბმული: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"ელფოსტა: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"ტელეფონის ნომერი: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"არჩევანის დასაწყისი"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"არჩევანის დასასრული"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>-დან"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-kk/strings.xml b/pdf/pdf-viewer/src/main/res/values-kk/strings.xml
index 678c988..27917cf 100644
--- a/pdf/pdf-viewer/src/main/res/values-kk/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-kk/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Файл түрі"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Бұл файл қорғалған"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Құпия сөз"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Құпия сөз қате"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Бас тарту"</string>
+ <string name="button_open" msgid="5445014062438566842">"Ашу"</string>
+ <string name="desc_password" msgid="6636473611443746739">"құпия сөз өрісі"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"құпия сөз қате"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"құпия сөз қате"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"Бет: <xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"<xliff:g id="FIRST">%1$d</xliff:g> пайызға масштабтау"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"<xliff:g id="PAGE_NUMBER">%1$d</xliff:g>-бетке өтіңіз."</string>
<string name="desc_page" msgid="5684226167093594168">"<xliff:g id="PAGE">%1$d</xliff:g>-бет"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Пікір қалдыру үшін мәтін таңдаңыз."</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Пікір қалдыру үшін аймақты түртіңіз."</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Бас тарту"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF файлын көрсету мүмкін емес (<xliff:g id="TITLE">%1$s</xliff:g> форматы жарамсыз)."</string>
+ <string name="error_on_page" msgid="1592475819957182385">"<xliff:g id="PAGE">%1$d</xliff:g>-бетті көрсету мүмкін емес (файл қатесі)."</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Бұл элемент үшін aннотация режимін жүктеу мүмкін емес."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Сілтеме: <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> веб-беті"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Сілтеме: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Электрондық мекенжай: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Телефон: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"таңдалған мәтіннің басы"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"таңдалған мәтіннің соңы"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-kn/strings.xml b/pdf/pdf-viewer/src/main/res/values-kn/strings.xml
index dca93d4..eef4ed4 100644
--- a/pdf/pdf-viewer/src/main/res/values-kn/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-kn/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"ಫೈಲ್ ಪ್ರಕಾರ"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"ಈ ಫೈಲ್ ಅನ್ನು ಸಂರಕ್ಷಿಸಲಾಗಿದೆ"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"ಪಾಸ್ವರ್ಡ್"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"ಪಾಸ್ವರ್ಡ್ ತಪ್ಪಾಗಿದೆ"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"ರದ್ದುಮಾಡಿ"</string>
+ <string name="button_open" msgid="5445014062438566842">"ತೆರೆಯಿರಿ"</string>
+ <string name="desc_password" msgid="6636473611443746739">"ಪಾಸ್ವರ್ಡ್ ಫೀಲ್ಡ್"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"ಪಾಸ್ವರ್ಡ್ ತಪ್ಪಾಗಿದೆ"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"ಪಾಸ್ವರ್ಡ್ ತಪ್ಪಾಗಿದೆ"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="TOTAL">%2$d</xliff:g> ರಲ್ಲಿ <xliff:g id="PAGE">%1$d</xliff:g> ಪುಟ"</string>
<string name="desc_zoom" msgid="7318480946145947242">"ಶೇಕಡಾ <xliff:g id="FIRST">%1$d</xliff:g> ರಷ್ಟು ಝೂಮ್ ಮಾಡಿ"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"ಪುಟ <xliff:g id="PAGE_NUMBER">%1$d</xliff:g> ಕ್ಕೆ ತೆರಳಿ"</string>
<string name="desc_page" msgid="5684226167093594168">"ಪುಟ <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"ನಿಮ್ಮ ಕಾಮೆಂಟ್ ಅನ್ನು ಇರಿಸಲು ಪಠ್ಯವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"ಕಾಮೆಂಟ್ ಮಾಡಲು ಪ್ರದೇಶವನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"ರದ್ದುಮಾಡಿ"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF ಅನ್ನು ಪ್ರದರ್ಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ (<xliff:g id="TITLE">%1$s</xliff:g> ಅಮಾನ್ಯವಾದ ಫಾರ್ಮ್ಯಾಟ್ ಆಗಿದೆ)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"<xliff:g id="PAGE">%1$d</xliff:g> ಪುಟವನ್ನು ಪ್ರದರ್ಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ (ಫೈಲ್ ದೋಷ)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"ಈ ಐಟಂಗೆ ಟಿಪ್ಪಣಿಯನ್ನು ಲೋಡ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"ಲಿಂಕ್: <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> ನಲ್ಲಿರುವ ವೆಬ್ಪುಟ"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"ಲಿಂಕ್: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"ಇಮೇಲ್: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"ಫೋನ್: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"ಆಯ್ಕೆ ಪ್ರಾರಂಭ"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"ಆಯ್ಕೆ ಮುಕ್ತಾಯ"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ko/strings.xml b/pdf/pdf-viewer/src/main/res/values-ko/strings.xml
index c473a9f..f183833 100644
--- a/pdf/pdf-viewer/src/main/res/values-ko/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ko/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"파일 형식"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"보호된 파일임"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"비밀번호"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"비밀번호가 잘못됨"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"취소"</string>
+ <string name="button_open" msgid="5445014062438566842">"열기"</string>
+ <string name="desc_password" msgid="6636473611443746739">"비밀번호 입력란"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"비밀번호가 잘못됨"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"비밀번호가 잘못됨"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="TOTAL">%2$d</xliff:g>페이지 중 <xliff:g id="PAGE">%1$d</xliff:g>페이지"</string>
<string name="desc_zoom" msgid="7318480946145947242">"<xliff:g id="FIRST">%1$d</xliff:g>%% 확대/축소"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"<xliff:g id="PAGE_NUMBER">%1$d</xliff:g> 페이지로 이동"</string>
<string name="desc_page" msgid="5684226167093594168">"<xliff:g id="PAGE">%1$d</xliff:g>페이지"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"댓글을 달려는 텍스트를 선택하세요."</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"댓글을 달려는 영역을 탭하세요."</string>
+ <string name="action_cancel" msgid="5494417739210197522">"취소"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"<xliff:g id="TITLE">%1$s</xliff:g>의 형식이 잘못되어 PDF를 표시할 수 없음"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"파일 오류로 <xliff:g id="PAGE">%1$d</xliff:g> 페이지를 표시할 수 없음"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"이 항목에 대한 주석 모드를 로드할 수 없습니다."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"링크: <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>의 웹페이지"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"링크: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"이메일: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"전화번호: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"선택 영역 시작"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"선택 영역 끝"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>~<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-lt/strings.xml b/pdf/pdf-viewer/src/main/res/values-lt/strings.xml
index ca512f2..6742411 100644
--- a/pdf/pdf-viewer/src/main/res/values-lt/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-lt/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Failo tipas"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Šis failas yra apsaugotas"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Slaptažodis"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Slaptažodis netinkamas"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Atšaukti"</string>
+ <string name="button_open" msgid="5445014062438566842">"Atidaryti"</string>
+ <string name="desc_password" msgid="6636473611443746739">"slaptažodžio laukas"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"slaptažodis netinkamas"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"slaptažodis netinkamas"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> iš <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="PAGE">%1$d</xliff:g> psl. iš <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"keisti mastelį <xliff:g id="FIRST">%1$d</xliff:g> proc."</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Eiti į <xliff:g id="PAGE_NUMBER">%1$d</xliff:g> puslapį"</string>
<string name="desc_page" msgid="5684226167093594168">"<xliff:g id="PAGE">%1$d</xliff:g> psl."</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Pasirinkite tekstą, kad pateiktumėte komentarą"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Palieskite komentuotiną sritį"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Atšaukti"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Negalima pateikti PDF („<xliff:g id="TITLE">%1$s</xliff:g>“ netinkamo formato)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Negalima pateikti <xliff:g id="PAGE">%1$d</xliff:g> puslapio (failo klaida)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Nepavyko įkelti šio elemento komentaro režimo."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Nuoroda: tinklalapis adresu <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Nuoroda: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"El. pašto adresas: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Telefono numeris: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"pasirinkimo pradžia"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"pasirinkimo pabaiga"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g> iš <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-lv/strings.xml b/pdf/pdf-viewer/src/main/res/values-lv/strings.xml
index 6807178..00d9d40 100644
--- a/pdf/pdf-viewer/src/main/res/values-lv/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-lv/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Faila tips"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Šis fails ir aizsargāts"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Parole"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Parole nav pareiza"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Atcelt"</string>
+ <string name="button_open" msgid="5445014062438566842">"Atvērt"</string>
+ <string name="desc_password" msgid="6636473611443746739">"paroles lauks"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"parole nav pareiza"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"parole nav pareiza"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="PAGE">%1$d</xliff:g>. lapa no <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"tālummaiņa procentos ir <xliff:g id="FIRST">%1$d</xliff:g>"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Doties uz <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>. lapu"</string>
<string name="desc_page" msgid="5684226167093594168">"<xliff:g id="PAGE">%1$d</xliff:g>. lapa"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Atlasiet tekstu, lai pievienotu komentāru"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Pieskarieties komentējamajam apgabalam"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Atcelt"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Nevar parādīt PDF (faila “<xliff:g id="TITLE">%1$s</xliff:g>” formāts nav derīgs)."</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Nevar parādīt <xliff:g id="PAGE">%1$d</xliff:g>. lapu (faila kļūda)."</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Šim vienumam nevar ielādēt anotēšanas režīmu."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Saite: tīmekļa lapa domēnā <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Saite: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"E-pasta adrese: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Tālruņa numurs: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"atlases sākums"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"atlases beigas"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-mk/strings.xml b/pdf/pdf-viewer/src/main/res/values-mk/strings.xml
index 2c8826b..d128f84 100644
--- a/pdf/pdf-viewer/src/main/res/values-mk/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-mk/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Вид датотека"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Датотекава е заштитена"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Лозинка"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Лозинката е неточна"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Откажи"</string>
+ <string name="button_open" msgid="5445014062438566842">"Отвори"</string>
+ <string name="desc_password" msgid="6636473611443746739">"поле за лозинка"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"лозинката е неточна"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"лозинката е неточна"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"страница <xliff:g id="PAGE">%1$d</xliff:g> од <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"зумирајте <xliff:g id="FIRST">%1$d</xliff:g> проценти"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Одете на страницата <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"страница <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Изберете текст за поставување на коментарот"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Допрете област за која ќе коментирате"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Откажи"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Не може да се прикаже PDF (<xliff:g id="TITLE">%1$s</xliff:g> е со неважечки формат)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Не може да се прикаже страницата <xliff:g id="PAGE">%1$d</xliff:g> (грешка во датотеката)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Не може да се вчита „Режимот за прибелешки“ за ставкава."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Линк: веб-страница на <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Линк: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Е-пошта: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Телефон: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"почеток на изборот"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"крај на изборот"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> – <xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-mn/strings.xml b/pdf/pdf-viewer/src/main/res/values-mn/strings.xml
index aacb03b..e746e33 100644
--- a/pdf/pdf-viewer/src/main/res/values-mn/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-mn/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Файлын төрөл"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Энэ файл хамгаалагдсан"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Нууц үг"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Нууц үг буруу байна"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Цуцлах"</string>
+ <string name="button_open" msgid="5445014062438566842">"Нээх"</string>
+ <string name="desc_password" msgid="6636473611443746739">"нууц үгний талбар"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"нууц үг буруу байна"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"нууц үг буруу байна"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="TOTAL">%2$d</xliff:g>-н <xliff:g id="PAGE">%1$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="TOTAL">%2$d</xliff:g>-н <xliff:g id="PAGE">%1$d</xliff:g>-р хуудас"</string>
<string name="desc_zoom" msgid="7318480946145947242">"<xliff:g id="FIRST">%1$d</xliff:g> хувь томруулсан"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"<xliff:g id="PAGE_NUMBER">%1$d</xliff:g>-р хуудсанд очих"</string>
<string name="desc_page" msgid="5684226167093594168">"<xliff:g id="PAGE">%1$d</xliff:g>-р хуудас"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Сэтгэгдлээ байрлуулахын тулд текст сонгоно уу"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Сэтгэгдэл бичих хэсэг дээр товшино уу"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Цуцлах"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF-г үзүүлэх боломжгүй (<xliff:g id="TITLE">%1$s</xliff:g>-н формат буруу байна)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"<xliff:g id="PAGE">%1$d</xliff:g> хуудсыг үзүүлэх боломжгүй (файлын алдаа)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Энэ зүйлд тэмдэглэгээний горимыг ачаалах боломжгүй."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Холбоос: <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> дээрх веб хуудас"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Холбоос: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Имэйл: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Утас: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"сонголтын эхлэл"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"сонголтын төгсгөл"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-mr/strings.xml b/pdf/pdf-viewer/src/main/res/values-mr/strings.xml
index 1d11dc7..4da35f6 100644
--- a/pdf/pdf-viewer/src/main/res/values-mr/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-mr/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"फाइल प्रकार"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"ही फाइल संरक्षित आहे"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"पासवर्ड"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"पासवर्ड चुकीचा आहे"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"रद्द करा"</string>
+ <string name="button_open" msgid="5445014062438566842">"उघडा"</string>
+ <string name="desc_password" msgid="6636473611443746739">"पासवर्ड फील्ड"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"पासवर्ड चुकीचा आहे"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"पासवर्ड चुकीचा आहे"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="TOTAL">%2$d</xliff:g> पैकी पेज <xliff:g id="PAGE">%1$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"<xliff:g id="FIRST">%1$d</xliff:g> टक्के झूम करा"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"पेज <xliff:g id="PAGE_NUMBER">%1$d</xliff:g> वर जा"</string>
<string name="desc_page" msgid="5684226167093594168">"पेज <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"तुमच्या टिप्पणी ठेवण्यासाठी मजकूर निवडा"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"टिप्पणी करायच्या क्षेत्रावर टॅप करा"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"रद्द करा"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF दाखवू शकत नाही (<xliff:g id="TITLE">%1$s</xliff:g> चा फॉरमॅट चुकीचा आहे)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"<xliff:g id="PAGE">%1$d</xliff:g> पेज दाखवू शकत नाही (फाइल एरर)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"या आयटमसाठी भाष्य मोड लोड करू शकत नाही."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"लिंक: <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> वरील वेबपेज"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"लिंक: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"ईमेल: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"फोन: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"निवडणे सुरू करा"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"निवडणे संपवा"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-my/strings.xml b/pdf/pdf-viewer/src/main/res/values-my/strings.xml
index dbeac1d..085401d 100644
--- a/pdf/pdf-viewer/src/main/res/values-my/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-my/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"ဖိုင်အမျိုးအစား"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"ဤဖိုင်ကို ကာကွယ်ထားသည်"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"စကားဝှက်"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"စကားဝှက် မှားနေသည်"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"မလုပ်တော့"</string>
+ <string name="button_open" msgid="5445014062438566842">"ဖွင့်ရန်"</string>
+ <string name="desc_password" msgid="6636473611443746739">"စကားဝှက်ထည့်ရန် အကွက်"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"စကားဝှက် မှားနေသည်"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"စကားဝှက် မှားနေသည်"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"စာမျက်နှာ <xliff:g id="TOTAL">%2$d</xliff:g> အနက် <xliff:g id="PAGE">%1$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"ဇူးမ် <xliff:g id="FIRST">%1$d</xliff:g> ရာခိုင်နှုန်း"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"စာမျက်နှာ <xliff:g id="PAGE_NUMBER">%1$d</xliff:g> သို့"</string>
<string name="desc_page" msgid="5684226167093594168">"စာမျက်နှာ <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"သင်၏မှတ်ချက်ထည့်ရန် စာသားကို ရွေးပါ"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"မှတ်ချက်ပေးရန် နေရာကို တို့ပါ"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"မလုပ်တော့"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF ကို ပြ၍မရပါ (<xliff:g id="TITLE">%1$s</xliff:g> သည် မမှန်ကန်သော ဖော်မက်ဖြစ်သည်)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"စာမျက်နှာ <xliff:g id="PAGE">%1$d</xliff:g> ကို ပြ၍မရပါ (ဖိုင်အမှား)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"ဤအကြောင်းအရာအတွက် မှတ်ချက်မုဒ် ဖွင့်၍မရပါ။"</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"လင့်ခ်- <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> ရှိ ဝဘ်စာမျက်နှာ"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"လင့်ခ်- <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"အီးမေးလ်- <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"ဖုန်း- <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"ရွေးချယ်မှုအစ"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"ရွေးချယ်မှုအဆုံး"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-nb/strings.xml b/pdf/pdf-viewer/src/main/res/values-nb/strings.xml
index 189acf8..c1c2c18 100644
--- a/pdf/pdf-viewer/src/main/res/values-nb/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-nb/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Filtype"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Denne filen er beskyttet"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Passord"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Passordet er feil"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Avbryt"</string>
+ <string name="button_open" msgid="5445014062438566842">"Åpne"</string>
+ <string name="desc_password" msgid="6636473611443746739">"passordfelt"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"feil passord"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"feil passord"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"side <xliff:g id="PAGE">%1$d</xliff:g> av <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> prosent"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Gå til side <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"side <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Merk tekst for å sette inn kommentaren din"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Trykk på et område du vil kommentere"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Avbryt"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Kan ikke vise PDF-filen (<xliff:g id="TITLE">%1$s</xliff:g> har ugyldig format)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Kan ikke vise side <xliff:g id="PAGE">%1$d</xliff:g> (filfeil)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Kan ikke laste inn annoteringsmodus for dette elementet."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: nettside på <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"E-postadresse: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Telefonnummer: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"starten av utvalget"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"slutten av utvalget"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-nl/strings.xml b/pdf/pdf-viewer/src/main/res/values-nl/strings.xml
index caadce5..cf1802a 100644
--- a/pdf/pdf-viewer/src/main/res/values-nl/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-nl/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Bestandstype"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Dit bestand is beveiligd"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Wachtwoord"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Wachtwoord is onjuist"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Annuleren"</string>
+ <string name="button_open" msgid="5445014062438566842">"Openen"</string>
+ <string name="desc_password" msgid="6636473611443746739">"wachtwoordveld"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"wachtwoord is onjuist"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"wachtwoord is onjuist"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"pagina <xliff:g id="PAGE">%1$d</xliff:g> van <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> procent"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Ga naar pagina <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"pagina <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Selecteer tekst om je reactie te plaatsen"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Tik op een gedeelte waarop je wilt reageren"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Annuleren"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Kan pdf niet weergeven (indeling van <xliff:g id="TITLE">%1$s</xliff:g> is ongeldig)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Kan pagina <xliff:g id="PAGE">%1$d</xliff:g> niet weergeven (bestandsfout)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Kan de annotatiemodus voor dit item niet laden."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: webpagina op <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"E-mail: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Telefoonnummer: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"begin selectie"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"einde selectie"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-pa/strings.xml b/pdf/pdf-viewer/src/main/res/values-pa/strings.xml
index 7579ef3..284fce6 100644
--- a/pdf/pdf-viewer/src/main/res/values-pa/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-pa/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"ਫ਼ਾਈਲ ਦੀ ਕਿਸਮ"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"ਇਹ ਫ਼ਾਈਲ ਸੁਰੱਖਿਅਤ ਹੈ"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"ਪਾਸਵਰਡ"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"ਪਾਸਵਰਡ ਗਲਤ ਹੈ"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"ਰੱਦ ਕਰੋ"</string>
+ <string name="button_open" msgid="5445014062438566842">"ਖੋਲ੍ਹੋ"</string>
+ <string name="desc_password" msgid="6636473611443746739">"ਪਾਸਵਰਡ ਖੇਤਰ"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"ਪਾਸਵਰਡ ਗਲਤ ਹੈ"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"ਪਾਸਵਰਡ ਗਲਤ ਹੈ"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="TOTAL">%2$d</xliff:g> ਵਿੱਚੋਂ <xliff:g id="PAGE">%1$d</xliff:g> ਪੰਨਾ"</string>
<string name="desc_zoom" msgid="7318480946145947242">"ਜ਼ੂਮ <xliff:g id="FIRST">%1$d</xliff:g> ਫ਼ੀਸਦ"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"<xliff:g id="PAGE_NUMBER">%1$d</xliff:g> ਪੰਨੇ \'ਤੇ ਜਾਓ"</string>
<string name="desc_page" msgid="5684226167093594168">"ਪੰਨਾ <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"ਆਪਣੀ ਟਿੱਪਣੀ ਕਰਨ ਲਈ ਲਿਖਤ ਨੂੰ ਚੁਣੋ"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"ਟਿੱਪਣੀ ਕਰਨ ਲਈ ਕਿਸੇ ਖੇਤਰ \'ਤੇ ਟੈਪ ਕਰੋ"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"ਰੱਦ ਕਰੋ"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF ਨੂੰ ਦਿਖਾਇਆ ਨਹੀਂ ਜਾ ਸਕਦਾ (<xliff:g id="TITLE">%1$s</xliff:g> ਅਵੈਧ ਫਾਰਮੈਟ ਦਾ ਹੈ)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"<xliff:g id="PAGE">%1$d</xliff:g> ਪੰਨੇ ਨੂੰ ਦਿਖਾਇਆ ਨਹੀਂ ਜਾ ਸਕਦਾ (ਫ਼ਾਈਲ ਗੜਬੜ)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"ਇਸ ਆਈਟਮ ਲਈ ਐਨੋਟੇਸ਼ਨ ਮੋਡ ਨੂੰ ਲੋਡ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ।"</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"ਲਿੰਕ: ਵੈੱਬ-ਪੰਨਾ <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> \'ਤੇ ਹੈ"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"ਲਿੰਕ: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"ਈਮੇਲ: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"ਫ਼ੋਨ ਨੰਬਰ: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"ਚੁਣੀ ਲਿਖਤ ਦਾ ਸ਼ੁਰੂਆਤੀ ਸਿਰਾ"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"ਚੁਣੀ ਲਿਖਤ ਦਾ ਆਖਰੀ ਸਿਰਾ"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-pt-rBR/strings.xml b/pdf/pdf-viewer/src/main/res/values-pt-rBR/strings.xml
index 42e6c8c..439ec80 100644
--- a/pdf/pdf-viewer/src/main/res/values-pt-rBR/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-pt-rBR/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Tipo de arquivo"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Este arquivo está protegido"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Senha"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Senha incorreta"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Cancelar"</string>
+ <string name="button_open" msgid="5445014062438566842">"Abrir"</string>
+ <string name="desc_password" msgid="6636473611443746739">"campo senha"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"senha incorreta"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"senha incorreta"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"página <xliff:g id="PAGE">%1$d</xliff:g> de <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"zoom de <xliff:g id="FIRST">%1$d</xliff:g>%%"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Ir para a página <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"página <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Selecione o texto para inserir seu comentário"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Toque em uma área para comentar"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Cancelar"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Não é possível mostrar o PDF (<xliff:g id="TITLE">%1$s</xliff:g>: formato inválido)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Não é possível mostrar a página <xliff:g id="PAGE">%1$d</xliff:g> (erro de arquivo)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Não foi possível carregar o modo de anotação deste item."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: página da Web de <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"E-mail: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Telefone: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"início da seleção"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"fim da seleção"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> a <xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-pt/strings.xml b/pdf/pdf-viewer/src/main/res/values-pt/strings.xml
index 42e6c8c..439ec80 100644
--- a/pdf/pdf-viewer/src/main/res/values-pt/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-pt/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Tipo de arquivo"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Este arquivo está protegido"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Senha"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Senha incorreta"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Cancelar"</string>
+ <string name="button_open" msgid="5445014062438566842">"Abrir"</string>
+ <string name="desc_password" msgid="6636473611443746739">"campo senha"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"senha incorreta"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"senha incorreta"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"página <xliff:g id="PAGE">%1$d</xliff:g> de <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"zoom de <xliff:g id="FIRST">%1$d</xliff:g>%%"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Ir para a página <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"página <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Selecione o texto para inserir seu comentário"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Toque em uma área para comentar"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Cancelar"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Não é possível mostrar o PDF (<xliff:g id="TITLE">%1$s</xliff:g>: formato inválido)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Não é possível mostrar a página <xliff:g id="PAGE">%1$d</xliff:g> (erro de arquivo)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Não foi possível carregar o modo de anotação deste item."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: página da Web de <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"E-mail: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Telefone: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"início da seleção"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"fim da seleção"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> a <xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ro/strings.xml b/pdf/pdf-viewer/src/main/res/values-ro/strings.xml
index 25f3894..ca17732 100644
--- a/pdf/pdf-viewer/src/main/res/values-ro/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ro/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Tip de fișier"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Acest fișier este protejat"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Parolă"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Parolă incorectă"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Anulează"</string>
+ <string name="button_open" msgid="5445014062438566842">"Deschide"</string>
+ <string name="desc_password" msgid="6636473611443746739">"câmpul pentru parolă"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"parolă incorectă"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"parolă incorectă"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"pagina <xliff:g id="PAGE">%1$d</xliff:g> din <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"zoom de <xliff:g id="FIRST">%1$d</xliff:g> %%"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Accesează pagina <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"pagina <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Selectează textul pentru a comenta"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Atinge o zonă pentru a comenta"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Anulează"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Nu se poate afișa ca PDF (<xliff:g id="TITLE">%1$s</xliff:g> are un format nevalid)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Nu se poate afișa pagina <xliff:g id="PAGE">%1$d</xliff:g> (eroare de fișier)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Nu se poate încărca modul de adnotare pentru acest element."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: pagina web de la <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"E-mail: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Telefon: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"începutul selecției"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"sfârșitul selecției"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-si/strings.xml b/pdf/pdf-viewer/src/main/res/values-si/strings.xml
index 79a1229..23cd51b 100644
--- a/pdf/pdf-viewer/src/main/res/values-si/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-si/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"ගොනු වර්ගය"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"මෙම ගොනුව ආරක්ෂා කර ඇත"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"මුරපදය"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"මුරපදය වැරදියි"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"අවලංගු කරන්න"</string>
+ <string name="button_open" msgid="5445014062438566842">"විවෘත කරන්න"</string>
+ <string name="desc_password" msgid="6636473611443746739">"මුරපද ක්ෂේත්රය"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"මුරපදය වැරදියි"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"මුරපදය වැරදියි"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="TOTAL">%2$d</xliff:g> න් <xliff:g id="PAGE">%1$d</xliff:g> වෙනි පිටුව"</string>
<string name="desc_zoom" msgid="7318480946145947242">"විශාලනය සියයට <xliff:g id="FIRST">%1$d</xliff:g>"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"<xliff:g id="PAGE_NUMBER">%1$d</xliff:g> වෙනි පිටුවට යන්න"</string>
<string name="desc_page" msgid="5684226167093594168">"පිටුව <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"ඔබේ අදහස තැබීමට පෙළ තෝරන්න"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"අදහස් දැක්වීමට ප්රදේශයක් තට්ටු කරන්න"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"අවලංගු කරන්න"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF සංදර්ශනය කළ නොහැක (<xliff:g id="TITLE">%1$s</xliff:g> අවලංගු ආකෘතියකි)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"පිටුව සංදර්ශනය කළ නොහැක <xliff:g id="PAGE">%1$d</xliff:g> (ගොනු දෝෂය)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"මෙම අයිතමය සඳහා අනුසටහන් ප්රකාරය පූරණය කළ නොහැක."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"සබැඳිය: <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> හි දී වෙබ් පිටුව"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"සබැඳිය: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"ඉ-තැපෑල: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"දුරකථනය: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"තේරීම ආරම්භය"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"තේරීම අවසානය"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-sq/strings.xml b/pdf/pdf-viewer/src/main/res/values-sq/strings.xml
index b478e0c..caebc77 100644
--- a/pdf/pdf-viewer/src/main/res/values-sq/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-sq/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Lloji i skedarit"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Ky skedar është i mbrojtur."</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Fjalëkalimi"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Fjalëkalimi është i pasaktë"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Anulo"</string>
+ <string name="button_open" msgid="5445014062438566842">"Hap"</string>
+ <string name="desc_password" msgid="6636473611443746739">"fusha e fjalëkalimit"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"fjalëkalimi është i pasaktë"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"fjalëkalimi është i pasaktë"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"faqja <xliff:g id="PAGE">%1$d</xliff:g> nga <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"zmadho me <xliff:g id="FIRST">%1$d</xliff:g> për qind"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Shko te faqja <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"faqja <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Zgjidh tekstin për të vendosur komentin"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Trokit te një zonë për të komentuar"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Anulo"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Skedari PDF nuk mund të shfaqet (\"<xliff:g id="TITLE">%1$s</xliff:g>\" ka format të pavlefshëm)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Nuk mund të shfaqet faqja <xliff:g id="PAGE">%1$d</xliff:g> (gabim i skedarit)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Modaliteti i shënimit nuk mund të ngarkohet për këtë artikull."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Lidhja: faqe uebi te <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Lidhja: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Email-i: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Telefoni: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"fillimi i përzgjedhjes"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"fundi i përzgjedhjes"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-sv/strings.xml b/pdf/pdf-viewer/src/main/res/values-sv/strings.xml
index 925f7d9..99b7d55 100644
--- a/pdf/pdf-viewer/src/main/res/values-sv/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-sv/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Filtyp"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Den här filen är skyddad"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Lösenord"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Felaktigt lösenord"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Avbryt"</string>
+ <string name="button_open" msgid="5445014062438566842">"Öppna"</string>
+ <string name="desc_password" msgid="6636473611443746739">"lösenordsfält"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"felaktigt lösenord"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"felaktigt lösenord"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"sida <xliff:g id="PAGE">%1$d</xliff:g> av <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"zooma <xliff:g id="FIRST">%1$d</xliff:g> procent"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Öppna sidan <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"sida <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Markera text för att kommentera"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Tryck på ett område för att kommentera"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Avbryt"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Det går inte att visa PDF-filen (<xliff:g id="TITLE">%1$s</xliff:g> har ett ogiltigt format)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Det går inte att visa sidan <xliff:g id="PAGE">%1$d</xliff:g> (filfel)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Det gick inte att läsa in kommentarsläget för det här objektet."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Länk: webbsida på <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Länk: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"E-postadress: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Telefonnummer: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"textmarkeringens början"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"textmarkeringens slut"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ta/strings.xml b/pdf/pdf-viewer/src/main/res/values-ta/strings.xml
index c2f1606..63788a8 100644
--- a/pdf/pdf-viewer/src/main/res/values-ta/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ta/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"ஃபைல் வகை"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"இந்த ஃபைல் பாதுகாக்கப்பட்டுள்ளது"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"கடவுச்சொல்"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"கடவுச்சொல் தவறானது"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"ரத்துசெய்"</string>
+ <string name="button_open" msgid="5445014062438566842">"திற"</string>
+ <string name="desc_password" msgid="6636473611443746739">"கடவுச்சொல் புலம்"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"கடவுச்சொல் தவறானது"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"கடவுச்சொல் தவறானது"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"பக்கம் <xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"<xliff:g id="FIRST">%1$d</xliff:g> சதவீத அளவை மாற்று"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"பக்கம் <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>க்கு செல்லும்"</string>
<string name="desc_page" msgid="5684226167093594168">"பக்கம் <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"கருத்து வழங்க வார்த்தையைத் தேர்ந்தெடுக்கவும்"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"கருத்து வழங்குவதற்கான பகுதியைத் தட்டவும்"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"ரத்துசெய்"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"PDFஐக் காட்ட முடியவில்லை (<xliff:g id="TITLE">%1$s</xliff:g> தவறான வடிவத்தில் உள்ளது)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"பக்கம் <xliff:g id="PAGE">%1$d</xliff:g>ஐக் காட்ட முடியவில்லை (ஃபைல் பிழை)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"இதற்கான விரிவுரைப் பயன்முறையை ஏற்ற முடியவில்லை."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"இணைப்பு: <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> இல் உள்ள இணையப் பக்கம்"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"இணைப்பு: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"மின்னஞ்சல்: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"ஃபோன் எண்: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"தேர்வுசெய்த வார்த்தையின் தொடக்கம்"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"தேர்வுசெய்த வார்த்தையின் முடிவு"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-tr/strings.xml b/pdf/pdf-viewer/src/main/res/values-tr/strings.xml
index e789a8a..db0c86c7 100644
--- a/pdf/pdf-viewer/src/main/res/values-tr/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-tr/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Dosya türü"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Bu dosya korunuyor"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Şifre"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Şifre yanlış"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"İptal"</string>
+ <string name="button_open" msgid="5445014062438566842">"Aç"</string>
+ <string name="desc_password" msgid="6636473611443746739">"şifre alanı"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"şifre yanlış"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"şifre yanlış"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"sayfa <xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"yakınlaştırma yüzdesi <xliff:g id="FIRST">%1$d</xliff:g>"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Şu sayfaya git <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"sayfa <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Yorumunuzu yerleştireceğiniz metni seçin"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Hakkında yorum yapacağınız alana dokunun"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"İptal"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF görüntülenemiyor (<xliff:g id="TITLE">%1$s</xliff:g> geçersiz biçimde)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"<xliff:g id="PAGE">%1$d</xliff:g>. sayfa görüntülenemiyor (dosya hatası)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Bu öğe için ek açıklama modu yüklenemiyor."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Bağlantı: <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> alan adındaki web sayfası"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Bağlantı: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"E-posta gönder: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Telefon: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"seçim başlangıcı"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"seçim sonu"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-uk/strings.xml b/pdf/pdf-viewer/src/main/res/values-uk/strings.xml
index de608a9..216d16c 100644
--- a/pdf/pdf-viewer/src/main/res/values-uk/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-uk/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Тип файлу"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Цей файл захищено"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Пароль"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Неправильний пароль"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Скасувати"</string>
+ <string name="button_open" msgid="5445014062438566842">"Відкрити"</string>
+ <string name="desc_password" msgid="6636473611443746739">"поле пароля"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"неправильний пароль"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"неправильний пароль"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"сторінка <xliff:g id="PAGE">%1$d</xliff:g> з <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"масштаб <xliff:g id="FIRST">%1$d</xliff:g>%%"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Перейти на сторінку <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"сторінка <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Виділіть текст, щоб додати коментар"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Торкніться місця, яке хочете коментувати"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Скасувати"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Не вдається відобразити PDF (недійсний формат файлу \"<xliff:g id="TITLE">%1$s</xliff:g>\")"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Не вдається відобразити сторінку <xliff:g id="PAGE">%1$d</xliff:g> (помилка файлу)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Не вдається завантажити режим анотацій для цього об’єкта."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Посилання: вебсторінка в домені <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Посилання: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Електронна адреса: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Номер телефону: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"початок виділеного тексту"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"кінець виділеного тексту"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-uz/strings.xml b/pdf/pdf-viewer/src/main/res/values-uz/strings.xml
index 7ac1e17..2a6902f 100644
--- a/pdf/pdf-viewer/src/main/res/values-uz/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-uz/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Fayl turi"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Ushbu fayl himoyalangan"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Parol"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Parol xato"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Bekor qilish"</string>
+ <string name="button_open" msgid="5445014062438566842">"Ochish"</string>
+ <string name="desc_password" msgid="6636473611443746739">"parol maydonchasi"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"parol xato"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"parol xato"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"sahifa: <xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"zum: <xliff:g id="FIRST">%1$d</xliff:g> foiz"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"<xliff:g id="PAGE_NUMBER">%1$d</xliff:g>-sahifaga oʻtish"</string>
<string name="desc_page" msgid="5684226167093594168">"sahifa: <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Fikr bildirish uchun matnni tanlang."</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Fikr qoʻshish uchun biror maydonni bosing"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Bekor qilish"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF fayl koʻrsatilmaydi (<xliff:g id="TITLE">%1$s</xliff:g> yaroqsiz formatda)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"<xliff:g id="PAGE">%1$d</xliff:g>-sahifa koʻrsatilmaydi (fayl xatosi)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Bu obyekt uchun izoh rejimi yuklanmadi."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Havola: <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> sahifasi"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Havola: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Email: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Telefon: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"belgilashni boshlash"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"belgilashni yakunlash"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-vi/strings.xml b/pdf/pdf-viewer/src/main/res/values-vi/strings.xml
index 463515d..0f5033a 100644
--- a/pdf/pdf-viewer/src/main/res/values-vi/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-vi/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Loại tệp"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Tệp này đang được bảo vệ"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Mật khẩu"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Mật khẩu không chính xác"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Huỷ"</string>
+ <string name="button_open" msgid="5445014062438566842">"Mở"</string>
+ <string name="desc_password" msgid="6636473611443746739">"trường nhập mật khẩu"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"mật khẩu không chính xác"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"mật khẩu không chính xác"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"trang <xliff:g id="PAGE">%1$d</xliff:g> trong số <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"thu phóng <xliff:g id="FIRST">%1$d</xliff:g> phần trăm"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Chuyển đến trang <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"trang <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Chọn văn bản để đưa ra nhận xét"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Nhấn vào một khu vực để thêm nhận xét"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Huỷ"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Không hiển thị được tệp PDF (<xliff:g id="TITLE">%1$s</xliff:g> có định dạng không hợp lệ)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Không hiển thị được trang <xliff:g id="PAGE">%1$d</xliff:g> (lỗi tệp)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Không tải được chế độ chú giải cho mục này."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Đường liên kết: trang trên trang web <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Đường liên kết: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"Email: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Số điện thoại: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"đầu văn bản đã chọn"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"cuối văn bản đã chọn"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> – <xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-zh-rCN/strings.xml b/pdf/pdf-viewer/src/main/res/values-zh-rCN/strings.xml
index 57799bb..3094e5c 100644
--- a/pdf/pdf-viewer/src/main/res/values-zh-rCN/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-zh-rCN/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"文件类型"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"此文件受密码保护"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"密码"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"密码不正确"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"取消"</string>
+ <string name="button_open" msgid="5445014062438566842">"打开"</string>
+ <string name="desc_password" msgid="6636473611443746739">"密码字段"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"密码不正确"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"密码不正确"</string>
<string name="label_page_single" msgid="456123685879261101">"第 <xliff:g id="PAGE">%1$d</xliff:g> 页,共 <xliff:g id="TOTAL">%2$d</xliff:g> 页"</string>
<string name="desc_page_single" msgid="8459583146661044094">"第 <xliff:g id="PAGE">%1$d</xliff:g> 页,共 <xliff:g id="TOTAL">%2$d</xliff:g> 页"</string>
<string name="desc_zoom" msgid="7318480946145947242">"缩放比例为百分之 <xliff:g id="FIRST">%1$d</xliff:g>"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"前往第 <xliff:g id="PAGE_NUMBER">%1$d</xliff:g> 页"</string>
<string name="desc_page" msgid="5684226167093594168">"第 <xliff:g id="PAGE">%1$d</xliff:g> 页"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"选择要添加评论的文本"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"点按要添加评论的区域"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"取消"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"无法显示 PDF(“<xliff:g id="TITLE">%1$s</xliff:g>”的格式无效)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"无法显示第 <xliff:g id="PAGE">%1$d</xliff:g> 页(文件错误)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"无法为此内容加载注解模式。"</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"链接:位于 <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> 的网页"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"链接:<xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"电子邮件地址:<xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"电话号码:<xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"所选文本的开头"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"所选文本的结尾"</string>
<string name="label_page_range" msgid="8290964180158460076">"第 <xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> 页,共 <xliff:g id="TOTAL">%3$d</xliff:g> 页"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-zh-rHK/strings.xml b/pdf/pdf-viewer/src/main/res/values-zh-rHK/strings.xml
index 0711b16..34b36c0 100644
--- a/pdf/pdf-viewer/src/main/res/values-zh-rHK/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-zh-rHK/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"檔案類型"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"此檔案受到保護"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"密碼"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"密碼不正確"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"取消"</string>
+ <string name="button_open" msgid="5445014062438566842">"開啟"</string>
+ <string name="desc_password" msgid="6636473611443746739">"密碼欄位"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"密碼不正確"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"密碼不正確"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"第 <xliff:g id="PAGE">%1$d</xliff:g> 頁,共 <xliff:g id="TOTAL">%2$d</xliff:g> 頁"</string>
<string name="desc_zoom" msgid="7318480946145947242">"縮放 <xliff:g id="FIRST">%1$d</xliff:g>%%"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"前往第 <xliff:g id="PAGE_NUMBER">%1$d</xliff:g> 頁"</string>
<string name="desc_page" msgid="5684226167093594168">"第 <xliff:g id="PAGE">%1$d</xliff:g> 頁"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"選取文字以加入留言"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"輕按要加入留言的區域"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"取消"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"無法顯示 PDF (<xliff:g id="TITLE">%1$s</xliff:g> 格式無效)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"無法顯示第 <xliff:g id="PAGE">%1$d</xliff:g> 頁 (檔案錯誤)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"無法為此項目載入註釋模式。"</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"連結:位於 <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> 的網頁"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"連結:<xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"電郵地址:<xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"電話:<xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"選取開頭"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"選取結尾"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> - <xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-zh-rTW/strings.xml b/pdf/pdf-viewer/src/main/res/values-zh-rTW/strings.xml
index 1f08710..f836592 100644
--- a/pdf/pdf-viewer/src/main/res/values-zh-rTW/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-zh-rTW/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"檔案類型"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"這個檔案受密碼保護"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"密碼"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"密碼不正確"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"取消"</string>
+ <string name="button_open" msgid="5445014062438566842">"開啟"</string>
+ <string name="desc_password" msgid="6636473611443746739">"密碼欄位"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"密碼不正確"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"密碼不正確"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"第 <xliff:g id="PAGE">%1$d</xliff:g> 頁,共 <xliff:g id="TOTAL">%2$d</xliff:g> 頁"</string>
<string name="desc_zoom" msgid="7318480946145947242">"縮放 <xliff:g id="FIRST">%1$d</xliff:g>%%"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"前往第 <xliff:g id="PAGE_NUMBER">%1$d</xliff:g> 頁"</string>
<string name="desc_page" msgid="5684226167093594168">"第 <xliff:g id="PAGE">%1$d</xliff:g> 頁"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"選取要加註的文字"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"輕觸要加註的區域"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"取消"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"無法顯示 PDF (「<xliff:g id="TITLE">%1$s</xliff:g>」的格式無效)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"無法顯示第 <xliff:g id="PAGE">%1$d</xliff:g> 頁 (檔案錯誤)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"無法載入這個項目的註解模式。"</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"連結:位於 <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> 的網頁"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"連結:<xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"電子郵件地址:<xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"電話號碼:<xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"選取開頭"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"選取結尾"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> - <xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-zu/strings.xml b/pdf/pdf-viewer/src/main/res/values-zu/strings.xml
index 11347a3..103f045 100644
--- a/pdf/pdf-viewer/src/main/res/values-zu/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-zu/strings.xml
@@ -18,48 +18,29 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="desc_file_type" msgid="8918077960128045611">"Uhlobo lwefayela"</string>
- <!-- no translation found for title_dialog_password (2018068413709926925) -->
- <skip />
- <!-- no translation found for label_password_first (4456258714097111908) -->
- <skip />
- <!-- no translation found for label_password_incorrect (8449142641187704667) -->
- <skip />
- <!-- no translation found for button_cancel (5855794576957267334) -->
- <skip />
- <!-- no translation found for button_open (5445014062438566842) -->
- <skip />
- <!-- no translation found for desc_password (6636473611443746739) -->
- <skip />
- <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
- <skip />
- <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
- <skip />
+ <string name="title_dialog_password" msgid="2018068413709926925">"Leli fayela livikelwe"</string>
+ <string name="label_password_first" msgid="4456258714097111908">"Iphasiwedi"</string>
+ <string name="label_password_incorrect" msgid="8449142641187704667">"Iphasiwedi ayilungile"</string>
+ <string name="button_cancel" msgid="5855794576957267334">"Khansela"</string>
+ <string name="button_open" msgid="5445014062438566842">"Vula"</string>
+ <string name="desc_password" msgid="6636473611443746739">"inkambu yephasiwedi"</string>
+ <string name="desc_password_incorrect" msgid="4718823067483963845">"iphasiwedi ayilungile"</string>
+ <string name="desc_password_incorrect_message" msgid="4849541619951023025">"iphasiwedi ayilungile"</string>
<string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_page_single" msgid="8459583146661044094">"ikhasi <xliff:g id="PAGE">%1$d</xliff:g> kwangu-<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="desc_zoom" msgid="7318480946145947242">"sondeza iphesenti elingu-<xliff:g id="FIRST">%1$d</xliff:g>"</string>
- <!-- no translation found for desc_goto_link (2461368384824849714) -->
- <skip />
+ <string name="desc_goto_link" msgid="2461368384824849714">"Iya ekhasini <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
<string name="desc_page" msgid="5684226167093594168">"ikhasi <xliff:g id="PAGE">%1$d</xliff:g>"</string>
- <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
- <skip />
- <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
- <skip />
- <!-- no translation found for action_cancel (5494417739210197522) -->
- <skip />
- <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
- <skip />
- <!-- no translation found for error_on_page (1592475819957182385) -->
- <skip />
- <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
- <skip />
- <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
- <skip />
- <!-- no translation found for desc_web_link (2776023299237058419) -->
- <skip />
- <!-- no translation found for desc_email_link (7027325672358507448) -->
- <skip />
- <!-- no translation found for desc_phone_link (4986414958429253135) -->
- <skip />
+ <string name="message_select_text_to_comment" msgid="5725327644007067522">"Khetha umbhalo ukuze ubeke amazwana akho"</string>
+ <string name="message_tap_to_comment" msgid="7820801719181709999">"Thepha indawo ukuze ubeke amazwana kuyo"</string>
+ <string name="action_cancel" msgid="5494417739210197522">"Khansela"</string>
+ <string name="error_file_format_pdf" msgid="7567006188638831878">"Ayikwazi ukubonisa i-PDF (i-<xliff:g id="TITLE">%1$s</xliff:g> ingeyefomethi engavumelekile)"</string>
+ <string name="error_on_page" msgid="1592475819957182385">"Ayikwazi ukubonisa ikhasi elingu-<xliff:g id="PAGE">%1$d</xliff:g> (iphutha lefayela)"</string>
+ <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Ayikwazi ukulayisha imodi yesichasiselo yale nto."</string>
+ <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Ilinki: ikhasi lewebhu ku-<xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+ <string name="desc_web_link" msgid="2776023299237058419">"Ilinki: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+ <string name="desc_email_link" msgid="7027325672358507448">"I-imeyili: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+ <string name="desc_phone_link" msgid="4986414958429253135">"Ifoni: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
<string name="desc_selection_start" msgid="3249210022376857070">"isiqalo sokukhetha"</string>
<string name="desc_selection_stop" msgid="2690168835536726898">"isiphetho sokukhetha"</string>
<string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/playground-common/androidx-shared.properties b/playground-common/androidx-shared.properties
index 83e5c69..63f5783 100644
--- a/playground-common/androidx-shared.properties
+++ b/playground-common/androidx-shared.properties
@@ -47,7 +47,7 @@
# Generate versioned API files
androidx.writeVersionedApiFiles=true
-androidx.compileSdkVersion=android-34
+androidx.compileSdk=34
androidx.targetSdkVersion=34
# Disable features we do not use
diff --git a/privacysandbox/ads/ads-adservices-java/build.gradle b/privacysandbox/ads/ads-adservices-java/build.gradle
index 4ecece0..8548818 100644
--- a/privacysandbox/ads/ads-adservices-java/build.gradle
+++ b/privacysandbox/ads/ads-adservices-java/build.gradle
@@ -64,7 +64,8 @@
multiDexEnabled = true
}
- compileSdkVersion = "android-34-ext11"
+ compileSdk = 34
+ compileSdkExtension = 11
namespace "androidx.privacysandbox.ads.adservices.java"
}
diff --git a/privacysandbox/ads/ads-adservices/build.gradle b/privacysandbox/ads/ads-adservices/build.gradle
index 47b3f47..c18440f 100644
--- a/privacysandbox/ads/ads-adservices/build.gradle
+++ b/privacysandbox/ads/ads-adservices/build.gradle
@@ -58,7 +58,8 @@
multiDexEnabled = true
}
- compileSdkVersion = "android-34-ext11"
+ compileSdk = 34
+ compileSdkExtension = 11
namespace "androidx.privacysandbox.ads.adservices"
}
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/build.gradle b/privacysandbox/sdkruntime/sdkruntime-client/build.gradle
index f8c0828..6464bf3 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/build.gradle
+++ b/privacysandbox/sdkruntime/sdkruntime-client/build.gradle
@@ -145,7 +145,8 @@
}
namespace "androidx.privacysandbox.sdkruntime.client"
- compileSdkVersion = "android-34-ext10"
+ compileSdk = 34
+ compileSdkExtension = 10
}
androidx {
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/build.gradle b/privacysandbox/sdkruntime/sdkruntime-core/build.gradle
index 353e73e..d1cfc2e 100644
--- a/privacysandbox/sdkruntime/sdkruntime-core/build.gradle
+++ b/privacysandbox/sdkruntime/sdkruntime-core/build.gradle
@@ -56,7 +56,8 @@
}
namespace "androidx.privacysandbox.sdkruntime.core"
- compileSdkVersion = "android-34-ext10"
+ compileSdk = 34
+ compileSdkExtension = 10
}
androidx {
diff --git a/privacysandbox/sdkruntime/sdkruntime-provider/build.gradle b/privacysandbox/sdkruntime/sdkruntime-provider/build.gradle
index d83e35f..67a9568 100644
--- a/privacysandbox/sdkruntime/sdkruntime-provider/build.gradle
+++ b/privacysandbox/sdkruntime/sdkruntime-provider/build.gradle
@@ -44,7 +44,8 @@
android {
namespace "androidx.privacysandbox.sdkruntime.provider"
- compileSdkVersion = "android-34-ext10"
+ compileSdk = 34
+ compileSdkExtension = 10
}
androidx {
diff --git a/privacysandbox/tools/tools-apicompiler/build.gradle b/privacysandbox/tools/tools-apicompiler/build.gradle
index f1f5a3b..ec701e3 100644
--- a/privacysandbox/tools/tools-apicompiler/build.gradle
+++ b/privacysandbox/tools/tools-apicompiler/build.gradle
@@ -58,7 +58,7 @@
// Get AIDL compiler path and framework.aidl path and pass to tests for code generation.
def aidlCompilerPath = "${SdkHelperKt.getSdkPath(project)}/build-tools/$buildToolsVersion/aidl"
-def frameworkAidlPath = "${SdkHelperKt.getSdkPath(project)}/platforms/$compileSdk/framework.aidl"
+def frameworkAidlPath = "${SdkHelperKt.getSdkPath(project)}/platforms/android-$compileSdk/framework.aidl"
def testGeneratedSourcesPath = "${project.buildDir}/testGeneratedSources"
tasks.withType(Test).configureEach { test ->
test.inputs.files(aidlCompilerPath)
diff --git a/privacysandbox/tools/tools-apigenerator/build.gradle b/privacysandbox/tools/tools-apigenerator/build.gradle
index a6ba53c..b419d0b 100644
--- a/privacysandbox/tools/tools-apigenerator/build.gradle
+++ b/privacysandbox/tools/tools-apigenerator/build.gradle
@@ -28,6 +28,7 @@
plugins {
id("AndroidXPlugin")
id("kotlin")
+ id("com.github.johnrengelman.shadow")
}
androidx.configureAarAsJarForConfiguration("testImplementation")
@@ -35,11 +36,48 @@
def buildToolsVersion = AndroidXConfig.getDefaultAndroidConfig(project).getBuildToolsVersion()
def compileSdk = AndroidXConfig.getDefaultAndroidConfig(project).getCompileSdk()
+configurations {
+ // Configuration of shadowed / jarjared dependencies
+ shadowed
+ // Shadowed dependencies are compile only
+ compileOnly.extendsFrom(shadowed)
+ // Include shadowed dependencies for test compilation
+ testCompile.extendsFrom(shadowed)
+
+ // Replace the standard jar with the one built by 'shadowJar' in both api and runtime variants
+ apiElements.outgoing.artifacts.clear()
+ apiElements.outgoing.artifact(shadowJar) {
+ builtBy shadowJar
+ }
+ runtimeElements.outgoing.artifacts.clear()
+ runtimeElements.outgoing.artifact(shadowJar) {
+ builtBy shadowJar
+ }
+}
+
+shadowJar {
+ archiveClassifier = ""
+ configurations = [project.configurations.shadowed]
+ relocate("kotlinx.metadata", "androidx.privacysandbox.tools.kotlinx.metadata")
+ mergeServiceFiles() // kotlinx-metadata-jvm has a service descriptor that needs transformation
+ // Exclude Kotlin metadata files from kotlinx-metadata-jvm
+ exclude 'META-INF/kotlinx-metadata-jvm.kotlin_module'
+ exclude 'META-INF/kotlinx-metadata.kotlin_module'
+ exclude 'META-INF/metadata.jvm.kotlin_module'
+ exclude 'META-INF/metadata.kotlin_module'
+}
+
+jar {
+ archiveClassifier = "before-jarjar"
+}
+
dependencies {
api(libs.kotlinStdlib)
implementation(libs.asm)
implementation(libs.asmCommons)
- implementation(libs.kotlinMetadataJvm)
+ shadowed(libs.kotlinMetadataJvm) {
+ exclude group: "org.jetbrains.kotlin", module: "kotlin-stdlib"
+ }
implementation(libs.kotlinPoet)
implementation project(path: ':privacysandbox:tools:tools')
implementation project(path: ':privacysandbox:tools:tools-core')
@@ -55,6 +93,7 @@
testImplementationAarAsJar(project(":privacysandbox:sdkruntime:sdkruntime-client"))
testImplementationAarAsJar(project(":privacysandbox:sdkruntime:sdkruntime-core"))
testImplementation(libs.kotlinCoroutinesCore)
+ testImplementation(libs.kotlinMetadataJvm)
testImplementation(libs.junit)
testImplementation(libs.truth)
@@ -64,7 +103,7 @@
// Get AIDL compiler path and framework.aidl path and pass to tests for code generation.
def aidlCompilerPath = "${SdkHelperKt.getSdkPath(project)}/build-tools/$buildToolsVersion/aidl"
-def frameworkAidlPath = "${SdkHelperKt.getSdkPath(project)}/platforms/$compileSdk/framework.aidl"
+def frameworkAidlPath = "${SdkHelperKt.getSdkPath(project)}/platforms/android-$compileSdk/framework.aidl"
def testGeneratedSourcesPath = "${project.buildDir}/testGeneratedSources"
tasks.withType(Test).configureEach { test ->
test.inputs.files(aidlCompilerPath)
diff --git a/privacysandbox/tools/tools-core/build.gradle b/privacysandbox/tools/tools-core/build.gradle
index fbc42d4..666c58e 100644
--- a/privacysandbox/tools/tools-core/build.gradle
+++ b/privacysandbox/tools/tools-core/build.gradle
@@ -53,7 +53,7 @@
// Get AIDL compiler path and framework.aidl path and pass to tests for code generation.
def aidlCompilerPath = "${SdkHelperKt.getSdkPath(project)}/build-tools/$buildToolsVersion/aidl"
-def frameworkAidlPath = "${SdkHelperKt.getSdkPath(project)}/platforms/$compileSdk/framework.aidl"
+def frameworkAidlPath = "${SdkHelperKt.getSdkPath(project)}/platforms/android-$compileSdk/framework.aidl"
tasks.withType(Test).configureEach { test ->
test.inputs.files(aidlCompilerPath)
.withPropertyName("aidl_compiler_path")
diff --git a/room/integration-tests/incremental-annotation-processing/src/test/kotlin/androidx/room/gradle/RoomIncrementalAnnotationProcessingTest.kt b/room/integration-tests/incremental-annotation-processing/src/test/kotlin/androidx/room/gradle/RoomIncrementalAnnotationProcessingTest.kt
index 603cead..ae26317 100644
--- a/room/integration-tests/incremental-annotation-processing/src/test/kotlin/androidx/room/gradle/RoomIncrementalAnnotationProcessingTest.kt
+++ b/room/integration-tests/incremental-annotation-processing/src/test/kotlin/androidx/room/gradle/RoomIncrementalAnnotationProcessingTest.kt
@@ -161,6 +161,7 @@
ksp {
arg('room.incremental', '$withIncrementalRoom')
arg('room.schemaLocation', '${projectRoot.resolve(GEN_RES_DIR).canonicalPath}')
+ arg('room.generateKotlin', 'false')
}
""".trimIndent()
} else {
diff --git a/room/integration-tests/multiplatformtestapp/build.gradle b/room/integration-tests/multiplatformtestapp/build.gradle
index 2ec523d..a10ab82 100644
--- a/room/integration-tests/multiplatformtestapp/build.gradle
+++ b/room/integration-tests/multiplatformtestapp/build.gradle
@@ -129,5 +129,4 @@
schemaDirectory(
provider { layout.projectDirectory.dir("schemas-ksp").getAsFile().getAbsolutePath() }
)
- generateKotlin = true
}
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt
index 8c0aeb1..18ce9fa 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt
@@ -72,8 +72,20 @@
*/
private val xTypeName: XTypeName by lazy {
val jvmWildcardType = env.resolveWildcards(typeAlias ?: ksType, scope).let {
- if (it == ksType) {
- this
+ if (ksType == it) {
+ if (ksType.arguments != it.arguments) {
+ // Replacing the type arguments to retain the variances resolved in
+ // `resolveWildcards`. See https://github.com/google/ksp/issues/1778.
+ copy(
+ env = env,
+ ksType = ksType.replace(it.arguments),
+ originalKSAnnotations = originalKSAnnotations,
+ scope = scope,
+ typeAlias = typeAlias
+ )
+ } else {
+ this
+ }
} else {
env.wrap(
ksType = it,
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/Context.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/Context.kt
index 16cce2b..1e6377a 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/Context.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/Context.kt
@@ -31,7 +31,6 @@
import androidx.room.verifier.DatabaseVerifier
import androidx.room.vo.BuiltInConverterFlags
import androidx.room.vo.Warning
-import javax.tools.Diagnostic
class Context private constructor(
val processingEnv: XProcessingEnv,
@@ -86,17 +85,16 @@
}
val codeLanguage: CodeLanguage by lazy {
- if (BooleanProcessorOptions.GENERATE_KOTLIN.getValue(processingEnv)) {
- if (processingEnv.backend == XProcessingEnv.Backend.KSP) {
+ if (processingEnv.backend == XProcessingEnv.Backend.KSP) {
+ if (BooleanProcessorOptions.GENERATE_KOTLIN.getValue(processingEnv)) {
CodeLanguage.KOTLIN
} else {
- processingEnv.messager.printMessage(
- Diagnostic.Kind.ERROR,
- "${BooleanProcessorOptions.GENERATE_KOTLIN.argName} can only be enabled in KSP."
- )
CodeLanguage.JAVA
}
} else {
+ if (BooleanProcessorOptions.GENERATE_KOTLIN.getInputValue(processingEnv) == true) {
+ logger.e(ProcessorErrors.INVALID_KOTLIN_CODE_GEN_IN_JAVAC)
+ }
CodeLanguage.JAVA
}
}
@@ -287,7 +285,7 @@
INCREMENTAL("room.incremental", defaultValue = true),
EXPAND_PROJECTION("room.expandProjection", defaultValue = false),
USE_NULL_AWARE_CONVERTER("room.useNullAwareTypeAnalysis", defaultValue = false),
- GENERATE_KOTLIN("room.generateKotlin", defaultValue = false),
+ GENERATE_KOTLIN("room.generateKotlin", defaultValue = true),
EXPORT_SCHEMA_RESOURCE("room.exportSchemaResource", defaultValue = false);
/**
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
index 78e4106..2cdf066 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
@@ -1158,4 +1158,7 @@
val INVALID_BLOCKING_DAO_FUNCTION_NON_ANDROID = "Only suspend functions are allowed in DAOs" +
" declared in source sets targeting non-Android platforms."
+
+ val INVALID_KOTLIN_CODE_GEN_IN_JAVAC =
+ "${Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName} can only be enabled in KSP."
}
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/BaseEntityParserTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/BaseEntityParserTest.kt
index eff1336..e8f12f5 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/BaseEntityParserTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/BaseEntityParserTest.kt
@@ -65,6 +65,7 @@
code = ENTITY_PREFIX.format(attributesReplacement, baseClassReplacement) +
input + ENTITY_SUFFIX
),
+ options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
classpath = classpathFiles
) { invocation ->
val entity = invocation.roundEnv
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/DaoProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/DaoProcessorTest.kt
index 2758547..24b55f7 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/DaoProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/DaoProcessorTest.kt
@@ -764,6 +764,7 @@
),
COMMON.USER
),
+ options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
classpath = classpathFiles
) { invocation: XTestInvocation ->
val dao = invocation.roundEnv
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/DatabaseProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/DatabaseProcessorTest.kt
index f74dcbb..63fd4dc 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/DatabaseProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/DatabaseProcessorTest.kt
@@ -487,6 +487,7 @@
)
runProcessorTest(
sources = listOf(BOOK, BOOK_DAO, DB1, DB2, db1_2),
+ options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
createProcessingSteps = { listOf(DatabaseProcessingStep()) }
) { result ->
result.generatedSourceFileWithPath("foo/bar/Db1_Impl.java")
@@ -1465,7 +1466,10 @@
)
runProcessorTest(
sources = listOf(dbSource, USER),
- options = mapOf("room.schemaLocation" to "schemas/")
+ options = mapOf(
+ "room.schemaLocation" to "schemas/",
+ "room.generateKotlin" to "false"
+ )
) { invocation ->
val dbAnnotationName = "androidx.room.Database"
val roundElements = mapOf(
@@ -1537,7 +1541,10 @@
}
"""
)
- runProcessorTest(sources = listOf(jvmNameInDaoGetter)) { invocation ->
+ runProcessorTest(
+ sources = listOf(jvmNameInDaoGetter),
+ options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
+ ) { invocation ->
val element = invocation.processingEnv.requireTypeElement("foo.bar.MyDb")
DatabaseProcessor(
baseContext = invocation.context,
@@ -1614,7 +1621,8 @@
body: (List<DatabaseView>, XTestInvocation) -> Unit
) {
runProcessorTest(
- sources = listOf(DB3, BOOK)
+ sources = listOf(DB3, BOOK),
+ options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
) { invocation ->
val database = invocation.roundEnv
.getElementsAnnotatedWith(
@@ -1665,6 +1673,7 @@
)
runProcessorTest(
sources = listOf(BOOK, bookDao) + dbs,
+ options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
createProcessingSteps = { listOf(DatabaseProcessingStep()) },
) {
onCompilationResult?.invoke(it)
@@ -1685,7 +1694,8 @@
),
classpath = classpath,
options = mapOf(
- "room.schemaLocation" to schemaFolder.root.absolutePath
+ "room.schemaLocation" to schemaFolder.root.absolutePath,
+ Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"
)
) { invocation ->
val entity = invocation.roundEnv
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/DeleteOrUpdateShortcutMethodProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/DeleteOrUpdateShortcutMethodProcessorTest.kt
index 7f7e12a..80de5d3 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/DeleteOrUpdateShortcutMethodProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/DeleteOrUpdateShortcutMethodProcessorTest.kt
@@ -795,7 +795,8 @@
COMMON.GUAVA_ROOM
)
runProcessorTest(
- sources = commonSources + additionalSources + inputSource
+ sources = commonSources + additionalSources + inputSource,
+ options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
) { invocation ->
val (owner, methods) = invocation.roundEnv
.getElementsAnnotatedWith(Dao::class.qualifiedName!!)
@@ -836,7 +837,8 @@
)
runProcessorTest(
- sources = commonSources + additionalSources + inputSource
+ sources = commonSources + additionalSources + inputSource,
+ options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
) { invocation ->
val (owner, methods) = invocation.roundEnv
.getElementsAnnotatedWith(Dao::class.qualifiedName!!)
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/InsertOrUpsertShortcutMethodProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/InsertOrUpsertShortcutMethodProcessorTest.kt
index 45f42288..fa50917 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/InsertOrUpsertShortcutMethodProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/InsertOrUpsertShortcutMethodProcessorTest.kt
@@ -1122,7 +1122,8 @@
)
runProcessorTest(
- sources = commonSources + additionalSources + inputSource
+ sources = commonSources + additionalSources + inputSource,
+ options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
) { invocation ->
val (owner, methods) = invocation.roundEnv
.getElementsAnnotatedWith(Dao::class.qualifiedName!!)
@@ -1162,7 +1163,8 @@
)
runProcessorTest(
- sources = commonSources + additionalSources + inputSource
+ sources = commonSources + additionalSources + inputSource,
+ options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
) { invocation ->
val (owner, methods) = invocation.roundEnv
.getElementsAnnotatedWith(Dao::class.qualifiedName!!)
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt
index 9c40b99..636a827 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt
@@ -1309,9 +1309,11 @@
COMMON.NOT_AN_ENTITY, COMMON.ARTIST, COMMON.SONG, COMMON.IMAGE, COMMON.IMAGE_FORMAT,
COMMON.CONVERTER
)
+ val allOptions =
+ mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false") + options
runProcessorTest(
sources = additionalSources + commonSources + inputSource,
- options = options
+ options = allOptions
) { invocation ->
val (owner, methods) = invocation.roundEnv
.getElementsAnnotatedWith(Dao::class.qualifiedName!!)
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/RawQueryMethodProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/RawQueryMethodProcessorTest.kt
index 805c6ea..c28313e 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/RawQueryMethodProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/RawQueryMethodProcessorTest.kt
@@ -672,7 +672,8 @@
COMMON.IMAGE_FORMAT, COMMON.CONVERTER
)
runProcessorTest(
- sources = commonSources + inputSource
+ sources = commonSources + inputSource,
+ options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
) { invocation ->
val (owner, methods) = invocation.roundEnv
.getElementsAnnotatedWith(Dao::class.qualifiedName!!)
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/RemoveUnusedColumnsTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/RemoveUnusedColumnsTest.kt
index 3c39305..439f503 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/RemoveUnusedColumnsTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/RemoveUnusedColumnsTest.kt
@@ -118,7 +118,8 @@
listOf(DatabaseProcessingStep())
},
options = mapOf(
- "room.expandProjection" to enableExpandProjection.toString()
+ "room.expandProjection" to enableExpandProjection.toString(),
+ "room.generateKotlin" to "false",
)
) { result ->
validate(result)
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/solver/BuiltInConverterFlagsTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/solver/BuiltInConverterFlagsTest.kt
index c48870e..177e637 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/solver/BuiltInConverterFlagsTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/solver/BuiltInConverterFlagsTest.kt
@@ -24,6 +24,7 @@
import androidx.room.compiler.processing.util.Source
import androidx.room.compiler.processing.util.XTestInvocation
import androidx.room.compiler.processing.util.runProcessorTest
+import androidx.room.processor.Context
import androidx.room.processor.ProcessorErrors.CANNOT_FIND_COLUMN_TYPE_ADAPTER
import androidx.room.processor.ProcessorErrors.CANNOT_FIND_CURSOR_READER
import org.junit.Test
@@ -177,7 +178,8 @@
dbAnnotation = dbAnnotation
)
runProcessorTest(
- sources = listOf(source)
+ sources = listOf(source),
+ options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
) { invocation ->
val subject = invocation.processingEnv.requireTypeElement("MyDatabase")
DatabaseProcessingStep().process(
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/solver/CustomTypeConverterResolutionTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/solver/CustomTypeConverterResolutionTest.kt
index f4ade0b..c188e08 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/solver/CustomTypeConverterResolutionTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/solver/CustomTypeConverterResolutionTest.kt
@@ -35,6 +35,7 @@
import androidx.room.ext.CommonTypeNames
import androidx.room.ext.RoomAnnotationTypeNames
import androidx.room.ext.RoomTypeNames.ROOM_DB
+import androidx.room.processor.Context
import androidx.room.processor.ProcessorErrors.CANNOT_BIND_QUERY_PARAMETER_INTO_STMT
import org.junit.Test
import org.junit.runner.RunWith
@@ -259,6 +260,7 @@
runProcessorTest(
sources = sources + CUSTOM_TYPE_JFO + CUSTOM_TYPE_CONVERTER_JFO +
CUSTOM_TYPE_SET_CONVERTER_JFO,
+ options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
createProcessingSteps = {
listOf(DatabaseProcessingStep())
},
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/writer/DatabaseWriterTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/writer/DatabaseWriterTest.kt
index 253ff02..ed72d66 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/writer/DatabaseWriterTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/writer/DatabaseWriterTest.kt
@@ -22,6 +22,7 @@
import androidx.room.compiler.processing.util.CompilationResultSubject
import androidx.room.compiler.processing.util.Source
import androidx.room.compiler.processing.util.runProcessorTest
+import androidx.room.processor.Context
import androidx.testutils.generateAllEnumerations
import loadTestSource
import org.junit.Test
@@ -141,6 +142,7 @@
) + inputs
runProcessorTest(
sources = sources,
+ options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
javacProcessors = listOf(RoomProcessor()),
symbolProcessorProviders = listOf(RoomKspProcessor.Provider()),
onCompilationResult = onCompilationResult
diff --git a/room/room-paging-guava/src/androidTest/kotlin/androidx/room/paging/guava/LimitOffsetListenableFuturePagingSourceTest.kt b/room/room-paging-guava/src/androidTest/kotlin/androidx/room/paging/guava/LimitOffsetListenableFuturePagingSourceTest.kt
index 0a621a1..af3980f 100644
--- a/room/room-paging-guava/src/androidTest/kotlin/androidx/room/paging/guava/LimitOffsetListenableFuturePagingSourceTest.kt
+++ b/room/room-paging-guava/src/androidTest/kotlin/androidx/room/paging/guava/LimitOffsetListenableFuturePagingSourceTest.kt
@@ -207,7 +207,7 @@
@Test
fun refresh_consecutively() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db, true)
val pagingSource2 = LimitOffsetListenableFuturePagingSourceImpl(db, true)
@@ -308,7 +308,7 @@
}
@Test
fun refresh_onSuccess() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db, true)
val listenableFuture = pagingSource.refresh(key = 30)
@@ -336,7 +336,7 @@
@Test
fun append_onSuccess() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
pagingSource.itemCount.set(100) // bypass check for initial load
@@ -364,7 +364,7 @@
@Test
fun prepend_onSuccess() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
pagingSource.itemCount.set(100) // bypass check for initial load
@@ -632,7 +632,7 @@
@Test
fun refresh_AfterCancellation() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db, true)
pagingSource.itemCount.set(100) // bypass check for initial load
@@ -656,7 +656,7 @@
@Test
fun appendAgain_afterFutureCanceled() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
pagingSource.itemCount.set(100) // bypass check for initial load
@@ -680,7 +680,7 @@
@Test
fun prependAgain_afterFutureCanceled() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
pagingSource.itemCount.set(100) // bypass check for initial load
@@ -721,7 +721,7 @@
// run this async separately from queryExecutor
run {
- db.dao.addItem(TestItem(101))
+ db.getDao().addItem(TestItem(101))
}
// tasks in queue [nonInitialLoad, InvalidationTracker(from additem)]
@@ -755,7 +755,7 @@
// run this async separately from queryExecutor
run {
- db.dao.addItem(TestItem(101))
+ db.getDao().addItem(TestItem(101))
}
// tasks in queue [nonInitialLoad, InvalidationTracker(from additem)]
@@ -789,7 +789,7 @@
}
}
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val listenableFuture = pagingSource.refresh()
val page = listenableFuture.await() as LoadResult.Page
@@ -812,7 +812,7 @@
}
}
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
pagingSource.itemCount.set(100)
val listenableFuture = pagingSource.append(key = 50)
@@ -836,7 +836,7 @@
}
}
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
pagingSource.itemCount.set(100)
val listenableFuture = pagingSource.prepend(key = 50)
@@ -875,7 +875,7 @@
.build()
runTest {
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
queryExecutor.executeAll() // InvalidationTracker from the addAllItems
test(db, queryExecutor, transactionExecutor)
}
@@ -1091,7 +1091,7 @@
@Database(entities = [TestItem::class], version = 1, exportSchema = false)
abstract class LimitOffsetTestDb : RoomDatabase() {
- abstract val dao: TestItemDao
+ abstract fun getDao(): TestItemDao
}
@Entity(tableName = "TestItem")
diff --git a/room/room-paging-rxjava2/src/androidTest/kotlin/androidx/room/paging/rxjava2/LimitOffsetRxPagingSourceTest.kt b/room/room-paging-rxjava2/src/androidTest/kotlin/androidx/room/paging/rxjava2/LimitOffsetRxPagingSourceTest.kt
index fca3c49..84cf1d4 100644
--- a/room/room-paging-rxjava2/src/androidTest/kotlin/androidx/room/paging/rxjava2/LimitOffsetRxPagingSourceTest.kt
+++ b/room/room-paging-rxjava2/src/androidTest/kotlin/androidx/room/paging/rxjava2/LimitOffsetRxPagingSourceTest.kt
@@ -87,7 +87,7 @@
@Test
fun initialLoad() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.refresh()
val result = single.await() as LoadResult.Page
@@ -98,7 +98,7 @@
@Test
fun simpleAppend() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.append(key = 15)
val result = single.await() as LoadResult.Page
@@ -109,7 +109,7 @@
@Test
fun simplePrepend() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.prepend(key = 20)
val result = single.await() as LoadResult.Page
@@ -120,7 +120,7 @@
@Test
fun initialLoad_invalidationTracker_isRegistered() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.refresh()
// run loadSingle to register InvalidationTracker
@@ -131,7 +131,7 @@
@Test
fun nonInitialLoad_invalidationTracker_isRegistered() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.prepend(key = 20)
// run loadSingle to register InvalidationTracker
@@ -142,7 +142,7 @@
@Test
fun refresh_singleImmediatelyReturn() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.refresh()
@@ -163,7 +163,7 @@
@Test
fun append_singleImmediatelyReturn() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.append(key = 10)
@@ -184,7 +184,7 @@
@Test
fun prepend_singleImmediatelyReturn() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.prepend(key = 15)
@@ -205,7 +205,7 @@
@Test
fun dbUpdate_invalidatesPagingSource() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.append(key = 50)
@@ -218,7 +218,7 @@
assertFalse(pagingSource.invalid)
// this should cause refreshVersionsSync to invalidate pagingSource
- db.dao.addItem(TestItem(113))
+ db.getDao().addItem(TestItem(113))
countingTaskExecutorRule.drainTasks(500, TimeUnit.MILLISECONDS)
assertTrue(pagingSource.invalid)
@@ -230,7 +230,7 @@
@Test
fun append_returnsInvalid() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.append(key = 50)
@@ -248,7 +248,7 @@
@Test
fun prepend_returnsInvalid() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.prepend(key = 50)
@@ -268,7 +268,7 @@
@Test
fun refresh_consecutively() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.refresh()
val result = single.await() as LoadResult.Page
@@ -286,7 +286,7 @@
@Test
fun append_consecutively() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.append(key = 15)
@@ -310,7 +310,7 @@
@Test
fun prepend_consecutively() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.prepend(key = 15)
@@ -334,7 +334,7 @@
@Test
fun refreshAgain_afterDispose() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
var isDisposed = false
@@ -359,7 +359,7 @@
@Test
fun appendAgain_afterDispose() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
var isDisposed = false
@@ -384,7 +384,7 @@
@Test
fun prependAgain_afterDispose() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
var isDisposed = false
@@ -416,7 +416,7 @@
).setQueryExecutor(queryExecutor)
.build()
- testDb.dao.addAllItems(ITEMS_LIST)
+ testDb.getDao().addAllItems(ITEMS_LIST)
queryExecutor.executeAll() // add items first
runTest {
@@ -454,7 +454,7 @@
LimitOffsetTestDb::class.java
).build()
- testDb.dao.addAllItems(ITEMS_LIST)
+ testDb.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(testDb)
runBlocking {
@@ -490,7 +490,7 @@
}
}
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val single = pagingSource.refresh()
val result = single.await() as LoadResult.Page
assertThat(result.data).containsExactlyElementsIn(
@@ -509,7 +509,7 @@
}
}
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val single = pagingSource.append(key = 15)
val result = single.await() as LoadResult.Page
assertThat(result.data).containsExactlyElementsIn(
@@ -528,7 +528,7 @@
}
}
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val single = pagingSource.prepend(key = 15)
val result = single.await() as LoadResult.Page
assertThat(result.data).containsExactlyElementsIn(
@@ -673,7 +673,7 @@
@Database(entities = [TestItem::class], version = 1, exportSchema = false)
abstract class LimitOffsetTestDb : RoomDatabase() {
- abstract val dao: TestItemDao
+ abstract fun getDao(): TestItemDao
}
@Entity(tableName = "TestItem")
diff --git a/room/room-paging-rxjava3/src/androidTest/kotlin/androidx/room/paging/rxjava3/LimitOffsetRxPagingSourceTest.kt b/room/room-paging-rxjava3/src/androidTest/kotlin/androidx/room/paging/rxjava3/LimitOffsetRxPagingSourceTest.kt
index 1684489..df8ac9b 100644
--- a/room/room-paging-rxjava3/src/androidTest/kotlin/androidx/room/paging/rxjava3/LimitOffsetRxPagingSourceTest.kt
+++ b/room/room-paging-rxjava3/src/androidTest/kotlin/androidx/room/paging/rxjava3/LimitOffsetRxPagingSourceTest.kt
@@ -87,7 +87,7 @@
@Test
fun initialLoad() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.refresh()
val result = single.await() as LoadResult.Page
@@ -98,7 +98,7 @@
@Test
fun simpleAppend() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.append(key = 15)
val result = single.await() as LoadResult.Page
@@ -109,7 +109,7 @@
@Test
fun simplePrepend() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.prepend(key = 20)
val result = single.await() as LoadResult.Page
@@ -120,7 +120,7 @@
@Test
fun initialLoad_invalidationTracker_isRegistered() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.refresh()
// run loadSingle to register InvalidationTracker
@@ -131,7 +131,7 @@
@Test
fun nonInitialLoad_invalidationTracker_isRegistered() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.prepend(key = 20)
// run loadSingle to register InvalidationTracker
@@ -142,7 +142,7 @@
@Test
fun refresh_singleImmediatelyReturn() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.refresh()
@@ -163,7 +163,7 @@
@Test
fun append_singleImmediatelyReturn() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.append(key = 10)
@@ -184,7 +184,7 @@
@Test
fun prepend_singleImmediatelyReturn() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.prepend(key = 15)
@@ -205,7 +205,7 @@
@Test
fun dbUpdate_invalidatesPagingSource() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.append(key = 50)
@@ -218,7 +218,7 @@
assertFalse(pagingSource.invalid)
// this should cause refreshVersionsSync to invalidate pagingSource
- db.dao.addItem(TestItem(113))
+ db.getDao().addItem(TestItem(113))
countingTaskExecutorRule.drainTasks(500, TimeUnit.MILLISECONDS)
assertTrue(pagingSource.invalid)
@@ -230,7 +230,7 @@
@Test
fun append_returnsInvalid() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.append(key = 50)
@@ -248,7 +248,7 @@
@Test
fun prepend_returnsInvalid() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.prepend(key = 50)
@@ -268,7 +268,7 @@
@Test
fun refresh_consecutively() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.refresh()
val result = single.await() as LoadResult.Page
@@ -286,7 +286,7 @@
@Test
fun append_consecutively() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.append(key = 15)
@@ -310,7 +310,7 @@
@Test
fun prepend_consecutively() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
val single = pagingSource.prepend(key = 15)
@@ -334,7 +334,7 @@
@Test
fun refreshAgain_afterDispose() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
var isDisposed = false
@@ -359,7 +359,7 @@
@Test
fun appendAgain_afterDispose() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
var isDisposed = false
@@ -384,7 +384,7 @@
@Test
fun prependAgain_afterDispose() = setupAndRun { db ->
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(db)
var isDisposed = false
@@ -416,7 +416,7 @@
).setQueryExecutor(queryExecutor)
.build()
- testDb.dao.addAllItems(ITEMS_LIST)
+ testDb.getDao().addAllItems(ITEMS_LIST)
queryExecutor.executeAll() // add items first
runTest {
@@ -454,7 +454,7 @@
LimitOffsetTestDb::class.java
).build()
- testDb.dao.addAllItems(ITEMS_LIST)
+ testDb.getDao().addAllItems(ITEMS_LIST)
val pagingSource = LimitOffsetRxPagingSourceImpl(testDb)
runBlocking {
@@ -489,7 +489,7 @@
}
}
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val single = pagingSource.refresh()
val result = single.await() as LoadResult.Page
assertThat(result.data).containsExactlyElementsIn(
@@ -508,7 +508,7 @@
}
}
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val single = pagingSource.append(key = 15)
val result = single.await() as LoadResult.Page
assertThat(result.data).containsExactlyElementsIn(
@@ -527,7 +527,7 @@
}
}
- db.dao.addAllItems(ITEMS_LIST)
+ db.getDao().addAllItems(ITEMS_LIST)
val single = pagingSource.prepend(key = 15)
val result = single.await() as LoadResult.Page
assertThat(result.data).containsExactlyElementsIn(
@@ -672,7 +672,7 @@
@Database(entities = [TestItem::class], version = 1, exportSchema = false)
abstract class LimitOffsetTestDb : RoomDatabase() {
- abstract val dao: TestItemDao
+ abstract fun getDao(): TestItemDao
}
@Entity(tableName = "TestItem")
diff --git a/room/room-paging/src/androidTest/kotlin/androidx/room/paging/LimitOffsetPagingSourceTest.kt b/room/room-paging/src/androidTest/kotlin/androidx/room/paging/LimitOffsetPagingSourceTest.kt
index 65518e8..6743669 100644
--- a/room/room-paging/src/androidTest/kotlin/androidx/room/paging/LimitOffsetPagingSourceTest.kt
+++ b/room/room-paging/src/androidTest/kotlin/androidx/room/paging/LimitOffsetPagingSourceTest.kt
@@ -68,7 +68,7 @@
ApplicationProvider.getApplicationContext(),
LimitOffsetTestDb::class.java,
).build()
- dao = database.dao
+ dao = database.getDao()
}
@After
@@ -735,7 +735,7 @@
it.run()
}.setQueryExecutor(queryExecutor)
.build()
- dao = db.dao
+ dao = db.getDao()
}
@After
diff --git a/room/room-paging/src/androidTest/kotlin/androidx/room/paging/LimitOffsetTestDb.kt b/room/room-paging/src/androidTest/kotlin/androidx/room/paging/LimitOffsetTestDb.kt
index 8d31c44..6a9c989 100644
--- a/room/room-paging/src/androidTest/kotlin/androidx/room/paging/LimitOffsetTestDb.kt
+++ b/room/room-paging/src/androidTest/kotlin/androidx/room/paging/LimitOffsetTestDb.kt
@@ -21,5 +21,5 @@
@Database(entities = [TestItem::class], version = 1, exportSchema = false)
abstract class LimitOffsetTestDb : RoomDatabase() {
- abstract val dao: TestItemDao
+ abstract fun getDao(): TestItemDao
}
diff --git a/room/room-runtime/build.gradle b/room/room-runtime/build.gradle
index 8ba82d1..9d0c517 100644
--- a/room/room-runtime/build.gradle
+++ b/room/room-runtime/build.gradle
@@ -219,10 +219,6 @@
add("kspAndroidAndroidTest", project(":room:room-compiler"))
}
-ksp {
- arg("room.generateKotlin", "true")
-}
-
androidx {
name = "Room-Runtime"
type = LibraryType.PUBLISHED_LIBRARY
diff --git a/testutils/testutils-gradle-plugin/src/main/java/androidx/testutils/gradle/ProjectSetupRule.kt b/testutils/testutils-gradle-plugin/src/main/java/androidx/testutils/gradle/ProjectSetupRule.kt
index 8676631..08ae513 100644
--- a/testutils/testutils-gradle-plugin/src/main/java/androidx/testutils/gradle/ProjectSetupRule.kt
+++ b/testutils/testutils-gradle-plugin/src/main/java/androidx/testutils/gradle/ProjectSetupRule.kt
@@ -74,7 +74,7 @@
val androidProject: String
get() = """
android {
- compileSdkVersion ${props.compileSdkVersion}
+ compileSdk ${props.compileSdk}
buildToolsVersion "${props.buildToolsVersion}"
defaultConfig {
@@ -210,7 +210,7 @@
// TODO(b/233600239): document the rest of the parameters
data class ProjectProps(
- val compileSdkVersion: String,
+ val compileSdk: String,
val buildToolsVersion: String,
val minSdkVersion: String,
val debugKeystore: String,
@@ -260,11 +260,7 @@
File(it).canonicalPath
}
},
- compileSdkVersion = properties.getProperty("compileSdkVersion").let {
- // Add quotes around preview SDK string so that we call
- // compileSdkVersion(String) instead of compileSdkVersion(int)
- return@let if (it.startsWith("android-")) "\"$it\"" else it
- },
+ compileSdk = properties.getProperty("compileSdk"),
buildToolsVersion = properties.getProperty("buildToolsVersion"),
minSdkVersion = properties.getProperty("minSdkVersion"),
navigationRuntime = properties.getProperty("navigationRuntime"),
diff --git a/testutils/testutils-navigation/src/main/java/androidx/testutils/TestNavigatorDestinationBuilder.kt b/testutils/testutils-navigation/src/main/java/androidx/testutils/TestNavigatorDestinationBuilder.kt
index d321417..b24ff3b 100644
--- a/testutils/testutils-navigation/src/main/java/androidx/testutils/TestNavigatorDestinationBuilder.kt
+++ b/testutils/testutils-navigation/src/main/java/androidx/testutils/TestNavigatorDestinationBuilder.kt
@@ -23,8 +23,10 @@
import androidx.navigation.NavDestinationBuilder
import androidx.navigation.NavDestinationDsl
import androidx.navigation.NavGraphBuilder
+import androidx.navigation.NavType
import androidx.navigation.get
import kotlin.reflect.KClass
+import kotlin.reflect.KType
/**
* Construct a new [TestNavigator.Destination]
@@ -39,7 +41,9 @@
/**
* Construct a new [TestNavigator.Destination]
*/
-inline fun NavGraphBuilder.test(route: KClass<*>) = test(route) {}
+inline fun <reified T : Any> NavGraphBuilder.test(
+ typeMap: Map<KType, NavType<*>> = emptyMap()
+) = test<T>(typeMap) {}
/**
* Construct a new [TestNavigator.Destination]
@@ -68,21 +72,26 @@
/**
* Construct a new [TestNavigator.Destination]
*/
-inline fun NavGraphBuilder.test(
- route: KClass<*>,
+inline fun <reified T : Any> NavGraphBuilder.test(
+ typeMap: Map<KType, NavType<*>> = emptyMap(),
builder: TestNavigatorDestinationBuilder.() -> Unit
) = destination(
- TestNavigatorDestinationBuilder(provider[TestNavigator::class], route).apply(builder)
+ TestNavigatorDestinationBuilder(provider[TestNavigator::class], T::class, typeMap)
+ .apply(builder)
)
/**
* DSL for constructing a new [TestNavigator.Destination]
*/
@NavDestinationDsl
+@OptIn(ExperimentalSafeArgsApi::class)
class TestNavigatorDestinationBuilder : NavDestinationBuilder<TestNavigator.Destination> {
@Suppress("DEPRECATION")
constructor(navigator: TestNavigator, @IdRes id: Int = 0) : super(navigator, id)
constructor(navigator: TestNavigator, route: String) : super(navigator, route)
- @OptIn(ExperimentalSafeArgsApi::class)
- constructor(navigator: TestNavigator, route: KClass<*>) : super(navigator, route, emptyMap())
+ constructor(
+ navigator: TestNavigator,
+ route: KClass<*>,
+ typeMap: Map<KType, NavType<*>>
+ ) : super(navigator, route, typeMap)
}
diff --git a/tv/samples/src/main/java/androidx/tv/samples/CardContainerSamples.kt b/tv/samples/src/main/java/androidx/tv/samples/CardContainerSamples.kt
index bc3333f..feb4f87 100644
--- a/tv/samples/src/main/java/androidx/tv/samples/CardContainerSamples.kt
+++ b/tv/samples/src/main/java/androidx/tv/samples/CardContainerSamples.kt
@@ -29,7 +29,7 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
-import androidx.tv.material3.CardContainerDefaults
+import androidx.tv.material3.Card
import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.StandardCardContainer
import androidx.tv.material3.Text
@@ -41,7 +41,7 @@
StandardCardContainer(
modifier = Modifier.size(150.dp, 120.dp),
imageCard = { interactionSource ->
- CardContainerDefaults.ImageCard(
+ Card(
onClick = { },
interactionSource = interactionSource
) {
@@ -63,7 +63,7 @@
WideCardContainer(
modifier = Modifier.size(180.dp, 100.dp),
imageCard = { interactionSource ->
- CardContainerDefaults.ImageCard(
+ Card(
onClick = { },
interactionSource = interactionSource
) {
diff --git a/tv/samples/src/main/java/androidx/tv/samples/CardSamples.kt b/tv/samples/src/main/java/androidx/tv/samples/CardSamples.kt
index 6cf206a..014a502 100644
--- a/tv/samples/src/main/java/androidx/tv/samples/CardSamples.kt
+++ b/tv/samples/src/main/java/androidx/tv/samples/CardSamples.kt
@@ -19,20 +19,25 @@
package androidx.tv.samples
import androidx.annotation.Sampled
+import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
+import androidx.tv.material3.Border
import androidx.tv.material3.Card
+import androidx.tv.material3.CardDefaults
import androidx.tv.material3.ClassicCard
import androidx.tv.material3.CompactCard
import androidx.tv.material3.ExperimentalTvMaterial3Api
@@ -41,17 +46,78 @@
@Sampled
@Composable
-fun CardSample() {
+fun HorizontalImageAspectRatioCardSample() {
Card(
- modifier = Modifier.size(150.dp, 120.dp),
- onClick = { }
+ onClick = { },
+ modifier = Modifier
+ .width(200.dp)
+ .aspectRatio(CardDefaults.HorizontalImageAspectRatio),
+ border = CardDefaults.border(
+ focusedBorder = Border(
+ border = BorderStroke(width = 3.dp, color = Color.Green),
+ shape = RoundedCornerShape(5),
+ ),
+ ),
+ colors = CardDefaults.colors(
+ containerColor = Color.Red,
+ focusedContainerColor = Color.Yellow
+ ),
+ scale = CardDefaults.scale(
+ focusedScale = 1.05f,
+ )
) {
- Box(Modifier.fillMaxSize()) {
- Text(
- text = "Card",
- modifier = Modifier.align(Alignment.Center)
- )
- }
+ }
+}
+
+@Sampled
+@Composable
+fun VerticalImageAspectRatioCardSample() {
+ Card(
+ onClick = { },
+ modifier = Modifier
+ .width(200.dp)
+ .aspectRatio(CardDefaults.VerticalImageAspectRatio),
+ border = CardDefaults.border(
+ focusedBorder = Border(
+ border = BorderStroke(width = 3.dp, color = Color.Green),
+ shape = RoundedCornerShape(5),
+ ),
+ ),
+ colors = CardDefaults.colors(
+ containerColor = Color.Red,
+ focusedContainerColor = Color.Yellow
+ ),
+ scale = CardDefaults.scale(
+ focusedScale = 1.05f,
+ )
+ ) {
+ }
+}
+
+@Sampled
+@Composable
+fun SquareImageAspectRatioCardSample() {
+ Card(
+ onClick = { },
+ modifier = Modifier
+ .width(150.dp)
+ .aspectRatio(CardDefaults.SquareImageAspectRatio),
+ border = CardDefaults.border(
+ focusedBorder = Border(
+ border = BorderStroke(width = 3.dp, color = Color.Green)
+ ),
+ ),
+ shape = CardDefaults.shape(
+ shape = CircleShape,
+ ),
+ colors = CardDefaults.colors(
+ containerColor = Color.Red,
+ focusedContainerColor = Color.Yellow
+ ),
+ scale = CardDefaults.scale(
+ focusedScale = 1.05f,
+ )
+ ) {
}
}
diff --git a/tv/tv-material/api/current.txt b/tv/tv-material/api/current.txt
index d1d9b94..54f54a8 100644
--- a/tv/tv-material/api/current.txt
+++ b/tv/tv-material/api/current.txt
@@ -86,7 +86,6 @@
}
public final class CardContainerDefaults {
- method @androidx.compose.runtime.Composable public void ImageCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, kotlin.jvm.functions.Function0<kotlin.Unit> content);
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.CardContainerColors contentColor(optional long contentColor, optional long focusedContentColor, optional long pressedContentColor);
field public static final androidx.tv.material3.CardContainerDefaults INSTANCE;
}
@@ -100,11 +99,11 @@
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.CardBorder border(optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder);
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.CardColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor);
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.CardColors compactCardColors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor);
- method public androidx.compose.ui.graphics.Brush getContainerGradient();
+ method public androidx.compose.ui.graphics.Brush getScrimBrush();
method public androidx.tv.material3.CardGlow glow(optional androidx.tv.material3.Glow glow, optional androidx.tv.material3.Glow focusedGlow, optional androidx.tv.material3.Glow pressedGlow);
method public androidx.tv.material3.CardScale scale(optional @FloatRange(from=0.0) float scale, optional @FloatRange(from=0.0) float focusedScale, optional @FloatRange(from=0.0) float pressedScale);
method public androidx.tv.material3.CardShape shape(optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.graphics.Shape focusedShape, optional androidx.compose.ui.graphics.Shape pressedShape);
- property public final androidx.compose.ui.graphics.Brush ContainerGradient;
+ property public final androidx.compose.ui.graphics.Brush ScrimBrush;
field public static final float HorizontalImageAspectRatio = 1.7777778f;
field public static final androidx.tv.material3.CardDefaults INSTANCE;
field public static final float SquareImageAspectRatio = 1.0f;
@@ -490,21 +489,16 @@
public final class ListItemDefaults {
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ListItemBorder border(optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder, optional androidx.tv.material3.Border selectedBorder, optional androidx.tv.material3.Border disabledBorder, optional androidx.tv.material3.Border focusedSelectedBorder, optional androidx.tv.material3.Border focusedDisabledBorder, optional androidx.tv.material3.Border pressedSelectedBorder);
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ListItemColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor, optional long selectedContainerColor, optional long selectedContentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long focusedSelectedContainerColor, optional long focusedSelectedContentColor, optional long pressedSelectedContainerColor, optional long pressedSelectedContentColor);
- method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.Border getFocusedDisabledBorder();
method public float getIconSize();
method public float getIconSizeDense();
- method public androidx.compose.foundation.shape.RoundedCornerShape getListItemShape();
method public float getTonalElevation();
method public androidx.tv.material3.ListItemGlow glow(optional androidx.tv.material3.Glow glow, optional androidx.tv.material3.Glow focusedGlow, optional androidx.tv.material3.Glow pressedGlow, optional androidx.tv.material3.Glow selectedGlow, optional androidx.tv.material3.Glow focusedSelectedGlow, optional androidx.tv.material3.Glow pressedSelectedGlow);
method public androidx.tv.material3.ListItemScale scale(optional @FloatRange(from=0.0) float scale, optional @FloatRange(from=0.0) float focusedScale, optional @FloatRange(from=0.0) float pressedScale, optional @FloatRange(from=0.0) float selectedScale, optional @FloatRange(from=0.0) float disabledScale, optional @FloatRange(from=0.0) float focusedSelectedScale, optional @FloatRange(from=0.0) float focusedDisabledScale, optional @FloatRange(from=0.0) float pressedSelectedScale);
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ListItemShape shape(optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.graphics.Shape focusedShape, optional androidx.compose.ui.graphics.Shape pressedShape, optional androidx.compose.ui.graphics.Shape selectedShape, optional androidx.compose.ui.graphics.Shape disabledShape, optional androidx.compose.ui.graphics.Shape focusedSelectedShape, optional androidx.compose.ui.graphics.Shape focusedDisabledShape, optional androidx.compose.ui.graphics.Shape pressedSelectedShape);
- property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.tv.material3.Border FocusedDisabledBorder;
property public final float IconSize;
property public final float IconSizeDense;
- property public final androidx.compose.foundation.shape.RoundedCornerShape ListItemShape;
property public final float TonalElevation;
field public static final androidx.tv.material3.ListItemDefaults INSTANCE;
- field public static final float SelectedContainerColorOpacity = 0.4f;
}
@androidx.compose.runtime.Immutable public final class ListItemGlow {
@@ -755,16 +749,6 @@
property public abstract boolean hasFocus;
}
- @androidx.compose.runtime.Immutable public final class NonInteractiveSurfaceColors {
- }
-
- public final class NonInteractiveSurfaceDefaults {
- method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.NonInteractiveSurfaceColors colors(optional long containerColor, optional long contentColor);
- method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.ui.graphics.Shape getShape();
- property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.ui.graphics.Shape shape;
- field public static final androidx.tv.material3.NonInteractiveSurfaceDefaults INSTANCE;
- }
-
public final class OutlinedButtonDefaults {
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ButtonBorder border(optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder, optional androidx.tv.material3.Border disabledBorder, optional androidx.tv.material3.Border focusedDisabledBorder);
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ButtonColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor, optional long disabledContainerColor, optional long disabledContentColor);
@@ -923,8 +907,18 @@
field public static final androidx.tv.material3.SuggestionChipDefaults INSTANCE;
}
+ @androidx.compose.runtime.Immutable public final class SurfaceColors {
+ }
+
+ public final class SurfaceDefaults {
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.SurfaceColors colors(optional long containerColor, optional long contentColor);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.ui.graphics.Shape getShape();
+ property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.ui.graphics.Shape shape;
+ field public static final androidx.tv.material3.SurfaceDefaults 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 float tonalElevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.tv.material3.NonInteractiveSurfaceColors colors, optional androidx.tv.material3.Border border, optional androidx.tv.material3.Glow glow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(optional androidx.compose.ui.Modifier modifier, optional float tonalElevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.tv.material3.SurfaceColors colors, optional androidx.tv.material3.Border border, optional androidx.tv.material3.Glow glow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void Surface(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>? onLongClick, optional float tonalElevation, optional androidx.tv.material3.SelectableSurfaceShape shape, optional androidx.tv.material3.SelectableSurfaceColors colors, optional androidx.tv.material3.SelectableSurfaceScale scale, optional androidx.tv.material3.SelectableSurfaceBorder border, optional androidx.tv.material3.SelectableSurfaceGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void Surface(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional boolean enabled, optional float tonalElevation, optional androidx.tv.material3.ClickableSurfaceShape shape, optional androidx.tv.material3.ClickableSurfaceColors colors, optional androidx.tv.material3.ClickableSurfaceScale scale, optional androidx.tv.material3.ClickableSurfaceBorder border, optional androidx.tv.material3.ClickableSurfaceGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
}
diff --git a/tv/tv-material/api/restricted_current.txt b/tv/tv-material/api/restricted_current.txt
index d1d9b94..54f54a8 100644
--- a/tv/tv-material/api/restricted_current.txt
+++ b/tv/tv-material/api/restricted_current.txt
@@ -86,7 +86,6 @@
}
public final class CardContainerDefaults {
- method @androidx.compose.runtime.Composable public void ImageCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, kotlin.jvm.functions.Function0<kotlin.Unit> content);
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.CardContainerColors contentColor(optional long contentColor, optional long focusedContentColor, optional long pressedContentColor);
field public static final androidx.tv.material3.CardContainerDefaults INSTANCE;
}
@@ -100,11 +99,11 @@
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.CardBorder border(optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder);
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.CardColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor);
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.CardColors compactCardColors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor);
- method public androidx.compose.ui.graphics.Brush getContainerGradient();
+ method public androidx.compose.ui.graphics.Brush getScrimBrush();
method public androidx.tv.material3.CardGlow glow(optional androidx.tv.material3.Glow glow, optional androidx.tv.material3.Glow focusedGlow, optional androidx.tv.material3.Glow pressedGlow);
method public androidx.tv.material3.CardScale scale(optional @FloatRange(from=0.0) float scale, optional @FloatRange(from=0.0) float focusedScale, optional @FloatRange(from=0.0) float pressedScale);
method public androidx.tv.material3.CardShape shape(optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.graphics.Shape focusedShape, optional androidx.compose.ui.graphics.Shape pressedShape);
- property public final androidx.compose.ui.graphics.Brush ContainerGradient;
+ property public final androidx.compose.ui.graphics.Brush ScrimBrush;
field public static final float HorizontalImageAspectRatio = 1.7777778f;
field public static final androidx.tv.material3.CardDefaults INSTANCE;
field public static final float SquareImageAspectRatio = 1.0f;
@@ -490,21 +489,16 @@
public final class ListItemDefaults {
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ListItemBorder border(optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder, optional androidx.tv.material3.Border selectedBorder, optional androidx.tv.material3.Border disabledBorder, optional androidx.tv.material3.Border focusedSelectedBorder, optional androidx.tv.material3.Border focusedDisabledBorder, optional androidx.tv.material3.Border pressedSelectedBorder);
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ListItemColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor, optional long selectedContainerColor, optional long selectedContentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long focusedSelectedContainerColor, optional long focusedSelectedContentColor, optional long pressedSelectedContainerColor, optional long pressedSelectedContentColor);
- method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.Border getFocusedDisabledBorder();
method public float getIconSize();
method public float getIconSizeDense();
- method public androidx.compose.foundation.shape.RoundedCornerShape getListItemShape();
method public float getTonalElevation();
method public androidx.tv.material3.ListItemGlow glow(optional androidx.tv.material3.Glow glow, optional androidx.tv.material3.Glow focusedGlow, optional androidx.tv.material3.Glow pressedGlow, optional androidx.tv.material3.Glow selectedGlow, optional androidx.tv.material3.Glow focusedSelectedGlow, optional androidx.tv.material3.Glow pressedSelectedGlow);
method public androidx.tv.material3.ListItemScale scale(optional @FloatRange(from=0.0) float scale, optional @FloatRange(from=0.0) float focusedScale, optional @FloatRange(from=0.0) float pressedScale, optional @FloatRange(from=0.0) float selectedScale, optional @FloatRange(from=0.0) float disabledScale, optional @FloatRange(from=0.0) float focusedSelectedScale, optional @FloatRange(from=0.0) float focusedDisabledScale, optional @FloatRange(from=0.0) float pressedSelectedScale);
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ListItemShape shape(optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.graphics.Shape focusedShape, optional androidx.compose.ui.graphics.Shape pressedShape, optional androidx.compose.ui.graphics.Shape selectedShape, optional androidx.compose.ui.graphics.Shape disabledShape, optional androidx.compose.ui.graphics.Shape focusedSelectedShape, optional androidx.compose.ui.graphics.Shape focusedDisabledShape, optional androidx.compose.ui.graphics.Shape pressedSelectedShape);
- property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.tv.material3.Border FocusedDisabledBorder;
property public final float IconSize;
property public final float IconSizeDense;
- property public final androidx.compose.foundation.shape.RoundedCornerShape ListItemShape;
property public final float TonalElevation;
field public static final androidx.tv.material3.ListItemDefaults INSTANCE;
- field public static final float SelectedContainerColorOpacity = 0.4f;
}
@androidx.compose.runtime.Immutable public final class ListItemGlow {
@@ -755,16 +749,6 @@
property public abstract boolean hasFocus;
}
- @androidx.compose.runtime.Immutable public final class NonInteractiveSurfaceColors {
- }
-
- public final class NonInteractiveSurfaceDefaults {
- method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.NonInteractiveSurfaceColors colors(optional long containerColor, optional long contentColor);
- method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.ui.graphics.Shape getShape();
- property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.ui.graphics.Shape shape;
- field public static final androidx.tv.material3.NonInteractiveSurfaceDefaults INSTANCE;
- }
-
public final class OutlinedButtonDefaults {
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ButtonBorder border(optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder, optional androidx.tv.material3.Border disabledBorder, optional androidx.tv.material3.Border focusedDisabledBorder);
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ButtonColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor, optional long disabledContainerColor, optional long disabledContentColor);
@@ -923,8 +907,18 @@
field public static final androidx.tv.material3.SuggestionChipDefaults INSTANCE;
}
+ @androidx.compose.runtime.Immutable public final class SurfaceColors {
+ }
+
+ public final class SurfaceDefaults {
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.SurfaceColors colors(optional long containerColor, optional long contentColor);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.ui.graphics.Shape getShape();
+ property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.ui.graphics.Shape shape;
+ field public static final androidx.tv.material3.SurfaceDefaults 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 float tonalElevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.tv.material3.NonInteractiveSurfaceColors colors, optional androidx.tv.material3.Border border, optional androidx.tv.material3.Glow glow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(optional androidx.compose.ui.Modifier modifier, optional float tonalElevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.tv.material3.SurfaceColors colors, optional androidx.tv.material3.Border border, optional androidx.tv.material3.Glow glow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void Surface(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>? onLongClick, optional float tonalElevation, optional androidx.tv.material3.SelectableSurfaceShape shape, optional androidx.tv.material3.SelectableSurfaceColors colors, optional androidx.tv.material3.SelectableSurfaceScale scale, optional androidx.tv.material3.SelectableSurfaceBorder border, optional androidx.tv.material3.SelectableSurfaceGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void Surface(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional boolean enabled, optional float tonalElevation, optional androidx.tv.material3.ClickableSurfaceShape shape, optional androidx.tv.material3.ClickableSurfaceColors colors, optional androidx.tv.material3.ClickableSurfaceScale scale, optional androidx.tv.material3.ClickableSurfaceBorder border, optional androidx.tv.material3.ClickableSurfaceGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
}
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardContainerScreenshotTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardContainerScreenshotTest.kt
index 81eefa5..2c5473c 100644
--- a/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardContainerScreenshotTest.kt
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardContainerScreenshotTest.kt
@@ -72,7 +72,7 @@
StandardCardContainer(
modifier = standardCardContainerSizeModifier,
imageCard = { interactionSource ->
- CardContainerDefaults.ImageCard(
+ Card(
onClick = { },
interactionSource = interactionSource
) {
@@ -103,7 +103,7 @@
StandardCardContainer(
modifier = standardCardContainerSizeModifier,
imageCard = { interactionSource ->
- CardContainerDefaults.ImageCard(
+ Card(
onClick = { },
interactionSource = interactionSource
) {
@@ -135,7 +135,7 @@
StandardCardContainer(
modifier = standardCardContainerSizeModifier,
imageCard = { interactionSource ->
- CardContainerDefaults.ImageCard(
+ Card(
onClick = { },
interactionSource = interactionSource
) {
@@ -170,7 +170,7 @@
WideCardContainer(
modifier = wideCardContainerSizeModifier,
imageCard = { interactionSource ->
- CardContainerDefaults.ImageCard(
+ Card(
onClick = { },
interactionSource = interactionSource
) {
@@ -201,7 +201,7 @@
WideCardContainer(
modifier = wideCardContainerSizeModifier,
imageCard = { interactionSource ->
- CardContainerDefaults.ImageCard(
+ Card(
onClick = { },
interactionSource = interactionSource
) {
@@ -233,7 +233,7 @@
WideCardContainer(
modifier = wideCardContainerSizeModifier,
imageCard = { interactionSource ->
- CardContainerDefaults.ImageCard(
+ Card(
onClick = { },
interactionSource = interactionSource
) {
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardContainerTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardContainerTest.kt
index 791bc65..218639e 100644
--- a/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardContainerTest.kt
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardContainerTest.kt
@@ -66,7 +66,7 @@
.semantics(mergeDescendants = true) {}
.testTag(StandardCardContainerTag),
imageCard = { interactionSource ->
- CardContainerDefaults.ImageCard(
+ Card(
onClick = { count.value += 1 },
interactionSource = interactionSource
) { SampleImage() }
@@ -97,7 +97,7 @@
.semantics(mergeDescendants = true) {}
.testTag(StandardCardContainerTag),
imageCard = { interactionSource ->
- CardContainerDefaults.ImageCard(
+ Card(
onClick = { count.value += 1 },
interactionSource = interactionSource
) { SampleImage() }
@@ -129,7 +129,7 @@
.semantics(mergeDescendants = true) {}
.testTag(WideCardContainerTag),
imageCard = { interactionSource ->
- CardContainerDefaults.ImageCard(
+ Card(
onClick = { count.value += 1 },
interactionSource = interactionSource
) { SampleImage() }
@@ -160,7 +160,7 @@
.semantics(mergeDescendants = true) {}
.testTag(WideCardContainerTag),
imageCard = { interactionSource ->
- CardContainerDefaults.ImageCard(
+ Card(
onClick = { count.value += 1 },
interactionSource = interactionSource
) { SampleImage() }
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/NonInteractiveSurfaceScreenshotTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/NonInteractiveSurfaceScreenshotTest.kt
index 439bb98..88cf3d9 100644
--- a/tv/tv-material/src/androidTest/java/androidx/tv/material3/NonInteractiveSurfaceScreenshotTest.kt
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/NonInteractiveSurfaceScreenshotTest.kt
@@ -60,7 +60,7 @@
.align(Alignment.Center)
}
- private val wrapperTestTag = "NonInteractiveSurfaceWrapper"
+ private val wrapperTestTag = "SurfaceWrapper"
@Test
fun nonInteractiveSurface_noCustomizations() {
@@ -98,7 +98,7 @@
Box(containerModifier.testTag(wrapperTestTag)) {
Surface(
surfaceModifier(),
- colors = NonInteractiveSurfaceDefaults.colors(containerColor = Color.Green)
+ colors = SurfaceDefaults.colors(containerColor = Color.Green)
) {}
}
}
@@ -111,7 +111,7 @@
Box(containerModifier.testTag(wrapperTestTag)) {
Surface(
surfaceModifier(),
- colors = NonInteractiveSurfaceDefaults.colors(contentColor = Color.Red)
+ colors = SurfaceDefaults.colors(contentColor = Color.Red)
) {}
}
}
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/TabRowScreenshotTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/TabRowScreenshotTest.kt
index 093e9b7..9e5999e 100644
--- a/tv/tv-material/src/androidTest/java/androidx/tv/material3/TabRowScreenshotTest.kt
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/TabRowScreenshotTest.kt
@@ -70,7 +70,7 @@
Surface(
modifier = wrapperModifier,
- colors = NonInteractiveSurfaceDefaults.colors(
+ colors = SurfaceDefaults.colors(
containerColor = Color.Transparent
),
shape = RectangleShape
@@ -108,7 +108,7 @@
Surface(
modifier = wrapperModifier.focusRequester(focusRequester),
- colors = NonInteractiveSurfaceDefaults.colors(
+ colors = SurfaceDefaults.colors(
containerColor = Color.Transparent
),
shape = RectangleShape
@@ -152,7 +152,7 @@
Surface(
modifier = wrapperModifier.focusRequester(focusRequester),
- colors = NonInteractiveSurfaceDefaults.colors(
+ colors = SurfaceDefaults.colors(
containerColor = Color.Transparent
),
shape = RectangleShape
@@ -195,7 +195,7 @@
Surface(
modifier = wrapperModifier,
- colors = NonInteractiveSurfaceDefaults.colors(
+ colors = SurfaceDefaults.colors(
containerColor = Color.Transparent
),
shape = RectangleShape
@@ -239,7 +239,7 @@
Surface(
modifier = wrapperModifier.focusRequester(focusRequester),
- colors = NonInteractiveSurfaceDefaults.colors(
+ colors = SurfaceDefaults.colors(
containerColor = Color.Transparent
),
shape = RectangleShape
@@ -289,7 +289,7 @@
Surface(
modifier = wrapperModifier.focusRequester(focusRequester),
- colors = NonInteractiveSurfaceDefaults.colors(
+ colors = SurfaceDefaults.colors(
containerColor = Color.Transparent
),
shape = RectangleShape
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/Card.kt b/tv/tv-material/src/main/java/androidx/tv/material3/Card.kt
index 7f9b9b3..f08da19 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/Card.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/Card.kt
@@ -45,7 +45,11 @@
*
* This Card handles click events, calling its [onClick] lambda.
*
- * @sample androidx.tv.samples.CardSample
+ * Checkout <a href="https://developer.android.com/design/ui/tv/guides/components/cards#usage">TV Guidelines for Aspect ratios</a> for cards
+ *
+ * @sample androidx.tv.samples.HorizontalImageAspectRatioCardSample
+ * @sample androidx.tv.samples.VerticalImageAspectRatioCardSample
+ * @sample androidx.tv.samples.SquareImageAspectRatioCardSample
*
* @param onClick called when this card is clicked.
* @param modifier the [Modifier] to be applied to this card.
@@ -212,7 +216,7 @@
* @param glow [CardGlow] defines a shadow to be shown behind the card for different interaction
* states. See [CardDefaults.glow].
* @param scrimBrush [Brush] defines a brush/gradient to be used to draw the scrim over the image
- * in the background. See [CardDefaults.ContainerGradient].
+ * in the background. See [CardDefaults.ScrimBrush].
* @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
* emitting [Interaction]s for this card. You can use this to change the card's appearance
* or preview the card in different states. Note that if `null` is provided, interactions will
@@ -232,7 +236,7 @@
scale: CardScale = CardDefaults.scale(),
border: CardBorder = CardDefaults.border(),
glow: CardGlow = CardDefaults.glow(),
- scrimBrush: Brush = CardDefaults.ContainerGradient,
+ scrimBrush: Brush = CardDefaults.ScrimBrush,
interactionSource: MutableInteractionSource? = null
) {
Card(
@@ -407,7 +411,7 @@
* Gradient used in cards to give more emphasis to the textual content that is generally
* displayed above an image.
*/
- val ContainerGradient = Brush.verticalGradient(
+ val ScrimBrush = Brush.verticalGradient(
listOf(
Color(red = 28, green = 27, blue = 31, alpha = 0),
Color(red = 28, green = 27, blue = 31, alpha = 204)
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/CardContainer.kt b/tv/tv-material/src/main/java/androidx/tv/material3/CardContainer.kt
index d896f89..6185285 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/CardContainer.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/CardContainer.kt
@@ -46,9 +46,7 @@
*
* @sample androidx.tv.samples.StandardCardContainerSample
*
- * @param imageCard defines the [Composable] to be used for the image card. See
- * [CardContainerDefaults.ImageCard] to create an image card. The `interactionSource` param provided
- * in the lambda function should be forwarded and used with the image card composable.
+ * @param imageCard defines the [Composable] to be used for the image card.
* @param title defines the [Composable] title placed below the image card in the CardContainer.
* @param modifier the [Modifier] to be applied to this CardContainer.
* @param subtitle defines the [Composable] supporting text placed below the title in CardContainer.
@@ -111,9 +109,7 @@
*
* @sample androidx.tv.samples.WideCardContainerSample
*
- * @param imageCard defines the [Composable] to be used for the image card. See
- * [CardContainerDefaults.ImageCard] to create an image card. The `interactionSource` param provided
- * in the lambda function should to be forwarded and used with the image card composable.
+ * @param imageCard defines the [Composable] to be used for the image card.
* @param title defines the [Composable] title placed below the image card in the CardContainer.
* @param modifier the [Modifier] to be applied to this CardContainer.
* @param subtitle defines the [Composable] supporting text placed below the title in CardContainer.
@@ -191,58 +187,6 @@
focusedContentColor = focusedContentColor,
pressedContentColor = pressedContentColor
)
-
- /**
- * [ImageCard] is basically a [Card] composable with an image as the content. It is recommended
- * to be used with the different CardContainer(s).
- *
- * This Card handles click events, calling its [onClick] lambda.
- *
- * @param onClick called when this card is clicked.
- * @param interactionSource a hoisted [MutableInteractionSource] for observing and
- * emitting [Interaction]s for this card. When using with the CardContainer(s), it is recommended
- * to pass in the interaction state obtained from the parent lambda.
- * @param modifier the [Modifier] to be applied to this card.
- * @param onLongClick called when this card is long clicked (long-pressed).
- * @param shape [CardShape] defines the shape of this card's container in different interaction
- * states. See [CardDefaults.shape].
- * @param colors [CardColors] defines the background & content colors used in this card for
- * different interaction states. See [CardDefaults.colors].
- * @param scale [CardScale] defines size of the card relative to its original size for different
- * interaction states. See [CardDefaults.scale].
- * @param border [CardBorder] defines a border around the card for different interaction states.
- * See [CardDefaults.border].
- * @param glow [CardGlow] defines a shadow to be shown behind the card for different interaction
- * states. See [CardDefaults.glow].
- * @param content defines the image content [Composable] to be displayed inside the Card.
- */
- @Composable
- fun ImageCard(
- onClick: () -> Unit,
- interactionSource: MutableInteractionSource,
- modifier: Modifier = Modifier,
- onLongClick: (() -> Unit)? = null,
- shape: CardShape = CardDefaults.shape(),
- colors: CardColors = CardDefaults.colors(),
- scale: CardScale = CardDefaults.scale(),
- border: CardBorder = CardDefaults.border(),
- glow: CardGlow = CardDefaults.glow(),
- content: @Composable () -> Unit
- ) {
- Card(
- onClick = onClick,
- onLongClick = onLongClick,
- modifier = modifier,
- shape = shape,
- colors = colors,
- scale = scale,
- border = border,
- glow = glow,
- interactionSource = interactionSource
- ) {
- content()
- }
- }
}
/**
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/ListItemDefaults.kt b/tv/tv-material/src/main/java/androidx/tv/material3/ListItemDefaults.kt
index 1ea5747..f80a652 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/ListItemDefaults.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/ListItemDefaults.kt
@@ -50,12 +50,12 @@
/**
* The default shape for a [ListItem].
*/
- val ListItemShape = RoundedCornerShape(8.dp)
+ private val ListItemShape = RoundedCornerShape(8.dp)
/**
* The default border applied to [ListItem] in focused disabled state.
*/
- val FocusedDisabledBorder
+ private val FocusedDisabledBorder
@ReadOnlyComposable
@Composable get() = Border(
border = BorderStroke(
@@ -67,7 +67,7 @@
/**
* The default opacity for the [ListItem] container color in selected state.
*/
- const val SelectedContainerColorOpacity = 0.4f
+ private const val SelectedContainerColorOpacity = 0.4f
/**
* The default content padding [PaddingValues] used by [ListItem]
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/Surface.kt b/tv/tv-material/src/main/java/androidx/tv/material3/Surface.kt
index 4665acf..92792c2 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/Surface.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/Surface.kt
@@ -66,7 +66,7 @@
* in a darker color in light theme and lighter color in dark theme.
* @param shape Defines the surface's shape.
* @param colors Defines the background & content color to be used in this Surface.
- * See [NonInteractiveSurfaceDefaults.colors].
+ * See [SurfaceDefaults.colors].
* @param border Defines a border around the Surface.
* @param glow Diffused shadow to be shown behind the Surface. Note that glow is disabled for API
* levels below 28 as it is not supported by the underlying OS
@@ -77,10 +77,10 @@
fun Surface(
modifier: Modifier = Modifier,
tonalElevation: Dp = 0.dp,
- shape: Shape = NonInteractiveSurfaceDefaults.shape,
- colors: NonInteractiveSurfaceColors = NonInteractiveSurfaceDefaults.colors(),
- border: Border = NonInteractiveSurfaceDefaults.border,
- glow: Glow = NonInteractiveSurfaceDefaults.glow,
+ shape: Shape = SurfaceDefaults.shape,
+ colors: SurfaceColors = SurfaceDefaults.colors(),
+ border: Border = SurfaceDefaults.border,
+ glow: Glow = SurfaceDefaults.glow,
content: @Composable (BoxScope.() -> Unit)
) {
SurfaceImpl(
@@ -210,7 +210,7 @@
*
* To manually retrieve the content color inside a surface, use [LocalContentColor].
*
- * @param selected whether or not this Surface is toggled on or off
+ * @param selected whether or not this Surface is selected
* @param onClick callback to be invoked when the selectable Surface is clicked.
* @param modifier [Modifier] to be applied to the layout corresponding to the surface
* @param onLongClick callback to be called when the selectable surface is long clicked
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/SurfaceDefaults.kt b/tv/tv-material/src/main/java/androidx/tv/material3/SurfaceDefaults.kt
index 3d32a1c..eeab748 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/SurfaceDefaults.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/SurfaceDefaults.kt
@@ -29,14 +29,14 @@
/**
* Contains the default values used by a non-interactive [Surface]
*/
-object NonInteractiveSurfaceDefaults {
+object SurfaceDefaults {
/**
* Represents the default shape used by a non-interactive [Surface]
*/
val shape: Shape @ReadOnlyComposable @Composable get() = RectangleShape
/**
- * Creates a [NonInteractiveSurfaceColors] that represents the default container & content
+ * Creates a [SurfaceColors] that represents the default container & content
* colors used by a non-interactive [Surface].
*
* @param containerColor the container color of this Surface
@@ -47,7 +47,7 @@
fun colors(
containerColor: Color = MaterialTheme.colorScheme.surface,
contentColor: Color = contentColorFor(containerColor)
- ) = NonInteractiveSurfaceColors(
+ ) = SurfaceColors(
containerColor = containerColor,
contentColor = contentColor
)
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/SurfaceStyles.kt b/tv/tv-material/src/main/java/androidx/tv/material3/SurfaceStyles.kt
index bf922e6..026f4b4 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/SurfaceStyles.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/SurfaceStyles.kt
@@ -597,7 +597,7 @@
* Defines the container & content color [Color] for a non interactive surface.
*/
@Immutable
-class NonInteractiveSurfaceColors internal constructor(
+class SurfaceColors internal constructor(
internal val containerColor: Color,
internal val contentColor: Color
) {
@@ -605,7 +605,7 @@
if (this === other) return true
if (other == null || this::class != other::class) return false
- other as NonInteractiveSurfaceColors
+ other as SurfaceColors
if (containerColor != other.containerColor) return false
if (contentColor != other.contentColor) return false
@@ -620,7 +620,7 @@
}
override fun toString(): String {
- return "NonInteractiveSurfaceColors(containerColor=$containerColor, " +
+ return "SurfaceColors(containerColor=$containerColor, " +
"contentColor=$contentColor)"
}
}
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/TabRow.kt b/tv/tv-material/src/main/java/androidx/tv/material3/TabRow.kt
index 2b19522..82481b31 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/TabRow.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/TabRow.kt
@@ -114,7 +114,7 @@
.horizontalScroll(scrollState)
.onFocusChanged { doesTabRowHaveFocus = it.hasFocus }
.selectableGroup(),
- colors = NonInteractiveSurfaceDefaults.colors(
+ colors = SurfaceDefaults.colors(
containerColor = containerColor,
contentColor = contentColor
),
diff --git a/viewpager2/integration-tests/targetsdk-tests/build.gradle b/viewpager2/integration-tests/targetsdk-tests/build.gradle
index 4572431..b6076f6 100644
--- a/viewpager2/integration-tests/targetsdk-tests/build.gradle
+++ b/viewpager2/integration-tests/targetsdk-tests/build.gradle
@@ -25,11 +25,21 @@
productFlavors {
targetSdk29 {
dimension "targetSdk"
- targetSdkVersion 29
+ testOptions {
+ targetSdk 29
+ }
+ lint {
+ targetSdk 29
+ }
}
targetSdk30 {
dimension "targetSdk"
- targetSdkVersion 30
+ testOptions {
+ targetSdk 30
+ }
+ lint {
+ targetSdk 30
+ }
}
targetSdkLatest {
dimension "targetSdk"
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyColumnMeasure.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyColumnMeasure.kt
index 7584d68..29de39c 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyColumnMeasure.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyColumnMeasure.kt
@@ -236,7 +236,7 @@
if (minTransitionArea != other.minTransitionArea) return false
if (maxTransitionArea != other.maxTransitionArea) return false
if (scaleInterpolator != other.scaleInterpolator) return false
- if (viewportVerticalOffsetResolver != other.viewportVerticalOffsetResolver) return false
+ if (viewportVerticalOffsetResolver !== other.viewportVerticalOffsetResolver) return false
return true
}
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt
index b3abd6e..bf11025 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt
@@ -240,7 +240,7 @@
if (minTransitionArea != other.minTransitionArea) return false
if (maxTransitionArea != other.maxTransitionArea) return false
if (scaleInterpolator != other.scaleInterpolator) return false
- if (viewportVerticalOffsetResolver != other.viewportVerticalOffsetResolver) return false
+ if (viewportVerticalOffsetResolver !== other.viewportVerticalOffsetResolver) return false
return true
}
diff --git a/wear/compose/compose-material3/build.gradle b/wear/compose/compose-material3/build.gradle
index 955646f..d18ada1 100644
--- a/wear/compose/compose-material3/build.gradle
+++ b/wear/compose/compose-material3/build.gradle
@@ -85,7 +85,7 @@
"developers to write Jetpack Compose applications for Wearable devices that " +
"implement Wear Material 3 Design UX guidelines and specifications. It builds upon " +
"the Jetpack Compose libraries."
- samples(project(":wear:compose:compose-material-samples"))
+ samples(project(":wear:compose:compose-material3-samples"))
}
tasks.withType(KotlinCompile).configureEach {
diff --git a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/Fingerprint.java b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/Fingerprint.java
index 004bea8..d92eaa5 100644
--- a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/Fingerprint.java
+++ b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/Fingerprint.java
@@ -41,7 +41,6 @@
@RestrictTo(Scope.LIBRARY_GROUP)
public final class Fingerprint {
private static final int DEFAULT_VALUE = 0;
- private static final int DISCARDED_VALUE = -1;
private final int selfTypeValue;
private int selfPropsValue;
private int childNodesValue;
@@ -65,12 +64,9 @@
/**
* Get the aggregate numeric fingerprint, representing the message itself as well as all its
- * child nodes. Returns -1 if the fingerprint is discarded.
+ * child nodes.
*/
public int aggregateValueAsInt() {
- if (selfPropsValue == DISCARDED_VALUE) {
- return DISCARDED_VALUE;
- }
int aggregateValue = selfTypeValue;
aggregateValue = (31 * aggregateValue) + selfPropsValue;
aggregateValue = (31 * aggregateValue) + childNodesValue;
@@ -84,72 +80,29 @@
/**
* Get the numeric fingerprint for the message's properties only, excluding its type and child
- * nodes. Returns -1 if the fingerprint is discarded.
+ * nodes.
*/
public int selfPropsValue() {
return selfPropsValue;
}
- /**
- * Get the numeric fingerprint for the child nodes. Returns -1 if the fingerprint for children
- * is discarded.
- *
- * <p>Note: If {@link #childNodes()} is empty, the children should be considered fully discarded
- * at this level. Otherwise, at least one of the children is discarded (self discard) and the
- * fingerprint of each children should be checked individually.
- */
+ /** Get the numeric fingerprint for the child nodes. */
public int childNodesValue() {
return childNodesValue;
}
- /**
- * Get the child nodes. Returns empty list if the node has no children, or if the child
- * fingerprints are discarded.
- */
+ /** Get the child nodes. Returns empty list if the node has no children. */
public @NonNull List<Fingerprint> childNodes() {
return childNodes == null ? Collections.emptyList() : childNodes;
}
/** Add a child node to this fingerprint. */
public void addChildNode(@NonNull Fingerprint childNode) {
- // Even if the children are not discarded directly through discardValued(true), if one of
- // them is individually discarded, we need to propagate that so that the differ knows it
- // has to go down one more level. That's why childNodesValue == DISCARDED_VALUE doesn't
- // necessarily mean all of the children are discarded. childNodes is used to
- // differentiate these two cases.
- if (selfPropsValue == DISCARDED_VALUE
- && childNodesValue == DISCARDED_VALUE
- && childNodes == null) {
- return;
- }
if (childNodes == null) {
childNodes = new ArrayList<>();
}
childNodes.add(childNode);
- if (childNode.selfPropsValue == DISCARDED_VALUE) {
- childNodesValue = DISCARDED_VALUE;
- } else if (childNodesValue != DISCARDED_VALUE) {
- childNodesValue = (31 * childNodesValue) + childNode.aggregateValueAsInt();
- }
- }
-
- /**
- * Discard values of this fingerprint.
- *
- * @param includeChildren if True, discards children values of this fingerprints too.
- */
- public void discardValues(boolean includeChildren) {
- if (selfPropsValue == DISCARDED_VALUE
- && childNodesValue == DISCARDED_VALUE
- && !includeChildren) {
- throw new IllegalStateException(
- "Container is in discarded state. Children can't be reinstated.");
- }
- selfPropsValue = DISCARDED_VALUE;
- if (includeChildren) {
- childNodesValue = DISCARDED_VALUE;
- childNodes = null;
- }
+ childNodesValue = (31 * childNodesValue) + childNode.aggregateValueAsInt();
}
/** Record a property value being updated. */
diff --git a/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/FingerprintTest.java b/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/FingerprintTest.java
index ad075ef..2f99ad8 100644
--- a/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/FingerprintTest.java
+++ b/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/FingerprintTest.java
@@ -44,34 +44,6 @@
}
@Test
- public void discard_clearsSelfFingerprint() {
- Fingerprint parentFingerPrint = new Fingerprint(SELF_TYPE_VALUE);
- Fingerprint childFingerPrint = new Fingerprint(SELF_TYPE_VALUE);
- childFingerPrint.recordPropertyUpdate(FIELD_1, VALUE_HASH1);
- parentFingerPrint.addChildNode(childFingerPrint);
-
- parentFingerPrint.discardValues(/* includeChildren= */ false);
-
- assertThat(parentFingerPrint.selfPropsValue()).isEqualTo(DISCARDED_VALUE);
- assertThat(parentFingerPrint.childNodes()).containsExactly(childFingerPrint);
- assertThat(parentFingerPrint.childNodesValue()).isNotEqualTo(DISCARDED_VALUE);
- }
-
- @Test
- public void discard_includeChildren_clearsSelfAndChildrenFingerprint() {
- Fingerprint parentFingerPrint = new Fingerprint(SELF_TYPE_VALUE);
- Fingerprint childFingerPrint = new Fingerprint(SELF_TYPE_VALUE);
- childFingerPrint.recordPropertyUpdate(FIELD_1, VALUE_HASH1);
- parentFingerPrint.addChildNode(childFingerPrint);
-
- parentFingerPrint.discardValues(/* includeChildren= */ true);
-
- assertThat(parentFingerPrint.selfPropsValue()).isEqualTo(DISCARDED_VALUE);
- assertThat(parentFingerPrint.childNodes()).isEmpty();
- assertThat(parentFingerPrint.childNodesValue()).isEqualTo(DISCARDED_VALUE);
- }
-
- @Test
public void toProto_fromProto() {
Fingerprint parentFingerPrint = new Fingerprint(SELF_TYPE_VALUE);
Fingerprint childFingerPrint = new Fingerprint(SELF_TYPE_VALUE);
diff --git a/wear/protolayout/protolayout-material-core/src/main/java/androidx/wear/protolayout/materialcore/Chip.java b/wear/protolayout/protolayout-material-core/src/main/java/androidx/wear/protolayout/materialcore/Chip.java
index 97cb0f0..0dafa26 100644
--- a/wear/protolayout/protolayout-material-core/src/main/java/androidx/wear/protolayout/materialcore/Chip.java
+++ b/wear/protolayout/protolayout-material-core/src/main/java/androidx/wear/protolayout/materialcore/Chip.java
@@ -307,7 +307,11 @@
new Corner.Builder()
.setRadius(radiusOf(mHeight))
.build())
- .build());
+ .build())
+ .setSemantics(
+ new Semantics.Builder()
+ .setContentDescription(getCorrectContentDescription())
+ .build());
Box.Builder visible =
new Box.Builder()
@@ -327,14 +331,9 @@
.setWidth(resolveMinTappableWidth())
.setHeight(dp(resolveMinTappableHeight()))
.setModifiers(
- new Modifiers.Builder()
- .setMetadata(getCorrectMetadataTag())
- .setSemantics(
- new Semantics.Builder()
- .setContentDescription(
- getCorrectContentDescription())
- .build())
- .build())
+ new Modifiers.Builder()
+ .setMetadata(getCorrectMetadataTag())
+ .build())
.addContent(visible.build())
.build();
@@ -463,7 +462,8 @@
/** Returns content description of this Chip. */
@Nullable
public StringProp getContentDescription() {
- Semantics semantics = checkNotNull(mImpl.getModifiers()).getSemantics();
+ // Semantics are applied to the visible view.
+ Semantics semantics = checkNotNull(mElement.getModifiers()).getSemantics();
if (semantics == null) {
return null;
}
diff --git a/wear/protolayout/protolayout-material/api/current.txt b/wear/protolayout/protolayout-material/api/current.txt
index fda934c..02d6896 100644
--- a/wear/protolayout/protolayout-material/api/current.txt
+++ b/wear/protolayout/protolayout-material/api/current.txt
@@ -189,6 +189,7 @@
ctor public Text.Builder(android.content.Context, String);
method public androidx.wear.protolayout.material.Text build();
method public androidx.wear.protolayout.material.Text.Builder setColor(androidx.wear.protolayout.ColorBuilders.ColorProp);
+ method public androidx.wear.protolayout.material.Text.Builder setIsScalable(boolean);
method public androidx.wear.protolayout.material.Text.Builder setItalic(boolean);
method public androidx.wear.protolayout.material.Text.Builder setMaxLines(@IntRange(from=1) int);
method public androidx.wear.protolayout.material.Text.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
diff --git a/wear/protolayout/protolayout-material/api/restricted_current.txt b/wear/protolayout/protolayout-material/api/restricted_current.txt
index fda934c..02d6896 100644
--- a/wear/protolayout/protolayout-material/api/restricted_current.txt
+++ b/wear/protolayout/protolayout-material/api/restricted_current.txt
@@ -189,6 +189,7 @@
ctor public Text.Builder(android.content.Context, String);
method public androidx.wear.protolayout.material.Text build();
method public androidx.wear.protolayout.material.Text.Builder setColor(androidx.wear.protolayout.ColorBuilders.ColorProp);
+ method public androidx.wear.protolayout.material.Text.Builder setIsScalable(boolean);
method public androidx.wear.protolayout.material.Text.Builder setItalic(boolean);
method public androidx.wear.protolayout.material.Text.Builder setMaxLines(@IntRange(from=1) int);
method public androidx.wear.protolayout.material.Text.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
diff --git a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Chip.java b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Chip.java
index e256216..26f4d3f 100644
--- a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Chip.java
+++ b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Chip.java
@@ -368,7 +368,7 @@
}
}
- @SuppressWarnings("deprecation") // ELLIPSIZE_END as existing API
+ @SuppressWarnings("deprecation") // TEXT_OVERFLOW_ELLIPSIZE_END as existing API
private void setCorrectContent() {
if (mImageResourceId != null) {
Image icon =
diff --git a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Text.java b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Text.java
index f50c11f..1dd0856 100644
--- a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Text.java
+++ b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Text.java
@@ -151,7 +151,9 @@
// Text size is always set in SP, however, by setting this field, we do calculation to
// interpret it like DP. When getting the text font's size in getters, there is no way to
// know whether that size was scaled or not.
- Builder setIsScalable(boolean isScalable) {
+ @NonNull
+ @SuppressWarnings("MissingGetterMatchingBuilder")
+ public Builder setIsScalable(boolean isScalable) {
this.mIsScalable = isScalable;
return this;
}
diff --git a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Typography.java b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Typography.java
index a297558..9e1613e 100644
--- a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Typography.java
+++ b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Typography.java
@@ -185,7 +185,7 @@
@NonNull
@SuppressLint("ResourceType")
- @SuppressWarnings("deprecation")
+ @SuppressWarnings("deprecation") // scaledDensity, b/335215227
// This is a helper function to make the font not scalable. It should interpret in value as DP
// and convert it to SP which is needed to be passed in as a font size. However, we will pass an
// SP object to it, because the default style is defined in it, but for the case when the font
diff --git a/wear/protolayout/protolayout-proto/src/main/proto/layout.proto b/wear/protolayout/protolayout-proto/src/main/proto/layout.proto
index 32eec63..e55a6199d 100644
--- a/wear/protolayout/protolayout-proto/src/main/proto/layout.proto
+++ b/wear/protolayout/protolayout-proto/src/main/proto/layout.proto
@@ -136,6 +136,32 @@
// body text, which can be selected using this field. If not specified,
// defaults to "body".
FontVariantProp variant = 7;
+
+ // The collection of font variation settings to be applied.
+ //
+ // Supported settings depend on the font used and renderer version. Renderers supporting 1.4 will
+ // have custom weight always available. If this is used with the variable fonts on those
+ // renderers, width setting will be always available too.
+ FontVariation variation_settings = 8;
+}
+
+// The collection of font variation settings.
+//
+// Supported settings depend on the font used and renderer version. Renderers supporting 1.4 will
+// have custom weight always available. If this is used with the variable fonts on those renderers,
+// width setting will be always available too.
+message FontVariation {
+ // A single point of customization in a variation, with axis name and a value for it.
+ repeated Setting settings = 1;
+}
+
+// A single point of customization in a variation, with axis name and a value for it.
+message Setting {
+ // The axis name for this setting. This represents a 4 ASCII characters tag.
+ fixed32 axis_name = 1;
+
+ // The value for this setting.
+ float variation_value = 2;
}
// How text that will not fit inside the bounds of a Text element will be
diff --git a/wear/protolayout/protolayout/api/current.txt b/wear/protolayout/protolayout/api/current.txt
index 24afe14..e950512 100644
--- a/wear/protolayout/protolayout/api/current.txt
+++ b/wear/protolayout/protolayout/api/current.txt
@@ -1153,8 +1153,8 @@
}
@androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=400) public static final class ModifiersBuilders.Transformation {
- method public androidx.wear.protolayout.DimensionBuilders.PivotDimension? getPivotX();
- method public androidx.wear.protolayout.DimensionBuilders.PivotDimension? getPivotY();
+ method public androidx.wear.protolayout.DimensionBuilders.PivotDimension getPivotX();
+ method public androidx.wear.protolayout.DimensionBuilders.PivotDimension getPivotY();
method public androidx.wear.protolayout.DimensionBuilders.DegreesProp getRotation();
method public androidx.wear.protolayout.TypeBuilders.FloatProp getScaleX();
method public androidx.wear.protolayout.TypeBuilders.FloatProp getScaleY();
diff --git a/wear/protolayout/protolayout/api/restricted_current.txt b/wear/protolayout/protolayout/api/restricted_current.txt
index 24afe14..e950512 100644
--- a/wear/protolayout/protolayout/api/restricted_current.txt
+++ b/wear/protolayout/protolayout/api/restricted_current.txt
@@ -1153,8 +1153,8 @@
}
@androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=400) public static final class ModifiersBuilders.Transformation {
- method public androidx.wear.protolayout.DimensionBuilders.PivotDimension? getPivotX();
- method public androidx.wear.protolayout.DimensionBuilders.PivotDimension? getPivotY();
+ method public androidx.wear.protolayout.DimensionBuilders.PivotDimension getPivotX();
+ method public androidx.wear.protolayout.DimensionBuilders.PivotDimension getPivotY();
method public androidx.wear.protolayout.DimensionBuilders.DegreesProp getRotation();
method public androidx.wear.protolayout.TypeBuilders.FloatProp getScaleX();
method public androidx.wear.protolayout.TypeBuilders.FloatProp getScaleY();
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 a6bb9fe..c3f280c 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
@@ -1399,28 +1399,30 @@
}
/**
- * Sets the x offset of the point around which the element is rotated and scaled.
- * Dynamic value is supported.
+ * Gets the horizontal location of the point around which the element is rotated and scaled.
+ * With type {@link DpProp}, it is the offset from the element center; otherwise with type
+ * {@link BoundingBoxRatio}, it is the location proportional to the bounding box width.
*/
- @Nullable
+ @NonNull
public PivotDimension getPivotX() {
if (mImpl.hasPivotX()) {
return DimensionBuilders.pivotDimensionFromProto(mImpl.getPivotX());
} else {
- return null;
+ return new DpProp.Builder(0f).build();
}
}
/**
- * Gets the y offset of the point around which the element is rotated and scaled.
- * Dynamic value is supported.
+ * Gets the vertical location of the point around which the element is rotated and scaled.
+ * With type {@link DpProp}, it is the offset from the element center; otherwise with type
+ * {@link BoundingBoxRatio}, it is the location proportional to the bounding box height.
*/
- @Nullable
+ @NonNull
public PivotDimension getPivotY() {
if (mImpl.hasPivotY()) {
return DimensionBuilders.pivotDimensionFromProto(mImpl.getPivotY());
} else {
- return null;
+ return new DpProp.Builder(0f).build();
}
}
@@ -1548,8 +1550,10 @@
}
/**
- * Sets the x offset of the point around which the element is rotated and scaled.
- * Dynamic value is supported. If not set, defaults to the element center.
+ * Sets the horizontal location of the point around which the element is rotated and
+ * scaled. With type {@link DpProp}, it is the offset from the element center; otherwise
+ * with type {@link BoundingBoxRatio}, it is the location proportional to the bounding
+ * box width. Dynamic value is supported. If not set, defaults to the element center.
*/
@RequiresSchemaVersion(major = 1, minor = 400)
@NonNull
@@ -1561,8 +1565,10 @@
}
/**
- * Sets the y offset of the point around which the element is rotated and scaled.
- * Dynamic value is supported. If not set, defaults to the element center.
+ * Sets the vertical location of the point around which the element is rotated and
+ * scaled. With type {@link DpProp}, it is the offset from the element center; otherwise
+ * with type {@link BoundingBoxRatio}, it is the location proportional to the bounding
+ * box height. Dynamic value is supported. If not set, defaults to the element center.
*/
@RequiresSchemaVersion(major = 1, minor = 400)
@NonNull
diff --git a/webkit/integration-tests/instrumentation/build.gradle b/webkit/integration-tests/instrumentation/build.gradle
index a3fa81d..4a7e8af 100644
--- a/webkit/integration-tests/instrumentation/build.gradle
+++ b/webkit/integration-tests/instrumentation/build.gradle
@@ -23,7 +23,12 @@
productFlavors {
targetSdk32 {
dimension "targetSdk"
- targetSdkVersion 32
+ testOptions {
+ targetSdk 32
+ }
+ lint {
+ targetSdk 32
+ }
}
targetSdkLatest {
dimension "targetSdk"
diff --git a/window/window/build.gradle b/window/window/build.gradle
index 4df8a41..0f9e2d0 100644
--- a/window/window/build.gradle
+++ b/window/window/build.gradle
@@ -101,4 +101,5 @@
// Suppressing deprecation warnings, since there is a need to maintain compatibility with old
// Sidecar interface.
failOnDeprecationWarnings = false
+ samples(project(":window:window-samples"))
}