Merge changes I0571008f,I83929941 into androidx-main
* changes:
useDefaultMaxWidth -> usePlatformDefaultWidth
Alow Dialogs to use the entire screen width
diff --git a/.github/workflows/presubmit.yml b/.github/workflows/presubmit.yml
index d292755..c41d950 100644
--- a/.github/workflows/presubmit.yml
+++ b/.github/workflows/presubmit.yml
@@ -56,29 +56,10 @@
echo "ANDROID_SDK_ROOT=$HOME/Library/Android/sdk" >> $GITHUB_ENV
echo "DIST_DIR=$HOME/dist" >> $GITHUB_ENV
- - name: "Compute actions/checkout arguments"
- id: checkout-args
- run: |
- set -x
-
- REF=${{ github.event.pull_request.head.ref }}
- if [ -z "$REF" ]; then
- REF=${{ github.event.ref }}
- fi
- echo "::set-output name=ref::$REF"
-
- REPOSITORY=${{ github.event.pull_request.head.repo.full_name }}
- if [ -z "$REPOSITORY" ]; then
- REPOSITORY=${{ github.repository }}
- fi
- echo "::set-output name=repository::$REPOSITORY"
-
- name: "Checkout androidx repo"
uses: actions/checkout@v2
with:
- ref: ${{ steps.checkout-args.outputs.ref }}
- repository: ${{ steps.checkout-args.outputs.repository }}
- fetch-depth: 0 # Need full depth for changed-files-action
+ fetch-depth: 1
- name: "Get changed files in push or pull_request"
id: changed-files
@@ -102,7 +83,7 @@
JAVA_HOME: ${{ steps.setup-java.outputs.path }}
with:
arguments: -q :ktlintCheckFile ${{ steps.ktlint-file-args.outputs.ktlint-file-args }} ${{ needs.setup.outputs.gradlew_flags }}
- build-root-directory: activity
+ build-root-directory: room
configuration-cache-enabled: true
dependencies-cache-enabled: true
gradle-executable: activity/gradlew
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatBaseImageViewTest.java b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatBaseImageViewTest.java
index 18f7ef7..44ce501 100755
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatBaseImageViewTest.java
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatBaseImageViewTest.java
@@ -20,6 +20,8 @@
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static org.junit.Assert.assertEquals;
+
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.PorterDuff;
@@ -35,6 +37,7 @@
import androidx.appcompat.testutils.TestUtils;
import androidx.core.content.res.ResourcesCompat;
import androidx.core.graphics.ColorUtils;
+import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.MediumTest;
import org.junit.Test;
@@ -459,4 +462,30 @@
verifyImageSourceIsColoredAs("New lilac image tinting", view,
lilacDefault, 0);
}
+
+ @Test
+ @UiThreadTest
+ public void testLevelOnSetImageDrawable() {
+ final @IdRes int viewId = R.id.view_without_level;
+ final Resources res = mActivity.getResources();
+ final ImageView imageView = mContainer.findViewById(viewId);
+ final Drawable drawable = res.getDrawable(R.drawable.test_level_drawable);
+ drawable.setLevel(5);
+ imageView.setImageDrawable(drawable);
+ assertEquals(5, imageView.getDrawable().getLevel());
+ }
+
+ @Test
+ @UiThreadTest
+ public void testSetImageLevel() {
+ final @IdRes int viewId = R.id.view_without_level;
+ final Resources res = mActivity.getResources();
+ final ImageView imageView = mContainer.findViewById(viewId);
+ imageView.setImageLevel(5);
+ final Drawable drawable = res.getDrawable(R.drawable.test_level_drawable);
+ drawable.setLevel(1);
+ imageView.setImageDrawable(drawable);
+ assertEquals(5, imageView.getDrawable().getLevel());
+ }
+
}
diff --git a/appcompat/appcompat/src/androidTest/res/layout/appcompat_imagebutton_activity.xml b/appcompat/appcompat/src/androidTest/res/layout/appcompat_imagebutton_activity.xml
index e8733b2..3007988 100755
--- a/appcompat/appcompat/src/androidTest/res/layout/appcompat_imagebutton_activity.xml
+++ b/appcompat/appcompat/src/androidTest/res/layout/appcompat_imagebutton_activity.xml
@@ -96,6 +96,11 @@
android:layout_height="wrap_content"
android:focusable="false"/>
+ <androidx.appcompat.widget.AppCompatImageButton
+ android:id="@+id/view_without_level"
+ android:layout_width="30dp"
+ android:layout_height="30dp" />
+
</LinearLayout>
</ScrollView>
diff --git a/appcompat/appcompat/src/androidTest/res/layout/appcompat_imageview_activity.xml b/appcompat/appcompat/src/androidTest/res/layout/appcompat_imageview_activity.xml
index 2ccd325..fbb8459 100644
--- a/appcompat/appcompat/src/androidTest/res/layout/appcompat_imageview_activity.xml
+++ b/appcompat/appcompat/src/androidTest/res/layout/appcompat_imageview_activity.xml
@@ -95,6 +95,11 @@
android:src="@drawable/test_drawable_blue"
app:srcCompat="@drawable/test_drawable_red" />
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/view_without_level"
+ android:layout_width="30dp"
+ android:layout_height="30dp" />
+
</LinearLayout>
</ScrollView>
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatImageButton.java b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatImageButton.java
index 1ea6667..39072be 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatImageButton.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatImageButton.java
@@ -63,6 +63,7 @@
private final AppCompatBackgroundHelper mBackgroundTintHelper;
private final AppCompatImageHelper mImageHelper;
+ private boolean mHasLevel = false;
public AppCompatImageButton(@NonNull Context context) {
this(context, null);
@@ -93,9 +94,17 @@
@Override
public void setImageDrawable(@Nullable Drawable drawable) {
+ if (mImageHelper != null && drawable != null && !mHasLevel) {
+ // If there is no level set already then obtain the level from the drawable
+ mImageHelper.obtainLevelFromDrawable(drawable);
+ }
super.setImageDrawable(drawable);
if (mImageHelper != null) {
mImageHelper.applySupportImageTint();
+ if (!mHasLevel) {
+ // Apply the level from drawable
+ mImageHelper.applyImageLevel();
+ }
}
}
@@ -257,4 +266,10 @@
public boolean hasOverlappingRendering() {
return mImageHelper.hasOverlappingRendering() && super.hasOverlappingRendering();
}
+
+ @Override
+ public void setImageLevel(int level) {
+ super.setImageLevel(level);
+ mHasLevel = true;
+ }
}
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatImageHelper.java b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatImageHelper.java
index 27e9118..0c7a123 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatImageHelper.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatImageHelper.java
@@ -43,6 +43,7 @@
private TintInfo mInternalImageTint;
private TintInfo mImageTint;
private TintInfo mTmpInfo;
+ private int mLevel = 0;
public AppCompatImageHelper(@NonNull ImageView view) {
mView = view;
@@ -221,4 +222,21 @@
return false;
}
+
+ /**
+ * Extracts the level from the drawable parameter and save it for the future use in
+ * {@link #applyImageLevel()}
+ */
+ void obtainLevelFromDrawable(@NonNull Drawable drawable) {
+ mLevel = drawable.getLevel();
+ }
+
+ /**
+ * Applies the level previously set through {@link #obtainLevelFromDrawable}
+ */
+ void applyImageLevel() {
+ if (mView.getDrawable() != null) {
+ mView.getDrawable().setLevel(mLevel);
+ }
+ }
}
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatImageView.java b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatImageView.java
index c5bf0f8..78ffeb4 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatImageView.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatImageView.java
@@ -63,6 +63,8 @@
private final AppCompatBackgroundHelper mBackgroundTintHelper;
private final AppCompatImageHelper mImageHelper;
+ private boolean mHasLevel = false;
+
public AppCompatImageView(@NonNull Context context) {
this(context, null);
}
@@ -103,9 +105,17 @@
@Override
public void setImageDrawable(@Nullable Drawable drawable) {
+ if (mImageHelper != null && drawable != null && !mHasLevel) {
+ // If there is no level set already then obtain the level from the drawable
+ mImageHelper.obtainLevelFromDrawable(drawable);
+ }
super.setImageDrawable(drawable);
if (mImageHelper != null) {
mImageHelper.applySupportImageTint();
+ if (!mHasLevel) {
+ // Apply the level from drawable
+ mImageHelper.applyImageLevel();
+ }
}
}
@@ -268,4 +278,10 @@
public boolean hasOverlappingRendering() {
return mImageHelper.hasOverlappingRendering() && super.hasOverlappingRendering();
}
+
+ @Override
+ public void setImageLevel(int level) {
+ super.setImageLevel(level);
+ mHasLevel = true;
+ }
}
diff --git a/appcompat/appcompat/src/main/res/drawable/test_level_drawable.xml b/appcompat/appcompat/src/main/res/drawable/test_level_drawable.xml
new file mode 100644
index 0000000..41dadfd
--- /dev/null
+++ b/appcompat/appcompat/src/main/res/drawable/test_level_drawable.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="@color/primary_dark_material_dark"/>
+ <corners android:radius="10dp"/>
+</shape>
\ No newline at end of file
diff --git a/appcompat/appcompat/src/main/res/values-or/strings.xml b/appcompat/appcompat/src/main/res/values-or/strings.xml
index 6f29662..edb0e65 100644
--- a/appcompat/appcompat/src/main/res/values-or/strings.xml
+++ b/appcompat/appcompat/src/main/res/values-or/strings.xml
@@ -31,7 +31,7 @@
<string name="abc_activity_chooser_view_see_all" msgid="1189761859438369441">"ସବୁ ଦେଖନ୍ତୁ"</string>
<string name="abc_shareactionprovider_share_with_application" msgid="9055268688411532828">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> ସହ ସେୟାର୍ କରନ୍ତୁ"</string>
<string name="abc_shareactionprovider_share_with" msgid="8875138169939072951">"ଏହାଙ୍କ ସହ ସେୟାର୍ କରନ୍ତୁ"</string>
- <string name="abc_capital_on" msgid="884982626291842264">"ଅନ୍"</string>
+ <string name="abc_capital_on" msgid="884982626291842264">"ଚାଲୁ ଅଛି"</string>
<string name="abc_capital_off" msgid="4215997306490295099">"ବନ୍ଦ"</string>
<string name="search_menu_title" msgid="6264217191555673260">"Search"</string>
<string name="abc_prepend_shortcut_label" msgid="5520303668377388990">"ମେନୁ"</string>
@@ -43,5 +43,5 @@
<string name="abc_menu_function_shortcut_label" msgid="375214403600139847">"Function+"</string>
<string name="abc_menu_space_shortcut_label" msgid="5473865519181928982">"ସ୍ପେସ୍"</string>
<string name="abc_menu_enter_shortcut_label" msgid="7986526966204849475">"ଏଣ୍ଟର୍"</string>
- <string name="abc_menu_delete_shortcut_label" msgid="838001238306846836">"ଡିଲିଟ୍"</string>
+ <string name="abc_menu_delete_shortcut_label" msgid="838001238306846836">"ଡିଲିଟ୍ କରନ୍ତୁ"</string>
</resources>
diff --git a/buildSrc/src/main/kotlin/androidx/build/checkapi/ApiTasks.kt b/buildSrc/src/main/kotlin/androidx/build/checkapi/ApiTasks.kt
index 4f521ef..46c5574 100644
--- a/buildSrc/src/main/kotlin/androidx/build/checkapi/ApiTasks.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/checkapi/ApiTasks.kt
@@ -163,7 +163,10 @@
javaInputs = JavaCompileInputs.fromLibraryVariant(
variant,
- project
+ project,
+ // Note, in addition to androidx, bootClasspath will also include stub jars
+ // from android { useLibrary "android.foo" } block.
+ files(config.library.bootClasspath)
)
processManifest = config.library.buildOutputs.getByName(variant.name)
.processManifestProvider.get() as ProcessLibraryManifest
diff --git a/buildSrc/src/main/kotlin/androidx/build/java/JavaCompileInputs.kt b/buildSrc/src/main/kotlin/androidx/build/java/JavaCompileInputs.kt
index 98740fa..2693218 100644
--- a/buildSrc/src/main/kotlin/androidx/build/java/JavaCompileInputs.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/java/JavaCompileInputs.kt
@@ -40,7 +40,8 @@
// Constructs a JavaCompileInputs from a library and its variant
fun fromLibraryVariant(
variant: BaseVariant,
- project: Project
+ project: Project,
+ bootClasspath: FileCollection
): JavaCompileInputs {
val sourceCollection = getSourceCollection(variant, project)
@@ -51,7 +52,7 @@
return JavaCompileInputs(
sourceCollection,
dependencyClasspath,
- androidJarFile(project)
+ bootClasspath
)
}
diff --git a/camera/camera-camera2-pipe-integration/build.gradle b/camera/camera-camera2-pipe-integration/build.gradle
index 09c1751..97e9f89 100644
--- a/camera/camera-camera2-pipe-integration/build.gradle
+++ b/camera/camera-camera2-pipe-integration/build.gradle
@@ -64,6 +64,8 @@
testImplementation(libs.robolectric)
testImplementation(libs.kotlinCoroutinesTest)
testImplementation(project(":camera:camera-camera2-pipe-testing"))
+ testImplementation(project(":camera:camera-testing"))
+ testImplementation(project(":internal-testutils-ktx"))
testImplementation(project(":internal-testutils-truth"))
androidTestImplementation(libs.testExtJunit)
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapter.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapter.kt
new file mode 100644
index 0000000..6da648c
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapter.kt
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.camera2.pipe.integration.adapter
+
+import android.hardware.camera2.CaptureRequest
+import android.view.Surface
+import androidx.camera.camera2.pipe.CameraGraph
+import androidx.camera.camera2.pipe.StreamId
+import androidx.camera.camera2.pipe.core.Log
+import androidx.camera.camera2.pipe.core.Log.debug
+import androidx.camera.camera2.pipe.integration.impl.UseCaseThreads
+import androidx.camera.core.UseCase
+import androidx.camera.core.impl.DeferrableSurface
+import androidx.camera.core.impl.SessionConfig
+import androidx.camera.core.impl.utils.futures.Futures
+import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.async
+import kotlinx.coroutines.guava.await
+import kotlinx.coroutines.isActive
+import kotlinx.coroutines.withContext
+import kotlinx.coroutines.withTimeoutOrNull
+
+private const val TIMEOUT_GET_SURFACE_IN_MS = 5_000L
+
+/**
+ * Aggregate the SessionConfig from a List of [UseCase]s, and provide a validated SessionConfig for
+ * operation.
+ */
+class SessionConfigAdapter(
+ private val useCases: List<UseCase>,
+ private val threads: UseCaseThreads,
+) {
+ private val validatingBuilder: SessionConfig.ValidatingBuilder by lazy {
+ val validatingBuilder = SessionConfig.ValidatingBuilder()
+ useCases.forEach {
+ it.sessionConfig?.let { sessionConfig -> validatingBuilder.add(sessionConfig) }
+ ?: Log.debug { "Failed to add use case: $it" }
+ }
+ validatingBuilder
+ }
+
+ private val deferrableSurfaces: List<DeferrableSurface> by lazy {
+ sessionConfig.surfaces
+ }
+
+ private val sessionConfig: SessionConfig by lazy {
+ check(validatingBuilder.isValid)
+
+ validatingBuilder.build()
+ }
+
+ fun getValidSessionConfigOrNull(): SessionConfig? {
+ return if (isSessionConfigValid()) sessionConfig else null
+ }
+
+ fun isSessionConfigValid(): Boolean {
+ return validatingBuilder.isValid
+ }
+
+ fun setupSurfaceAsync(
+ graph: CameraGraph,
+ surfaceToStreamMap: Map<DeferrableSurface, StreamId>
+ ): Deferred<Unit> =
+ threads.scope.async {
+ val surfaces = getSurfaces(deferrableSurfaces)
+
+ if (!isActive) return@async
+
+ if (surfaces.isEmpty()) {
+ Log.debug { "Surface list is empty" }
+ return@async
+ }
+
+ if (areSurfacesValid(surfaces)) {
+ surfaceToStreamMap.forEach {
+ val stream = it.value
+ val surface = surfaces[deferrableSurfaces.indexOf(it.key)]
+ debug { "Configured $surface for $stream" }
+ graph.setSurface(
+ stream = stream,
+ surface = surface
+ )
+ }
+ } else {
+ Log.debug { "Surface contains failed, notify SessionConfig invalid" }
+
+ // Only handle the first failed Surface since subsequent calls to
+ // CameraInternal#onUseCaseReset() will handle the other failed Surfaces if there
+ // are any.
+ val deferrableSurface = deferrableSurfaces[surfaces.indexOf(null)]
+ val sessionConfig =
+ useCases.firstOrNull { useCase ->
+ useCase.sessionConfig?.surfaces?.contains(deferrableSurface) ?: false
+ }?.sessionConfig
+
+ withContext(Dispatchers.Main) {
+ // The error listener is used to notify the UseCase to recreate the pipeline,
+ // and the create pipeline task would be executed on the main thread.
+ sessionConfig?.errorListeners?.forEach {
+ it.onError(
+ sessionConfig,
+ SessionConfig.SessionError.SESSION_ERROR_SURFACE_NEEDS_RESET
+ )
+ }
+ }
+ }
+ }
+
+ private suspend fun getSurfaces(deferrableSurfaces: List<DeferrableSurface>): List<Surface?> {
+ return withTimeoutOrNull(timeMillis = TIMEOUT_GET_SURFACE_IN_MS) {
+ Futures.successfulAsList(
+ deferrableSurfaces.map {
+ it.surface
+ }
+ ).await()
+ }.orEmpty()
+ }
+
+ private fun areSurfacesValid(surfaces: List<Surface?>): Boolean {
+ // If a Surface in configuredSurfaces is null it means the
+ // Surface was not retrieved from the ListenableFuture.
+ return surfaces.isNotEmpty() && !surfaces.contains(null)
+ }
+}
+
+/**
+ * Convert the implementation options to the CaptureRequest key-value map.
+ */
+fun SessionConfig.getImplementationOptionParameters(): Map<CaptureRequest.Key<*>, Any> {
+ val parameters = mutableMapOf<CaptureRequest.Key<*>, Any>()
+ for (configOption in implementationOptions.listOptions()) {
+ val requestKey = configOption.token as? CaptureRequest.Key<*> ?: continue
+ val value = implementationOptions.retrieveOption(configOption) ?: continue
+ parameters[requestKey] = value
+ }
+
+ return parameters
+}
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCamera.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCamera.kt
index bf7a093..5f44be3 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCamera.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCamera.kt
@@ -18,7 +18,6 @@
import android.hardware.camera2.CaptureRequest
import android.hardware.camera2.params.MeteringRectangle
-import android.view.Surface
import androidx.camera.camera2.pipe.CameraGraph
import androidx.camera.camera2.pipe.CameraPipe
import androidx.camera.camera2.pipe.CameraStream
@@ -29,13 +28,13 @@
import androidx.camera.camera2.pipe.TorchState
import androidx.camera.camera2.pipe.core.Log.debug
import androidx.camera.camera2.pipe.integration.adapter.CaptureConfigAdapter
+import androidx.camera.camera2.pipe.integration.adapter.SessionConfigAdapter
+import androidx.camera.camera2.pipe.integration.adapter.getImplementationOptionParameters
import androidx.camera.camera2.pipe.integration.config.CameraConfig
import androidx.camera.camera2.pipe.integration.config.UseCaseCameraScope
import androidx.camera.core.UseCase
import androidx.camera.core.impl.CaptureConfig
import androidx.camera.core.impl.DeferrableSurface
-import androidx.camera.core.impl.utils.futures.FutureCallback
-import androidx.camera.core.impl.utils.futures.Futures
import dagger.Module
import dagger.Provides
import kotlinx.atomicfu.atomic
@@ -81,6 +80,7 @@
) : UseCaseCamera {
private val debugId = useCaseCameraIds.incrementAndGet()
private val currentParameters = mutableMapOf<CaptureRequest.Key<*>, Any>()
+ private var activeSessionConfigAdapter: SessionConfigAdapter? = null
private var _activeUseCases = setOf<UseCase>()
override var activeUseCases: Set<UseCase>
@@ -89,6 +89,7 @@
// Note: This may be called with the same set of values that was previously set. This
// is used as a signal to indicate the properties of the UseCase may have changed.
_activeUseCases = value
+ activeSessionConfigAdapter = SessionConfigAdapter(_activeUseCases.toList(), threads)
updateUseCases()
}
@@ -166,14 +167,26 @@
}
}
}
-
- val repeatingCallbacks = useCase.sessionConfig?.repeatingCameraCaptureCallbacks
- repeatingCallbacks?.forEach {
- repeatingListeners.addCaptureCallback(it, threads.backgroundExecutor)
- }
}
- state.update(streams = repeatingStreamIds, listeners = setOf(repeatingListeners))
+ activeSessionConfigAdapter?.getValidSessionConfigOrNull()?.let { sessionConfig ->
+ sessionConfig.repeatingCameraCaptureCallbacks.forEach { callback ->
+ repeatingListeners.addCaptureCallback(
+ callback,
+ threads.backgroundExecutor
+ )
+ }
+
+ // Only update the state when the SessionConfig is valid
+ state.update(
+ parameters = sessionConfig.getImplementationOptionParameters(),
+ streams = repeatingStreamIds,
+ listeners = setOf(repeatingListeners)
+ )
+ } ?: run {
+ debug { "Unable to reset the session due to invalid config" }
+ // TODO: Consider to reset the session if there is no valid config.
+ }
}
override fun toString(): String = "UseCaseCamera-$debugId"
@@ -226,25 +239,16 @@
if (stream != null && deferredSurfaces != null && deferredSurfaces.size == 1) {
val deferredSurface = deferredSurfaces.first()
surfaceToStreamMap[deferredSurface] = stream.id
-
- Futures.addCallback(
- deferredSurface.surface,
- object : FutureCallback<Surface?> {
- override fun onSuccess(result: Surface?) {
- debug { "Configured $result for $stream" }
- graph.setSurface(stream.id, result)
- }
-
- override fun onFailure(t: Throwable) {
- debug(t) { "Surface for $deferredSurface failed to arrive!" }
- graph.setSurface(stream.id, null)
- }
- },
- threads.backgroundExecutor
- )
}
}
+ val adapter = SessionConfigAdapter(useCases, threads)
+ if (adapter.isSessionConfigValid()) {
+ adapter.setupSurfaceAsync(graph, surfaceToStreamMap)
+ } else {
+ debug { "Unable to create capture session due to conflicting configurations" }
+ }
+
val state = UseCaseCameraState(graph, threads)
val configAdapter =
CaptureConfigAdapter(surfaceToStreamMap, threads.backgroundExecutor)
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapterTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapterTest.kt
new file mode 100644
index 0000000..0d46290
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapterTest.kt
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.camera2.pipe.integration.adapter
+
+import android.graphics.SurfaceTexture
+import android.hardware.camera2.CameraDevice
+import android.os.Build
+import android.view.Surface
+import androidx.camera.camera2.pipe.CameraGraph
+import androidx.camera.camera2.pipe.StreamGraph
+import androidx.camera.camera2.pipe.StreamId
+import androidx.camera.camera2.pipe.integration.impl.UseCaseThreads
+import androidx.camera.core.impl.DeferrableSurface
+import androidx.camera.core.impl.SessionConfig
+import androidx.camera.core.impl.utils.futures.Futures
+import androidx.camera.testing.fakes.FakeUseCase
+import androidx.camera.testing.fakes.FakeUseCaseConfig
+import androidx.testutils.MainDispatcherRule
+import com.google.common.truth.Truth.assertThat
+import com.google.common.util.concurrent.ListenableFuture
+import kotlinx.coroutines.CoroutineName
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.asCoroutineDispatcher
+import kotlinx.coroutines.runBlocking
+import org.junit.AfterClass
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.annotation.Config
+import org.robolectric.annotation.internal.DoNotInstrument
+import java.util.concurrent.Executors
+
+@RunWith(RobolectricCameraPipeTestRunner::class)
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
+@DoNotInstrument
+class SessionConfigAdapterTest {
+
+ @get:Rule
+ val dispatcherRule = MainDispatcherRule(useCaseThreads.backgroundDispatcher)
+
+ companion object {
+ private val executor = Executors.newSingleThreadExecutor()
+ private val useCaseThreads by lazy {
+ val dispatcher = executor.asCoroutineDispatcher()
+ val cameraScope = CoroutineScope(
+ Job() +
+ dispatcher +
+ CoroutineName("SessionConfigAdapterTest")
+ )
+
+ UseCaseThreads(
+ cameraScope,
+ executor,
+ dispatcher
+ )
+ }
+
+ @JvmStatic
+ @AfterClass
+ fun close() {
+ executor.shutdown()
+ }
+ }
+
+ @Test
+ fun setupSurface_deferrableSurfaceClosed_notifyError() = runBlocking {
+ // Arrange, create DeferrableSurface and invoke DeferrableSurface#close() immediately to
+ // close the Surface and we expect the DeferrableSurface.getSurface() will return a
+ // {@link SurfaceClosedException}.
+ val testDeferrableSurface1 = createTestDeferrableSurface().also { it.close() }
+ val testDeferrableSurface2 = createTestDeferrableSurface().also { it.close() }
+
+ val errorListener = object : SessionConfig.ErrorListener {
+ val results = mutableListOf<Pair<SessionConfig, SessionConfig.SessionError>>()
+ override fun onError(sessionConfig: SessionConfig, error: SessionConfig.SessionError) {
+ results.add(Pair(sessionConfig, error))
+ }
+ }
+
+ val fakeTestUseCase1 = createFakeTestUseCase {
+ it.setupSessionConfig(
+ SessionConfig.Builder().also { sessionConfigBuilder ->
+ sessionConfigBuilder.setTemplateType(CameraDevice.TEMPLATE_PREVIEW)
+ sessionConfigBuilder.addSurface(testDeferrableSurface1)
+ sessionConfigBuilder.addErrorListener(errorListener)
+ }
+ )
+ }
+ val fakeTestUseCase2 = createFakeTestUseCase {
+ it.setupSessionConfig(
+ SessionConfig.Builder().also { sessionConfigBuilder ->
+ sessionConfigBuilder.setTemplateType(CameraDevice.TEMPLATE_PREVIEW)
+ sessionConfigBuilder.addSurface(testDeferrableSurface2)
+ sessionConfigBuilder.addErrorListener(errorListener)
+ }
+ )
+ }
+
+ val fakeGraph = FakeCameraGraph()
+
+ // Act
+ SessionConfigAdapter(
+ useCases = listOf(fakeTestUseCase1, fakeTestUseCase2), threads = useCaseThreads
+ ).setupSurfaceAsync(
+ fakeGraph,
+ mapOf(
+ testDeferrableSurface1 to StreamId(0),
+ testDeferrableSurface2 to StreamId(1)
+ )
+ ).await()
+
+ // Assert, verify it only reports the SURFACE_NEEDS_RESET error on one SessionConfig
+ // at a time.
+ assertThat(fakeGraph.setSurfaceResults.size).isEqualTo(0)
+ assertThat(errorListener.results.size).isEqualTo(1)
+ assertThat(errorListener.results[0].second).isEqualTo(
+ SessionConfig.SessionError.SESSION_ERROR_SURFACE_NEEDS_RESET
+ )
+ }
+
+ @Test
+ fun setupSurface_surfacesShouldSetToGraph() = runBlocking {
+ // Arrange
+ val testDeferrableSurface1 = createTestDeferrableSurface()
+ val testDeferrableSurface2 = createTestDeferrableSurface()
+ val fakeTestUseCase1 = createFakeTestUseCase {
+ it.setupSessionConfig(
+ SessionConfig.Builder().also { sessionConfigBuilder ->
+ sessionConfigBuilder.setTemplateType(CameraDevice.TEMPLATE_PREVIEW)
+ sessionConfigBuilder.addSurface(testDeferrableSurface1)
+ }
+ )
+ }
+ val fakeTestUseCase2 = createFakeTestUseCase {
+ it.setupSessionConfig(
+ SessionConfig.Builder().also { sessionConfigBuilder ->
+ sessionConfigBuilder.setTemplateType(CameraDevice.TEMPLATE_PREVIEW)
+ sessionConfigBuilder.addSurface(testDeferrableSurface2)
+ }
+ )
+ }
+
+ val fakeGraph = FakeCameraGraph()
+ val deferrableSurfaceToStreamId: Map<DeferrableSurface, StreamId> = mapOf(
+ testDeferrableSurface1 to StreamId(0),
+ testDeferrableSurface2 to StreamId(1)
+ )
+
+ // Act
+ SessionConfigAdapter(
+ useCases = listOf(fakeTestUseCase1, fakeTestUseCase2), threads = useCaseThreads
+ ).setupSurfaceAsync(
+ fakeGraph, deferrableSurfaceToStreamId
+ ).await()
+
+ // Assert, 2 surfaces from the fakeTestUseCase1 and fakeTestUseCase2 should be set to the
+ // Graph
+ assertThat(fakeGraph.setSurfaceResults).isEqualTo(
+ deferrableSurfaceToStreamId.map {
+ it.value to (it.key as TestDeferrableSurface).testSurface
+ }.toMap()
+ )
+
+ // Clean up
+ testDeferrableSurface1.close()
+ testDeferrableSurface2.close()
+ }
+
+ @Test
+ fun invalidSessionConfig() {
+ // Arrange
+ val testDeferrableSurface = createTestDeferrableSurface()
+
+ // Create an invalid SessionConfig which doesn't set the template
+ val fakeTestUseCase = createFakeTestUseCase {
+ it.setupSessionConfig(
+ SessionConfig.Builder().also { sessionConfigBuilder ->
+ sessionConfigBuilder.addSurface(testDeferrableSurface)
+ }
+ )
+ }
+
+ // Act
+ val sessionConfigAdapter = SessionConfigAdapter(
+ useCases = listOf(fakeTestUseCase), threads = useCaseThreads
+ )
+
+ // Assert
+ assertThat(sessionConfigAdapter.isSessionConfigValid()).isFalse()
+ assertThat(sessionConfigAdapter.getValidSessionConfigOrNull()).isNull()
+
+ // Clean up
+ testDeferrableSurface.close()
+ }
+
+ private fun createFakeTestUseCase(block: (FakeTestUseCase) -> Unit): FakeTestUseCase = run {
+ val configBuilder = FakeUseCaseConfig.Builder().setTargetName("UseCase")
+ FakeTestUseCase(configBuilder.useCaseConfig).also {
+ block(it)
+ }
+ }
+
+ private fun createTestDeferrableSurface(): TestDeferrableSurface = run {
+ TestDeferrableSurface().also {
+ it.terminationFuture.addListener({ it.cleanUp() }, useCaseThreads.backgroundExecutor)
+ }
+ }
+}
+
+private class FakeTestUseCase(
+ config: FakeUseCaseConfig,
+) : FakeUseCase(config) {
+
+ fun setupSessionConfig(sessionConfigBuilder: SessionConfig.Builder) {
+ updateSessionConfig(sessionConfigBuilder.build())
+ notifyActive()
+ }
+}
+
+private class TestDeferrableSurface : DeferrableSurface() {
+ private val surfaceTexture = SurfaceTexture(0).also {
+ it.setDefaultBufferSize(0, 0)
+ }
+ val testSurface = Surface(surfaceTexture)
+
+ override fun provideSurface(): ListenableFuture<Surface> {
+ return Futures.immediateFuture(testSurface)
+ }
+
+ fun cleanUp() {
+ testSurface.release()
+ surfaceTexture.release()
+ }
+}
+
+private class FakeCameraGraph : CameraGraph {
+ val setSurfaceResults = mutableMapOf<StreamId, Surface?>()
+
+ override val streams: StreamGraph
+ get() = throw NotImplementedError("Not used in testing")
+
+ override suspend fun acquireSession(): CameraGraph.Session {
+ throw NotImplementedError("Not used in testing")
+ }
+
+ override fun acquireSessionOrNull(): CameraGraph.Session? {
+ throw NotImplementedError("Not used in testing")
+ }
+
+ override fun close() {
+ throw NotImplementedError("Not used in testing")
+ }
+
+ override fun setSurface(stream: StreamId, surface: Surface?) {
+ setSurfaceResults[stream] = surface
+ }
+
+ override fun start() {
+ throw NotImplementedError("Not used in testing")
+ }
+
+ override fun stop() {
+ throw NotImplementedError("Not used in testing")
+ }
+}
diff --git a/car/app/app-projected/src/main/aidl/androidx/car/app/hardware/ICarHardwareHost.aidl b/car/app/app-projected/src/main/aidl/androidx/car/app/hardware/ICarHardwareHost.aidl
index 35fc908..c366c06 100644
--- a/car/app/app-projected/src/main/aidl/androidx/car/app/hardware/ICarHardwareHost.aidl
+++ b/car/app/app-projected/src/main/aidl/androidx/car/app/hardware/ICarHardwareHost.aidl
@@ -37,6 +37,6 @@
* Indicates to the host that the app wants to unsubscribe from a vehicle result that changes
* over time.
*/
- void unsubscribeCarHardwareResult(in int resultType) = 3;
+ void unsubscribeCarHardwareResult(in int resultType, in @nullable Bundleable params) = 3;
}
diff --git a/car/app/app-projected/src/test/java/androidx/car/app/hardware/common/CarHardwareHostDispatcherTest.java b/car/app/app-projected/src/test/java/androidx/car/app/hardware/common/CarHardwareHostDispatcherTest.java
index 6c9644d..d963035 100644
--- a/car/app/app-projected/src/test/java/androidx/car/app/hardware/common/CarHardwareHostDispatcherTest.java
+++ b/car/app/app-projected/src/test/java/androidx/car/app/hardware/common/CarHardwareHostDispatcherTest.java
@@ -123,7 +123,7 @@
}
@Override
- public void getCarHardwareResult(int resultType, Bundleable params,
+ public void getCarHardwareResult(int resultType, @Nullable Bundleable params,
ICarHardwareResult callback) throws RemoteException {
mCallback = callback;
// Record the call in the mock
@@ -135,12 +135,13 @@
}
@Override
- public void subscribeCarHardwareResult(int resultType, Bundleable params,
+ public void subscribeCarHardwareResult(int resultType, @Nullable Bundleable params,
ICarHardwareResult callback) throws RemoteException {
}
@Override
- public void unsubscribeCarHardwareResult(int resultType) throws RemoteException {
+ public void unsubscribeCarHardwareResult(int resultType, @Nullable Bundleable params)
+ throws RemoteException {
}
}
}
diff --git a/car/app/app-projected/src/test/java/androidx/car/app/hardware/common/CarResultStubTest.java b/car/app/app-projected/src/test/java/androidx/car/app/hardware/common/CarResultStubTest.java
index fb4f66f..7e7347c 100644
--- a/car/app/app-projected/src/test/java/androidx/car/app/hardware/common/CarResultStubTest.java
+++ b/car/app/app-projected/src/test/java/androidx/car/app/hardware/common/CarResultStubTest.java
@@ -145,7 +145,7 @@
}
@Override
- public void getCarHardwareResult(int resultType, Bundleable params,
+ public void getCarHardwareResult(int resultType, @Nullable Bundleable params,
ICarHardwareResult callback) throws RemoteException {
mCallback = callback;
// Record the call in the mock
@@ -157,7 +157,7 @@
}
@Override
- public void subscribeCarHardwareResult(int resultType, Bundleable params,
+ public void subscribeCarHardwareResult(int resultType, @Nullable Bundleable params,
ICarHardwareResult callback) throws RemoteException {
mCallback = callback;
mMockCarHardwareHost.subscribeCarHardwareResult(resultType, params, callback);
@@ -167,8 +167,9 @@
}
@Override
- public void unsubscribeCarHardwareResult(int resultType) throws RemoteException {
- mMockCarHardwareHost.unsubscribeCarHardwareResult(resultType);
+ public void unsubscribeCarHardwareResult(int resultType, @Nullable Bundleable params)
+ throws RemoteException {
+ mMockCarHardwareHost.unsubscribeCarHardwareResult(resultType, params);
}
}
}
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/SurfaceRenderer.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/SurfaceRenderer.java
index 878d2ca..d0285b9 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/SurfaceRenderer.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/SurfaceRenderer.java
@@ -34,13 +34,19 @@
import androidx.car.app.hardware.CarHardwareManager;
import androidx.car.app.hardware.common.CarValue;
import androidx.car.app.hardware.common.OnCarDataListener;
+import androidx.car.app.hardware.info.Accelerometer;
+import androidx.car.app.hardware.info.CarHardwareLocation;
import androidx.car.app.hardware.info.CarInfo;
+import androidx.car.app.hardware.info.CarSensors;
+import androidx.car.app.hardware.info.Compass;
+import androidx.car.app.hardware.info.Gyroscope;
import androidx.car.app.hardware.info.Model;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
+import java.util.List;
import java.util.concurrent.Executor;
/** A very simple implementation of a renderer for the app's background surface. */
@@ -65,8 +71,11 @@
private final Paint mCarInfoPaint = new Paint();
private boolean mShowCarHardwareSurfaceInfo;
- @Nullable
- Model mModel;
+ @Nullable Model mModel;
+ @Nullable Accelerometer mAccelerometer;
+ @Nullable Gyroscope mGyroscope;
+ @Nullable Compass mCompass;
+ @Nullable CarHardwareLocation mCarHardwareLocation;
private OnCarDataListener<Model> mModelListener = new OnCarDataListener<Model>() {
@Override
@@ -79,6 +88,38 @@
}
};
+ private OnCarDataListener<Accelerometer> mAccelerometerListener = data -> {
+ synchronized (SurfaceRenderer.this) {
+ Log.i(TAG, String.format("Received accelerometer %s", data));
+ mAccelerometer = data;
+ renderFrame();
+ }
+ };
+
+ private OnCarDataListener<Gyroscope> mGyroscopeListener = data -> {
+ synchronized (SurfaceRenderer.this) {
+ Log.i(TAG, String.format("Received gyroscope %s", data));
+ mGyroscope = data;
+ renderFrame();
+ }
+ };
+
+ private OnCarDataListener<Compass> mCompassListener = data -> {
+ synchronized (SurfaceRenderer.this) {
+ Log.i(TAG, String.format("Received compass %s", data));
+ mCompass = data;
+ renderFrame();
+ }
+ };
+
+ private OnCarDataListener<CarHardwareLocation> mCarLocationListener = data -> {
+ synchronized (SurfaceRenderer.this) {
+ Log.i(TAG, String.format("Received car location %s", data));
+ mCarHardwareLocation = data;
+ renderFrame();
+ }
+ };
+
private final SurfaceCallback mSurfaceCallback =
new SurfaceCallback() {
@Override
@@ -142,7 +183,6 @@
mCarInfoPaint.setAntiAlias(true);
mCarInfoPaint.setStyle(Style.STROKE);
mCarInfoPaint.setTextAlign(Align.CENTER);
-
mCarHardwareExecutor = ContextCompat.getMainExecutor(mCarContext);
lifecycle.addObserver(this);
@@ -158,14 +198,39 @@
if (isEnabled == mShowCarHardwareSurfaceInfo) {
return;
}
+ CarHardwareManager carHardwareManager =
+ mCarContext.getCarService(CarHardwareManager.class);
if (isEnabled) {
- CarHardwareManager carHardwareManager =
- mCarContext.getCarService(CarHardwareManager.class);
-
// Request any single shot values.
CarInfo carInfo = carHardwareManager.getCarInfo();
mModel = null;
carInfo.getModel(mCarHardwareExecutor, mModelListener);
+
+ // Request sensors
+ CarSensors carSensors = carHardwareManager.getCarSensors();
+ mCompass = null;
+ carSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL, mCarHardwareExecutor,
+ mCompassListener);
+ mGyroscope = null;
+ carSensors.addGyroscopeListener(CarSensors.UPDATE_RATE_NORMAL, mCarHardwareExecutor,
+ mGyroscopeListener);
+ mAccelerometer = null;
+ carSensors.addAccelerometerListener(CarSensors.UPDATE_RATE_NORMAL, mCarHardwareExecutor,
+ mAccelerometerListener);
+ mCarHardwareLocation = null;
+ carSensors.addCarHardwareLocationListener(CarSensors.UPDATE_RATE_NORMAL,
+ mCarHardwareExecutor, mCarLocationListener);
+ } else {
+ // Unsubscribe sensors
+ CarSensors carSensors = carHardwareManager.getCarSensors();
+ mCompass = null;
+ carSensors.removeCompassListener(mCompassListener);
+ mGyroscope = null;
+ carSensors.removeGyroscopeListener(mGyroscopeListener);
+ mAccelerometer = null;
+ carSensors.removeAccelerometerListener(mAccelerometerListener);
+ mCarHardwareLocation = null;
+ carSensors.removeCarHardwareLocationListener(mCarLocationListener);
}
mShowCarHardwareSurfaceInfo = isEnabled;
renderFrame();
@@ -204,6 +269,10 @@
visibleArea.set(0, 0, canvas.getWidth() - 1, canvas.getHeight() - 1);
}
+ Paint.FontMetrics fm = mCarInfoPaint.getFontMetrics();
+ float height = fm.descent - fm.ascent;
+ float verticalPos = visibleArea.top + VERTICAL_TEXT_MARGIN_FROM_TOP;
+
StringBuilder info = new StringBuilder();
if (mModel == null) {
info.append("Fetching model info.");
@@ -226,11 +295,71 @@
info.append(mModel.getYear());
}
}
- canvas.drawText(info.toString(), visibleArea.centerX(),
- visibleArea.top + VERTICAL_TEXT_MARGIN_FROM_TOP, mCarInfoPaint);
+ canvas.drawText(info.toString(), visibleArea.centerX(), verticalPos, mCarInfoPaint);
+ verticalPos += height;
+ info = new StringBuilder();
+ if (mAccelerometer == null) {
+ info.append("Fetching accelerometer");
+ } else {
+ if (mAccelerometer.getForces().getStatus() != CarValue.STATUS_SUCCESS) {
+ info.append("Accelerometer unavailable.");
+ } else {
+ info.append("Accelerometer: ");
+ appendFloatList(info, mAccelerometer.getForces().getValue());
+ }
+ }
+ canvas.drawText(info.toString(), visibleArea.centerX(), verticalPos, mCarInfoPaint);
+ verticalPos += height;
+ info = new StringBuilder();
+ if (mGyroscope == null) {
+ info.append("Fetching gyroscope");
+ } else {
+ if (mGyroscope.getRotations().getStatus() != CarValue.STATUS_SUCCESS) {
+ info.append("Gyroscope unavailable.");
+ } else {
+ info.append("Gyroscope: ");
+ appendFloatList(info, mGyroscope.getRotations().getValue());
+ }
+ }
+ canvas.drawText(info.toString(), visibleArea.centerX(), verticalPos, mCarInfoPaint);
+ verticalPos += height;
+ info = new StringBuilder();
+ if (mCompass == null) {
+ info.append("Fetching compass");
+ } else {
+ if (mCompass.getOrientations().getStatus() != CarValue.STATUS_SUCCESS) {
+ info.append("Compass unavailable.");
+ } else {
+ info.append("Compass: ");
+ appendFloatList(info, mCompass.getOrientations().getValue());
+ }
+ }
+ canvas.drawText(info.toString(), visibleArea.centerX(), verticalPos, mCarInfoPaint);
+ verticalPos += height;
+ info = new StringBuilder();
+ if (mCarHardwareLocation == null) {
+ info.append("Fetching location");
+ } else {
+ if (mCarHardwareLocation.getLocation().getStatus() != CarValue.STATUS_SUCCESS) {
+ info.append("Car Hardware Location unavailable");
+ } else {
+ info.append("Car Hardware location: ");
+ info.append(mCarHardwareLocation.getLocation().getValue().toString());
+ }
+ }
+ canvas.drawText(info.toString(), visibleArea.centerX(), verticalPos, mCarInfoPaint);
}
}
+ private void appendFloatList(StringBuilder builder, List<Float> values) {
+ builder.append("[ ");
+ for (Float value : values) {
+ builder.append(value);
+ builder.append(" ");
+ }
+ builder.append("]");
+ }
+
private void renderStandardFrame(Canvas canvas) {
// Draw a rectangle showing the inset.
diff --git a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationEndReason.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationEndReason.kt
index 91b6a8b..0a9dad9 100644
--- a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationEndReason.kt
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationEndReason.kt
@@ -22,7 +22,7 @@
enum class AnimationEndReason {
/**
* Animation will be forced to end when its value reaches upper/lower bound (if they have
- * been defined, e.g via [Animatable.updateBounds])
+ * been defined, e.g. via [Animatable.updateBounds])
*
* Unlike [Finished], when an animation ends due to [BoundReached], it often falls short
* from its initial target, and the remaining velocity is often non-zero. Both the end value
diff --git a/compose/animation/animation/api/public_plus_experimental_1.0.0-beta10.txt b/compose/animation/animation/api/public_plus_experimental_1.0.0-beta10.txt
index 3ca024e..20da353 100644
--- a/compose/animation/animation/api/public_plus_experimental_1.0.0-beta10.txt
+++ b/compose/animation/animation/api/public_plus_experimental_1.0.0-beta10.txt
@@ -50,7 +50,7 @@
method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(boolean visible, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.foundation.layout.RowScope, boolean visible, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.foundation.layout.ColumnScope, boolean visible, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
- method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.animation.core.MutableTransitionState<java.lang.Boolean> visibleState, optional androidx.compose.ui.Modifier modifier, androidx.compose.animation.EnterTransition enter, androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
+ method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.animation.core.MutableTransitionState<java.lang.Boolean> visibleState, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.foundation.layout.RowScope, androidx.compose.animation.core.MutableTransitionState<java.lang.Boolean> visibleState, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.foundation.layout.ColumnScope, androidx.compose.animation.core.MutableTransitionState<java.lang.Boolean> visibleState, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static <T> void AnimatedVisibility(androidx.compose.animation.core.Transition<T>, kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> visible, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
diff --git a/compose/animation/animation/api/public_plus_experimental_current.txt b/compose/animation/animation/api/public_plus_experimental_current.txt
index 3ca024e..20da353 100644
--- a/compose/animation/animation/api/public_plus_experimental_current.txt
+++ b/compose/animation/animation/api/public_plus_experimental_current.txt
@@ -50,7 +50,7 @@
method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(boolean visible, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.foundation.layout.RowScope, boolean visible, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.foundation.layout.ColumnScope, boolean visible, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
- method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.animation.core.MutableTransitionState<java.lang.Boolean> visibleState, optional androidx.compose.ui.Modifier modifier, androidx.compose.animation.EnterTransition enter, androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
+ method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.animation.core.MutableTransitionState<java.lang.Boolean> visibleState, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.foundation.layout.RowScope, androidx.compose.animation.core.MutableTransitionState<java.lang.Boolean> visibleState, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.foundation.layout.ColumnScope, androidx.compose.animation.core.MutableTransitionState<java.lang.Boolean> visibleState, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static <T> void AnimatedVisibility(androidx.compose.animation.core.Transition<T>, kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> visible, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt
index c1b5784..f5beb63 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt
@@ -345,10 +345,10 @@
*
* @param visibleState defines whether the content should be visible
* @param modifier modifier for the [Layout] created to contain the [content]
- * @param enter EnterTransition(s) used for the appearing animation, fading in while expanding
- * vertically by default
+ * @param enter EnterTransition(s) used for the appearing animation, fading in while expanding by
+ * default
* @param exit ExitTransition(s) used for the disappearing animation, fading out while
- * shrinking vertically by default
+ * shrinking by default
* @param content Content to appear or disappear based on the value of [visibleState]
*
* @see EnterTransition
@@ -366,8 +366,8 @@
fun AnimatedVisibility(
visibleState: MutableTransitionState<Boolean>,
modifier: Modifier = Modifier,
- enter: EnterTransition,
- exit: ExitTransition,
+ enter: EnterTransition = fadeIn() + expandIn(),
+ exit: ExitTransition = fadeOut() + shrinkOut(),
content: @Composable() AnimatedVisibilityScope.() -> Unit
) {
val transition = updateTransition(visibleState)
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/gesture/ForEachGestureTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/gesture/ForEachGestureTest.kt
new file mode 100644
index 0000000..544f512
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/gesture/ForEachGestureTest.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.gesture
+
+import androidx.compose.foundation.gestures.forEachGesture
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.size
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import org.junit.Assert.assertTrue
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.util.concurrent.CancellationException
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class ForEachGestureTest {
+ @get:Rule
+ val rule = createComposeRule()
+
+ /**
+ * Make sure that an empty `forEachGesture` block does not cause a crash.
+ */
+ @Test
+ fun testEmptyForEachGesture() {
+ val latch1 = CountDownLatch(2)
+ val latch2 = CountDownLatch(1)
+ rule.setContent {
+ Box(
+ Modifier.pointerInput(Unit) {
+ forEachGesture {
+ if (latch1.count == 0L) {
+ // forEachGesture will loop infinitely with nothing in the middle
+ // so cancel this before it becomes a problem
+ throw CancellationException()
+ }
+ latch1.countDown()
+ }
+ }.pointerInput(Unit) {
+ awaitPointerEventScope {
+ assertTrue(currentEvent.changes.isEmpty())
+ latch2.countDown()
+ }
+ }.size(10.dp)
+ )
+ }
+ assertTrue(latch1.await(1, TimeUnit.SECONDS))
+ assertTrue(latch2.await(1, TimeUnit.SECONDS))
+ }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Draggable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Draggable.kt
index 4e484f4..7bcb55a 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Draggable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Draggable.kt
@@ -82,7 +82,7 @@
* [draggable].
*
* This method is used internally for low level operations, allowing implementers of
- * [DraggableState] influence the consumption as suits them, e.g introduce nested scrolling.
+ * [DraggableState] influence the consumption as suits them, e.g. introduce nested scrolling.
* Manually dispatching delta via this method will likely result in a bad user experience,
* you must prefer [drag] method over this one.
*
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/TransformGestureDetector.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/TransformGestureDetector.kt
index 3755604..725334c 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/TransformGestureDetector.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/TransformGestureDetector.kt
@@ -32,7 +32,7 @@
import kotlin.math.atan2
/**
- * A gesture detector for rotationg, panning, and zoom. Once touch slop has been reached, the
+ * A gesture detector for rotation, panning, and zoom. Once touch slop has been reached, the
* user can use rotation, panning and zoom gestures. [onGesture] will be called when any of the
* rotation, zoom or pan occurs, passing the rotation angle in degrees, zoom in scale factor and
* pan as an offset in pixels. Each of these changes is a difference between the previous call
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazySemantics.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazySemantics.kt
index a460b39..8f697eb 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazySemantics.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazySemantics.kt
@@ -16,13 +16,19 @@
package androidx.compose.foundation.lazy
+import androidx.compose.foundation.gestures.ScrollableState
+import androidx.compose.foundation.gestures.scrollBy
import androidx.compose.runtime.State
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.CollectionInfo
+import androidx.compose.ui.semantics.ScrollAxisRange
import androidx.compose.ui.semantics.collectionInfo
+import androidx.compose.ui.semantics.horizontalScrollAxisRange
import androidx.compose.ui.semantics.indexForKey
+import androidx.compose.ui.semantics.scrollBy
import androidx.compose.ui.semantics.scrollToIndex
import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.semantics.verticalScrollAxisRange
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@@ -43,6 +49,31 @@
-1
}
+ val accessibilityScrollState = ScrollAxisRange(
+ value = {
+ // This is a simple way of representing the current position without
+ // needing any lazy items to be measured. It's good enough so far, because
+ // screen-readers care mostly about whether scroll position changed or not
+ // rather than the actual offset in pixels.
+ state.firstVisibleItemIndex + state.firstVisibleItemScrollOffset / 100_000f
+ },
+ maxValue = { Float.POSITIVE_INFINITY }
+ )
+ if (isVertical) {
+ verticalScrollAxisRange = accessibilityScrollState
+ } else {
+ horizontalScrollAxisRange = accessibilityScrollState
+ }
+
+ scrollBy { x, y ->
+ val delta = if (isVertical) { y } else { x }
+ coroutineScope.launch {
+ (state as ScrollableState).scrollBy(delta)
+ }
+ // TODO(aelias): is it important to return false if we know in advance we cannot scroll?
+ true
+ }
+
scrollToIndex { index ->
require(index >= 0 && index < stateOfItemsProvider.value.itemsCount) {
"Can't scroll to index $index, it is out of bounds [0, ${stateOfItemsProvider
diff --git a/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/animation/Animation.kt b/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/animation/Animation.kt
index f674d16..ccf28a0 100644
--- a/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/animation/Animation.kt
+++ b/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/animation/Animation.kt
@@ -15,7 +15,10 @@
*/
// Ignore lint warnings in documentation snippets
-@file:Suppress("CanBeVal", "UNUSED_VARIABLE", "RemoveExplicitTypeArguments", "unused")
+@file:Suppress(
+ "CanBeVal", "UNUSED_VARIABLE", "RemoveExplicitTypeArguments", "unused",
+ "MemberVisibilityCanBePrivate"
+)
@file:SuppressLint("ModifierInspectorInfo", "NewApi")
package androidx.compose.integration.docs.animation
@@ -95,6 +98,7 @@
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.input.pointer.positionChange
import androidx.compose.ui.input.pointer.util.VelocityTracker
+import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.test.captureToImage
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onRoot
@@ -128,11 +132,12 @@
@Composable
fun AnimatedVisibilityWithEnterAndExit() {
var visible by remember { mutableStateOf(true) }
+ val density = LocalDensity.current
AnimatedVisibility(
visible = visible,
enter = slideInVertically(
- // Slide in from 40 px from the top.
- initialOffsetY = { -40 }
+ // Slide in from 40 dp from the top.
+ initialOffsetY = { with(density) { -40.dp.roundToPx() } }
) + expandVertically(
// Expand from the top.
expandFrom = Alignment.Top
@@ -477,13 +482,15 @@
): Modifier = composed {
val offsetX = remember { Animatable(0f) }
pointerInput(Unit) {
+ // Used to calculate fling decay.
val decay = splineBasedDecay<Float>(this)
+ // Use suspend functions for touch events and the Animatable.
coroutineScope {
while (true) {
// Detect a touch down event.
val pointerId = awaitPointerEventScope { awaitFirstDown().id }
val velocityTracker = VelocityTracker()
- // Intercept an ongoing animation (if there's one).
+ // Stop any ongoing animation.
offsetX.stop()
awaitPointerEventScope {
horizontalDrag(pointerId) { change ->
@@ -499,6 +506,7 @@
)
}
}
+ // No longer receiving touch events. Prepare the animation.
val velocity = velocityTracker.calculateVelocity().x
val targetOffsetX = decay.calculateTargetValue(
offsetX.value,
diff --git a/compose/material/material/api/public_plus_experimental_1.0.0-beta10.txt b/compose/material/material/api/public_plus_experimental_1.0.0-beta10.txt
index a7a2c2d..aa65079 100644
--- a/compose/material/material/api/public_plus_experimental_1.0.0-beta10.txt
+++ b/compose/material/material/api/public_plus_experimental_1.0.0-beta10.txt
@@ -560,6 +560,7 @@
}
public final class SliderKt {
+ method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static void RangeSlider(kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> values, kotlin.jvm.functions.Function1<? super kotlin.ranges.ClosedFloatingPointRange<java.lang.Float>,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional int steps, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.material.SliderColors colors);
method @androidx.compose.runtime.Composable public static void Slider(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional int steps, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.SliderColors colors);
}
diff --git a/compose/material/material/api/public_plus_experimental_current.txt b/compose/material/material/api/public_plus_experimental_current.txt
index a7a2c2d..aa65079 100644
--- a/compose/material/material/api/public_plus_experimental_current.txt
+++ b/compose/material/material/api/public_plus_experimental_current.txt
@@ -560,6 +560,7 @@
}
public final class SliderKt {
+ method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static void RangeSlider(kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> values, kotlin.jvm.functions.Function1<? super kotlin.ranges.ClosedFloatingPointRange<java.lang.Float>,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional int steps, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.material.SliderColors colors);
method @androidx.compose.runtime.Composable public static void Slider(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional int steps, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.SliderColors colors);
}
diff --git a/compose/material/material/integration-tests/material-catalog/src/main/java/androidx/compose/material/catalog/model/Examples.kt b/compose/material/material/integration-tests/material-catalog/src/main/java/androidx/compose/material/catalog/model/Examples.kt
index 6f76c9c..6f787a5 100644
--- a/compose/material/material/integration-tests/material-catalog/src/main/java/androidx/compose/material/catalog/model/Examples.kt
+++ b/compose/material/material/integration-tests/material-catalog/src/main/java/androidx/compose/material/catalog/model/Examples.kt
@@ -49,6 +49,7 @@
import androidx.compose.material.samples.PasswordTextField
import androidx.compose.material.samples.RadioButtonSample
import androidx.compose.material.samples.RadioGroupSample
+import androidx.compose.material.samples.RangeSliderSample
import androidx.compose.material.samples.ScaffoldWithCoroutinesSnackbar
import androidx.compose.material.samples.ScaffoldWithCustomSnackbar
import androidx.compose.material.samples.ScaffoldWithSimpleSnackbar
@@ -62,6 +63,7 @@
import androidx.compose.material.samples.SimpleTextFieldSample
import androidx.compose.material.samples.SimpleTopAppBar
import androidx.compose.material.samples.SliderSample
+import androidx.compose.material.samples.StepRangeSliderSample
import androidx.compose.material.samples.StepsSliderSample
import androidx.compose.material.samples.SwitchSample
import androidx.compose.material.samples.TextAndIconTabs
@@ -424,7 +426,21 @@
sourceUrl = SlidersExampleSourceUrl
) {
StepsSliderSample()
- }
+ },
+ Example(
+ name = ::RangeSliderSample.name,
+ description = SlidersExampleDescription,
+ sourceUrl = SlidersExampleSourceUrl
+ ) {
+ RangeSliderSample()
+ },
+ Example(
+ name = ::StepRangeSliderSample.name,
+ description = SlidersExampleDescription,
+ sourceUrl = SlidersExampleSourceUrl
+ ) {
+ StepRangeSliderSample()
+ },
)
private const val SnackbarsExampleDescription = "Snackbars examples"
diff --git a/compose/material/material/integration-tests/material-demos/src/main/java/androidx/compose/material/demos/SliderDemo.kt b/compose/material/material/integration-tests/material-demos/src/main/java/androidx/compose/material/demos/SliderDemo.kt
index 8e974cf9..774f44c 100644
--- a/compose/material/material/integration-tests/material-demos/src/main/java/androidx/compose/material/demos/SliderDemo.kt
+++ b/compose/material/material/integration-tests/material-demos/src/main/java/androidx/compose/material/demos/SliderDemo.kt
@@ -18,11 +18,13 @@
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
+import androidx.compose.material.samples.RangeSliderSample
import androidx.compose.material.samples.SliderSample
+import androidx.compose.material.samples.StepRangeSliderSample
import androidx.compose.material.samples.StepsSliderSample
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
@@ -39,5 +41,11 @@
Text(text = "Discrete Slider with custom color", style = headerStyle)
Spacer(Modifier.requiredHeight(16.dp))
StepsSliderSample()
+ Text(text = "Range Continuous Slider", style = headerStyle)
+ Spacer(Modifier.requiredHeight(16.dp))
+ RangeSliderSample()
+ Text(text = "Range Discrete Slider", style = headerStyle)
+ Spacer(Modifier.requiredHeight(16.dp))
+ StepRangeSliderSample()
}
}
diff --git a/compose/material/material/samples/src/main/java/androidx/compose/material/samples/SliderSample.kt b/compose/material/material/samples/src/main/java/androidx/compose/material/samples/SliderSample.kt
index 98211d5..e68c665 100644
--- a/compose/material/material/samples/src/main/java/androidx/compose/material/samples/SliderSample.kt
+++ b/compose/material/material/samples/src/main/java/androidx/compose/material/samples/SliderSample.kt
@@ -17,7 +17,9 @@
package androidx.compose.material.samples
import androidx.annotation.Sampled
+import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.MaterialTheme
+import androidx.compose.material.RangeSlider
import androidx.compose.material.Slider
import androidx.compose.material.SliderDefaults
import androidx.compose.material.Text
@@ -54,4 +56,43 @@
activeTrackColor = MaterialTheme.colors.secondary
)
)
+}
+
+@Sampled
+@Composable
+@OptIn(ExperimentalMaterialApi::class)
+fun RangeSliderSample() {
+ var sliderPosition by remember { mutableStateOf(0f..100f) }
+ Text(text = sliderPosition.toString())
+ RangeSlider(
+ values = sliderPosition,
+ onValueChange = { sliderPosition = it },
+ valueRange = 0f..100f,
+ onValueChangeFinished = {
+ // launch some business logic update with the state you hold
+ // viewModel.updateSelectedSliderValue(sliderPosition)
+ },
+ )
+}
+
+@Sampled
+@Composable
+@OptIn(ExperimentalMaterialApi::class)
+fun StepRangeSliderSample() {
+ var sliderPosition by remember { mutableStateOf(0f..100f) }
+ Text(text = sliderPosition.toString())
+ RangeSlider(
+ steps = 5,
+ values = sliderPosition,
+ onValueChange = { sliderPosition = it },
+ valueRange = 0f..100f,
+ onValueChangeFinished = {
+ // launch some business logic update with the state you hold
+ // viewModel.updateSelectedSliderValue(sliderPosition)
+ },
+ colors = SliderDefaults.colors(
+ thumbColor = MaterialTheme.colors.secondary,
+ activeTrackColor = MaterialTheme.colors.secondary
+ )
+ )
}
\ No newline at end of file
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/MaterialTextSelectionColorsScreenshotTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/MaterialTextSelectionColorsScreenshotTest.kt
index e73e6c7..85a1e8f 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/MaterialTextSelectionColorsScreenshotTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/MaterialTextSelectionColorsScreenshotTest.kt
@@ -36,6 +36,7 @@
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp
import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.FlakyTest
import androidx.test.filters.LargeTest
import androidx.test.filters.SdkSuppress
import androidx.test.screenshot.AndroidXScreenshotTestRule
@@ -85,6 +86,7 @@
.isEqualTo(darkPrimary.copy(alpha = 0.375f))
}
+ @FlakyTest(bugId = 191141357)
@Test
fun text_lightThemeSelectionColors() {
rule.setContent {
@@ -103,6 +105,7 @@
.assertAgainstGolden(screenshotRule, "text_lightThemeSelectionColors")
}
+ @FlakyTest(bugId = 191141357)
@Test
fun text_darkThemeSelectionColors() {
rule.setContent {
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SliderScreenshotTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SliderScreenshotTest.kt
index 80e0fbf..dfbdacc 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SliderScreenshotTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SliderScreenshotTest.kt
@@ -175,4 +175,52 @@
.captureToImage()
.assertAgainstGolden(screenshotRule, goldenName)
}
+
+ @Test
+ @ExperimentalMaterialApi
+ fun rangeSliderTest_middle_steps_disabled() {
+ rule.setMaterialContent {
+ Box(wrap.testTag(wrapperTestTag)) {
+ var position by remember { mutableStateOf(0.5f..1f) }
+ RangeSlider(position, { position = it }, steps = 5, enabled = false)
+ }
+ }
+ assertSliderAgainstGolden("rangeSlider_middle_steps_disabled")
+ }
+
+ @Test
+ @ExperimentalMaterialApi
+ fun rangeSliderTest_middle_steps_enabled() {
+ rule.setMaterialContent {
+ Box(wrap.testTag(wrapperTestTag)) {
+ var position by remember { mutableStateOf(0.5f..1f) }
+ RangeSlider(position, { position = it }, steps = 5)
+ }
+ }
+ assertSliderAgainstGolden("rangeSlider_middle_steps_enabled")
+ }
+
+ @Test
+ @ExperimentalMaterialApi
+ fun rangeSliderTest_overlapingThumbs() {
+ rule.setMaterialContent {
+ Box(wrap.testTag(wrapperTestTag)) {
+ var position by remember { mutableStateOf(0.5f..0.51f) }
+ RangeSlider(position, { position = it })
+ }
+ }
+ assertSliderAgainstGolden("rangeSlider_overlapingThumbs")
+ }
+
+ @Test
+ @ExperimentalMaterialApi
+ fun rangeSliderTest_fullRange() {
+ rule.setMaterialContent {
+ Box(wrap.testTag(wrapperTestTag)) {
+ var position by remember { mutableStateOf(0f..1f) }
+ RangeSlider(position, { position = it })
+ }
+ }
+ assertSliderAgainstGolden("rangeSlider_fullRange")
+ }
}
\ No newline at end of file
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SliderTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SliderTest.kt
index 998ebaf..339d051 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SliderTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SliderTest.kt
@@ -62,7 +62,6 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import kotlin.math.abs
@MediumTest
@RunWith(AndroidJUnit4::class)
@@ -207,7 +206,7 @@
expected = calculateFraction(left, right, centerX + 100 - slop)
}
rule.runOnIdle {
- Truth.assertThat(abs(state.value - expected)).isLessThan(0.001f)
+ Truth.assertThat(state.value).isWithin(0.001f).of(expected)
}
}
@@ -236,7 +235,7 @@
expected = calculateFraction(left, right, centerX + 50)
}
rule.runOnIdle {
- Truth.assertThat(abs(state.value - expected)).isLessThan(0.001f)
+ Truth.assertThat(state.value).isWithin(0.001f).of(expected)
}
}
@@ -268,7 +267,7 @@
}
rule.runOnIdle {
- Truth.assertThat(abs(state.value - expected)).isLessThan(0.001f)
+ Truth.assertThat(state.value).isWithin(0.001f).of(expected)
}
}
@@ -303,7 +302,7 @@
expected = calculateFraction(left, right, centerX - 100 + slop)
}
rule.runOnIdle {
- Truth.assertThat(abs(state.value - expected)).isLessThan(0.001f)
+ Truth.assertThat(state.value).isWithin(0.001f).of(expected)
}
}
@@ -334,7 +333,38 @@
expected = calculateFraction(left, right, centerX - 50)
}
rule.runOnIdle {
- Truth.assertThat(abs(state.value - expected)).isLessThan(0.001f)
+ Truth.assertThat(state.value).isWithin(0.001f).of(expected)
+ }
+ }
+
+ @Test
+ fun rangeSlider_tap_rtl() {
+ val state = mutableStateOf(0f)
+
+ rule.setMaterialContent {
+ CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) {
+ Slider(
+ modifier = Modifier.testTag(tag),
+ value = state.value,
+ onValueChange = { state.value = it }
+ )
+ }
+ }
+
+ rule.runOnUiThread {
+ Truth.assertThat(state.value).isEqualTo(0f)
+ }
+
+ var expected = 0f
+
+ rule.onNodeWithTag(tag)
+ .performGesture {
+ down(Offset(centerX + 50, centerY))
+ up()
+ expected = calculateFraction(left, right, centerX - 50)
+ }
+ rule.runOnIdle {
+ Truth.assertThat(state.value).isWithin(0.001f).of(expected)
}
}
@@ -473,4 +503,211 @@
.isEqualTo(interactions[0])
}
}
+
+ @ExperimentalMaterialApi
+ @Test
+ fun rangeSlider_dragThumb() {
+ val state = mutableStateOf(0f..1f)
+ var slop = 0f
+
+ rule.setMaterialContent {
+ slop = LocalViewConfiguration.current.touchSlop
+ RangeSlider(
+ modifier = Modifier.testTag(tag),
+ values = state.value,
+ onValueChange = { state.value = it }
+ )
+ }
+
+ rule.runOnUiThread {
+ Truth.assertThat(state.value).isEqualTo(0f..1f)
+ }
+
+ var expected = 0f
+
+ rule.onNodeWithTag(tag)
+ .performGesture {
+ down(center)
+ moveBy(Offset(100f, 0f))
+ up()
+ expected = calculateFraction(left, right, centerX + 100 - slop)
+ }
+ rule.runOnIdle {
+ Truth.assertThat(state.value.start).isEqualTo(0f)
+ Truth.assertThat(state.value.endInclusive).isWithin(0.001f).of(expected)
+ }
+ }
+
+ @ExperimentalMaterialApi
+ @Test
+ fun rangeSlider_tap() {
+ val state = mutableStateOf(0f..1f)
+
+ rule.setMaterialContent {
+ RangeSlider(
+ modifier = Modifier.testTag(tag),
+ values = state.value,
+ onValueChange = { state.value = it }
+ )
+ }
+
+ rule.runOnUiThread {
+ Truth.assertThat(state.value).isEqualTo(0f..1f)
+ }
+
+ var expected = 0f
+
+ rule.onNodeWithTag(tag)
+ .performGesture {
+ down(Offset(centerX + 50, centerY))
+ up()
+ expected = calculateFraction(left, right, centerX + 50)
+ }
+ rule.runOnIdle {
+ Truth.assertThat(state.value.endInclusive).isWithin(0.001f).of(expected)
+ Truth.assertThat(state.value.start).isEqualTo(0f)
+ }
+ }
+
+ @ExperimentalMaterialApi
+ @Test
+ fun rangeSlider_tap_rangeChange() {
+ val state = mutableStateOf(0f..25f)
+ val rangeEnd = mutableStateOf(.25f)
+
+ rule.setMaterialContent {
+ RangeSlider(
+ modifier = Modifier.testTag(tag),
+ values = state.value,
+ onValueChange = { state.value = it },
+ valueRange = 0f..rangeEnd.value
+ )
+ }
+ // change to 1 since [calculateFraction] coerces between 0..1
+ rule.runOnUiThread {
+ rangeEnd.value = 1f
+ }
+
+ var expected = 0f
+
+ rule.onNodeWithTag(tag)
+ .performGesture {
+ down(Offset(centerX + 50, centerY))
+ up()
+ expected = calculateFraction(left, right, centerX + 50)
+ }
+
+ rule.runOnIdle {
+ Truth.assertThat(state.value.endInclusive).isWithin(0.001f).of(expected)
+ }
+ }
+
+ @ExperimentalMaterialApi
+ @Test
+ fun rangeSlider_drag_rtl() {
+ val state = mutableStateOf(0f..1f)
+ var slop = 0f
+
+ rule.setMaterialContent {
+ CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) {
+ slop = LocalViewConfiguration.current.touchSlop
+ RangeSlider(
+ modifier = Modifier.testTag(tag),
+ values = state.value,
+ onValueChange = { state.value = it }
+ )
+ }
+ }
+
+ rule.runOnUiThread {
+ Truth.assertThat(state.value).isEqualTo(0f..1f)
+ }
+
+ var expected = 0f
+
+ rule.onNodeWithTag(tag)
+ .performGesture {
+ down(center)
+ moveBy(Offset(100f, 0f))
+ up()
+ // subtract here as we're in rtl and going in the opposite direction
+ expected = calculateFraction(left, right, centerX - 100 + slop)
+ }
+ rule.runOnIdle {
+ Truth.assertThat(state.value.start).isEqualTo(0f)
+ Truth.assertThat(state.value.endInclusive).isWithin(0.001f).of(expected)
+ }
+ }
+
+ @ExperimentalMaterialApi
+ @Test
+ fun rangeSlider_closeThumbs_dragRight() {
+ val state = mutableStateOf(0.5f..0.5f)
+ var slop = 0f
+
+ rule.setMaterialContent {
+ slop = LocalViewConfiguration.current.touchSlop
+ RangeSlider(
+ modifier = Modifier.testTag(tag),
+ values = state.value,
+ onValueChange = { state.value = it }
+ )
+ }
+
+ rule.runOnUiThread {
+ Truth.assertThat(state.value).isEqualTo(0.5f..0.5f)
+ }
+
+ var expected = 0f
+
+ rule.onNodeWithTag(tag)
+ .performGesture {
+ down(center)
+ moveBy(Offset(slop, 0f))
+ moveBy(Offset(100f, 0f))
+ up()
+ // subtract here as we're in rtl and going in the opposite direction
+ expected = calculateFraction(left, right, centerX + 100)
+ }
+ rule.runOnIdle {
+ Truth.assertThat(state.value.start).isEqualTo(0.5f)
+ Truth.assertThat(state.value.endInclusive).isWithin(0.001f).of(expected)
+ }
+ }
+
+ @ExperimentalMaterialApi
+ @Test
+ fun rangeSlider_closeThumbs_dragLeft() {
+ val state = mutableStateOf(0.5f..0.5f)
+ var slop = 0f
+
+ rule.setMaterialContent {
+ slop = LocalViewConfiguration.current.touchSlop
+ RangeSlider(
+ modifier = Modifier.testTag(tag),
+ values = state.value,
+ onValueChange = { state.value = it }
+ )
+ }
+
+ rule.runOnUiThread {
+ Truth.assertThat(state.value).isEqualTo(0.5f..0.5f)
+ }
+
+ var expected = 0f
+
+ rule.onNodeWithTag(tag)
+ .performGesture {
+ down(center)
+ moveBy(Offset(-slop - 1, 0f))
+ moveBy(Offset(-100f, 0f))
+ up()
+ // subtract here as we're in rtl and going in the opposite direction
+ expected = calculateFraction(left, right, centerX - 100)
+ }
+ rule.runOnIdle {
+ Truth.assertThat(state.value.start).isWithin(0.001f).of(expected)
+ Truth.assertThat(state.value.endInclusive).isEqualTo(0.5f)
+ }
+ }
}
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/OutlinedTextField.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/OutlinedTextField.kt
index 4805fb8..a5e1b53 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/OutlinedTextField.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/OutlinedTextField.kt
@@ -479,15 +479,15 @@
// on top we offset either by default padding or by label's half height if its too big
// minWidth must not be set to 0 due to how foundation TextField treats zero minWidth
val topPadding = max(heightOrZero(labelPlaceable) / 2, bottomPadding)
- val textContraints = incomingConstraints.offset(
+ val textConstraints = incomingConstraints.offset(
horizontal = -occupiedSpaceHorizontally,
vertical = -bottomPadding - topPadding
).copy(minHeight = 0)
val textFieldPlaceable =
- measurables.first { it.layoutId == TextFieldId }.measure(textContraints)
+ measurables.first { it.layoutId == TextFieldId }.measure(textConstraints)
// measure placeholder
- val placeholderConstraints = textContraints.copy(minWidth = 0)
+ val placeholderConstraints = textConstraints.copy(minWidth = 0)
val placeholderPlaceable =
measurables.find { it.layoutId == PlaceholderId }?.measure(placeholderConstraints)
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt
index 054d49f..a45ce5c 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt
@@ -26,8 +26,12 @@
import androidx.compose.foundation.gestures.DragScope
import androidx.compose.foundation.gestures.DraggableState
import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.gestures.awaitFirstDown
+import androidx.compose.foundation.gestures.awaitHorizontalTouchSlopOrCancellation
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.gestures.draggable
+import androidx.compose.foundation.gestures.forEachGesture
+import androidx.compose.foundation.gestures.horizontalDrag
import androidx.compose.foundation.indication
import androidx.compose.foundation.interaction.DragInteraction
import androidx.compose.foundation.interaction.Interaction
@@ -48,6 +52,7 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.MutableState
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
@@ -67,16 +72,23 @@
import androidx.compose.ui.graphics.PointMode
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.compositeOver
+import androidx.compose.ui.input.pointer.AwaitPointerEventScope
+import androidx.compose.ui.input.pointer.PointerId
+import androidx.compose.ui.input.pointer.PointerInputChange
+import androidx.compose.ui.input.pointer.consumePositionChange
import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.input.pointer.positionChange
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.semantics.disabled
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.setProgress
+import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.lerp
import kotlinx.coroutines.CancellationException
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
@@ -138,7 +150,7 @@
require(steps >= 0) { "steps should be >= 0" }
val onValueChangeState = rememberUpdatedState(onValueChange)
val tickFractions = remember(steps) {
- if (steps == 0) emptyList() else List(steps + 2) { it.toFloat() / (steps + 1) }
+ stepsToTickFractions(steps)
}
BoxWithConstraints(
modifier
@@ -163,20 +175,12 @@
onValueChangeState.value.invoke(scaleToUserValue(rawOffset.value))
}
}
- SideEffect {
- val newOffset = scaleToOffset(value)
- // floating point error due to rescaling
- val error = (valueRange.endInclusive - valueRange.start) / 1000
- if (abs(newOffset - rawOffset.value) > error) rawOffset.value = newOffset
- }
+
+ CorrectValueSideEffect(::scaleToOffset, valueRange, rawOffset, value)
val gestureEndAction = rememberUpdatedState<(Float) -> Unit> { velocity: Float ->
val current = rawOffset.value
- // target is a closest anchor to the `current`, if exists
- val target = tickFractions
- .minByOrNull { abs(lerp(minPx, maxPx, it) - current) }
- ?.run { lerp(minPx, maxPx, this) }
- ?: current
+ val target = snapValueToTick(current, tickFractions, minPx, maxPx)
if (current != target) {
scope.launch {
animateToTarget(draggableState, current, target, velocity)
@@ -201,6 +205,7 @@
startDragImmediately = draggableState.isDragging,
state = draggableState
)
+
val coerced = value.coerceIn(valueRange.start, valueRange.endInclusive)
val fraction = calcFraction(valueRange.start, valueRange.endInclusive, coerced)
SliderImpl(
@@ -216,6 +221,147 @@
}
/**
+ * <a href="https://material.io/components/sliders" class="external" target="_blank">Material Design slider</a>.
+ *
+ * Range Sliders expand upon [Slider] using the same concepts but allow the user to select 2 values.
+ *
+ * The two values are still bounded by the value range but they also cannot cross each other.
+ *
+ * Use continuous Range Sliders to allow users to make meaningful selections that don’t
+ * require a specific values:
+ *
+ * @sample androidx.compose.material.samples.RangeSliderSample
+ *
+ * You can allow the user to choose only between predefined set of values by specifying the amount
+ * of steps between min and max values:
+ *
+ * @sample androidx.compose.material.samples.StepRangeSliderSample
+ *
+ * @param values current values of the RangeSlider. If either value is outside of [valueRange]
+ * provided, it will be coerced to this range.
+ * @param onValueChange lambda in which values should be updated
+ * @param modifier modifiers for the Range Slider layout
+ * @param enabled whether or not component is enabled and can we interacted with or not
+ * @param valueRange range of values that Range Slider values can take. Passed [values] will be
+ * coerced to this range
+ * @param steps if greater than 0, specifies the amounts of discrete values, evenly distributed
+ * between across the whole value range. If 0, range slider will behave as a continuous slider and
+ * allow to choose any values from the range specified. Must not be negative.
+ * @param onValueChangeFinished lambda to be invoked when value change has ended. This callback
+ * shouldn't be used to update the range slider values (use [onValueChange] for that), but rather to
+ * know when the user has completed selecting a new value by ending a drag or a click.
+ * @param colors [SliderColors] that will be used to determine the color of the Range Slider
+ * parts in different state. See [SliderDefaults.colors] to customize.
+ */
+@Composable
+@ExperimentalMaterialApi
+fun RangeSlider(
+ values: ClosedFloatingPointRange<Float>,
+ onValueChange: (ClosedFloatingPointRange<Float>) -> Unit,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true,
+ valueRange: ClosedFloatingPointRange<Float> = 0f..1f,
+ /*@IntRange(from = 0)*/
+ steps: Int = 0,
+ onValueChangeFinished: (() -> Unit)? = null,
+ colors: SliderColors = SliderDefaults.colors()
+) {
+ val startInteractionSource: MutableInteractionSource = remember { MutableInteractionSource() }
+ val endInteractionSource: MutableInteractionSource = remember { MutableInteractionSource() }
+
+ require(steps >= 0) { "steps should be >= 0" }
+ val onValueChangeState = rememberUpdatedState(onValueChange)
+ val tickFractions = remember(steps) {
+ stepsToTickFractions(steps)
+ }
+
+ BoxWithConstraints {
+ val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl
+ val maxPx = constraints.maxWidth.toFloat()
+ val minPx = 0f
+
+ fun scaleToUserValue(offset: ClosedFloatingPointRange<Float>) =
+ scale(minPx, maxPx, offset, valueRange.start, valueRange.endInclusive)
+
+ fun scaleToOffset(userValue: Float) =
+ scale(valueRange.start, valueRange.endInclusive, userValue, minPx, maxPx)
+
+ val rawOffsetStart = remember { mutableStateOf(scaleToOffset(values.start)) }
+ val rawOffsetEnd = remember { mutableStateOf(scaleToOffset(values.endInclusive)) }
+
+ CorrectValueSideEffect(::scaleToOffset, valueRange, rawOffsetStart, values.start)
+ CorrectValueSideEffect(::scaleToOffset, valueRange, rawOffsetEnd, values.endInclusive)
+
+ val scope = rememberCoroutineScope()
+ val gestureEndAction = rememberUpdatedState<(Boolean) -> Unit> { isStart ->
+ val current = (if (isStart) rawOffsetStart else rawOffsetEnd).value
+ // target is a closest anchor to the `current`, if exists
+ val target = snapValueToTick(current, tickFractions, minPx, maxPx)
+ if (current == target) {
+ onValueChangeFinished?.invoke()
+ return@rememberUpdatedState
+ }
+
+ scope.launch {
+ Animatable(initialValue = current).animateTo(
+ target, SliderToTickAnimation,
+ 0f
+ ) {
+ (if (isStart) rawOffsetStart else rawOffsetEnd).value = this.value
+ onValueChangeState.value.invoke(
+ scaleToUserValue(rawOffsetStart.value..rawOffsetEnd.value)
+ )
+ }
+
+ onValueChangeFinished?.invoke()
+ }
+ }
+
+ val pressDrag = modifier.rangeSliderPressDragModifier(
+ startInteractionSource,
+ endInteractionSource,
+ rawOffsetStart,
+ rawOffsetEnd,
+ enabled,
+ isRtl,
+ maxPx,
+ valueRange,
+ gestureEndAction,
+ ) { isStart, offset ->
+ if (isStart) {
+ rawOffsetStart.value = (rawOffsetStart.value + offset)
+ .coerceIn(minPx, rawOffsetEnd.value)
+ } else {
+ rawOffsetEnd.value = (rawOffsetEnd.value + offset)
+ .coerceIn(rawOffsetStart.value, maxPx)
+ }
+
+ onValueChangeState.value.invoke(
+ scaleToUserValue(rawOffsetStart.value..rawOffsetEnd.value)
+ )
+ }
+
+ // The positions of the thumbs are dependant on each other.
+ val coercedStart = values.start.coerceIn(valueRange.start, values.endInclusive)
+ val coercedEnd = values.endInclusive.coerceIn(values.start, valueRange.endInclusive)
+ val fractionStart = calcFraction(valueRange.start, valueRange.endInclusive, coercedStart)
+ val fractionEnd = calcFraction(valueRange.start, valueRange.endInclusive, coercedEnd)
+
+ RangeSliderImpl(
+ enabled,
+ fractionStart,
+ fractionEnd,
+ tickFractions,
+ colors,
+ maxPx,
+ startInteractionSource,
+ endInteractionSource,
+ modifier = pressDrag.then(modifier),
+ )
+ }
+}
+
+/**
* Object to hold defaults used by [Slider]
*/
object SliderDefaults {
@@ -357,63 +503,130 @@
interactionSource: MutableInteractionSource,
modifier: Modifier
) {
- val widthDp = with(LocalDensity.current) {
- width.toDp()
- }
Box(modifier.then(DefaultSliderConstraints)) {
+ val trackStrokeWidth: Float
+ val thumbPx: Float
+ val widthDp: Dp
+ with(LocalDensity.current) {
+ trackStrokeWidth = TrackHeight.toPx()
+ thumbPx = ThumbRadius.toPx()
+ widthDp = width.toDp()
+ }
+
val thumbSize = ThumbRadius * 2
val offset = (widthDp - thumbSize) * positionFraction
val center = Modifier.align(Alignment.CenterStart)
- val trackStrokeWidth: Float
- val thumbPx: Float
- with(LocalDensity.current) {
- trackStrokeWidth = TrackHeight.toPx()
- thumbPx = ThumbRadius.toPx()
- }
Track(
center.fillMaxSize(),
colors,
enabled,
+ 0f,
positionFraction,
tickFractions,
thumbPx,
trackStrokeWidth
)
- Box(center.padding(start = offset)) {
- val interactions = remember { mutableStateListOf<Interaction>() }
+ SliderThumb(center, offset, interactionSource, colors, enabled, thumbSize)
+ }
+}
- LaunchedEffect(interactionSource) {
- interactionSource.interactions.collect { interaction ->
- when (interaction) {
- is PressInteraction.Press -> interactions.add(interaction)
- is PressInteraction.Release -> interactions.remove(interaction.press)
- is PressInteraction.Cancel -> interactions.remove(interaction.press)
- is DragInteraction.Start -> interactions.add(interaction)
- is DragInteraction.Stop -> interactions.remove(interaction.start)
- is DragInteraction.Cancel -> interactions.remove(interaction.start)
- }
+@Composable
+private fun RangeSliderImpl(
+ enabled: Boolean,
+ positionFractionStart: Float,
+ positionFractionEnd: Float,
+ tickFractions: List<Float>,
+ colors: SliderColors,
+ width: Float,
+ startInteractionSource: MutableInteractionSource,
+ endInteractionSource: MutableInteractionSource,
+ modifier: Modifier
+) {
+
+ Box(modifier.then(DefaultSliderConstraints)) {
+ val trackStrokeWidth: Float
+ val thumbPx: Float
+ val widthDp: Dp
+ with(LocalDensity.current) {
+ trackStrokeWidth = TrackHeight.toPx()
+ thumbPx = ThumbRadius.toPx()
+ widthDp = width.toDp()
+ }
+
+ val thumbSize = ThumbRadius * 2
+ val offsetStart = (widthDp - thumbSize) * positionFractionStart
+ val offsetEnd = (widthDp - thumbSize) * positionFractionEnd
+ Track(
+ Modifier.align(Alignment.CenterStart).fillMaxSize(),
+ colors,
+ enabled,
+ positionFractionStart,
+ positionFractionEnd,
+ tickFractions,
+ thumbPx,
+ trackStrokeWidth
+ )
+
+ SliderThumb(
+ Modifier.align(Alignment.CenterStart),
+ offsetStart,
+ startInteractionSource,
+ colors,
+ enabled,
+ thumbSize
+ )
+ SliderThumb(
+ Modifier.align(Alignment.CenterStart),
+ offsetEnd,
+ endInteractionSource,
+ colors,
+ enabled,
+ thumbSize
+ )
+ }
+}
+
+@Composable
+private fun SliderThumb(
+ modifier: Modifier,
+ offset: Dp,
+ interactionSource: MutableInteractionSource,
+ colors: SliderColors,
+ enabled: Boolean,
+ thumbSize: Dp
+) {
+ Box(modifier.padding(start = offset)) {
+ val interactions = remember { mutableStateListOf<Interaction>() }
+ LaunchedEffect(interactionSource) {
+ interactionSource.interactions.collect { interaction ->
+ when (interaction) {
+ is PressInteraction.Press -> interactions.add(interaction)
+ is PressInteraction.Release -> interactions.remove(interaction.press)
+ is PressInteraction.Cancel -> interactions.remove(interaction.press)
+ is DragInteraction.Start -> interactions.add(interaction)
+ is DragInteraction.Stop -> interactions.remove(interaction.start)
+ is DragInteraction.Cancel -> interactions.remove(interaction.start)
}
}
-
- val hasInteraction = interactions.isNotEmpty()
- val elevation = if (hasInteraction) {
- ThumbPressedElevation
- } else {
- ThumbDefaultElevation
- }
- Spacer(
- Modifier
- .size(thumbSize, thumbSize)
- .focusable(interactionSource = interactionSource)
- .indication(
- interactionSource = interactionSource,
- indication = rememberRipple(bounded = false, radius = ThumbRippleRadius)
- )
- .shadow(if (enabled) elevation else 0.dp, CircleShape, clip = false)
- .background(colors.thumbColor(enabled).value, CircleShape)
- )
}
+
+ val elevation = if (interactions.isNotEmpty()) {
+ ThumbPressedElevation
+ } else {
+ ThumbDefaultElevation
+ }
+ Spacer(
+ Modifier
+ .size(thumbSize, thumbSize)
+ .focusable(interactionSource = interactionSource)
+ .indication(
+ interactionSource = interactionSource,
+ indication = rememberRipple(bounded = false, radius = ThumbRippleRadius)
+ )
+ .shadow(if (enabled) elevation else 0.dp, CircleShape, clip = false)
+ .background(colors.thumbColor(enabled).value, CircleShape)
+ )
}
}
@@ -422,7 +635,8 @@
modifier: Modifier,
colors: SliderColors,
enabled: Boolean,
- positionFraction: Float,
+ positionFractionStart: Float,
+ positionFractionEnd: Float,
tickFractions: List<Float>,
thumbPx: Float,
trackStrokeWidth: Float
@@ -444,19 +658,24 @@
trackStrokeWidth,
StrokeCap.Round
)
- val sliderValue = Offset(
- sliderStart.x + (sliderEnd.x - sliderStart.x) * positionFraction,
+ val sliderValueEnd = Offset(
+ sliderStart.x + (sliderEnd.x - sliderStart.x) * positionFractionEnd,
+ center.y
+ )
+
+ val sliderValueStart = Offset(
+ sliderStart.x + (sliderEnd.x - sliderStart.x) * positionFractionStart,
center.y
)
drawLine(
activeTrackColor.value,
- sliderStart,
- sliderValue,
+ sliderValueStart,
+ sliderValueEnd,
trackStrokeWidth,
StrokeCap.Round
)
- tickFractions.groupBy { it > positionFraction }.forEach { (afterFraction, list) ->
+ tickFractions.groupBy { it > positionFractionEnd }.forEach { (afterFraction, list) ->
drawPoints(
list.map {
Offset(lerp(sliderStart, sliderEnd, it).x, center.y)
@@ -470,14 +689,62 @@
}
}
+private fun snapValueToTick(
+ current: Float,
+ tickFractions: List<Float>,
+ minPx: Float,
+ maxPx: Float
+): Float {
+ // target is a closest anchor to the `current`, if exists
+ return tickFractions
+ .minByOrNull { abs(lerp(minPx, maxPx, it) - current) }
+ ?.run { lerp(minPx, maxPx, this) }
+ ?: current
+}
+
+private suspend fun AwaitPointerEventScope.awaitSlop(
+ id: PointerId
+): Pair<PointerInputChange, Float>? {
+ var initialDelta = 0f
+ val postTouchSlop = { pointerInput: PointerInputChange, offset: Float ->
+ pointerInput.consumePositionChange()
+ initialDelta = offset
+ }
+ val afterSlopResult = awaitHorizontalTouchSlopOrCancellation(id, postTouchSlop)
+ return if (afterSlopResult != null) afterSlopResult to initialDelta else null
+}
+
+private fun stepsToTickFractions(steps: Int): List<Float> {
+ return if (steps == 0) emptyList() else List(steps + 2) { it.toFloat() / (steps + 1) }
+}
+
// Scale x1 from a1..b1 range to a2..b2 range
private fun scale(a1: Float, b1: Float, x1: Float, a2: Float, b2: Float) =
lerp(a2, b2, calcFraction(a1, b1, x1))
+// Scale x.start, x.endInclusive from a1..b1 range to a2..b2 range
+private fun scale(a1: Float, b1: Float, x: ClosedFloatingPointRange<Float>, a2: Float, b2: Float) =
+ scale(a1, b1, x.start, a2, b2)..scale(a1, b1, x.endInclusive, a2, b2)
+
// Calculate the 0..1 fraction that `pos` value represents between `a` and `b`
private fun calcFraction(a: Float, b: Float, pos: Float) =
(if (b - a == 0f) 0f else (pos - a) / (b - a)).coerceIn(0f, 1f)
+@Composable
+private fun CorrectValueSideEffect(
+ scaleToOffset: (Float) -> Float,
+ valueRange: ClosedFloatingPointRange<Float>,
+ valueState: MutableState<Float>,
+ value: Float
+) {
+ SideEffect {
+ val error = (valueRange.endInclusive - valueRange.start) / 1000
+ val newOffset = scaleToOffset(value)
+ if (abs(newOffset - valueState.value) > error)
+ valueState.value = newOffset
+ }
+}
+
private fun Modifier.sliderSemantics(
value: Float,
tickFractions: List<Float>,
@@ -566,6 +833,137 @@
}
}
+private fun Modifier.rangeSliderPressDragModifier(
+ startInteractionSource: MutableInteractionSource,
+ endInteractionSource: MutableInteractionSource,
+ rawOffsetStart: State<Float>,
+ rawOffsetEnd: State<Float>,
+ enabled: Boolean,
+ isRtl: Boolean,
+ maxPx: Float,
+ valueRange: ClosedFloatingPointRange<Float>,
+ gestureEndAction: State<(Boolean) -> Unit>,
+ onDrag: (Boolean, Float) -> Unit,
+): Modifier =
+ if (enabled) {
+ pointerInput(startInteractionSource, endInteractionSource, maxPx, isRtl, valueRange) {
+ val rangeSliderLogic = RangeSliderLogic(
+ startInteractionSource,
+ endInteractionSource,
+ rawOffsetStart,
+ rawOffsetEnd,
+ onDrag
+ )
+ coroutineScope {
+ forEachGesture {
+ awaitPointerEventScope {
+ var thumbCaptured = false
+ // If we are dragging the start thumb, false if we are dragging end thumb.
+ var draggingStart = true
+ val pointerEvent = awaitFirstDown(requireUnconsumed = false)
+ val interaction = PressInteraction.Press(pointerEvent.position)
+ val slop = viewConfiguration.touchSlop
+ val posX =
+ if (isRtl) maxPx - pointerEvent.position.x else pointerEvent.position.x
+
+ if (abs(rawOffsetEnd.value - posX) > slop ||
+ abs(rawOffsetStart.value - posX) > slop
+ ) {
+ // We have enough distance we can start dragging right away
+ draggingStart = rangeSliderLogic.shouldCaptureStartThumb(posX)
+ rangeSliderLogic.captureThumb(
+ draggingStart,
+ posX,
+ interaction,
+ this@coroutineScope
+ )
+ thumbCaptured = true
+ }
+
+ awaitSlop(pointerEvent.id)?.let {
+ if (thumbCaptured) {
+ onDrag(draggingStart, if (isRtl) -it.second else it.second)
+ } else {
+ // Determine which thumb to drag based on the direction the user
+ // is dragging
+ val dir = it.second
+ draggingStart = if (isRtl) dir >= 0f else dir < 0f
+ }
+ }
+
+ if (!thumbCaptured) {
+ rangeSliderLogic.captureThumb(
+ draggingStart,
+ posX,
+ interaction,
+ this@coroutineScope
+ )
+ }
+
+ val finishInteraction = try {
+ val success = horizontalDrag(pointerId = pointerEvent.id) {
+ val deltaX = it.positionChange().x
+ onDrag(draggingStart, if (isRtl) -deltaX else deltaX)
+ }
+ if (success) {
+ PressInteraction.Release(interaction)
+ } else {
+ PressInteraction.Cancel(interaction)
+ }
+ } catch (e: CancellationException) {
+ PressInteraction.Cancel(interaction)
+ }
+
+ gestureEndAction.value.invoke(draggingStart)
+ launch {
+ rangeSliderLogic
+ .activeInteraction(draggingStart)
+ .emit(finishInteraction)
+ }
+ }
+ }
+ }
+ }
+ } else {
+ this
+ }
+
+private class RangeSliderLogic(
+ val startInteractionSource: MutableInteractionSource,
+ val endInteractionSource: MutableInteractionSource,
+ val rawOffsetStart: State<Float>,
+ val rawOffsetEnd: State<Float>,
+ val onDrag: (Boolean, Float) -> Unit,
+) {
+ fun activeInteraction(draggingStart: Boolean): MutableInteractionSource =
+ if (draggingStart) startInteractionSource else endInteractionSource
+
+ fun shouldCaptureStartThumb(eventX: Float): Boolean {
+ val diffStart = abs(rawOffsetStart.value - eventX)
+ val diffEnd = abs(rawOffsetEnd.value - eventX)
+ return if (diffEnd == diffStart)
+ rawOffsetStart.value > eventX
+ else diffStart < diffEnd
+ }
+
+ fun captureThumb(
+ draggingStart: Boolean,
+ posX: Float,
+ interaction: Interaction,
+ scope: CoroutineScope
+ ) {
+ // TODO() interaction sources are not exposed in the public API so
+ // we only emit press events
+ onDrag(
+ draggingStart,
+ posX - if (draggingStart) rawOffsetStart.value else rawOffsetEnd.value
+ )
+ scope.launch {
+ activeInteraction(draggingStart).emit(interaction)
+ }
+ }
+}
+
@Immutable
private class DefaultSliderColors(
private val thumbColor: Color,
@@ -683,4 +1081,4 @@
override fun dispatchRawDelta(delta: Float) {
return onDelta(delta)
}
-}
+}
\ No newline at end of file
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Snackbar.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Snackbar.kt
index a7e4097..5f0854d 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Snackbar.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Snackbar.kt
@@ -61,7 +61,7 @@
* of the [SnackbarHost] to the [Scaffold]:
* @sample androidx.compose.material.samples.ScaffoldWithCustomSnackbar
*
- * @param modifier modifiers for the the Snackbar layout
+ * @param modifier modifiers for the Snackbar layout
* @param action action / button component to add as an action to the snackbar. Consider using
* [SnackbarDefaults.primaryActionColor] as the color for the action, if you do not
* have a predefined color you wish to use instead.
@@ -205,7 +205,7 @@
/**
* Provides a best-effort 'primary' color to be used as the primary color inside a [Snackbar].
- * Given that [Snackbar]s have an 'inverted' theme, i.e in a light theme they appear dark, and
+ * Given that [Snackbar]s have an 'inverted' theme, i.e. in a light theme they appear dark, and
* in a dark theme they appear light, just using [Colors.primary] will not work, and has
* incorrect contrast.
*
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Swipeable.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Swipeable.kt
index dec32d4..acd0a8a 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Swipeable.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Swipeable.kt
@@ -485,7 +485,7 @@
}
/**
- * Create and [remember] a [SwipeableState] which is kept in sync with another state, i.e:
+ * Create and [remember] a [SwipeableState] which is kept in sync with another state, i.e.:
* 1. Whenever the [value] changes, the [SwipeableState] will be animated to that new value.
* 2. Whenever the value of the [SwipeableState] changes (e.g. after a swipe), the owner of the
* [value] will be notified to update their state to the new value of the [SwipeableState] by
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 1e0658eb..d676337 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
@@ -1176,7 +1176,7 @@
override fun dispose() {
// Disposing the global snapshot is a no-op.
- // The dispose behavior is preformed by advancing the global snapshot. This method is
+ // The dispose behavior is performed by advancing the global snapshot. This method is
// squelched so calling it from `currentSnapshot` doesn't cause incorrect behavior
}
}
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotIdSet.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotIdSet.kt
index 8c5502f..19a2458 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotIdSet.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotIdSet.kt
@@ -50,7 +50,7 @@
) : Iterable<Int> {
/**
- * The the value of the bit at index [bit]
+ * The value of the bit at index [bit]
*/
fun get(bit: Int): Boolean {
val offset = bit - lowerBound
diff --git a/compose/ui/ui-graphics/api/public_plus_experimental_1.0.0-beta10.txt b/compose/ui/ui-graphics/api/public_plus_experimental_1.0.0-beta10.txt
index 587aad3..39b20cc 100644
--- a/compose/ui/ui-graphics/api/public_plus_experimental_1.0.0-beta10.txt
+++ b/compose/ui/ui-graphics/api/public_plus_experimental_1.0.0-beta10.txt
@@ -332,6 +332,8 @@
method public long getUnspecified-0d7_KjU();
method public long getWhite-0d7_KjU();
method public long getYellow-0d7_KjU();
+ method @androidx.compose.ui.graphics.ExperimentalGraphicsApi public long hsl-0d7_KjU(float hue, float saturation, float lightness, optional float alpha, optional androidx.compose.ui.graphics.colorspace.Rgb colorSpace);
+ method @androidx.compose.ui.graphics.ExperimentalGraphicsApi public long hsv-0d7_KjU(float hue, float saturation, float value, optional float alpha, optional androidx.compose.ui.graphics.colorspace.Rgb colorSpace);
property public final long Black;
property public final long Blue;
property public final long Cyan;
@@ -397,6 +399,9 @@
public final class DegreesKt {
}
+ @kotlin.RequiresOptIn(message="This API is experimental and is likely to change in the future.") public @interface ExperimentalGraphicsApi {
+ }
+
@androidx.compose.runtime.Immutable public final inline class FilterQuality {
ctor public FilterQuality();
method @androidx.compose.runtime.Immutable public static inline boolean equals-impl(int p, Object? p1);
diff --git a/compose/ui/ui-graphics/api/public_plus_experimental_current.txt b/compose/ui/ui-graphics/api/public_plus_experimental_current.txt
index 587aad3..39b20cc 100644
--- a/compose/ui/ui-graphics/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui-graphics/api/public_plus_experimental_current.txt
@@ -332,6 +332,8 @@
method public long getUnspecified-0d7_KjU();
method public long getWhite-0d7_KjU();
method public long getYellow-0d7_KjU();
+ method @androidx.compose.ui.graphics.ExperimentalGraphicsApi public long hsl-0d7_KjU(float hue, float saturation, float lightness, optional float alpha, optional androidx.compose.ui.graphics.colorspace.Rgb colorSpace);
+ method @androidx.compose.ui.graphics.ExperimentalGraphicsApi public long hsv-0d7_KjU(float hue, float saturation, float value, optional float alpha, optional androidx.compose.ui.graphics.colorspace.Rgb colorSpace);
property public final long Black;
property public final long Blue;
property public final long Cyan;
@@ -397,6 +399,9 @@
public final class DegreesKt {
}
+ @kotlin.RequiresOptIn(message="This API is experimental and is likely to change in the future.") public @interface ExperimentalGraphicsApi {
+ }
+
@androidx.compose.runtime.Immutable public final inline class FilterQuality {
ctor public FilterQuality();
method @androidx.compose.runtime.Immutable public static inline boolean equals-impl(int p, Object? p1);
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Color.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Color.kt
index 5524df22..c987420 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Color.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Color.kt
@@ -319,6 +319,72 @@
*/
@Stable
val Unspecified = Color(0f, 0f, 0f, 0f, ColorSpaces.Unspecified)
+
+ /**
+ * Return a [Color] from [hue], [saturation], and [value] (HSV representation).
+ *
+ * @param hue The color value in the range (0..360), where 0 is red, 120 is green, and
+ * 240 is blue
+ * @param saturation The amount of [hue] represented in the color in the range (0..1),
+ * where 0 has no color and 1 is fully saturated.
+ * @param value The strength of the color, where 0 is black.
+ * @param colorSpace The RGB color space used to calculate the Color from the HSV values.
+ */
+ @ExperimentalGraphicsApi
+ fun hsv(
+ hue: Float,
+ saturation: Float,
+ value: Float,
+ alpha: Float = 1f,
+ colorSpace: Rgb = ColorSpaces.Srgb
+ ): Color {
+ require(hue in 0f..360f && saturation in 0f..1f && value in 0f..1f) {
+ "HSV ($hue, $saturation, $value) must be in range (0..360, 0..1, 0..1)"
+ }
+ val red = hsvToRgbComponent(5, hue, saturation, value)
+ val green = hsvToRgbComponent(3, hue, saturation, value)
+ val blue = hsvToRgbComponent(1, hue, saturation, value)
+ return Color(red, green, blue, alpha, colorSpace)
+ }
+
+ private fun hsvToRgbComponent(n: Int, h: Float, s: Float, v: Float): Float {
+ val k = (n.toFloat() + h / 60f) % 6f
+ return v - (v * s * max(0f, minOf(k, 4 - k, 1f)))
+ }
+
+ /**
+ * Return a [Color] from [hue], [saturation], and [lightness] (HSL representation).
+ *
+ * @param hue The color value in the range (0..360), where 0 is red, 120 is green, and
+ * 240 is blue
+ * @param saturation The amount of [hue] represented in the color in the range (0..1),
+ * where 0 has no color and 1 is fully saturated.
+ * @param lightness A range of (0..1) where 0 is black, 0.5 is fully colored, and 1 is
+ * white.
+ * @param colorSpace The RGB color space used to calculate the Color from the HSL values.
+ */
+ @ExperimentalGraphicsApi
+ fun hsl(
+ hue: Float,
+ saturation: Float,
+ lightness: Float,
+ alpha: Float = 1f,
+ colorSpace: Rgb = ColorSpaces.Srgb
+ ): Color {
+ require(hue in 0f..360f && saturation in 0f..1f && lightness in 0f..1f) {
+ "HSL ($hue, $saturation, $lightness) must be in range (0..360, 0..1, 0..1)"
+ }
+ val red = hslToRgbComponent(0, hue, saturation, lightness)
+ val green = hslToRgbComponent(8, hue, saturation, lightness)
+ val blue = hslToRgbComponent(4, hue, saturation, lightness)
+ return Color(red, green, blue, alpha, colorSpace)
+ }
+
+ private fun hslToRgbComponent(n: Int, h: Float, s: Float, l: Float): Float {
+ val k = (n.toFloat() + h / 30f) % 12f
+ val a = s * min(l, 1f - l)
+ return l - a * max(-1f, minOf(k - 3, 9 - k, 1f))
+ }
}
}
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/ExperimentalGraphicsApi.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/ExperimentalGraphicsApi.kt
new file mode 100644
index 0000000..aa38621
--- /dev/null
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/ExperimentalGraphicsApi.kt
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.ui.graphics
+
+@RequiresOptIn("This API is experimental and is likely to change in the future.")
+annotation class ExperimentalGraphicsApi
\ No newline at end of file
diff --git a/compose/ui/ui-graphics/src/test/java/androidx/compose/ui/graphics/ColorTest.kt b/compose/ui/ui-graphics/src/test/java/androidx/compose/ui/graphics/ColorTest.kt
index eaa0c4f..c87b11c 100644
--- a/compose/ui/ui-graphics/src/test/java/androidx/compose/ui/graphics/ColorTest.kt
+++ b/compose/ui/ui-graphics/src/test/java/androidx/compose/ui/graphics/ColorTest.kt
@@ -285,6 +285,104 @@
assertEquals(0.6f, alpha, epsilon)
}
+ @OptIn(ExperimentalGraphicsApi::class)
+ @Test
+ fun testHsvInSrgb() {
+ assertEquals(Color.Transparent, Color.hsv(0f, 0f, 0f, 0f))
+ assertEquals(Color.Black, Color.hsv(0f, 0f, 0f))
+ assertEquals(Color.Black, Color.hsv(120f, 0f, 0f))
+ assertEquals(Color.Black, Color.hsv(120f, 1f, 0f))
+ assertEquals(Color.White, Color.hsv(0f, 0f, 1f))
+ assertEquals(Color.White, Color.hsv(120f, 0f, 1f))
+ assertEquals(Color.White, Color.hsv(240f, 0f, 1f))
+ val gray = Color(0xFF808080)
+ assertEquals(gray, Color.hsv(0f, 0f, 0.5f))
+ assertEquals(gray, Color.hsv(120f, 0f, 0.5f))
+ assertEquals(gray, Color.hsv(240f, 0f, 0.5f))
+
+ assertEquals(Color.Red, Color.hsv(0f, 1f, 1f))
+ assertEquals(Color.Yellow, Color.hsv(60f, 1f, 1f))
+ assertEquals(Color.Green, Color.hsv(120f, 1f, 1f))
+ assertEquals(Color.Cyan, Color.hsv(180f, 1f, 1f))
+ assertEquals(Color.Blue, Color.hsv(240f, 1f, 1f))
+ assertEquals(Color.Magenta, Color.hsv(300f, 1f, 1f))
+ assertEquals(Color.Red, Color.hsv(360f, 1f, 1f))
+ }
+
+ @OptIn(ExperimentalGraphicsApi::class)
+ @Test
+ fun testHsvInLinearSrgb() {
+ val lrgb = ColorSpaces.LinearSrgb
+ val srgb = ColorSpaces.Srgb
+ assertEquals(Color.Black, Color.hsv(0f, 0f, 0f, 1f, lrgb).convert(srgb))
+ assertEquals(Color.Black, Color.hsv(120f, 0f, 0f, 1f, lrgb).convert(srgb))
+ assertEquals(Color.Black, Color.hsv(120f, 1f, 0f, 1f, lrgb).convert(srgb))
+ assertEquals(Color.White, Color.hsv(0f, 0f, 1f, 1f, lrgb).convert(srgb))
+ assertEquals(Color.White, Color.hsv(120f, 0f, 1f, 1f, lrgb).convert(srgb))
+ assertEquals(Color.White, Color.hsv(240f, 0f, 1f, 1f, lrgb).convert(srgb))
+ val gray = Color(0.5f, 0.5f, 0.5f, 1f, lrgb)
+ assertEquals(gray, Color.hsv(0f, 0f, 0.5f, 1f, lrgb))
+ assertEquals(gray, Color.hsv(120f, 0f, 0.5f, 1f, lrgb))
+ assertEquals(gray, Color.hsv(240f, 0f, 0.5f, 1f, lrgb))
+
+ assertEquals(Color(1f, 0f, 0f, 1f, lrgb), Color.hsv(0f, 1f, 1f, 1f, lrgb))
+ assertEquals(Color(1f, 1f, 0f, 1f, lrgb), Color.hsv(60f, 1f, 1f, 1f, lrgb))
+ assertEquals(Color(0f, 1f, 0f, 1f, lrgb), Color.hsv(120f, 1f, 1f, 1f, lrgb))
+ assertEquals(Color(0f, 1f, 1f, 1f, lrgb), Color.hsv(180f, 1f, 1f, 1f, lrgb))
+ assertEquals(Color(0f, 0f, 1f, 1f, lrgb), Color.hsv(240f, 1f, 1f, 1f, lrgb))
+ assertEquals(Color(1f, 0f, 1f, 1f, lrgb), Color.hsv(300f, 1f, 1f, 1f, lrgb))
+ assertEquals(Color(1f, 0f, 0f, 1f, lrgb), Color.hsv(360f, 1f, 1f, 1f, lrgb))
+ }
+
+ @OptIn(ExperimentalGraphicsApi::class)
+ @Test
+ fun testHslInSrgb() {
+ assertEquals(Color.Transparent, Color.hsl(0f, 0f, 0f, 0f))
+ assertEquals(Color.Black, Color.hsl(0f, 0f, 0f))
+ assertEquals(Color.Black, Color.hsl(120f, 0f, 0f))
+ assertEquals(Color.Black, Color.hsl(120f, 1f, 0f))
+ assertEquals(Color.White, Color.hsl(0f, 0f, 1f))
+ assertEquals(Color.White, Color.hsl(120f, 1f, 1f))
+ assertEquals(Color.White, Color.hsl(240f, 0.5f, 1f))
+ val gray = Color(0xFF808080)
+ assertEquals(gray, Color.hsl(0f, 0f, 0.5f))
+ assertEquals(gray, Color.hsl(120f, 0f, 0.5f))
+ assertEquals(gray, Color.hsl(240f, 0f, 0.5f))
+
+ assertEquals(Color.Red, Color.hsl(0f, 1f, 0.5f))
+ assertEquals(Color.Yellow, Color.hsl(60f, 1f, 0.5f))
+ assertEquals(Color.Green, Color.hsl(120f, 1f, 0.5f))
+ assertEquals(Color.Cyan, Color.hsl(180f, 1f, 0.5f))
+ assertEquals(Color.Blue, Color.hsl(240f, 1f, 0.5f))
+ assertEquals(Color.Magenta, Color.hsl(300f, 1f, 0.5f))
+ assertEquals(Color.Red, Color.hsl(360f, 1f, 0.5f))
+ }
+
+ @OptIn(ExperimentalGraphicsApi::class)
+ @Test
+ fun testHslInLinearSrgb() {
+ val lrgb = ColorSpaces.LinearSrgb
+ val srgb = ColorSpaces.Srgb
+ assertEquals(Color.Black, Color.hsl(0f, 0f, 0f, 1f, lrgb).convert(srgb))
+ assertEquals(Color.Black, Color.hsl(120f, 0f, 0f, 1f, lrgb).convert(srgb))
+ assertEquals(Color.Black, Color.hsl(120f, 1f, 0f, 1f, lrgb).convert(srgb))
+ assertEquals(Color.White, Color.hsl(0f, 0f, 1f, 1f, lrgb).convert(srgb))
+ assertEquals(Color.White, Color.hsl(120f, 0f, 1f, 1f, lrgb).convert(srgb))
+ assertEquals(Color.White, Color.hsl(240f, 0f, 1f, 1f, lrgb).convert(srgb))
+ val gray = Color(0.5f, 0.5f, 0.5f, 1f, lrgb)
+ assertEquals(gray, Color.hsl(0f, 0f, 0.5f, 1f, lrgb))
+ assertEquals(gray, Color.hsl(120f, 0f, 0.5f, 1f, lrgb))
+ assertEquals(gray, Color.hsl(240f, 0f, 0.5f, 1f, lrgb))
+
+ assertEquals(Color(1f, 0f, 0f, 1f, lrgb), Color.hsl(0f, 1f, 0.5f, 1f, lrgb))
+ assertEquals(Color(1f, 1f, 0f, 1f, lrgb), Color.hsl(60f, 1f, 0.5f, 1f, lrgb))
+ assertEquals(Color(0f, 1f, 0f, 1f, lrgb), Color.hsl(120f, 1f, 0.5f, 1f, lrgb))
+ assertEquals(Color(0f, 1f, 1f, 1f, lrgb), Color.hsl(180f, 1f, 0.5f, 1f, lrgb))
+ assertEquals(Color(0f, 0f, 1f, 1f, lrgb), Color.hsl(240f, 1f, 0.5f, 1f, lrgb))
+ assertEquals(Color(1f, 0f, 1f, 1f, lrgb), Color.hsl(300f, 1f, 0.5f, 1f, lrgb))
+ assertEquals(Color(1f, 0f, 0f, 1f, lrgb), Color.hsl(360f, 1f, 0.5f, 1f, lrgb))
+ }
+
companion object {
@OptIn(kotlin.ExperimentalUnsignedTypes::class)
fun Int.toHexString() = "0x${toUInt().toString(16).padStart(8, '0')}"
diff --git a/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/SimpleComposablePreview.kt b/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/SimpleComposablePreview.kt
index 679b4a1..c4098c8 100644
--- a/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/SimpleComposablePreview.kt
+++ b/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/SimpleComposablePreview.kt
@@ -16,6 +16,8 @@
package androidx.compose.ui.tooling
+import androidx.activity.compose.LocalActivityResultRegistryOwner
+import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
@@ -86,6 +88,24 @@
Text("SaveableStateRegistry preview")
}
+@Preview
+@Composable
+private fun OnBackPressedDispatcherPreview() {
+ if (LocalOnBackPressedDispatcherOwner.current == null) throw IllegalArgumentException(
+ "OnBackPressedDispatcher is not provided"
+ )
+ Text("OnBackPressedDispatcher preview")
+}
+
+@Preview
+@Composable
+private fun ActivityResultRegistryPreview() {
+ if (LocalActivityResultRegistryOwner.current == null) throw IllegalArgumentException(
+ "ActivityResultRegistry is not provided"
+ )
+ Text("ActivityResultRegistry preview")
+}
+
class TestGroup {
@Preview
@Composable
diff --git a/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/preview/ComposeViewAdapterTest.kt b/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/preview/ComposeViewAdapterTest.kt
index 7a66e0d..a8c2933 100644
--- a/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/preview/ComposeViewAdapterTest.kt
+++ b/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/preview/ComposeViewAdapterTest.kt
@@ -265,6 +265,22 @@
)
}
+ @Test
+ fun onBackPressedDispatcherUsedInsidePreview() {
+ assertRendersCorrectly(
+ "androidx.compose.ui.tooling.SimpleComposablePreviewKt",
+ "OnBackPressedDispatcherPreview"
+ )
+ }
+
+ @Test
+ fun activityResultRegistryUsedInsidePreview() {
+ assertRendersCorrectly(
+ "androidx.compose.ui.tooling.SimpleComposablePreviewKt",
+ "ActivityResultRegistryPreview"
+ )
+ }
+
/**
* Check that no re-composition happens without forcing it.
*/
diff --git a/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/preview/ComposeViewAdapter.kt b/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/preview/ComposeViewAdapter.kt
index d20854c..4dabeea 100644
--- a/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/preview/ComposeViewAdapter.kt
+++ b/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/preview/ComposeViewAdapter.kt
@@ -25,6 +25,13 @@
import android.util.AttributeSet
import android.util.Log
import android.widget.FrameLayout
+import androidx.activity.OnBackPressedDispatcher
+import androidx.activity.OnBackPressedDispatcherOwner
+import androidx.activity.compose.LocalActivityResultRegistryOwner
+import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
+import androidx.activity.result.ActivityResultRegistry
+import androidx.activity.result.ActivityResultRegistryOwner
+import androidx.activity.result.contract.ActivityResultContract
import androidx.annotation.VisibleForTesting
import androidx.compose.animation.core.InternalAnimationApi
import androidx.compose.animation.core.Transition
@@ -49,6 +56,7 @@
import androidx.compose.ui.tooling.preview.animation.PreviewAnimationClock
import androidx.compose.ui.tooling.preview.CommonPreviewUtils.invokeComposableViaReflection
import androidx.compose.ui.unit.IntRect
+import androidx.core.app.ActivityOptionsCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleRegistry
import androidx.lifecycle.ViewModelStoreOwner
@@ -479,7 +487,11 @@
// We need to replace the FontResourceLoader to avoid using ResourcesCompat.
// ResourcesCompat can not load fonts within Layoutlib and, since Layoutlib always runs
// the latest version, we do not need it.
- CompositionLocalProvider(LocalFontLoader provides LayoutlibFontResourceLoader(context)) {
+ CompositionLocalProvider(
+ LocalFontLoader provides LayoutlibFontResourceLoader(context),
+ LocalOnBackPressedDispatcherOwner provides FakeOnBackPressedDispatcherOwner,
+ LocalActivityResultRegistryOwner provides FakeActivityResultRegistryOwner,
+ ) {
Inspectable(slotTableRecord, content)
}
}
@@ -678,4 +690,26 @@
private val FakeViewModelStoreOwner = ViewModelStoreOwner {
throw IllegalStateException("ViewModels creation is not supported in Preview")
}
+
+ private val FakeOnBackPressedDispatcherOwner = object : OnBackPressedDispatcherOwner {
+ private val onBackPressedDispatcher = OnBackPressedDispatcher()
+
+ override fun getOnBackPressedDispatcher() = onBackPressedDispatcher
+ override fun getLifecycle() = FakeSavedStateRegistryOwner.lifecycle
+ }
+
+ private val FakeActivityResultRegistryOwner = object : ActivityResultRegistryOwner {
+ private val activityResultRegistry = object : ActivityResultRegistry() {
+ override fun <I : Any?, O : Any?> onLaunch(
+ requestCode: Int,
+ contract: ActivityResultContract<I, O>,
+ input: I,
+ options: ActivityOptionsCompat?
+ ) {
+ throw IllegalStateException("Calling launch() is not supported in Preview")
+ }
+ }
+
+ override fun getActivityResultRegistry(): ActivityResultRegistry = activityResultRegistry
+ }
}
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
index d134ee9..cdf94ae 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
@@ -38,6 +38,7 @@
import android.widget.LinearLayout
import android.widget.TextView
import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -47,11 +48,15 @@
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.LazyRow
+import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.progressSemantics
import androidx.compose.foundation.selection.selectable
import androidx.compose.foundation.selection.toggleable
import androidx.compose.foundation.text.BasicText
import androidx.compose.foundation.text.BasicTextField
+import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -104,6 +109,7 @@
import androidx.test.filters.LargeTest
import androidx.test.filters.SdkSuppress
import androidx.test.platform.app.InstrumentationRegistry
+import com.google.common.truth.Truth.assertThat
import com.nhaarman.mockitokotlin2.argThat
import com.nhaarman.mockitokotlin2.atLeastOnce
import com.nhaarman.mockitokotlin2.doReturn
@@ -495,6 +501,147 @@
}
@Test
+ fun testPerformAction_showOnScreen() {
+ val scrollState = ScrollState(initial = 0)
+ val target1Tag = "target1"
+ val target2Tag = "target2"
+ container.setContent {
+ Box {
+ Column(
+ Modifier
+ .size(200.dp)
+ .verticalScroll(scrollState)
+ ) {
+ BasicText("Backward", Modifier.testTag(target2Tag).size(150.dp))
+ BasicText("Forward", Modifier.testTag(target1Tag).size(150.dp))
+ }
+ }
+ }
+
+ waitForSubtreeEventToSend()
+ assertThat(scrollState.value).isEqualTo(0)
+
+ val showOnScreen = android.R.id.accessibilityActionShowOnScreen
+ val targetNode1 = rule.onNodeWithTag(target1Tag)
+ .fetchSemanticsNode("couldn't find node with tag $target1Tag")
+ rule.runOnUiThread {
+ assertTrue(provider.performAction(targetNode1.id, showOnScreen, null))
+ }
+ with(rule.density) {
+ assertThat(scrollState.value).isGreaterThan(99.dp.toPx().toInt())
+ }
+
+ val targetNode2 = rule.onNodeWithTag(target2Tag)
+ .fetchSemanticsNode("couldn't find node with tag $target2Tag")
+ rule.runOnUiThread {
+ assertTrue(provider.performAction(targetNode2.id, showOnScreen, null))
+ }
+ assertThat(scrollState.value).isEqualTo(0)
+ }
+
+ @Test
+ fun testPerformAction_showOnScreen_lazy() {
+ val lazyState = LazyListState()
+ val target1Tag = "target1"
+ val target2Tag = "target2"
+ container.setContent {
+ Box {
+ LazyColumn(
+ modifier = Modifier.size(200.dp),
+ state = lazyState
+ ) {
+ item {
+ BasicText("Backward", Modifier.testTag(target2Tag).size(150.dp))
+ }
+ item {
+ BasicText("Forward", Modifier.testTag(target1Tag).size(150.dp))
+ }
+ }
+ }
+ }
+
+ waitForSubtreeEventToSend()
+ assertThat(lazyState.firstVisibleItemScrollOffset).isEqualTo(0)
+
+ val showOnScreen = android.R.id.accessibilityActionShowOnScreen
+ val targetNode1 = rule.onNodeWithTag(target1Tag)
+ .fetchSemanticsNode("couldn't find node with tag $target1Tag")
+ rule.runOnUiThread {
+ assertTrue(provider.performAction(targetNode1.id, showOnScreen, null))
+ }
+ with(rule.density) {
+ assertThat(lazyState.firstVisibleItemIndex).isEqualTo(0)
+ assertThat(lazyState.firstVisibleItemScrollOffset).isGreaterThan(99.dp.toPx().toInt())
+ }
+
+ val targetNode2 = rule.onNodeWithTag(target2Tag)
+ .fetchSemanticsNode("couldn't find node with tag $target2Tag")
+ rule.runOnUiThread {
+ assertTrue(provider.performAction(targetNode2.id, showOnScreen, null))
+ }
+ assertThat(lazyState.firstVisibleItemIndex).isEqualTo(0)
+ assertThat(lazyState.firstVisibleItemScrollOffset).isEqualTo(0)
+ }
+
+ @Test
+ fun testPerformAction_showOnScreen_lazynested() {
+ val parentLazyState = LazyListState()
+ val lazyState = LazyListState()
+ val target1Tag = "target1"
+ val target2Tag = "target2"
+ container.setContent {
+ Box {
+ LazyRow(
+ modifier = Modifier.size(250.dp),
+ state = parentLazyState
+ ) {
+ item {
+ LazyColumn(
+ modifier = Modifier.size(200.dp),
+ state = lazyState
+ ) {
+ item {
+ BasicText("Backward", Modifier.testTag(target2Tag).size(150.dp))
+ }
+ item {
+ BasicText("Forward", Modifier.testTag(target1Tag).size(150.dp))
+ }
+ }
+ }
+ }
+ }
+ }
+
+ waitForSubtreeEventToSend()
+ assertThat(lazyState.firstVisibleItemIndex).isEqualTo(0)
+ assertThat(lazyState.firstVisibleItemScrollOffset).isEqualTo(0)
+
+ // Test that child column scrolls to make it fully visible in its context, without being
+ // influenced by or influencing the parent row.
+ // TODO(b/190865803): Is this the ultimate right behavior we want?
+ val showOnScreen = android.R.id.accessibilityActionShowOnScreen
+ val targetNode1 = rule.onNodeWithTag(target1Tag)
+ .fetchSemanticsNode("couldn't find node with tag $target1Tag")
+ rule.runOnUiThread {
+ assertTrue(provider.performAction(targetNode1.id, showOnScreen, null))
+ }
+ with(rule.density) {
+ assertThat(lazyState.firstVisibleItemIndex).isEqualTo(0)
+ assertThat(lazyState.firstVisibleItemScrollOffset).isGreaterThan(99.dp.toPx().toInt())
+ }
+ assertThat(parentLazyState.firstVisibleItemScrollOffset).isEqualTo(0)
+
+ val targetNode2 = rule.onNodeWithTag(target2Tag)
+ .fetchSemanticsNode("couldn't find node with tag $target2Tag")
+ rule.runOnUiThread {
+ assertTrue(provider.performAction(targetNode2.id, showOnScreen, null))
+ }
+ assertThat(lazyState.firstVisibleItemIndex).isEqualTo(0)
+ assertThat(lazyState.firstVisibleItemScrollOffset).isEqualTo(0)
+ assertThat(parentLazyState.firstVisibleItemScrollOffset).isEqualTo(0)
+ }
+
+ @Test
fun testPerformAction_succeedOnEnabledNodes() {
val tag = "Toggleable"
container.setContent {
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidComposeViewAccessibilityDelegateCompatTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidComposeViewAccessibilityDelegateCompatTest.kt
index fea1c50..6663e6c 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidComposeViewAccessibilityDelegateCompatTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidComposeViewAccessibilityDelegateCompatTest.kt
@@ -25,9 +25,11 @@
import android.widget.FrameLayout
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.snapshots.Snapshot
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
+import androidx.compose.runtime.structuralEqualityPolicy
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.node.InnerPlaceable
@@ -597,55 +599,46 @@
}
@Test
- fun notSendScrollEvent_whenOnlyScrollAxisRangeMaxValueChanges() {
- val oldSemanticsNode = createSemanticsNodeWithProperties(1, true) {
- this.verticalScrollAxisRange = ScrollAxisRange({ 0f }, { 0f }, false)
+ fun sendScrollEvent_byStateObservation() {
+ var scrollValue by mutableStateOf(0f, structuralEqualityPolicy())
+ var scrollMaxValue by mutableStateOf(100f, structuralEqualityPolicy())
+
+ val semanticsNode = createSemanticsNodeWithProperties(1, false) {
+ verticalScrollAxisRange = ScrollAxisRange({ scrollValue }, { scrollMaxValue })
}
+
accessibilityDelegate.previousSemanticsNodes[1] =
AndroidComposeViewAccessibilityDelegateCompat.SemanticsNodeCopy(
- oldSemanticsNode,
+ semanticsNode,
mapOf()
)
val newNodes = mutableMapOf<Int, SemanticsNodeWithAdjustedBounds>()
- newNodes[1] = createSemanticsNodeWithAdjustedBoundsWithProperties(1, true) {
- this.verticalScrollAxisRange = ScrollAxisRange({ 0f }, { 5f }, false)
- }
- accessibilityDelegate.sendSemanticsPropertyChangeEvents(newNodes)
-
- verify(container, never()).requestSendAccessibilityEvent(
- eq(androidComposeView),
- argThat(
- ArgumentMatcher {
- it.eventType == AccessibilityEvent.TYPE_VIEW_SCROLLED
- }
- )
+ newNodes[1] = SemanticsNodeWithAdjustedBounds(
+ semanticsNode,
+ android.graphics.Rect()
)
- }
- @Test
- fun sendScrollEvent_whenScrollAxisRangeValueChanges() {
- val oldSemanticsNode = createSemanticsNodeWithProperties(2, false) {
- this.verticalScrollAxisRange = ScrollAxisRange({ 0f }, { 5f }, false)
+ try {
+ accessibilityDelegate.view.snapshotObserver.startObserving()
+
+ accessibilityDelegate.sendSemanticsPropertyChangeEvents(newNodes)
+
+ Snapshot.notifyObjectsInitialized()
+ scrollValue = 1f
+ Snapshot.sendApplyNotifications()
+ } finally {
+ accessibilityDelegate.view.snapshotObserver.stopObserving()
}
- accessibilityDelegate.previousSemanticsNodes[2] =
- AndroidComposeViewAccessibilityDelegateCompat.SemanticsNodeCopy(
- oldSemanticsNode,
- mapOf()
- )
- val newNodes = mutableMapOf<Int, SemanticsNodeWithAdjustedBounds>()
- newNodes[2] = createSemanticsNodeWithAdjustedBoundsWithProperties(2, false) {
- this.verticalScrollAxisRange = ScrollAxisRange({ 2f }, { 5f }, false)
- }
- accessibilityDelegate.sendSemanticsPropertyChangeEvents(newNodes)
verify(container, times(1)).requestSendAccessibilityEvent(
eq(androidComposeView),
argThat(
ArgumentMatcher {
- it.eventType == AccessibilityEvent.TYPE_VIEW_SCROLLED && it.scrollY == 2 &&
- it.maxScrollY == 5 &&
+ it.eventType == AccessibilityEvent.TYPE_VIEW_SCROLLED &&
+ it.scrollY == 1 &&
+ it.maxScrollY == 100 &&
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
- it.scrollDeltaY == 2
+ it.scrollDeltaY == 1
} else {
true
}
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
index b441e23..fe177ce 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
@@ -45,8 +45,10 @@
import androidx.compose.ui.graphics.toAndroidRect
import androidx.compose.ui.layout.boundsInParent
import androidx.compose.ui.node.LayoutNode
+import androidx.compose.ui.node.OwnerScope
import androidx.compose.ui.semantics.CustomAccessibilityAction
import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.ScrollAxisRange
import androidx.compose.ui.semantics.SemanticsActions
import androidx.compose.ui.semantics.SemanticsActions.CustomActions
import androidx.compose.ui.semantics.SemanticsNode
@@ -1198,6 +1200,33 @@
AccessibilityNodeInfoCompat.ACTION_DISMISS -> {
return node.config.getOrNull(SemanticsActions.Dismiss)?.action?.invoke() ?: false
}
+ android.R.id.accessibilityActionShowOnScreen -> {
+ // TODO(b/190865803): Consider scrolling nested containers instead of only the first one.
+ var scrollableAncestor: SemanticsNode? = node.parent
+ var scrollAction = scrollableAncestor?.config?.getOrNull(SemanticsActions.ScrollBy)
+ while (scrollableAncestor != null) {
+ if (scrollAction != null) {
+ break
+ }
+ scrollableAncestor = scrollableAncestor.parent
+ scrollAction = scrollableAncestor?.config?.getOrNull(SemanticsActions.ScrollBy)
+ }
+ if (scrollableAncestor == null) {
+ return false
+ }
+
+ // TalkBack expects the minimum amount of movement to fully reveal the node.
+ var xDelta = node.size.width - node.boundsInWindow.width
+ if (node.boundsInWindow.left == scrollableAncestor.positionInWindow.x) {
+ xDelta = -xDelta
+ }
+ var yDelta = node.size.height - node.boundsInWindow.height
+ if (node.boundsInWindow.top == scrollableAncestor.positionInWindow.y) {
+ yDelta = -yDelta
+ }
+
+ return scrollAction?.action?.invoke(xDelta, yDelta) ?: false
+ }
// TODO: handling for other system actions
else -> {
val label = actionIdToLabel[virtualViewId]?.get(action) ?: return false
@@ -1601,14 +1630,23 @@
internal fun sendSemanticsPropertyChangeEvents(
newSemanticsNodes: Map<Int, SemanticsNodeWithAdjustedBounds>
) {
+ val oldScrollObservationScopes = ArrayList(scrollObservationScopes)
+ scrollObservationScopes.clear()
for (id in newSemanticsNodes.keys) {
// We do doing this search because the new configuration is set as a whole, so we
// can't indicate which property is changed when setting the new configuration.
val oldNode = previousSemanticsNodes[id] ?: continue
val newNode = newSemanticsNodes[id]?.semanticsNode
var propertyChanged = false
+
for (entry in newNode!!.config) {
- if (entry.value == oldNode.config.getOrNull(entry.key)) {
+ var newlyObservingScroll = false
+ if (entry.key == SemanticsProperties.HorizontalScrollAxisRange ||
+ entry.key == SemanticsProperties.VerticalScrollAxisRange
+ ) {
+ newlyObservingScroll = registerScrollingId(id, oldScrollObservationScopes)
+ }
+ if (!newlyObservingScroll && entry.value == oldNode.config.getOrNull(entry.key)) {
continue
}
@Suppress("UNCHECKED_CAST")
@@ -1707,47 +1745,16 @@
SemanticsProperties.HorizontalScrollAxisRange,
SemanticsProperties.VerticalScrollAxisRange -> {
// TODO(yingleiw): Add throttling for scroll/state events.
- val newXState = newNode.config.getOrNull(
- SemanticsProperties.HorizontalScrollAxisRange
- )
- val oldXState = oldNode.config.getOrNull(
- SemanticsProperties.HorizontalScrollAxisRange
- )
- val newYState = newNode.config.getOrNull(
- SemanticsProperties.VerticalScrollAxisRange
- )
- val oldYState = oldNode.config.getOrNull(
- SemanticsProperties.VerticalScrollAxisRange
- )
notifySubtreeAccessibilityStateChangedIfNeeded(newNode.layoutNode)
- val deltaX = if (newXState != null && oldXState != null) {
- newXState.value() - oldXState.value()
- } else {
- 0f
- }
- val deltaY = if (newYState != null && oldYState != null) {
- newYState.value() - oldYState.value()
- } else {
- 0f
- }
- if (deltaX != 0f || deltaY != 0f) {
- val event = createEvent(
- semanticsNodeIdToAccessibilityVirtualNodeId(id),
- AccessibilityEvent.TYPE_VIEW_SCROLLED
- )
- if (newXState != null) {
- event.scrollX = newXState.value().toInt()
- event.maxScrollX = newXState.maxValue().toInt()
- }
- if (newYState != null) {
- event.scrollY = newYState.value().toInt()
- event.maxScrollY = newYState.maxValue().toInt()
- }
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
- Api28Impl.setScrollEventDelta(event, deltaX.toInt(), deltaY.toInt())
- }
- sendEvent(event)
- }
+
+ val scope = scrollObservationScopes.findById(id)!!
+ scope.horizontalScrollAxisRange = newNode.config.getOrNull(
+ SemanticsProperties.HorizontalScrollAxisRange
+ )
+ scope.verticalScrollAxisRange = newNode.config.getOrNull(
+ SemanticsProperties.VerticalScrollAxisRange
+ )
+ sendScrollEventIfNeeded(scope)
}
SemanticsProperties.Focused -> {
if (entry.value as Boolean) {
@@ -1814,6 +1821,93 @@
}
}
+ // List of visible scrollable nodes (which are observing scroll state snapshot writes).
+ private val scrollObservationScopes = mutableListOf<ScrollObservationScope>()
+
+ /*
+ * Lambda to store in scrolling snapshot observer, which must never be recreated because
+ * the snapshot system makes use of lambda reference comparisons.
+ * (Note that recent versions of the Kotlin compiler do maintain a persistent
+ * object for most lambda expressions, so this is just for the purpose of explicitness.)
+ */
+ private val sendScrollEventIfNeededLambda: (ScrollObservationScope) -> Unit = {
+ this.sendScrollEventIfNeeded(it)
+ }
+
+ private fun registerScrollingId(
+ id: Int,
+ oldScrollObservationScopes: List<ScrollObservationScope>
+ ): Boolean {
+ var newlyObservingScroll = false
+ val oldScope = oldScrollObservationScopes.findById(id)
+ val newScope = if (oldScope != null) {
+ oldScope
+ } else {
+ newlyObservingScroll = true
+ ScrollObservationScope(
+ semanticsNodeId = id,
+ allScopes = scrollObservationScopes,
+ oldXValue = null,
+ oldYValue = null,
+ horizontalScrollAxisRange = null,
+ verticalScrollAxisRange = null
+ )
+ }
+ scrollObservationScopes.add(newScope)
+ return newlyObservingScroll
+ }
+
+ private fun sendScrollEventIfNeeded(scrollObservationScope: ScrollObservationScope) {
+ if (!scrollObservationScope.isValid) {
+ return
+ }
+ view.snapshotObserver.observeReads(scrollObservationScope, sendScrollEventIfNeededLambda) {
+ val newXState = scrollObservationScope.horizontalScrollAxisRange
+ val newYState = scrollObservationScope.verticalScrollAxisRange
+ val oldXValue = scrollObservationScope.oldXValue
+ val oldYValue = scrollObservationScope.oldYValue
+
+ val deltaX = if (newXState != null && oldXValue != null) {
+ newXState.value() - oldXValue
+ } else {
+ 0f
+ }
+ val deltaY = if (newYState != null && oldYValue != null) {
+ newYState.value() - oldYValue
+ } else {
+ 0f
+ }
+
+ if (deltaX != 0f || deltaY != 0f) {
+ val event = createEvent(
+ semanticsNodeIdToAccessibilityVirtualNodeId(
+ scrollObservationScope.semanticsNodeId
+ ),
+ AccessibilityEvent.TYPE_VIEW_SCROLLED
+ )
+ if (newXState != null) {
+ event.scrollX = newXState.value().toInt()
+ event.maxScrollX = newXState.maxValue().toInt()
+ }
+ if (newYState != null) {
+ event.scrollY = newYState.value().toInt()
+ event.maxScrollY = newYState.maxValue().toInt()
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ Api28Impl.setScrollEventDelta(event, deltaX.toInt(), deltaY.toInt())
+ }
+ sendEvent(event)
+ }
+
+ if (newXState != null) {
+ scrollObservationScope.oldXValue = newXState.value()
+ }
+ if (newYState != null) {
+ scrollObservationScope.oldYValue = newYState.value()
+ }
+ }
+ }
+
private fun sendPaneChangeEvents(
semanticsNodeId: Int,
contentChangeType: Int,
@@ -2341,4 +2435,27 @@
fun setAvailableExtraData(node: AccessibilityNodeInfo, data: List<String>) {
node.availableExtraData = data
}
+}
+
+// These objects are used as snapshot observation scopes for the purpose of sending accessibility
+// scroll events whenever the scroll offset changes. There is one per scroller and their lifecycle
+// is the same as the scroller's lifecycle in the semantics tree.
+internal class ScrollObservationScope(
+ val semanticsNodeId: Int,
+ val allScopes: List<ScrollObservationScope>,
+ var oldXValue: Float?,
+ var oldYValue: Float?,
+ var horizontalScrollAxisRange: ScrollAxisRange?,
+ var verticalScrollAxisRange: ScrollAxisRange?
+) : OwnerScope {
+ override val isValid get() = allScopes.contains(this)
+}
+
+internal fun List<ScrollObservationScope>.findById(id: Int): ScrollObservationScope? {
+ for (index in indices) {
+ if (this[index].semanticsNodeId == id) {
+ return this[index]
+ }
+ }
+ return null
}
\ No newline at end of file
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/TextInputServiceAndroid.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/TextInputServiceAndroid.android.kt
index e61215c..333a055 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/TextInputServiceAndroid.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/TextInputServiceAndroid.android.kt
@@ -70,7 +70,11 @@
private val layoutListener = ViewTreeObserver.OnGlobalLayoutListener {
// focusedRect is null if there is not ongoing text input session. So safe to request
// latest focused rectangle whenever global layout has changed.
- focusedRect?.let { view.requestRectangleOnScreen(it) }
+ focusedRect?.let {
+ // Notice that view.requestRectangleOnScreen may modify the input Rect, we have to
+ // create another Rect and then pass it.
+ view.requestRectangleOnScreen(android.graphics.Rect(it))
+ }
}
internal constructor(view: View) : this(view, InputMethodManagerImpl(view.context))
@@ -236,7 +240,11 @@
// Even if we miss all the timing of requesting rectangle during initial text field focus,
// focused rectangle will be requested when software keyboard has shown.
if (ic == null) {
- view.requestRectangleOnScreen(focusedRect)
+ focusedRect?.let {
+ // Notice that view.requestRectangleOnScreen may modify the input Rect, we have to
+ // create another Rect and then pass it.
+ view.requestRectangleOnScreen(android.graphics.Rect(it))
+ }
}
}
}
diff --git a/compose/ui/ui/src/androidMain/res/values-af/strings.xml b/compose/ui/ui/src/androidMain/res/values-af/strings.xml
new file mode 100644
index 0000000..0a70b81
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-af/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Nie gemerk of ontmerk nie"</string>
+ <string name="on" msgid="8655164131929253426">"Aan"</string>
+ <string name="off" msgid="875452955155264703">"Af"</string>
+ <string name="selected" msgid="6043586758067023">"Gekies"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Nie gekies nie"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> persent."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Besig"</string>
+ <string name="tab" msgid="1672349317127674378">"Oortjie"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Navigasiekieslys"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Maak navigasiekieslys toe"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Maak sigblad toe"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Ongeldige invoer"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-am/strings.xml b/compose/ui/ui/src/androidMain/res/values-am/strings.xml
new file mode 100644
index 0000000..45c14ea
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-am/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"ምልክት የተደረገበትም ያልተደረገበትም"</string>
+ <string name="on" msgid="8655164131929253426">"በርቷል"</string>
+ <string name="off" msgid="875452955155264703">"ጠፍቷል"</string>
+ <string name="selected" msgid="6043586758067023">"ተመርጧል"</string>
+ <string name="not_selected" msgid="6610465462668679431">"ያልተመረጡ"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> በመቶ።"</string>
+ <string name="in_progress" msgid="6827826412747255547">"በሂደት ላይ"</string>
+ <string name="tab" msgid="1672349317127674378">"ትር"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"የዳሰሳ ምናሌ"</string>
+ <string name="close_drawer" msgid="406453423630273620">"የዳሰሳ ምናሌን ዝጋ"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"ሉህን ዝጋ"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"ልክ ያልሆነ ግቤት"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-ar/strings.xml b/compose/ui/ui/src/androidMain/res/values-ar/strings.xml
new file mode 100644
index 0000000..760e115
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-ar/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"لم يتم وضع علامة أو إزالتها"</string>
+ <string name="on" msgid="8655164131929253426">"مفعّل"</string>
+ <string name="off" msgid="875452955155264703">"غير مفعّل"</string>
+ <string name="selected" msgid="6043586758067023">"محدّد"</string>
+ <string name="not_selected" msgid="6610465462668679431">"غير محدّد"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> في المئة."</string>
+ <string name="in_progress" msgid="6827826412747255547">"قيد التقدم"</string>
+ <string name="tab" msgid="1672349317127674378">"علامة تبويب"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"قائمة تنقل"</string>
+ <string name="close_drawer" msgid="406453423630273620">"إغلاق قائمة التنقل"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"إغلاق الورقة"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"إدخال غير صالح"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-as/strings.xml b/compose/ui/ui/src/androidMain/res/values-as/strings.xml
new file mode 100644
index 0000000..f1eed51
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-as/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"টিক চিহ্ন দিয়াও নাই আঁতৰোৱাও নাই"</string>
+ <string name="on" msgid="8655164131929253426">"অন কৰা আছে"</string>
+ <string name="off" msgid="875452955155264703">"অফ আছে"</string>
+ <string name="selected" msgid="6043586758067023">"বাছনি কৰা হৈছে"</string>
+ <string name="not_selected" msgid="6610465462668679431">"বাছনি কৰা হোৱা নাই"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> শতাংশ।"</string>
+ <string name="in_progress" msgid="6827826412747255547">"প্ৰক্ৰিয়াকৰণ কৰি থকা হৈছে"</string>
+ <string name="tab" msgid="1672349317127674378">"টেব"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"নেভিগেশ্বন মেনু"</string>
+ <string name="close_drawer" msgid="406453423630273620">"নেভিগেশ্বন মেনু বন্ধ কৰক"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"শ্বীট বন্ধ কৰক"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"অমান্য ইনপুট"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-az/strings.xml b/compose/ui/ui/src/androidMain/res/values-az/strings.xml
new file mode 100644
index 0000000..549f325
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-az/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Nə seçilməyib, nə də seçim ləğv edilməyib"</string>
+ <string name="on" msgid="8655164131929253426">"Aktiv"</string>
+ <string name="off" msgid="875452955155264703">"Deaktiv"</string>
+ <string name="selected" msgid="6043586758067023">"Seçilib"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Seçilməyib"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> faiz."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Davam edir"</string>
+ <string name="tab" msgid="1672349317127674378">"Tab"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Naviqasiya menyusu"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Naviqasiya menyusunu bağlayın"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Səhifəni bağlayın"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Yanlış daxiletmə"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-b+sr+Latn/strings.xml b/compose/ui/ui/src/androidMain/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..5b6e403
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Nije označeno niti poništeno"</string>
+ <string name="on" msgid="8655164131929253426">"Uključeno"</string>
+ <string name="off" msgid="875452955155264703">"Isključeno"</string>
+ <string name="selected" msgid="6043586758067023">"Izabrano"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Nije izabrano"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> posto."</string>
+ <string name="in_progress" msgid="6827826412747255547">"U toku"</string>
+ <string name="tab" msgid="1672349317127674378">"Kartica"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Meni za navigaciju"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Zatvori meni za navigaciju"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Zatvorite tabelu"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Unos je nevažeći"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-be/strings.xml b/compose/ui/ui/src/androidMain/res/values-be/strings.xml
new file mode 100644
index 0000000..db26c43
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-be/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Птушка не пастаўлена і не знята"</string>
+ <string name="on" msgid="8655164131929253426">"Уключана"</string>
+ <string name="off" msgid="875452955155264703">"Выключана"</string>
+ <string name="selected" msgid="6043586758067023">"Выбрана"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Не выбрана"</string>
+ <string name="template_percent" msgid="5946805113151406391">"Працэнтаў: <xliff:g id="PERCENTAGE">%1$d</xliff:g>."</string>
+ <string name="in_progress" msgid="6827826412747255547">"У працэсе"</string>
+ <string name="tab" msgid="1672349317127674378">"Укладка"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Меню навігацыі"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Закрыць меню навігацыі"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Закрыць аркуш"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Памылка ўводу"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-bg/strings.xml b/compose/ui/ui/src/androidMain/res/values-bg/strings.xml
new file mode 100644
index 0000000..ee7ab18
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-bg/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Няма поставена или премахната отметка"</string>
+ <string name="on" msgid="8655164131929253426">"Вкл."</string>
+ <string name="off" msgid="875452955155264703">"Изкл."</string>
+ <string name="selected" msgid="6043586758067023">"Избрано"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Не е избрано"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> процента."</string>
+ <string name="in_progress" msgid="6827826412747255547">"В ход"</string>
+ <string name="tab" msgid="1672349317127674378">"Раздел"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Меню за навигация"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Затваряне на менюто за навигация"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Затваряне на таблицата"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Въведеното е невалидно"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-bs/strings.xml b/compose/ui/ui/src/androidMain/res/values-bs/strings.xml
new file mode 100644
index 0000000..529ef91
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-bs/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Nije odabrano ni poništeno"</string>
+ <string name="on" msgid="8655164131929253426">"Uključeno"</string>
+ <string name="off" msgid="875452955155264703">"Isključeno"</string>
+ <string name="selected" msgid="6043586758067023">"Odabrano"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Nije odabrano"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> posto."</string>
+ <string name="in_progress" msgid="6827826412747255547">"U toku"</string>
+ <string name="tab" msgid="1672349317127674378">"Kartica"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Meni za navigaciju"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Zatvaranje navigacionog menija"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Zatvaranje tabele"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Pogrešan unos"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-ca/strings.xml b/compose/ui/ui/src/androidMain/res/values-ca/strings.xml
new file mode 100644
index 0000000..21f81fb
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-ca/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Ni marcada ni desmarcada"</string>
+ <string name="on" msgid="8655164131929253426">"Activat"</string>
+ <string name="off" msgid="875452955155264703">"Desactivat"</string>
+ <string name="selected" msgid="6043586758067023">"Seleccionat"</string>
+ <string name="not_selected" msgid="6610465462668679431">"No seleccionat"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> per cent"</string>
+ <string name="in_progress" msgid="6827826412747255547">"En curs"</string>
+ <string name="tab" msgid="1672349317127674378">"Pestanya"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Menú de navegació"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Tanca el menú de navegació"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Tanca el full"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"L\'entrada no és vàlida"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-cs/strings.xml b/compose/ui/ui/src/androidMain/res/values-cs/strings.xml
new file mode 100644
index 0000000..48ba4f2
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-cs/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Ani zaškrtnuto, ani nezaškrtnuto"</string>
+ <string name="on" msgid="8655164131929253426">"Zap"</string>
+ <string name="off" msgid="875452955155264703">"Vyp"</string>
+ <string name="selected" msgid="6043586758067023">"Vybráno"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Nevybráno"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> procent."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Probíhá"</string>
+ <string name="tab" msgid="1672349317127674378">"Karta"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Navigační nabídka"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Zavřít navigační panel"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Zavřít sešit"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Neplatný údaj"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-da/strings.xml b/compose/ui/ui/src/androidMain/res/values-da/strings.xml
new file mode 100644
index 0000000..7ff8daff
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-da/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Hverken tilvalgt eller fravalgt"</string>
+ <string name="on" msgid="8655164131929253426">"Til"</string>
+ <string name="off" msgid="875452955155264703">"Fra"</string>
+ <string name="selected" msgid="6043586758067023">"Valgt"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Ikke valgt"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> procent."</string>
+ <string name="in_progress" msgid="6827826412747255547">"I gang"</string>
+ <string name="tab" msgid="1672349317127674378">"Fane"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Navigationsmenu"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Luk navigationsmenuen"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Luk arket"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Ugyldigt input"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-de/strings.xml b/compose/ui/ui/src/androidMain/res/values-de/strings.xml
new file mode 100644
index 0000000..b716e53
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-de/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Häkchen weder gesetzt noch entfernt"</string>
+ <string name="on" msgid="8655164131929253426">"An"</string>
+ <string name="off" msgid="875452955155264703">"Aus"</string>
+ <string name="selected" msgid="6043586758067023">"Ausgewählt"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Nicht ausgewählt"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> Prozent."</string>
+ <string name="in_progress" msgid="6827826412747255547">"In Bearbeitung"</string>
+ <string name="tab" msgid="1672349317127674378">"Tab"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Navigationsmenü"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Navigationsmenü schließen"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Tabelle schließen"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Ungültige Eingabe"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-el/strings.xml b/compose/ui/ui/src/androidMain/res/values-el/strings.xml
new file mode 100644
index 0000000..69dcbd3
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-el/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Ούτε επιλεγμένο ούτε μη επιλεγμένο"</string>
+ <string name="on" msgid="8655164131929253426">"Ενεργό"</string>
+ <string name="off" msgid="875452955155264703">"Ανενεργό"</string>
+ <string name="selected" msgid="6043586758067023">"Επιλεγμένο"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Δεν έχει επιλεχθεί"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> τοις εκατό."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Σε εξέλιξη"</string>
+ <string name="tab" msgid="1672349317127674378">"Καρτέλα"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Μενού πλοήγησης"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Κλείσιμο του μενού πλοήγησης"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Κλείσιμο φύλλου"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Μη έγκυρη καταχώριση"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-en-rAU/strings.xml b/compose/ui/ui/src/androidMain/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..0bcdf21
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-en-rAU/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Neither ticked nor unticked"</string>
+ <string name="on" msgid="8655164131929253426">"On"</string>
+ <string name="off" msgid="875452955155264703">"Off"</string>
+ <string name="selected" msgid="6043586758067023">"Selected"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Not selected"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> per cent."</string>
+ <string name="in_progress" msgid="6827826412747255547">"In progress"</string>
+ <string name="tab" msgid="1672349317127674378">"Tab"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Navigation menu"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Close navigation menu"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Close sheet"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Invalid input"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-en-rCA/strings.xml b/compose/ui/ui/src/androidMain/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..0bcdf21
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-en-rCA/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Neither ticked nor unticked"</string>
+ <string name="on" msgid="8655164131929253426">"On"</string>
+ <string name="off" msgid="875452955155264703">"Off"</string>
+ <string name="selected" msgid="6043586758067023">"Selected"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Not selected"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> per cent."</string>
+ <string name="in_progress" msgid="6827826412747255547">"In progress"</string>
+ <string name="tab" msgid="1672349317127674378">"Tab"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Navigation menu"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Close navigation menu"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Close sheet"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Invalid input"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-en-rGB/strings.xml b/compose/ui/ui/src/androidMain/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..0bcdf21
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-en-rGB/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Neither ticked nor unticked"</string>
+ <string name="on" msgid="8655164131929253426">"On"</string>
+ <string name="off" msgid="875452955155264703">"Off"</string>
+ <string name="selected" msgid="6043586758067023">"Selected"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Not selected"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> per cent."</string>
+ <string name="in_progress" msgid="6827826412747255547">"In progress"</string>
+ <string name="tab" msgid="1672349317127674378">"Tab"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Navigation menu"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Close navigation menu"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Close sheet"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Invalid input"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-en-rIN/strings.xml b/compose/ui/ui/src/androidMain/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..0bcdf21
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-en-rIN/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Neither ticked nor unticked"</string>
+ <string name="on" msgid="8655164131929253426">"On"</string>
+ <string name="off" msgid="875452955155264703">"Off"</string>
+ <string name="selected" msgid="6043586758067023">"Selected"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Not selected"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> per cent."</string>
+ <string name="in_progress" msgid="6827826412747255547">"In progress"</string>
+ <string name="tab" msgid="1672349317127674378">"Tab"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Navigation menu"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Close navigation menu"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Close sheet"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Invalid input"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-en-rXC/strings.xml b/compose/ui/ui/src/androidMain/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..c08a8ca
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-en-rXC/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Neither checked nor unchecked"</string>
+ <string name="on" msgid="8655164131929253426">"On"</string>
+ <string name="off" msgid="875452955155264703">"Off"</string>
+ <string name="selected" msgid="6043586758067023">"Selected"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Not selected"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> percent."</string>
+ <string name="in_progress" msgid="6827826412747255547">"In progress"</string>
+ <string name="tab" msgid="1672349317127674378">"Tab"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Navigation menu"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Close navigation menu"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Close sheet"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Invalid input"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-es-rUS/strings.xml b/compose/ui/ui/src/androidMain/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..878c0d6
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-es-rUS/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Ni marcada ni desmarcada"</string>
+ <string name="on" msgid="8655164131929253426">"Sí"</string>
+ <string name="off" msgid="875452955155264703">"No"</string>
+ <string name="selected" msgid="6043586758067023">"Seleccionado"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Sin seleccionar"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> por ciento."</string>
+ <string name="in_progress" msgid="6827826412747255547">"En curso"</string>
+ <string name="tab" msgid="1672349317127674378">"Pestaña"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Menú de navegación"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Cerrar el menú de navegación"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Cerrar hoja"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Entrada no válida"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-es/strings.xml b/compose/ui/ui/src/androidMain/res/values-es/strings.xml
new file mode 100644
index 0000000..1c59f02
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-es/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Ni marcada ni desmarcada"</string>
+ <string name="on" msgid="8655164131929253426">"Activado"</string>
+ <string name="off" msgid="875452955155264703">"Desactivado"</string>
+ <string name="selected" msgid="6043586758067023">"Seleccionado"</string>
+ <string name="not_selected" msgid="6610465462668679431">"No seleccionado"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> por cien."</string>
+ <string name="in_progress" msgid="6827826412747255547">"En curso"</string>
+ <string name="tab" msgid="1672349317127674378">"Pestaña"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Menú de navegación"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Cerrar menú de navegación"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Cerrar hoja"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Entrada no válida"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-et/strings.xml b/compose/ui/ui/src/androidMain/res/values-et/strings.xml
new file mode 100644
index 0000000..36a1d50
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-et/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Ei märgitud ega märkimata"</string>
+ <string name="on" msgid="8655164131929253426">"Sees"</string>
+ <string name="off" msgid="875452955155264703">"Väljas"</string>
+ <string name="selected" msgid="6043586758067023">"Valitud"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Pole valitud"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> protsenti."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Pooleli"</string>
+ <string name="tab" msgid="1672349317127674378">"Vaheleht"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Navigeerimismenüü"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Sule navigeerimismenüü"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Sule leht"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Sobimatu sisend"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-eu/strings.xml b/compose/ui/ui/src/androidMain/res/values-eu/strings.xml
new file mode 100644
index 0000000..821ca0b
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-eu/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Ez markatuta eta ez markatu gabe"</string>
+ <string name="on" msgid="8655164131929253426">"Aktibatuta"</string>
+ <string name="off" msgid="875452955155264703">"Desaktibatuta"</string>
+ <string name="selected" msgid="6043586758067023">"Hautatuta"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Hautatu gabe"</string>
+ <string name="template_percent" msgid="5946805113151406391">"Ehuneko <xliff:g id="PERCENTAGE">%1$d</xliff:g>."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Abian"</string>
+ <string name="tab" msgid="1672349317127674378">"Fitxa"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Nabigazio-menua"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Itxi nabigazio-menua"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Itxi orria"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Sarrerak ez du balio"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-fa/strings.xml b/compose/ui/ui/src/androidMain/res/values-fa/strings.xml
new file mode 100644
index 0000000..079c362
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-fa/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"نه علامتگذاری شده و نه علامتگذاری آن لغو شده"</string>
+ <string name="on" msgid="8655164131929253426">"روشن"</string>
+ <string name="off" msgid="875452955155264703">"خاموش"</string>
+ <string name="selected" msgid="6043586758067023">"انتخاب شد"</string>
+ <string name="not_selected" msgid="6610465462668679431">"انتخابنشده"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> درصد."</string>
+ <string name="in_progress" msgid="6827826412747255547">"درحال انجام"</string>
+ <string name="tab" msgid="1672349317127674378">"برگه"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"منوی پیمایش"</string>
+ <string name="close_drawer" msgid="406453423630273620">"بستن منوی پیمایش"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"بستن برگ"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"ورودی نامعتبر"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-fi/strings.xml b/compose/ui/ui/src/androidMain/res/values-fi/strings.xml
new file mode 100644
index 0000000..d606a79
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-fi/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Ei valittu eikä valitsematta"</string>
+ <string name="on" msgid="8655164131929253426">"Päällä"</string>
+ <string name="off" msgid="875452955155264703">"Pois"</string>
+ <string name="selected" msgid="6043586758067023">"Valittu"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Ei valittu"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> prosenttia"</string>
+ <string name="in_progress" msgid="6827826412747255547">"Kesken"</string>
+ <string name="tab" msgid="1672349317127674378">"Välilehti"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Navigointivalikko"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Sulje navigointivalikko"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Sulje taulukko"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Virheellinen syöte"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-fr-rCA/strings.xml b/compose/ui/ui/src/androidMain/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..fcd13b9
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-fr-rCA/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Ni cochée ni décochée"</string>
+ <string name="on" msgid="8655164131929253426">"Activé"</string>
+ <string name="off" msgid="875452955155264703">"Désactivé"</string>
+ <string name="selected" msgid="6043586758067023">"Sélectionné"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Non sélectionné"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> pour cent."</string>
+ <string name="in_progress" msgid="6827826412747255547">"En cours…"</string>
+ <string name="tab" msgid="1672349317127674378">"Onglet"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Menu de navigation"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Fermer le menu de navigation"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Fermer la feuille"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Entrée incorrecte"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-fr/strings.xml b/compose/ui/ui/src/androidMain/res/values-fr/strings.xml
new file mode 100644
index 0000000..47a728f
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-fr/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Ni cochée, ni décochée"</string>
+ <string name="on" msgid="8655164131929253426">"Activé"</string>
+ <string name="off" msgid="875452955155264703">"Désactivé"</string>
+ <string name="selected" msgid="6043586758067023">"Sélectionné"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Non sélectionné"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> pour cent."</string>
+ <string name="in_progress" msgid="6827826412747255547">"En cours"</string>
+ <string name="tab" msgid="1672349317127674378">"Onglet"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Menu de navigation"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Fermer le menu de navigation"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Fermer la feuille"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Données incorrectes"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-gl/strings.xml b/compose/ui/ui/src/androidMain/res/values-gl/strings.xml
new file mode 100644
index 0000000..d3505c6
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-gl/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Non marcada nin desmarcada"</string>
+ <string name="on" msgid="8655164131929253426">"Activado"</string>
+ <string name="off" msgid="875452955155264703">"Desactivado"</string>
+ <string name="selected" msgid="6043586758067023">"Seleccionado"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Non seleccionado"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> por cento."</string>
+ <string name="in_progress" msgid="6827826412747255547">"En curso"</string>
+ <string name="tab" msgid="1672349317127674378">"Tabulador"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Menú de navegación"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Pechar menú de navegación"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Pechar folla"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"O texto escrito non é válido"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-hi/strings.xml b/compose/ui/ui/src/androidMain/res/values-hi/strings.xml
new file mode 100644
index 0000000..8562884
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-hi/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"चेकबॉक्स पर न तो सही का निशान लगाया गया, न ही पहले से लगा सही का निशान हटाया गया"</string>
+ <string name="on" msgid="8655164131929253426">"चालू है"</string>
+ <string name="off" msgid="875452955155264703">"बंद है"</string>
+ <string name="selected" msgid="6043586758067023">"चुना गया"</string>
+ <string name="not_selected" msgid="6610465462668679431">"नहीं चुना गया"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> प्रतिशत."</string>
+ <string name="in_progress" msgid="6827826412747255547">"जारी है"</string>
+ <string name="tab" msgid="1672349317127674378">"टैब"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"नेविगेशन मेन्यू"</string>
+ <string name="close_drawer" msgid="406453423630273620">"नेविगेशन मेन्यू बंद करें"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"शीट बंद करें"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"अमान्य इनपुट"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-hr/strings.xml b/compose/ui/ui/src/androidMain/res/values-hr/strings.xml
new file mode 100644
index 0000000..c786212
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-hr/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Nije označeno ni poništeno"</string>
+ <string name="on" msgid="8655164131929253426">"Uključeno"</string>
+ <string name="off" msgid="875452955155264703">"Isključeno"</string>
+ <string name="selected" msgid="6043586758067023">"Odabrano"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Nije odabrano"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> posto."</string>
+ <string name="in_progress" msgid="6827826412747255547">"U tijeku"</string>
+ <string name="tab" msgid="1672349317127674378">"Kartica"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Navigacijski izbornik"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Zatvaranje izbornika za navigaciju"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Zatvaranje lista"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Nevažeći unos"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-hu/strings.xml b/compose/ui/ui/src/androidMain/res/values-hu/strings.xml
new file mode 100644
index 0000000..9bfc7f9
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-hu/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Sem bejelöléssel, sem bejelölés nélkül"</string>
+ <string name="on" msgid="8655164131929253426">"Be"</string>
+ <string name="off" msgid="875452955155264703">"Ki"</string>
+ <string name="selected" msgid="6043586758067023">"Kijelölve"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Nincs kijelölve"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> százalék."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Folyamatban"</string>
+ <string name="tab" msgid="1672349317127674378">"Lap"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Navigációs menü"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Navigációs menü bezárása"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Munkalap bezárása"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Érvénytelen adat"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-in/strings.xml b/compose/ui/ui/src/androidMain/res/values-in/strings.xml
new file mode 100644
index 0000000..4651485
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-in/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Tidak dicentang atau dihapus centangnya"</string>
+ <string name="on" msgid="8655164131929253426">"Aktif"</string>
+ <string name="off" msgid="875452955155264703">"Nonaktif"</string>
+ <string name="selected" msgid="6043586758067023">"Dipilih"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Tidak dipilih"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> persen."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Dalam proses"</string>
+ <string name="tab" msgid="1672349317127674378">"Tab"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Menu navigasi"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Tutup menu navigasi"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Tutup sheet"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Input tidak valid"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-is/strings.xml b/compose/ui/ui/src/androidMain/res/values-is/strings.xml
new file mode 100644
index 0000000..f8ff962
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-is/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Hvorki merkt né afmerkt"</string>
+ <string name="on" msgid="8655164131929253426">"Kveikt"</string>
+ <string name="off" msgid="875452955155264703">"Slökkt"</string>
+ <string name="selected" msgid="6043586758067023">"Valið"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Ekki valið"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> prósent."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Í vinnslu"</string>
+ <string name="tab" msgid="1672349317127674378">"Flipi"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Yfirlitsvalmynd"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Loka yfirlitsvalmynd"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Loka blaði"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Ógildur innsláttur"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-it/strings.xml b/compose/ui/ui/src/androidMain/res/values-it/strings.xml
new file mode 100644
index 0000000..97f5387
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-it/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Casella di controllo né selezionata né deselezionata"</string>
+ <string name="on" msgid="8655164131929253426">"On"</string>
+ <string name="off" msgid="875452955155264703">"Off"</string>
+ <string name="selected" msgid="6043586758067023">"Elemento selezionato"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Opzione non selezionata"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> percento."</string>
+ <string name="in_progress" msgid="6827826412747255547">"In corso"</string>
+ <string name="tab" msgid="1672349317127674378">"Scheda"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Menu di navigazione"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Chiudi il menu di navigazione"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Chiudi il foglio"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Valore non valido"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-ja/strings.xml b/compose/ui/ui/src/androidMain/res/values-ja/strings.xml
new file mode 100644
index 0000000..58574d5
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-ja/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"オンでもオフでもありません"</string>
+ <string name="on" msgid="8655164131929253426">"オン"</string>
+ <string name="off" msgid="875452955155264703">"オフ"</string>
+ <string name="selected" msgid="6043586758067023">"選択済み"</string>
+ <string name="not_selected" msgid="6610465462668679431">"未選択"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>パーセント。"</string>
+ <string name="in_progress" msgid="6827826412747255547">"処理しています"</string>
+ <string name="tab" msgid="1672349317127674378">"タブ"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"ナビゲーションメニュー"</string>
+ <string name="close_drawer" msgid="406453423630273620">"ナビゲーションメニューを閉じる"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"シートを閉じる"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"入力値が無効です"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-ka/strings.xml b/compose/ui/ui/src/androidMain/res/values-ka/strings.xml
new file mode 100644
index 0000000..16f9b79
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-ka/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"არც მონიშნულია და არც მოუნიშნავი"</string>
+ <string name="on" msgid="8655164131929253426">"ჩართული"</string>
+ <string name="off" msgid="875452955155264703">"გამორთული"</string>
+ <string name="selected" msgid="6043586758067023">"არჩეული"</string>
+ <string name="not_selected" msgid="6610465462668679431">"არ არის არჩეული"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> პროცენტი."</string>
+ <string name="in_progress" msgid="6827826412747255547">"მუშავდება"</string>
+ <string name="tab" msgid="1672349317127674378">"ჩანართი"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"ნავიგაციის მენიუ"</string>
+ <string name="close_drawer" msgid="406453423630273620">"ნავიგაციის მენიუს დახურვა"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"ფურცლის დახურვა"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"შენატანი არასწორია"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-kk/strings.xml b/compose/ui/ui/src/androidMain/res/values-kk/strings.xml
new file mode 100644
index 0000000..ceeb61f
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-kk/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Белгіленбеді немесе белгісі алынбады"</string>
+ <string name="on" msgid="8655164131929253426">"Қосулы"</string>
+ <string name="off" msgid="875452955155264703">"Өшірулі"</string>
+ <string name="selected" msgid="6043586758067023">"Таңдалды"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Таңдалмады"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> пайыз."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Орындалуда"</string>
+ <string name="tab" msgid="1672349317127674378">"Қойынды"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Навигация мәзірі"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Навигация мәзірін жабу"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Парақты жабу"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Енгізілген мән жарамсыз."</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-km/strings.xml b/compose/ui/ui/src/androidMain/res/values-km/strings.xml
new file mode 100644
index 0000000..7c77db5
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-km/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"មិនបានធីក ហើយក៏មិនបានដោះធីកដែរ"</string>
+ <string name="on" msgid="8655164131929253426">"បើក"</string>
+ <string name="off" msgid="875452955155264703">"បិទ"</string>
+ <string name="selected" msgid="6043586758067023">"បានជ្រើសរើស"</string>
+ <string name="not_selected" msgid="6610465462668679431">"មិនបានជ្រើសរើស"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> ភាគរយ។"</string>
+ <string name="in_progress" msgid="6827826412747255547">"កំពុងដំណើរការ"</string>
+ <string name="tab" msgid="1672349317127674378">"Tab"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"ម៉ឺនុយរុករក"</string>
+ <string name="close_drawer" msgid="406453423630273620">"បិទម៉ឺនុយរុករក"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"បិទសន្លឹក"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"ការបញ្ចូលមិនត្រឹមត្រូវ"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-ko/strings.xml b/compose/ui/ui/src/androidMain/res/values-ko/strings.xml
new file mode 100644
index 0000000..6a2688a
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-ko/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"선택 또는 선택 해제되지 않음"</string>
+ <string name="on" msgid="8655164131929253426">"켜짐"</string>
+ <string name="off" msgid="875452955155264703">"꺼짐"</string>
+ <string name="selected" msgid="6043586758067023">"선택됨"</string>
+ <string name="not_selected" msgid="6610465462668679431">"선택되지 않음"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>퍼센트"</string>
+ <string name="in_progress" msgid="6827826412747255547">"진행 중"</string>
+ <string name="tab" msgid="1672349317127674378">"탭"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"탐색 메뉴"</string>
+ <string name="close_drawer" msgid="406453423630273620">"탐색 메뉴 닫기"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"시트 닫기"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"입력이 잘못됨"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-ky/strings.xml b/compose/ui/ui/src/androidMain/res/values-ky/strings.xml
new file mode 100644
index 0000000..636d1d3
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-ky/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Белгиленген же белгиленбеген эмес"</string>
+ <string name="on" msgid="8655164131929253426">"Күйүк"</string>
+ <string name="off" msgid="875452955155264703">"Өчүк"</string>
+ <string name="selected" msgid="6043586758067023">"Тандалды"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Тандалган жок"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> пайыз."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Аткарылууда"</string>
+ <string name="tab" msgid="1672349317127674378">"Өтмөк"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Чабыттоо менюсу"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Чабыттоо менюсун жабуу"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Баракты жабуу"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Киргизилген маалымат жараксыз"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-lt/strings.xml b/compose/ui/ui/src/androidMain/res/values-lt/strings.xml
new file mode 100644
index 0000000..9bc393d
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-lt/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Nei pažymėta, nei nepažymėta"</string>
+ <string name="on" msgid="8655164131929253426">"Įjungta"</string>
+ <string name="off" msgid="875452955155264703">"Išjungta"</string>
+ <string name="selected" msgid="6043586758067023">"Pasirinkta"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Nepasirinkta"</string>
+ <string name="template_percent" msgid="5946805113151406391">"Procentų: <xliff:g id="PERCENTAGE">%1$d</xliff:g>."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Vyksta"</string>
+ <string name="tab" msgid="1672349317127674378">"Tabuliavimo klavišas"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Naršymo meniu"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Uždaryti naršymo meniu"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Uždaryti lapą"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Netinkama įvestis"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-lv/strings.xml b/compose/ui/ui/src/androidMain/res/values-lv/strings.xml
new file mode 100644
index 0000000..46a596d
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-lv/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Nav ne atzīmēta, ne neatzīmēta"</string>
+ <string name="on" msgid="8655164131929253426">"Ieslēgts"</string>
+ <string name="off" msgid="875452955155264703">"Izslēgts"</string>
+ <string name="selected" msgid="6043586758067023">"Atlasīts"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Nav atlasīts"</string>
+ <string name="template_percent" msgid="5946805113151406391">"Procenti: <xliff:g id="PERCENTAGE">%1$d</xliff:g>."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Notiek apstrāde"</string>
+ <string name="tab" msgid="1672349317127674378">"Cilne"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Navigācijas izvēlne"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Aizvērt navigācijas izvēlni"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Aizvērt izklājlapu"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Nederīga ievade"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-mk/strings.xml b/compose/ui/ui/src/androidMain/res/values-mk/strings.xml
new file mode 100644
index 0000000..13e7bd1
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-mk/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Ниту штиклирано, ниту отштиклирано"</string>
+ <string name="on" msgid="8655164131929253426">"Вклучено"</string>
+ <string name="off" msgid="875452955155264703">"Исклучено"</string>
+ <string name="selected" msgid="6043586758067023">"Избрано"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Не е избрано"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> проценти."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Во тек"</string>
+ <string name="tab" msgid="1672349317127674378">"Картичка"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Мени за навигација"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Затворете го менито за навигација"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Затворете го листот"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Неважечки запис"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-mn/strings.xml b/compose/ui/ui/src/androidMain/res/values-mn/strings.xml
new file mode 100644
index 0000000..dcc5796
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-mn/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Тэмдэглэсэн, сонголтыг болиулаагүйн аль нь ч биш"</string>
+ <string name="on" msgid="8655164131929253426">"Асаалттай"</string>
+ <string name="off" msgid="875452955155264703">"Унтраалттай"</string>
+ <string name="selected" msgid="6043586758067023">"Сонгосон"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Сонгоогүй"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> хувь."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Үргэлжилж байна"</string>
+ <string name="tab" msgid="1672349317127674378">"Таб"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Навигацын цэс"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Навигацын цэсийг хаах"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Хүснэгтийг хаах"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Буруу оролт"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-ms/strings.xml b/compose/ui/ui/src/androidMain/res/values-ms/strings.xml
new file mode 100644
index 0000000..399fce6
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-ms/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Berkecuali"</string>
+ <string name="on" msgid="8655164131929253426">"Hidup"</string>
+ <string name="off" msgid="875452955155264703">"Mati"</string>
+ <string name="selected" msgid="6043586758067023">"Dipilih"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Tidak dipilih"</string>
+ <string name="template_percent" msgid="5946805113151406391">"Peratus <xliff:g id="PERCENTAGE">%1$d</xliff:g>."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Dalam proses"</string>
+ <string name="tab" msgid="1672349317127674378">"Tab"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Menu navigasi"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Tutup menu navigasi"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Tutup helaian"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Input tidak sah"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-my/strings.xml b/compose/ui/ui/src/androidMain/res/values-my/strings.xml
new file mode 100644
index 0000000..72d22c7
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-my/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"အမှတ်ခြစ်မထားပါ (သို့) အမှတ်ခြစ်ပြီး"</string>
+ <string name="on" msgid="8655164131929253426">"ဖွင့်"</string>
+ <string name="off" msgid="875452955155264703">"ပိတ်"</string>
+ <string name="selected" msgid="6043586758067023">"ရွေးထားသည်"</string>
+ <string name="not_selected" msgid="6610465462668679431">"ရွေးမထားပါ"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> ရာခိုင်နှုန်း။"</string>
+ <string name="in_progress" msgid="6827826412747255547">"ဆောင်ရွက်နေဆဲ"</string>
+ <string name="tab" msgid="1672349317127674378">"တဘ်"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"လမ်းညွှန် မီနူး"</string>
+ <string name="close_drawer" msgid="406453423630273620">"လမ်းညွှန် မီနူး ပိတ်ရန်"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"စာမျက်နှာ ပိတ်ရန်"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"ထည့်သွင်းမှု မမှန်ကန်ပါ"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-nb/strings.xml b/compose/ui/ui/src/androidMain/res/values-nb/strings.xml
new file mode 100644
index 0000000..2b8314b
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-nb/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Verken avmerket eller ikke avmerket"</string>
+ <string name="on" msgid="8655164131929253426">"På"</string>
+ <string name="off" msgid="875452955155264703">"Av"</string>
+ <string name="selected" msgid="6043586758067023">"Valgt"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Ikke valgt"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> prosent."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Pågår"</string>
+ <string name="tab" msgid="1672349317127674378">"Fane"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Navigasjonsmeny"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Lukk navigasjonsmenyen"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Lukk arket"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Ugyldige inndata"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-nl/strings.xml b/compose/ui/ui/src/androidMain/res/values-nl/strings.xml
new file mode 100644
index 0000000..667814b
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-nl/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Niet aangevinkt of uitgevinkt"</string>
+ <string name="on" msgid="8655164131929253426">"Aan"</string>
+ <string name="off" msgid="875452955155264703">"Uit"</string>
+ <string name="selected" msgid="6043586758067023">"Geselecteerd"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Niet geselecteerd"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> procent."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Bezig"</string>
+ <string name="tab" msgid="1672349317127674378">"Tabblad"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Navigatiemenu"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Navigatiemenu sluiten"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Blad sluiten"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Ongeldige invoer"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-pl/strings.xml b/compose/ui/ui/src/androidMain/res/values-pl/strings.xml
new file mode 100644
index 0000000..812531b
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-pl/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Ani nie zaznaczono, ani nie odznaczono"</string>
+ <string name="on" msgid="8655164131929253426">"Włączono"</string>
+ <string name="off" msgid="875452955155264703">"Wyłączono"</string>
+ <string name="selected" msgid="6043586758067023">"Wybrano"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Nie wybrano"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> procent."</string>
+ <string name="in_progress" msgid="6827826412747255547">"W toku"</string>
+ <string name="tab" msgid="1672349317127674378">"Karta"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Menu nawigacyjne"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Zamknij menu nawigacyjne"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Zamknij arkusz"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Nieprawidłowe dane wejściowe"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-pt-rBR/strings.xml b/compose/ui/ui/src/androidMain/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..d687d4b
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-pt-rBR/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Nem marcada nem desmarcada"</string>
+ <string name="on" msgid="8655164131929253426">"Ativado"</string>
+ <string name="off" msgid="875452955155264703">"Desativado"</string>
+ <string name="selected" msgid="6043586758067023">"Selecionado"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Não selecionado"</string>
+ <!-- String.format failed for translation -->
+ <!-- no translation found for template_percent (5946805113151406391) -->
+ <skip />
+ <string name="in_progress" msgid="6827826412747255547">"Em andamento"</string>
+ <string name="tab" msgid="1672349317127674378">"Guia"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Menu de navegação"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Fechar menu de navegação"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Fechar planilha"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Entrada inválida"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-pt-rPT/strings.xml b/compose/ui/ui/src/androidMain/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..b7fb8a6
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-pt-rPT/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Nem selecionada nem desselecionada"</string>
+ <string name="on" msgid="8655164131929253426">"Ativado"</string>
+ <string name="off" msgid="875452955155264703">"Desativado"</string>
+ <string name="selected" msgid="6043586758067023">"Selecionado"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Não selecionado"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> por cento."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Em curso"</string>
+ <string name="tab" msgid="1672349317127674378">"Separador"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Menu de navegação"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Fechar menu de navegação"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Fechar folha"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Entrada inválida"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-pt/strings.xml b/compose/ui/ui/src/androidMain/res/values-pt/strings.xml
new file mode 100644
index 0000000..d687d4b
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-pt/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Nem marcada nem desmarcada"</string>
+ <string name="on" msgid="8655164131929253426">"Ativado"</string>
+ <string name="off" msgid="875452955155264703">"Desativado"</string>
+ <string name="selected" msgid="6043586758067023">"Selecionado"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Não selecionado"</string>
+ <!-- String.format failed for translation -->
+ <!-- no translation found for template_percent (5946805113151406391) -->
+ <skip />
+ <string name="in_progress" msgid="6827826412747255547">"Em andamento"</string>
+ <string name="tab" msgid="1672349317127674378">"Guia"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Menu de navegação"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Fechar menu de navegação"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Fechar planilha"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Entrada inválida"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-ro/strings.xml b/compose/ui/ui/src/androidMain/res/values-ro/strings.xml
new file mode 100644
index 0000000..ad20c72
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-ro/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Nici bifată, nici debifată"</string>
+ <string name="on" msgid="8655164131929253426">"Activat"</string>
+ <string name="off" msgid="875452955155264703">"Dezactivat"</string>
+ <string name="selected" msgid="6043586758067023">"Selectat"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Neselectat"</string>
+ <!-- String.format failed for translation -->
+ <!-- no translation found for template_percent (5946805113151406391) -->
+ <skip />
+ <string name="in_progress" msgid="6827826412747255547">"În curs"</string>
+ <string name="tab" msgid="1672349317127674378">"Filă"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Meniu de navigare"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Închideți meniul de navigare"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Închideți foaia"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Intrare nevalidă"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-ru/strings.xml b/compose/ui/ui/src/androidMain/res/values-ru/strings.xml
new file mode 100644
index 0000000..65c7bfe
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-ru/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Флажок не установлен и не снят"</string>
+ <string name="on" msgid="8655164131929253426">"Включено"</string>
+ <string name="off" msgid="875452955155264703">"Выключено"</string>
+ <string name="selected" msgid="6043586758067023">"Выбрано"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Не выбрано"</string>
+ <string name="template_percent" msgid="5946805113151406391">"Процентов: <xliff:g id="PERCENTAGE">%1$d</xliff:g>."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Выполняется"</string>
+ <string name="tab" msgid="1672349317127674378">"Вкладка"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Меню навигации"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Закрыть меню навигации"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Закрыть лист"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Неправильный ввод"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-si/strings.xml b/compose/ui/ui/src/androidMain/res/values-si/strings.xml
new file mode 100644
index 0000000..1d0294a
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-si/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"හරි ලකුණු යොදා හෝ හරි ලකුණු යෙදීම ඉවත් කර නැත"</string>
+ <string name="on" msgid="8655164131929253426">"ක්රියාත්මකයි"</string>
+ <string name="off" msgid="875452955155264703">"ක්රියාවිරහිතයි"</string>
+ <string name="selected" msgid="6043586758067023">"තෝරන ලදි"</string>
+ <string name="not_selected" msgid="6610465462668679431">"තෝරා නැත"</string>
+ <string name="template_percent" msgid="5946805113151406391">"සියයට <xliff:g id="PERCENTAGE">%1$d</xliff:g>."</string>
+ <string name="in_progress" msgid="6827826412747255547">"ප්රගතියේ පවතී"</string>
+ <string name="tab" msgid="1672349317127674378">"ටැබය"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"සංචාලන මෙනුව"</string>
+ <string name="close_drawer" msgid="406453423630273620">"සංචාලන මෙනුව වසන්න"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"පත්රය වසන්න"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"වලංගු නොවන ආදානයකි"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-sk/strings.xml b/compose/ui/ui/src/androidMain/res/values-sk/strings.xml
new file mode 100644
index 0000000..b912997
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-sk/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Ani začiarknuté ani nezačiarknuté"</string>
+ <string name="on" msgid="8655164131929253426">"Zapnuté"</string>
+ <string name="off" msgid="875452955155264703">"Vypnuté"</string>
+ <string name="selected" msgid="6043586758067023">"Vybrané"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Nevybrané"</string>
+ <!-- String.format failed for translation -->
+ <!-- no translation found for template_percent (5946805113151406391) -->
+ <skip />
+ <string name="in_progress" msgid="6827826412747255547">"Prebieha"</string>
+ <string name="tab" msgid="1672349317127674378">"Karta"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Navigačná ponuka"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Zavrieť navigačnú ponuku"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Zavrieť hárok"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Neplatný vstup"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-sl/strings.xml b/compose/ui/ui/src/androidMain/res/values-sl/strings.xml
new file mode 100644
index 0000000..e30acad
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-sl/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Niti potrjeno niti nepotrjeno"</string>
+ <string name="on" msgid="8655164131929253426">"Vklopljeno"</string>
+ <string name="off" msgid="875452955155264703">"Izklopljeno"</string>
+ <string name="selected" msgid="6043586758067023">"Izbrano"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Ni izbrano"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> odstotkov"</string>
+ <string name="in_progress" msgid="6827826412747255547">"Poteka"</string>
+ <string name="tab" msgid="1672349317127674378">"Zavihek"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Meni za krmarjenje"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Zapri meni za krmarjenje"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Zapri list"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Neveljaven vnos"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-sr/strings.xml b/compose/ui/ui/src/androidMain/res/values-sr/strings.xml
new file mode 100644
index 0000000..485493f
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-sr/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Није означено нити поништено"</string>
+ <string name="on" msgid="8655164131929253426">"Укључено"</string>
+ <string name="off" msgid="875452955155264703">"Искључено"</string>
+ <string name="selected" msgid="6043586758067023">"Изабрано"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Није изабрано"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> посто."</string>
+ <string name="in_progress" msgid="6827826412747255547">"У току"</string>
+ <string name="tab" msgid="1672349317127674378">"Картица"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Мени за навигацију"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Затвори мени за навигацију"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Затворите табелу"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Унос је неважећи"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-sv/strings.xml b/compose/ui/ui/src/androidMain/res/values-sv/strings.xml
new file mode 100644
index 0000000..bb491c8
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-sv/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Varken markerad eller avmarkerad"</string>
+ <string name="on" msgid="8655164131929253426">"På"</string>
+ <string name="off" msgid="875452955155264703">"Av"</string>
+ <string name="selected" msgid="6043586758067023">"Valt"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Inte vald"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> procent."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Pågår"</string>
+ <string name="tab" msgid="1672349317127674378">"Flik"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Navigeringsmeny"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Stäng navigeringsmenyn"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Stäng kalkylarket"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Ogiltiga indata"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-sw/strings.xml b/compose/ui/ui/src/androidMain/res/values-sw/strings.xml
new file mode 100644
index 0000000..1f8eec8
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-sw/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Hujateua wala kubatilisha uteuzi"</string>
+ <string name="on" msgid="8655164131929253426">"Imewashwa"</string>
+ <string name="off" msgid="875452955155264703">"Imezimwa"</string>
+ <string name="selected" msgid="6043586758067023">"Umechagua"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Hujachagua"</string>
+ <string name="template_percent" msgid="5946805113151406391">"Asilimia <xliff:g id="PERCENTAGE">%1$d</xliff:g>."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Inaendelea"</string>
+ <string name="tab" msgid="1672349317127674378">"Kichupo"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Menyu ya kusogeza"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Funga menyu ya kusogeza"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Funga laha"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Ulichoweka si sahihi"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-ta/strings.xml b/compose/ui/ui/src/androidMain/res/values-ta/strings.xml
new file mode 100644
index 0000000..ed3b4a2
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-ta/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"தேர்வுசெய்யப்பட்டது மற்றும் தேர்வுசெய்யப்படாதது"</string>
+ <string name="on" msgid="8655164131929253426">"இயக்கப்பட்டுள்ளது"</string>
+ <string name="off" msgid="875452955155264703">"முடக்கப்பட்டுள்ளது"</string>
+ <string name="selected" msgid="6043586758067023">"தேர்ந்தெடுக்கப்பட்டுள்ளது"</string>
+ <string name="not_selected" msgid="6610465462668679431">"தேர்ந்தெடுக்கப்படவில்லை"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> சதவீதம்."</string>
+ <string name="in_progress" msgid="6827826412747255547">"செயலிலுள்ளது"</string>
+ <string name="tab" msgid="1672349317127674378">"பிரிவு"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"வழிசெலுத்தல் மெனு"</string>
+ <string name="close_drawer" msgid="406453423630273620">"வழிசெலுத்தல் மெனுவை மூடும்"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"ஷீட்டை மூடும்"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"தவறான உள்ளீடு"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-th/strings.xml b/compose/ui/ui/src/androidMain/res/values-th/strings.xml
new file mode 100644
index 0000000..43a3761
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-th/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"ไม่ได้เลือกหรือยกเลิกการเลือก"</string>
+ <string name="on" msgid="8655164131929253426">"เปิด"</string>
+ <string name="off" msgid="875452955155264703">"ปิด"</string>
+ <string name="selected" msgid="6043586758067023">"เลือกไว้"</string>
+ <string name="not_selected" msgid="6610465462668679431">"ไม่ได้เลือก"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> เปอร์เซ็นต์"</string>
+ <string name="in_progress" msgid="6827826412747255547">"กำลังดำเนินการ"</string>
+ <string name="tab" msgid="1672349317127674378">"แท็บ"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"เมนูการนำทาง"</string>
+ <string name="close_drawer" msgid="406453423630273620">"ปิดเมนูการนำทาง"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"ปิดชีต"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"อินพุตไม่ถูกต้อง"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-tl/strings.xml b/compose/ui/ui/src/androidMain/res/values-tl/strings.xml
new file mode 100644
index 0000000..f0700fb
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-tl/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Hindi may check o walang check"</string>
+ <string name="on" msgid="8655164131929253426">"Naka-on"</string>
+ <string name="off" msgid="875452955155264703">"Naka-off"</string>
+ <string name="selected" msgid="6043586758067023">"Napili"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Hindi napili"</string>
+ <string name="template_percent" msgid="5946805113151406391">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> (na) porsyento."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Isinasagawa"</string>
+ <string name="tab" msgid="1672349317127674378">"Tab"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Menu ng navigation"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Isara ang menu ng navigation"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Isara ang sheet"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Invalid na input"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-tr/strings.xml b/compose/ui/ui/src/androidMain/res/values-tr/strings.xml
new file mode 100644
index 0000000..edb132d
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-tr/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Ne işaretlendi ne de işareti kaldırıldı"</string>
+ <string name="on" msgid="8655164131929253426">"Açık"</string>
+ <string name="off" msgid="875452955155264703">"Kapalı"</string>
+ <string name="selected" msgid="6043586758067023">"Seçili"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Seçilmedi"</string>
+ <string name="template_percent" msgid="5946805113151406391">"Yüzde <xliff:g id="PERCENTAGE">%1$d</xliff:g>."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Devam ediyor"</string>
+ <string name="tab" msgid="1672349317127674378">"Sekme"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Gezinme menüsü"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Gezinme menüsünü kapat"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Sayfayı kapat"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Geçersiz giriş"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-uk/strings.xml b/compose/ui/ui/src/androidMain/res/values-uk/strings.xml
new file mode 100644
index 0000000..1e73c6e
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-uk/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Прапорець ані поставлено, ані знято"</string>
+ <string name="on" msgid="8655164131929253426">"Увімкнено"</string>
+ <string name="off" msgid="875452955155264703">"Вимкнено"</string>
+ <string name="selected" msgid="6043586758067023">"Вибрано"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Не вибрано"</string>
+ <string name="template_percent" msgid="5946805113151406391">"Відсотків: <xliff:g id="PERCENTAGE">%1$d</xliff:g>."</string>
+ <string name="in_progress" msgid="6827826412747255547">"Виконується"</string>
+ <string name="tab" msgid="1672349317127674378">"Вкладка"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Меню навігації"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Закрити меню навігації"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Закрити аркуш"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Введено недійсні дані"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-vi/strings.xml b/compose/ui/ui/src/androidMain/res/values-vi/strings.xml
new file mode 100644
index 0000000..5dd316f
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-vi/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"Không đánh dấu cũng không bỏ đánh dấu"</string>
+ <string name="on" msgid="8655164131929253426">"Đang bật"</string>
+ <string name="off" msgid="875452955155264703">"Đang tắt"</string>
+ <string name="selected" msgid="6043586758067023">"Đã chọn"</string>
+ <string name="not_selected" msgid="6610465462668679431">"Chưa chọn"</string>
+ <!-- String.format failed for translation -->
+ <!-- no translation found for template_percent (5946805113151406391) -->
+ <skip />
+ <string name="in_progress" msgid="6827826412747255547">"Đang thực hiện"</string>
+ <string name="tab" msgid="1672349317127674378">"Thẻ"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"Trình đơn điều hướng"</string>
+ <string name="close_drawer" msgid="406453423630273620">"Đóng trình đơn điều hướng"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"Đóng trang tính"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"Giá trị nhập không hợp lệ"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-zh-rCN/strings.xml b/compose/ui/ui/src/androidMain/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..6392b8b
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-zh-rCN/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"既没有勾选也没有取消选中"</string>
+ <string name="on" msgid="8655164131929253426">"开启"</string>
+ <string name="off" msgid="875452955155264703">"关闭"</string>
+ <string name="selected" msgid="6043586758067023">"已选择"</string>
+ <string name="not_selected" msgid="6610465462668679431">"未选择"</string>
+ <string name="template_percent" msgid="5946805113151406391">"百分之 <xliff:g id="PERCENTAGE">%1$d</xliff:g>。"</string>
+ <string name="in_progress" msgid="6827826412747255547">"进行中"</string>
+ <string name="tab" msgid="1672349317127674378">"标签页"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"导航菜单"</string>
+ <string name="close_drawer" msgid="406453423630273620">"关闭导航菜单"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"关闭工作表"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"输入无效"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-zh-rHK/strings.xml b/compose/ui/ui/src/androidMain/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..5b4e62b
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-zh-rHK/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"未勾選或者未取消勾選"</string>
+ <string name="on" msgid="8655164131929253426">"開"</string>
+ <string name="off" msgid="875452955155264703">"閂"</string>
+ <string name="selected" msgid="6043586758067023">"揀咗"</string>
+ <string name="not_selected" msgid="6610465462668679431">"未揀"</string>
+ <string name="template_percent" msgid="5946805113151406391">"百分之 <xliff:g id="PERCENTAGE">%1$d</xliff:g>。"</string>
+ <string name="in_progress" msgid="6827826412747255547">"進行中"</string>
+ <string name="tab" msgid="1672349317127674378">"分頁"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"導覽選單"</string>
+ <string name="close_drawer" msgid="406453423630273620">"閂導覽選單"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"閂表單"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"輸入嘅資料無效"</string>
+</resources>
diff --git a/compose/ui/ui/src/androidMain/res/values-zh-rTW/strings.xml b/compose/ui/ui/src/androidMain/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..8f47f69
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/res/values-zh-rTW/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="indeterminate" msgid="2486394087603402002">"沒有勾選也沒有取消勾選"</string>
+ <string name="on" msgid="8655164131929253426">"已開啟"</string>
+ <string name="off" msgid="875452955155264703">"已關閉"</string>
+ <string name="selected" msgid="6043586758067023">"已選取"</string>
+ <string name="not_selected" msgid="6610465462668679431">"未選取"</string>
+ <string name="template_percent" msgid="5946805113151406391">"百分之 <xliff:g id="PERCENTAGE">%1$d</xliff:g>。"</string>
+ <string name="in_progress" msgid="6827826412747255547">"處理中"</string>
+ <string name="tab" msgid="1672349317127674378">"Tab 鍵"</string>
+ <string name="navigation_menu" msgid="542007171693138492">"導覽選單"</string>
+ <string name="close_drawer" msgid="406453423630273620">"關閉導覽選單"</string>
+ <string name="close_sheet" msgid="7573152094250666567">"關閉功能表"</string>
+ <string name="default_error_message" msgid="8038256446254964252">"輸入內容無效"</string>
+</resources>
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 53cccdb..d8909b8 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
@@ -230,6 +230,8 @@
private val DownChangeConsumed = ConsumedData(downChange = true)
+private val EmptyPointerEvent = PointerEvent(emptyList())
+
/**
* Implementation notes:
* This class does a lot of lifting. It is both a [PointerInputModifier] and that modifier's
@@ -256,7 +258,7 @@
override val pointerInputFilter: PointerInputFilter
get() = this
- private var currentEvent: PointerEvent? = null
+ private var currentEvent: PointerEvent = EmptyPointerEvent
/**
* Actively registered input handlers from currently ongoing calls to [awaitPointerEventScope].
@@ -416,9 +418,7 @@
private var awaitPass: PointerEventPass = PointerEventPass.Main
override val currentEvent: PointerEvent
- get() = checkNotNull(this@SuspendingPointerInputFilter.currentEvent) {
- "cannot access currentEvent outside of input dispatch"
- }
+ get() = this@SuspendingPointerInputFilter.currentEvent
override val size: IntSize
get() = this@SuspendingPointerInputFilter.boundsSize
override val viewConfiguration: ViewConfiguration
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/SaveRestoreBackStackTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/SaveRestoreBackStackTest.kt
index 42ad4dc..f14d650 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/SaveRestoreBackStackTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/SaveRestoreBackStackTest.kt
@@ -16,12 +16,9 @@
package androidx.fragment.app
-import android.os.Bundle
import androidx.fragment.app.test.FragmentTestActivity
-import androidx.fragment.app.test.TestViewModel
import androidx.fragment.test.R
import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.ViewModelProvider
import androidx.test.core.app.ActivityScenario
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
@@ -43,7 +40,7 @@
supportFragmentManager
}
val fragmentBase = StrictFragment()
- val fragmentReplacement = ViewModelStrictFragment()
+ val fragmentReplacement = StateSaveFragment()
fm.beginTransaction()
.add(R.id.content, fragmentBase)
@@ -433,32 +430,4 @@
assertThat(fm.backStackEntryCount).isEqualTo(1)
}
}
-
- public open class ViewModelStrictFragment : StrictFragment() {
- public val viewModel: TestViewModel by lazy {
- ViewModelProvider(this).get(TestViewModel::class.java)
- }
- }
-
- public class StateSaveFragment(
- public var savedState: String? = null,
- public val unsavedState: String? = null
- ) : ViewModelStrictFragment() {
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- if (savedInstanceState != null) {
- savedState = savedInstanceState.getString(STATE_KEY)
- }
- }
-
- override fun onSaveInstanceState(outState: Bundle) {
- super.onSaveInstanceState(outState)
- outState.putString(STATE_KEY, savedState)
- }
-
- private companion object {
- private const val STATE_KEY = "state"
- }
- }
}
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/test/StateSaveFragment.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/test/StateSaveFragment.kt
index 0ab9d0d..1edd340 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/test/StateSaveFragment.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/test/StateSaveFragment.kt
@@ -17,6 +17,8 @@
package androidx.fragment.app
import android.os.Bundle
+import androidx.fragment.app.test.TestViewModel
+import androidx.lifecycle.ViewModelProvider
class StateSaveFragment(
var savedState: String? = null,
@@ -40,6 +42,10 @@
outState.putString(STATE_KEY, savedState)
}
+ public val viewModel: TestViewModel by lazy {
+ ViewModelProvider(this).get(TestViewModel::class.java)
+ }
+
companion object {
private const val STATE_KEY = "state"
}
diff --git a/leanback/leanback/src/main/res/values-bs/strings.xml b/leanback/leanback/src/main/res/values-bs/strings.xml
index 68aa6f3..0421ed7 100644
--- a/leanback/leanback/src/main/res/values-bs/strings.xml
+++ b/leanback/leanback/src/main/res/values-bs/strings.xml
@@ -47,7 +47,7 @@
<string name="lb_playback_controls_high_quality_disable" msgid="1209119371486219736">"Isključi visoki kvalitet"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2346334170216706076">"Uključi titlove"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="8691966842977635128">"Isključi titlove"</string>
- <string name="lb_playback_controls_picture_in_picture" msgid="5770668162543767702">"Uđi u način rada Slika u slici"</string>
+ <string name="lb_playback_controls_picture_in_picture" msgid="5770668162543767702">"Uđi u način rada slike u slici"</string>
<string name="lb_playback_time_separator" msgid="1471121602610716654">"/"</string>
<string name="lb_playback_controls_shown" msgid="8690223891515602822">"Kontrole za medije su prikazane"</string>
<string name="lb_playback_controls_hidden" msgid="5859666950961624736">"Kontrole za medije su skrivene. Pritisnite d-pad da ih prikažete"</string>
diff --git a/leanback/leanback/src/main/res/values-ky/strings.xml b/leanback/leanback/src/main/res/values-ky/strings.xml
index 3eee16b..4d12f12 100644
--- a/leanback/leanback/src/main/res/values-ky/strings.xml
+++ b/leanback/leanback/src/main/res/values-ky/strings.xml
@@ -50,7 +50,7 @@
<string name="lb_playback_controls_picture_in_picture" msgid="5770668162543767702">"Сүрөт режиминде сүрөт киргизүү"</string>
<string name="lb_playback_time_separator" msgid="1471121602610716654">"/"</string>
<string name="lb_playback_controls_shown" msgid="8690223891515602822">"Медиа файлды башкаруу көрсөтүлдү"</string>
- <string name="lb_playback_controls_hidden" msgid="5859666950961624736">"Медиа файлды башкаруу жашырылган, көрүү үчүн d-pad көзөмөлдөө каражатын басыңыз"</string>
+ <string name="lb_playback_controls_hidden" msgid="5859666950961624736">"Медиа файлды башкаруу жашырылган, көрүү үчүн d-pad башкаруу элементин басыңыз"</string>
<string name="lb_guidedaction_finish_title" msgid="3330958750346333890">"Бүттү"</string>
<string name="lb_guidedaction_continue_title" msgid="893619591225519922">"Улантуу"</string>
<string name="lb_media_player_error" msgid="3228326776757666747">"MediaPlayer\'деги катанын коду: %1$d, кошумча: %2$d"</string>
diff --git a/lint-checks/src/test/java/androidx/build/lint/ClassVerificationFailureDetectorTest.kt b/lint-checks/src/test/java/androidx/build/lint/ClassVerificationFailureDetectorTest.kt
index 8360616..f3dfe69 100644
--- a/lint-checks/src/test/java/androidx/build/lint/ClassVerificationFailureDetectorTest.kt
+++ b/lint-checks/src/test/java/androidx/build/lint/ClassVerificationFailureDetectorTest.kt
@@ -18,7 +18,6 @@
package androidx.build.lint
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -34,7 +33,6 @@
) {
@Test
- @Ignore("b/190726182")
fun `Detection of unsafe references in Java sources`() {
val input = arrayOf(
javaSample("androidx.ClassVerificationFailureFromJava"),
diff --git a/navigation/navigation-common/src/androidTest/java/androidx/navigation/AddInDefaultArgsTest.kt b/navigation/navigation-common/src/androidTest/java/androidx/navigation/AddInDefaultArgsTest.kt
index 78d1f94..6cd431e 100644
--- a/navigation/navigation-common/src/androidTest/java/androidx/navigation/AddInDefaultArgsTest.kt
+++ b/navigation/navigation-common/src/androidTest/java/androidx/navigation/AddInDefaultArgsTest.kt
@@ -22,6 +22,7 @@
import androidx.navigation.test.longArgument
import androidx.navigation.test.referenceArgument
import androidx.navigation.test.stringArgument
+import androidx.navigation.test.stringArrayArgument
import androidx.test.filters.SmallTest
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
@@ -35,6 +36,7 @@
private val longArgumentWithDefault = "longArg" to longArgument(123L)
private val floatArgumentWithDefault = "floatArg" to floatArgument(123f)
private val referenceArgumentWithDefault = "referenceArg" to referenceArgument(123)
+private val stringArrayArgumentWithDefault = "stringArrayArg" to stringArrayArgument(null)
@SmallTest
@RunWith(Parameterized::class)
@@ -60,7 +62,9 @@
// Test with arguments that have default values (long)
mapOf(stringArgumentWithDefault, floatArgumentWithDefault),
// Test with arguments that have default values (reference)
- mapOf(stringArgumentWithDefault, referenceArgumentWithDefault)
+ mapOf(stringArgumentWithDefault, referenceArgumentWithDefault),
+ // Test with arguments that have default values (string array)
+ mapOf(stringArgumentWithDefault, stringArrayArgumentWithDefault)
).forEach { arguments: Map<String, NavArgument> ->
// Run with a null Bundle
diff --git a/navigation/navigation-common/src/androidTest/java/androidx/navigation/test/NavArgument.kt b/navigation/navigation-common/src/androidTest/java/androidx/navigation/test/NavArgument.kt
index 71a36750..760817c 100644
--- a/navigation/navigation-common/src/androidTest/java/androidx/navigation/test/NavArgument.kt
+++ b/navigation/navigation-common/src/androidTest/java/androidx/navigation/test/NavArgument.kt
@@ -21,6 +21,7 @@
import androidx.navigation.NavType.Companion.IntType
import androidx.navigation.NavType.Companion.LongType
import androidx.navigation.NavType.Companion.ReferenceType
+import androidx.navigation.NavType.Companion.StringArrayType
import androidx.navigation.NavType.Companion.StringType
// region IntType
@@ -80,3 +81,12 @@
.setIsNullable(true)
.build()
// endregion
+
+// region StringArrayType
+fun stringArrayArgument(
+ defaultValue: Array<String>?
+) = NavArgument.Builder().setType(StringArrayType)
+ .setIsNullable(true)
+ .setDefaultValue(defaultValue)
+ .build()
+// endregion
\ No newline at end of file
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 401f880..48618f9 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavType.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavType.kt
@@ -527,20 +527,22 @@
* Default values in Navigation XML files are not supported.
*/
@JvmField
- public val StringArrayType: NavType<Array<String>> = object : NavType<Array<String>>(true) {
+ public val StringArrayType: NavType<Array<String>?> = object : NavType<Array<String>?>(
+ true
+ ) {
override val name: String
get() = "string[]"
- override fun put(bundle: Bundle, key: String, value: Array<String>) {
+ override fun put(bundle: Bundle, key: String, value: Array<String>?) {
bundle.putStringArray(key, value)
}
@Suppress("UNCHECKED_CAST")
- override fun get(bundle: Bundle, key: String): Array<String> {
- return bundle[key] as Array<String>
+ override fun get(bundle: Bundle, key: String): Array<String>? {
+ return bundle[key] as Array<String>?
}
- override fun parseValue(value: String): Array<String> {
+ override fun parseValue(value: String): Array<String>? {
throw UnsupportedOperationException("Arrays don't support default values.")
}
}
diff --git a/navigation/navigation-dynamic-features-runtime/api/current.ignore b/navigation/navigation-dynamic-features-runtime/api/current.ignore
index fdf7759..2d8ef14 100644
--- a/navigation/navigation-dynamic-features-runtime/api/current.ignore
+++ b/navigation/navigation-dynamic-features-runtime/api/current.ignore
@@ -1,5 +1,7 @@
// Baseline format: 1.0
RemovedMethod: androidx.navigation.dynamicfeatures.DynamicExtras#DynamicExtras():
Removed constructor androidx.navigation.dynamicfeatures.DynamicExtras()
+RemovedMethod: androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator#navigate(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph, android.os.Bundle, androidx.navigation.NavOptions, androidx.navigation.Navigator.Extras):
+ Removed method androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.navigate(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph,android.os.Bundle,androidx.navigation.NavOptions,androidx.navigation.Navigator.Extras)
RemovedMethod: androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator#popBackStack():
Removed method androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.popBackStack()
diff --git a/navigation/navigation-dynamic-features-runtime/api/current.txt b/navigation/navigation-dynamic-features-runtime/api/current.txt
index 6d9572f..85b8d16 100644
--- a/navigation/navigation-dynamic-features-runtime/api/current.txt
+++ b/navigation/navigation-dynamic-features-runtime/api/current.txt
@@ -71,7 +71,6 @@
@androidx.navigation.Navigator.Name("include-dynamic") public final class DynamicIncludeGraphNavigator extends androidx.navigation.Navigator<androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph> {
ctor public DynamicIncludeGraphNavigator(android.content.Context context, androidx.navigation.NavigatorProvider navigatorProvider, androidx.navigation.NavInflater navInflater, androidx.navigation.dynamicfeatures.DynamicInstallManager installManager);
method public androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph createDestination();
- method @Deprecated public androidx.navigation.NavDestination? navigate(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph destination, android.os.Bundle? args, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
}
public static final class DynamicIncludeGraphNavigator.DynamicIncludeNavGraph extends androidx.navigation.NavDestination {
diff --git a/navigation/navigation-dynamic-features-runtime/api/public_plus_experimental_current.txt b/navigation/navigation-dynamic-features-runtime/api/public_plus_experimental_current.txt
index 6d9572f..85b8d16 100644
--- a/navigation/navigation-dynamic-features-runtime/api/public_plus_experimental_current.txt
+++ b/navigation/navigation-dynamic-features-runtime/api/public_plus_experimental_current.txt
@@ -71,7 +71,6 @@
@androidx.navigation.Navigator.Name("include-dynamic") public final class DynamicIncludeGraphNavigator extends androidx.navigation.Navigator<androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph> {
ctor public DynamicIncludeGraphNavigator(android.content.Context context, androidx.navigation.NavigatorProvider navigatorProvider, androidx.navigation.NavInflater navInflater, androidx.navigation.dynamicfeatures.DynamicInstallManager installManager);
method public androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph createDestination();
- method @Deprecated public androidx.navigation.NavDestination? navigate(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph destination, android.os.Bundle? args, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
}
public static final class DynamicIncludeGraphNavigator.DynamicIncludeNavGraph extends androidx.navigation.NavDestination {
diff --git a/navigation/navigation-dynamic-features-runtime/api/restricted_current.ignore b/navigation/navigation-dynamic-features-runtime/api/restricted_current.ignore
index fdf7759..2d8ef14 100644
--- a/navigation/navigation-dynamic-features-runtime/api/restricted_current.ignore
+++ b/navigation/navigation-dynamic-features-runtime/api/restricted_current.ignore
@@ -1,5 +1,7 @@
// Baseline format: 1.0
RemovedMethod: androidx.navigation.dynamicfeatures.DynamicExtras#DynamicExtras():
Removed constructor androidx.navigation.dynamicfeatures.DynamicExtras()
+RemovedMethod: androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator#navigate(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph, android.os.Bundle, androidx.navigation.NavOptions, androidx.navigation.Navigator.Extras):
+ Removed method androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.navigate(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph,android.os.Bundle,androidx.navigation.NavOptions,androidx.navigation.Navigator.Extras)
RemovedMethod: androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator#popBackStack():
Removed method androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.popBackStack()
diff --git a/navigation/navigation-dynamic-features-runtime/api/restricted_current.txt b/navigation/navigation-dynamic-features-runtime/api/restricted_current.txt
index 6d9572f..85b8d16 100644
--- a/navigation/navigation-dynamic-features-runtime/api/restricted_current.txt
+++ b/navigation/navigation-dynamic-features-runtime/api/restricted_current.txt
@@ -71,7 +71,6 @@
@androidx.navigation.Navigator.Name("include-dynamic") public final class DynamicIncludeGraphNavigator extends androidx.navigation.Navigator<androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph> {
ctor public DynamicIncludeGraphNavigator(android.content.Context context, androidx.navigation.NavigatorProvider navigatorProvider, androidx.navigation.NavInflater navInflater, androidx.navigation.dynamicfeatures.DynamicInstallManager installManager);
method public androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph createDestination();
- method @Deprecated public androidx.navigation.NavDestination? navigate(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph destination, android.os.Bundle? args, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
}
public static final class DynamicIncludeGraphNavigator.DynamicIncludeNavGraph extends androidx.navigation.NavDestination {
diff --git a/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicIncludeGraphNavigator.kt b/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicIncludeGraphNavigator.kt
index a8a9a22..8db61ba 100644
--- a/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicIncludeGraphNavigator.kt
+++ b/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicIncludeGraphNavigator.kt
@@ -24,6 +24,7 @@
import androidx.core.content.withStyledAttributes
import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavDestination
+import androidx.navigation.NavGraph
import androidx.navigation.NavInflater
import androidx.navigation.NavInflater.Companion.APPLICATION_ID_PLACEHOLDER
import androidx.navigation.NavOptions
@@ -59,9 +60,17 @@
}
/**
+ * Navigates to a dynamically included graph from a `com.android.dynamic-feature` module.
+ *
+ * @param entries destination(s) to navigate to
+ * @param navOptions additional options for navigation
+ * @param navigatorExtras extras unique to your Navigator.
+ *
* @throws Resources.NotFoundException if one of the [entries] does not have a valid
* `graphResourceName` and `graphPackage`.
* @throws IllegalStateException if one of the [entries] does not have a parent.
+
+ * @see Navigator.navigate
*/
override fun navigate(
entries: List<NavBackStackEntry>,
@@ -74,23 +83,6 @@
}
/**
- * @throws Resources.NotFoundException if the [destination] does not have a valid
- * `graphResourceName` and `graphPackage`.
- * @throws IllegalStateException if the [destination] does not have a parent.
- */
- @Deprecated("Use NavBackStackEntry version of this method instead")
- override fun navigate(
- destination: DynamicIncludeNavGraph,
- args: Bundle?,
- navOptions: NavOptions?,
- navigatorExtras: Extras?
- ): NavDestination? {
- val entry = NavBackStackEntry.create(null, destination, args)
- navigate(entry, navOptions, navigatorExtras)
- return null
- }
-
- /**
* @throws Resources.NotFoundException if the [entry] does not have a valid
* `graphResourceName` and `graphPackage`.
* @throws IllegalStateException if the [entry] does not have a parent.
@@ -109,10 +101,9 @@
installManager.performInstall(entry, extras, moduleName)
} else {
val includedNav = replaceWithIncludedNav(destination)
- val navigator: Navigator<NavDestination> = navigatorProvider[
- includedNav.destination.navigatorName
- ]
- navigator.navigate(listOf(includedNav), navOptions, navigatorExtras)
+ val navigator: Navigator<NavDestination> = navigatorProvider[includedNav.navigatorName]
+ val newGraphEntry = state.createBackStackEntry(includedNav, entry.arguments)
+ navigator.navigate(listOf(newGraphEntry), navOptions, navigatorExtras)
}
}
@@ -121,7 +112,7 @@
*
* @return the newly inflated included navigation graph
*/
- private fun replaceWithIncludedNav(destination: DynamicIncludeNavGraph): NavBackStackEntry {
+ private fun replaceWithIncludedNav(destination: DynamicIncludeNavGraph): NavGraph {
val graphId = context.resources.getIdentifier(
destination.graphResourceName, "navigation",
destination.graphPackage
@@ -146,11 +137,9 @@
outerNav.addDestination(includedNav)
// Avoid calling replaceWithIncludedNav() on the same destination more than once
createdDestinations.remove(destination)
- return NavBackStackEntry.create(context, includedNav)
+ return includedNav
}
- override fun popBackStack(): Boolean = true
-
override fun onSaveState(): Bundle? {
// Return a non-null Bundle to get a callback to onRestoreState
return Bundle.EMPTY
diff --git a/navigation/navigation-fragment/src/androidTest/java/androidx/navigation/fragment/FragmentNavigatorDestinationBuilderTest.kt b/navigation/navigation-fragment/src/androidTest/java/androidx/navigation/fragment/FragmentNavigatorDestinationBuilderTest.kt
index 616174b..233e23e 100644
--- a/navigation/navigation-fragment/src/androidTest/java/androidx/navigation/fragment/FragmentNavigatorDestinationBuilderTest.kt
+++ b/navigation/navigation-fragment/src/androidTest/java/androidx/navigation/fragment/FragmentNavigatorDestinationBuilderTest.kt
@@ -23,8 +23,7 @@
import androidx.test.annotation.UiThreadTest
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertTrue
+import com.google.common.truth.Truth.assertWithMessage
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -47,15 +46,12 @@
val graph = navHostFragment.createGraph(startDestination = DESTINATION_ID) {
fragment<BuilderTestFragment>(DESTINATION_ID)
}
- assertTrue(
- "Destination should be added to the graph",
- DESTINATION_ID in graph
- )
- assertEquals(
- "Fragment class should be set to BuilderTestFragment",
- BuilderTestFragment::class.java.name,
- (graph[DESTINATION_ID] as FragmentNavigator.Destination).className
- )
+ assertWithMessage("Destination should be added to the graph")
+ .that(DESTINATION_ID in graph)
+ .isTrue()
+ assertWithMessage("Fragment class should be set to BuilderTestFragment")
+ .that((graph[DESTINATION_ID] as FragmentNavigator.Destination).className)
+ .isEqualTo(BuilderTestFragment::class.java.name)
}
@Suppress("DEPRECATION")
@@ -70,19 +66,15 @@
label = LABEL
}
}
- assertTrue(
- "Destination should be added to the graph",
- DESTINATION_ID in graph
- )
- assertEquals(
- "Fragment class should be set to BuilderTestFragment",
- BuilderTestFragment::class.java.name,
- (graph[DESTINATION_ID] as FragmentNavigator.Destination).className
- )
- assertEquals(
- "Fragment should have label set",
- LABEL, graph[DESTINATION_ID].label
- )
+ assertWithMessage("Destination should be added to the graph")
+ .that(DESTINATION_ID in graph)
+ .isTrue()
+ assertWithMessage("Fragment class should be set to BuilderTestFragment")
+ .that((graph[DESTINATION_ID] as FragmentNavigator.Destination).className)
+ .isEqualTo(BuilderTestFragment::class.java.name)
+ assertWithMessage("Fragment should have label set")
+ .that(graph[DESTINATION_ID].label)
+ .isEqualTo(LABEL)
}
@UiThreadTest
@@ -94,15 +86,12 @@
val graph = navHostFragment.createGraph(startDestination = DESTINATION_ROUTE) {
fragment<BuilderTestFragment>(DESTINATION_ROUTE)
}
- assertTrue(
- "Destination should be added to the graph",
- DESTINATION_ROUTE in graph
- )
- assertEquals(
- "Fragment class should be set to BuilderTestFragment",
- BuilderTestFragment::class.java.name,
- (graph[DESTINATION_ROUTE] as FragmentNavigator.Destination).className
- )
+ assertWithMessage("Destination should be added to the graph")
+ .that(DESTINATION_ROUTE in graph)
+ .isTrue()
+ assertWithMessage("Fragment class should be set to BuilderTestFragment")
+ .that((graph[DESTINATION_ROUTE] as FragmentNavigator.Destination).className)
+ .isEqualTo(BuilderTestFragment::class.java.name)
}
@UiThreadTest
@@ -116,19 +105,15 @@
label = LABEL
}
}
- assertTrue(
- "Destination should be added to the graph",
- DESTINATION_ROUTE in graph
- )
- assertEquals(
- "Fragment class should be set to BuilderTestFragment",
- BuilderTestFragment::class.java.name,
- (graph[DESTINATION_ROUTE] as FragmentNavigator.Destination).className
- )
- assertEquals(
- "Fragment should have label set",
- LABEL, graph[DESTINATION_ROUTE].label
- )
+ assertWithMessage("Destination should be added to the graph")
+ .that(DESTINATION_ROUTE in graph)
+ .isTrue()
+ assertWithMessage("Fragment class should be set to BuilderTestFragment")
+ .that((graph[DESTINATION_ROUTE] as FragmentNavigator.Destination).className)
+ .isEqualTo(BuilderTestFragment::class.java.name)
+ assertWithMessage("Fragment should have label set")
+ .that(graph[DESTINATION_ROUTE].label)
+ .isEqualTo(LABEL)
}
}
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ActivityNavigatorDestinationBuilderTest.kt b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ActivityNavigatorDestinationBuilderTest.kt
index 6e1ae7a..d74eef3 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ActivityNavigatorDestinationBuilderTest.kt
+++ b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ActivityNavigatorDestinationBuilderTest.kt
@@ -21,8 +21,6 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.google.common.truth.Truth.assertWithMessage
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
@@ -40,15 +38,12 @@
label = LABEL
}
}
- assertTrue(
- "Destination should be added to the graph",
- DESTINATION_ID in graph
- )
- assertEquals(
- "Destination should have label set",
- LABEL,
- graph[DESTINATION_ID].label
- )
+ assertWithMessage("Destination should be added to the graph")
+ .that(DESTINATION_ID in graph)
+ .isTrue()
+ assertWithMessage("Destination should have label set")
+ .that(graph[DESTINATION_ID].label)
+ .isEqualTo(LABEL)
}
@Suppress("DEPRECATION")
@@ -75,15 +70,12 @@
activityClass = TestActivity::class
}
}
- assertTrue(
- "Destination should be added to the graph",
- DESTINATION_ID in graph
- )
- assertEquals(
- "Destination should have ComponentName set",
- TestActivity::class.java.name,
- (graph[DESTINATION_ID] as ActivityNavigator.Destination).component?.className
- )
+ assertWithMessage("Destination should be added to the graph")
+ .that(DESTINATION_ID in graph)
+ .isTrue()
+ assertWithMessage("Destination should have ComponentName set")
+ .that((graph[DESTINATION_ID] as ActivityNavigator.Destination).component?.className)
+ .isEqualTo(TestActivity::class.java.name)
}
@Suppress("DEPRECATION")
@@ -94,15 +86,12 @@
action = ACTION
}
}
- assertTrue(
- "Destination should be added to the graph",
- DESTINATION_ID in graph
- )
- assertEquals(
- "Destination should have action set",
- ACTION,
- (graph[DESTINATION_ID] as ActivityNavigator.Destination).action
- )
+ assertWithMessage("Destination should be added to the graph")
+ .that(DESTINATION_ID in graph)
+ .isTrue()
+ assertWithMessage("Destination should have action set")
+ .that((graph[DESTINATION_ID] as ActivityNavigator.Destination).action)
+ .isEqualTo(ACTION)
}
@Suppress("DEPRECATION")
@@ -113,15 +102,12 @@
data = DATA
}
}
- assertTrue(
- "Destination should be added to the graph",
- DESTINATION_ID in graph
- )
- assertEquals(
- "Destination should have data set",
- DATA,
- (graph[DESTINATION_ID] as ActivityNavigator.Destination).data
- )
+ assertWithMessage("Destination should be added to the graph")
+ .that(DESTINATION_ID in graph)
+ .isTrue()
+ assertWithMessage("Destination should have data set")
+ .that((graph[DESTINATION_ID] as ActivityNavigator.Destination).data)
+ .isEqualTo(DATA)
}
@Suppress("DEPRECATION")
@@ -132,15 +118,12 @@
dataPattern = DATA_PATTERN
}
}
- assertTrue(
- "Destination should be added to the graph",
- DESTINATION_ID in graph
- )
- assertEquals(
- "Destination should have data pattern set",
- DATA_PATTERN,
- (graph[DESTINATION_ID] as ActivityNavigator.Destination).dataPattern
- )
+ assertWithMessage("Destination should be added to the graph")
+ .that(DESTINATION_ID in graph)
+ .isTrue()
+ assertWithMessage("Destination should have data pattern set")
+ .that((graph[DESTINATION_ID] as ActivityNavigator.Destination).dataPattern)
+ .isEqualTo(DATA_PATTERN)
}
@Test
@@ -150,15 +133,12 @@
label = LABEL
}
}
- assertTrue(
- "Destination should be added to the graph",
- DESTINATION_ROUTE in graph
- )
- assertEquals(
- "Destination should have label set",
- LABEL,
- graph[DESTINATION_ROUTE].label
- )
+ assertWithMessage("Destination should be added to the graph")
+ .that(DESTINATION_ROUTE in graph)
+ .isTrue()
+ assertWithMessage("Destination should have label set")
+ .that(graph[DESTINATION_ROUTE].label)
+ .isEqualTo(LABEL)
}
@Test
@@ -183,15 +163,12 @@
activityClass = TestActivity::class
}
}
- assertTrue(
- "Destination should be added to the graph",
- DESTINATION_ROUTE in graph
- )
- assertEquals(
- "Destination should have ComponentName set",
- TestActivity::class.java.name,
- (graph[DESTINATION_ROUTE] as ActivityNavigator.Destination).component?.className
- )
+ assertWithMessage("Destination should be added to the graph")
+ .that(DESTINATION_ROUTE in graph)
+ .isTrue()
+ assertWithMessage("Destination should have ComponentName set")
+ .that((graph[DESTINATION_ROUTE] as ActivityNavigator.Destination).component?.className)
+ .isEqualTo(TestActivity::class.java.name)
}
@Test
@@ -201,15 +178,12 @@
action = ACTION
}
}
- assertTrue(
- "Destination should be added to the graph",
- DESTINATION_ROUTE in graph
- )
- assertEquals(
- "Destination should have action set",
- ACTION,
- (graph[DESTINATION_ROUTE] as ActivityNavigator.Destination).action
- )
+ assertWithMessage("Destination should be added to the graph")
+ .that(DESTINATION_ROUTE in graph)
+ .isTrue()
+ assertWithMessage("Destination should have action set")
+ .that((graph[DESTINATION_ROUTE] as ActivityNavigator.Destination).action)
+ .isEqualTo(ACTION)
}
@Test
@@ -219,15 +193,12 @@
data = DATA
}
}
- assertTrue(
- "Destination should be added to the graph",
- DESTINATION_ROUTE in graph
- )
- assertEquals(
- "Destination should have data set",
- DATA,
- (graph[DESTINATION_ROUTE] as ActivityNavigator.Destination).data
- )
+ assertWithMessage("Destination should be added to the graph")
+ .that(DESTINATION_ROUTE in graph)
+ .isTrue()
+ assertWithMessage("Destination should have data set")
+ .that((graph[DESTINATION_ROUTE] as ActivityNavigator.Destination).data)
+ .isEqualTo(DATA)
}
@Test
@@ -237,15 +208,12 @@
dataPattern = DATA_PATTERN
}
}
- assertTrue(
- "Destination should be added to the graph",
- DESTINATION_ROUTE in graph
- )
- assertEquals(
- "Destination should have data pattern set",
- DATA_PATTERN,
- (graph[DESTINATION_ROUTE] as ActivityNavigator.Destination).dataPattern
- )
+ assertWithMessage("Destination should be added to the graph")
+ .that(DESTINATION_ROUTE in graph)
+ .isTrue()
+ assertWithMessage("Destination should have data pattern set")
+ .that((graph[DESTINATION_ROUTE] as ActivityNavigator.Destination).dataPattern)
+ .isEqualTo(DATA_PATTERN)
}
}
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavDeepLinkBuilderTest.kt b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavDeepLinkBuilderTest.kt
index 0b21a08..5a6b530 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavDeepLinkBuilderTest.kt
+++ b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavDeepLinkBuilderTest.kt
@@ -26,7 +26,6 @@
import androidx.testutils.TestNavigator
import androidx.testutils.test
import com.google.common.truth.Truth.assertWithMessage
-import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
@@ -66,7 +65,7 @@
deepLinkBuilder.setGraph(R.navigation.nav_simple)
deepLinkBuilder.setDestination(R.id.second_test)
val taskStackBuilder = deepLinkBuilder.createTaskStackBuilder()
- assertEquals("Expected one Intent", 1, taskStackBuilder.intentCount)
+ assertWithMessage("Expected one Intent").that(taskStackBuilder.intentCount).isEqualTo(1)
}
@Test
@@ -76,7 +75,7 @@
deepLinkBuilder.setGraph(nav_simple_route_graph)
deepLinkBuilder.setDestination("second_test")
val taskStackBuilder = deepLinkBuilder.createTaskStackBuilder()
- assertEquals("Expected one Intent", 1, taskStackBuilder.intentCount)
+ assertWithMessage("Expected one Intent").that(taskStackBuilder.intentCount).isEqualTo(1)
}
@Test
@@ -92,7 +91,7 @@
deepLinkBuilder.setGraph(navGraph)
deepLinkBuilder.setDestination(R.id.second_test)
val taskStackBuilder = deepLinkBuilder.createTaskStackBuilder()
- assertEquals("Expected one Intent", 1, taskStackBuilder.intentCount)
+ assertWithMessage("Expected one Intent").that(taskStackBuilder.intentCount).isEqualTo(1)
}
@Test
@@ -102,7 +101,7 @@
deepLinkBuilder.setGraph(nav_simple_route_graph)
deepLinkBuilder.setDestination("second_test")
val taskStackBuilder = deepLinkBuilder.createTaskStackBuilder()
- assertEquals("Expected one Intent", 1, taskStackBuilder.intentCount)
+ assertWithMessage("Expected one Intent").that(taskStackBuilder.intentCount).isEqualTo(1)
}
@Suppress("DEPRECATION")
@@ -120,7 +119,7 @@
deepLinkBuilder.setGraph(navGraph)
deepLinkBuilder.setDestination(1)
val taskStackBuilder = deepLinkBuilder.createTaskStackBuilder()
- assertEquals("Expected one Intent", 1, taskStackBuilder.intentCount)
+ assertWithMessage("Expected one Intent").that(taskStackBuilder.intentCount).isEqualTo(1)
}
@Test
@@ -139,7 +138,7 @@
deepLinkBuilder.setGraph(navGraph)
deepLinkBuilder.setDestination("test")
val taskStackBuilder = deepLinkBuilder.createTaskStackBuilder()
- assertEquals("Expected one Intent", 1, taskStackBuilder.intentCount)
+ assertWithMessage("Expected one Intent").that(taskStackBuilder.intentCount).isEqualTo(1)
}
@UiThreadTest
@@ -153,7 +152,7 @@
deepLinkBuilder.setDestination(R.id.second_test)
val taskStackBuilder = deepLinkBuilder.createTaskStackBuilder()
- assertEquals("Expected one Intent", 1, taskStackBuilder.intentCount)
+ assertWithMessage("Expected one Intent").that(taskStackBuilder.intentCount).isEqualTo(1)
}
@UiThreadTest
@@ -167,7 +166,7 @@
deepLinkBuilder.setDestination("second_test")
val taskStackBuilder = deepLinkBuilder.createTaskStackBuilder()
- assertEquals("Expected one Intent", 1, taskStackBuilder.intentCount)
+ assertWithMessage("Expected one Intent").that(taskStackBuilder.intentCount).isEqualTo(1)
}
@Test
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavInflaterTest.kt b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavInflaterTest.kt
index 9f25763..ae4d0f9 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavInflaterTest.kt
+++ b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavInflaterTest.kt
@@ -233,6 +233,14 @@
}
@Test
+ fun testDefaultArgumentsStringArray() {
+ val defaultArguments = inflateDefaultArgumentsFromGraph()
+
+ assertThat(defaultArguments["test_string_array"]?.run { type to defaultValue })
+ .isEqualTo(NavType.StringArrayType to null)
+ }
+
+ @Test
fun testDefaultArgumentsReference() {
val defaultArguments = inflateDefaultArgumentsFromGraph()
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_default_arguments.xml b/navigation/navigation-runtime/src/androidTest/res/navigation/nav_default_arguments.xml
index 0b66aec..248f22f 100644
--- a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_default_arguments.xml
+++ b/navigation/navigation-runtime/src/androidTest/res/navigation/nav_default_arguments.xml
@@ -90,6 +90,11 @@
app:argType="string" />
<argument
+ android:name="test_string_array"
+ android:defaultValue="@null"
+ app:argType="string[]" />
+
+ <argument
android:name="test_long"
android:defaultValue="456789013456L" />
<argument
diff --git a/playground-common/playground.properties b/playground-common/playground.properties
index 76f0b30..dac9b6d 100644
--- a/playground-common/playground.properties
+++ b/playground-common/playground.properties
@@ -26,7 +26,7 @@
kotlin.code.style=official
# Disable docs
androidx.enableDocumentation=false
-androidx.playground.snapshotBuildId=7440113
+androidx.playground.snapshotBuildId=7456910
androidx.playground.metalavaBuildId=7255182
androidx.playground.dokkaBuildId=7299536
androidx.studio.type=playground
diff --git a/preference/preference/res/values-or/strings.xml b/preference/preference/res/values-or/strings.xml
index d3bcbc8..fc0b5e7 100644
--- a/preference/preference/res/values-or/strings.xml
+++ b/preference/preference/res/values-or/strings.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="v7_preference_on" msgid="89551595707643515">"ଅନ୍ ଅଛି"</string>
+ <string name="v7_preference_on" msgid="89551595707643515">"ଚାଲୁ ଅଛି"</string>
<string name="v7_preference_off" msgid="3140233346420563315">"ବନ୍ଦ"</string>
<string name="expand_button_title" msgid="2427401033573778270">"ଅଧିକ ଉନ୍ନତ"</string>
<string name="summary_collapsed_preference_list" msgid="9167775378838880170">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XBasicAnnotationProcessor.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XBasicAnnotationProcessor.kt
new file mode 100644
index 0000000..733e5f9
--- /dev/null
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XBasicAnnotationProcessor.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room.compiler.processing
+
+/**
+ * Common interface for basic annotation processors.
+ *
+ * A processor should not implement this interface directly and instead should extend
+ * [androidx.room.compiler.processing.javac.JavacBasicAnnotationProcessor] or
+ * [androidx.room.compiler.processing.ksp.KspBasicAnnotationProcessor].
+ */
+interface XBasicAnnotationProcessor {
+
+ /**
+ * The list of processing steps to execute.
+ */
+ fun processingSteps(): Iterable<XProcessingStep>
+
+ /**
+ * Called at the end of a processing round after all [processingSteps] have been executed.
+ */
+ fun postRound(env: XProcessingEnv, round: XRoundEnv) { }
+}
\ No newline at end of file
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XProcessingStep.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XProcessingStep.kt
index b3bac7f..96f3994 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XProcessingStep.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XProcessingStep.kt
@@ -16,16 +16,6 @@
package androidx.room.compiler.processing
-import androidx.room.compiler.processing.javac.JavacElement
-import androidx.room.compiler.processing.javac.JavacProcessingEnv
-import androidx.room.compiler.processing.ksp.KspElement
-import androidx.room.compiler.processing.ksp.KspProcessingEnv
-import com.google.auto.common.BasicAnnotationProcessor
-import com.google.common.collect.ImmutableSetMultimap
-import com.google.devtools.ksp.symbol.KSAnnotated
-import javax.annotation.processing.ProcessingEnvironment
-import javax.lang.model.element.Element
-
/**
* Processing step to simplify processing a set of annotations.
*/
@@ -47,59 +37,4 @@
* The set of annotation qualified names processed by this step.
*/
fun annotations(): Set<String>
-
- companion object {
-
- /**
- * Wraps current [XProcessingStep] into an Auto Common
- * [BasicAnnotationProcessor.ProcessingStep].
- */
- @JvmStatic
- fun XProcessingStep.asAutoCommonProcessor(
- env: ProcessingEnvironment
- ): BasicAnnotationProcessor.Step {
- return JavacProcessingStepDelegate(
- env = env,
- delegate = this
- )
- }
-
- @JvmStatic
- fun XProcessingStep.executeInKsp(env: XProcessingEnv): List<KSAnnotated> {
- check(env is KspProcessingEnv)
- val round = XRoundEnv.create(env)
- val args = annotations().associateWith { annotation ->
- round.getElementsAnnotatedWith(annotation)
- }
- return process(env, args)
- .map { (it as KspElement).declaration }
- }
- }
-}
-
-internal class JavacProcessingStepDelegate(
- val env: ProcessingEnvironment,
- val delegate: XProcessingStep
-) : BasicAnnotationProcessor.Step {
- override fun annotations(): Set<String> = delegate.annotations()
-
- @Suppress("UnstableApiUsage")
- override fun process(
- elementsByAnnotation: ImmutableSetMultimap<String, Element>
- ): Set<Element> {
- val converted = mutableMapOf<String, Set<XElement>>()
- // create a new x processing environment for each step to ensure it can freely cache
- // whatever it wants and we don't keep elements references across rounds.
- val xEnv = JavacProcessingEnv(env)
- annotations().forEach { annotation ->
- val elements = elementsByAnnotation[annotation].mapNotNull { element ->
- xEnv.wrapAnnotatedElement(element, annotation)
- }.toSet()
- converted[annotation] = elements
- }
- val result = delegate.process(xEnv, converted)
- return result.map {
- (it as JavacElement).element
- }.toSet()
- }
}
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/compat/XConverters.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/compat/XConverters.kt
index 4d5e1ee..c3cadc6 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/compat/XConverters.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/compat/XConverters.kt
@@ -19,15 +19,18 @@
import androidx.room.compiler.processing.XElement
import androidx.room.compiler.processing.XExecutableElement
import androidx.room.compiler.processing.XProcessingEnv
+import androidx.room.compiler.processing.XRoundEnv
import androidx.room.compiler.processing.XType
import androidx.room.compiler.processing.XTypeElement
import androidx.room.compiler.processing.XVariableElement
import androidx.room.compiler.processing.javac.JavacElement
import androidx.room.compiler.processing.javac.JavacExecutableElement
import androidx.room.compiler.processing.javac.JavacProcessingEnv
+import androidx.room.compiler.processing.javac.JavacRoundEnv
import androidx.room.compiler.processing.javac.JavacType
import androidx.room.compiler.processing.javac.JavacTypeElement
import androidx.room.compiler.processing.javac.JavacVariableElement
+import javax.annotation.processing.RoundEnvironment
import javax.lang.model.element.Element
import javax.lang.model.element.ExecutableElement
import javax.lang.model.element.TypeElement
@@ -38,6 +41,9 @@
object XConverters {
@JvmStatic
+ fun XRoundEnv.toJavac(): RoundEnvironment = (this as JavacRoundEnv).delegate
+
+ @JvmStatic
fun XElement.toJavac(): Element = (this as JavacElement).element
@JvmStatic
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacBasicAnnotationProcessor.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacBasicAnnotationProcessor.kt
new file mode 100644
index 0000000..f8926ad
--- /dev/null
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacBasicAnnotationProcessor.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room.compiler.processing.javac
+
+import androidx.room.compiler.processing.XBasicAnnotationProcessor
+import androidx.room.compiler.processing.XElement
+import androidx.room.compiler.processing.XRoundEnv
+import com.google.auto.common.BasicAnnotationProcessor
+import com.google.common.collect.ImmutableSetMultimap
+import javax.annotation.processing.RoundEnvironment
+import javax.lang.model.element.Element
+
+/**
+ * Javac implementation of a [XBasicAnnotationProcessor] with built-in support for validating and
+ * deferring elements via auto-common's [BasicAnnotationProcessor].
+ */
+abstract class JavacBasicAnnotationProcessor :
+ BasicAnnotationProcessor(), XBasicAnnotationProcessor {
+
+ final override fun steps(): Iterable<Step> {
+ // Execute all processing steps in a single auto-common Step. This is done to share the
+ // XProcessingEnv and its cached across steps in the same round.
+ val steps = processingSteps()
+ val parentStep = object : Step {
+ override fun annotations() = steps.flatMap { it.annotations() }.toSet()
+
+ override fun process(
+ elementsByAnnotation: ImmutableSetMultimap<String, Element>
+ ): Set<Element> {
+ val xEnv = JavacProcessingEnv(processingEnv)
+ val convertedElementsByAnnotation = mutableMapOf<String, Set<XElement>>()
+ annotations().forEach { annotation ->
+ convertedElementsByAnnotation[annotation] =
+ elementsByAnnotation[annotation].mapNotNull { element ->
+ xEnv.wrapAnnotatedElement(element, annotation)
+ }.toSet()
+ }
+ val results = steps.flatMap { step ->
+ step.process(
+ env = xEnv,
+ elementsByAnnotation = step.annotations().associateWith {
+ convertedElementsByAnnotation[it] ?: emptySet()
+ }
+ )
+ }
+ return results.map { (it as JavacElement).element }.toSet()
+ }
+ }
+ return listOf(parentStep)
+ }
+
+ final override fun postRound(roundEnv: RoundEnvironment) {
+ // Due to BasicAnnotationProcessor taking over AbstractProcessor#process() we can't
+ // share the same XProcessingEnv from the steps, but that might be ok...
+ val xEnv = JavacProcessingEnv(processingEnv)
+ val xRound = XRoundEnv.create(xEnv, roundEnv)
+ postRound(xEnv, xRound)
+ }
+}
\ No newline at end of file
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspBasicAnnotationProcessor.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspBasicAnnotationProcessor.kt
new file mode 100644
index 0000000..9551d6d
--- /dev/null
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspBasicAnnotationProcessor.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room.compiler.processing.ksp
+
+import androidx.room.compiler.processing.XBasicAnnotationProcessor
+import androidx.room.compiler.processing.XElement
+import androidx.room.compiler.processing.XProcessingEnv
+import androidx.room.compiler.processing.XRoundEnv
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.processing.SymbolProcessor
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.validate
+
+/**
+ * KSP implementation of a [XBasicAnnotationProcessor] with built-in support for validating and
+ * deferring symbols.
+ */
+abstract class KspBasicAnnotationProcessor(
+ val symbolProcessorEnvironment: SymbolProcessorEnvironment
+) : SymbolProcessor, XBasicAnnotationProcessor {
+
+ final override fun process(resolver: Resolver): List<KSAnnotated> {
+ val processingEnv = XProcessingEnv.create(
+ symbolProcessorEnvironment.options,
+ resolver,
+ symbolProcessorEnvironment.codeGenerator,
+ symbolProcessorEnvironment.logger
+ )
+ val round = XRoundEnv.create(processingEnv)
+ val deferredElements = processingSteps().flatMap { step ->
+ val invalidElements = mutableSetOf<XElement>()
+ val elementsByAnnotation = step.annotations().associateWith { annotation ->
+ val annotatedElements = round.getElementsAnnotatedWith(annotation)
+ annotatedElements
+ .filter { (it as KspElement).declaration.validate() }
+ .also { invalidElements.addAll(annotatedElements - it) }
+ .toSet()
+ }
+ invalidElements + step.process(processingEnv, elementsByAnnotation)
+ }
+ postRound(processingEnv, round)
+ return deferredElements.map { (it as KspElement).declaration }
+ }
+}
\ No newline at end of file
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XProcessingStepTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XProcessingStepTest.kt
index 004ace1..b0af4d3 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XProcessingStepTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XProcessingStepTest.kt
@@ -16,20 +16,18 @@
package androidx.room.compiler.processing
-import androidx.room.compiler.processing.XProcessingStep.Companion.asAutoCommonProcessor
-import androidx.room.compiler.processing.XProcessingStep.Companion.executeInKsp
+import androidx.room.compiler.processing.javac.JavacBasicAnnotationProcessor
+import androidx.room.compiler.processing.ksp.KspBasicAnnotationProcessor
+import androidx.room.compiler.processing.ksp.KspElement
import androidx.room.compiler.processing.testcode.MainAnnotation
import androidx.room.compiler.processing.testcode.OtherAnnotation
import androidx.room.compiler.processing.util.CompilationTestCapabilities
-import com.google.auto.common.BasicAnnotationProcessor
import com.google.common.truth.Truth.assertAbout
import com.google.common.truth.Truth.assertThat
-import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
import com.google.devtools.ksp.processing.SymbolProcessorProvider
import com.google.devtools.ksp.symbol.ClassKind
-import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.google.testing.compile.JavaFileObjects
import com.google.testing.compile.JavaSourcesSubjectFactory
@@ -79,12 +77,8 @@
)
}
}
- val mainProcessor = object : BasicAnnotationProcessor() {
- override fun steps(): Iterable<Step> {
- return listOf(
- processingStep.asAutoCommonProcessor(processingEnv)
- )
- }
+ val mainProcessor = object : JavacBasicAnnotationProcessor() {
+ override fun processingSteps() = listOf(processingStep)
}
val main = JavaFileObjects.forSourceString(
"foo.bar.Main",
@@ -187,19 +181,8 @@
).that(
listOf(main)
).processedWith(
- object : BasicAnnotationProcessor() {
- override fun steps(): Iterable<Step> {
- return listOf(
- processingStep.asAutoCommonProcessor(processingEnv)
- )
- }
-
- override fun getSupportedOptions(): Set<String> {
- return setOf(
- MainAnnotation::class.qualifiedName!!,
- OtherAnnotation::class.qualifiedName!!
- )
- }
+ object : JavacBasicAnnotationProcessor() {
+ override fun processingSteps() = listOf(processingStep)
}
).compilesWithoutError()
assertThat(otherAnnotatedElements).containsExactly(
@@ -267,19 +250,8 @@
).that(
listOf(main)
).processedWith(
- object : BasicAnnotationProcessor() {
- override fun steps(): Iterable<Step> {
- return listOf(
- processingStep.asAutoCommonProcessor(processingEnv)
- )
- }
-
- override fun getSupportedOptions(): Set<String> {
- return setOf(
- MainAnnotation::class.qualifiedName!!,
- OtherAnnotation::class.qualifiedName!!
- )
- }
+ object : JavacBasicAnnotationProcessor() {
+ override fun processingSteps() = listOf(processingStep)
}
).compilesWithoutError()
assertThat(elementPerRound).hasSize(2)
@@ -298,6 +270,7 @@
@Test
fun kspReturnsUnprocessed() {
CompilationTestCapabilities.assumeKspIsEnabled()
+ var returned: Set<XElement>? = null
val processingStep = object : XProcessingStep {
override fun process(
env: XProcessingEnv,
@@ -306,26 +279,17 @@
return elementsByAnnotation.values
.flatten()
.toSet()
+ .also { returned = it }
}
override fun annotations(): Set<String> {
return setOf(OtherAnnotation::class.qualifiedName!!)
}
}
- var returned: List<KSAnnotated>? = null
val processorProvider = object : SymbolProcessorProvider {
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
- return object : SymbolProcessor {
- override fun process(resolver: Resolver): List<KSAnnotated> {
- val env = XProcessingEnv.create(
- emptyMap(),
- resolver,
- environment.codeGenerator,
- environment.logger
- )
- return processingStep.executeInKsp(env)
- .also { returned = it }
- }
+ return object : KspBasicAnnotationProcessor(environment) {
+ override fun processingSteps() = listOf(processingStep)
}
}
}
@@ -352,8 +316,137 @@
isNotNull()
isNotEmpty()
}
- val element = returned!!.first() as KSClassDeclaration
+ val element =
+ returned!!.map { (it as KspElement).declaration }.first() as KSClassDeclaration
assertThat(element.classKind).isEqualTo(ClassKind.CLASS)
assertThat(element.qualifiedName!!.asString()).isEqualTo("foo.bar.Other")
}
+
+ @Test
+ fun javacAnnotatedElementsByStep() {
+ val main = JavaFileObjects.forSourceString(
+ "foo.bar.Main",
+ """
+ package foo.bar;
+ import androidx.room.compiler.processing.testcode.*;
+ @MainAnnotation(
+ typeList = {},
+ singleType = Object.class,
+ intMethod = 3,
+ singleOtherAnnotation = @OtherAnnotation("y")
+ )
+ class Main {
+ }
+ """.trimIndent()
+ )
+ val other = JavaFileObjects.forSourceString(
+ "foo.bar.Other",
+ """
+ package foo.bar;
+ import androidx.room.compiler.processing.testcode.*;
+ @OtherAnnotation("x")
+ class Other {
+ }
+ """.trimIndent()
+ )
+ val elementsByStep = mutableMapOf<XProcessingStep, Collection<String>>()
+ val mainStep = object : XProcessingStep {
+ override fun annotations() = setOf(MainAnnotation::class.qualifiedName!!)
+ override fun process(
+ env: XProcessingEnv,
+ elementsByAnnotation: Map<String, Set<XElement>>
+ ): Set<XElement> {
+ elementsByStep[this] = elementsByAnnotation.values.flatten()
+ .map { (it as XTypeElement).qualifiedName }
+ return emptySet()
+ }
+ }
+ val otherStep = object : XProcessingStep {
+ override fun annotations() = setOf(OtherAnnotation::class.qualifiedName!!)
+ override fun process(
+ env: XProcessingEnv,
+ elementsByAnnotation: Map<String, Set<XElement>>
+ ): Set<XElement> {
+ elementsByStep[this] = elementsByAnnotation.values.flatten()
+ .map { (it as XTypeElement).qualifiedName }
+ return emptySet()
+ }
+ }
+ assertAbout(
+ JavaSourcesSubjectFactory.javaSources()
+ ).that(
+ listOf(main, other)
+ ).processedWith(
+ object : JavacBasicAnnotationProcessor() {
+ override fun processingSteps() = listOf(mainStep, otherStep)
+ }
+ ).compilesWithoutError()
+ assertThat(elementsByStep[mainStep])
+ .containsExactly("foo.bar.Main")
+ assertThat(elementsByStep[otherStep])
+ .containsExactly("foo.bar.Other")
+ }
+
+ @Test
+ fun kspAnnotatedElementsByStep() {
+ val main = SourceFile.kotlin(
+ "Classes.kt",
+ """
+ package foo.bar
+ import androidx.room.compiler.processing.testcode.*
+ @MainAnnotation(
+ typeList = [],
+ singleType = Any::class,
+ intMethod = 3,
+ singleOtherAnnotation = OtherAnnotation("y")
+ )
+ class Main {
+ }
+ @OtherAnnotation("y")
+ class Other {
+ }
+ """.trimIndent()
+ )
+ val elementsByStep = mutableMapOf<XProcessingStep, Collection<String>>()
+ val mainStep = object : XProcessingStep {
+ override fun annotations() = setOf(MainAnnotation::class.qualifiedName!!)
+ override fun process(
+ env: XProcessingEnv,
+ elementsByAnnotation: Map<String, Set<XElement>>
+ ): Set<XElement> {
+ elementsByStep[this] = elementsByAnnotation.values.flatten()
+ .map { (it as XTypeElement).qualifiedName }
+ return emptySet()
+ }
+ }
+ val otherStep = object : XProcessingStep {
+ override fun annotations() = setOf(OtherAnnotation::class.qualifiedName!!)
+ override fun process(
+ env: XProcessingEnv,
+ elementsByAnnotation: Map<String, Set<XElement>>
+ ): Set<XElement> {
+ elementsByStep[this] = elementsByAnnotation.values.flatten()
+ .map { (it as XTypeElement).qualifiedName }
+ return emptySet()
+ }
+ }
+ val processorProvider = object : SymbolProcessorProvider {
+ override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
+ return object : KspBasicAnnotationProcessor(environment) {
+ override fun processingSteps() = listOf(mainStep, otherStep)
+ }
+ }
+ }
+ KotlinCompilation().apply {
+ workingDir = temporaryFolder.root
+ inheritClassPath = true
+ symbolProcessorProviders = listOf(processorProvider)
+ sources = listOf(main)
+ verbose = false
+ }.compile()
+ assertThat(elementsByStep[mainStep])
+ .containsExactly("foo.bar.Main")
+ assertThat(elementsByStep[otherStep])
+ .containsExactly("foo.bar.Other")
+ }
}
\ No newline at end of file
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/RoomKspProcessor.kt b/room/room-compiler/src/main/kotlin/androidx/room/RoomKspProcessor.kt
index fa1656b9..7437810 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/RoomKspProcessor.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/RoomKspProcessor.kt
@@ -16,44 +16,25 @@
package androidx.room
-import androidx.room.compiler.processing.XProcessingEnv
-import androidx.room.compiler.processing.XProcessingStep.Companion.executeInKsp
-import com.google.devtools.ksp.processing.CodeGenerator
-import com.google.devtools.ksp.processing.KSPLogger
-import com.google.devtools.ksp.processing.Resolver
+import androidx.room.compiler.processing.ksp.KspBasicAnnotationProcessor
import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
import com.google.devtools.ksp.processing.SymbolProcessorProvider
-import com.google.devtools.ksp.symbol.KSAnnotated
/**
* Entry point for processing using KSP.
*/
class RoomKspProcessor(
- private val options: Map<String, String>,
- private val codeGenerator: CodeGenerator,
- private val logger: KSPLogger
-) : SymbolProcessor {
- override fun process(resolver: Resolver): List<KSAnnotated> {
- val processingEnv = XProcessingEnv.create(
- options,
- resolver,
- codeGenerator,
- logger
- )
+ environment: SymbolProcessorEnvironment
+) : KspBasicAnnotationProcessor(environment) {
- return DatabaseProcessingStep().executeInKsp(
- processingEnv
- )
- }
+ override fun processingSteps() = listOf(
+ DatabaseProcessingStep()
+ )
class Provider : SymbolProcessorProvider {
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
- return RoomKspProcessor(
- options = environment.options,
- codeGenerator = environment.codeGenerator,
- logger = environment.logger
- )
+ return RoomKspProcessor(environment)
}
}
}
\ No newline at end of file
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/RoomProcessor.kt b/room/room-compiler/src/main/kotlin/androidx/room/RoomProcessor.kt
index 8119102..8f6c8ac 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/RoomProcessor.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/RoomProcessor.kt
@@ -17,12 +17,11 @@
package androidx.room
import androidx.room.compiler.processing.XProcessingEnv
-import androidx.room.compiler.processing.XProcessingStep.Companion.asAutoCommonProcessor
+import androidx.room.compiler.processing.javac.JavacBasicAnnotationProcessor
import androidx.room.processor.Context
import androidx.room.processor.ProcessorErrors
import androidx.room.util.SimpleJavaVersion
import androidx.room.vo.Warning
-import com.google.auto.common.BasicAnnotationProcessor
import javax.lang.model.SourceVersion
/**
@@ -34,20 +33,18 @@
/**
* The annotation processor for Room.
*/
-class RoomProcessor : BasicAnnotationProcessor() {
+class RoomProcessor : JavacBasicAnnotationProcessor() {
/** Helper variable to avoid reporting the warning twice. */
private var jdkVersionHasBugReported = false
- override fun steps(): MutableIterable<Step> {
- return mutableListOf(
- DatabaseProcessingStep().asAutoCommonProcessor(processingEnv)
- )
- }
+ override fun processingSteps() = listOf(
+ DatabaseProcessingStep()
+ )
override fun getSupportedOptions(): MutableSet<String> {
val supportedOptions = Context.ARG_OPTIONS.toMutableSet()
- // x processing is a cheap wrapper so it is fine to re-create.
+ // XProcessingEnv is a cheap wrapper so it is fine to re-create.
val xProcessing = XProcessingEnv.create(processingEnv)
if (Context.BooleanProcessorOptions.INCREMENTAL.getValue(xProcessing)) {
if (methodParametersVisibleInClassFiles()) {
diff --git a/settings.gradle b/settings.gradle
index 9be70e4..8e095e4 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -620,6 +620,7 @@
includeProject(":wear:compose:compose-foundation", "wear/compose/foundation", [BuildType.COMPOSE])
includeProject(":wear:compose:compose-material", "wear/compose/material", [BuildType.COMPOSE])
includeProject(":wear:compose:compose-material-benchmark", "wear/compose/material/benchmark", [BuildType.COMPOSE])
+includeProject(":wear:compose:integration-tests:demos", "wear/compose/integration-tests/demos", [BuildType.COMPOSE])
includeProject(":wear:wear-input", "wear/wear-input", [BuildType.MAIN, BuildType.WEAR])
includeProject(":wear:wear-input-testing", "wear/wear-input-testing", [BuildType.MAIN, BuildType.WEAR])
includeProject(":wear:wear-ongoing", "wear/wear-ongoing", [BuildType.MAIN, BuildType.WEAR])
diff --git a/slices/view/src/main/res/values-tr/strings.xml b/slices/view/src/main/res/values-tr/strings.xml
index 84da5fb..74de868 100644
--- a/slices/view/src/main/res/values-tr/strings.xml
+++ b/slices/view/src/main/res/values-tr/strings.xml
@@ -18,7 +18,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
- <string name="abc_slice_more" msgid="1983560225998630901">"Diğer"</string>
+ <string name="abc_slice_more" msgid="1983560225998630901">"Daha fazla"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Daha fazla göster"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Güncellenme zamanı: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
diff --git a/testutils/testutils-espresso/build.gradle b/testutils/testutils-espresso/build.gradle
index 57507bf..8ac3572 100644
--- a/testutils/testutils-espresso/build.gradle
+++ b/testutils/testutils-espresso/build.gradle
@@ -25,6 +25,7 @@
implementation(libs.espressoCore, excludes.espresso)
implementation(libs.kotlinStdlib)
+ implementation("androidx.core:core:1.2.0")
}
android {
diff --git a/testutils/testutils-espresso/src/main/java/androidx/testutils/SwipeExclusionRects.kt b/testutils/testutils-espresso/src/main/java/androidx/testutils/SwipeExclusionRects.kt
new file mode 100644
index 0000000..e3c9b5e
--- /dev/null
+++ b/testutils/testutils-espresso/src/main/java/androidx/testutils/SwipeExclusionRects.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.testutils
+
+import android.graphics.Rect
+import android.view.View
+import androidx.core.view.ViewCompat
+
+/**
+ * Sets exclusion rects for system gestures on this view that will make sure Espresso's
+ * predefined swipes (such as [swipeRight][androidx.test.espresso.action.ViewActions.swipeRight])
+ * won't be mistaken for system gestures.
+ *
+ * Set this on the view on which you will perform the swipe ViewActions.
+ */
+fun View.setSystemExclusionRectsForEspressoSwipes() {
+ addOnLayoutChangeListener(SetExclusionRectsOnLayout())
+}
+
+private class SetExclusionRectsOnLayout : View.OnLayoutChangeListener {
+ private val exclusionRects = mutableListOf<Rect>()
+
+ override fun onLayoutChange(
+ v: View?,
+ left: Int,
+ top: Int,
+ right: Int,
+ bottom: Int,
+ oldLeft: Int,
+ oldTop: Int,
+ oldRight: Int,
+ oldBottom: Int
+ ) {
+ if (v == null) return
+ exclusionRects.clear()
+ val vCenter = (bottom - top) / 2
+ val hCenter = (right - left) / 2
+ // Create an exclusion strip of 2px thick (center +/- 1) through the middle, hor and ver
+ exclusionRects += Rect(left, vCenter - 1, right, vCenter + 1)
+ exclusionRects += Rect(hCenter - 1, top, hCenter + 1, bottom)
+ ViewCompat.setSystemGestureExclusionRects(v, exclusionRects)
+ }
+}
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/LayoutIntrinsics.kt b/text/text/src/main/java/androidx/compose/ui/text/android/LayoutIntrinsics.kt
index 8773399..d9b29cd 100644
--- a/text/text/src/main/java/androidx/compose/ui/text/android/LayoutIntrinsics.kt
+++ b/text/text/src/main/java/androidx/compose/ui/text/android/LayoutIntrinsics.kt
@@ -22,7 +22,6 @@
import android.text.TextPaint
import androidx.compose.ui.text.android.style.LetterSpacingSpanEm
import androidx.compose.ui.text.android.style.LetterSpacingSpanPx
-import androidx.compose.ui.text.android.style.LineHeightSpan
import java.text.BreakIterator
import java.util.PriorityQueue
@@ -139,6 +138,5 @@
textPaint.letterSpacing != 0f ||
charSequence.hasSpan(LetterSpacingSpanPx::class.java) ||
charSequence.hasSpan(LetterSpacingSpanEm::class.java)
- ) &&
- charSequence.hasSpan(LineHeightSpan::class.java)
+ )
}
\ No newline at end of file
diff --git a/viewpager/viewpager/src/androidTest/java/androidx/viewpager/widget/BaseViewPagerTest.java b/viewpager/viewpager/src/androidTest/java/androidx/viewpager/widget/BaseViewPagerTest.java
index ad223ff..6423be2 100644
--- a/viewpager/viewpager/src/androidTest/java/androidx/viewpager/widget/BaseViewPagerTest.java
+++ b/viewpager/viewpager/src/androidTest/java/androidx/viewpager/widget/BaseViewPagerTest.java
@@ -1068,6 +1068,7 @@
@Test
@LargeTest
+ @FlakyTest(bugId = 179887413)
public void testPageScrollPositionChangesSwipe() {
// Swipe one page to the left
verifyScrollCallbacksToHigherPage(ViewPagerActions.wrap(swipeLeft()), 1);
diff --git a/viewpager2/integration-tests/testapp/build.gradle b/viewpager2/integration-tests/testapp/build.gradle
index 3c2e9d5..7aed76de 100644
--- a/viewpager2/integration-tests/testapp/build.gradle
+++ b/viewpager2/integration-tests/testapp/build.gradle
@@ -35,6 +35,7 @@
exclude group: "androidx.viewpager2", module: "viewpager2"
}
+ androidTestImplementation(project(":internal-testutils-espresso"))
androidTestImplementation(libs.testRules)
androidTestImplementation(libs.testExtJunit)
androidTestImplementation(libs.espressoCore)
diff --git a/viewpager2/integration-tests/testapp/src/androidTest/java/androidx/viewpager2/integration/testapp/test/BaseTest.kt b/viewpager2/integration-tests/testapp/src/androidTest/java/androidx/viewpager2/integration/testapp/test/BaseTest.kt
index 46ef639..3ac083f 100644
--- a/viewpager2/integration-tests/testapp/src/androidTest/java/androidx/viewpager2/integration/testapp/test/BaseTest.kt
+++ b/viewpager2/integration-tests/testapp/src/androidTest/java/androidx/viewpager2/integration/testapp/test/BaseTest.kt
@@ -29,6 +29,7 @@
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
+import androidx.testutils.setSystemExclusionRectsForEspressoSwipes
import androidx.viewpager2.integration.testapp.R
import androidx.viewpager2.integration.testapp.test.util.ViewPagerIdleWatcher
import androidx.viewpager2.integration.testapp.test.util.onCurrentPage
@@ -71,6 +72,7 @@
@Before
open fun setUp() {
viewPager = activityTestRule.activity.findViewById(layoutId)
+ viewPager.setSystemExclusionRectsForEspressoSwipes()
idleWatcher = ViewPagerIdleWatcher(viewPager)
onView(withId(layoutId)).perform(waitForInjectMotionEvents())
}
diff --git a/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt
index c1aae40..c6668d7 100644
--- a/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt
+++ b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt
@@ -45,6 +45,7 @@
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.testutils.LocaleTestUtils
import androidx.testutils.recreate
+import androidx.testutils.setSystemExclusionRectsForEspressoSwipes
import androidx.testutils.waitForExecution
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.test.R
@@ -117,7 +118,10 @@
onView(withId(R.id.view_pager)).perform(waitForInjectMotionEvents())
val viewPager: ViewPager2 = activityTestRule.activity.findViewById(R.id.view_pager)
- activityTestRule.runOnUiThread { viewPager.orientation = orientation }
+ activityTestRule.runOnUiThread {
+ viewPager.orientation = orientation
+ viewPager.setSystemExclusionRectsForEspressoSwipes()
+ }
onView(withId(R.id.view_pager)).check(matches(isDisplayed()))
// animations getting in the way on API < 16
@@ -143,6 +147,7 @@
viewPager.orientation = orientation
viewPager.isUserInputEnabled = isUserInputEnabled
viewPager.adapter = adapterProvider(activity)
+ viewPager.setSystemExclusionRectsForEspressoSwipes()
onCreateCallback(viewPager)
}
activity = activityTestRule.recreate()
diff --git a/wear/compose/integration-tests/demos/build.gradle b/wear/compose/integration-tests/demos/build.gradle
new file mode 100644
index 0000000..a82173a
--- /dev/null
+++ b/wear/compose/integration-tests/demos/build.gradle
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+plugins {
+ id("AndroidXPlugin")
+ id("AndroidXComposePlugin")
+ id 'com.android.application'
+ id("org.jetbrains.kotlin.android")
+}
+
+android {
+ defaultConfig {
+ applicationId "androidx.wear.compose.integration.demos"
+ minSdk 25
+ targetSdk 30
+ versionCode 1
+ versionName "1.0"
+ // Change the APK name to match the *testapp regex we use to pick up APKs for testing as
+ // part of CI.
+ archivesBaseName = "wear-compose-demos-testapp"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ buildFeatures {
+ viewBinding true
+ }
+}
+
+dependencies {
+ kotlinPlugin(project(":compose:compiler:compiler"))
+
+ implementation 'androidx.wear:wear:1.1.0'
+ implementation(project(":compose:ui:ui"))
+ implementation project(path: ':compose:integration-tests:demos:common')
+ implementation project(path: ':wear:compose:compose-material')
+ implementation(project(":compose:foundation:foundation"))
+ implementation(project(":compose:foundation:foundation-layout"))
+ implementation(project(":compose:runtime:runtime"))
+
+ androidTestImplementation(project(":compose:ui:ui-test-junit4"))
+ androidTestImplementation(libs.testCore)
+ androidTestImplementation(libs.testRules)
+ androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.espressoCore)
+ androidTestImplementation(libs.junit)
+ androidTestImplementation(libs.truth)
+}
\ No newline at end of file
diff --git a/wear/compose/integration-tests/demos/proguard-rules.pro b/wear/compose/integration-tests/demos/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/wear/compose/integration-tests/demos/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/wear/compose/integration-tests/demos/src/androidTest/AndroidManifest.xml b/wear/compose/integration-tests/demos/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..cfe8548
--- /dev/null
+++ b/wear/compose/integration-tests/demos/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<manifest package="androidx.wear.compose.integration.demos" />
diff --git a/wear/compose/integration-tests/demos/src/androidTest/java/androidx/wear/compose/integration/demos/test/DemoTest.kt b/wear/compose/integration-tests/demos/src/androidTest/java/androidx/wear/compose/integration/demos/test/DemoTest.kt
new file mode 100644
index 0000000..0ca836b
--- /dev/null
+++ b/wear/compose/integration-tests/demos/src/androidTest/java/androidx/wear/compose/integration/demos/test/DemoTest.kt
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.compose.integration.demos.test
+
+import androidx.compose.integration.demos.common.Demo
+import androidx.compose.integration.demos.common.DemoCategory
+import androidx.compose.integration.demos.common.allDemos
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.SemanticsNodeInteractionCollection
+import androidx.compose.ui.test.hasClickAction
+import androidx.compose.ui.test.hasText
+import androidx.compose.ui.test.isDialog
+import androidx.compose.ui.test.junit4.createAndroidComposeRule
+import androidx.compose.ui.test.performClick
+import androidx.compose.ui.test.performScrollTo
+import androidx.test.espresso.Espresso
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.wear.compose.integration.demos.DemoActivity
+import androidx.wear.compose.integration.demos.WearComposeDemos
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private val ignoredDemos = listOf<String>(
+ // Not ignoring any of them \o/
+)
+
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+@OptIn(ExperimentalTestApi::class)
+class DemoTest {
+ // We need to provide the recompose factory first to use new clock.
+ @get:Rule
+ val rule = createAndroidComposeRule<DemoActivity>()
+
+ @Test
+ fun navigateThroughAllDemos() {
+ // Compose integration-tests are split into batches due to size,
+ // but that's overkill until we have a decent population of tests.
+ navigateThroughAllDemos(AllButIgnoredDemos)
+ }
+
+ private fun navigateThroughAllDemos(root: DemoCategory, fastForwardClock: Boolean = false) {
+ // Keep track of each demo we visit.
+ val visitedDemos = mutableListOf<Demo>()
+
+ // Visit all demos.
+ root.visitDemos(
+ visitedDemos = visitedDemos,
+ path = listOf(root),
+ fastForwardClock = fastForwardClock
+ )
+
+ // Ensure that we visited all the demos we expected to, in the order we expected to.
+ assertThat(visitedDemos).isEqualTo(root.allDemos())
+ }
+
+ /**
+ * DFS traversal of each demo in a [DemoCategory] using [Demo.visit]
+ *
+ * @param path The path of categories that leads to this demo
+ */
+ private fun DemoCategory.visitDemos(
+ visitedDemos: MutableList<Demo>,
+ path: List<DemoCategory>,
+ fastForwardClock: Boolean
+ ) {
+ demos.forEach { demo ->
+ visitedDemos.add(demo)
+ demo.visit(visitedDemos, path, fastForwardClock)
+ }
+ }
+
+ /**
+ * Visits a [Demo], and then navigates back up to the [DemoCategory] it was inside.
+ *
+ * If this [Demo] is a [DemoCategory], this will visit sub-[Demo]s first before continuing
+ * in the current category.
+ *
+ * @param path The path of categories that leads to this demo
+ */
+ private fun Demo.visit(
+ visitedDemos: MutableList<Demo>,
+ path: List<DemoCategory>,
+ fastForwardClock: Boolean
+ ) {
+ val navigationTitle = path.navigationTitle
+
+ if (fastForwardClock) {
+ // Skip through the enter animation of the list screen
+ fastForwardClock()
+ }
+
+ rule.onNode(hasText(title) and hasClickAction())
+ .assertExists("Couldn't find \"$title\" in \"$navigationTitle\"")
+ .performScrollTo()
+ .performClick()
+
+ if (this is DemoCategory) {
+ visitDemos(visitedDemos, path + this, fastForwardClock)
+ }
+
+ if (fastForwardClock) {
+ // Skip through the enter animation of the visited demo
+ fastForwardClock()
+ }
+
+ rule.waitForIdle()
+ while (rule.onAllNodes(isDialog()).isNotEmpty()) {
+ Espresso.pressBack()
+ rule.waitForIdle()
+ }
+
+ clearFocusFromDemo()
+ rule.waitForIdle()
+
+ Espresso.pressBack()
+ rule.waitForIdle()
+
+ if (fastForwardClock) {
+ // Pump press back
+ fastForwardClock(2000)
+ }
+ }
+
+ private fun fastForwardClock(millis: Long = 5000) {
+ rule.waitForIdle()
+ rule.mainClock.advanceTimeBy(millis)
+ }
+
+ private fun SemanticsNodeInteractionCollection.isNotEmpty(): Boolean {
+ return fetchSemanticsNodes(atLeastOneRootRequired = false).isNotEmpty()
+ }
+
+ private fun clearFocusFromDemo() {
+ with(rule.activity) {
+ if (hostView.hasFocus()) {
+ if (hostView.isFocused) {
+ // One of the Compose components has focus.
+ focusManager.clearFocus(force = true)
+ } else {
+ // A child view has focus. (View interop scenario).
+ // We could also use hostViewGroup.focusedChild?.clearFocus(), but the
+ // interop views might end up being focused if one of them is marked as
+ // focusedByDefault. So we clear focus by requesting focus on the owner.
+ rule.runOnUiThread { hostView.requestFocus() }
+ }
+ }
+ }
+ }
+}
+
+private val AllButIgnoredDemos =
+ WearComposeDemos.filter { path, demo ->
+ demo.navigationTitle(path) !in ignoredDemos
+ }
+
+private fun Demo.navigationTitle(path: List<DemoCategory>): String {
+ return path.plus(this).navigationTitle
+}
+
+private val List<Demo>.navigationTitle: String
+ get() = if (size == 1) first().title else drop(1).joinToString(" > ")
+
+/**
+ * Trims the tree of [Demo]s represented by this [DemoCategory] by cutting all leave demos for
+ * which the [predicate] returns `false` and recursively removing all empty categories as a result.
+ */
+private fun DemoCategory.filter(
+ path: List<DemoCategory> = emptyList(),
+ predicate: (path: List<DemoCategory>, demo: Demo) -> Boolean
+): DemoCategory {
+ val newPath = path + this
+ return DemoCategory(
+ title,
+ demos.mapNotNull {
+ when (it) {
+ is DemoCategory -> {
+ it.filter(newPath, predicate).let { if (it.demos.isEmpty()) null else it }
+ }
+ else -> {
+ if (predicate(newPath, it)) it else null
+ }
+ }
+ }
+ )
+}
diff --git a/wear/compose/integration-tests/demos/src/main/AndroidManifest.xml b/wear/compose/integration-tests/demos/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..ec8bddb
--- /dev/null
+++ b/wear/compose/integration-tests/demos/src/main/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="androidx.wear.compose.integration.demos">
+
+ <application
+ android:allowBackup="true"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:supportsRtl="true"
+ android:theme="@android:style/Theme.DeviceDefault">
+ <activity
+ android:name=".DemoActivity"
+ android:exported="true"
+ android:label="@string/app_name">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+</manifest>
\ No newline at end of file
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/ButtonDemo.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/ButtonDemo.kt
new file mode 100644
index 0000000..757d704
--- /dev/null
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/ButtonDemo.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.compose.integration.demos
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.unit.dp
+import androidx.wear.compose.material.Button
+import androidx.wear.compose.material.ButtonDefaults
+import androidx.wear.compose.material.CompactButton
+import androidx.wear.compose.material.MaterialTheme
+import androidx.wear.compose.material.Text
+import androidx.wear.compose.material.ToggleButton
+
+@Composable
+fun ButtonDemo() {
+ var enabled by remember { mutableStateOf(true) }
+
+ Column(
+ modifier = Modifier.fillMaxSize(),
+ verticalArrangement = Arrangement.Center,
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ Row(
+ horizontalArrangement = Arrangement.spacedBy(2.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Button(
+ onClick = {},
+ enabled = enabled,
+ modifier = Modifier.size(ButtonDefaults.LargeButtonSize),
+ ) {
+ Text("Lrg")
+ }
+ Button(
+ onClick = {},
+ enabled = enabled,
+ ) {
+ // NB Leave size as default for this one.
+ Text("Def")
+ }
+ Button(
+ onClick = {},
+ enabled = enabled,
+ modifier = Modifier.size(ButtonDefaults.SmallButtonSize),
+ ) {
+ Text("Sml")
+ }
+ CompactButton(
+ onClick = {},
+ enabled = enabled,
+ ) {
+ Text("XS")
+ }
+ }
+ Spacer(modifier = Modifier.size(4.dp))
+ Row(
+ horizontalArrangement = Arrangement.Center,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(
+ text = "Enabled",
+ style = MaterialTheme.typography.caption2,
+ color = Color.White
+ )
+ Spacer(modifier = Modifier.size(4.dp))
+ ToggleButton(
+ checked = enabled,
+ onCheckedChange = {
+ enabled = it
+ },
+ modifier = Modifier.size(ButtonDefaults.SmallButtonSize)
+ ) {
+ Text(text = if (enabled) "Yes" else "No")
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoActivity.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoActivity.kt
new file mode 100644
index 0000000..c74d8d8
--- /dev/null
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoActivity.kt
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.compose.integration.demos
+
+import android.app.Activity
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import androidx.activity.ComponentActivity
+import androidx.activity.OnBackPressedCallback
+import androidx.activity.OnBackPressedDispatcher
+import androidx.compose.integration.demos.common.ActivityDemo
+import androidx.compose.integration.demos.common.Demo
+import androidx.compose.integration.demos.common.DemoCategory
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.Saver
+import androidx.compose.runtime.saveable.listSaver
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.focus.FocusManager
+import androidx.compose.ui.platform.ComposeView
+import androidx.compose.ui.platform.LocalFocusManager
+import androidx.compose.ui.platform.LocalView
+import androidx.wear.compose.material.MaterialTheme
+
+/**
+ * Main [Activity] for Wear Compose related demos.
+ */
+class DemoActivity : ComponentActivity() {
+ lateinit var hostView: View
+ lateinit var focusManager: FocusManager
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ ComposeView(this).also {
+ setContentView(it)
+ }.setContent {
+ hostView = LocalView.current
+ focusManager = LocalFocusManager.current
+ val activityStarter = fun(demo: ActivityDemo<*>) {
+ startActivity(Intent(this, demo.activityClass.java))
+ }
+ val navigator = rememberSaveable(
+ saver = Navigator.Saver(WearComposeDemos, onBackPressedDispatcher, activityStarter)
+ ) {
+ Navigator(WearComposeDemos, onBackPressedDispatcher, activityStarter)
+ }
+ MaterialTheme {
+ DemoApp(
+ currentDemo = navigator.currentDemo,
+ onNavigateToDemo = { demo ->
+ navigator.navigateTo(demo)
+ },
+ )
+ }
+ }
+ }
+}
+
+private class Navigator private constructor(
+ private val backDispatcher: OnBackPressedDispatcher,
+ private val launchActivityDemo: (ActivityDemo<*>) -> Unit,
+ private val rootDemo: Demo,
+ initialDemo: Demo,
+ private val backStack: MutableList<Demo>
+) {
+ constructor(
+ rootDemo: Demo,
+ backDispatcher: OnBackPressedDispatcher,
+ launchActivityDemo: (ActivityDemo<*>) -> Unit
+ ) : this(backDispatcher, launchActivityDemo, rootDemo, rootDemo, mutableListOf<Demo>())
+
+ private val onBackPressed = object : OnBackPressedCallback(false) {
+ override fun handleOnBackPressed() {
+ popBackStack()
+ }
+ }.apply {
+ isEnabled = !isRoot
+ backDispatcher.addCallback(this)
+ }
+
+ private var _currentDemo by mutableStateOf(initialDemo)
+ var currentDemo: Demo
+ get() = _currentDemo
+ private set(value) {
+ _currentDemo = value
+ onBackPressed.isEnabled = !isRoot
+ }
+
+ val isRoot: Boolean get() = backStack.isEmpty()
+
+ val backStackTitle: String
+ get() =
+ (backStack.drop(1) + currentDemo).joinToString(separator = " > ") { it.title }
+
+ fun navigateTo(demo: Demo) {
+ if (demo is ActivityDemo<*>) {
+ launchActivityDemo(demo)
+ } else {
+ backStack.add(currentDemo)
+ currentDemo = demo
+ }
+ }
+
+ fun popAll() {
+ if (!isRoot) {
+ backStack.clear()
+ currentDemo = rootDemo
+ }
+ }
+
+ private fun popBackStack() {
+ currentDemo = backStack.removeAt(backStack.lastIndex)
+ }
+
+ companion object {
+ fun Saver(
+ rootDemo: DemoCategory,
+ backDispatcher: OnBackPressedDispatcher,
+ launchActivityDemo: (ActivityDemo<*>) -> Unit
+ ): Saver<Navigator, *> = listSaver<Navigator, String>(
+ save = { navigator ->
+ (navigator.backStack + navigator.currentDemo).map { it.title }
+ },
+ restore = { restored ->
+ require(restored.isNotEmpty())
+ val backStack = restored.mapTo(mutableListOf()) {
+ requireNotNull(findDemo(rootDemo, it))
+ }
+ val initial = backStack.removeAt(backStack.lastIndex)
+ Navigator(backDispatcher, launchActivityDemo, rootDemo, initial, backStack)
+ }
+ )
+
+ private fun findDemo(demo: Demo, title: String): Demo? {
+ if (demo.title == title) {
+ return demo
+ }
+ if (demo is DemoCategory) {
+ demo.demos.forEach { child ->
+ findDemo(child, title)
+ ?.let { return it }
+ }
+ }
+ return null
+ }
+ }
+}
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoApp.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoApp.kt
new file mode 100644
index 0000000..4e8f1e6
--- /dev/null
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoApp.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.compose.integration.demos
+
+import androidx.compose.animation.Crossfade
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.integration.demos.common.ActivityDemo
+import androidx.compose.integration.demos.common.ComposableDemo
+import androidx.compose.integration.demos.common.Demo
+import androidx.compose.integration.demos.common.DemoCategory
+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.wear.compose.material.ChipDefaults
+import androidx.wear.compose.material.CompactChip
+import androidx.wear.compose.material.MaterialTheme
+import androidx.wear.compose.material.Text
+
+@Composable
+fun DemoApp(
+ currentDemo: Demo,
+ onNavigateToDemo: (Demo) -> Unit,
+) {
+ DemoContent(currentDemo, onNavigateToDemo)
+}
+
+@Composable
+private fun DemoContent(
+ currentDemo: Demo,
+ onNavigate: (Demo) -> Unit,
+) {
+ Crossfade(currentDemo) { demo ->
+ DisplayDemo(demo, onNavigate)
+ }
+}
+
+@Composable
+private fun DisplayDemo(demo: Demo, onNavigate: (Demo) -> Unit) {
+ when (demo) {
+ is ActivityDemo<*> -> {
+ /* should never get here as activity demos are not added to the backstack*/
+ }
+ is ComposableDemo -> demo.content()
+ is DemoCategory -> DisplayDemoList(demo, onNavigate)
+ }
+}
+
+@Composable
+private fun DisplayDemoList(category: DemoCategory, onNavigate: (Demo) -> Unit) {
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ modifier = Modifier.fillMaxWidth().verticalScroll(rememberScrollState())
+ ) {
+ Spacer(modifier = Modifier.size(16.dp))
+ Text(
+ text = category.title,
+ style = MaterialTheme.typography.caption1,
+ color = Color.White
+ )
+ Spacer(modifier = Modifier.size(4.dp))
+ category.demos.forEach { demo ->
+ CompactChip(
+ onClick = { onNavigate(demo) },
+ colors = ChipDefaults.secondaryChipColors(),
+ label = {
+ Text(
+ text = demo.title,
+ modifier = Modifier.align(Alignment.CenterHorizontally)
+ )
+ },
+ modifier = Modifier.width(100.dp)
+ )
+ }
+ }
+}
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/Demos.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/Demos.kt
new file mode 100644
index 0000000..125bb33
--- /dev/null
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/Demos.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.compose.integration.demos
+
+import androidx.compose.integration.demos.common.DemoCategory
+
+/**
+ * [DemoCategory] containing all the top level demo categories.
+ */
+val WearComposeDemos = DemoCategory(
+ "Wear Compose Demos",
+ listOf(
+ WearMaterialDemos,
+ )
+)
\ No newline at end of file
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/MaterialDemos.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/MaterialDemos.kt
new file mode 100644
index 0000000..34fedc1
--- /dev/null
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/MaterialDemos.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.compose.integration.demos
+
+import androidx.compose.integration.demos.common.ComposableDemo
+import androidx.compose.integration.demos.common.DemoCategory
+
+val WearMaterialDemos = DemoCategory(
+ "Material",
+ listOf(
+ ComposableDemo("Button") { ButtonDemo() },
+ ),
+)
diff --git a/wear/compose/integration-tests/demos/src/main/res/mipmap-hdpi/ic_launcher.webp b/wear/compose/integration-tests/demos/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..c209e78
--- /dev/null
+++ b/wear/compose/integration-tests/demos/src/main/res/mipmap-hdpi/ic_launcher.webp
Binary files differ
diff --git a/wear/compose/integration-tests/demos/src/main/res/mipmap-mdpi/ic_launcher.webp b/wear/compose/integration-tests/demos/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..4f0f1d6
--- /dev/null
+++ b/wear/compose/integration-tests/demos/src/main/res/mipmap-mdpi/ic_launcher.webp
Binary files differ
diff --git a/wear/compose/integration-tests/demos/src/main/res/mipmap-xhdpi/ic_launcher.webp b/wear/compose/integration-tests/demos/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..948a307
--- /dev/null
+++ b/wear/compose/integration-tests/demos/src/main/res/mipmap-xhdpi/ic_launcher.webp
Binary files differ
diff --git a/wear/compose/integration-tests/demos/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/wear/compose/integration-tests/demos/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..28d4b77
--- /dev/null
+++ b/wear/compose/integration-tests/demos/src/main/res/mipmap-xxhdpi/ic_launcher.webp
Binary files differ
diff --git a/wear/compose/integration-tests/demos/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/wear/compose/integration-tests/demos/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..aa7d642
--- /dev/null
+++ b/wear/compose/integration-tests/demos/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
Binary files differ
diff --git a/wear/compose/integration-tests/demos/src/main/res/values/strings.xml b/wear/compose/integration-tests/demos/src/main/res/values/strings.xml
new file mode 100644
index 0000000..8086034
--- /dev/null
+++ b/wear/compose/integration-tests/demos/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+ <string name="app_name">Wear Compose Integration Demos</string>
+</resources>
\ No newline at end of file
diff --git a/wear/wear-complications-data/src/main/java/androidx/wear/complications/ComplicationHelperActivity.java b/wear/wear-complications-data/src/main/java/androidx/wear/complications/ComplicationHelperActivity.java
index 10b577e..1a66ba7 100644
--- a/wear/wear-complications-data/src/main/java/androidx/wear/complications/ComplicationHelperActivity.java
+++ b/wear/wear-complications-data/src/main/java/androidx/wear/complications/ComplicationHelperActivity.java
@@ -168,6 +168,7 @@
int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (grantResults.length == 0) {
// Request was cancelled.
+ finish();
return;
}
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
diff --git a/wear/wear-watchface-client/api/current.txt b/wear/wear-watchface-client/api/current.txt
index 286846e..7a48103 100644
--- a/wear/wear-watchface-client/api/current.txt
+++ b/wear/wear-watchface-client/api/current.txt
@@ -72,7 +72,7 @@
public interface HeadlessWatchFaceClient extends java.lang.AutoCloseable {
method @AnyThread public void addClientDisconnectListener(androidx.wear.watchface.client.HeadlessWatchFaceClient.ClientDisconnectListener listener, java.util.concurrent.Executor executor);
method public default static androidx.wear.watchface.client.HeadlessWatchFaceClient createFromBundle(android.os.Bundle bundle);
- method public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> getComplicationsSlotState();
+ method public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> getComplicationSlotsState();
method public long getPreviewReferenceTimeMillis();
method public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema();
method @AnyThread public boolean isConnectionAlive();
@@ -80,7 +80,7 @@
method @RequiresApi(27) public android.graphics.Bitmap? renderComplicationToBitmap(int complicationSlotId, androidx.wear.watchface.RenderParameters renderParameters, long calendarTimeMillis, androidx.wear.complications.data.ComplicationData complicationData, androidx.wear.watchface.style.UserStyle? userStyle);
method @RequiresApi(27) public android.graphics.Bitmap renderWatchFaceToBitmap(androidx.wear.watchface.RenderParameters renderParameters, long calendarTimeMillis, androidx.wear.watchface.style.UserStyle? userStyle, java.util.Map<java.lang.Integer,? extends androidx.wear.complications.data.ComplicationData>? slotIdToComplicationData);
method public android.os.Bundle toBundle();
- property public abstract java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> complicationsSlotState;
+ property public abstract java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> complicationSlotsState;
property public abstract long previewReferenceTimeMillis;
property public abstract androidx.wear.watchface.style.UserStyleSchema userStyleSchema;
field public static final String BINDER_KEY = "HeadlessWatchFaceClient";
@@ -99,7 +99,7 @@
method @AnyThread public void addClientDisconnectListener(androidx.wear.watchface.client.InteractiveWatchFaceClient.ClientDisconnectListener listener, java.util.concurrent.Executor executor);
method public void displayPressedAnimation(int complicationSlotId);
method public default Integer? getComplicationIdAt(@Px int x, @Px int y);
- method public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> getComplicationsSlotState();
+ method public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> getComplicationSlotsState();
method public java.util.List<androidx.wear.watchface.ContentDescriptionLabel> getContentDescriptionLabels();
method public String getInstanceId();
method public long getPreviewReferenceTimeMillis();
@@ -113,7 +113,7 @@
method public void updateComplicationData(java.util.Map<java.lang.Integer,? extends androidx.wear.complications.data.ComplicationData> slotIdToComplicationData);
method public void updateWatchFaceInstance(String newInstanceId, androidx.wear.watchface.style.UserStyle userStyle);
method public void updateWatchFaceInstance(String newInstanceId, androidx.wear.watchface.style.UserStyleData userStyle);
- property public abstract java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> complicationsSlotState;
+ property public abstract java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> complicationSlotsState;
property public abstract java.util.List<androidx.wear.watchface.ContentDescriptionLabel> contentDescriptionLabels;
property public abstract String instanceId;
property public abstract long previewReferenceTimeMillis;
diff --git a/wear/wear-watchface-client/api/public_plus_experimental_current.txt b/wear/wear-watchface-client/api/public_plus_experimental_current.txt
index 286846e..7a48103 100644
--- a/wear/wear-watchface-client/api/public_plus_experimental_current.txt
+++ b/wear/wear-watchface-client/api/public_plus_experimental_current.txt
@@ -72,7 +72,7 @@
public interface HeadlessWatchFaceClient extends java.lang.AutoCloseable {
method @AnyThread public void addClientDisconnectListener(androidx.wear.watchface.client.HeadlessWatchFaceClient.ClientDisconnectListener listener, java.util.concurrent.Executor executor);
method public default static androidx.wear.watchface.client.HeadlessWatchFaceClient createFromBundle(android.os.Bundle bundle);
- method public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> getComplicationsSlotState();
+ method public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> getComplicationSlotsState();
method public long getPreviewReferenceTimeMillis();
method public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema();
method @AnyThread public boolean isConnectionAlive();
@@ -80,7 +80,7 @@
method @RequiresApi(27) public android.graphics.Bitmap? renderComplicationToBitmap(int complicationSlotId, androidx.wear.watchface.RenderParameters renderParameters, long calendarTimeMillis, androidx.wear.complications.data.ComplicationData complicationData, androidx.wear.watchface.style.UserStyle? userStyle);
method @RequiresApi(27) public android.graphics.Bitmap renderWatchFaceToBitmap(androidx.wear.watchface.RenderParameters renderParameters, long calendarTimeMillis, androidx.wear.watchface.style.UserStyle? userStyle, java.util.Map<java.lang.Integer,? extends androidx.wear.complications.data.ComplicationData>? slotIdToComplicationData);
method public android.os.Bundle toBundle();
- property public abstract java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> complicationsSlotState;
+ property public abstract java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> complicationSlotsState;
property public abstract long previewReferenceTimeMillis;
property public abstract androidx.wear.watchface.style.UserStyleSchema userStyleSchema;
field public static final String BINDER_KEY = "HeadlessWatchFaceClient";
@@ -99,7 +99,7 @@
method @AnyThread public void addClientDisconnectListener(androidx.wear.watchface.client.InteractiveWatchFaceClient.ClientDisconnectListener listener, java.util.concurrent.Executor executor);
method public void displayPressedAnimation(int complicationSlotId);
method public default Integer? getComplicationIdAt(@Px int x, @Px int y);
- method public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> getComplicationsSlotState();
+ method public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> getComplicationSlotsState();
method public java.util.List<androidx.wear.watchface.ContentDescriptionLabel> getContentDescriptionLabels();
method public String getInstanceId();
method public long getPreviewReferenceTimeMillis();
@@ -113,7 +113,7 @@
method public void updateComplicationData(java.util.Map<java.lang.Integer,? extends androidx.wear.complications.data.ComplicationData> slotIdToComplicationData);
method public void updateWatchFaceInstance(String newInstanceId, androidx.wear.watchface.style.UserStyle userStyle);
method public void updateWatchFaceInstance(String newInstanceId, androidx.wear.watchface.style.UserStyleData userStyle);
- property public abstract java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> complicationsSlotState;
+ property public abstract java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> complicationSlotsState;
property public abstract java.util.List<androidx.wear.watchface.ContentDescriptionLabel> contentDescriptionLabels;
property public abstract String instanceId;
property public abstract long previewReferenceTimeMillis;
diff --git a/wear/wear-watchface-client/api/restricted_current.txt b/wear/wear-watchface-client/api/restricted_current.txt
index 4600381..056d19d 100644
--- a/wear/wear-watchface-client/api/restricted_current.txt
+++ b/wear/wear-watchface-client/api/restricted_current.txt
@@ -74,7 +74,7 @@
public interface HeadlessWatchFaceClient extends java.lang.AutoCloseable {
method @AnyThread public void addClientDisconnectListener(androidx.wear.watchface.client.HeadlessWatchFaceClient.ClientDisconnectListener listener, java.util.concurrent.Executor executor);
method public default static androidx.wear.watchface.client.HeadlessWatchFaceClient createFromBundle(android.os.Bundle bundle);
- method public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> getComplicationsSlotState();
+ method public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> getComplicationSlotsState();
method public long getPreviewReferenceTimeMillis();
method public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema();
method @AnyThread public boolean isConnectionAlive();
@@ -82,7 +82,7 @@
method @RequiresApi(27) public android.graphics.Bitmap? renderComplicationToBitmap(int complicationSlotId, androidx.wear.watchface.RenderParameters renderParameters, long calendarTimeMillis, androidx.wear.complications.data.ComplicationData complicationData, androidx.wear.watchface.style.UserStyle? userStyle);
method @RequiresApi(27) public android.graphics.Bitmap renderWatchFaceToBitmap(androidx.wear.watchface.RenderParameters renderParameters, long calendarTimeMillis, androidx.wear.watchface.style.UserStyle? userStyle, java.util.Map<java.lang.Integer,? extends androidx.wear.complications.data.ComplicationData>? slotIdToComplicationData);
method public android.os.Bundle toBundle();
- property public abstract java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> complicationsSlotState;
+ property public abstract java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> complicationSlotsState;
property public abstract long previewReferenceTimeMillis;
property public abstract androidx.wear.watchface.style.UserStyleSchema userStyleSchema;
field public static final String BINDER_KEY = "HeadlessWatchFaceClient";
@@ -101,7 +101,7 @@
method @AnyThread public void addClientDisconnectListener(androidx.wear.watchface.client.InteractiveWatchFaceClient.ClientDisconnectListener listener, java.util.concurrent.Executor executor);
method public void displayPressedAnimation(int complicationSlotId);
method public default Integer? getComplicationIdAt(@Px int x, @Px int y);
- method public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> getComplicationsSlotState();
+ method public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> getComplicationSlotsState();
method public java.util.List<androidx.wear.watchface.ContentDescriptionLabel> getContentDescriptionLabels();
method public String getInstanceId();
method public long getPreviewReferenceTimeMillis();
@@ -115,7 +115,7 @@
method public void updateComplicationData(java.util.Map<java.lang.Integer,? extends androidx.wear.complications.data.ComplicationData> slotIdToComplicationData);
method public void updateWatchFaceInstance(String newInstanceId, androidx.wear.watchface.style.UserStyle userStyle);
method public void updateWatchFaceInstance(String newInstanceId, androidx.wear.watchface.style.UserStyleData userStyle);
- property public abstract java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> complicationsSlotState;
+ property public abstract java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> complicationSlotsState;
property public abstract java.util.List<androidx.wear.watchface.ContentDescriptionLabel> contentDescriptionLabels;
property public abstract String instanceId;
property public abstract long previewReferenceTimeMillis;
diff --git a/wear/wear-watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/WatchFaceControlClientTest.kt b/wear/wear-watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/WatchFaceControlClientTest.kt
index cba4daf..87c4eab 100644
--- a/wear/wear-watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/WatchFaceControlClientTest.kt
+++ b/wear/wear-watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/WatchFaceControlClientTest.kt
@@ -304,9 +304,9 @@
400
)!!
- assertThat(headlessInstance.complicationsSlotState.size).isEqualTo(2)
+ assertThat(headlessInstance.complicationSlotsState.size).isEqualTo(2)
- val leftComplicationDetails = headlessInstance.complicationsSlotState[
+ val leftComplicationDetails = headlessInstance.complicationSlotsState[
EXAMPLE_CANVAS_WATCHFACE_LEFT_COMPLICATION_ID
]!!
assertThat(leftComplicationDetails.bounds).isEqualTo(Rect(80, 160, 160, 240))
@@ -327,7 +327,7 @@
)
assertTrue(leftComplicationDetails.isEnabled)
- val rightComplicationDetails = headlessInstance.complicationsSlotState[
+ val rightComplicationDetails = headlessInstance.complicationSlotsState[
EXAMPLE_CANVAS_WATCHFACE_RIGHT_COMPLICATION_ID
]!!
assertThat(rightComplicationDetails.bounds).isEqualTo(Rect(240, 160, 320, 240))
@@ -501,9 +501,9 @@
)
)
- assertThat(interactiveInstance.complicationsSlotState.size).isEqualTo(2)
+ assertThat(interactiveInstance.complicationSlotsState.size).isEqualTo(2)
- val leftComplicationDetails = interactiveInstance.complicationsSlotState[
+ val leftComplicationDetails = interactiveInstance.complicationSlotsState[
EXAMPLE_CANVAS_WATCHFACE_LEFT_COMPLICATION_ID
]!!
assertThat(leftComplicationDetails.bounds).isEqualTo(Rect(80, 160, 160, 240))
@@ -527,7 +527,7 @@
ComplicationType.SHORT_TEXT
)
- val rightComplicationDetails = interactiveInstance.complicationsSlotState[
+ val rightComplicationDetails = interactiveInstance.complicationSlotsState[
EXAMPLE_CANVAS_WATCHFACE_RIGHT_COMPLICATION_ID
]!!
assertThat(rightComplicationDetails.bounds).isEqualTo(Rect(240, 160, 320, 240))
@@ -689,7 +689,7 @@
// We need to wait for watch face init to have completed before lateinit
// wallpaperService.watchFace will be assigned. To do this we issue an arbitrary API
// call which by necessity awaits full initialization.
- interactiveInstance.complicationsSlotState
+ interactiveInstance.complicationSlotsState
// Add some additional ContentDescriptionLabels
wallpaperService.watchFace.renderer.additionalContentDescriptionLabels = listOf(
@@ -785,10 +785,10 @@
assertThat(interactiveInstance.instanceId).isEqualTo("testId2")
// The complicationSlots should have been cleared.
- val leftComplication = interactiveInstance.complicationsSlotState[
+ val leftComplication = interactiveInstance.complicationSlotsState[
EXAMPLE_CANVAS_WATCHFACE_LEFT_COMPLICATION_ID
]!!
- val rightComplication = interactiveInstance.complicationsSlotState[
+ val rightComplication = interactiveInstance.complicationSlotsState[
EXAMPLE_CANVAS_WATCHFACE_RIGHT_COMPLICATION_ID
]!!
assertThat(leftComplication.currentType).isEqualTo(ComplicationType.NO_DATA)
@@ -867,7 +867,7 @@
try {
// The first call on the interface should report the crash.
- awaitWithTimeout(client).complicationsSlotState
+ awaitWithTimeout(client).complicationSlotsState
fail("Expected an exception to be thrown because the watchface crashed on init")
} catch (e: Exception) {
assertThat(e.toString()).contains("Deliberately crashing")
@@ -978,7 +978,7 @@
): ComplicationSlotsManager {
return ComplicationSlotsManager(
listOf(
- ComplicationSlot.createRoundRectComplicationBuilder(
+ ComplicationSlot.createRoundRectComplicationSlotBuilder(
COMPLICATION_ID,
{ _, _ -> throw Exception("Deliberately crashing") },
listOf(ComplicationType.LONG_TEXT),
diff --git a/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/HeadlessWatchFaceClient.kt b/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/HeadlessWatchFaceClient.kt
index 10bb17a..6ab859e 100644
--- a/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/HeadlessWatchFaceClient.kt
+++ b/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/HeadlessWatchFaceClient.kt
@@ -67,7 +67,7 @@
* [ComplicationSlotsUserStyleSetting]. Because the style can't change, ComplicationSlotState is
* immutable for a headless watch face.
*/
- public val complicationsSlotState: Map<Int, ComplicationSlotState>
+ public val complicationSlotsState: Map<Int, ComplicationSlotState>
/**
* Renders the watchface to a shared memory backed [Bitmap] with the given settings.
@@ -170,7 +170,7 @@
override val userStyleSchema: UserStyleSchema
get() = UserStyleSchema(iHeadlessWatchFace.userStyleSchema)
- override val complicationsSlotState: Map<Int, ComplicationSlotState>
+ override val complicationSlotsState: Map<Int, ComplicationSlotState>
get() = iHeadlessWatchFace.complicationState.associateBy(
{ it.id },
{ ComplicationSlotState(it.complicationState) }
diff --git a/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/InteractiveWatchFaceClient.kt b/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/InteractiveWatchFaceClient.kt
index 7e341e1..f3594f2 100644
--- a/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/InteractiveWatchFaceClient.kt
+++ b/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/InteractiveWatchFaceClient.kt
@@ -110,7 +110,7 @@
* [ComplicationSlotsUserStyleSetting]. As a consequence ComplicationSlotState may update based
* on style changes.
*/
- public val complicationsSlotState: Map<Int, ComplicationSlotState>
+ public val complicationSlotsState: Map<Int, ComplicationSlotState>
/**
* Returns the ID of the [androidx.wear.watchface.ComplicationSlot] at the given coordinates or
@@ -118,7 +118,7 @@
*/
@SuppressWarnings("AutoBoxing")
public fun getComplicationIdAt(@Px x: Int, @Px y: Int): Int? =
- complicationsSlotState.asSequence().firstOrNull {
+ complicationSlotsState.asSequence().firstOrNull {
it.value.isEnabled && when (it.value.boundsType) {
ComplicationSlotBoundsType.ROUND_RECT -> it.value.bounds.contains(x, y)
ComplicationSlotBoundsType.BACKGROUND -> false
@@ -281,7 +281,7 @@
override val userStyleSchema: UserStyleSchema
get() = UserStyleSchema(iInteractiveWatchFace.userStyleSchema)
- override val complicationsSlotState: Map<Int, ComplicationSlotState>
+ override val complicationSlotsState: Map<Int, ComplicationSlotState>
get() = iInteractiveWatchFace.complicationDetails.associateBy(
{ it.id },
{ ComplicationSlotState(it.complicationState) }
diff --git a/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceControlClient.kt b/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceControlClient.kt
index ae1e00b..c95610e 100644
--- a/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceControlClient.kt
+++ b/wear/wear-watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceControlClient.kt
@@ -385,7 +385,7 @@
// NB .use {} syntax doesn't compile here.
try {
- headlessClient.complicationsSlotState.mapValues {
+ headlessClient.complicationSlotsState.mapValues {
DefaultComplicationProviderPolicyAndType(
it.value.defaultProviderPolicy,
it.value.defaultProviderType
diff --git a/wear/wear-watchface-editor/src/androidTest/java/androidx/wear/watchface/editor/EditingSessionTest.kt b/wear/wear-watchface-editor/src/androidTest/java/androidx/wear/watchface/editor/EditingSessionTest.kt
index 7e4fb70..9657d08 100644
--- a/wear/wear-watchface-editor/src/androidTest/java/androidx/wear/watchface/editor/EditingSessionTest.kt
+++ b/wear/wear-watchface-editor/src/androidTest/java/androidx/wear/watchface/editor/EditingSessionTest.kt
@@ -321,7 +321,7 @@
mockInvalidateCallback
)
private val leftComplication =
- ComplicationSlot.createRoundRectComplicationBuilder(
+ ComplicationSlot.createRoundRectComplicationSlotBuilder(
LEFT_COMPLICATION_ID,
{ _, _ -> mockLeftCanvasComplication },
listOf(
@@ -342,7 +342,7 @@
mockInvalidateCallback
)
private val rightComplication =
- ComplicationSlot.createRoundRectComplicationBuilder(
+ ComplicationSlot.createRoundRectComplicationSlotBuilder(
RIGHT_COMPLICATION_ID,
{ _, _ -> mockRightCanvasComplication },
listOf(
@@ -369,7 +369,7 @@
mockInvalidateCallback
)
private val backgroundComplication =
- ComplicationSlot.createBackgroundComplicationBuilder(
+ ComplicationSlot.createBackgroundComplicationSlotBuilder(
BACKGROUND_COMPLICATION_ID,
{ _, _ -> mockBackgroundCanvasComplication },
emptyList(),
@@ -624,7 +624,7 @@
mockInvalidateCallback
)
val fixedLeftComplication =
- ComplicationSlot.createRoundRectComplicationBuilder(
+ ComplicationSlot.createRoundRectComplicationSlotBuilder(
LEFT_COMPLICATION_ID,
{ _, _ -> mockLeftCanvasComplication },
listOf(
diff --git a/wear/wear-watchface-editor/src/androidTest/java/androidx/wear/watchface/editor/EditorSessionGuavaTest.kt b/wear/wear-watchface-editor/src/androidTest/java/androidx/wear/watchface/editor/EditorSessionGuavaTest.kt
index b37a4ef..ec2cdf6 100644
--- a/wear/wear-watchface-editor/src/androidTest/java/androidx/wear/watchface/editor/EditorSessionGuavaTest.kt
+++ b/wear/wear-watchface-editor/src/androidTest/java/androidx/wear/watchface/editor/EditorSessionGuavaTest.kt
@@ -73,7 +73,7 @@
mockInvalidateCallback
)
private val leftComplication =
- ComplicationSlot.createRoundRectComplicationBuilder(
+ ComplicationSlot.createRoundRectComplicationSlotBuilder(
LEFT_COMPLICATION_ID,
{ _, _, -> mockLeftCanvasComplication },
listOf(
@@ -95,7 +95,7 @@
mockInvalidateCallback
)
private val rightComplication =
- ComplicationSlot.createRoundRectComplicationBuilder(
+ ComplicationSlot.createRoundRectComplicationSlotBuilder(
RIGHT_COMPLICATION_ID,
{ _, _, -> mockRightCanvasComplication },
listOf(
diff --git a/wear/wear-watchface-editor/src/main/java/androidx/wear/watchface/editor/EditorSession.kt b/wear/wear-watchface-editor/src/main/java/androidx/wear/watchface/editor/EditorSession.kt
index 00766da..d7863a8 100644
--- a/wear/wear-watchface-editor/src/main/java/androidx/wear/watchface/editor/EditorSession.kt
+++ b/wear/wear-watchface-editor/src/main/java/androidx/wear/watchface/editor/EditorSession.kt
@@ -738,7 +738,7 @@
override val previewReferenceTimeMillis = headlessWatchFaceClient.previewReferenceTimeMillis
- override val complicationSlotsState = headlessWatchFaceClient.complicationsSlotState
+ override val complicationSlotsState = headlessWatchFaceClient.complicationSlotsState
override fun renderWatchFaceToBitmap(
renderParameters: RenderParameters,
diff --git a/wear/wear-watchface/api/current.txt b/wear/wear-watchface/api/current.txt
index cb50825..e0ea586 100644
--- a/wear/wear-watchface/api/current.txt
+++ b/wear/wear-watchface/api/current.txt
@@ -27,9 +27,9 @@
public final class ComplicationSlot {
method public android.graphics.Rect computeBounds(android.graphics.Rect screen);
- method public static androidx.wear.watchface.ComplicationSlot.Builder createBackgroundComplicationBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy);
- method public static androidx.wear.watchface.ComplicationSlot.Builder createEdgeComplicationBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy, androidx.wear.complications.ComplicationSlotBounds bounds, androidx.wear.watchface.ComplicationTapFilter complicationTapFilter);
- method public static androidx.wear.watchface.ComplicationSlot.Builder createRoundRectComplicationBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy, androidx.wear.complications.ComplicationSlotBounds bounds);
+ method public static androidx.wear.watchface.ComplicationSlot.Builder createBackgroundComplicationSlotBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy);
+ method public static androidx.wear.watchface.ComplicationSlot.Builder createEdgeComplicationSlotBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy, androidx.wear.complications.ComplicationSlotBounds bounds, androidx.wear.watchface.ComplicationTapFilter complicationTapFilter);
+ method public static androidx.wear.watchface.ComplicationSlot.Builder createRoundRectComplicationSlotBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy, androidx.wear.complications.ComplicationSlotBounds bounds);
method @UiThread public int getAccessibilityTraversalIndex();
method public int getBoundsType();
method public androidx.wear.watchface.CanvasComplicationFactory getCanvasComplicationFactory();
@@ -76,9 +76,9 @@
}
public static final class ComplicationSlot.Companion {
- method public androidx.wear.watchface.ComplicationSlot.Builder createBackgroundComplicationBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy);
- method public androidx.wear.watchface.ComplicationSlot.Builder createEdgeComplicationBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy, androidx.wear.complications.ComplicationSlotBounds bounds, androidx.wear.watchface.ComplicationTapFilter complicationTapFilter);
- method public androidx.wear.watchface.ComplicationSlot.Builder createRoundRectComplicationBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy, androidx.wear.complications.ComplicationSlotBounds bounds);
+ method public androidx.wear.watchface.ComplicationSlot.Builder createBackgroundComplicationSlotBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy);
+ method public androidx.wear.watchface.ComplicationSlot.Builder createEdgeComplicationSlotBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy, androidx.wear.complications.ComplicationSlotBounds bounds, androidx.wear.watchface.ComplicationTapFilter complicationTapFilter);
+ method public androidx.wear.watchface.ComplicationSlot.Builder createRoundRectComplicationSlotBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy, androidx.wear.complications.ComplicationSlotBounds bounds);
}
public final class ComplicationSlotsManager {
diff --git a/wear/wear-watchface/api/public_plus_experimental_current.txt b/wear/wear-watchface/api/public_plus_experimental_current.txt
index cb50825..e0ea586 100644
--- a/wear/wear-watchface/api/public_plus_experimental_current.txt
+++ b/wear/wear-watchface/api/public_plus_experimental_current.txt
@@ -27,9 +27,9 @@
public final class ComplicationSlot {
method public android.graphics.Rect computeBounds(android.graphics.Rect screen);
- method public static androidx.wear.watchface.ComplicationSlot.Builder createBackgroundComplicationBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy);
- method public static androidx.wear.watchface.ComplicationSlot.Builder createEdgeComplicationBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy, androidx.wear.complications.ComplicationSlotBounds bounds, androidx.wear.watchface.ComplicationTapFilter complicationTapFilter);
- method public static androidx.wear.watchface.ComplicationSlot.Builder createRoundRectComplicationBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy, androidx.wear.complications.ComplicationSlotBounds bounds);
+ method public static androidx.wear.watchface.ComplicationSlot.Builder createBackgroundComplicationSlotBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy);
+ method public static androidx.wear.watchface.ComplicationSlot.Builder createEdgeComplicationSlotBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy, androidx.wear.complications.ComplicationSlotBounds bounds, androidx.wear.watchface.ComplicationTapFilter complicationTapFilter);
+ method public static androidx.wear.watchface.ComplicationSlot.Builder createRoundRectComplicationSlotBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy, androidx.wear.complications.ComplicationSlotBounds bounds);
method @UiThread public int getAccessibilityTraversalIndex();
method public int getBoundsType();
method public androidx.wear.watchface.CanvasComplicationFactory getCanvasComplicationFactory();
@@ -76,9 +76,9 @@
}
public static final class ComplicationSlot.Companion {
- method public androidx.wear.watchface.ComplicationSlot.Builder createBackgroundComplicationBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy);
- method public androidx.wear.watchface.ComplicationSlot.Builder createEdgeComplicationBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy, androidx.wear.complications.ComplicationSlotBounds bounds, androidx.wear.watchface.ComplicationTapFilter complicationTapFilter);
- method public androidx.wear.watchface.ComplicationSlot.Builder createRoundRectComplicationBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy, androidx.wear.complications.ComplicationSlotBounds bounds);
+ method public androidx.wear.watchface.ComplicationSlot.Builder createBackgroundComplicationSlotBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy);
+ method public androidx.wear.watchface.ComplicationSlot.Builder createEdgeComplicationSlotBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy, androidx.wear.complications.ComplicationSlotBounds bounds, androidx.wear.watchface.ComplicationTapFilter complicationTapFilter);
+ method public androidx.wear.watchface.ComplicationSlot.Builder createRoundRectComplicationSlotBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy, androidx.wear.complications.ComplicationSlotBounds bounds);
}
public final class ComplicationSlotsManager {
diff --git a/wear/wear-watchface/api/restricted_current.txt b/wear/wear-watchface/api/restricted_current.txt
index bc6df21..43dc248 100644
--- a/wear/wear-watchface/api/restricted_current.txt
+++ b/wear/wear-watchface/api/restricted_current.txt
@@ -53,9 +53,9 @@
public final class ComplicationSlot {
method public android.graphics.Rect computeBounds(android.graphics.Rect screen);
- method public static androidx.wear.watchface.ComplicationSlot.Builder createBackgroundComplicationBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy);
- method public static androidx.wear.watchface.ComplicationSlot.Builder createEdgeComplicationBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy, androidx.wear.complications.ComplicationSlotBounds bounds, androidx.wear.watchface.ComplicationTapFilter complicationTapFilter);
- method public static androidx.wear.watchface.ComplicationSlot.Builder createRoundRectComplicationBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy, androidx.wear.complications.ComplicationSlotBounds bounds);
+ method public static androidx.wear.watchface.ComplicationSlot.Builder createBackgroundComplicationSlotBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy);
+ method public static androidx.wear.watchface.ComplicationSlot.Builder createEdgeComplicationSlotBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy, androidx.wear.complications.ComplicationSlotBounds bounds, androidx.wear.watchface.ComplicationTapFilter complicationTapFilter);
+ method public static androidx.wear.watchface.ComplicationSlot.Builder createRoundRectComplicationSlotBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy, androidx.wear.complications.ComplicationSlotBounds bounds);
method @UiThread public int getAccessibilityTraversalIndex();
method public int getBoundsType();
method public androidx.wear.watchface.CanvasComplicationFactory getCanvasComplicationFactory();
@@ -102,9 +102,9 @@
}
public static final class ComplicationSlot.Companion {
- method public androidx.wear.watchface.ComplicationSlot.Builder createBackgroundComplicationBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy);
- method public androidx.wear.watchface.ComplicationSlot.Builder createEdgeComplicationBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy, androidx.wear.complications.ComplicationSlotBounds bounds, androidx.wear.watchface.ComplicationTapFilter complicationTapFilter);
- method public androidx.wear.watchface.ComplicationSlot.Builder createRoundRectComplicationBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy, androidx.wear.complications.ComplicationSlotBounds bounds);
+ method public androidx.wear.watchface.ComplicationSlot.Builder createBackgroundComplicationSlotBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy);
+ method public androidx.wear.watchface.ComplicationSlot.Builder createEdgeComplicationSlotBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy, androidx.wear.complications.ComplicationSlotBounds bounds, androidx.wear.watchface.ComplicationTapFilter complicationTapFilter);
+ method public androidx.wear.watchface.ComplicationSlot.Builder createRoundRectComplicationSlotBuilder(int id, androidx.wear.watchface.CanvasComplicationFactory canvasComplicationFactory, java.util.List<? extends androidx.wear.complications.data.ComplicationType> supportedTypes, androidx.wear.complications.DefaultComplicationProviderPolicy defaultProviderPolicy, androidx.wear.complications.ComplicationSlotBounds bounds);
}
public final class ComplicationSlotsManager {
diff --git a/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasAnalogWatchFaceService.kt b/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasAnalogWatchFaceService.kt
index edcf7f8..a1240d2 100644
--- a/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasAnalogWatchFaceService.kt
+++ b/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasAnalogWatchFaceService.kt
@@ -231,7 +231,7 @@
listener
)
}
- val leftComplication = ComplicationSlot.createRoundRectComplicationBuilder(
+ val leftComplication = ComplicationSlot.createRoundRectComplicationSlotBuilder(
EXAMPLE_CANVAS_WATCHFACE_LEFT_COMPLICATION_ID,
canvasComplicationFactory,
listOf(
@@ -245,7 +245,7 @@
ComplicationSlotBounds(RectF(0.2f, 0.4f, 0.4f, 0.6f))
).setDefaultProviderType(ComplicationType.SHORT_TEXT)
.build()
- val rightComplication = ComplicationSlot.createRoundRectComplicationBuilder(
+ val rightComplication = ComplicationSlot.createRoundRectComplicationSlotBuilder(
EXAMPLE_CANVAS_WATCHFACE_RIGHT_COMPLICATION_ID,
canvasComplicationFactory,
listOf(
diff --git a/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasDigitalWatchFaceService.kt b/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasDigitalWatchFaceService.kt
index a9367ed..2725dfb 100644
--- a/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasDigitalWatchFaceService.kt
+++ b/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasDigitalWatchFaceService.kt
@@ -509,7 +509,7 @@
)
}
- private val leftComplication = ComplicationSlot.createRoundRectComplicationBuilder(
+ private val leftComplication = ComplicationSlot.createRoundRectComplicationSlotBuilder(
ComplicationID.LEFT.ordinal,
canvasComplicationFactory,
listOf(
@@ -528,7 +528,7 @@
).setDefaultProviderType(ComplicationType.SHORT_TEXT)
.build()
- private val rightComplication = ComplicationSlot.createRoundRectComplicationBuilder(
+ private val rightComplication = ComplicationSlot.createRoundRectComplicationSlotBuilder(
ComplicationID.RIGHT.ordinal,
canvasComplicationFactory,
listOf(
@@ -555,7 +555,7 @@
ComplicationType.SMALL_IMAGE
)
// The upper and lower complicationSlots change shape depending on the complication's type.
- private val upperComplication = ComplicationSlot.createRoundRectComplicationBuilder(
+ private val upperComplication = ComplicationSlot.createRoundRectComplicationSlotBuilder(
ComplicationID.UPPER.ordinal,
canvasComplicationFactory,
upperAndLowerComplicationTypes,
@@ -578,7 +578,7 @@
).setDefaultProviderType(ComplicationType.LONG_TEXT)
.build()
- private val lowerComplication = ComplicationSlot.createRoundRectComplicationBuilder(
+ private val lowerComplication = ComplicationSlot.createRoundRectComplicationSlotBuilder(
ComplicationID.LOWER.ordinal,
canvasComplicationFactory,
upperAndLowerComplicationTypes,
@@ -601,7 +601,7 @@
).setDefaultProviderType(ComplicationType.LONG_TEXT)
.build()
- private val backgroundComplication = ComplicationSlot.createBackgroundComplicationBuilder(
+ private val backgroundComplication = ComplicationSlot.createBackgroundComplicationSlotBuilder(
ComplicationID.BACKGROUND.ordinal,
canvasComplicationFactory,
listOf(ComplicationType.PHOTO_IMAGE),
diff --git a/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleOpenGLWatchFaceService.kt b/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleOpenGLWatchFaceService.kt
index 0c3adf8..e131161 100644
--- a/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleOpenGLWatchFaceService.kt
+++ b/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleOpenGLWatchFaceService.kt
@@ -105,7 +105,7 @@
)
}
- private val complication = ComplicationSlot.createRoundRectComplicationBuilder(
+ private val complication = ComplicationSlot.createRoundRectComplicationSlotBuilder(
EXAMPLE_OPENGL_COMPLICATION_ID,
{ watchState, listener ->
CanvasComplicationDrawable(
diff --git a/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/KDocExampleWatchFace.kt b/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/KDocExampleWatchFace.kt
index 11928a5..255993a 100644
--- a/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/KDocExampleWatchFace.kt
+++ b/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/KDocExampleWatchFace.kt
@@ -113,7 +113,7 @@
}
return ComplicationSlotsManager(
listOf(
- ComplicationSlot.createRoundRectComplicationBuilder(
+ ComplicationSlot.createRoundRectComplicationSlotBuilder(
/*id */ 0,
canvasComplicationFactory,
listOf(
@@ -127,7 +127,7 @@
ComplicationSlotBounds(RectF(0.15625f, 0.1875f, 0.84375f, 0.3125f))
).setDefaultProviderType(ComplicationType.SHORT_TEXT)
.build(),
- ComplicationSlot.createRoundRectComplicationBuilder(
+ ComplicationSlot.createRoundRectComplicationSlotBuilder(
/*id */ 1,
canvasComplicationFactory,
listOf(
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/ComplicationSlot.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/ComplicationSlot.kt
index 3b85ee5..188bd5f 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/ComplicationSlot.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/ComplicationSlot.kt
@@ -256,7 +256,7 @@
* @param bounds The complication's [ComplicationSlotBounds].
*/
@JvmStatic
- public fun createRoundRectComplicationBuilder(
+ public fun createRoundRectComplicationSlotBuilder(
id: Int,
canvasComplicationFactory: CanvasComplicationFactory,
supportedTypes: List<ComplicationType>,
@@ -290,7 +290,7 @@
* the initial complication provider when the watch is first installed.
*/
@JvmStatic
- public fun createBackgroundComplicationBuilder(
+ public fun createBackgroundComplicationSlotBuilder(
id: Int,
canvasComplicationFactory: CanvasComplicationFactory,
supportedTypes: List<ComplicationType>,
@@ -331,7 +331,7 @@
* not a tap hit the complication.
*/
@JvmStatic
- public fun createEdgeComplicationBuilder(
+ public fun createEdgeComplicationSlotBuilder(
id: Int,
canvasComplicationFactory: CanvasComplicationFactory,
supportedTypes: List<ComplicationType>,
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/ComplicationSlotsManager.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/ComplicationSlotsManager.kt
index 6e3b513..0e42149 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/ComplicationSlotsManager.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/ComplicationSlotsManager.kt
@@ -142,7 +142,7 @@
userStyle[complicationsStyleCategory]!! as ComplicationSlotsOption
if (previousOption != newlySelectedOption) {
previousOption = newlySelectedOption
- applyComplicationsSlotStyleCategoryOption(newlySelectedOption)
+ applyComplicationSlotsStyleCategoryOption(newlySelectedOption)
}
}
}
@@ -177,7 +177,7 @@
onComplicationsUpdated()
}
- internal fun applyComplicationsSlotStyleCategoryOption(styleOption: ComplicationSlotsOption) {
+ internal fun applyComplicationSlotsStyleCategoryOption(styleOption: ComplicationSlotsOption) {
for ((id, complication) in complicationSlots) {
val override = styleOption.complicationSlotOverlays.find { it.complicationSlotId == id }
val initialConfig = initialComplicationConfigs[id]!!
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
index b40aa58..5ab8463 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
@@ -666,7 +666,7 @@
}
}
- private class RendererAndComplicationsSlotManager(
+ private class RendererAndComplicationSlotsManager(
val renderer: Renderer,
val complicationSlotsManager: ComplicationSlotsManager
)
@@ -693,7 +693,7 @@
* [deferredRendererAndComplicationManager] will complete before [deferredWatchFaceImpl].
*/
private var deferredRendererAndComplicationManager =
- CompletableDeferred<RendererAndComplicationsSlotManager>()
+ CompletableDeferred<RendererAndComplicationSlotsManager>()
/**
* [deferredWatchFaceImpl] will complete after [deferredRendererAndComplicationManager].
@@ -1351,7 +1351,7 @@
)
}
deferredRendererAndComplicationManager.complete(
- RendererAndComplicationsSlotManager(
+ RendererAndComplicationSlotsManager(
watchFace.renderer,
complicationSlotsManager
)
diff --git a/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt b/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
index d79e267..ba314ad 100644
--- a/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
+++ b/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
@@ -169,7 +169,7 @@
ListUserStyleSetting.ListOption(Option.Id("bad_option"), "Bad", icon = null)
private val leftComplication =
- ComplicationSlot.createRoundRectComplicationBuilder(
+ ComplicationSlot.createRoundRectComplicationSlotBuilder(
LEFT_COMPLICATION_ID,
{ watchState, listener ->
CanvasComplicationDrawable(
@@ -191,7 +191,7 @@
.build()
private val rightComplication =
- ComplicationSlot.createRoundRectComplicationBuilder(
+ ComplicationSlot.createRoundRectComplicationSlotBuilder(
RIGHT_COMPLICATION_ID,
{ watchState, listener ->
CanvasComplicationDrawable(
@@ -214,7 +214,7 @@
private val edgeComplicationHitTester = mock<ComplicationTapFilter>()
private val edgeComplication =
- ComplicationSlot.createEdgeComplicationBuilder(
+ ComplicationSlot.createEdgeComplicationSlotBuilder(
EDGE_COMPLICATION_ID,
{ watchState, listener ->
CanvasComplicationDrawable(
@@ -237,7 +237,7 @@
.build()
private val backgroundComplication =
- ComplicationSlot.createBackgroundComplicationBuilder(
+ ComplicationSlot.createBackgroundComplicationSlotBuilder(
BACKGROUND_COMPLICATION_ID,
{ watchState, listener ->
CanvasComplicationDrawable(
@@ -1535,7 +1535,7 @@
public fun defaultProvidersWithFallbacks_newApi() {
val provider1 = ComponentName("com.app1", "com.app1.App1")
val provider2 = ComponentName("com.app2", "com.app2.App2")
- val complication = ComplicationSlot.createRoundRectComplicationBuilder(
+ val complication = ComplicationSlot.createRoundRectComplicationSlotBuilder(
LEFT_COMPLICATION_ID,
{ watchState, listener ->
CanvasComplicationDrawable(complicationDrawableLeft, watchState, listener)
@@ -1565,7 +1565,7 @@
public fun defaultProvidersWithFallbacks_oldApi() {
val provider1 = ComponentName("com.app1", "com.app1.App1")
val provider2 = ComponentName("com.app2", "com.app2.App2")
- val complication = ComplicationSlot.createRoundRectComplicationBuilder(
+ val complication = ComplicationSlot.createRoundRectComplicationSlotBuilder(
LEFT_COMPLICATION_ID,
{ watchState, listener ->
CanvasComplicationDrawable(complicationDrawableLeft, watchState, listener)
@@ -1958,7 +1958,7 @@
val manager = ComplicationSlotsManager(
listOf(
- ComplicationSlot.createRoundRectComplicationBuilder(
+ ComplicationSlot.createRoundRectComplicationSlotBuilder(
complicationSlotId1,
{ watchState, listener ->
CanvasComplicationDrawable(complicationDrawableLeft, watchState, listener)
@@ -1972,7 +1972,7 @@
.setEnabled(false)
.build(),
- ComplicationSlot.createRoundRectComplicationBuilder(
+ ComplicationSlot.createRoundRectComplicationSlotBuilder(
complicationSlotId2,
{ watchState, listener ->
CanvasComplicationDrawable(complicationDrawableRight, watchState, listener)
@@ -2582,7 +2582,7 @@
public fun canvasComplication_onRendererCreated() {
val leftCanvasComplication = mock<CanvasComplication>()
val leftComplication =
- ComplicationSlot.createRoundRectComplicationBuilder(
+ ComplicationSlot.createRoundRectComplicationSlotBuilder(
LEFT_COMPLICATION_ID,
{ _, _ -> leftCanvasComplication },
listOf(
@@ -2595,7 +2595,7 @@
val rightCanvasComplication = mock<CanvasComplication>()
val rightComplication =
- ComplicationSlot.createRoundRectComplicationBuilder(
+ ComplicationSlot.createRoundRectComplicationSlotBuilder(
RIGHT_COMPLICATION_ID,
{ _, _ -> rightCanvasComplication },
listOf(
diff --git a/webkit/webkit/src/androidTest/java/androidx/webkit/WebSettingsCompatForceDarkTest.java b/webkit/webkit/src/androidTest/java/androidx/webkit/WebSettingsCompatForceDarkTest.java
index 6975136..f278ef0 100644
--- a/webkit/webkit/src/androidTest/java/androidx/webkit/WebSettingsCompatForceDarkTest.java
+++ b/webkit/webkit/src/androidTest/java/androidx/webkit/WebSettingsCompatForceDarkTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.graphics.Bitmap;
@@ -238,14 +239,19 @@
// Requires {@link WebViewFeature.OFF_SCREEN_PRERASTER} for {@link
// WebViewOnUiThread#captureBitmap}.
private int getWebPageColor() {
- Map<Integer, Integer> histogram;
- Integer[] colourValues;
-
- histogram = getBitmapHistogram(mWebViewOnUiThread.captureBitmap(), 0, 0, 64, 64);
- assertEquals("Bitmap should have a single colour", 1, histogram.size());
- colourValues = histogram.keySet().toArray(new Integer[0]);
-
- return colourValues[0];
+ Map<Integer, Integer> histogram =
+ getBitmapHistogram(mWebViewOnUiThread.captureBitmap(), 0, 0, 64, 64);
+ Map.Entry<Integer, Integer> maxEntry = null;
+ for (Map.Entry<Integer, Integer> entry : histogram.entrySet()) {
+ if (maxEntry == null || entry.getValue().compareTo(maxEntry.getValue()) > 0) {
+ maxEntry = entry;
+ }
+ }
+ assertNotNull("There must be at least one color on the screen", maxEntry);
+ assertTrue(
+ "The majority color should be at least 90% of the pixels",
+ 1.0 * maxEntry.getValue() / (64 * 64) > 0.9);
+ return maxEntry.getKey();
}
private Map<Integer, Integer> getBitmapHistogram(