Merge "Upgrade to Kotlin 1.5.0, KSP to 1.5.0-1.0.0-alpha09 Test: bos" into androidx-main
diff --git a/activity/activity-lint/build.gradle b/activity/activity-lint/build.gradle
index 91f9d3c..7e37c76 100644
--- a/activity/activity-lint/build.gradle
+++ b/activity/activity-lint/build.gradle
@@ -25,13 +25,7 @@
}
dependencies {
- // compileOnly because we use lintChecks and it doesn't allow other types of deps
- // this ugly hack exists because of b/63873667
- if (rootProject.hasProperty("android.injected.invoked.from.ide")) {
- compileOnly(LINT_API_LATEST)
- } else {
- compileOnly(LINT_API_MIN)
- }
+ compileOnly(LINT_API_MIN)
compileOnly(KOTLIN_STDLIB)
testImplementation(KOTLIN_STDLIB)
diff --git a/annotation/annotation-experimental-lint/build.gradle b/annotation/annotation-experimental-lint/build.gradle
index 15ad4d6..17d9220 100644
--- a/annotation/annotation-experimental-lint/build.gradle
+++ b/annotation/annotation-experimental-lint/build.gradle
@@ -34,13 +34,7 @@
}
dependencies {
- // compileOnly because we use lintChecks and it doesn't allow other types of deps
- // this ugly hack exists because of b/63873667
- if (rootProject.hasProperty("android.injected.invoked.from.ide")) {
- compileOnly(LINT_API_LATEST)
- } else {
- compileOnly(LINT_API_MIN)
- }
+ compileOnly(LINT_API_MIN)
compileOnly(KOTLIN_STDLIB)
testImplementation(KOTLIN_STDLIB)
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotateRecreatesActivityWithConfigTestCase.kt b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotateRecreatesActivityWithConfigTestCase.kt
index 3a8995a..b2cce55 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotateRecreatesActivityWithConfigTestCase.kt
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotateRecreatesActivityWithConfigTestCase.kt
@@ -27,6 +27,7 @@
import androidx.appcompat.testutils.NightModeUtils.assertConfigurationNightModeEquals
import androidx.appcompat.testutils.NightModeUtils.setNightModeAndWaitForRecreate
import androidx.lifecycle.Lifecycle
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.LargeTest
import androidx.test.filters.SdkSuppress
import androidx.test.platform.app.InstrumentationRegistry
@@ -77,6 +78,7 @@
}
}
+ @FlakyTest // b/188599568
@Test
public fun testRotateRecreatesActivityWithConfig() {
// Set local night mode to MODE_NIGHT_YES and wait for state RESUMED.
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatEmojiEditTextHelper.java b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatEmojiEditTextHelper.java
index 3316ef5..4a5dde1 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatEmojiEditTextHelper.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatEmojiEditTextHelper.java
@@ -28,7 +28,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.R;
-import androidx.emoji2.viewshelper.EmojiEditTextHelper;
+import androidx.emoji2.viewsintegration.EmojiEditTextHelper;
/**
* Helper for using EmojiCompat from TextView in appcompat.
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatEmojiTextHelper.java b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatEmojiTextHelper.java
index 28621fe..b7418d6 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatEmojiTextHelper.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatEmojiTextHelper.java
@@ -26,7 +26,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.R;
-import androidx.emoji2.viewshelper.EmojiTextViewHelper;
+import androidx.emoji2.viewsintegration.EmojiTextViewHelper;
/**
* Helper for using EmojiCompat from TextView in appcompat.
diff --git a/biometric/biometric/src/main/java/androidx/biometric/FingerprintDialogFragment.java b/biometric/biometric/src/main/java/androidx/biometric/FingerprintDialogFragment.java
index 240e6a2..13068b0 100644
--- a/biometric/biometric/src/main/java/androidx/biometric/FingerprintDialogFragment.java
+++ b/biometric/biometric/src/main/java/androidx/biometric/FingerprintDialogFragment.java
@@ -439,7 +439,7 @@
* Gets the resource ID of the {@code colorError} style attribute.
*/
static int getColorErrorAttr() {
- return R.attr.colorError;
+ return androidx.appcompat.R.attr.colorError;
}
}
diff --git a/buildSrc/src/main/kotlin/androidx/build/AndroidXUiPlugin.kt b/buildSrc/src/main/kotlin/androidx/build/AndroidXUiPlugin.kt
index f079592..a943bdd 100644
--- a/buildSrc/src/main/kotlin/androidx/build/AndroidXUiPlugin.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/AndroidXUiPlugin.kt
@@ -25,6 +25,7 @@
import org.gradle.api.Project
import org.gradle.api.artifacts.type.ArtifactTypeDefinition
import org.gradle.api.attributes.Attribute
+import org.gradle.api.file.DuplicatesStrategy
import org.gradle.api.tasks.ClasspathNormalizer
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.findByType
@@ -285,6 +286,14 @@
"multiplatformExtension is null (multiplatform plugin not enabled?)"
}
+ /**
+ * Temporary workaround for https://youtrack.jetbrains.com/issue/KT-46096
+ * Should be removed once the build switches to Kotlin 1.5
+ */
+ tasks.withType(org.gradle.jvm.tasks.Jar::class.java).configureEach { jar ->
+ jar.duplicatesStrategy = DuplicatesStrategy.INCLUDE
+ }
+
/*
The following configures source sets - note:
diff --git a/buildSrc/src/main/kotlin/androidx/build/ComposeJvmTarget.kt b/buildSrc/src/main/kotlin/androidx/build/ComposeJvmTarget.kt
new file mode 100644
index 0000000..d3f42f8
--- /dev/null
+++ b/buildSrc/src/main/kotlin/androidx/build/ComposeJvmTarget.kt
@@ -0,0 +1,229 @@
+/*
+ * 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.build
+
+import org.gradle.api.Project
+import org.gradle.api.file.ConfigurableFileCollection
+import org.gradle.api.plugins.JavaPlugin
+import org.gradle.api.plugins.JavaPluginConvention
+import org.gradle.api.tasks.SourceSet
+import org.gradle.api.tasks.compile.AbstractCompile
+import org.gradle.api.tasks.testing.Test
+import org.gradle.jvm.tasks.Jar
+import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation
+import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
+import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
+import java.lang.reflect.Modifier
+import java.util.concurrent.Callable
+
+object ComposeJvmTarget {
+ /**
+ * Temporary workaround for fixing Compose Desktop build with Kotlin 1.4 and Gradle 7
+ * Intended to be used only in :compose:desktop:desktop and only until Compose project
+ * switches to Kotlin 1.5.0
+ *
+ * This is basically a copy
+ * org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget.withJava from Kotlin 1.5.0,
+ * which fixes java.lang.NoSuchMethodError, thrown by Gradle 7 with Kotlin 1.4
+ * (https://youtrack.jetbrains.com/issue/KTIJ-10018).
+ *
+ * There are a few changes from the original:
+ * some internal methods are copied or called using Java Reflection
+ */
+ @JvmStatic
+ fun withJava(target: KotlinJvmTarget) {
+ val project = target.project
+
+ project.plugins.apply(JavaPlugin::class.java)
+ val javaPluginConvention = project.convention.getPlugin(JavaPluginConvention::class.java)
+ setUpJavaSourceSets(target)
+
+ javaPluginConvention.sourceSets.all { javaSourceSet ->
+ val compilation = target.compilations.getByName(javaSourceSet.name)
+ val compileJavaTask = project.tasks.withType(AbstractCompile::class.java)
+ .named(javaSourceSet.compileJavaTaskName)
+
+ setupJavaSourceSetSourcesAndResources(project, javaSourceSet, compilation)
+
+ val javaClasses = project.files(compileJavaTask.map { it.destinationDir })
+
+ compilation.output.classesDirs.from(javaClasses)
+
+ (javaSourceSet.output.classesDirs as? ConfigurableFileCollection)?.from(
+ compilation.output.classesDirs.minus(javaClasses)
+ )
+
+ javaSourceSet.output.setResourcesDir(
+ Callable { compilation.output.resourcesDirProvider }
+ )
+
+ setupDependenciesCrossInclusionForJava(project, compilation, javaSourceSet)
+ }
+
+ // Eliminate the Java output configurations from dependency resolution
+ // to avoid ambiguity between them and the equivalent configurations
+ // created for the target:
+ listOf(
+ JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME,
+ JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME
+ ).forEach { outputConfigurationName ->
+ project.configurations.findByName(outputConfigurationName)?.isCanBeConsumed = false
+ }
+
+ disableJavaPluginTasks(project, javaPluginConvention, target)
+ }
+
+ private fun setupDependenciesCrossInclusionForJava(
+ project: Project,
+ compilation: KotlinJvmCompilation,
+ javaSourceSet: SourceSet
+ ) {
+ // Make sure Kotlin compilation dependencies appear in the Java source set classpaths:
+
+ listOfNotNull(
+ compilation.apiConfigurationName,
+ compilation.implementationConfigurationName,
+ compilation.compileOnlyConfigurationName
+ ).forEach { configurationName ->
+ project.addExtendsFromRelation(
+ javaSourceSet.compileClasspathConfigurationName,
+ configurationName
+ )
+ }
+
+ listOfNotNull(
+ compilation.apiConfigurationName,
+ compilation.implementationConfigurationName,
+ compilation.runtimeOnlyConfigurationName
+ ).forEach { configurationName ->
+ project.addExtendsFromRelation(
+ javaSourceSet.runtimeClasspathConfigurationName,
+ configurationName
+ )
+ }
+
+ // Add the Java source set dependencies to the Kotlin compilation
+ // compile & runtime configurations:
+ listOfNotNull(
+ javaSourceSet.compileOnlyConfigurationName,
+ javaSourceSet.apiConfigurationName
+ .takeIf { project.configurations.findByName(it) != null },
+ javaSourceSet.implementationConfigurationName
+ ).forEach { configurationName ->
+ project.addExtendsFromRelation(
+ compilation.compileDependencyConfigurationName,
+ configurationName
+ )
+ }
+
+ listOfNotNull(
+ javaSourceSet.runtimeOnlyConfigurationName,
+ javaSourceSet.apiConfigurationName
+ .takeIf { project.configurations.findByName(it) != null },
+ javaSourceSet.implementationConfigurationName
+ ).forEach { configurationName ->
+ project.addExtendsFromRelation(
+ compilation.runtimeDependencyConfigurationName,
+ configurationName
+ )
+ }
+ }
+
+ /**
+ * Calls AbstractKotlinPlugin.setUpJavaSourceSets(target, false) using reflection
+ */
+ private fun setUpJavaSourceSets(target: KotlinJvmTarget) {
+ val abstractKotlinPluginClass = Class.forName(ABSTRACT_KOTLIN_PLUGIN)
+ ?: error("Could not find '$ABSTRACT_KOTLIN_PLUGIN' class")
+ val companionField = abstractKotlinPluginClass.fields
+ .find { it.name == COMPANION && Modifier.isStatic(it.modifiers) }
+ ?: error("Could not find '$COMPANION' field")
+ val companionInstance = companionField.get(abstractKotlinPluginClass)!!
+ val companionClass = companionInstance.javaClass
+ val setUpJavaSourceSetsMethod = companionClass.methods.find {
+ it.name == SET_UP_JAVA_SOURCE_SETS && it.parameterCount == 2
+ } ?: error("Could not find '$SET_UP_JAVA_SOURCE_SETS' method")
+ setUpJavaSourceSetsMethod.invoke(companionInstance, target, false)
+ }
+
+ private fun disableJavaPluginTasks(
+ project: Project,
+ javaPluginConvention: JavaPluginConvention,
+ target: KotlinJvmTarget
+ ) {
+ // A 'normal' build should not do redundant job like running the tests twice or building two JARs,
+ // so disable some tasks and just make them depend on the others:
+ val targetJar = project.tasks.withType(Jar::class.java).named(target.artifactsTaskName)
+
+ val mainJarTaskName = javaPluginConvention.sourceSets.getByName("main").jarTaskName
+ project.tasks.withType(Jar::class.java).named(mainJarTaskName) { javaJar ->
+ (javaJar.source as? ConfigurableFileCollection)?.setFrom(targetJar.map { it.source })
+ javaJar.conventionMapping("archiveName") { targetJar.get().archiveFileName.get() }
+ javaJar.dependsOn(targetJar)
+ javaJar.enabled = false
+ }
+
+ project.tasks.withType(Test::class.java).named(JavaPlugin.TEST_TASK_NAME) { javaTestTask ->
+ javaTestTask.dependsOn(project.tasks.named(target.testTaskName))
+ javaTestTask.enabled = false
+ }
+ }
+
+ private fun setupJavaSourceSetSourcesAndResources(
+ project: Project,
+ javaSourceSet: SourceSet,
+ compilation: KotlinJvmCompilation
+ ) {
+ javaSourceSet.java.setSrcDirs(listOf("src/${compilation.defaultSourceSet.name}/java"))
+ compilation.defaultSourceSet.kotlin.srcDirs(javaSourceSet.java.sourceDirectories)
+
+ // To avoid confusion in the sources layout, remove the default Java source directories
+ // (like src/main/java, src/test/java) and instead add sibling directories to those where the Kotlin
+ // sources are placed (i.e. src/jvmMain/java, src/jvmTest/java):
+ javaSourceSet.resources.setSrcDirs(
+ compilation.defaultSourceSet.resources.sourceDirectories
+ )
+ compilation.defaultSourceSet.resources.srcDirs(javaSourceSet.resources.sourceDirectories)
+
+ // Resources processing is done with the Kotlin resource processing task:
+ val processJavaResourcesTask =
+ project.tasks.getByName(javaSourceSet.processResourcesTaskName)
+ processJavaResourcesTask.dependsOn(
+ project.tasks.getByName(compilation.processResourcesTaskName)
+ )
+ processJavaResourcesTask.enabled = false
+ }
+
+ private const val ABSTRACT_KOTLIN_PLUGIN =
+ "org.jetbrains.kotlin.gradle.plugin.AbstractKotlinPlugin"
+ private const val COMPANION = "Companion"
+ private const val SET_UP_JAVA_SOURCE_SETS = "setUpJavaSourceSets${'$'}kotlin_gradle_plugin"
+ private const val ARTIFACT_TASK_NAME = "jar"
+
+ private val KotlinTarget.testTaskName: String
+ get() = lowerCamelCaseName(name, "test")
+
+ private fun lowerCamelCaseName(vararg nameParts: String?): String {
+ val nonEmptyParts = nameParts.mapNotNull { it?.takeIf(String::isNotEmpty) }
+ return nonEmptyParts.drop(1).joinToString(
+ separator = "",
+ prefix = nonEmptyParts.firstOrNull().orEmpty(),
+ transform = String::capitalize
+ )
+ }
+}
\ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt b/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
index 1733609..a31cbd8 100644
--- a/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
@@ -100,7 +100,7 @@
const val REACTIVE_STREAMS = "org.reactivestreams:reactive-streams:1.0.0"
const val RX_JAVA = "io.reactivex.rxjava2:rxjava:2.2.9"
const val RX_JAVA3 = "io.reactivex.rxjava3:rxjava:3.0.0"
-val SKIKO_VERSION = System.getenv("SKIKO_VERSION") ?: "0.2.30"
+val SKIKO_VERSION = System.getenv("SKIKO_VERSION") ?: "0.2.33"
val SKIKO = "org.jetbrains.skiko:skiko-jvm:$SKIKO_VERSION"
val SKIKO_LINUX_X64 = "org.jetbrains.skiko:skiko-jvm-runtime-linux-x64:$SKIKO_VERSION"
val SKIKO_MACOS_X64 = "org.jetbrains.skiko:skiko-jvm-runtime-macos-x64:$SKIKO_VERSION"
diff --git a/camera/camera-camera2-pipe-testing/src/test/java/androidx/camera/camera2/pipe/testing/CameraGraphSimulatorTest.kt b/camera/camera-camera2-pipe-testing/src/test/java/androidx/camera/camera2/pipe/testing/CameraGraphSimulatorTest.kt
index b3e5222..bd61d50 100644
--- a/camera/camera-camera2-pipe-testing/src/test/java/androidx/camera/camera2/pipe/testing/CameraGraphSimulatorTest.kt
+++ b/camera/camera-camera2-pipe-testing/src/test/java/androidx/camera/camera2/pipe/testing/CameraGraphSimulatorTest.kt
@@ -36,6 +36,7 @@
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeout
import kotlinx.coroutines.withTimeoutOrNull
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.annotation.Config
@@ -195,6 +196,7 @@
assertThat(lossEvent.streamId).isEqualTo(stream.id)
}
+ @Ignore // TODO(b/188446185): flaky
@Test
fun simulatorCanIssueMultipleFrames() = runBlocking {
val listener = FakeRequestListener()
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/PreviewTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/PreviewTest.java
index 1b1d237..8221172 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/PreviewTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/PreviewTest.java
@@ -58,6 +58,7 @@
import androidx.core.util.Consumer;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.LargeTest;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -123,6 +124,7 @@
CameraX.shutdown().get(10000, TimeUnit.MILLISECONDS);
}
+ @FlakyTest // b/188598639
@Test
public void surfaceProvider_isUsedAfterSetting() {
final Preview.SurfaceProvider surfaceProvider = mock(Preview.SurfaceProvider.class);
diff --git a/camera/integration-tests/extensionstestapp/src/main/java/androidx/camera/integration/extensions/CameraExtensionsActivity.java b/camera/integration-tests/extensionstestapp/src/main/java/androidx/camera/integration/extensions/CameraExtensionsActivity.java
index d84d77d..95d5f5b 100644
--- a/camera/integration-tests/extensionstestapp/src/main/java/androidx/camera/integration/extensions/CameraExtensionsActivity.java
+++ b/camera/integration-tests/extensionstestapp/src/main/java/androidx/camera/integration/extensions/CameraExtensionsActivity.java
@@ -119,27 +119,10 @@
}
}
- /**
- * Sets up the appropriate UseCases.
- */
- private void bindUseCases() {
- ImageCapture.Builder imageCaptureBuilder = new ImageCapture.Builder().setTargetName(
- "ImageCapture");
- mImageCapture = imageCaptureBuilder.build();
-
- Preview.Builder previewBuilder = new Preview.Builder().setTargetName("Preview");
-
- mPreview = previewBuilder.build();
- mPreview.setSurfaceProvider(mPreviewView.getSurfaceProvider());
-
- mCamera = mCameraProvider.bindToLifecycle(this, mCurrentCameraSelector,
- mImageCapture, mPreview);
- }
-
void setupButtons() {
Button btnToggleMode = findViewById(R.id.PhotoToggle);
Button btnSwitchCamera = findViewById(R.id.Switch);
- btnToggleMode.setOnClickListener(view -> enableNextExtension());
+ btnToggleMode.setOnClickListener(view -> bindUseCasesWithNextExtension());
btnSwitchCamera.setOnClickListener(view -> switchCameras());
}
@@ -147,8 +130,7 @@
mCameraProvider.unbindAll();
mCurrentCameraSelector = (mCurrentCameraSelector == CameraSelector.DEFAULT_BACK_CAMERA)
? CameraSelector.DEFAULT_FRONT_CAMERA : CameraSelector.DEFAULT_BACK_CAMERA;
- bindUseCases();
- enableExtension(mCurrentImageCaptureType);
+ bindUseCasesWithExtension(mCurrentImageCaptureType);
}
@Extensions.ExtensionMode
@@ -172,30 +154,37 @@
}
}
- void enableNextExtension() {
+ void bindUseCasesWithNextExtension() {
do {
mCurrentImageCaptureType = mCurrentImageCaptureType.getNextType();
- } while (!enableExtension(mCurrentImageCaptureType));
+ } while (!bindUseCasesWithExtension(mCurrentImageCaptureType));
}
// TODO(b/162875208) Suppress until new extensions API made public
@SuppressLint("RestrictedAPI")
- boolean enableExtension(ImageCaptureType imageCaptureType) {
+ boolean bindUseCasesWithExtension(ImageCaptureType imageCaptureType) {
// Check that extension can be enabled and if so enable it
@Extensions.ExtensionMode
int extensionMode = extensionModeFrom(imageCaptureType);
-
if (!mExtensions.isExtensionAvailable(mCameraProvider, mCurrentCameraSelector,
extensionMode)) {
return false;
}
+ ImageCapture.Builder imageCaptureBuilder = new ImageCapture.Builder().setTargetName(
+ "ImageCapture");
+ mImageCapture = imageCaptureBuilder.build();
+
+ Preview.Builder previewBuilder = new Preview.Builder().setTargetName("Preview");
+
+ mPreview = previewBuilder.build();
+ mPreview.setSurfaceProvider(mPreviewView.getSurfaceProvider());
+
CameraSelector cameraSelector = mExtensions.getExtensionCameraSelector(
mCurrentCameraSelector, extensionMode);
mCameraProvider.unbindAll();
-
- mCameraProvider.bindToLifecycle(this, cameraSelector, mImageCapture, mPreview);
+ mCamera = mCameraProvider.bindToLifecycle(this, cameraSelector, mImageCapture, mPreview);
// Update the UI and save location for ImageCapture
Button toggleButton = findViewById(R.id.PhotoToggle);
@@ -269,13 +258,6 @@
return true;
}
- /** Creates all the use cases. */
- void createUseCases() {
- ExtensionsManager.setExtensionsErrorListener((errorCode) ->
- Log.d(TAG, "Extensions error in error code: " + errorCode));
- bindUseCases();
- }
-
@SuppressWarnings("UnstableApiUsage")
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -339,8 +321,9 @@
case NONE:
mExtensions = ExtensionsManager.getExtensions(
getApplicationContext());
- createUseCases();
- enableNextExtension();
+ ExtensionsManager.setExtensionsErrorListener((errorCode) ->
+ Log.d(TAG, "Extensions error in error code: " + errorCode));
+ bindUseCasesWithNextExtension();
setupButtons();
break;
case LIBRARY_UNAVAILABLE_ERROR_LOADING:
@@ -407,9 +390,8 @@
motionEvent.getX(), motionEvent.getY());
mCamera.getCameraControl().startFocusAndMetering(
- new FocusMeteringAction.Builder(point).build())
- .addListener(() -> {},
- ContextCompat.getMainExecutor(CameraExtensionsActivity.this));
+ new FocusMeteringAction.Builder(point).build()).addListener(() -> {},
+ ContextCompat.getMainExecutor(CameraExtensionsActivity.this));
}
return true;
});
diff --git a/car/app/app-samples/navigation/common/src/main/java/androidx/car/app/sample/navigation/common/app/MainActivity.java b/car/app/app-samples/navigation/common/src/main/java/androidx/car/app/sample/navigation/common/app/MainActivity.java
index 9acd598..50f48ba2 100644
--- a/car/app/app-samples/navigation/common/src/main/java/androidx/car/app/sample/navigation/common/app/MainActivity.java
+++ b/car/app/app-samples/navigation/common/src/main/java/androidx/car/app/sample/navigation/common/app/MainActivity.java
@@ -30,7 +30,7 @@
import androidx.activity.ComponentActivity;
import androidx.annotation.Nullable;
-import androidx.car.app.connection.ConnectionToCar;
+import androidx.car.app.connection.CarConnection;
import androidx.car.app.sample.navigation.common.R;
import androidx.car.app.sample.navigation.common.nav.NavigationService;
@@ -82,7 +82,7 @@
Button stopNavButton = findViewById(R.id.stop_nav);
stopNavButton.setOnClickListener(this::stopNavigation);
- new ConnectionToCar(this).getType().observe(this,
+ new CarConnection(this).getType().observe(this,
this::onConnectionStateUpdate);
}
@@ -112,7 +112,7 @@
}
private void onConnectionStateUpdate(Integer connectionState) {
- String message = connectionState > ConnectionToCar.NOT_CONNECTED
+ String message = connectionState > CarConnection.CONNECTION_TYPE_NOT_CONNECTED
? "Connected to a car head unit"
: "Not Connected to a car head unit";
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
diff --git a/car/app/app-samples/navigation/common/src/main/java/androidx/car/app/sample/navigation/common/nav/NavigationService.java b/car/app/app-samples/navigation/common/src/main/java/androidx/car/app/sample/navigation/common/nav/NavigationService.java
index ca73d03..21dd896 100644
--- a/car/app/app-samples/navigation/common/src/main/java/androidx/car/app/sample/navigation/common/nav/NavigationService.java
+++ b/car/app/app-samples/navigation/common/src/main/java/androidx/car/app/sample/navigation/common/nav/NavigationService.java
@@ -570,6 +570,6 @@
private PendingIntent createMainActivityPendingIntent() {
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra(EXTRA_STARTED_FROM_NOTIFICATION, true);
- return PendingIntent.getActivity(this, 0, intent, 0);
+ return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
}
}
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/NotificationDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/NotificationDemoScreen.java
index e792847..3bfc510 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/NotificationDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/NotificationDemoScreen.java
@@ -235,7 +235,7 @@
builder.setSmallIcon(R.drawable.ic_bug_report_24px)
.setContentTitle(title + " (phone)")
.setContentText(text + " (phone)")
- .setColor(getCarContext().getColor(R.color.carColorGreen))
+ .setColor(getCarContext().getColor(androidx.car.app.R.color.carColorGreen))
.setColorized(true)
.setLargeIcon(
BitmapFactory.decodeResource(
@@ -340,7 +340,8 @@
/** Returns a pending intent with the provided intent action. */
private PendingIntent createPendingIntent(String intentAction) {
Intent intent = new Intent(intentAction);
- return PendingIntent.getBroadcast(getCarContext(), intentAction.hashCode(), intent, 0);
+ return PendingIntent.getBroadcast(getCarContext(), intentAction.hashCode(), intent,
+ PendingIntent.FLAG_IMMUTABLE);
}
final class HandlerCallback implements Handler.Callback {
diff --git a/car/app/app/api/current.txt b/car/app/app/api/current.txt
index 8d47bcd..777910c 100644
--- a/car/app/app/api/current.txt
+++ b/car/app/app/api/current.txt
@@ -179,14 +179,24 @@
package androidx.car.app.connection {
- public final class ConnectionToCar {
- ctor public ConnectionToCar(android.content.Context);
+ public final class CarConnection {
+ ctor public CarConnection(android.content.Context);
method public androidx.lifecycle.LiveData<java.lang.Integer!> getType();
field public static final String ACTION_CAR_CONNECTION_UPDATED = "androidx.car.app.connection.action.CAR_CONNECTION_UPDATED";
field public static final String CAR_CONNECTION_STATE = "CarConnectionState";
- field public static final int NATIVE = 1; // 0x1
- field public static final int NOT_CONNECTED = 0; // 0x0
- field public static final int PROJECTION = 2; // 0x2
+ field public static final int CONNECTION_TYPE_NATIVE = 1; // 0x1
+ field public static final int CONNECTION_TYPE_NOT_CONNECTED = 0; // 0x0
+ field public static final int CONNECTION_TYPE_PROJECTION = 2; // 0x2
+ }
+
+ @Deprecated public final class ConnectionToCar {
+ ctor @Deprecated public ConnectionToCar(android.content.Context);
+ method @Deprecated public androidx.lifecycle.LiveData<java.lang.Integer!> getType();
+ field @Deprecated public static final String ACTION_CAR_CONNECTION_UPDATED = "androidx.car.app.connection.action.CAR_CONNECTION_UPDATED";
+ field @Deprecated public static final String CAR_CONNECTION_STATE = "CarConnectionState";
+ field @Deprecated public static final int NATIVE = 1; // 0x1
+ field @Deprecated public static final int NOT_CONNECTED = 0; // 0x0
+ field @Deprecated public static final int PROJECTION = 2; // 0x2
}
}
@@ -1050,6 +1060,7 @@
}
public static final class Step.Builder {
+ ctor public Step.Builder();
ctor public Step.Builder(CharSequence);
ctor public Step.Builder(androidx.car.app.model.CarText);
method public androidx.car.app.navigation.model.Step.Builder addLane(androidx.car.app.navigation.model.Lane);
diff --git a/car/app/app/api/public_plus_experimental_current.txt b/car/app/app/api/public_plus_experimental_current.txt
index 0fafb1f..29159e0 100644
--- a/car/app/app/api/public_plus_experimental_current.txt
+++ b/car/app/app/api/public_plus_experimental_current.txt
@@ -182,14 +182,24 @@
package androidx.car.app.connection {
- public final class ConnectionToCar {
- ctor public ConnectionToCar(android.content.Context);
+ public final class CarConnection {
+ ctor public CarConnection(android.content.Context);
method public androidx.lifecycle.LiveData<java.lang.Integer!> getType();
field public static final String ACTION_CAR_CONNECTION_UPDATED = "androidx.car.app.connection.action.CAR_CONNECTION_UPDATED";
field public static final String CAR_CONNECTION_STATE = "CarConnectionState";
- field public static final int NATIVE = 1; // 0x1
- field public static final int NOT_CONNECTED = 0; // 0x0
- field public static final int PROJECTION = 2; // 0x2
+ field public static final int CONNECTION_TYPE_NATIVE = 1; // 0x1
+ field public static final int CONNECTION_TYPE_NOT_CONNECTED = 0; // 0x0
+ field public static final int CONNECTION_TYPE_PROJECTION = 2; // 0x2
+ }
+
+ @Deprecated public final class ConnectionToCar {
+ ctor @Deprecated public ConnectionToCar(android.content.Context);
+ method @Deprecated public androidx.lifecycle.LiveData<java.lang.Integer!> getType();
+ field @Deprecated public static final String ACTION_CAR_CONNECTION_UPDATED = "androidx.car.app.connection.action.CAR_CONNECTION_UPDATED";
+ field @Deprecated public static final String CAR_CONNECTION_STATE = "CarConnectionState";
+ field @Deprecated public static final int NATIVE = 1; // 0x1
+ field @Deprecated public static final int NOT_CONNECTED = 0; // 0x0
+ field @Deprecated public static final int PROJECTION = 2; // 0x2
}
}
@@ -1053,6 +1063,7 @@
}
public static final class Step.Builder {
+ ctor public Step.Builder();
ctor public Step.Builder(CharSequence);
ctor public Step.Builder(androidx.car.app.model.CarText);
method public androidx.car.app.navigation.model.Step.Builder addLane(androidx.car.app.navigation.model.Lane);
diff --git a/car/app/app/api/restricted_current.txt b/car/app/app/api/restricted_current.txt
index 8d47bcd..777910c 100644
--- a/car/app/app/api/restricted_current.txt
+++ b/car/app/app/api/restricted_current.txt
@@ -179,14 +179,24 @@
package androidx.car.app.connection {
- public final class ConnectionToCar {
- ctor public ConnectionToCar(android.content.Context);
+ public final class CarConnection {
+ ctor public CarConnection(android.content.Context);
method public androidx.lifecycle.LiveData<java.lang.Integer!> getType();
field public static final String ACTION_CAR_CONNECTION_UPDATED = "androidx.car.app.connection.action.CAR_CONNECTION_UPDATED";
field public static final String CAR_CONNECTION_STATE = "CarConnectionState";
- field public static final int NATIVE = 1; // 0x1
- field public static final int NOT_CONNECTED = 0; // 0x0
- field public static final int PROJECTION = 2; // 0x2
+ field public static final int CONNECTION_TYPE_NATIVE = 1; // 0x1
+ field public static final int CONNECTION_TYPE_NOT_CONNECTED = 0; // 0x0
+ field public static final int CONNECTION_TYPE_PROJECTION = 2; // 0x2
+ }
+
+ @Deprecated public final class ConnectionToCar {
+ ctor @Deprecated public ConnectionToCar(android.content.Context);
+ method @Deprecated public androidx.lifecycle.LiveData<java.lang.Integer!> getType();
+ field @Deprecated public static final String ACTION_CAR_CONNECTION_UPDATED = "androidx.car.app.connection.action.CAR_CONNECTION_UPDATED";
+ field @Deprecated public static final String CAR_CONNECTION_STATE = "CarConnectionState";
+ field @Deprecated public static final int NATIVE = 1; // 0x1
+ field @Deprecated public static final int NOT_CONNECTED = 0; // 0x0
+ field @Deprecated public static final int PROJECTION = 2; // 0x2
}
}
@@ -1050,6 +1060,7 @@
}
public static final class Step.Builder {
+ ctor public Step.Builder();
ctor public Step.Builder(CharSequence);
ctor public Step.Builder(androidx.car.app.model.CarText);
method public androidx.car.app.navigation.model.Step.Builder addLane(androidx.car.app.navigation.model.Lane);
diff --git a/car/app/app/src/main/java/androidx/car/app/connection/AutomotiveConnectionToCarTypeLiveData.java b/car/app/app/src/main/java/androidx/car/app/connection/AutomotiveCarConnectionTypeLiveData.java
similarity index 79%
rename from car/app/app/src/main/java/androidx/car/app/connection/AutomotiveConnectionToCarTypeLiveData.java
rename to car/app/app/src/main/java/androidx/car/app/connection/AutomotiveCarConnectionTypeLiveData.java
index f8857be..b35606b 100644
--- a/car/app/app/src/main/java/androidx/car/app/connection/AutomotiveConnectionToCarTypeLiveData.java
+++ b/car/app/app/src/main/java/androidx/car/app/connection/AutomotiveCarConnectionTypeLiveData.java
@@ -16,15 +16,15 @@
package androidx.car.app.connection;
-import androidx.car.app.connection.ConnectionToCar.ConnectionType;
+import androidx.car.app.connection.CarConnection.ConnectionType;
import androidx.lifecycle.LiveData;
/**
* A {@link LiveData} that always returns that it is connected natively to a car head unit.
*/
-final class AutomotiveConnectionToCarTypeLiveData extends LiveData<@ConnectionType Integer> {
+final class AutomotiveCarConnectionTypeLiveData extends LiveData<@ConnectionType Integer> {
@Override
protected void onActive() {
- setValue(ConnectionToCar.NATIVE);
+ setValue(CarConnection.CONNECTION_TYPE_NATIVE);
}
}
diff --git a/car/app/app/src/main/java/androidx/car/app/connection/CarConnection.java b/car/app/app/src/main/java/androidx/car/app/connection/CarConnection.java
new file mode 100644
index 0000000..79d81bd
--- /dev/null
+++ b/car/app/app/src/main/java/androidx/car/app/connection/CarConnection.java
@@ -0,0 +1,112 @@
+/*
+ * 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.car.app.connection;
+
+import static androidx.annotation.RestrictTo.Scope.LIBRARY;
+import static androidx.car.app.utils.CommonUtils.isAutomotiveOS;
+
+import static java.util.Objects.requireNonNull;
+
+import android.content.Context;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.lifecycle.LiveData;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A class that allows retrieval of information about connection to a car head unit.
+ */
+public final class CarConnection {
+ /**
+ * Defines current car connection state.
+ *
+ * <p>This is used for communication with the car host's content provider on queries for
+ * connection type.
+ */
+ public static final String CAR_CONNECTION_STATE = "CarConnectionState";
+
+ /**
+ * Broadcast action that notifies that the car connection has changed and needs to be updated.
+ */
+ public static final String ACTION_CAR_CONNECTION_UPDATED =
+ "androidx.car.app.connection.action.CAR_CONNECTION_UPDATED";
+
+ /**
+ * Represents the types of connections that exist to a car head unit.
+ *
+ * @hide
+ */
+ @IntDef({CONNECTION_TYPE_NOT_CONNECTED, CONNECTION_TYPE_NATIVE, CONNECTION_TYPE_PROJECTION})
+ @Retention(RetentionPolicy.SOURCE)
+ @Target({ElementType.TYPE_USE})
+ @RestrictTo(LIBRARY)
+ public @interface ConnectionType {
+ }
+
+ /**
+ * Not connected to any car head unit.z
+ */
+ public static final int CONNECTION_TYPE_NOT_CONNECTED = 0;
+
+ /**
+ * Natively running on a head unit (Android Automotive OS).
+ */
+ public static final int CONNECTION_TYPE_NATIVE = 1;
+
+ /**
+ * Connected to a car head unit by projecting to it.
+ */
+ public static final int CONNECTION_TYPE_PROJECTION = 2;
+
+ private final LiveData<Integer> mConnectionTypeLiveData;
+
+ /**
+ * Constructs a {@link CarConnection} that can be used to get connection information.
+ *
+ * @throws NullPointerException if {@code context} is {@code null}
+ */
+ public CarConnection(@NonNull Context context) {
+ requireNonNull(context);
+ mConnectionTypeLiveData = isAutomotiveOS(context)
+ ? new AutomotiveCarConnectionTypeLiveData()
+ : new CarConnectionTypeLiveData(context);
+ }
+
+ /**
+ * Returns a {@link LiveData} that can be observed to get current connection type.
+ *
+ * <p>The recommended pattern is to observe the {@link LiveData} with the activity's
+ * lifecycle in order to get updates on the state change throughout the activity's lifetime.
+ *
+ * <p>Connection types are:
+ * <ol>
+ * <li>{@link #CONNECTION_TYPE_NOT_CONNECTED}
+ * <li>{@link #CONNECTION_TYPE_NATIVE}
+ * <li>{@link #CONNECTION_TYPE_PROJECTION}
+ * </ol>
+ */
+ @NonNull
+ public LiveData<@ConnectionType Integer> getType() {
+ return mConnectionTypeLiveData;
+ }
+}
diff --git a/car/app/app/src/main/java/androidx/car/app/connection/ConnectionToCarTypeLiveData.java b/car/app/app/src/main/java/androidx/car/app/connection/CarConnectionTypeLiveData.java
similarity index 84%
rename from car/app/app/src/main/java/androidx/car/app/connection/ConnectionToCarTypeLiveData.java
rename to car/app/app/src/main/java/androidx/car/app/connection/CarConnectionTypeLiveData.java
index 77d714a..79f30f9 100644
--- a/car/app/app/src/main/java/androidx/car/app/connection/ConnectionToCarTypeLiveData.java
+++ b/car/app/app/src/main/java/androidx/car/app/connection/CarConnectionTypeLiveData.java
@@ -16,8 +16,8 @@
package androidx.car.app.connection;
-import static androidx.car.app.connection.ConnectionToCar.ACTION_CAR_CONNECTION_UPDATED;
-import static androidx.car.app.connection.ConnectionToCar.CAR_CONNECTION_STATE;
+import static androidx.car.app.connection.CarConnection.ACTION_CAR_CONNECTION_UPDATED;
+import static androidx.car.app.connection.CarConnection.CAR_CONNECTION_STATE;
import static androidx.car.app.utils.LogTags.TAG_CONNECTION_TO_CAR;
import android.content.AsyncQueryHandler;
@@ -31,14 +31,14 @@
import android.util.Log;
import androidx.annotation.VisibleForTesting;
-import androidx.car.app.connection.ConnectionToCar.ConnectionType;
+import androidx.car.app.connection.CarConnection.ConnectionType;
import androidx.lifecycle.LiveData;
/**
* A {@link LiveData} that will query once while being observed and only again if it gets updates
* via a broadcast.
*/
-final class ConnectionToCarTypeLiveData extends LiveData<@ConnectionType Integer> {
+final class CarConnectionTypeLiveData extends LiveData<@ConnectionType Integer> {
@VisibleForTesting
static final String CAR_CONNECTION_AUTHORITY = "androidx.car.app.connection";
@@ -50,7 +50,7 @@
private final AsyncQueryHandler mQueryHandler;
private final CarConnectionBroadcastReceiver mBroadcastReceiver;
- ConnectionToCarTypeLiveData(Context context) {
+ CarConnectionTypeLiveData(Context context) {
mContext = context;
mQueryHandler = new CarConnectionQueryHandler(
@@ -88,7 +88,7 @@
if (response == null) {
Log.w(TAG_CONNECTION_TO_CAR, "Null response from content provider when checking "
+ "connection to the car, treating as disconnected");
- postValue(ConnectionToCar.NOT_CONNECTED);
+ postValue(CarConnection.CONNECTION_TYPE_NOT_CONNECTED);
return;
}
@@ -96,14 +96,14 @@
if (carConnectionTypeColumn < 0) {
Log.e(TAG_CONNECTION_TO_CAR, "Connection to car response is missing the "
+ "connection type, treating as disconnected");
- postValue(ConnectionToCar.NOT_CONNECTED);
+ postValue(CarConnection.CONNECTION_TYPE_NOT_CONNECTED);
return;
}
if (!response.moveToNext()) {
- Log.e(TAG_CONNECTION_TO_CAR, "Connection to car response is empty, treating as "
+ Log.e(TAG_CONNECTION_TO_CAR, "Connection to car response is empty, treating as "
+ "disconnected");
- postValue(ConnectionToCar.NOT_CONNECTED);
+ postValue(CarConnection.CONNECTION_TYPE_NOT_CONNECTED);
return;
}
diff --git a/car/app/app/src/main/java/androidx/car/app/connection/ConnectionToCar.java b/car/app/app/src/main/java/androidx/car/app/connection/ConnectionToCar.java
index 1397c0a..4caabbe 100644
--- a/car/app/app/src/main/java/androidx/car/app/connection/ConnectionToCar.java
+++ b/car/app/app/src/main/java/androidx/car/app/connection/ConnectionToCar.java
@@ -33,14 +33,19 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+// TODO(b/169537526): Remove this class
/**
* A class that allows retrieval of information about connection to a car head unit.
+ *
+ * @deprecated use {@link CarConnection} instead.
*/
+@Deprecated
public final class ConnectionToCar {
/**
* Defines current car connection state.
*
- * <p>This is used for communication with the car host.
+ * <p>This is used for communication with the car host's content provider on queries for
+ * connection type.
*/
public static final String CAR_CONNECTION_STATE = "CarConnectionState";
@@ -87,8 +92,8 @@
public ConnectionToCar(@NonNull Context context) {
requireNonNull(context);
mConnectionTypeLiveData = isAutomotiveOS(context)
- ? new AutomotiveConnectionToCarTypeLiveData()
- : new ConnectionToCarTypeLiveData(context);
+ ? new AutomotiveCarConnectionTypeLiveData()
+ : new CarConnectionTypeLiveData(context);
}
/**
diff --git a/car/app/app/src/main/java/androidx/car/app/navigation/model/Step.java b/car/app/app/src/main/java/androidx/car/app/navigation/model/Step.java
index 5604161..5af30b8 100644
--- a/car/app/app/src/main/java/androidx/car/app/navigation/model/Step.java
+++ b/car/app/app/src/main/java/androidx/car/app/navigation/model/Step.java
@@ -173,15 +173,21 @@
private Maneuver mManeuver;
@Nullable
private CarIcon mLanesImage;
+ @Nullable
private CarText mCue;
@Nullable
private CarText mRoad;
/**
+ * Constructs a new builder of {@link Step}.
+ */
+ public Builder() {
+ }
+
+ /**
* Constructs a new builder of {@link Step} with a cue.
*
- * <p>A cue must always be set when the step is created and is used as a fallback when
- * {@link Maneuver} is not set or is unavailable.
+ * <p>A cue can be used as a fallback when {@link Maneuver} is not set or is unavailable.
*
* <p>Some cluster displays do not support UTF-8 encoded characters, in which case
* unsupported characters will not be displayed properly.
@@ -267,8 +273,7 @@
/**
* Sets a text description of this maneuver.
*
- * <p>Must always be set when the step is created and is used as a fallback when {@link
- * Maneuver} is not set or is unavailable.
+ * <p>A cue can be used as a fallback when {@link Maneuver} is not set or is unavailable.
*
* <p>For example "Turn left", "Make a U-Turn", "Sharp Right", or "Take the exit using
* the left lane"
diff --git a/car/app/app/src/test/java/androidx/car/app/connection/AutomotiveConnectionToCarTypeLiveDataTest.java b/car/app/app/src/test/java/androidx/car/app/connection/AutomotiveCarConnectionTypeLiveDataTest.java
similarity index 81%
rename from car/app/app/src/test/java/androidx/car/app/connection/AutomotiveConnectionToCarTypeLiveDataTest.java
rename to car/app/app/src/test/java/androidx/car/app/connection/AutomotiveCarConnectionTypeLiveDataTest.java
index 83a95bb..aeb08a8 100644
--- a/car/app/app/src/test/java/androidx/car/app/connection/AutomotiveConnectionToCarTypeLiveDataTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/connection/AutomotiveCarConnectionTypeLiveDataTest.java
@@ -28,10 +28,10 @@
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.internal.DoNotInstrument;
-/** Tests for {@link AutomotiveConnectionToCarTypeLiveData}. */
+/** Tests for {@link AutomotiveCarConnectionTypeLiveData}. */
@RunWith(RobolectricTestRunner.class)
@DoNotInstrument
-public class AutomotiveConnectionToCarTypeLiveDataTest {
+public class AutomotiveCarConnectionTypeLiveDataTest {
@Mock private Observer<Integer> mMockObserver;
@Before
@@ -41,8 +41,8 @@
@Test
public void observe_returnsNative() {
- new AutomotiveConnectionToCarTypeLiveData().observeForever(mMockObserver);
+ new AutomotiveCarConnectionTypeLiveData().observeForever(mMockObserver);
- verify(mMockObserver).onChanged(ConnectionToCar.NATIVE);
+ verify(mMockObserver).onChanged(CarConnection.CONNECTION_TYPE_NATIVE);
}
}
diff --git a/car/app/app/src/test/java/androidx/car/app/connection/ConnectionToCarTest.java b/car/app/app/src/test/java/androidx/car/app/connection/CarConnectionTest.java
similarity index 80%
rename from car/app/app/src/test/java/androidx/car/app/connection/ConnectionToCarTest.java
rename to car/app/app/src/test/java/androidx/car/app/connection/CarConnectionTest.java
index 18c6222..e7f4a7b 100644
--- a/car/app/app/src/test/java/androidx/car/app/connection/ConnectionToCarTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/connection/CarConnectionTest.java
@@ -31,23 +31,23 @@
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.internal.DoNotInstrument;
-/** Tests for {@link ConnectionToCar}. */
+/** Tests for {@link CarConnection}. */
@RunWith(RobolectricTestRunner.class)
@DoNotInstrument
-public class ConnectionToCarTest {
+public class CarConnectionTest {
private final Context mContext = ApplicationProvider.getApplicationContext();
@Test
public void getType_projection() {
- assertThat(new ConnectionToCar(mContext).getType()).isInstanceOf(
- ConnectionToCarTypeLiveData.class);
+ assertThat(new CarConnection(mContext).getType()).isInstanceOf(
+ CarConnectionTypeLiveData.class);
}
@Test
public void getType_automotive() {
shadowOf(mContext.getPackageManager()).setSystemFeature(FEATURE_AUTOMOTIVE, true);
- assertThat(new ConnectionToCar(mContext).getType()).isInstanceOf(
- AutomotiveConnectionToCarTypeLiveData.class);
+ assertThat(new CarConnection(mContext).getType()).isInstanceOf(
+ AutomotiveCarConnectionTypeLiveData.class);
}
}
diff --git a/car/app/app/src/test/java/androidx/car/app/connection/ConnectionToCarTypeLiveDataTest.java b/car/app/app/src/test/java/androidx/car/app/connection/CarConnectionTypeLiveDataTest.java
similarity index 73%
rename from car/app/app/src/test/java/androidx/car/app/connection/ConnectionToCarTypeLiveDataTest.java
rename to car/app/app/src/test/java/androidx/car/app/connection/CarConnectionTypeLiveDataTest.java
index 976b8ee..ae02a8e 100644
--- a/car/app/app/src/test/java/androidx/car/app/connection/ConnectionToCarTypeLiveDataTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/connection/CarConnectionTypeLiveDataTest.java
@@ -49,16 +49,16 @@
import org.robolectric.shadows.ShadowApplication;
import org.robolectric.shadows.ShadowLooper;
-/** Tests for {@link ConnectionToCarTypeLiveData}. */
+/** Tests for {@link CarConnectionTypeLiveData}. */
@RunWith(RobolectricTestRunner.class)
@DoNotInstrument
-public class ConnectionToCarTypeLiveDataTest {
+public class CarConnectionTypeLiveDataTest {
@Mock
private Observer<Integer> mMockObserver;
private final Application mApplication = ApplicationProvider.getApplicationContext();
private final Context mContext = ApplicationProvider.getApplicationContext();
- private ConnectionToCarTypeLiveData mConnectionToCarTypeLiveData;
+ private CarConnectionTypeLiveData mCarConnectionTypeLiveData;
private TestContentProvider mContentProvider;
@Before
@@ -66,76 +66,76 @@
MockitoAnnotations.initMocks(this);
ProviderInfo info = new ProviderInfo();
- info.authority = ConnectionToCarTypeLiveData.CAR_CONNECTION_AUTHORITY;
+ info.authority = CarConnectionTypeLiveData.CAR_CONNECTION_AUTHORITY;
mContentProvider =
Robolectric.buildContentProvider(TestContentProvider.class).create(info).get();
// Starts with 1 broadcast receiver (for CarPendingIntent)
assertThat(shadowOf(mApplication).getRegisteredReceivers()).hasSize(1);
- mConnectionToCarTypeLiveData = new ConnectionToCarTypeLiveData(mContext);
+ mCarConnectionTypeLiveData = new CarConnectionTypeLiveData(mContext);
}
@Test
public void observe_registersBroadcastReceiver() {
assertThat(shadowOf(mApplication).getRegisteredReceivers()).hasSize(1);
- mConnectionToCarTypeLiveData.observeForever(mMockObserver);
+ mCarConnectionTypeLiveData.observeForever(mMockObserver);
assertThat(shadowOf(mApplication).getRegisteredReceivers()).hasSize(2);
}
@Test
public void getInstance_queriesContentProvider() {
- mConnectionToCarTypeLiveData.observeForever(mMockObserver);
+ mCarConnectionTypeLiveData.observeForever(mMockObserver);
assertThat(mContentProvider.mDidQueryContentProvider).isTrue();
}
@Test
public void contentProviderQuery_wasProjecting() {
mContentProvider.mIsProjecting = true;
- mConnectionToCarTypeLiveData = new ConnectionToCarTypeLiveData(mContext);
+ mCarConnectionTypeLiveData = new CarConnectionTypeLiveData(mContext);
- mConnectionToCarTypeLiveData.observeForever(mMockObserver);
+ mCarConnectionTypeLiveData.observeForever(mMockObserver);
ShadowLooper.runUiThreadTasks();
- verify(mMockObserver).onChanged(ConnectionToCar.PROJECTION);
+ verify(mMockObserver).onChanged(CarConnection.CONNECTION_TYPE_PROJECTION);
}
@Test
public void contentProviderQuery_nullReturn() {
mContentProvider.mReturnNull = true;
- mConnectionToCarTypeLiveData = new ConnectionToCarTypeLiveData(mContext);
+ mCarConnectionTypeLiveData = new CarConnectionTypeLiveData(mContext);
- mConnectionToCarTypeLiveData.observeForever(mMockObserver);
+ mCarConnectionTypeLiveData.observeForever(mMockObserver);
ShadowLooper.runUiThreadTasks();
- verify(mMockObserver).onChanged(ConnectionToCar.NOT_CONNECTED);
+ verify(mMockObserver).onChanged(CarConnection.CONNECTION_TYPE_NOT_CONNECTED);
}
@Test
public void contentProviderQuery_noColumn() {
mContentProvider.mReturnNoColumn = true;
- mConnectionToCarTypeLiveData = new ConnectionToCarTypeLiveData(mContext);
+ mCarConnectionTypeLiveData = new CarConnectionTypeLiveData(mContext);
- mConnectionToCarTypeLiveData.observeForever(mMockObserver);
+ mCarConnectionTypeLiveData.observeForever(mMockObserver);
ShadowLooper.runUiThreadTasks();
- verify(mMockObserver).onChanged(ConnectionToCar.NOT_CONNECTED);
+ verify(mMockObserver).onChanged(CarConnection.CONNECTION_TYPE_NOT_CONNECTED);
}
@Test
public void contentProviderQuery_noRow() {
mContentProvider.mReturnNoRow = true;
- mConnectionToCarTypeLiveData = new ConnectionToCarTypeLiveData(mContext);
+ mCarConnectionTypeLiveData = new CarConnectionTypeLiveData(mContext);
- mConnectionToCarTypeLiveData.observeForever(mMockObserver);
+ mCarConnectionTypeLiveData.observeForever(mMockObserver);
ShadowLooper.runUiThreadTasks();
- verify(mMockObserver).onChanged(ConnectionToCar.NOT_CONNECTED);
+ verify(mMockObserver).onChanged(CarConnection.CONNECTION_TYPE_NOT_CONNECTED);
}
@Test
public void broadcastReceived_queriesAndSetsValue() {
InOrder mocks = inOrder(mMockObserver);
- mConnectionToCarTypeLiveData.observeForever(mMockObserver);
+ mCarConnectionTypeLiveData.observeForever(mMockObserver);
ShadowLooper.runUiThreadTasks();
ShadowApplication.Wrapper receiverWrapper = shadowOf(
@@ -143,11 +143,11 @@
mContentProvider.mIsProjecting = true;
receiverWrapper.broadcastReceiver.onReceive(mContext,
- new Intent(ConnectionToCar.ACTION_CAR_CONNECTION_UPDATED));
+ new Intent(CarConnection.ACTION_CAR_CONNECTION_UPDATED));
ShadowLooper.runUiThreadTasks();
- mocks.verify(mMockObserver).onChanged(ConnectionToCar.NOT_CONNECTED);
- mocks.verify(mMockObserver).onChanged(ConnectionToCar.PROJECTION);
+ mocks.verify(mMockObserver).onChanged(CarConnection.CONNECTION_TYPE_NOT_CONNECTED);
+ mocks.verify(mMockObserver).onChanged(CarConnection.CONNECTION_TYPE_PROJECTION);
mocks.verifyNoMoreInteractions();
}
@@ -155,11 +155,11 @@
public void stopObserving_removedBroadcastReceiver() {
assertThat(shadowOf(mApplication).getRegisteredReceivers()).hasSize(1);
- mConnectionToCarTypeLiveData.observeForever(mMockObserver);
+ mCarConnectionTypeLiveData.observeForever(mMockObserver);
assertThat(shadowOf(mApplication).getRegisteredReceivers()).hasSize(2);
- mConnectionToCarTypeLiveData.removeObserver(mMockObserver);
+ mCarConnectionTypeLiveData.removeObserver(mMockObserver);
assertThat(shadowOf(mApplication).getRegisteredReceivers()).hasSize(1);
}
@@ -182,7 +182,7 @@
@Nullable String selection, @Nullable String[] selectionArgs,
@Nullable String sortOrder) {
mDidQueryContentProvider = true;
- assertThat(projection).asList().containsExactly(ConnectionToCar.CAR_CONNECTION_STATE);
+ assertThat(projection).asList().containsExactly(CarConnection.CAR_CONNECTION_STATE);
if (mReturnNull) {
return null;
@@ -199,9 +199,9 @@
if (mReturnNoColumn) {
return cursor;
}
- rowBuilder.add(ConnectionToCar.CAR_CONNECTION_STATE,
- mIsProjecting ? ConnectionToCar.PROJECTION :
- ConnectionToCar.NOT_CONNECTED);
+ rowBuilder.add(CarConnection.CAR_CONNECTION_STATE,
+ mIsProjecting ? CarConnection.CONNECTION_TYPE_PROJECTION :
+ CarConnection.CONNECTION_TYPE_NOT_CONNECTED);
return cursor;
}
diff --git a/car/app/app/src/test/java/androidx/car/app/navigation/model/StepTest.java b/car/app/app/src/test/java/androidx/car/app/navigation/model/StepTest.java
index 1a46ce9..ea2a1d5 100644
--- a/car/app/app/src/test/java/androidx/car/app/navigation/model/StepTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/navigation/model/StepTest.java
@@ -77,6 +77,43 @@
}
@Test
+ public void createInstance_noCue() {
+ Lane lane = new Lane.Builder().addDirection(
+ LaneDirection.create(SHAPE_SHARP_LEFT, true)).build();
+
+ Step step =
+ new Step.Builder()
+ .addLane(lane)
+ .build();
+
+ assertThat(step.getCue()).isNull();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void createInstance_cueIsNullInBuilder() {
+ Lane lane = new Lane.Builder().addDirection(
+ LaneDirection.create(SHAPE_SHARP_LEFT, true)).build();
+ CharSequence charSequence = null;
+
+ Step step =
+ new Step.Builder(charSequence)
+ .addLane(lane)
+ .build();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void createInstance_cueIsNullInSetter() {
+ Lane lane = new Lane.Builder().addDirection(
+ LaneDirection.create(SHAPE_SHARP_LEFT, true)).build();
+
+ Step step =
+ new Step.Builder()
+ .setCue(null)
+ .addLane(lane)
+ .build();
+ }
+
+ @Test
public void createInstance_lanesImage_no_lanes_throws() {
String cue = "Left at State street.";
diff --git a/car/app/app/src/test/java/androidx/car/app/notification/CarAppExtenderTest.java b/car/app/app/src/test/java/androidx/car/app/notification/CarAppExtenderTest.java
index 1441ba9..fa6020b 100644
--- a/car/app/app/src/test/java/androidx/car/app/notification/CarAppExtenderTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/notification/CarAppExtenderTest.java
@@ -151,7 +151,8 @@
@Test
public void notification_extended_setContentIntent() {
Intent intent = new Intent(INTENT_PRIMARY_ACTION);
- PendingIntent contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+ PendingIntent contentIntent = PendingIntent.getBroadcast(mContext, 0, intent,
+ PendingIntent.FLAG_IMMUTABLE);
NotificationCompat.Builder builder =
new NotificationCompat.Builder(mContext, NOTIFICATION_CHANNEL_ID)
.extend(new CarAppExtender.Builder().setContentIntent(
@@ -163,7 +164,8 @@
@Test
public void notification_extended_setDeleteIntent() {
Intent intent = new Intent(INTENT_PRIMARY_ACTION);
- PendingIntent deleteIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+ PendingIntent deleteIntent = PendingIntent.getBroadcast(mContext, 0, intent,
+ PendingIntent.FLAG_IMMUTABLE);
NotificationCompat.Builder builder =
new NotificationCompat.Builder(mContext, NOTIFICATION_CHANNEL_ID)
.extend(new CarAppExtender.Builder().setDeleteIntent(deleteIntent).build());
@@ -185,12 +187,14 @@
int icon1 = TestUtils.getTestDrawableResId(mContext, "ic_test_1");
CharSequence title1 = "FirstAction";
Intent intent1 = new Intent(INTENT_PRIMARY_ACTION);
- PendingIntent actionIntent1 = PendingIntent.getBroadcast(mContext, 0, intent1, 0);
+ PendingIntent actionIntent1 = PendingIntent.getBroadcast(mContext, 0, intent1,
+ PendingIntent.FLAG_IMMUTABLE);
int icon2 = TestUtils.getTestDrawableResId(mContext, "ic_test_2");
CharSequence title2 = "SecondAction";
Intent intent2 = new Intent(INTENT_SECONDARY_ACTION);
- PendingIntent actionIntent2 = PendingIntent.getBroadcast(mContext, 0, intent2, 0);
+ PendingIntent actionIntent2 = PendingIntent.getBroadcast(mContext, 0, intent2,
+ PendingIntent.FLAG_IMMUTABLE);
NotificationCompat.Builder builder =
new NotificationCompat.Builder(mContext, NOTIFICATION_CHANNEL_ID)
diff --git a/car/app/app/src/test/java/androidx/car/app/notification/CarNotificationManagerTest.java b/car/app/app/src/test/java/androidx/car/app/notification/CarNotificationManagerTest.java
index cc01b10..7e55652 100644
--- a/car/app/app/src/test/java/androidx/car/app/notification/CarNotificationManagerTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/notification/CarNotificationManagerTest.java
@@ -70,9 +70,9 @@
mContext);
private final PendingIntent mDefaultPendingIntent = PendingIntent.getBroadcast(mContext, 1,
- new Intent("foo"), 0);
+ new Intent("foo"), PendingIntent.FLAG_IMMUTABLE);
private final PendingIntent mExtendedPendingIntent = PendingIntent.getBroadcast(mContext, 1,
- new Intent("bar"), 0);
+ new Intent("bar"), PendingIntent.FLAG_IMMUTABLE);
private int mDefaultIcon;
private int mExtendedIcon;
diff --git a/compose/animation/animation-core-lint/build.gradle b/compose/animation/animation-core-lint/build.gradle
index 9cee8fb..92c1abb 100644
--- a/compose/animation/animation-core-lint/build.gradle
+++ b/compose/animation/animation-core-lint/build.gradle
@@ -28,13 +28,7 @@
BundleInsideHelper.forInsideLintJar(project)
dependencies {
- // compileOnly because we use lintChecks and it doesn't allow other types of deps
- // this ugly hack exists because of b/63873667
- if (rootProject.hasProperty("android.injected.invoked.from.ide")) {
- compileOnly LINT_API_LATEST
- } else {
- compileOnly LINT_API_MIN
- }
+ compileOnly LINT_API_MIN
compileOnly KOTLIN_STDLIB
bundleInside(project(":compose:lint:common"))
diff --git a/compose/animation/animation-lint/build.gradle b/compose/animation/animation-lint/build.gradle
index 36f50b5..441f4b7 100644
--- a/compose/animation/animation-lint/build.gradle
+++ b/compose/animation/animation-lint/build.gradle
@@ -28,13 +28,7 @@
BundleInsideHelper.forInsideLintJar(project)
dependencies {
- // compileOnly because we use lintChecks and it doesn't allow other types of deps
- // this ugly hack exists because of b/63873667
- if (rootProject.hasProperty("android.injected.invoked.from.ide")) {
- compileOnly LINT_API_LATEST
- } else {
- compileOnly LINT_API_MIN
- }
+ compileOnly LINT_API_MIN
compileOnly KOTLIN_STDLIB
bundleInside(project(":compose:lint:common"))
diff --git a/compose/desktop/desktop/build.gradle b/compose/desktop/desktop/build.gradle
index ce53db3..a3ca2ad 100644
--- a/compose/desktop/desktop/build.gradle
+++ b/compose/desktop/desktop/build.gradle
@@ -19,6 +19,7 @@
import androidx.build.LibraryVersions
import androidx.build.RunApiTasks
import androidx.build.SupportConfigKt
+import androidx.build.ComposeJvmTarget
import static androidx.build.AndroidXPlugin.BUILD_ON_SERVER_TASK
import static androidx.build.dependencies.DependenciesKt.*
@@ -34,9 +35,9 @@
}
kotlin {
- jvm() {
- withJava()
- }
+ // Replace with jvm() { withJava() }
+ // Once the build switches to Kotlin 1.5
+ ComposeJvmTarget.withJava(jvm())
sourceSets {
commonMain.dependencies {
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/TextSelectionColorsScreenshotTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/TextSelectionColorsScreenshotTest.kt
index 111e669..13ee796 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/TextSelectionColorsScreenshotTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/TextSelectionColorsScreenshotTest.kt
@@ -140,6 +140,7 @@
.assertAgainstGolden(screenshotRule, "textField_defaultSelectionColors")
}
+ @FlakyTest(bugId = 188572883)
@Test
fun textField_customSelectionColors() {
rule.setContent {
diff --git a/compose/material/material-lint/build.gradle b/compose/material/material-lint/build.gradle
index 0ba4d6d..e413333 100644
--- a/compose/material/material-lint/build.gradle
+++ b/compose/material/material-lint/build.gradle
@@ -28,13 +28,7 @@
BundleInsideHelper.forInsideLintJar(project)
dependencies {
- // compileOnly because we use lintChecks and it doesn't allow other types of deps
- // this ugly hack exists because of b/63873667
- if (rootProject.hasProperty("android.injected.invoked.from.ide")) {
- compileOnly LINT_API_LATEST
- } else {
- compileOnly LINT_API_MIN
- }
+ compileOnly LINT_API_MIN
compileOnly KOTLIN_STDLIB
bundleInside(project(":compose:lint:common"))
diff --git a/compose/runtime/runtime-lint/build.gradle b/compose/runtime/runtime-lint/build.gradle
index e2db424..30b5400 100644
--- a/compose/runtime/runtime-lint/build.gradle
+++ b/compose/runtime/runtime-lint/build.gradle
@@ -28,13 +28,7 @@
BundleInsideHelper.forInsideLintJar(project)
dependencies {
- // compileOnly because we use lintChecks and it doesn't allow other types of deps
- // this ugly hack exists because of b/63873667
- if (rootProject.hasProperty("android.injected.invoked.from.ide")) {
- compileOnly(LINT_API_LATEST)
- } else {
- compileOnly(LINT_API_MIN)
- }
+ compileOnly(LINT_API_MIN)
compileOnly(KOTLIN_STDLIB)
bundleInside(project(":compose:lint:common"))
diff --git a/compose/runtime/runtime-saveable-lint/build.gradle b/compose/runtime/runtime-saveable-lint/build.gradle
index a1a65a0..dca4aab 100644
--- a/compose/runtime/runtime-saveable-lint/build.gradle
+++ b/compose/runtime/runtime-saveable-lint/build.gradle
@@ -28,13 +28,7 @@
BundleInsideHelper.forInsideLintJar(project)
dependencies {
- // compileOnly because we use lintChecks and it doesn't allow other types of deps
- // this ugly hack exists because of b/63873667
- if (rootProject.hasProperty("android.injected.invoked.from.ide")) {
- compileOnly(LINT_API_LATEST)
- } else {
- compileOnly(LINT_API_MIN)
- }
+ compileOnly(LINT_API_MIN)
compileOnly(KOTLIN_STDLIB)
bundleInside(project(":compose:lint:common"))
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
index ba6eb68..d6ea072 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
@@ -1211,7 +1211,6 @@
private fun endRoot() {
endGroup()
parentContext.doneComposing()
-
endGroup()
recordEndRoot()
finalizeCompose()
@@ -2538,6 +2537,7 @@
} finally {
isComposing = false
invalidations.clear()
+ providerUpdates.clear()
if (!complete) abortRoot()
}
}
diff --git a/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/CompositionLocalTests.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/CompositionLocalTests.kt
index f2dc064..c012791 100644
--- a/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/CompositionLocalTests.kt
+++ b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/CompositionLocalTests.kt
@@ -481,6 +481,53 @@
expectNoChanges()
assertFalse(composed.value)
}
+
+ @Test // Regression test for b/186094122
+ fun currentRetrievesCorrectValues() = compositionTest {
+ val state = mutableStateOf(0)
+ val providedValue = mutableStateOf(100)
+ val local = compositionLocalOf { 0 }
+ val static = staticCompositionLocalOf { -1 }
+ val providedStatic = mutableStateOf(2000)
+ var includeProviders by mutableStateOf(true)
+
+ @Composable
+ fun Validate(providedValue: Int) {
+ val currentValue = local.current
+ assertEquals(providedValue, currentValue)
+ state.value // Observe state for invalidates.
+ }
+
+ compose {
+ if (includeProviders) {
+ CompositionLocalProvider(
+ local provides providedValue.value,
+ static provides providedStatic.value
+ ) {
+ Validate(providedValue.value)
+ }
+ }
+ }
+
+ // Force an providerUpdates entry to be created.
+ providedStatic.value++
+ advance()
+
+ // Force a new provider scope to be created
+ includeProviders = false
+ advance()
+
+ includeProviders = true
+ advance()
+
+ // Change the provided value
+ providedValue.value++
+ advance()
+
+ // Ensure the old providerUpdates is not longer contains old values.
+ state.value++
+ advance()
+ }
}
data class SomeData(val value: String = "default")
diff --git a/compose/ui/ui-graphics-lint/build.gradle b/compose/ui/ui-graphics-lint/build.gradle
index 09e0ee9..8d06b87 100644
--- a/compose/ui/ui-graphics-lint/build.gradle
+++ b/compose/ui/ui-graphics-lint/build.gradle
@@ -28,13 +28,7 @@
BundleInsideHelper.forInsideLintJar(project)
dependencies {
- // compileOnly because we use lintChecks and it doesn't allow other types of deps
- // this ugly hack exists because of b/63873667
- if (rootProject.hasProperty("android.injected.invoked.from.ide")) {
- compileOnly(LINT_API_LATEST)
- } else {
- compileOnly(LINT_API_MIN)
- }
+ compileOnly(LINT_API_MIN)
compileOnly(KOTLIN_STDLIB)
bundleInside(project(":compose:lint:common"))
diff --git a/compose/ui/ui-lint/build.gradle b/compose/ui/ui-lint/build.gradle
index fe21cd0..ed38111 100644
--- a/compose/ui/ui-lint/build.gradle
+++ b/compose/ui/ui-lint/build.gradle
@@ -28,13 +28,7 @@
BundleInsideHelper.forInsideLintJar(project)
dependencies {
- // compileOnly because we use lintChecks and it doesn't allow other types of deps
- // this ugly hack exists because of b/63873667
- if (rootProject.hasProperty("android.injected.invoked.from.ide")) {
- compileOnly(LINT_API_LATEST)
- } else {
- compileOnly(LINT_API_MIN)
- }
+ compileOnly(LINT_API_MIN)
compileOnly(KOTLIN_STDLIB)
bundleInside(project(":compose:lint:common"))
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt
index 6cfa06b..16dfdc6 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt
@@ -1305,12 +1305,13 @@
++alignmentLinesCalculations
0
}
+ var linePosition by mutableStateOf(10)
activityTestRule.runOnUiThreadIR {
activity.setContent {
val innerChild = @Composable {
offset.value // Artificial remeasure.
Layout(content = {}) { _, _ ->
- layout(0, 0, mapOf(TestLine to 10)) { }
+ layout(0, 0, mapOf(TestLine to linePosition)) { }
}
}
val child = @Composable {
@@ -1340,12 +1341,12 @@
assertEquals(1, alignmentLinesCalculations)
layoutLatch = CountDownLatch(1)
- activityTestRule.runOnUiThreadIR { offset.value = 20 }
+ activityTestRule.runOnUiThreadIR { offset.value = 20; linePosition = 20 }
assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
assertEquals(1, alignmentLinesCalculations)
layoutLatch = CountDownLatch(1)
- activityTestRule.runOnUiThreadIR { offset.value = 10 }
+ activityTestRule.runOnUiThreadIR { offset.value = 10; linePosition = 30 }
assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
assertEquals(2, alignmentLinesCalculations)
}
@@ -1473,26 +1474,44 @@
}
}
assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
- // Two layouts as the alignment line was only queried after the child was placed.
- assertEquals(2, childLayouts)
+ assertEquals(1, childLayouts)
}
@Test
fun testAlignmentLines_whenQueriedAfterPlacing_haveCorrectNumberOfLayouts() {
- val TestLine = VerticalAlignmentLine(::min)
- var layoutLatch = CountDownLatch(1)
var childLayouts = 0
+ var childAlignmentLinesCalculations = 0
+ val TestLine = VerticalAlignmentLine { v1, _ ->
+ ++childAlignmentLinesCalculations
+ v1
+ }
val offset = mutableStateOf(10)
+ var linePositionState by mutableStateOf(10)
+ var linePosition = 10
+ fun changeLinePosition() {
+ linePosition = 30 - linePosition
+ linePositionState = 30 - linePositionState
+ }
+ var layoutLatch = CountDownLatch(1)
activityTestRule.runOnUiThreadIR {
activity.setContent {
- val child = @Composable {
+ val childChild = @Composable {
Layout(content = {}) { _, constraints ->
layout(
constraints.minWidth,
constraints.minHeight,
- mapOf(TestLine to 10)
+ mapOf(TestLine to linePositionState)
) {
offset.value // To ensure relayout.
+ }
+ }
+ }
+ val child = @Composable {
+ Layout(content = { childChild(); childChild() }) { measurables, constraints ->
+ val placeables = measurables.map { it.measure(constraints) }
+ layout(constraints.minWidth, constraints.minHeight) {
+ offset.value // To ensure relayout.
+ placeables.forEach { it.place(0, 0) }
++childLayouts
}
}
@@ -1503,9 +1522,9 @@
}) { measurables, constraints ->
val placeable = measurables[0].measure(constraints)
layout(placeable.width, placeable.height) {
- if (offset.value > 15) assertEquals(10, placeable[TestLine])
+ if (offset.value > 15) assertEquals(linePosition, placeable[TestLine])
placeable.place(0, 0)
- if (offset.value > 5) assertEquals(10, placeable[TestLine])
+ if (offset.value > 5) assertEquals(linePosition, placeable[TestLine])
}
}
}
@@ -1522,37 +1541,42 @@
}
}
assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
- // Two layouts as the alignment line was only queried after the child was placed.
- assertEquals(2, childLayouts)
-
- layoutLatch = CountDownLatch(1)
- activityTestRule.runOnUiThreadIR { offset.value = 12 }
- assertTrue(layoutLatch.await(5, TimeUnit.SECONDS))
- // Just one more layout as the alignment lines were speculatively calculated this time.
- assertEquals(3, childLayouts)
-
- layoutLatch = CountDownLatch(1)
- activityTestRule.runOnUiThreadIR { offset.value = 17 }
- assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
- // One layout as the alignment lines are queried before.
- assertEquals(4, childLayouts)
-
- layoutLatch = CountDownLatch(1)
- activityTestRule.runOnUiThreadIR { offset.value = 12 }
- assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
- // One layout as the alignment lines are still calculated speculatively.
- assertEquals(5, childLayouts)
+ assertEquals(2, childLayouts + childAlignmentLinesCalculations)
layoutLatch = CountDownLatch(1)
activityTestRule.runOnUiThreadIR { offset.value = 1 }
assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
- assertEquals(6, childLayouts)
+ assertEquals(3, childLayouts + childAlignmentLinesCalculations)
+
layoutLatch = CountDownLatch(1)
- activityTestRule.runOnUiThreadIR { offset.value = 10 }
+ activityTestRule.runOnUiThreadIR { offset.value = 10; changeLinePosition() }
assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
- // Two layouts again, since alignment lines were not queried during last layout,
- // so we did not calculate them speculatively anymore.
- assertEquals(8, childLayouts)
+ assertEquals(5, childLayouts + childAlignmentLinesCalculations)
+
+ layoutLatch = CountDownLatch(1)
+ activityTestRule.runOnUiThreadIR { offset.value = 12; changeLinePosition() }
+ assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
+ assertEquals(7, childLayouts + childAlignmentLinesCalculations)
+
+ layoutLatch = CountDownLatch(1)
+ activityTestRule.runOnUiThreadIR { offset.value = 17; changeLinePosition() }
+ assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
+ assertEquals(9, childLayouts + childAlignmentLinesCalculations)
+
+ layoutLatch = CountDownLatch(1)
+ activityTestRule.runOnUiThreadIR { offset.value = 12; changeLinePosition() }
+ assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
+ assertEquals(11, childLayouts + childAlignmentLinesCalculations)
+
+ layoutLatch = CountDownLatch(1)
+ activityTestRule.runOnUiThreadIR { offset.value = 1; changeLinePosition() }
+ assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
+ assertEquals(13, childLayouts + childAlignmentLinesCalculations)
+
+ layoutLatch = CountDownLatch(1)
+ activityTestRule.runOnUiThreadIR { offset.value = 10; changeLinePosition() }
+ assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
+ assertEquals(15, childLayouts + childAlignmentLinesCalculations)
}
@Test
@@ -1632,7 +1656,7 @@
testHorizontalLine: HorizontalAlignmentLine,
assertLines: Modifier.(Int, Int) -> Modifier
) {
- val layoutLatch = CountDownLatch(7)
+ val layoutLatch = CountDownLatch(1)
activityTestRule.runOnUiThreadIR {
activity.setContent {
val layout = @Composable { modifier: Modifier ->
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/EditorInfoTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/EditorInfoTest.kt
new file mode 100644
index 0000000..5894e49
--- /dev/null
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/EditorInfoTest.kt
@@ -0,0 +1,523 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.input
+
+import android.text.InputType
+import android.view.inputmethod.EditorInfo
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.ImeOptions
+import androidx.compose.ui.text.input.KeyboardCapitalization
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.text.input.TextFieldValue
+import androidx.compose.ui.text.input.update
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class EditorInfoTest {
+
+ @Test
+ fun test_fill_editor_info_text() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Text,
+ imeAction = ImeAction.Default
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_UNSPECIFIED
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_ascii() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Default
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
+ assertThat((EditorInfo.IME_FLAG_FORCE_ASCII and info.imeOptions) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_UNSPECIFIED
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_number() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Number,
+ imeAction = ImeAction.Default
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_NUMBER and info.inputType) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_UNSPECIFIED
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_phone() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Phone,
+ imeAction = ImeAction.Default
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_PHONE and info.inputType) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_UNSPECIFIED
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_uri() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Uri,
+ imeAction = ImeAction.Default
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
+ assertThat((InputType.TYPE_TEXT_VARIATION_URI and info.inputType) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_UNSPECIFIED
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_email() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Email,
+ imeAction = ImeAction.Default
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
+ assertThat((InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS and info.inputType) != 0)
+ .isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_UNSPECIFIED
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_password() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Password,
+ imeAction = ImeAction.Default
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
+ assertThat((InputType.TYPE_TEXT_VARIATION_PASSWORD and info.inputType) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_UNSPECIFIED
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_number_password() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.NumberPassword,
+ imeAction = ImeAction.Default
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_NUMBER and info.inputType) != 0).isTrue()
+ assertThat((InputType.TYPE_NUMBER_VARIATION_PASSWORD and info.inputType) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_UNSPECIFIED
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_action_none() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.None
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
+ assertThat((EditorInfo.IME_FLAG_FORCE_ASCII and info.imeOptions) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_NONE
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_action_go() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Go
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
+ assertThat((EditorInfo.IME_FLAG_FORCE_ASCII and info.imeOptions) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_GO
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_action_next() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Next
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
+ assertThat((EditorInfo.IME_FLAG_FORCE_ASCII and info.imeOptions) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_NEXT
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_action_previous() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Previous
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
+ assertThat((EditorInfo.IME_FLAG_FORCE_ASCII and info.imeOptions) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_PREVIOUS
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_action_search() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Search,
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
+ assertThat((EditorInfo.IME_FLAG_FORCE_ASCII and info.imeOptions) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_SEARCH
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_action_send() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Send
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
+ assertThat((EditorInfo.IME_FLAG_FORCE_ASCII and info.imeOptions) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_SEND
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_action_done() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done
+ )
+ )
+
+ assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
+ assertThat((EditorInfo.IME_FLAG_FORCE_ASCII and info.imeOptions) != 0).isTrue()
+ assertThat(
+ (EditorInfo.IME_MASK_ACTION and info.imeOptions)
+ == EditorInfo.IME_ACTION_DONE
+ ).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_multi_line() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ singleLine = false,
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done
+ )
+ )
+
+ assertThat((InputType.TYPE_TEXT_FLAG_MULTI_LINE and info.inputType) == 0).isFalse()
+ assertThat((EditorInfo.IME_FLAG_NO_ENTER_ACTION and info.imeOptions) == 0).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_multi_line_with_default_action() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ singleLine = false,
+ keyboardType = KeyboardType.Text,
+ imeAction = ImeAction.Default
+ )
+ )
+
+ assertThat((InputType.TYPE_TEXT_FLAG_MULTI_LINE and info.inputType) == 0).isFalse()
+ assertThat((EditorInfo.IME_FLAG_NO_ENTER_ACTION and info.imeOptions) == 0).isFalse()
+ }
+
+ @Test
+ fun test_fill_editor_info_single_line() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ singleLine = true,
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done
+ )
+ )
+
+ assertThat((InputType.TYPE_TEXT_FLAG_MULTI_LINE and info.inputType) == 0).isTrue()
+ assertThat((EditorInfo.IME_FLAG_NO_ENTER_ACTION and info.imeOptions) == 0).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_single_line_changes_ime_from_unspecified_to_done() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ singleLine = true,
+ keyboardType = KeyboardType.Text,
+ imeAction = ImeAction.Default
+ )
+ )
+
+ assertThat((EditorInfo.IME_ACTION_DONE and info.imeOptions) == 0).isFalse()
+ assertThat((EditorInfo.IME_ACTION_UNSPECIFIED and info.imeOptions) == 0).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_multi_line_not_set_when_input_type_is_not_text() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ singleLine = false,
+ keyboardType = KeyboardType.Number,
+ imeAction = ImeAction.Done
+ )
+ )
+
+ assertThat((InputType.TYPE_TEXT_FLAG_MULTI_LINE and info.inputType) == 0).isTrue()
+ assertThat((EditorInfo.IME_FLAG_NO_ENTER_ACTION and info.imeOptions) == 0).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_capitalization_none() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ capitalization = KeyboardCapitalization.None,
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done
+ )
+ )
+
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS and info.inputType) == 0).isTrue()
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_WORDS and info.inputType) == 0).isTrue()
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_SENTENCES and info.inputType) == 0).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_capitalization_characters() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ capitalization = KeyboardCapitalization.Characters,
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done
+ )
+ )
+
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS and info.inputType) == 0).isFalse()
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_WORDS and info.inputType) == 0).isTrue()
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_SENTENCES and info.inputType) == 0).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_capitalization_words() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ capitalization = KeyboardCapitalization.Words,
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done
+ )
+ )
+
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS and info.inputType) == 0).isTrue()
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_WORDS and info.inputType) == 0).isFalse()
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_SENTENCES and info.inputType) == 0).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_capitalization_sentences() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ capitalization = KeyboardCapitalization.Sentences,
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done,
+ )
+ )
+
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS and info.inputType) == 0).isTrue()
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_WORDS and info.inputType) == 0).isTrue()
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_SENTENCES and info.inputType) == 0).isFalse()
+ }
+
+ @Test
+ fun test_fill_editor_info_capitalization_not_added_when_input_type_is_not_text() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ capitalization = KeyboardCapitalization.Sentences,
+ keyboardType = KeyboardType.Number,
+ imeAction = ImeAction.Done,
+ )
+ )
+
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS and info.inputType) == 0).isTrue()
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_WORDS and info.inputType) == 0).isTrue()
+ assertThat((InputType.TYPE_TEXT_FLAG_CAP_SENTENCES and info.inputType) == 0).isTrue()
+ }
+
+ @Test
+ fun test_fill_editor_info_auto_correct_on() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ autoCorrect = true,
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done
+ )
+ )
+
+ assertThat((InputType.TYPE_TEXT_FLAG_AUTO_CORRECT and info.inputType) == 0).isFalse()
+ }
+
+ @Test
+ fun test_fill_editor_info_auto_correct_off() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ autoCorrect = false,
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done
+ )
+ )
+
+ assertThat((InputType.TYPE_TEXT_FLAG_AUTO_CORRECT and info.inputType) == 0).isTrue()
+ }
+
+ @Test
+ fun autocorrect_not_added_when_input_type_is_not_text() {
+ val info = EditorInfo()
+ info.update(
+ ImeOptions(
+ autoCorrect = true,
+ keyboardType = KeyboardType.Number,
+ imeAction = ImeAction.Done
+ )
+ )
+
+ assertThat((InputType.TYPE_TEXT_FLAG_AUTO_CORRECT and info.inputType) == 0).isTrue()
+ }
+
+ @Test
+ fun initial_default_selection_info_is_set() {
+ val info = EditorInfo()
+ info.update(ImeOptions.Default)
+
+ assertThat(info.initialSelStart).isEqualTo(0)
+ assertThat(info.initialSelEnd).isEqualTo(0)
+ }
+
+ @Test
+ fun initial_selection_info_is_set() {
+ val selection = TextRange(1, 2)
+ val info = EditorInfo()
+ info.update(ImeOptions.Default, TextFieldValue("abc", selection))
+
+ assertThat(info.initialSelStart).isEqualTo(selection.start)
+ assertThat(info.initialSelEnd).isEqualTo(selection.end)
+ }
+
+ private fun EditorInfo.update(imeOptions: ImeOptions) {
+ this.update(imeOptions, TextFieldValue())
+ }
+}
\ No newline at end of file
diff --git a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/input/TextInputServiceAndroidOnStateUpdateTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/TextInputServiceAndroidOnStateUpdateTest.kt
similarity index 74%
rename from compose/ui/ui/src/test/kotlin/androidx/compose/ui/input/TextInputServiceAndroidOnStateUpdateTest.kt
rename to compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/TextInputServiceAndroidOnStateUpdateTest.kt
index a43182af..25ba030 100644
--- a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/input/TextInputServiceAndroidOnStateUpdateTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/TextInputServiceAndroidOnStateUpdateTest.kt
@@ -16,43 +16,42 @@
package androidx.compose.ui.input
-import android.content.Context
import android.view.View
import android.view.inputmethod.EditorInfo
-import android.view.inputmethod.InputMethodManager
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.ImeOptions
+import androidx.compose.ui.text.input.InputMethodManager
import androidx.compose.ui.text.input.RecordingInputConnection
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.TextInputServiceAndroid
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
import com.google.common.truth.Truth.assertThat
import com.nhaarman.mockitokotlin2.any
-import com.nhaarman.mockitokotlin2.eq
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.never
import com.nhaarman.mockitokotlin2.times
import com.nhaarman.mockitokotlin2.verify
-import com.nhaarman.mockitokotlin2.whenever
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-@RunWith(JUnit4::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
class TextInputServiceAndroidOnStateUpdateTest {
private lateinit var textInputService: TextInputServiceAndroid
- private lateinit var imm: InputMethodManager
+ private lateinit var inputMethodManager: InputMethodManager
private lateinit var inputConnection: RecordingInputConnection
@Before
fun setup() {
- imm = mock()
- val view: View = mock()
- val context: Context = mock()
- whenever(context.getSystemService(eq(Context.INPUT_METHOD_SERVICE))).thenReturn(imm)
- whenever(view.context).thenReturn(context)
- textInputService = TextInputServiceAndroid(view)
+ val view = View(InstrumentationRegistry.getInstrumentation().context)
+ inputMethodManager = mock()
+ textInputService = TextInputServiceAndroid(view, mock())
+
+ textInputService = TextInputServiceAndroid(view, inputMethodManager)
textInputService.startInput(
value = TextFieldValue(""),
imeOptions = ImeOptions.Default,
@@ -71,8 +70,8 @@
newValue = newValue
)
- verify(imm, times(1)).restartInput(any())
- verify(imm, never()).updateSelection(any(), any(), any(), any(), any())
+ verify(inputMethodManager, times(1)).restartInput(any())
+ verify(inputMethodManager, never()).updateSelection(any(), any(), any(), any(), any())
assertThat(inputConnection.mTextFieldValue).isEqualTo(newValue)
assertThat(textInputService.state).isEqualTo(newValue)
@@ -86,8 +85,8 @@
newValue = newValue
)
- verify(imm, times(1)).restartInput(any())
- verify(imm, never()).updateSelection(any(), any(), any(), any(), any())
+ verify(inputMethodManager, times(1)).restartInput(any())
+ verify(inputMethodManager, never()).updateSelection(any(), any(), any(), any(), any())
assertThat(inputConnection.mTextFieldValue).isEqualTo(newValue)
assertThat(textInputService.state).isEqualTo(newValue)
@@ -101,8 +100,8 @@
newValue = newValue
)
- verify(imm, never()).restartInput(any())
- verify(imm, times(1)).updateSelection(any(), any(), any(), any(), any())
+ verify(inputMethodManager, never()).restartInput(any())
+ verify(inputMethodManager, times(1)).updateSelection(any(), any(), any(), any(), any())
assertThat(inputConnection.mTextFieldValue).isEqualTo(newValue)
assertThat(textInputService.state).isEqualTo(newValue)
@@ -116,8 +115,8 @@
newValue = newValue
)
- verify(imm, never()).restartInput(any())
- verify(imm, times(1)).updateSelection(any(), any(), any(), any(), any())
+ verify(inputMethodManager, never()).restartInput(any())
+ verify(inputMethodManager, times(1)).updateSelection(any(), any(), any(), any(), any())
assertThat(inputConnection.mTextFieldValue).isEqualTo(newValue)
assertThat(textInputService.state).isEqualTo(newValue)
@@ -131,8 +130,8 @@
newValue = value
)
- verify(imm, never()).restartInput(any())
- verify(imm, never()).updateSelection(any(), any(), any(), any(), any())
+ verify(inputMethodManager, never()).restartInput(any())
+ verify(inputMethodManager, never()).updateSelection(any(), any(), any(), any(), any())
assertThat(inputConnection.mTextFieldValue).isEqualTo(value)
assertThat(textInputService.state).isEqualTo(value)
@@ -146,8 +145,8 @@
newValue = value
)
- verify(imm, never()).restartInput(any())
- verify(imm, never()).updateSelection(any(), any(), any(), any(), any())
+ verify(inputMethodManager, never()).restartInput(any())
+ verify(inputMethodManager, never()).updateSelection(any(), any(), any(), any(), any())
// recreate the connection
inputConnection = textInputService.createInputConnection(EditorInfo())
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/AlignmentLineTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/AlignmentLineTest.kt
index 81b70cd..9c76455 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/AlignmentLineTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/AlignmentLineTest.kt
@@ -18,11 +18,18 @@
import androidx.activity.ComponentActivity
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.requiredSize
+import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableStateMapOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.IntOffset
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import org.junit.Assert.assertEquals
@@ -126,4 +133,1166 @@
}
rule.waitForIdle()
}
+
+ @Test
+ fun alignmentLinesArePropagated_whenSuppliedViaModifier() {
+ val size = 50
+ val sizeDp = with(rule.density) { size.toDp() }
+ val linePosition = 25
+ val hLine = HorizontalAlignmentLine(::min)
+ val vLine = VerticalAlignmentLine(::min)
+ rule.setContent {
+ val content = @Composable {
+ Box(Modifier.size(sizeDp)) {
+ Box(
+ Modifier.supplyAlignmentLines {
+ mapOf(
+ hLine to linePosition,
+ vLine to linePosition
+ )
+ }.size(sizeDp)
+ )
+ }
+ }
+
+ Layout(content) { measurables, constraints ->
+ val placeable = measurables.first().measure(constraints)
+ assertEquals(linePosition, placeable[hLine])
+ assertEquals(linePosition, placeable[vLine])
+ layout(0, 0) {}
+ }
+ }
+ }
+
+ @Test
+ fun alignmentLinesArePropagated_whenSuppliedViaModifier_withCorrectPosition() {
+ val size = 50
+ val sizeDp = with(rule.density) { size.toDp() }
+ val offset = 10
+ val offsetDp = with(rule.density) { offset.toDp() }
+ val linePosition = 25
+ val hLine = HorizontalAlignmentLine(::min)
+ val vLine = VerticalAlignmentLine(::min)
+ rule.setContent {
+ val content = @Composable {
+ Box(Modifier.size(sizeDp)) {
+ Box(
+ Modifier.offset(offsetDp, offsetDp)
+ .supplyAlignmentLines {
+ mapOf(
+ hLine to linePosition,
+ vLine to linePosition
+ )
+ }.size(sizeDp)
+ .offset(offsetDp, offsetDp)
+ )
+ }
+ }
+
+ Layout(content) { measurables, constraints ->
+ val placeable = measurables.first().measure(constraints)
+ assertEquals(linePosition + offset, placeable[hLine])
+ assertEquals(linePosition + offset, placeable[vLine])
+ layout(0, 0) {}
+ }
+ }
+ }
+
+ @Test
+ fun alignmentLinesChangeCausesRemeasure_whenSuppliedViaModifier() {
+ val size = 50
+ val sizeDp = with(rule.density) { size.toDp() }
+ val offset = 10
+ val linePosition = 25
+ val hLine = HorizontalAlignmentLine(::min)
+ val vLine = VerticalAlignmentLine(::min)
+ val alignmentLines = mutableStateMapOf(hLine to linePosition, vLine to linePosition)
+ var obtainedHLinePosition = -1
+ var obtainedVLinePosition = -1
+ rule.setContent {
+ val content = @Composable {
+ Box(Modifier.size(sizeDp)) {
+ Box(Modifier.supplyAlignmentLines { alignmentLines.toMap() }.size(sizeDp))
+ }
+ }
+
+ Layout(content) { measurables, constraints ->
+ val placeable = measurables.first().measure(constraints)
+ obtainedHLinePosition = placeable[hLine]
+ obtainedVLinePosition = placeable[vLine]
+ layout(0, 0) {}
+ }
+ }
+
+ rule.runOnIdle {
+ assertEquals(linePosition, obtainedHLinePosition)
+ assertEquals(linePosition, obtainedVLinePosition)
+ alignmentLines[hLine] = linePosition + offset
+ alignmentLines[vLine] = linePosition + offset
+ }
+
+ rule.runOnIdle {
+ assertEquals(linePosition + offset, obtainedHLinePosition)
+ assertEquals(linePosition + offset, obtainedVLinePosition)
+ }
+ }
+
+ @Test
+ fun alignmentLinesChangeCausesRemeasure_whenSuppliedViaLayout() {
+ val size = 50
+ val sizeDp = with(rule.density) { size.toDp() }
+ val offset = 10
+ val linePosition = 25
+ val hLine = HorizontalAlignmentLine(::min)
+ val vLine = VerticalAlignmentLine(::min)
+ val alignmentLines = mutableStateMapOf(hLine to linePosition, vLine to linePosition)
+ var obtainedHLinePosition = -1
+ var obtainedVLinePosition = -1
+ rule.setContent {
+ val content = @Composable {
+ val innerContent = @Composable {
+ Layout({}) { _, _ ->
+ layout(size, size, alignmentLines) {}
+ }
+ }
+ Layout(content = innerContent, Modifier.size(sizeDp)) { measurables, constraints ->
+ val placeable = measurables.first().measure(constraints)
+ layout(constraints.maxWidth, constraints.maxHeight) {
+ placeable.place(0, 0)
+ }
+ }
+ }
+
+ Layout(content) { measurables, constraints ->
+ val placeable = measurables.first().measure(constraints)
+ obtainedHLinePosition = placeable[hLine]
+ obtainedVLinePosition = placeable[vLine]
+ layout(0, 0) {}
+ }
+ }
+
+ rule.runOnIdle {
+ assertEquals(linePosition, obtainedHLinePosition)
+ assertEquals(linePosition, obtainedVLinePosition)
+ alignmentLines[hLine] = linePosition + offset
+ alignmentLines[vLine] = linePosition + offset
+ }
+
+ rule.runOnIdle {
+ assertEquals(linePosition + offset, obtainedHLinePosition)
+ assertEquals(linePosition + offset, obtainedVLinePosition)
+ }
+ }
+
+ @Test
+ fun scenario1() {
+ var parentMeasures = 0
+ var measures = 0
+ rule.setContent {
+ Parent(onMeasure = { ++parentMeasures }) {
+ Parent(onMeasure = { ++measures }, readDuringMeasure = true) {
+ Parent {
+ Provider()
+ }
+ }
+ }
+ }
+ rule.runOnIdle {
+ assertEquals(1, parentMeasures)
+ assertEquals(1, measures)
+ changeLinePosition()
+ }
+
+ rule.runOnIdle {
+ assertEquals(1, parentMeasures)
+ assertEquals(2, measures)
+ }
+ }
+
+ @Test
+ fun scenario2() {
+ var parentLayouts = 0
+ var measures = 0
+ var layouts = 0
+ rule.setContent {
+ Parent(onLayout = { ++parentLayouts }) {
+ Parent(
+ onMeasure = { ++measures },
+ onLayout = { ++layouts },
+ readDuringLayoutBeforePlacing = true
+ ) {
+ Parent {
+ Provider()
+ }
+ }
+ }
+ }
+ rule.runOnIdle {
+ assertEquals(1, parentLayouts)
+ assertEquals(1, measures)
+ assertEquals(1, layouts)
+ changeLinePosition()
+ }
+
+ rule.runOnIdle {
+ assertEquals(1, parentLayouts)
+ assertEquals(1, measures)
+ assertEquals(2, layouts)
+ }
+ }
+
+ @Test
+ fun scenario3() {
+ var parentLayouts = 0
+ var measures = 0
+ var layouts = 0
+ rule.setContent {
+ Parent(onLayout = { ++parentLayouts }) {
+ Parent(
+ onMeasure = { ++measures },
+ onLayout = { ++layouts },
+ readDuringLayoutAfterPlacing = true
+ ) {
+ Parent {
+ Provider()
+ }
+ }
+ }
+ }
+ rule.runOnIdle {
+ assertEquals(1, parentLayouts)
+ assertEquals(1, measures)
+ assertEquals(1, layouts)
+ changeLinePosition()
+ }
+
+ rule.runOnIdle {
+ assertEquals(1, parentLayouts)
+ assertEquals(1, measures)
+ assertEquals(2, layouts)
+ }
+ }
+
+ @Test
+ fun scenario4() {
+ var parentMeasures = 0
+ var parentLayouts = 0
+ var measures = 0
+ var layouts = 0
+ rule.setContent {
+ Parent(
+ onMeasure = { ++parentMeasures },
+ onLayout = { ++parentLayouts },
+ readDuringMeasure = true
+ ) {
+ Parent(
+ onMeasure = { ++measures },
+ onLayout = { ++layouts },
+ readDuringLayoutBeforePlacing = true
+ ) {
+ Parent {
+ Provider()
+ }
+ }
+ }
+ }
+ rule.runOnIdle {
+ assertEquals(1, parentMeasures)
+ assertEquals(1, parentLayouts)
+ assertEquals(1, measures)
+ assertEquals(1, layouts)
+ changeLinePosition()
+ }
+
+ rule.runOnIdle {
+ assertEquals(2, parentMeasures)
+ assertEquals(2, parentLayouts)
+ assertEquals(1, measures)
+ assertEquals(2, layouts)
+ }
+ }
+
+ @Test
+ fun scenario5() {
+ var parentMeasures = 0
+ var parentLayouts = 0
+ var measures = 0
+ var layouts = 0
+ rule.setContent {
+ Parent(
+ onMeasure = { ++parentMeasures },
+ onLayout = { ++parentLayouts },
+ readDuringMeasure = true
+ ) {
+ Parent(
+ onMeasure = { ++measures },
+ onLayout = { ++layouts },
+ readDuringLayoutAfterPlacing = true
+ ) {
+ Parent {
+ Provider()
+ }
+ }
+ }
+ }
+ rule.runOnIdle {
+ assertEquals(1, parentMeasures)
+ assertEquals(1, parentLayouts)
+ assertEquals(1, measures)
+ assertEquals(1, layouts)
+ changeLinePosition()
+ }
+
+ rule.runOnIdle {
+ assertEquals(2, parentMeasures)
+ assertEquals(2, parentLayouts)
+ assertEquals(1, measures)
+ assertEquals(2, layouts)
+ }
+ }
+
+ @Test
+ fun scenario6() {
+ var parentMeasures = 0
+ var parentLayouts = 0
+ var measures = 0
+ var layouts = 0
+ rule.setContent {
+ Parent(
+ onMeasure = { ++parentMeasures },
+ onLayout = { ++parentLayouts },
+ readDuringLayoutAfterPlacing = true
+ ) {
+ Parent(
+ onMeasure = { ++measures },
+ onLayout = { ++layouts },
+ readDuringMeasure = true
+ ) {
+ Parent {
+ Provider()
+ }
+ }
+ }
+ }
+ rule.runOnIdle {
+ assertEquals(1, parentMeasures)
+ assertEquals(1, parentLayouts)
+ assertEquals(1, measures)
+ assertEquals(1, layouts)
+ changeLinePosition()
+ }
+
+ rule.runOnIdle {
+ assertEquals(1, parentMeasures)
+ assertEquals(2, parentLayouts)
+ assertEquals(2, measures)
+ assertEquals(2, layouts)
+ }
+ }
+
+ @Test
+ fun scenario7() {
+ var parentMeasures = 0
+ var measures = 0
+ var layouts = 0
+ var childMeasures = 0
+ rule.setContent {
+ Parent(onMeasure = { ++parentMeasures }) {
+ Parent(
+ onMeasure = { ++measures },
+ onLayout = { ++layouts },
+ readDuringMeasure = true
+ ) {
+ Parent(modifier = Modifier.provider(), onMeasure = { ++childMeasures }) {
+ Parent()
+ }
+ }
+ }
+ }
+ rule.runOnIdle {
+ assertEquals(1, parentMeasures)
+ assertEquals(1, measures)
+ assertEquals(1, layouts)
+ assertEquals(1, childMeasures)
+ changeLinePosition()
+ }
+
+ rule.runOnIdle {
+ assertEquals(1, parentMeasures)
+ assertEquals(2, measures)
+ assertEquals(2, layouts)
+ assertEquals(2, childMeasures)
+ }
+ }
+
+ @Test
+ fun scenario8() {
+ var parentMeasures = 0
+ var measures = 0
+ var layouts = 0
+ var childMeasures = 0
+ rule.setContent {
+ Parent(onMeasure = { ++parentMeasures }) {
+ Parent(
+ onMeasure = { ++measures },
+ onLayout = { ++layouts },
+ readDuringLayoutBeforePlacing = true
+ ) {
+ Parent(modifier = Modifier.provider(), onMeasure = { ++childMeasures }) {
+ Parent()
+ }
+ }
+ }
+ }
+ rule.runOnIdle {
+ assertEquals(1, parentMeasures)
+ assertEquals(1, measures)
+ assertEquals(1, layouts)
+ assertEquals(1, childMeasures)
+ changeLinePosition()
+ }
+
+ rule.runOnIdle {
+ assertEquals(1, parentMeasures)
+ assertEquals(1, measures)
+ assertEquals(2, layouts)
+ assertEquals(2, childMeasures)
+ }
+ }
+
+ @Test
+ fun scenario9() {
+ var parentMeasures = 0
+ var measures = 0
+ var layouts = 0
+ var childMeasures = 0
+ rule.setContent {
+ Parent(onMeasure = { ++parentMeasures }) {
+ Parent(
+ onMeasure = { ++measures },
+ onLayout = { ++layouts },
+ readDuringLayoutAfterPlacing = true
+ ) {
+ Parent(modifier = Modifier.provider(), onMeasure = { ++childMeasures }) {
+ Parent()
+ }
+ }
+ }
+ }
+ rule.runOnIdle {
+ assertEquals(1, parentMeasures)
+ assertEquals(1, measures)
+ assertEquals(1, layouts)
+ assertEquals(1, childMeasures)
+ changeLinePosition()
+ }
+
+ rule.runOnIdle {
+ assertEquals(1, parentMeasures)
+ assertEquals(1, measures)
+ assertEquals(2, layouts)
+ assertEquals(2, childMeasures)
+ }
+ }
+
+ @Test
+ fun scenario10() {
+ var parentMeasures = 0
+ var measures = 0
+ var layouts = 0
+ var childMeasures = 0
+ rule.setContent {
+ Parent(onMeasure = { ++parentMeasures }, readDuringMeasure = true) {
+ Parent(
+ onMeasure = { ++measures },
+ onLayout = { ++layouts },
+ readDuringLayoutAfterPlacing = true
+ ) {
+ Parent(modifier = Modifier.provider(), onMeasure = { ++childMeasures }) {
+ Parent()
+ }
+ }
+ }
+ }
+ rule.runOnIdle {
+ assertEquals(1, parentMeasures)
+ assertEquals(1, measures)
+ assertEquals(1, layouts)
+ assertEquals(1, childMeasures)
+ changeLinePosition()
+ }
+
+ rule.runOnIdle {
+ assertEquals(2, parentMeasures)
+ assertEquals(1, measures)
+ assertEquals(2, layouts)
+ assertEquals(2, childMeasures)
+ }
+ }
+
+ @Test
+ fun scenario11() {
+ var measures = 0
+ var layouts = 0
+ var childMeasures = 0
+ rule.setContent {
+ Parent {
+ Parent(
+ onMeasure = { ++measures },
+ onLayout = { ++layouts },
+ readDuringLayoutAfterPlacing = true
+ ) {
+ Parent(
+ modifier = Modifier.reader(readDuringMeasure = true),
+ onMeasure = { ++childMeasures }
+ ) {
+ Provider()
+ }
+ }
+ }
+ }
+ rule.runOnIdle {
+ assertEquals(1, measures)
+ assertEquals(1, layouts)
+ assertEquals(1, childMeasures)
+ changeLinePosition()
+ }
+
+ rule.runOnIdle {
+ assertEquals(1, measures)
+ assertEquals(2, layouts)
+ assertEquals(2, childMeasures)
+ }
+ }
+
+ @Test
+ fun scenario12() {
+ var childMeasures = 0
+ rule.setContent {
+ Parent {
+ Provider(
+ modifier = Modifier.reader(readDuringMeasure = true),
+ onMeasure = { ++childMeasures }
+ )
+ }
+ }
+ rule.runOnIdle {
+ assertEquals(1, childMeasures)
+ changeLinePosition()
+ }
+
+ rule.runOnIdle {
+ assertEquals(2, childMeasures)
+ }
+ }
+
+ @Test
+ fun scenario13() {
+ var measures = 0
+ var childMeasures = 0
+ var childLayouts = 0
+ rule.setContent {
+ Parent(onMeasure = { ++measures }) {
+ Provider(
+ modifier = Modifier.reader(readDuringLayoutBeforePlacing = true),
+ onMeasure = { ++childMeasures },
+ onLayout = { ++childLayouts }
+ )
+ }
+ }
+ rule.runOnIdle {
+ assertEquals(1, measures)
+ assertEquals(1, childMeasures)
+ assertEquals(1, childLayouts)
+ changeLinePosition()
+ }
+
+ rule.runOnIdle {
+ assertEquals(1, measures)
+ assertEquals(2, childMeasures)
+ assertEquals(2, childLayouts)
+ }
+ }
+
+ @Test
+ fun scenario14() {
+ var measures = 0
+ var childMeasures = 0
+ var childLayouts = 0
+ rule.setContent {
+ Parent(onMeasure = { ++measures }) {
+ Provider(
+ modifier = Modifier.reader(readDuringLayoutAfterPlacing = true),
+ onMeasure = { ++childMeasures },
+ onLayout = { ++childLayouts }
+ )
+ }
+ }
+ rule.runOnIdle {
+ assertEquals(1, measures)
+ assertEquals(1, childMeasures)
+ assertEquals(1, childLayouts)
+ changeLinePosition()
+ }
+
+ rule.runOnIdle {
+ assertEquals(1, measures)
+ assertEquals(2, childMeasures)
+ assertEquals(2, childLayouts)
+ }
+ }
+
+ @Test
+ fun scenario15() {
+ var parentMeasures = 0
+ var measures = 0
+ var childMeasures = 0
+ rule.setContent {
+ Parent(onMeasure = { ++parentMeasures }) {
+ Parent(
+ modifier = Modifier.reader(readDuringMeasure = true).provider(),
+ onMeasure = { ++measures }
+ ) {
+ Parent(onMeasure = { ++childMeasures })
+ }
+ }
+ }
+ rule.runOnIdle {
+ assertEquals(1, parentMeasures)
+ assertEquals(1, measures)
+ assertEquals(1, childMeasures)
+ changeLinePosition()
+ }
+
+ rule.runOnIdle {
+ assertEquals(1, parentMeasures)
+ assertEquals(2, measures)
+ assertEquals(1, childMeasures)
+ }
+ }
+
+ @Test
+ fun scenario16() {
+ var parentMeasures = 0
+ var measures = 0
+ var childMeasures = 0
+ rule.setContent {
+ Parent(onMeasure = { ++parentMeasures }, readDuringMeasure = true) {
+ Parent(
+ modifier = Modifier.reader(readDuringMeasure = true).provider(),
+ onMeasure = { ++measures }
+ ) {
+ Parent(onMeasure = { ++childMeasures })
+ }
+ }
+ }
+ rule.runOnIdle {
+ assertEquals(1, parentMeasures)
+ assertEquals(1, measures)
+ assertEquals(1, childMeasures)
+ changeLinePosition()
+ }
+
+ rule.runOnIdle {
+ assertEquals(2, parentMeasures)
+ assertEquals(2, measures)
+ assertEquals(1, childMeasures)
+ }
+ }
+
+ @Test
+ fun scenario17() {
+ var parentMeasures = 0
+ var measures = 0
+ var childMeasures = 0
+ var read by mutableStateOf(true)
+ rule.setContent {
+ Parent(onMeasure = { ++parentMeasures }, readDuringMeasure = true) {
+ ChangingParent(
+ onMeasure = { ++measures },
+ readDuringMeasure = { read }
+ ) {
+ Parent(onMeasure = { ++childMeasures }) {
+ Provider()
+ }
+ }
+ }
+ }
+ rule.runOnIdle {
+ assertEquals(1, parentMeasures)
+ assertEquals(1, measures)
+ assertEquals(1, childMeasures)
+ changeLinePosition()
+ read = false
+ }
+
+ rule.runOnIdle {
+ assertEquals(2, parentMeasures)
+ assertEquals(2, measures)
+ assertEquals(1, childMeasures)
+ changeLinePosition()
+ }
+
+ rule.runOnIdle {
+ assertEquals(3, parentMeasures)
+ assertEquals(2, measures)
+ assertEquals(1, childMeasures)
+ }
+ }
+
+ @Test
+ fun scenario18() {
+ var parentLayouts = 0
+ var parentMeasures = 0
+ var measures = 0
+ var childMeasures = 0
+ var read by mutableStateOf(true)
+ rule.setContent {
+ Parent(
+ onMeasure = { ++parentMeasures },
+ onLayout = { ++parentLayouts },
+ readDuringLayoutAfterPlacing = true
+ ) {
+ ChangingParent(
+ onMeasure = { ++measures },
+ readDuringMeasure = { read }
+ ) {
+ Parent(onMeasure = { ++childMeasures }) {
+ Provider()
+ }
+ }
+ }
+ }
+ rule.runOnIdle {
+ assertEquals(1, parentMeasures)
+ assertEquals(1, parentLayouts)
+ assertEquals(1, measures)
+ assertEquals(1, childMeasures)
+ changeLinePosition()
+ read = false
+ }
+
+ rule.runOnIdle {
+ assertEquals(1, parentMeasures)
+ assertEquals(2, parentLayouts)
+ assertEquals(2, measures)
+ assertEquals(1, childMeasures)
+ changeLinePosition()
+ }
+
+ rule.runOnIdle {
+ assertEquals(1, parentMeasures)
+ assertEquals(3, parentLayouts)
+ assertEquals(2, measures)
+ assertEquals(1, childMeasures)
+ }
+ }
+
+ @Test
+ fun scenario19() {
+ var offset by mutableStateOf(IntOffset.Zero)
+ rule.setContent {
+ Parent(readDuringLayoutBeforePlacing = true) {
+ Provider(modifier = Modifier.offset { offset })
+ }
+ }
+ rule.runOnIdle {
+ offset = IntOffset(10, 10)
+ linePosition += 10
+ }
+
+ rule.waitForIdle()
+ }
+
+ @Test
+ fun scenario20() {
+ var parentLayouts = 0
+ var offset by mutableStateOf(IntOffset.Zero)
+ rule.setContent {
+ Parent(readDuringLayoutBeforePlacing = true, onLayout = { ++parentLayouts }) {
+ Parent {
+ Provider(modifier = Modifier.offset { offset })
+ }
+ }
+ }
+ rule.runOnIdle {
+ offset = IntOffset(10, 10)
+ linePosition += 10
+ }
+
+ rule.runOnIdle {
+ assertEquals(2, parentLayouts)
+ }
+
+ rule.waitForIdle()
+ }
+
+ @Test
+ fun scenario21() {
+ var parentMeasures = 0
+ var read by mutableStateOf(false)
+ rule.setContent {
+ ChangingParent(
+ readDuringMeasure = { read },
+ onMeasure = { ++parentMeasures }
+ ) {
+ Parent {
+ Provider()
+ }
+ }
+ }
+ rule.runOnIdle {
+ read = true
+ }
+
+ rule.runOnIdle {
+ assertEquals(2, parentMeasures)
+ }
+ }
+
+ @Test
+ fun scenario22() {
+ var parentLayouts = 0
+ var read by mutableStateOf(false)
+ rule.setContent {
+ ChangingParent(
+ readDuringLayoutBeforePlacing = { read },
+ onLayout = { ++parentLayouts }
+ ) {
+ Parent {
+ Provider()
+ }
+ }
+ }
+ rule.runOnIdle {
+ read = true
+ }
+
+ rule.runOnIdle {
+ assertEquals(2, parentLayouts)
+ }
+ }
+
+ @Test
+ fun scenario23() {
+ var obtainedPosition = 0
+ var changingState by mutableStateOf(false)
+ rule.setContent {
+ Layout(
+ content = {
+ Parent {
+ Provider()
+ }
+ }
+ ) { measurables, constraints ->
+ val placeable = measurables.first().measure(constraints)
+ layout(constraints.maxWidth, constraints.maxHeight) {
+ if (changingState) require(true)
+ obtainedPosition = placeable[TestLine]
+ placeable.place(0, 0)
+ }
+ }
+ }
+ rule.runOnIdle {
+ assertEquals(linePosition, obtainedPosition)
+ changeLinePosition()
+ changingState = true
+ }
+
+ rule.runOnIdle {
+ assertEquals(linePosition, obtainedPosition)
+ }
+ }
+
+ @Test
+ fun scenario24() {
+ var obtainedPosition = 0
+ var changingState by mutableStateOf(false)
+ rule.setContent {
+ Layout(
+ content = {
+ Parent {
+ Provider()
+ }
+ }
+ ) { measurables, constraints ->
+ val placeable = measurables.first().measure(constraints)
+ layout(constraints.maxWidth, constraints.maxHeight) {
+ if (changingState) require(true)
+ placeable.place(0, 0)
+ obtainedPosition = placeable[TestLine]
+ }
+ }
+ }
+ rule.runOnIdle {
+ assertEquals(linePosition, obtainedPosition)
+ changeLinePosition()
+ changingState = true
+ }
+
+ rule.runOnIdle {
+ assertEquals(linePosition, obtainedPosition)
+ }
+ }
+
+ @Test
+ fun scenario25() {
+ var obtainedPosition = 0
+ rule.setContent {
+ Parent(modifier = Modifier.onGloballyPositioned { obtainedPosition = it[TestLine] }) {
+ Parent {
+ Provider()
+ }
+ }
+ }
+ rule.runOnIdle {
+ assertEquals(linePosition, obtainedPosition)
+ changeLinePosition()
+ }
+
+ rule.runOnIdle {
+ assertEquals(linePosition, obtainedPosition)
+ }
+ }
+
+ @Test
+ fun scenario26() {
+ var measures = 0
+ var layouts = 0
+ rule.setContent {
+ Parent(
+ modifier = Modifier.reader(
+ readDuringMeasure = true,
+ readDuringLayoutBeforePlacing = true,
+ onMeasure = { ++measures },
+ onLayout = { ++layouts }
+ )
+ ) {
+ Parent {
+ Provider()
+ }
+ }
+ }
+ rule.runOnIdle {
+ assertEquals(1, measures)
+ assertEquals(1, layouts)
+ changeLinePosition()
+ }
+
+ rule.runOnIdle {
+ assertEquals(2, measures)
+ assertEquals(2, layouts)
+ }
+ }
+
+ @Test
+ fun scenario27() {
+ var measures = 0
+ var layouts = 0
+ rule.setContent {
+ Parent(
+ modifier = Modifier.reader(
+ readDuringLayoutBeforePlacing = true,
+ onMeasure = { ++measures },
+ onLayout = { ++layouts }
+ )
+ ) {
+ Parent {
+ Provider()
+ }
+ }
+ }
+ rule.runOnIdle {
+ assertEquals(1, measures)
+ assertEquals(1, layouts)
+ changeLinePosition()
+ }
+
+ rule.runOnIdle {
+ assertEquals(1, measures)
+ assertEquals(2, layouts)
+ }
+ }
+
+ @Test
+ fun scenario28() {
+ var measures = 0
+ var layouts = 0
+ rule.setContent {
+ Parent(
+ modifier = Modifier.reader(
+ readDuringLayoutAfterPlacing = true,
+ onMeasure = { ++measures },
+ onLayout = { ++layouts }
+ )
+ ) {
+ Parent {
+ Provider()
+ }
+ }
+ }
+ rule.runOnIdle {
+ assertEquals(1, measures)
+ assertEquals(1, layouts)
+ changeLinePosition()
+ }
+
+ rule.runOnIdle {
+ assertEquals(1, measures)
+ assertEquals(2, layouts)
+ }
+ }
+
+ private var linePosition = 10
+ private var linePositionState by mutableStateOf(10)
+ private fun changeLinePosition() {
+ linePosition += 10
+ linePositionState += 10
+ }
+ private val TestLine = HorizontalAlignmentLine(::min)
+
+ @Composable
+ private fun Parent(
+ modifier: Modifier = Modifier,
+ onMeasure: () -> Unit = {},
+ onLayout: () -> Unit = {},
+ readDuringMeasure: Boolean = false,
+ readDuringLayoutBeforePlacing: Boolean = false,
+ readDuringLayoutAfterPlacing: Boolean = false,
+ content: @Composable () -> Unit = {}
+ ) {
+ ChangingParent(
+ modifier,
+ onMeasure,
+ onLayout,
+ { readDuringMeasure },
+ { readDuringLayoutBeforePlacing },
+ { readDuringLayoutAfterPlacing },
+ content
+ )
+ }
+
+ @Composable
+ private fun ChangingParent(
+ modifier: Modifier = Modifier,
+ onMeasure: () -> Unit = {},
+ onLayout: () -> Unit = {},
+ readDuringMeasure: () -> Boolean = { false },
+ readDuringLayoutBeforePlacing: () -> Boolean = { false },
+ readDuringLayoutAfterPlacing: () -> Boolean = { false },
+ content: @Composable () -> Unit = {}
+ ) {
+ Layout(content, modifier) { measurables, constraints ->
+ onMeasure()
+ val placeables = measurables.map {
+ it.measure(constraints).also {
+ if (readDuringMeasure()) assertEquals(linePosition, it[TestLine])
+ }
+ }
+ layout(constraints.maxWidth, constraints.maxHeight) {
+ onLayout()
+ placeables.forEach { placeable ->
+ if (readDuringLayoutBeforePlacing()) {
+ // placeable[TestLine]
+ assertEquals(linePosition, placeable[TestLine])
+ }
+ placeable.place(0, 0)
+ if (readDuringLayoutAfterPlacing()) {
+ // placeable[TestLine]
+ assertEquals(linePosition, placeable[TestLine])
+ }
+ }
+ }
+ }
+ }
+
+ @Composable
+ private fun Provider(
+ modifier: Modifier = Modifier,
+ onMeasure: () -> Unit = {},
+ onLayout: () -> Unit = {},
+ content: @Composable () -> Unit = {}
+ ) {
+ Layout(content, modifier) { _, constraints ->
+ onMeasure()
+ layout(
+ constraints.maxWidth,
+ constraints.maxHeight,
+ mapOf(TestLine to linePositionState)
+ ) {
+ onLayout()
+ }
+ }
+ }
+
+ private fun Modifier.reader(
+ onMeasure: () -> Unit = {},
+ onLayout: () -> Unit = {},
+ readDuringMeasure: Boolean = false,
+ readDuringLayoutBeforePlacing: Boolean = false,
+ readDuringLayoutAfterPlacing: Boolean = false
+ ) = this.then(
+ ReaderModifier(
+ onMeasure,
+ onLayout,
+ readDuringMeasure,
+ readDuringLayoutBeforePlacing,
+ readDuringLayoutAfterPlacing
+ )
+ )
+ private inner class ReaderModifier(
+ val onMeasure: () -> Unit,
+ val onLayout: () -> Unit,
+ val readDuringMeasure: Boolean,
+ val readDuringLayoutBeforePlacing: Boolean,
+ val readDuringLayoutAfterPlacing: Boolean
+ ) : LayoutModifier {
+ override fun MeasureScope.measure(
+ measurable: Measurable,
+ constraints: Constraints
+ ): MeasureResult {
+ onMeasure()
+ val placeable = measurable.measure(constraints)
+ if (readDuringMeasure) assertEquals(linePosition, placeable[TestLine])
+ return layout(constraints.maxWidth, constraints.maxHeight) {
+ onLayout()
+ if (readDuringLayoutBeforePlacing) assertEquals(linePosition, placeable[TestLine])
+ placeable.place(0, 0)
+ if (readDuringLayoutAfterPlacing) assertEquals(linePosition, placeable[TestLine])
+ }
+ }
+ }
+
+ private fun Modifier.provider() = this.then(ProviderModifier())
+ private inner class ProviderModifier : LayoutModifier {
+ override fun MeasureScope.measure(
+ measurable: Measurable,
+ constraints: Constraints
+ ): MeasureResult {
+ val placeable = measurable.measure(constraints)
+ return layout(
+ constraints.maxWidth,
+ constraints.maxHeight,
+ mapOf(TestLine to linePositionState)
+ ) {
+ placeable.place(0, 0)
+ }
+ }
+
+ override fun hashCode(): Int {
+ return 0
+ }
+
+ override fun equals(other: Any?): Boolean {
+ return other is ProviderModifier
+ }
+ }
+
+ private fun Modifier.supplyAlignmentLines(alignmentLines: () -> Map<AlignmentLine, Int>) =
+ layout { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
+ layout(placeable.width, placeable.height, alignmentLines()) {
+ placeable.place(0, 0)
+ }
+ }
}
\ No newline at end of file
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/OnGloballyPositionedTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/OnGloballyPositionedTest.kt
index d7ae773..c66b1c7 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/OnGloballyPositionedTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/OnGloballyPositionedTest.kt
@@ -621,16 +621,24 @@
@Test
fun testAlignmentLinesArePresent() {
val latch = CountDownLatch(1)
- val line = VerticalAlignmentLine(::min)
+ val line1 = VerticalAlignmentLine(::min)
+ val line2 = HorizontalAlignmentLine(::min)
val lineValue = 10
rule.setContent {
val onPositioned = Modifier.onGloballyPositioned { coordinates: LayoutCoordinates ->
- assertEquals(1, coordinates.providedAlignmentLines.size)
- assertEquals(lineValue, coordinates[line])
+ assertEquals(2, coordinates.providedAlignmentLines.size)
+ assertEquals(lineValue, coordinates[line1])
+ assertEquals(lineValue, coordinates[line2])
latch.countDown()
}
- Layout(modifier = onPositioned, content = { }) { _, _ ->
- layout(0, 0, mapOf(line to lineValue)) { }
+ val lineProvider = Modifier.layout { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
+ layout(0, 0, mapOf(line2 to lineValue)) {
+ placeable.place(0, 0)
+ }
+ }
+ Layout(modifier = onPositioned.then(lineProvider), content = { }) { _, _ ->
+ layout(0, 0, mapOf(line1 to lineValue)) { }
}
}
assertTrue(latch.await(1, TimeUnit.SECONDS))
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/InputMethodManager.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/InputMethodManager.kt
new file mode 100644
index 0000000..39071a16
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/InputMethodManager.kt
@@ -0,0 +1,86 @@
+/*
+ * 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.text.input
+
+import android.content.Context
+import android.os.IBinder
+import android.view.View
+import android.view.inputmethod.ExtractedText
+
+internal interface InputMethodManager {
+ fun restartInput(view: View)
+
+ fun showSoftInput(view: View)
+
+ fun hideSoftInputFromWindow(windowToken: IBinder?)
+
+ fun updateExtractedText(
+ view: View,
+ token: Int,
+ extractedText: ExtractedText
+ )
+
+ fun updateSelection(
+ view: View,
+ selectionStart: Int,
+ selectionEnd: Int,
+ compositionStart: Int,
+ compositionEnd: Int
+ )
+}
+
+/**
+ * Wrapper class to prevent depending on getSystemService and final InputMethodManager.
+ * Let's us test TextInputServiceAndroid class.
+ */
+internal class InputMethodManagerImpl(context: Context) : InputMethodManager {
+
+ private val imm by lazy(LazyThreadSafetyMode.NONE) {
+ context.getSystemService(Context.INPUT_METHOD_SERVICE)
+ as android.view.inputmethod.InputMethodManager
+ }
+
+ override fun restartInput(view: View) {
+ imm.restartInput(view)
+ }
+
+ override fun showSoftInput(view: View) {
+ imm.showSoftInput(view, 0)
+ }
+
+ override fun hideSoftInputFromWindow(windowToken: IBinder?) {
+ imm.hideSoftInputFromWindow(windowToken, 0)
+ }
+
+ override fun updateExtractedText(
+ view: View,
+ token: Int,
+ extractedText: ExtractedText
+ ) {
+ imm.updateExtractedText(view, token, extractedText)
+ }
+
+ override fun updateSelection(
+ view: View,
+ selectionStart: Int,
+ selectionEnd: Int,
+ compositionStart: Int,
+ compositionEnd: Int
+ ) {
+ imm.updateSelection(view, selectionStart, selectionEnd, compositionStart, compositionEnd)
+ }
+}
\ No newline at end of file
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/RecordingInputConnection.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/RecordingInputConnection.android.kt
index 6ff574f..ceedc8c 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/RecordingInputConnection.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/RecordingInputConnection.android.kt
@@ -29,7 +29,6 @@
import android.view.inputmethod.ExtractedTextRequest
import android.view.inputmethod.InputConnection
import android.view.inputmethod.InputContentInfo
-import android.view.inputmethod.InputMethodManager
import androidx.annotation.VisibleForTesting
internal const val DEBUG = false
@@ -94,7 +93,11 @@
* This function may emits updateSelection and updateExtractedText to notify IMEs that the text
* contents has changed if needed.
*/
- fun updateInputState(state: TextFieldValue, imm: InputMethodManager, view: View) {
+ fun updateInputState(
+ state: TextFieldValue,
+ inputMethodManager: InputMethodManager,
+ view: View
+ ) {
if (!isActive) return
if (DEBUG) { logDebug("RecordingInputConnection.updateInputState: $state") }
@@ -102,7 +105,11 @@
mTextFieldValue = state
if (extractedTextMonitorMode) {
- imm.updateExtractedText(view, currentExtractedTextRequestToken, state.toExtractedText())
+ inputMethodManager.updateExtractedText(
+ view,
+ currentExtractedTextRequestToken,
+ state.toExtractedText()
+ )
}
// updateSelection API requires -1 if there is no composition
@@ -115,7 +122,7 @@
"composition = ($compositionStart, $compositionEnd))"
)
}
- imm.updateSelection(
+ inputMethodManager.updateSelection(
view, state.selection.min, state.selection.max, compositionStart, compositionEnd
)
}
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 0ecb4fe..e008960 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
@@ -16,9 +16,6 @@
package androidx.compose.ui.text.input
-import android.annotation.SuppressLint
-import android.content.Context
-import android.os.Build
import android.text.InputType
import android.util.Log
import android.view.KeyEvent
@@ -27,9 +24,9 @@
import android.view.inputmethod.BaseInputConnection
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputConnection
-import android.view.inputmethod.InputMethodManager
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.text.TextRange
+import androidx.core.view.inputmethod.EditorInfoCompat
import kotlinx.coroutines.channels.Channel
import kotlin.math.roundToInt
@@ -38,7 +35,10 @@
/**
* Provide Android specific input service with the Operating System.
*/
-internal class TextInputServiceAndroid(val view: View) : PlatformTextInputService {
+internal class TextInputServiceAndroid(
+ val view: View,
+ private val inputMethodManager: InputMethodManager
+) : PlatformTextInputService {
/** True if the currently editable composable has connected */
private var editorHasFocus = false
@@ -55,21 +55,11 @@
private var imeOptions = ImeOptions.Default
private var ic: RecordingInputConnection? = null
// used for sendKeyEvent delegation
- private var baseInputConnection: BaseInputConnection = BaseInputConnection(view, false)
- private var focusedRect: android.graphics.Rect? = null
+ private val baseInputConnection by lazy(LazyThreadSafetyMode.NONE) {
+ BaseInputConnection(view, false)
+ }
- private var _imm: InputMethodManager? = null
- /**
- * The editable buffer used for BaseInputConnection.
- */
- private val imm: InputMethodManager
- get() {
- if (_imm == null) {
- _imm = view.context.getSystemService(Context.INPUT_METHOD_SERVICE) as
- InputMethodManager
- }
- return _imm!!
- }
+ private var focusedRect: android.graphics.Rect? = null
/**
* A channel that is used to send ShowKeyboard/HideKeyboard commands. Send 'true' for
@@ -83,6 +73,8 @@
focusedRect?.let { view.requestRectangleOnScreen(it) }
}
+ internal constructor(view: View) : this(view, InputMethodManagerImpl(view.context))
+
init {
if (DEBUG) { Log.d(TAG, "$DEBUG_CLASS.create") }
@@ -104,7 +96,8 @@
if (!editorHasFocus) {
return null
}
- fillEditorInfo(outAttrs)
+
+ outAttrs.update(imeOptions, state)
return RecordingInputConnection(
initState = state,
@@ -167,7 +160,7 @@
private fun restartInput() {
if (DEBUG) Log.d(TAG, "$DEBUG_CLASS.restartInput")
- imm.restartInput(view)
+ inputMethodManager.restartInput(view)
}
override fun showSoftwareKeyboard() {
@@ -189,10 +182,10 @@
// to make sure that we use the most recent value.
if (showKeyboardChannel.poll() ?: showKeyboard) {
if (DEBUG) { Log.d(TAG, "$DEBUG_CLASS.keyboardVisibilityEventLoop.showSoftInput") }
- imm.showSoftInput(view, 0)
+ inputMethodManager.showSoftInput(view)
} else {
if (DEBUG) { Log.d(TAG, "$DEBUG_CLASS.keyboardVisibilityEventLoop.hideSoftInput") }
- imm.hideSoftInputFromWindow(view.windowToken, 0)
+ inputMethodManager.hideSoftInputFromWindow(view.windowToken)
}
}
}
@@ -224,7 +217,7 @@
if (restartInput) {
restartInput()
} else {
- ic?.updateInputState(this.state, imm, view)
+ ic?.updateInputState(this.state, inputMethodManager, view)
}
}
@@ -246,97 +239,94 @@
view.requestRectangleOnScreen(focusedRect)
}
}
+}
- /**
- * Fills necessary info of EditorInfo.
- */
- private fun fillEditorInfo(outInfo: EditorInfo) {
- outInfo.imeOptions = when (imeOptions.imeAction) {
- ImeAction.Default -> {
- if (imeOptions.singleLine) {
- // this is the last resort to enable single line
- // Android IME still show return key even if multi line is not send
- // TextView.java#onCreateInputConnection
- EditorInfo.IME_ACTION_DONE
- } else {
- EditorInfo.IME_ACTION_UNSPECIFIED
- }
- }
- ImeAction.None -> EditorInfo.IME_ACTION_NONE
- ImeAction.Go -> EditorInfo.IME_ACTION_GO
- ImeAction.Next -> EditorInfo.IME_ACTION_NEXT
- ImeAction.Previous -> EditorInfo.IME_ACTION_PREVIOUS
- ImeAction.Search -> EditorInfo.IME_ACTION_SEARCH
- ImeAction.Send -> EditorInfo.IME_ACTION_SEND
- ImeAction.Done -> EditorInfo.IME_ACTION_DONE
- else -> error("invalid ImeAction")
- }
- when (imeOptions.keyboardType) {
- KeyboardType.Text -> outInfo.inputType = InputType.TYPE_CLASS_TEXT
- KeyboardType.Ascii -> {
- outInfo.inputType = InputType.TYPE_CLASS_TEXT
- outInfo.imeOptions = outInfo.imeOptions or EditorInfo.IME_FLAG_FORCE_ASCII
- }
- KeyboardType.Number -> outInfo.inputType = InputType.TYPE_CLASS_NUMBER
- KeyboardType.Phone -> outInfo.inputType = InputType.TYPE_CLASS_PHONE
- KeyboardType.Uri ->
- outInfo.inputType = InputType.TYPE_CLASS_TEXT or EditorInfo.TYPE_TEXT_VARIATION_URI
- KeyboardType.Email ->
- outInfo.inputType =
- InputType.TYPE_CLASS_TEXT or EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
- KeyboardType.Password -> {
- outInfo.inputType =
- InputType.TYPE_CLASS_TEXT or EditorInfo.TYPE_TEXT_VARIATION_PASSWORD
- }
- KeyboardType.NumberPassword -> {
- outInfo.inputType =
- InputType.TYPE_CLASS_NUMBER or EditorInfo.TYPE_NUMBER_VARIATION_PASSWORD
- }
- else -> error("Invalid Keyboard Type")
- }
-
- if (!imeOptions.singleLine) {
- if (hasFlag(outInfo.inputType, InputType.TYPE_CLASS_TEXT)) {
- // TextView.java#setInputTypeSingleLine
- outInfo.inputType = outInfo.inputType or InputType.TYPE_TEXT_FLAG_MULTI_LINE
-
- if (imeOptions.imeAction == ImeAction.Default) {
- outInfo.imeOptions = outInfo.imeOptions or EditorInfo.IME_FLAG_NO_ENTER_ACTION
- }
+/**
+ * Fills necessary info of EditorInfo.
+ */
+internal fun EditorInfo.update(imeOptions: ImeOptions, textFieldValue: TextFieldValue) {
+ this.imeOptions = when (imeOptions.imeAction) {
+ ImeAction.Default -> {
+ if (imeOptions.singleLine) {
+ // this is the last resort to enable single line
+ // Android IME still show return key even if multi line is not send
+ // TextView.java#onCreateInputConnection
+ EditorInfo.IME_ACTION_DONE
+ } else {
+ EditorInfo.IME_ACTION_UNSPECIFIED
}
}
-
- if (hasFlag(outInfo.inputType, InputType.TYPE_CLASS_TEXT)) {
- when (imeOptions.capitalization) {
- KeyboardCapitalization.None -> {
- /* do nothing */
- }
- KeyboardCapitalization.Characters -> {
- outInfo.inputType = outInfo.inputType or InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS
- }
- KeyboardCapitalization.Words -> {
- outInfo.inputType = outInfo.inputType or InputType.TYPE_TEXT_FLAG_CAP_WORDS
- }
- KeyboardCapitalization.Sentences -> {
- outInfo.inputType = outInfo.inputType or InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
- }
- }
-
- if (imeOptions.autoCorrect) {
- outInfo.inputType = outInfo.inputType or InputType.TYPE_TEXT_FLAG_AUTO_CORRECT
- }
+ ImeAction.None -> EditorInfo.IME_ACTION_NONE
+ ImeAction.Go -> EditorInfo.IME_ACTION_GO
+ ImeAction.Next -> EditorInfo.IME_ACTION_NEXT
+ ImeAction.Previous -> EditorInfo.IME_ACTION_PREVIOUS
+ ImeAction.Search -> EditorInfo.IME_ACTION_SEARCH
+ ImeAction.Send -> EditorInfo.IME_ACTION_SEND
+ ImeAction.Done -> EditorInfo.IME_ACTION_DONE
+ else -> error("invalid ImeAction")
+ }
+ when (imeOptions.keyboardType) {
+ KeyboardType.Text -> this.inputType = InputType.TYPE_CLASS_TEXT
+ KeyboardType.Ascii -> {
+ this.inputType = InputType.TYPE_CLASS_TEXT
+ this.imeOptions = this.imeOptions or EditorInfo.IME_FLAG_FORCE_ASCII
}
-
- outInfo.initialSelStart = state.selection.start
- outInfo.initialSelEnd = state.selection.end
-
- @SuppressLint("UnsafeNewApiCall")
- if (Build.VERSION.SDK_INT >= 30) {
- outInfo.setInitialSurroundingText(state.text)
+ KeyboardType.Number -> this.inputType = InputType.TYPE_CLASS_NUMBER
+ KeyboardType.Phone -> this.inputType = InputType.TYPE_CLASS_PHONE
+ KeyboardType.Uri ->
+ this.inputType = InputType.TYPE_CLASS_TEXT or EditorInfo.TYPE_TEXT_VARIATION_URI
+ KeyboardType.Email ->
+ this.inputType =
+ InputType.TYPE_CLASS_TEXT or EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
+ KeyboardType.Password -> {
+ this.inputType =
+ InputType.TYPE_CLASS_TEXT or EditorInfo.TYPE_TEXT_VARIATION_PASSWORD
}
-
- outInfo.imeOptions = outInfo.imeOptions or EditorInfo.IME_FLAG_NO_FULLSCREEN
+ KeyboardType.NumberPassword -> {
+ this.inputType =
+ InputType.TYPE_CLASS_NUMBER or EditorInfo.TYPE_NUMBER_VARIATION_PASSWORD
+ }
+ else -> error("Invalid Keyboard Type")
}
- private fun hasFlag(bits: Int, flag: Int): Boolean = (bits and flag) == flag
-}
\ No newline at end of file
+ if (!imeOptions.singleLine) {
+ if (hasFlag(this.inputType, InputType.TYPE_CLASS_TEXT)) {
+ // TextView.java#setInputTypeSingleLine
+ this.inputType = this.inputType or InputType.TYPE_TEXT_FLAG_MULTI_LINE
+
+ if (imeOptions.imeAction == ImeAction.Default) {
+ this.imeOptions = this.imeOptions or EditorInfo.IME_FLAG_NO_ENTER_ACTION
+ }
+ }
+ }
+
+ if (hasFlag(this.inputType, InputType.TYPE_CLASS_TEXT)) {
+ when (imeOptions.capitalization) {
+ KeyboardCapitalization.None -> {
+ /* do nothing */
+ }
+ KeyboardCapitalization.Characters -> {
+ this.inputType = this.inputType or InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS
+ }
+ KeyboardCapitalization.Words -> {
+ this.inputType = this.inputType or InputType.TYPE_TEXT_FLAG_CAP_WORDS
+ }
+ KeyboardCapitalization.Sentences -> {
+ this.inputType = this.inputType or InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
+ }
+ }
+
+ if (imeOptions.autoCorrect) {
+ this.inputType = this.inputType or InputType.TYPE_TEXT_FLAG_AUTO_CORRECT
+ }
+ }
+
+ this.initialSelStart = textFieldValue.selection.start
+ this.initialSelEnd = textFieldValue.selection.end
+
+ EditorInfoCompat.setInitialSurroundingText(this, textFieldValue.text)
+
+ this.imeOptions = this.imeOptions or EditorInfo.IME_FLAG_NO_FULLSCREEN
+}
+
+private fun hasFlag(bits: Int, flag: Int): Boolean = (bits and flag) == flag
\ No newline at end of file
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DelegatingLayoutNodeWrapper.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DelegatingLayoutNodeWrapper.kt
index 387da83..b349ac6 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DelegatingLayoutNodeWrapper.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DelegatingLayoutNodeWrapper.kt
@@ -36,9 +36,6 @@
override var wrapped: LayoutNodeWrapper,
open var modifier: T
) : LayoutNodeWrapper(wrapped.layoutNode) {
- override val providedAlignmentLines: Set<AlignmentLine>
- get() = wrapped.providedAlignmentLines
-
override val measureScope: MeasureScope get() = wrapped.measureScope
/**
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/InnerPlaceable.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/InnerPlaceable.kt
index a8b4970..162c404 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/InnerPlaceable.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/InnerPlaceable.kt
@@ -35,9 +35,6 @@
layoutNode: LayoutNode
) : LayoutNodeWrapper(layoutNode), Density by layoutNode.measureScope {
- override val providedAlignmentLines: Set<AlignmentLine>
- get() = layoutNode.providedAlignmentLines.keys
-
override val measureScope get() = layoutNode.measureScope
override fun measure(constraints: Constraints): Placeable = performingMeasure(constraints) {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
index 394e52c..427f1fa 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
@@ -349,7 +349,7 @@
parent.invalidateLayer()
parent.requestRemeasure()
}
- alignmentLinesQueryOwner = null
+ alignmentLines.reset()
alignmentUsageByParent = UsageByParent.NotUsed
onDetach?.invoke(owner)
forEachDelegate { it.detach() }
@@ -494,15 +494,9 @@
override val height: Int get() = outerMeasurablePlaceable.height
/**
- * The alignment lines of this layout, inherited + intrinsic
+ * State corresponding to the alignment lines of this layout, inherited + intrinsic
*/
- internal var alignmentLines: LayoutNodeAlignmentLines? = null
- private set
-
- /**
- * The alignment lines provided by this layout at the last measurement
- */
- internal var providedAlignmentLines: Map<AlignmentLine, Int> = emptyMap()
+ internal var alignmentLines = LayoutNodeAlignmentLines(this)
internal val mDrawScope: LayoutNodeDrawScope = sharedDrawScope
@@ -532,36 +526,6 @@
*/
internal var measuredByParent: UsageByParent = UsageByParent.NotUsed
- /**
- * `true` while doing [calculateAlignmentLines]
- */
- private var isCalculatingAlignmentLines = false
-
- /**
- * `true` when the parent reads our alignment lines
- */
- private var alignmentLinesRead = false
-
- private var alignmentLinesCalculatedDuringLastLayout = false
-
- /**
- * `true` when an ancestor relies on our alignment lines
- */
- internal val alignmentLinesRequired
- get() = alignmentLinesQueryOwner != null && alignmentLinesQueryOwner!!.alignmentLinesRead
-
- /**
- * Used by the parent to identify if the child has been queried for alignment lines since
- * last measurement.
- */
- private var alignmentLinesQueriedSinceLastLayout = false
-
- /**
- * The closest layout node above in the hierarchy which asked for alignment lines.
- */
- internal var alignmentLinesQueryOwner: LayoutNode? = null
- private set
-
internal var alignmentUsageByParent = UsageByParent.NotUsed
@Deprecated("Temporary API to support ConstraintLayout prototyping.")
@@ -885,7 +849,9 @@
layoutChildren()
}
- private fun layoutChildren() {
+ internal fun layoutChildren() {
+ alignmentLines.recalculateQueryOwner()
+
if (layoutState == NeedsRelayout) {
onBeforeLayoutChildren()
}
@@ -900,16 +866,9 @@
_children.forEach { child ->
// and reset the place order for all the children before placing them
child.placeOrder = NotPlacedPlaceOrder
- if (alignmentLinesRequired && child.layoutState == Ready &&
- !child.alignmentLinesCalculatedDuringLastLayout
- ) {
- child.layoutState = NeedsRelayout
- }
- if (!child.alignmentLinesRequired) {
- child.alignmentLinesQueryOwner = alignmentLinesQueryOwner
- }
- child.alignmentLinesQueriedSinceLastLayout = false
+ child.alignmentLines.usedDuringParentLayout = false
}
+
innerLayoutNodeWrapper.measureResult.placeChildren()
_children.forEach { child ->
// we set `placeOrder` to NotPlacedPlaceOrder for all the children, then
@@ -921,20 +880,18 @@
// which is not placed anymore.
invalidateLayer()
}
- child.alignmentLinesRead = child.alignmentLinesQueriedSinceLastLayout
+ child.alignmentLines.previousUsedDuringParentLayout =
+ child.alignmentLines.usedDuringParentLayout
}
}
- alignmentLinesCalculatedDuringLastLayout = false
- if (alignmentLinesRequired) {
- alignmentLinesCalculatedDuringLastLayout = true
- val alignments = alignmentLines ?: LayoutNodeAlignmentLines(this).also {
- alignmentLines = it
- }
- alignments.recalculate()
- }
layoutState = Ready
}
+
+ if (alignmentLines.usedDuringParentLayout) {
+ alignmentLines.previousUsedDuringParentLayout = true
+ }
+ if (alignmentLines.dirty && alignmentLines.required) alignmentLines.recalculate()
}
private fun markSubtreeAsPlaced() {
@@ -991,56 +948,46 @@
}
internal fun onAlignmentsChanged() {
- val parent = parent
- if (parent != null) {
- if (alignmentUsageByParent == UsageByParent.InMeasureBlock &&
- parent.layoutState != LayingOut
- ) {
- parent.requestRemeasure()
- } else if (alignmentUsageByParent == UsageByParent.InLayoutBlock) {
- parent.requestRelayout()
- }
+ if (alignmentLines.dirty) return
+ alignmentLines.dirty = true
+
+ val parent = parent ?: return
+ if (alignmentLines.usedDuringParentMeasurement) {
+ parent.requestRemeasure()
+ } else if (alignmentLines.previousUsedDuringParentLayout) {
+ parent.requestRelayout()
}
+ if (alignmentLines.usedByModifierMeasurement) {
+ requestRemeasure()
+ }
+ if (alignmentLines.usedByModifierLayout) {
+ parent.requestRelayout()
+ }
+ parent.onAlignmentsChanged()
}
internal fun calculateAlignmentLines(): Map<AlignmentLine, Int> {
- isCalculatingAlignmentLines = true
- alignmentLinesRead = true
- alignmentLinesQueryOwner = this
- alignmentLinesQueriedSinceLastLayout = true
- val newUsageByParent = when (parent?.layoutState) {
- Measuring -> UsageByParent.InMeasureBlock
- LayingOut -> UsageByParent.InLayoutBlock
- else -> UsageByParent.NotUsed
+ if (!outerMeasurablePlaceable.duringAlignmentLinesQuery) {
+ alignmentLinesQueriedByModifier()
}
- val newUsageHasLowerPriority = newUsageByParent == UsageByParent.InLayoutBlock &&
- alignmentUsageByParent == UsageByParent.InMeasureBlock
- if (!newUsageHasLowerPriority) {
- alignmentUsageByParent = newUsageByParent
+ layoutChildren()
+ return alignmentLines.getLastCalculation()
+ }
+
+ private fun alignmentLinesQueriedByModifier() {
+ if (layoutState == Measuring) {
+ alignmentLines.usedByModifierMeasurement = true
+ // We quickly transition to NeedsRelayout as we need the alignment lines now.
+ // Later we will see that we also laid out as part of measurement and will skip layout.
+ if (alignmentLines.dirty) layoutState = NeedsRelayout
+ } else {
+ // Note this can also happen for onGloballyPositioned queries.
+ alignmentLines.usedByModifierLayout = true
}
- if (layoutState == NeedsRelayout || !alignmentLinesCalculatedDuringLastLayout) {
- // layoutChildren() is a state transformation from NeedsRelayout to Ready.
- // when we are already in NeedsRelayout we need to end up with Ready, but if we are
- // currently measuring or need remeasure this extra layoutChildren is just a side effect
- // and we will need to restore the current state.
- val endState = if (layoutState == Measuring || layoutState == NeedsRemeasure) {
- layoutState
- } else {
- Ready
- }
- if (!alignmentLinesCalculatedDuringLastLayout) {
- layoutState = NeedsRelayout
- }
- layoutChildren()
- layoutState = endState
- }
- isCalculatingAlignmentLines = false
- return alignmentLines?.getLastCalculation() ?: emptyMap()
}
internal fun handleMeasureResult(measureResult: MeasureResult) {
innerLayoutNodeWrapper.measureResult = measureResult
- providedAlignmentLines = measureResult.alignmentLines
}
/**
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeAlignmentLines.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeAlignmentLines.kt
index fba763a..3e1c26c 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeAlignmentLines.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeAlignmentLines.kt
@@ -26,57 +26,154 @@
private val layoutNode: LayoutNode
) {
/**
- * The alignment lines of this layout, inherited + intrinsic
+ * `true` when the alignment lines needs to be recalculated because they might have changed.
*/
- private val alignmentLines: MutableMap<AlignmentLine, Int> = hashMapOf()
+ internal var dirty = true
- private val previousAlignmentLines = mutableMapOf<AlignmentLine, Int>()
+ /**
+ * `true` when the alignment lines were used by the parent during measurement.
+ */
+ internal var usedDuringParentMeasurement = false
- fun getLastCalculation(): Map<AlignmentLine, Int> = alignmentLines
+ /**
+ * `true` when the alignment lines have been used by the parent during the current layout (or
+ * previous layout if there is no layout in progress).
+ */
+ internal var usedDuringParentLayout = false
+ /**
+ * `true` when the alignment lines were used by the parent during the last completed layout.
+ */
+ internal var previousUsedDuringParentLayout = false
- fun recalculate() {
- previousAlignmentLines.clear()
- previousAlignmentLines.putAll(alignmentLines)
- alignmentLines.clear()
- layoutNode._children.forEach { child ->
- val childAlignments = child.alignmentLines
- if (!child.isPlaced || childAlignments == null) return@forEach
- childAlignments.alignmentLines.keys.forEach { childLine ->
- val linePositionInContainer = childAlignments.getAlignmentLine(childLine)!!
- // If the line was already provided by a previous child, merge the values.
- alignmentLines[childLine] = if (childLine in alignmentLines) {
- childLine.merge(
- alignmentLines.getValue(childLine),
- linePositionInContainer
- )
- } else {
- linePositionInContainer
- }
+ /**
+ * `true` when the alignment lines were used by the modifier of the node during measurement.
+ */
+ internal var usedByModifierMeasurement = false
+
+ /**
+ * `true` when the alignment lines were used by the modifier of the node during measurement.
+ */
+ internal var usedByModifierLayout = false
+
+ /**
+ * `true` when the direct parent or our modifier relies on our alignment lines.
+ */
+ internal val queried get() = usedDuringParentMeasurement ||
+ previousUsedDuringParentLayout || usedByModifierMeasurement ||
+ usedByModifierLayout
+
+ /**
+ * The closest layout node ancestor who was asked for alignment lines, either by the parent or
+ * their own modifier. If the owner stops being queried for alignment lines, we have to
+ * [recalculateQueryOwner] to find the new owner if one exists.
+ */
+ private var queryOwner: LayoutNode? = null
+
+ /**
+ * Whether the alignment lines of this node are relevant (whether an ancestor depends on them).
+ */
+ internal val required: Boolean get() {
+ recalculateQueryOwner()
+ return queryOwner != null
+ }
+
+ /**
+ * Updates the alignment lines query owner according to the current values of the
+ * alignmentUsedBy* of the layout nodes in the hierarchy.
+ */
+ internal fun recalculateQueryOwner() {
+ queryOwner = if (queried) {
+ layoutNode
+ } else {
+ val parent = layoutNode.parent ?: return
+ val parentQueryOwner = parent.alignmentLines.queryOwner
+ if (parentQueryOwner != null && parentQueryOwner.alignmentLines.queried) {
+ parentQueryOwner
+ } else {
+ val owner = queryOwner
+ if (owner == null || owner.alignmentLines.queried) return
+ owner.parent?.alignmentLines?.recalculateQueryOwner()
+ owner.parent?.alignmentLines?.queryOwner
}
}
- alignmentLines += layoutNode.providedAlignmentLines
- if (previousAlignmentLines != alignmentLines) {
- layoutNode.onAlignmentsChanged()
- }
}
/**
- * Returns the alignment line value for a given alignment line without affecting whether
- * the flag for whether the alignment line was read.
+ * The alignment lines of this layout, inherited + intrinsic
*/
- private fun getAlignmentLine(alignmentLine: AlignmentLine): Int? {
- val linePos = alignmentLines[alignmentLine] ?: return null
- var pos = Offset(linePos.toFloat(), linePos.toFloat())
- var wrapper = layoutNode.innerLayoutNodeWrapper
- while (wrapper != layoutNode.outerLayoutNodeWrapper) {
- pos = wrapper.toParentPosition(pos)
- wrapper = wrapper.wrappedBy!!
+ private val alignmentLines: MutableMap<AlignmentLine, Int> = hashMapOf()
+
+ fun getLastCalculation(): Map<AlignmentLine, Int> = alignmentLines
+
+ fun recalculate() {
+ alignmentLines.clear()
+ /**
+ * Returns the alignment line value for a given alignment line without affecting whether
+ * the flag for whether the alignment line was read.
+ */
+ fun addAlignmentLine(
+ alignmentLine: AlignmentLine,
+ initialPosition: Int,
+ initialWrapper: LayoutNodeWrapper
+ ) {
+ var position = Offset(initialPosition.toFloat(), initialPosition.toFloat())
+ var wrapper = initialWrapper
+ while (true) {
+ position = wrapper.toParentPosition(position)
+ wrapper = wrapper.wrappedBy!!
+ if (wrapper == layoutNode.innerLayoutNodeWrapper) break
+ if (alignmentLine in wrapper.providedAlignmentLines) {
+ val newPosition = wrapper[alignmentLine]
+ position = Offset(newPosition.toFloat(), newPosition.toFloat())
+ }
+ }
+ val positionInContainer = if (alignmentLine is HorizontalAlignmentLine) {
+ position.y.roundToInt()
+ } else {
+ position.x.roundToInt()
+ }
+ // If the line was already provided by a previous child, merge the values.
+ alignmentLines[alignmentLine] = if (alignmentLine in alignmentLines) {
+ alignmentLine.merge(
+ alignmentLines.getValue(alignmentLine),
+ positionInContainer
+ )
+ } else {
+ positionInContainer
+ }
}
- pos = wrapper.toParentPosition(pos)
- return if (alignmentLine is HorizontalAlignmentLine) {
- pos.y.roundToInt()
- } else {
- pos.x.roundToInt()
+ layoutNode._children.forEach { child ->
+ if (!child.isPlaced) return@forEach
+ if (child.alignmentLines.dirty) {
+ // It did not need relayout, but we still call layout to recalculate
+ // alignment lines.
+ child.layoutChildren()
+ }
+ // Add alignment lines on the child node.
+ child.alignmentLines.alignmentLines.forEach { (childLine, linePosition) ->
+ addAlignmentLine(childLine, linePosition, child.innerLayoutNodeWrapper)
+ }
+
+ // Add alignment lines on the modifier of the child.
+ var wrapper = child.innerLayoutNodeWrapper.wrappedBy!!
+ while (wrapper != layoutNode.innerLayoutNodeWrapper) {
+ wrapper.providedAlignmentLines.forEach { childLine ->
+ addAlignmentLine(childLine, wrapper[childLine], wrapper)
+ }
+ wrapper = wrapper.wrappedBy!!
+ }
}
+ alignmentLines += layoutNode.innerLayoutNodeWrapper.measureResult.alignmentLines
+ dirty = false
+ }
+
+ internal fun reset() {
+ dirty = true
+ usedDuringParentMeasurement = false
+ previousUsedDuringParentLayout = false
+ usedDuringParentLayout = false
+ usedByModifierMeasurement = false
+ usedByModifierLayout = false
+ queryOwner = null
}
}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeWrapper.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeWrapper.kt
index b584d63..dde4d76 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeWrapper.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeWrapper.kt
@@ -88,9 +88,40 @@
if (old == null || value.width != old.width || value.height != old.height) {
onMeasureResultChanged(value.width, value.height)
}
+ // We do not simply compare against old.alignmentLines in case this is a
+ // MutableStateMap and the same instance might be passed.
+ if ((!oldAlignmentLines.isNullOrEmpty() || value.alignmentLines.isNotEmpty()) &&
+ value.alignmentLines != oldAlignmentLines
+ ) {
+ if (wrapped?.layoutNode == layoutNode) {
+ layoutNode.parent?.onAlignmentsChanged()
+ // We might need to request remeasure or relayout for the parent in
+ // case they ask for the lines so we are the query owner, without
+ // marking dirty our alignment lines (because only the modifier's changed).
+ if (layoutNode.alignmentLines.usedDuringParentMeasurement) {
+ layoutNode.parent?.requestRemeasure()
+ } else if (layoutNode.alignmentLines.usedDuringParentLayout) {
+ layoutNode.parent?.requestRelayout()
+ }
+ } else {
+ // It means we are an InnerPlaceable.
+ layoutNode.onAlignmentsChanged()
+ }
+ layoutNode.alignmentLines.dirty = true
+
+ val oldLines = oldAlignmentLines
+ ?: (mutableMapOf<AlignmentLine, Int>().also { oldAlignmentLines = it })
+ oldLines.clear()
+ oldLines.putAll(value.alignmentLines)
+ }
}
}
+ private var oldAlignmentLines: MutableMap<AlignmentLine, Int>? = null
+
+ override val providedAlignmentLines: Set<AlignmentLine>
+ get() = _measureResult?.alignmentLines?.keys ?: emptySet()
+
/**
* Called when the width or height of [measureResult] change. The object instance pointed to
* by [measureResult] may or may not have changed.
@@ -190,6 +221,11 @@
} else {
wrappedBy?.invalidateLayer()
}
+ if (wrapped?.layoutNode != layoutNode) {
+ layoutNode.onAlignmentsChanged()
+ } else {
+ layoutNode.parent?.onAlignmentsChanged()
+ }
layoutNode.owner?.onLayoutChange(layoutNode)
}
this.zIndex = zIndex
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutTreeConsistencyChecker.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutTreeConsistencyChecker.kt
index 289268a..337e2b0 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutTreeConsistencyChecker.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutTreeConsistencyChecker.kt
@@ -68,7 +68,8 @@
return relayoutNodes.contains(this) ||
parentLayoutState == LayoutNode.LayoutState.NeedsRemeasure ||
parentLayoutState == LayoutNode.LayoutState.NeedsRelayout ||
- parentLayoutState == LayoutNode.LayoutState.Measuring
+ parentLayoutState == LayoutNode.LayoutState.Measuring ||
+ parentLayoutState == LayoutNode.LayoutState.LayingOut
}
}
return true
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureAndLayoutDelegate.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureAndLayoutDelegate.kt
index 33e625a..02ec181 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureAndLayoutDelegate.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureAndLayoutDelegate.kt
@@ -23,7 +23,6 @@
import androidx.compose.ui.node.LayoutNode.LayoutState.Ready
import androidx.compose.ui.node.LayoutNode.UsageByParent.InLayoutBlock
import androidx.compose.ui.node.LayoutNode.UsageByParent.InMeasureBlock
-import androidx.compose.ui.node.LayoutNode.UsageByParent.NotUsed
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.util.fastForEach
@@ -200,13 +199,9 @@
duringMeasureLayout = true
try {
relayoutNodes.popEach { layoutNode ->
- val alignmentLinesOwner = layoutNode.alignmentLinesQueryOwner
if (layoutNode.isPlaced ||
layoutNode.canAffectParent ||
- (
- alignmentLinesOwner != null && alignmentLinesOwner
- .alignmentUsageByParent != NotUsed
- )
+ layoutNode.alignmentLines.required
) {
if (layoutNode.layoutState == NeedsRemeasure) {
if (doRemeasure(layoutNode, rootConstraints)) {
@@ -266,5 +261,5 @@
private val LayoutNode.canAffectParent
get() = layoutState == NeedsRemeasure &&
- (measuredByParent == InMeasureBlock || alignmentLinesQueryOwner != null)
+ (measuredByParent == InMeasureBlock || alignmentLines.required)
}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OnGloballyPositionedModifierWrapper.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OnGloballyPositionedModifierWrapper.kt
index 21a928e..9e4370a 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OnGloballyPositionedModifierWrapper.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OnGloballyPositionedModifierWrapper.kt
@@ -16,6 +16,7 @@
package androidx.compose.ui.node
+import androidx.compose.ui.layout.AlignmentLine
import androidx.compose.ui.layout.OnGloballyPositionedModifier
/**
@@ -24,4 +25,17 @@
internal class OnGloballyPositionedModifierWrapper(
wrapped: LayoutNodeWrapper,
modifier: OnGloballyPositionedModifier
-) : DelegatingLayoutNodeWrapper<OnGloballyPositionedModifier>(wrapped, modifier)
+) : DelegatingLayoutNodeWrapper<OnGloballyPositionedModifier>(wrapped, modifier) {
+ override val providedAlignmentLines: Set<AlignmentLine>
+ get() {
+ val result = mutableSetOf<AlignmentLine>()
+ layoutNode
+ var wrapper = wrapped as LayoutNodeWrapper?
+ while (wrapper != null) {
+ result += wrapper.providedAlignmentLines
+ if (wrapper == layoutNode.innerLayoutNodeWrapper) break
+ wrapper = wrapper.wrapped
+ }
+ return result
+ }
+}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OuterMeasurablePlaceable.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OuterMeasurablePlaceable.kt
index eadbc1c..6ca6b5f 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OuterMeasurablePlaceable.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OuterMeasurablePlaceable.kt
@@ -36,9 +36,10 @@
check(measuredOnce)
return measurementConstraints
}
+ internal var duringAlignmentLinesQuery = false
+
private var lastPosition: IntOffset = IntOffset.Zero
private var lastLayerBlock: (GraphicsLayerScope.() -> Unit)? = null
- private var lastProvidedAlignmentLines: MutableMap<AlignmentLine, Int>? = null
private var lastZIndex: Float = 0f
/**
@@ -87,6 +88,8 @@
if (layoutNode.layoutState == LayoutState.NeedsRemeasure ||
measurementConstraints != constraints
) {
+ layoutNode.alignmentLines.usedByModifierMeasurement = false
+ layoutNode._children.forEach { it.alignmentLines.usedDuringParentMeasurement = false }
measuredOnce = true
layoutNode.layoutState = LayoutState.Measuring
measurementConstraints = constraints
@@ -94,8 +97,12 @@
owner.snapshotObserver.observeMeasureSnapshotReads(layoutNode) {
outerWrapper.measure(constraints)
}
- layoutNode.layoutState = LayoutState.NeedsRelayout
- notifyAlignmentChanges()
+ // The resulting layout state might be Ready. This can happen when the layout node's
+ // own modifier is querying an alignment line during measurement, therefore we
+ // need to also layout the layout node.
+ if (layoutNode.layoutState == LayoutState.Measuring) {
+ layoutNode.layoutState = LayoutState.NeedsRelayout
+ }
val sizeChanged = outerWrapper.size != outerWrapperPreviousMeasuredSize ||
outerWrapper.width != width ||
outerWrapper.height != height
@@ -106,26 +113,6 @@
return false
}
- private fun notifyAlignmentChanges() {
- // optimized to only create a lastProvidedAlignmentLines when we do have non empty map
- if (layoutNode.providedAlignmentLines.isNotEmpty()) {
- val previous = lastProvidedAlignmentLines ?: mutableMapOf<AlignmentLine, Int>().also {
- lastProvidedAlignmentLines = it
- }
- if (layoutNode.providedAlignmentLines != previous) {
- previous.clear()
- previous.putAll(layoutNode.providedAlignmentLines)
- layoutNode.onAlignmentsChanged()
- }
- } else {
- val previous = lastProvidedAlignmentLines
- if (previous != null && previous.isNotEmpty()) {
- previous.clear()
- layoutNode.onAlignmentsChanged()
- }
- }
- }
-
// We are setting our measuredSize to match the coerced outerWrapper size, to prevent
// double offseting for layout cooperation. However, this means that here we need
// to override these getters to make the measured values correct in Measured.
@@ -133,7 +120,17 @@
override val measuredWidth: Int get() = outerWrapper.measuredWidth
override val measuredHeight: Int get() = outerWrapper.measuredHeight
- override fun get(alignmentLine: AlignmentLine): Int = outerWrapper[alignmentLine]
+ override fun get(alignmentLine: AlignmentLine): Int {
+ if (layoutNode.parent?.layoutState == LayoutState.Measuring) {
+ layoutNode.alignmentLines.usedDuringParentMeasurement = true
+ } else if (layoutNode.parent?.layoutState == LayoutState.LayingOut) {
+ layoutNode.alignmentLines.usedDuringParentLayout = true
+ }
+ duringAlignmentLinesQuery = true
+ val result = outerWrapper[alignmentLine]
+ duringAlignmentLinesQuery = false
+ return result
+ }
override fun placeAt(
position: IntOffset,
@@ -144,6 +141,7 @@
lastPosition = position
lastZIndex = zIndex
lastLayerBlock = layerBlock
+ layoutNode.alignmentLines.usedByModifierLayout = false
with(PlacementScope) {
if (layerBlock == null) {
outerWrapper.place(position, lastZIndex)
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposeLayer.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposeLayer.desktop.kt
index 296411b..03dbbbc 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposeLayer.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposeLayer.desktop.kt
@@ -54,7 +54,12 @@
// method?
private val events = AWTDebounceEventQueue()
- internal val wrapped = Wrapped()
+ internal val wrapped = Wrapped().apply {
+ onStateChanged(SkiaLayer.PropertyKind.ContentScale) { _ ->
+ resetDensity()
+ }
+ }
+
internal val owners: DesktopOwners = DesktopOwners(
coroutineScope,
wrapped,
@@ -82,12 +87,7 @@
initOwner()
}
- override fun contentScaleChanged() {
- super.contentScaleChanged()
- resetDensity()
- }
-
- private fun resetDensity() {
+ internal fun resetDensity() {
this@ComposeLayer.density = detectCurrentDensity()
owner?.density = density
}
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposePanel.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposePanel.desktop.kt
index cfe712b..a29563d 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposePanel.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposePanel.desktop.kt
@@ -18,6 +18,7 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import org.jetbrains.skiko.ClipComponent
+import org.jetbrains.skiko.GraphicsApi
import java.awt.Color
import java.awt.Component
import javax.swing.JLayeredPane
@@ -112,4 +113,12 @@
layer!!.component.requestFocus()
}
}
+
+ /**
+ * Returns low-level rendering API used for rendering in this ComposeWindow. API is
+ * automatically selected based on operating system, graphical hardware and `SKIKO_RENDER_API`
+ * environment variable.
+ */
+ val renderApi: GraphicsApi
+ get() = if (layer != null) layer!!.component.renderApi else GraphicsApi.UNKNOWN
}
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposeWindow.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposeWindow.desktop.kt
index 273b3b0..9b865cf 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposeWindow.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposeWindow.desktop.kt
@@ -20,6 +20,7 @@
import androidx.compose.runtime.CompositionLocalProvider
import org.jetbrains.skiko.ClipComponent
import org.jetbrains.skiko.GraphicsApi
+import org.jetbrains.skiko.SkiaLayer
import java.awt.Component
import javax.swing.JFrame
import javax.swing.JLayeredPane
@@ -98,15 +99,26 @@
}
/**
- * Retrieve underlying platform-specific operating system handle for the window where ComposeWindow is rendered.
- * Currently returns HWND on Windows, Drawable on X11 and 0 on macOS.
+ * Registers a task to run when the rendering API changes.
+ */
+ fun onRenderApiChanged(action: () -> Unit) {
+ layer.component.onStateChanged(SkiaLayer.PropertyKind.Renderer) {
+ action()
+ }
+ }
+
+ /**
+ * Retrieve underlying platform-specific operating system handle for the root window where
+ * ComposeWindow is rendered. Currently returns HWND on Windows, Display on X11 and NSWindow
+ * on macOS.
*/
val windowHandle: Long
get() = layer.component.windowHandle
/**
- * Returns low level rendering API used for rendering in this ComposeWindow. API is automatically selected based on
- * operating system, graphical hardware and `SKIKO_RENDER_API` environment variable.
+ * Returns low-level rendering API used for rendering in this ComposeWindow. API is
+ * automatically selected based on operating system, graphical hardware and `SKIKO_RENDER_API`
+ * environment variable.
*/
val renderApi: GraphicsApi
get() = layer.component.renderApi
diff --git a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/input/RecordingInputConnectionUpdateTextFieldValueTest.kt b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/input/RecordingInputConnectionUpdateTextFieldValueTest.kt
index 2721714..bb39d23 100644
--- a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/input/RecordingInputConnectionUpdateTextFieldValueTest.kt
+++ b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/input/RecordingInputConnectionUpdateTextFieldValueTest.kt
@@ -19,9 +19,9 @@
import android.view.View
import android.view.inputmethod.ExtractedText
import android.view.inputmethod.InputConnection
-import android.view.inputmethod.InputMethodManager
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.InputEventCallback2
+import androidx.compose.ui.text.input.InputMethodManager
import androidx.compose.ui.text.input.RecordingInputConnection
import androidx.compose.ui.text.input.TextFieldValue
import com.google.common.truth.Truth.assertThat
diff --git a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/input/TextInputServiceAndroidTest.kt b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/input/TextInputServiceAndroidTest.kt
deleted file mode 100644
index 48050b9..0000000
--- a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/input/TextInputServiceAndroidTest.kt
+++ /dev/null
@@ -1,693 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.input
-
-import android.content.Context
-import android.text.InputType
-import android.view.View
-import android.view.inputmethod.EditorInfo
-import android.view.inputmethod.InputMethodManager
-import androidx.compose.ui.text.TextRange
-import androidx.compose.ui.text.input.ImeAction
-import androidx.compose.ui.text.input.ImeOptions
-import androidx.compose.ui.text.input.KeyboardCapitalization
-import androidx.compose.ui.text.input.KeyboardType
-import androidx.compose.ui.text.input.TextFieldValue
-import androidx.compose.ui.text.input.TextInputServiceAndroid
-import com.google.common.truth.Truth.assertThat
-import com.nhaarman.mockitokotlin2.eq
-import com.nhaarman.mockitokotlin2.mock
-import com.nhaarman.mockitokotlin2.whenever
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class TextInputServiceAndroidTest {
-
- private lateinit var textInputService: TextInputServiceAndroid
- private lateinit var imm: InputMethodManager
-
- @Before
- fun setup() {
- imm = mock()
- val view: View = mock()
- val context: Context = mock()
- whenever(context.getSystemService(eq(Context.INPUT_METHOD_SERVICE))).thenReturn(imm)
- whenever(view.context).thenReturn(context)
- textInputService = TextInputServiceAndroid(view)
- }
-
- @Test
- fun test_fill_editor_info_text() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- keyboardType = KeyboardType.Text,
- imeAction = ImeAction.Default
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
- assertThat(
- (EditorInfo.IME_MASK_ACTION and info.imeOptions)
- == EditorInfo.IME_ACTION_UNSPECIFIED
- ).isTrue()
- }
- }
-
- @Test
- fun test_fill_editor_info_ascii() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- keyboardType = KeyboardType.Ascii,
- imeAction = ImeAction.Default
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
- assertThat((EditorInfo.IME_FLAG_FORCE_ASCII and info.imeOptions) != 0).isTrue()
- assertThat(
- (EditorInfo.IME_MASK_ACTION and info.imeOptions)
- == EditorInfo.IME_ACTION_UNSPECIFIED
- ).isTrue()
- }
- }
-
- @Test
- fun test_fill_editor_info_number() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- keyboardType = KeyboardType.Number,
- imeAction = ImeAction.Default
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_CLASS_NUMBER and info.inputType) != 0).isTrue()
- assertThat(
- (EditorInfo.IME_MASK_ACTION and info.imeOptions)
- == EditorInfo.IME_ACTION_UNSPECIFIED
- ).isTrue()
- }
- }
-
- @Test
- fun test_fill_editor_info_phone() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- keyboardType = KeyboardType.Phone,
- imeAction = ImeAction.Default
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_CLASS_PHONE and info.inputType) != 0).isTrue()
- assertThat(
- (EditorInfo.IME_MASK_ACTION and info.imeOptions)
- == EditorInfo.IME_ACTION_UNSPECIFIED
- ).isTrue()
- }
- }
-
- @Test
- fun test_fill_editor_info_uri() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- keyboardType = KeyboardType.Uri,
- imeAction = ImeAction.Default
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
- assertThat((InputType.TYPE_TEXT_VARIATION_URI and info.inputType) != 0).isTrue()
- assertThat(
- (EditorInfo.IME_MASK_ACTION and info.imeOptions)
- == EditorInfo.IME_ACTION_UNSPECIFIED
- ).isTrue()
- }
- }
-
- @Test
- fun test_fill_editor_info_email() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- keyboardType = KeyboardType.Email,
- imeAction = ImeAction.Default
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
- assertThat((InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS and info.inputType) != 0)
- .isTrue()
- assertThat(
- (EditorInfo.IME_MASK_ACTION and info.imeOptions)
- == EditorInfo.IME_ACTION_UNSPECIFIED
- ).isTrue()
- }
- }
-
- @Test
- fun test_fill_editor_info_password() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- keyboardType = KeyboardType.Password,
- imeAction = ImeAction.Default
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
- assertThat((InputType.TYPE_TEXT_VARIATION_PASSWORD and info.inputType) != 0).isTrue()
- assertThat(
- (EditorInfo.IME_MASK_ACTION and info.imeOptions)
- == EditorInfo.IME_ACTION_UNSPECIFIED
- ).isTrue()
- }
- }
-
- @Test
- fun test_fill_editor_info_number_password() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- keyboardType = KeyboardType.NumberPassword,
- imeAction = ImeAction.Default
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_CLASS_NUMBER and info.inputType) != 0).isTrue()
- assertThat((InputType.TYPE_NUMBER_VARIATION_PASSWORD and info.inputType) != 0).isTrue()
- assertThat(
- (EditorInfo.IME_MASK_ACTION and info.imeOptions)
- == EditorInfo.IME_ACTION_UNSPECIFIED
- ).isTrue()
- }
- }
-
- @Test
- fun test_fill_editor_info_action_none() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- keyboardType = KeyboardType.Ascii,
- imeAction = ImeAction.None
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
- assertThat((EditorInfo.IME_FLAG_FORCE_ASCII and info.imeOptions) != 0).isTrue()
- assertThat(
- (EditorInfo.IME_MASK_ACTION and info.imeOptions)
- == EditorInfo.IME_ACTION_NONE
- ).isTrue()
- }
- }
-
- @Test
- fun test_fill_editor_info_action_go() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- keyboardType = KeyboardType.Ascii,
- imeAction = ImeAction.Go
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
- assertThat((EditorInfo.IME_FLAG_FORCE_ASCII and info.imeOptions) != 0).isTrue()
- assertThat(
- (EditorInfo.IME_MASK_ACTION and info.imeOptions)
- == EditorInfo.IME_ACTION_GO
- ).isTrue()
- }
- }
-
- @Test
- fun test_fill_editor_info_action_next() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- keyboardType = KeyboardType.Ascii,
- imeAction = ImeAction.Next
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
- assertThat((EditorInfo.IME_FLAG_FORCE_ASCII and info.imeOptions) != 0).isTrue()
- assertThat(
- (EditorInfo.IME_MASK_ACTION and info.imeOptions)
- == EditorInfo.IME_ACTION_NEXT
- ).isTrue()
- }
- }
-
- @Test
- fun test_fill_editor_info_action_previous() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- keyboardType = KeyboardType.Ascii,
- imeAction = ImeAction.Previous
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
- assertThat((EditorInfo.IME_FLAG_FORCE_ASCII and info.imeOptions) != 0).isTrue()
- assertThat(
- (EditorInfo.IME_MASK_ACTION and info.imeOptions)
- == EditorInfo.IME_ACTION_PREVIOUS
- ).isTrue()
- }
- }
-
- @Test
- fun test_fill_editor_info_action_search() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- keyboardType = KeyboardType.Ascii,
- imeAction = ImeAction.Search,
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
- assertThat((EditorInfo.IME_FLAG_FORCE_ASCII and info.imeOptions) != 0).isTrue()
- assertThat(
- (EditorInfo.IME_MASK_ACTION and info.imeOptions)
- == EditorInfo.IME_ACTION_SEARCH
- ).isTrue()
- }
- }
-
- @Test
- fun test_fill_editor_info_action_send() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- keyboardType = KeyboardType.Ascii,
- imeAction = ImeAction.Send
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
- assertThat((EditorInfo.IME_FLAG_FORCE_ASCII and info.imeOptions) != 0).isTrue()
- assertThat(
- (EditorInfo.IME_MASK_ACTION and info.imeOptions)
- == EditorInfo.IME_ACTION_SEND
- ).isTrue()
- }
- }
-
- @Test
- fun test_fill_editor_info_action_done() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- keyboardType = KeyboardType.Ascii,
- imeAction = ImeAction.Done
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_CLASS_TEXT and info.inputType) != 0).isTrue()
- assertThat((EditorInfo.IME_FLAG_FORCE_ASCII and info.imeOptions) != 0).isTrue()
- assertThat(
- (EditorInfo.IME_MASK_ACTION and info.imeOptions)
- == EditorInfo.IME_ACTION_DONE
- ).isTrue()
- }
- }
-
- @Test
- fun test_fill_editor_info_multi_line() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- singleLine = false,
- keyboardType = KeyboardType.Ascii,
- imeAction = ImeAction.Done
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_TEXT_FLAG_MULTI_LINE and info.inputType) == 0).isFalse()
- assertThat((EditorInfo.IME_FLAG_NO_ENTER_ACTION and info.imeOptions) == 0).isTrue()
- }
- }
-
- @Test
- fun test_fill_editor_info_multi_line_with_default_action() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- singleLine = false,
- keyboardType = KeyboardType.Text,
- imeAction = ImeAction.Default
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_TEXT_FLAG_MULTI_LINE and info.inputType) == 0).isFalse()
- assertThat((EditorInfo.IME_FLAG_NO_ENTER_ACTION and info.imeOptions) == 0).isFalse()
- }
- }
-
- @Test
- fun test_fill_editor_info_single_line() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- singleLine = true,
- keyboardType = KeyboardType.Ascii,
- imeAction = ImeAction.Done
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_TEXT_FLAG_MULTI_LINE and info.inputType) == 0).isTrue()
- assertThat((EditorInfo.IME_FLAG_NO_ENTER_ACTION and info.imeOptions) == 0).isTrue()
- }
- }
-
- @Test
- fun test_fill_editor_info_single_line_changes_ime_from_unspecified_to_done() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- singleLine = true,
- keyboardType = KeyboardType.Text,
- imeAction = ImeAction.Default
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((EditorInfo.IME_ACTION_DONE and info.imeOptions) == 0).isFalse()
- assertThat((EditorInfo.IME_ACTION_UNSPECIFIED and info.imeOptions) == 0).isTrue()
- }
- }
-
- @Test
- fun test_fill_editor_info_multi_line_not_set_when_input_type_is_not_text() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- singleLine = false,
- keyboardType = KeyboardType.Number,
- imeAction = ImeAction.Done
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_TEXT_FLAG_MULTI_LINE and info.inputType) == 0).isTrue()
- assertThat((EditorInfo.IME_FLAG_NO_ENTER_ACTION and info.imeOptions) == 0).isTrue()
- }
- }
-
- @Test
- fun test_fill_editor_info_capitalization_none() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- capitalization = KeyboardCapitalization.None,
- keyboardType = KeyboardType.Ascii,
- imeAction = ImeAction.Done
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS and info.inputType) == 0).isTrue()
- assertThat((InputType.TYPE_TEXT_FLAG_CAP_WORDS and info.inputType) == 0).isTrue()
- assertThat((InputType.TYPE_TEXT_FLAG_CAP_SENTENCES and info.inputType) == 0).isTrue()
- }
- }
-
- @Test
- fun test_fill_editor_info_capitalization_characters() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- capitalization = KeyboardCapitalization.Characters,
- keyboardType = KeyboardType.Ascii,
- imeAction = ImeAction.Done
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS and info.inputType) == 0).isFalse()
- assertThat((InputType.TYPE_TEXT_FLAG_CAP_WORDS and info.inputType) == 0).isTrue()
- assertThat((InputType.TYPE_TEXT_FLAG_CAP_SENTENCES and info.inputType) == 0).isTrue()
- }
- }
-
- @Test
- fun test_fill_editor_info_capitalization_words() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- capitalization = KeyboardCapitalization.Words,
- keyboardType = KeyboardType.Ascii,
- imeAction = ImeAction.Done
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS and info.inputType) == 0).isTrue()
- assertThat((InputType.TYPE_TEXT_FLAG_CAP_WORDS and info.inputType) == 0).isFalse()
- assertThat((InputType.TYPE_TEXT_FLAG_CAP_SENTENCES and info.inputType) == 0).isTrue()
- }
- }
-
- @Test
- fun test_fill_editor_info_capitalization_sentences() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- capitalization = KeyboardCapitalization.Sentences,
- keyboardType = KeyboardType.Ascii,
- imeAction = ImeAction.Done,
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS and info.inputType) == 0).isTrue()
- assertThat((InputType.TYPE_TEXT_FLAG_CAP_WORDS and info.inputType) == 0).isTrue()
- assertThat((InputType.TYPE_TEXT_FLAG_CAP_SENTENCES and info.inputType) == 0).isFalse()
- }
- }
-
- @Test
- fun test_fill_editor_info_capitalization_not_added_when_input_type_is_not_text() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- capitalization = KeyboardCapitalization.Sentences,
- keyboardType = KeyboardType.Number,
- imeAction = ImeAction.Done,
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS and info.inputType) == 0).isTrue()
- assertThat((InputType.TYPE_TEXT_FLAG_CAP_WORDS and info.inputType) == 0).isTrue()
- assertThat((InputType.TYPE_TEXT_FLAG_CAP_SENTENCES and info.inputType) == 0).isTrue()
- }
- }
-
- @Test
- fun test_fill_editor_info_auto_correct_on() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- autoCorrect = true,
- keyboardType = KeyboardType.Ascii,
- imeAction = ImeAction.Done
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_TEXT_FLAG_AUTO_CORRECT and info.inputType) == 0).isFalse()
- }
- }
-
- @Test
- fun test_fill_editor_info_auto_correct_off() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- autoCorrect = false,
- keyboardType = KeyboardType.Ascii,
- imeAction = ImeAction.Done
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_TEXT_FLAG_AUTO_CORRECT and info.inputType) == 0).isTrue()
- }
- }
-
- @Test
- fun autocorrect_not_added_when_input_type_is_not_text() {
- textInputService.startInput(
- value = TextFieldValue(""),
- imeOptions = ImeOptions(
- autoCorrect = true,
- keyboardType = KeyboardType.Number,
- imeAction = ImeAction.Done
- ),
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat((InputType.TYPE_TEXT_FLAG_AUTO_CORRECT and info.inputType) == 0).isTrue()
- }
- }
-
- @Test
- fun initial_default_selection_info_is_set() {
- textInputService.startInput(
- value = TextFieldValue(),
- imeOptions = ImeOptions.Default,
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat(info.initialSelStart).isEqualTo(0)
- assertThat(info.initialSelEnd).isEqualTo(0)
- }
- }
-
- @Test
- fun initial_selection_info_is_set() {
- val selection = TextRange(1, 2)
- textInputService.startInput(
- value = TextFieldValue("abc", selection),
- imeOptions = ImeOptions.Default,
- onEditCommand = {},
- onImeActionPerformed = {}
- )
-
- EditorInfo().let { info ->
- textInputService.createInputConnection(info)
- assertThat(info.initialSelStart).isEqualTo(selection.start)
- assertThat(info.initialSelEnd).isEqualTo(selection.end)
- }
- }
-}
\ No newline at end of file
diff --git a/core/core/src/main/java/androidx/core/view/TintableBackgroundView.java b/core/core/src/main/java/androidx/core/view/TintableBackgroundView.java
index c2c5e5d..338f46e 100644
--- a/core/core/src/main/java/androidx/core/view/TintableBackgroundView.java
+++ b/core/core/src/main/java/androidx/core/view/TintableBackgroundView.java
@@ -25,6 +25,11 @@
* Interface which allows a {@link android.view.View} to receive background tinting calls from
* {@link ViewCompat} when running on API v20 devices or lower.
*/
+/*
+ * When used with androidx.resourceinspection.annotation.AppCompatShadowedAttributes, this
+ * interface implies that AppCompat shadows the platform's background tint attributes.
+ * See androidx.resourceinspection.processor for more details and a full mapping of attributes.
+ */
public interface TintableBackgroundView {
/**
diff --git a/core/core/src/main/java/androidx/core/widget/AutoSizeableTextView.java b/core/core/src/main/java/androidx/core/widget/AutoSizeableTextView.java
index 315f298..eaf80fc5 100644
--- a/core/core/src/main/java/androidx/core/widget/AutoSizeableTextView.java
+++ b/core/core/src/main/java/androidx/core/widget/AutoSizeableTextView.java
@@ -27,6 +27,11 @@
/**
* Interface which allows a {@link android.widget.TextView} to receive background auto-sizing calls
* from {@link TextViewCompat} when running on API v26 devices or lower.
+ * <p>
+ * When used on a View annotated with
+ * {@link androidx.resourceinspection.annotation.AppCompatShadowedAttributes}, this interface
+ * implies that AppCompat shadows the platform's auto-size attributes. See
+ * {@link androidx.resourceinspection.processor} for more details and a full mapping of attributes.
*
* @hide Internal use only
*/
diff --git a/core/core/src/main/java/androidx/core/widget/TintableCheckedTextView.java b/core/core/src/main/java/androidx/core/widget/TintableCheckedTextView.java
index 748987d..fe28197 100644
--- a/core/core/src/main/java/androidx/core/widget/TintableCheckedTextView.java
+++ b/core/core/src/main/java/androidx/core/widget/TintableCheckedTextView.java
@@ -28,6 +28,12 @@
/**
* Interface which allows a {@link android.widget.CheckedTextView} to receive tinting
* calls from {@code CheckedTextViewCompat} when running on API v20 devices or lower.
+ * <p>
+ * When used on a View annotated with
+ * {@link androidx.resourceinspection.annotation.AppCompatShadowedAttributes}, this interface
+ * implies that AppCompat shadows the platform's check mark tint attributes. See
+ * {@link androidx.resourceinspection.processor} for more details and a full mapping of attributes.
+ *
* @hide
*/
@RestrictTo(LIBRARY_GROUP_PREFIX)
diff --git a/core/core/src/main/java/androidx/core/widget/TintableCompoundButton.java b/core/core/src/main/java/androidx/core/widget/TintableCompoundButton.java
index 3b367ac..2de5353 100644
--- a/core/core/src/main/java/androidx/core/widget/TintableCompoundButton.java
+++ b/core/core/src/main/java/androidx/core/widget/TintableCompoundButton.java
@@ -26,6 +26,11 @@
* Interface which allows a {@link android.widget.CompoundButton} to receive tinting
* calls from {@code CompoundButtonCompat} when running on API v20 devices or lower.
*/
+/*
+ * When used with androidx.resourceinspection.annotation.AppCompatShadowedAttributes, this
+ * interface implies that AppCompat shadows the platform's button tint attributes.
+ * See androidx.resourceinspection.processor for more details and a full mapping of attributes.
+ */
public interface TintableCompoundButton {
/**
diff --git a/core/core/src/main/java/androidx/core/widget/TintableCompoundDrawablesView.java b/core/core/src/main/java/androidx/core/widget/TintableCompoundDrawablesView.java
index 212d603..5afe7a4 100644
--- a/core/core/src/main/java/androidx/core/widget/TintableCompoundDrawablesView.java
+++ b/core/core/src/main/java/androidx/core/widget/TintableCompoundDrawablesView.java
@@ -25,6 +25,11 @@
* Interface which allows {@link android.widget.TextView} and subclasses to tint compound drawables
* with {@link TextViewCompat} when running on API v22 devices or lower.
*/
+/*
+ * When used with androidx.resourceinspection.annotation.AppCompatShadowedAttributes, this
+ * interface implies that AppCompat shadows the platform's compound drawable tint attributes.
+ * See androidx.resourceinspection.processor for more details and a full mapping of attributes.
+ */
public interface TintableCompoundDrawablesView {
/**
* Applies a tint to the compound drawables. Does not modify the
diff --git a/core/core/src/main/java/androidx/core/widget/TintableImageSourceView.java b/core/core/src/main/java/androidx/core/widget/TintableImageSourceView.java
index 1bf8732..6adbb4c 100644
--- a/core/core/src/main/java/androidx/core/widget/TintableImageSourceView.java
+++ b/core/core/src/main/java/androidx/core/widget/TintableImageSourceView.java
@@ -27,6 +27,11 @@
/**
* Interface which allows an {@link android.widget.ImageView} to receive image tinting calls
* from {@link ImageViewCompat} when running on API v20 devices or lower.
+ * <p>
+ * When used on a View annotated with
+ * {@link androidx.resourceinspection.annotation.AppCompatShadowedAttributes}, this interface
+ * implies that AppCompat shadows the platform's image tint attributes. See
+ * {@link androidx.resourceinspection.processor} for more details and a full mapping of attributes.
*
* @hide Internal use only
*/
diff --git a/emoji2/emoji2-views-helper/AndroidManifest.xml b/emoji2/emoji2-views-helper/AndroidManifest.xml
index 0b6d86b..1597e30 100644
--- a/emoji2/emoji2-views-helper/AndroidManifest.xml
+++ b/emoji2/emoji2-views-helper/AndroidManifest.xml
@@ -13,4 +13,4 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<manifest package="androidx.emoji2.viewshelper"/>
+<manifest package="androidx.emoji2.viewsintegration"/>
diff --git a/emoji2/emoji2-views-helper/api/current.txt b/emoji2/emoji2-views-helper/api/current.txt
index ec4fcf7..35a9171 100644
--- a/emoji2/emoji2-views-helper/api/current.txt
+++ b/emoji2/emoji2-views-helper/api/current.txt
@@ -1,5 +1,5 @@
// Signature format: 4.0
-package androidx.emoji2.viewshelper {
+package androidx.emoji2.viewsintegration {
public final class EmojiEditTextHelper {
ctor public EmojiEditTextHelper(android.widget.EditText);
diff --git a/emoji2/emoji2-views-helper/api/public_plus_experimental_current.txt b/emoji2/emoji2-views-helper/api/public_plus_experimental_current.txt
index ec4fcf7..35a9171 100644
--- a/emoji2/emoji2-views-helper/api/public_plus_experimental_current.txt
+++ b/emoji2/emoji2-views-helper/api/public_plus_experimental_current.txt
@@ -1,5 +1,5 @@
// Signature format: 4.0
-package androidx.emoji2.viewshelper {
+package androidx.emoji2.viewsintegration {
public final class EmojiEditTextHelper {
ctor public EmojiEditTextHelper(android.widget.EditText);
diff --git a/emoji2/emoji2-views-helper/api/restricted_current.txt b/emoji2/emoji2-views-helper/api/restricted_current.txt
index ec4fcf7..35a9171 100644
--- a/emoji2/emoji2-views-helper/api/restricted_current.txt
+++ b/emoji2/emoji2-views-helper/api/restricted_current.txt
@@ -1,5 +1,5 @@
// Signature format: 4.0
-package androidx.emoji2.viewshelper {
+package androidx.emoji2.viewsintegration {
public final class EmojiEditTextHelper {
ctor public EmojiEditTextHelper(android.widget.EditText);
diff --git a/emoji2/emoji2-views-helper/src/androidTest/AndroidManifest.xml b/emoji2/emoji2-views-helper/src/androidTest/AndroidManifest.xml
index f28fe19..05a087b 100644
--- a/emoji2/emoji2-views-helper/src/androidTest/AndroidManifest.xml
+++ b/emoji2/emoji2-views-helper/src/androidTest/AndroidManifest.xml
@@ -13,7 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<manifest package="androidx.emoji2.viewshelper">
+<manifest package="androidx.emoji2.viewsintegration">
<application>
</application>
diff --git a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiEditTextHelperDisabledTest.java b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiEditTextHelperDisabledTest.java
similarity index 98%
rename from emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiEditTextHelperDisabledTest.java
rename to emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiEditTextHelperDisabledTest.java
index 81e672c..070c8b1 100644
--- a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiEditTextHelperDisabledTest.java
+++ b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiEditTextHelperDisabledTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package androidx.emoji2.viewshelper;
+package androidx.emoji2.viewsintegration;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.assertEquals;
diff --git a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiEditTextHelperPre19Test.java b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiEditTextHelperPre19Test.java
similarity index 98%
rename from emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiEditTextHelperPre19Test.java
rename to emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiEditTextHelperPre19Test.java
index 829fae8..fbd32df 100644
--- a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiEditTextHelperPre19Test.java
+++ b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiEditTextHelperPre19Test.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package androidx.emoji2.viewshelper;
+package androidx.emoji2.viewsintegration;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
diff --git a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiEditTextHelperTest.java b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiEditTextHelperTest.java
similarity index 99%
rename from emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiEditTextHelperTest.java
rename to emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiEditTextHelperTest.java
index 4733f17..1210a11 100644
--- a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiEditTextHelperTest.java
+++ b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiEditTextHelperTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package androidx.emoji2.viewshelper;
+package androidx.emoji2.viewsintegration;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.assertEquals;
diff --git a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiEditableFactoryTest.java b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiEditableFactoryTest.java
similarity index 98%
rename from emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiEditableFactoryTest.java
rename to emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiEditableFactoryTest.java
index d85e40c..9f92fb1 100644
--- a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiEditableFactoryTest.java
+++ b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiEditableFactoryTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package androidx.emoji2.viewshelper;
+package androidx.emoji2.viewsintegration;
import static org.hamcrest.Matchers.arrayWithSize;
import static org.hamcrest.Matchers.instanceOf;
diff --git a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiInputConnectionTest.java b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiInputConnectionTest.java
similarity index 98%
rename from emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiInputConnectionTest.java
rename to emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiInputConnectionTest.java
index 843a803..42b6263f 100644
--- a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiInputConnectionTest.java
+++ b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiInputConnectionTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package androidx.emoji2.viewshelper;
+package androidx.emoji2.viewsintegration;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
diff --git a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiInputFilterTest.java b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiInputFilterTest.java
similarity index 98%
rename from emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiInputFilterTest.java
rename to emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiInputFilterTest.java
index 4dd7387..5c5824f 100644
--- a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiInputFilterTest.java
+++ b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiInputFilterTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package androidx.emoji2.viewshelper;
+package androidx.emoji2.viewsintegration;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
diff --git a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiKeyListenerTest.java b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiKeyListenerTest.java
similarity index 98%
rename from emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiKeyListenerTest.java
rename to emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiKeyListenerTest.java
index d944658..f73e1a2 100644
--- a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiKeyListenerTest.java
+++ b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiKeyListenerTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package androidx.emoji2.viewshelper;
+package androidx.emoji2.viewsintegration;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
diff --git a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiTextViewHelperPre19Test.java b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTextViewHelperPre19Test.java
similarity index 98%
rename from emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiTextViewHelperPre19Test.java
rename to emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTextViewHelperPre19Test.java
index 308dcfd..b54be67 100644
--- a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiTextViewHelperPre19Test.java
+++ b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTextViewHelperPre19Test.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package androidx.emoji2.viewshelper;
+package androidx.emoji2.viewsintegration;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
diff --git a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiTextViewHelperTest.java b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTextViewHelperTest.java
similarity index 99%
rename from emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiTextViewHelperTest.java
rename to emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTextViewHelperTest.java
index 909ca57..39a1bdc 100644
--- a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiTextViewHelperTest.java
+++ b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTextViewHelperTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package androidx.emoji2.viewshelper;
+package androidx.emoji2.viewsintegration;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.hasItem;
diff --git a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiTextWatcherDisabledTest.java b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTextWatcherDisabledTest.java
similarity index 98%
rename from emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiTextWatcherDisabledTest.java
rename to emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTextWatcherDisabledTest.java
index e5d4b12..b3456bc 100644
--- a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiTextWatcherDisabledTest.java
+++ b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTextWatcherDisabledTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package androidx.emoji2.viewshelper;
+package androidx.emoji2.viewsintegration;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
diff --git a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiTextWatcherTest.java b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTextWatcherTest.java
similarity index 98%
rename from emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiTextWatcherTest.java
rename to emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTextWatcherTest.java
index 0822f36..8f149da 100644
--- a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiTextWatcherTest.java
+++ b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTextWatcherTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package androidx.emoji2.viewshelper;
+package androidx.emoji2.viewsintegration;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
diff --git a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiTransformationMethodTest.java b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTransformationMethodTest.java
similarity index 99%
rename from emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiTransformationMethodTest.java
rename to emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTransformationMethodTest.java
index e0c6792..b8e13b7 100644
--- a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewshelper/EmojiTransformationMethodTest.java
+++ b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTransformationMethodTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package androidx.emoji2.viewshelper;
+package androidx.emoji2.viewsintegration;
import static androidx.emoji2.util.EmojiMatcher.sameCharSequence;
diff --git a/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewshelper/EmojiEditTextHelper.java b/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiEditTextHelper.java
similarity index 99%
rename from emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewshelper/EmojiEditTextHelper.java
rename to emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiEditTextHelper.java
index b784466c..0c482b3 100644
--- a/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewshelper/EmojiEditTextHelper.java
+++ b/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiEditTextHelper.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package androidx.emoji2.viewshelper;
+package androidx.emoji2.viewsintegration;
import android.os.Build;
import android.text.method.KeyListener;
diff --git a/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewshelper/EmojiEditableFactory.java b/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiEditableFactory.java
similarity index 98%
rename from emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewshelper/EmojiEditableFactory.java
rename to emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiEditableFactory.java
index 7e9c5a4..bd10953 100644
--- a/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewshelper/EmojiEditableFactory.java
+++ b/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiEditableFactory.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package androidx.emoji2.viewshelper;
+package androidx.emoji2.viewsintegration;
import android.annotation.SuppressLint;
import android.text.Editable;
diff --git a/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewshelper/EmojiInputConnection.java b/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiInputConnection.java
similarity index 98%
rename from emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewshelper/EmojiInputConnection.java
rename to emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiInputConnection.java
index 9a0cedd..1d5a3af 100644
--- a/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewshelper/EmojiInputConnection.java
+++ b/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiInputConnection.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package androidx.emoji2.viewshelper;
+package androidx.emoji2.viewsintegration;
import android.text.Editable;
import android.view.inputmethod.EditorInfo;
diff --git a/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewshelper/EmojiInputFilter.java b/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiInputFilter.java
similarity index 98%
rename from emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewshelper/EmojiInputFilter.java
rename to emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiInputFilter.java
index f3746de..abe03f0 100644
--- a/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewshelper/EmojiInputFilter.java
+++ b/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiInputFilter.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package androidx.emoji2.viewshelper;
+package androidx.emoji2.viewsintegration;
import android.text.Selection;
import android.text.Spannable;
diff --git a/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewshelper/EmojiKeyListener.java b/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiKeyListener.java
similarity index 98%
rename from emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewshelper/EmojiKeyListener.java
rename to emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiKeyListener.java
index 67ddc72..b2b2e91 100644
--- a/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewshelper/EmojiKeyListener.java
+++ b/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiKeyListener.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package androidx.emoji2.viewshelper;
+package androidx.emoji2.viewsintegration;
import android.text.Editable;
import android.text.method.KeyListener;
diff --git a/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewshelper/EmojiTextViewHelper.java b/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiTextViewHelper.java
similarity index 99%
rename from emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewshelper/EmojiTextViewHelper.java
rename to emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiTextViewHelper.java
index 80c0f63..e3aed72 100644
--- a/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewshelper/EmojiTextViewHelper.java
+++ b/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiTextViewHelper.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package androidx.emoji2.viewshelper;
+package androidx.emoji2.viewsintegration;
import android.os.Build;
import android.text.InputFilter;
diff --git a/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewshelper/EmojiTextWatcher.java b/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiTextWatcher.java
similarity index 98%
rename from emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewshelper/EmojiTextWatcher.java
rename to emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiTextWatcher.java
index 64e1f61a..876a7e7 100644
--- a/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewshelper/EmojiTextWatcher.java
+++ b/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiTextWatcher.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package androidx.emoji2.viewshelper;
+package androidx.emoji2.viewsintegration;
import android.text.Editable;
import android.text.Selection;
diff --git a/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewshelper/EmojiTransformationMethod.java b/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiTransformationMethod.java
similarity index 98%
rename from emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewshelper/EmojiTransformationMethod.java
rename to emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiTransformationMethod.java
index bd3561f..3123fe3 100644
--- a/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewshelper/EmojiTransformationMethod.java
+++ b/emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiTransformationMethod.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package androidx.emoji2.viewshelper;
+package androidx.emoji2.viewsintegration;
import android.graphics.Rect;
import android.text.method.TransformationMethod;
diff --git a/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiButton.java b/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiButton.java
index 373e03e..3040488 100644
--- a/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiButton.java
+++ b/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiButton.java
@@ -24,7 +24,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.widget.TextViewCompat;
-import androidx.emoji2.viewshelper.EmojiTextViewHelper;
+import androidx.emoji2.viewsintegration.EmojiTextViewHelper;
/**
* Button widget enhanced with emoji capability by using {@link EmojiTextViewHelper}. When used
diff --git a/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiEditText.java b/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiEditText.java
index b7dbdc3..5ad64d7 100644
--- a/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiEditText.java
+++ b/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiEditText.java
@@ -28,7 +28,7 @@
import androidx.annotation.Nullable;
import androidx.core.widget.TextViewCompat;
import androidx.emoji2.text.EmojiCompat;
-import androidx.emoji2.viewshelper.EmojiEditTextHelper;
+import androidx.emoji2.viewsintegration.EmojiEditTextHelper;
/**
* EditText widget enhanced with emoji capability by using {@link EmojiEditTextHelper}. When used
diff --git a/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiExtractEditText.java b/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiExtractEditText.java
index 6f625f8..83002be 100644
--- a/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiExtractEditText.java
+++ b/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiExtractEditText.java
@@ -32,7 +32,7 @@
import androidx.core.widget.TextViewCompat;
import androidx.emoji2.text.EmojiCompat;
import androidx.emoji2.text.EmojiSpan;
-import androidx.emoji2.viewshelper.EmojiEditTextHelper;
+import androidx.emoji2.viewsintegration.EmojiEditTextHelper;
/**
* ExtractEditText widget enhanced with emoji capability by using {@link EmojiEditTextHelper}.
diff --git a/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiTextView.java b/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiTextView.java
index d32dcf3..9ca8147 100644
--- a/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiTextView.java
+++ b/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiTextView.java
@@ -24,7 +24,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.widget.TextViewCompat;
-import androidx.emoji2.viewshelper.EmojiTextViewHelper;
+import androidx.emoji2.viewsintegration.EmojiTextViewHelper;
/**
* TextView widget enhanced with emoji capability by using {@link EmojiTextViewHelper}. When used
diff --git a/fragment/fragment-lint/build.gradle b/fragment/fragment-lint/build.gradle
index 446b4be..da2c726 100644
--- a/fragment/fragment-lint/build.gradle
+++ b/fragment/fragment-lint/build.gradle
@@ -25,13 +25,7 @@
}
dependencies {
- // compileOnly because we use lintChecks and it doesn't allow other types of deps
- // this ugly hack exists because of b/63873667
- if (rootProject.hasProperty("android.injected.invoked.from.ide")) {
- compileOnly(LINT_API_LATEST)
- } else {
- compileOnly(LINT_API_MIN)
- }
+ compileOnly(LINT_API_MIN)
compileOnly(KOTLIN_STDLIB)
testImplementation(KOTLIN_STDLIB)
diff --git a/fragment/fragment-testing-lint/build.gradle b/fragment/fragment-testing-lint/build.gradle
index e8edd4f..9242788 100644
--- a/fragment/fragment-testing-lint/build.gradle
+++ b/fragment/fragment-testing-lint/build.gradle
@@ -25,13 +25,7 @@
}
dependencies {
- // compileOnly because we use lintChecks and it doesn't allow other types of deps
- // this ugly hack exists because of b/63873667
- if (rootProject.hasProperty("android.injected.invoked.from.ide")) {
- compileOnly(LINT_API_LATEST)
- } else {
- compileOnly(LINT_API_MIN)
- }
+ compileOnly(LINT_API_MIN)
compileOnly(KOTLIN_STDLIB)
testImplementation(KOTLIN_STDLIB)
diff --git a/gradle.properties b/gradle.properties
index 5edf07a8..fc4663d 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -9,6 +9,7 @@
android.uniquePackageNames=false
android.enableAdditionalTestOutput=true
android.useAndroidX=true
+android.nonTransitiveRClass=true
# Run multiple kotlin compilations in parallel within the same project.
# See also https://github.com/JetBrains/kotlin/blob/1978db9d0e68a2ec29aded30a07e9c3c740c29f6/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt#L100 and https://blog.jetbrains.com/kotlin/2019/01/kotlin-1-3-20-released/
kotlin.parallel.tasks.in.project=true
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 16b03d1..7b7b0a3 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -121,7 +121,7 @@
protobuf = { module = "com.google.protobuf:protobuf-java", version = "3.4.0" }
protobufCompiler = { module = "com.google.protobuf:protoc", version = "3.10.0" }
protobufGradlePlugin = { module = "com.google.protobuf:protobuf-gradle-plugin", version = "0.8.16" }
-protobufLite = { module = "com.google.protobuf:protobuf-javalite", version = "3.4.0" }
+protobufLite = { module = "com.google.protobuf:protobuf-javalite", version = "3.10.0" }
reactiveStreams = { module = "org.reactivestreams:reactive-streams", version = "1.0.0" }
retrofit = { module = "com.squareup.retrofit2:retrofit", version = "2.7.2" }
robolectric = { module = "org.robolectric:robolectric", version = "4.4-alpha-2" }
diff --git a/lifecycle/lifecycle-compiler/build.gradle b/lifecycle/lifecycle-compiler/build.gradle
index cde5b80..f64dfa1 100644
--- a/lifecycle/lifecycle-compiler/build.gradle
+++ b/lifecycle/lifecycle-compiler/build.gradle
@@ -25,13 +25,6 @@
id("kotlin")
}
-// Temporary hack to stop AS to adding two guavas into test's classpath
-configurations.all {
- resolutionStrategy {
- force GUAVA
- }
-}
-
dependencies {
implementation(project(":lifecycle:lifecycle-common"))
implementation(KOTLIN_STDLIB)
diff --git a/lifecycle/lifecycle-livedata-core-ktx-lint/build.gradle b/lifecycle/lifecycle-livedata-core-ktx-lint/build.gradle
index 0dc1113..193e1c7 100644
--- a/lifecycle/lifecycle-livedata-core-ktx-lint/build.gradle
+++ b/lifecycle/lifecycle-livedata-core-ktx-lint/build.gradle
@@ -26,15 +26,8 @@
}
dependencies {
- // compileOnly because we use lintChecks and it doesn't allow other types of deps
- // this ugly hack exists because of b/63873667
- if (rootProject.hasProperty("android.injected.invoked.from.ide")) {
- compileOnly(LINT_API_LATEST)
- compileOnly(LINT_CORE)
- } else {
- compileOnly(LINT_API_MIN)
- compileOnly("com.android.tools.lint:lint:$lintMinVersion")
- }
+ compileOnly(LINT_API_MIN)
+ compileOnly("com.android.tools.lint:lint:$lintMinVersion")
compileOnly(KOTLIN_STDLIB)
testImplementation(KOTLIN_STDLIB)
diff --git a/lifecycle/lifecycle-runtime-ktx-lint/build.gradle b/lifecycle/lifecycle-runtime-ktx-lint/build.gradle
index c7e05bd..6a17065 100644
--- a/lifecycle/lifecycle-runtime-ktx-lint/build.gradle
+++ b/lifecycle/lifecycle-runtime-ktx-lint/build.gradle
@@ -26,13 +26,7 @@
}
dependencies {
- // compileOnly because we use lintChecks and it doesn't allow other types of deps
- // this ugly hack exists because of b/63873667
- if (rootProject.hasProperty("android.injected.invoked.from.ide")) {
- compileOnly(LINT_API_LATEST)
- } else {
- compileOnly(LINT_API_MIN)
- }
+ compileOnly(LINT_API_MIN)
compileOnly(KOTLIN_STDLIB)
testImplementation(KOTLIN_STDLIB)
diff --git a/media2/media2-widget/src/main/res/values-eu/strings.xml b/media2/media2-widget/src/main/res/values-eu/strings.xml
index 4fde31a..5999909 100644
--- a/media2/media2-widget/src/main/res/values-eu/strings.xml
+++ b/media2/media2-widget/src/main/res/values-eu/strings.xml
@@ -20,7 +20,7 @@
<string name="MediaControlView_subtitle_off_text" msgid="3464220590351304587">"Desaktibatuta"</string>
<string name="MediaControlView_audio_track_text" msgid="3309135445007366582">"Audio-pista"</string>
<string name="MediaControlView_audio_track_none_text" msgid="2659752099246305694">"Bat ere ez"</string>
- <string name="MediaControlView_playback_speed_text" msgid="1481072528142380025">"Erreprodukzioaren abiadura"</string>
+ <string name="MediaControlView_playback_speed_text" msgid="1481072528142380025">"Erreprodukzio-abiadura"</string>
<string name="MediaControlView_playback_speed_normal" msgid="2029510260288453183">"Normala"</string>
<string name="MediaControlView_time_placeholder" msgid="6734584158942500617">"00:00:00"</string>
<string name="MediaControlView_subtitle_track_number_text" msgid="2241078077382492349">"<xliff:g id="TRACK_NUMBER">%1$d</xliff:g>. pista"</string>
diff --git a/recyclerview/recyclerview-lint/build.gradle b/recyclerview/recyclerview-lint/build.gradle
index 3a3b3ff..e976ce8 100644
--- a/recyclerview/recyclerview-lint/build.gradle
+++ b/recyclerview/recyclerview-lint/build.gradle
@@ -25,13 +25,7 @@
}
dependencies {
- // compileOnly because we use lintChecks and it doesn't allow other types of deps
- // this ugly hack exists because of b/63873667
- if (rootProject.hasProperty("android.injected.invoked.from.ide")) {
- compileOnly(LINT_API_LATEST)
- } else {
- compileOnly(LINT_API_MIN)
- }
+ compileOnly(LINT_API_MIN)
compileOnly(KOTLIN_STDLIB)
testImplementation(KOTLIN_STDLIB)
diff --git a/resourceinspection/resourceinspection-annotation/src/main/java/androidx/resourceinspection/annotation/AppCompatShadowedAttributes.java b/resourceinspection/resourceinspection-annotation/src/main/java/androidx/resourceinspection/annotation/AppCompatShadowedAttributes.java
index 2ec1183..fa0ccbe 100644
--- a/resourceinspection/resourceinspection-annotation/src/main/java/androidx/resourceinspection/annotation/AppCompatShadowedAttributes.java
+++ b/resourceinspection/resourceinspection-annotation/src/main/java/androidx/resourceinspection/annotation/AppCompatShadowedAttributes.java
@@ -50,6 +50,15 @@
* AppCompat to mix shadowed attributes and regular attribute annotations on the same view
* without hand-written inspection companions.
* <p>
+ * The full list of supported interfaces is
+ * {@link androidx.core.widget.AutoSizeableTextView},
+ * {@link androidx.core.view.TintableBackgroundView},
+ * {@link androidx.core.widget.TintableCheckedTextView},
+ * {@link androidx.core.widget.TintableCompoundButton},
+ * {@link androidx.core.widget.TintableCompoundDrawablesView}, and
+ * {@link androidx.core.widget.TintableImageSourceView}.
+ * Please see the mapping in {@link androidx.resourceinspection.processor} for full details.
+ *
* @hide
*/
@Target(TYPE)
diff --git a/resourceinspection/resourceinspection-processor/build.gradle b/resourceinspection/resourceinspection-processor/build.gradle
index 42b6a9d..8e8f114 100644
--- a/resourceinspection/resourceinspection-processor/build.gradle
+++ b/resourceinspection/resourceinspection-processor/build.gradle
@@ -38,16 +38,17 @@
kapt(GRADLE_INCAP_HELPER_PROCESSOR)
kapt(AUTO_SERVICE_PROCESSOR)
- testImplementation(project(":resourceinspection:resourceinspection-annotation"))
- testImplementation(project(":annotation:annotation"))
- testImplementation(INTELLIJ_ANNOTATIONS)
testImplementation(JUNIT)
- testImplementation(JSR250)
testImplementation(GOOGLE_COMPILE_TESTING)
testImplementation(TRUTH)
- testImplementation fileTree(
+
+ testRuntimeOnly(project(":resourceinspection:resourceinspection-annotation"))
+ testRuntimeOnly(project(":annotation:annotation"))
+ testRuntimeOnly(fileTree(
dir: "${getSdkPath(project)}/platforms/$SupportConfig.COMPILE_SDK_VERSION/",
- include : "android.jar")
+ include : "android.jar"))
+ testRuntimeOnly(INTELLIJ_ANNOTATIONS)
+ testRuntimeOnly(JSR250)
}
androidx {
diff --git a/resourceinspection/resourceinspection-processor/src/main/kotlin/androidx/resourceinspection/processor/LayoutInspectionStep.kt b/resourceinspection/resourceinspection-processor/src/main/kotlin/androidx/resourceinspection/processor/LayoutInspectionStep.kt
index a9d59b3..33bc66c 100644
--- a/resourceinspection/resourceinspection-processor/src/main/kotlin/androidx/resourceinspection/processor/LayoutInspectionStep.kt
+++ b/resourceinspection/resourceinspection-processor/src/main/kotlin/androidx/resourceinspection/processor/LayoutInspectionStep.kt
@@ -21,6 +21,7 @@
import com.google.auto.common.GeneratedAnnotationSpecs.generatedAnnotationSpec
import com.google.auto.common.MoreElements.asExecutable
import com.google.auto.common.MoreElements.asType
+import com.google.auto.common.MoreElements.getPackage
import com.google.auto.common.Visibility
import com.google.auto.common.Visibility.effectiveVisibilityOfElement
import com.google.common.collect.ImmutableSetMultimap
@@ -48,40 +49,48 @@
).orElse(null)
override fun annotations(): Set<String> {
- return setOf(ATTRIBUTE)
+ return setOf(ATTRIBUTE, APP_COMPAT_SHADOWED_ATTRIBUTES)
}
override fun process(
elementsByAnnotation: ImmutableSetMultimap<String, Element>
): Set<Element> {
// TODO(b/180039277): Validate that linked APIs (e.g. InspectionCompanion) are present
- elementsByAnnotation[ATTRIBUTE]
- .map { asExecutable(it) }
- .groupBy { asType(it.enclosingElement) }
- .forEach { (type, getters) ->
- parseView(type, getters)?.let { view ->
- generateInspectionCompanion(view, generatedAnnotation)
- .writeTo(processingEnv.filer)
- }
- }
+
+ val views = mergeViews(
+ elementsByAnnotation[ATTRIBUTE]
+ .groupBy({ asType(it.enclosingElement) }, { asExecutable(it) }),
+ elementsByAnnotation[APP_COMPAT_SHADOWED_ATTRIBUTES]
+ .mapTo(mutableSetOf()) { asType(it) }
+ )
+ val filer = processingEnv.filer
+
+ views.forEach { generateInspectionCompanion(it, generatedAnnotation).writeTo(filer) }
+
+ // We don't defer elements for later rounds in this processor
return emptySet()
}
- /** Parse the annotated getters of a view class into a [View]. */
- private fun parseView(type: TypeElement, getters: Iterable<ExecutableElement>): View? {
- if (!type.asType().isAssignableTo("android.view.View")) {
- getters.forEach { getter ->
- printError(
- "@Attribute must only annotate subclasses of android.view.View",
- getter,
- getter.getAnnotationMirror(ATTRIBUTE)
- )
+ /** Merge shadowed and regular attributes into [View] models. */
+ private fun mergeViews(
+ viewsWithGetters: Map<TypeElement, List<ExecutableElement>>,
+ viewsWithShadowedAttributes: Set<TypeElement>
+ ): List<View> {
+ return (viewsWithGetters.keys + viewsWithShadowedAttributes).mapNotNull { viewType ->
+ val getterAttributes = viewsWithGetters[viewType].orEmpty().map(::parseGetter)
+
+ if (viewType in viewsWithShadowedAttributes) {
+ inferShadowedAttributes(viewType)?.let { shadowedAttributes ->
+ createView(viewType, getterAttributes + shadowedAttributes)
+ }
+ } else {
+ createView(viewType, getterAttributes)
}
- return null
}
+ }
- val attributes = getters.map(::parseAttribute)
-
+ /** Parse the annotated getters of a view class into a [View]. */
+ private fun createView(type: TypeElement, attributes: Collection<Attribute?>): View? {
val duplicateAttributes = attributes
.filterNotNull()
.groupBy { it.qualifiedName }
@@ -106,7 +115,7 @@
return null
}
- if (attributes.any { it == null }) {
+ if (attributes.isEmpty() || attributes.any { it == null }) {
return null
}
@@ -114,7 +123,7 @@
}
/** Get an [Attribute] from a method known to have an `Attribute` annotation. */
- private fun parseAttribute(getter: ExecutableElement): Attribute? {
+ private fun parseGetter(getter: ExecutableElement): Attribute? {
val annotation = getter.getAnnotationMirror(ATTRIBUTE)!!
val annotationValue = getAnnotationValue(annotation, "value")
val value = annotationValue.value as String
@@ -129,6 +138,11 @@
return null
}
+ if (!getter.enclosingElement.asType().isAssignableTo(VIEW)) {
+ printError("@Attribute must be on a subclass of android.view.View", getter, annotation)
+ return null
+ }
+
val match = ATTRIBUTE_VALUE.matchEntire(value)
return if (match != null) {
@@ -189,7 +203,7 @@
AttributeType.LONG
}
TypeKind.DECLARED, TypeKind.ARRAY ->
- if (getter.returnType.isAssignableTo("android.graphics.Color")) {
+ if (getter.returnType.isAssignableTo(COLOR)) {
AttributeType.COLOR
} else {
// TODO(b/180041034): Validate object types and unbox primitives
@@ -199,6 +213,43 @@
}
}
+ /** Determines shadowed attributes based on interfaces present on the view. */
+ private fun inferShadowedAttributes(viewType: TypeElement): List<ShadowedAttribute>? {
+ if (!viewType.asType().isAssignableTo(VIEW)) {
+ printError(
+ "@AppCompatShadowedAttributes must be on a subclass of android.view.View",
+ viewType,
+ viewType.getAnnotationMirror(APP_COMPAT_SHADOWED_ATTRIBUTES)
+ )
+ return null
+ }
+
+ if (!getPackage(viewType).qualifiedName.startsWith("androidx.appcompat.")) {
+ printError(
+ "@AppCompatShadowedAttributes is only supported in the androidx.appcompat package",
+ viewType,
+ viewType.getAnnotationMirror(APP_COMPAT_SHADOWED_ATTRIBUTES)
+ )
+ return null
+ }
+
+ val attributes = viewType.interfaces.flatMap {
+ APP_COMPAT_INTERFACE_MAP[it.toString()].orEmpty()
+ }
+
+ if (attributes.isEmpty()) {
+ printError(
+ "@AppCompatShadowedAttributes is present on this view, but it does not implement " +
+ "any interfaces that indicate it has shadowed attributes.",
+ viewType,
+ viewType.getAnnotationMirror(APP_COMPAT_SHADOWED_ATTRIBUTES)
+ )
+ return null
+ }
+
+ return attributes
+ }
+
private fun Element.hasResourceIdAnnotation(): Boolean {
return this.annotationMirrors.any {
asType(it.annotationType.asElement()).qualifiedName matches RESOURCE_ID_ANNOTATION
@@ -248,9 +299,16 @@
/** Regex for matching resource ID annotations. */
val RESOURCE_ID_ANNOTATION = """androidx?\.annotation\.[A-Z]\w+Res""".toRegex()
- /** Fully qualified name of the `Attribute` annotation` */
+ /** Fully qualified name of the `Attribute` annotation */
const val ATTRIBUTE = "androidx.resourceinspection.annotation.Attribute"
+ /** Fully qualified name of the `AppCompatShadowedAttributes` annotation */
+ const val APP_COMPAT_SHADOWED_ATTRIBUTES =
+ "androidx.resourceinspection.annotation.AppCompatShadowedAttributes"
+
+ /** Fully qualified name of the platform's Color class */
+ const val COLOR = "android.graphics.Color"
+
/** Fully qualified name of `ColorInt` */
const val COLOR_INT = "androidx.annotation.ColorInt"
@@ -259,5 +317,61 @@
/** Fully qualified name of `GravityInt` */
const val GRAVITY_INT = "androidx.annotation.GravityInt"
+
+ /** Fully qualified name of the platform's View class */
+ const val VIEW = "android.view.View"
+
+ /**
+ * Map of compat interface names in `androidx.core` to the AppCompat attributes they
+ * shadow. These virtual attributes are added to the inspection companion for views within
+ * AppCompat with the `@AppCompatShadowedAttributes` annotation.
+ *
+ * As you can tell, this is brittle. The good news is these are established platform APIs
+ * from API <= 29 (the minimum for app inspection) and are unlikely to change in the
+ * future. If you update this list, please update the documentation comment in
+ * [androidx.resourceinspection.annotation.AppCompatShadowedAttributes] as well.
+ */
+ val APP_COMPAT_INTERFACE_MAP: Map<String, List<ShadowedAttribute>> = mapOf(
+ "androidx.core.view.TintableBackgroundView" to listOf(
+ ShadowedAttribute("backgroundTint", "getBackgroundTintList()"),
+ ShadowedAttribute("backgroundTintMode", "getBackgroundTintMode()")
+ ),
+ "androidx.core.widget.AutoSizeableTextView" to listOf(
+ ShadowedAttribute(
+ "autoSizeTextType",
+ "getAutoSizeTextType()",
+ AttributeType.INT_ENUM,
+ listOf(
+ IntMap("none", 0 /* TextView.AUTO_SIZE_TEXT_TYPE_NONE */),
+ IntMap("uniform", 1 /* TextView.AUTO_SIZE_TEXT_TYPE_UNIFORM */),
+ )
+ ),
+ ShadowedAttribute(
+ "autoSizeStepGranularity", "getAutoSizeStepGranularity()", AttributeType.INT
+ ),
+ ShadowedAttribute(
+ "autoSizeMinTextSize", "getAutoSizeMinTextSize()", AttributeType.INT
+ ),
+ ShadowedAttribute(
+ "autoSizeMaxTextSize", "getAutoSizeMaxTextSize()", AttributeType.INT
+ )
+ ),
+ "androidx.core.widget.TintableCheckedTextView" to listOf(
+ ShadowedAttribute("checkMarkTint", "getCheckMarkTintList()"),
+ ShadowedAttribute("checkMarkTintMode", "getCheckMarkTintMode()")
+ ),
+ "androidx.core.widget.TintableCompoundButton" to listOf(
+ ShadowedAttribute("buttonTint", "getButtonTintList()"),
+ ShadowedAttribute("buttonTintMode", "getButtonTintMode()")
+ ),
+ "androidx.core.widget.TintableCompoundDrawablesView" to listOf(
+ ShadowedAttribute("drawableTint", "getCompoundDrawableTintList()"),
+ ShadowedAttribute("drawableTintMode", "getCompoundDrawableTintMode()")
+ ),
+ "androidx.core.widget.TintableImageSourceView" to listOf(
+ ShadowedAttribute("tint", "getImageTintList()"),
+ ShadowedAttribute("tintMode", "getImageTintMode()"),
+ )
+ )
}
}
diff --git a/resourceinspection/resourceinspection-processor/src/main/kotlin/androidx/resourceinspection/processor/Models.kt b/resourceinspection/resourceinspection-processor/src/main/kotlin/androidx/resourceinspection/processor/Models.kt
index ad46352..761d783 100644
--- a/resourceinspection/resourceinspection-processor/src/main/kotlin/androidx/resourceinspection/processor/Models.kt
+++ b/resourceinspection/resourceinspection-processor/src/main/kotlin/androidx/resourceinspection/processor/Models.kt
@@ -53,6 +53,19 @@
get() = "${getter.simpleName}()"
}
+/**
+ * Represents a shadowed platform attribute in a different namespace, mainly for AppCompat.
+ *
+ * The constructor has some reasonable defaults to make defining these as constants less toilsome.
+ */
+internal data class ShadowedAttribute(
+ override val name: String,
+ override val invocation: String,
+ override val type: AttributeType = AttributeType.OBJECT,
+ override val intMapping: List<IntMap> = emptyList(),
+ override val namespace: String = "androidx.appcompat"
+) : Attribute
+
/** Represents an `Attribute.IntMap` entry. */
internal data class IntMap(
val name: String,
diff --git a/resourceinspection/resourceinspection-processor/src/test/kotlin/androidx/resourceinspection/processor/ResourceInspectionProcessorTest.kt b/resourceinspection/resourceinspection-processor/src/test/kotlin/androidx/resourceinspection/processor/ResourceInspectionProcessorTest.kt
index 4a62ea9..83ef333 100644
--- a/resourceinspection/resourceinspection-processor/src/test/kotlin/androidx/resourceinspection/processor/ResourceInspectionProcessorTest.kt
+++ b/resourceinspection/resourceinspection-processor/src/test/kotlin/androidx/resourceinspection/processor/ResourceInspectionProcessorTest.kt
@@ -684,7 +684,7 @@
"""
)
)
- ).hadErrorContaining("@Attribute must only annotate subclasses of android.view.View")
+ ).hadErrorContaining("@Attribute must be on a subclass of android.view.View")
}
@Test
@@ -855,6 +855,582 @@
)
}
+ @Test
+ fun `shadowed background tint`() {
+ assertThat(
+ compile(
+ fakeR("androidx.appcompat", "backgroundTint", "backgroundTintMode"),
+ fakeInterface("androidx.core.view.TintableBackgroundView"),
+ java(
+ "androidx.appcompat.test.BackgroundTintTestView",
+ """
+ package androidx.appcompat.test;
+
+ import android.content.Context;
+ import android.util.AttributeSet;
+ import android.view.View;
+ import androidx.core.view.TintableBackgroundView;
+ import androidx.resourceinspection.annotation.AppCompatShadowedAttributes;
+
+ @AppCompatShadowedAttributes
+ public final class BackgroundTintTestView extends View
+ implements TintableBackgroundView {
+ public BackgroundTintTestView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+ }
+ """
+ )
+ )
+ ).generatedSourceFile(
+ "androidx.appcompat.test.BackgroundTintTestView${'$'}InspectionCompanion",
+ ).hasSourceEquivalentTo(
+ java(
+ "androidx.appcompat.test.BackgroundTintTestView${'$'}InspectionCompanion",
+ """
+ package androidx.appcompat.test;
+
+ import android.view.inspector.InspectionCompanion;
+ import android.view.inspector.PropertyMapper;
+ import android.view.inspector.PropertyReader;
+ import androidx.annotation.NonNull;
+ import androidx.annotation.RequiresApi;
+ import androidx.appcompat.R;
+ import java.lang.Override;
+ import javax.annotation.processing.Generated;
+
+ @RequiresApi(29)
+ @Generated("androidx.resourceinspection.processor.ResourceInspectionProcessor")
+ public final class BackgroundTintTestView${'$'}InspectionCompanion
+ implements InspectionCompanion<BackgroundTintTestView> {
+ private boolean mPropertiesMapped = false;
+ private int mBackgroundTintId;
+ private int mBackgroundTintModeId;
+
+ @Override
+ public void mapProperties(@NonNull PropertyMapper propertyMapper) {
+ mBackgroundTintId = propertyMapper
+ .mapObject("backgroundTint", R.attr.backgroundTint);
+ mBackgroundTintModeId = propertyMapper
+ .mapObject("backgroundTintMode", R.attr.backgroundTintMode);
+ }
+
+ @Override
+ public void readProperties(
+ @NonNull BackgroundTintTestView backgroundTintTestView,
+ @NonNull PropertyReader propertyReader
+ ) {
+ if (!mPropertiesMapped) {
+ throw new InspectionCompanion.UninitializedPropertyMapException();
+ }
+ propertyReader.readObject(
+ mBackgroundTintId,
+ backgroundTintTestView.getBackgroundTintList());
+ propertyReader.readObject(
+ mBackgroundTintModeId,
+ backgroundTintTestView.getBackgroundTintMode());
+ }
+ }
+ """
+ )
+ )
+ }
+
+ @Test
+ fun `shadowed auto-size text view`() {
+ assertThat(
+ compile(
+ fakeR(
+ "androidx.appcompat", "autoSizeMaxTextSize", "autoSizeMinTextSize",
+ "autoSizeStepGranularity", "autoSizeTextType"
+ ),
+ fakeInterface("androidx.core.widget.AutoSizeableTextView"),
+ java(
+ "androidx.appcompat.test.AutoSizeTestView",
+ """
+ package androidx.appcompat.test;
+
+ import android.content.Context;
+ import android.util.AttributeSet;
+ import android.widget.TextView;
+ import androidx.core.widget.AutoSizeableTextView;
+ import androidx.resourceinspection.annotation.AppCompatShadowedAttributes;
+
+ @AppCompatShadowedAttributes
+ public final class AutoSizeTestView extends TextView
+ implements AutoSizeableTextView {
+ public AutoSizeTestView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+ }
+ """
+ )
+ )
+ ).generatedSourceFile(
+ "androidx.appcompat.test.AutoSizeTestView${'$'}InspectionCompanion",
+ ).hasSourceEquivalentTo(
+ java(
+ "androidx.appcompat.test.AutoSizeTestView${'$'}InspectionCompanion",
+ """
+ package androidx.appcompat.test;
+
+ import android.view.inspector.InspectionCompanion;
+ import android.view.inspector.PropertyMapper;
+ import android.view.inspector.PropertyReader;
+ import androidx.annotation.NonNull;
+ import androidx.annotation.RequiresApi;
+ import androidx.appcompat.R;
+ import java.lang.Override;
+ import java.lang.String;
+ import java.util.function.IntFunction;
+ import javax.annotation.processing.Generated;
+
+ @RequiresApi(29)
+ @Generated("androidx.resourceinspection.processor.ResourceInspectionProcessor")
+ public final class AutoSizeTestView${'$'}InspectionCompanion
+ implements InspectionCompanion<AutoSizeTestView> {
+ private boolean mPropertiesMapped = false;
+ private int mAutoSizeMaxTextSizeId;
+ private int mAutoSizeMinTextSizeId;
+ private int mAutoSizeStepGranularityId;
+ private int mAutoSizeTextTypeId;
+
+ @Override
+ public void mapProperties(@NonNull PropertyMapper propertyMapper) {
+ mAutoSizeMaxTextSizeId = propertyMapper
+ .mapInt("autoSizeMaxTextSize", R.attr.autoSizeMaxTextSize);
+ mAutoSizeMinTextSizeId = propertyMapper
+ .mapInt("autoSizeMinTextSize", R.attr.autoSizeMinTextSize);
+ mAutoSizeStepGranularityId = propertyMapper
+ .mapInt("autoSizeStepGranularity", R.attr.autoSizeStepGranularity);
+ mAutoSizeTextTypeId = propertyMapper.mapIntEnum(
+ "autoSizeTextType",
+ R.attr.autoSizeTextType,
+ new IntFunction<String>() {
+ @Override
+ public String apply(int value) {
+ switch (value) {
+ case 0:
+ return "none";
+ case 1:
+ return "uniform";
+ default:
+ return String.valueOf(value);
+ }
+ }
+ }
+ );
+ }
+
+ @Override
+ public void readProperties(
+ @NonNull AutoSizeTestView autoSizeTestView,
+ @NonNull PropertyReader propertyReader
+ ) {
+ if (!mPropertiesMapped) {
+ throw new InspectionCompanion.UninitializedPropertyMapException();
+ }
+ propertyReader.readInt(
+ mAutoSizeMaxTextSizeId,
+ autoSizeTestView.getAutoSizeMaxTextSize());
+ propertyReader.readInt(
+ mAutoSizeMinTextSizeId,
+ autoSizeTestView.getAutoSizeMinTextSize());
+ propertyReader.readInt(
+ mAutoSizeStepGranularityId,
+ autoSizeTestView.getAutoSizeStepGranularity());
+ propertyReader.readIntEnum(
+ mAutoSizeTextTypeId,
+ autoSizeTestView.getAutoSizeTextType());
+ }
+ }
+ """
+ )
+ )
+ }
+
+ @Test
+ fun `shadowed check mark tint`() {
+ assertThat(
+ compile(
+ fakeR("androidx.appcompat", "checkMarkTint", "checkMarkTintMode"),
+ fakeInterface("androidx.core.widget.TintableCheckedTextView"),
+ java(
+ "androidx.appcompat.test.CheckMarkTintTestView",
+ """
+ package androidx.appcompat.test;
+
+ import android.content.Context;
+ import android.util.AttributeSet;
+ import android.widget.CheckedTextView;
+ import androidx.core.widget.TintableCheckedTextView;
+ import androidx.resourceinspection.annotation.AppCompatShadowedAttributes;
+
+ @AppCompatShadowedAttributes
+ public final class CheckMarkTintTestView extends CheckedTextView
+ implements TintableCheckedTextView {
+ public CheckMarkTintTestView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+ }
+ """
+ )
+ )
+ ).generatedSourceFile(
+ "androidx.appcompat.test.CheckMarkTintTestView${'$'}InspectionCompanion",
+ ).hasSourceEquivalentTo(
+ java(
+ "androidx.appcompat.test.CheckMarkTintTestView${'$'}InspectionCompanion",
+ """
+ package androidx.appcompat.test;
+
+ import android.view.inspector.InspectionCompanion;
+ import android.view.inspector.PropertyMapper;
+ import android.view.inspector.PropertyReader;
+ import androidx.annotation.NonNull;
+ import androidx.annotation.RequiresApi;
+ import androidx.appcompat.R;
+ import java.lang.Override;
+ import javax.annotation.processing.Generated;
+
+ @RequiresApi(29)
+ @Generated("androidx.resourceinspection.processor.ResourceInspectionProcessor")
+ public final class CheckMarkTintTestView${'$'}InspectionCompanion
+ implements InspectionCompanion<CheckMarkTintTestView> {
+ private boolean mPropertiesMapped = false;
+ private int mCheckMarkTintId;
+ private int mCheckMarkTintModeId;
+
+ @Override
+ public void mapProperties(@NonNull PropertyMapper propertyMapper) {
+ mCheckMarkTintId = propertyMapper
+ .mapObject("checkMarkTint", R.attr.checkMarkTint);
+ mCheckMarkTintModeId = propertyMapper
+ .mapObject("checkMarkTintMode", R.attr.checkMarkTintMode);
+ }
+
+ @Override
+ public void readProperties(
+ @NonNull CheckMarkTintTestView checkMarkTintTestView,
+ @NonNull PropertyReader propertyReader
+ ) {
+ if (!mPropertiesMapped) {
+ throw new InspectionCompanion.UninitializedPropertyMapException();
+ }
+ propertyReader.readObject(
+ mCheckMarkTintId,
+ checkMarkTintTestView.getCheckMarkTintList());
+ propertyReader.readObject(
+ mCheckMarkTintModeId,
+ checkMarkTintTestView.getCheckMarkTintMode());
+ }
+ }
+ """
+ )
+ )
+ }
+
+ @Test
+ fun `shadowed compound button tint`() {
+ assertThat(
+ compile(
+ fakeR("androidx.appcompat", "buttonTint", "buttonTintMode"),
+ fakeInterface("androidx.core.widget.TintableCompoundButton"),
+ java(
+ "androidx.appcompat.test.CompoundButtonTintTestView",
+ """
+ package androidx.appcompat.test;
+
+ import android.content.Context;
+ import android.util.AttributeSet;
+ import android.widget.RadioButton;
+ import androidx.core.widget.TintableCompoundButton;
+ import androidx.resourceinspection.annotation.AppCompatShadowedAttributes;
+
+ @AppCompatShadowedAttributes
+ public final class CompoundButtonTintTestView extends RadioButton
+ implements TintableCompoundButton {
+ public CompoundButtonTintTestView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+ }
+ """
+ )
+ )
+ ).generatedSourceFile(
+ "androidx.appcompat.test.CompoundButtonTintTestView${'$'}InspectionCompanion",
+ ).hasSourceEquivalentTo(
+ java(
+ "androidx.appcompat.test.CompoundButtonTintTestView${'$'}InspectionCompanion",
+ """
+ package androidx.appcompat.test;
+
+ import android.view.inspector.InspectionCompanion;
+ import android.view.inspector.PropertyMapper;
+ import android.view.inspector.PropertyReader;
+ import androidx.annotation.NonNull;
+ import androidx.annotation.RequiresApi;
+ import androidx.appcompat.R;
+ import java.lang.Override;
+ import javax.annotation.processing.Generated;
+
+ @RequiresApi(29)
+ @Generated("androidx.resourceinspection.processor.ResourceInspectionProcessor")
+ public final class CompoundButtonTintTestView${'$'}InspectionCompanion
+ implements InspectionCompanion<CompoundButtonTintTestView> {
+ private boolean mPropertiesMapped = false;
+ private int mButtonTintId;
+ private int mButtonTintModeId;
+
+ @Override
+ public void mapProperties(@NonNull PropertyMapper propertyMapper) {
+ mButtonTintId = propertyMapper
+ .mapObject("buttonTint", R.attr.buttonTint);
+ mButtonTintModeId = propertyMapper
+ .mapObject("buttonTintMode", R.attr.buttonTintMode);
+ }
+
+ @Override
+ public void readProperties(
+ @NonNull CompoundButtonTintTestView compoundButtonTintTestView,
+ @NonNull PropertyReader propertyReader
+ ) {
+ if (!mPropertiesMapped) {
+ throw new InspectionCompanion.UninitializedPropertyMapException();
+ }
+ propertyReader.readObject(
+ mButtonTintId,
+ compoundButtonTintTestView.getButtonTintList());
+ propertyReader.readObject(
+ mButtonTintModeId,
+ compoundButtonTintTestView.getButtonTintMode());
+ }
+ }
+ """
+ )
+ )
+ }
+
+ @Test
+ fun `shadowed compound drawables tint`() {
+ assertThat(
+ compile(
+ fakeR("androidx.appcompat", "drawableTint", "drawableTintMode"),
+ fakeInterface("androidx.core.widget.TintableCompoundDrawablesView"),
+ java(
+ "androidx.appcompat.test.CompoundDrawablesTestView",
+ """
+ package androidx.appcompat.test;
+
+ import android.content.Context;
+ import android.util.AttributeSet;
+ import android.widget.TextView;
+ import androidx.core.widget.TintableCompoundDrawablesView;
+ import androidx.resourceinspection.annotation.AppCompatShadowedAttributes;
+
+ @AppCompatShadowedAttributes
+ public final class CompoundDrawablesTestView extends TextView
+ implements TintableCompoundDrawablesView {
+ public CompoundDrawablesTestView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+ }
+ """
+ )
+ )
+ ).generatedSourceFile(
+ "androidx.appcompat.test.CompoundDrawablesTestView${'$'}InspectionCompanion",
+ ).hasSourceEquivalentTo(
+ java(
+ "androidx.appcompat.test.CompoundDrawablesTestView${'$'}InspectionCompanion",
+ """
+ package androidx.appcompat.test;
+
+ import android.view.inspector.InspectionCompanion;
+ import android.view.inspector.PropertyMapper;
+ import android.view.inspector.PropertyReader;
+ import androidx.annotation.NonNull;
+ import androidx.annotation.RequiresApi;
+ import androidx.appcompat.R;
+ import java.lang.Override;
+ import javax.annotation.processing.Generated;
+
+ @RequiresApi(29)
+ @Generated("androidx.resourceinspection.processor.ResourceInspectionProcessor")
+ public final class CompoundDrawablesTestView${'$'}InspectionCompanion
+ implements InspectionCompanion<CompoundDrawablesTestView> {
+ private boolean mPropertiesMapped = false;
+ private int mDrawableTintId;
+ private int mDrawableTintModeId;
+
+ @Override
+ public void mapProperties(@NonNull PropertyMapper propertyMapper) {
+ mDrawableTintId = propertyMapper
+ .mapObject("drawableTint", R.attr.drawableTint);
+ mDrawableTintModeId = propertyMapper
+ .mapObject("drawableTintMode", R.attr.drawableTintMode);
+ }
+
+ @Override
+ public void readProperties(
+ @NonNull CompoundDrawablesTestView compoundDrawablesTestView,
+ @NonNull PropertyReader propertyReader
+ ) {
+ if (!mPropertiesMapped) {
+ throw new InspectionCompanion.UninitializedPropertyMapException();
+ }
+ propertyReader.readObject(
+ mDrawableTintId,
+ compoundDrawablesTestView.getCompoundDrawableTintList());
+ propertyReader.readObject(
+ mDrawableTintModeId,
+ compoundDrawablesTestView.getCompoundDrawableTintMode());
+ }
+ }
+ """
+ )
+ )
+ }
+
+ @Test
+ fun `shadowed image tint`() {
+ assertThat(
+ compile(
+ fakeR("androidx.appcompat", "tint", "tintMode"),
+ fakeInterface("androidx.core.widget.TintableImageSourceView"),
+ java(
+ "androidx.appcompat.test.ImageTintTestView",
+ """
+ package androidx.appcompat.test;
+
+ import android.content.Context;
+ import android.util.AttributeSet;
+ import android.widget.ImageView;
+ import androidx.core.widget.TintableImageSourceView;
+ import androidx.resourceinspection.annotation.AppCompatShadowedAttributes;
+
+ @AppCompatShadowedAttributes
+ public final class ImageTintTestView extends ImageView
+ implements TintableImageSourceView {
+ public ImageTintTestView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+ }
+ """
+ )
+ )
+ ).generatedSourceFile(
+ "androidx.appcompat.test.ImageTintTestView${'$'}InspectionCompanion",
+ ).hasSourceEquivalentTo(
+ java(
+ "androidx.appcompat.test.ImageTintTestView${'$'}InspectionCompanion",
+ """
+ package androidx.appcompat.test;
+
+ import android.view.inspector.InspectionCompanion;
+ import android.view.inspector.PropertyMapper;
+ import android.view.inspector.PropertyReader;
+ import androidx.annotation.NonNull;
+ import androidx.annotation.RequiresApi;
+ import androidx.appcompat.R;
+ import java.lang.Override;
+ import javax.annotation.processing.Generated;
+
+ @RequiresApi(29)
+ @Generated("androidx.resourceinspection.processor.ResourceInspectionProcessor")
+ public final class ImageTintTestView${'$'}InspectionCompanion
+ implements InspectionCompanion<ImageTintTestView> {
+ private boolean mPropertiesMapped = false;
+ private int mTintId;
+ private int mTintModeId;
+
+ @Override
+ public void mapProperties(@NonNull PropertyMapper propertyMapper) {
+ mTintId = propertyMapper.mapObject("tint", R.attr.tint);
+ mTintModeId = propertyMapper.mapObject("tintMode", R.attr.tintMode);
+ }
+
+ @Override
+ public void readProperties(
+ @NonNull ImageTintTestView imageTintTestView,
+ @NonNull PropertyReader propertyReader
+ ) {
+ if (!mPropertiesMapped) {
+ throw new InspectionCompanion.UninitializedPropertyMapException();
+ }
+ propertyReader
+ .readObject(mTintId, imageTintTestView.getImageTintList());
+ propertyReader
+ .readObject(mTintModeId, imageTintTestView.getImageTintMode());
+ }
+ }
+ """
+ )
+ )
+ }
+
+ @Test
+ fun `shadowed attributes fails outside of appcompat`() {
+ assertThat(
+ compile(
+ fakeR("androidx.appcompat", "backgroundTint", "backgroundTintMode"),
+ fakeInterface("androidx.core.view.TintableBackgroundView"),
+ java(
+ "androidx.pkg.BadPackageShadowedTestView",
+ """
+ package androidx.pkg;
+
+ import android.content.Context;
+ import android.util.AttributeSet;
+ import android.view.View;
+ import androidx.core.view.TintableBackgroundView;
+ import androidx.resourceinspection.annotation.AppCompatShadowedAttributes;
+
+ @AppCompatShadowedAttributes
+ public final class BadPackageShadowedTestView extends View implements
+ TintableBackgroundView {
+ public BadPackageShadowedTestView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+ }
+ """
+ )
+ )
+ ).hadErrorContaining(
+ "@AppCompatShadowedAttributes is only supported in the androidx.appcompat package"
+ )
+ }
+
+ @Test
+ fun `shadowed attributes fails with no interfaces`() {
+ assertThat(
+ compile(
+ java(
+ "androidx.appcompat.test.NoShadowedInterfaceTestView",
+ """
+ package androidx.appcompat.test;
+
+ import android.content.Context;
+ import android.util.AttributeSet;
+ import android.view.View;
+ import androidx.core.view.TintableBackgroundView;
+ import androidx.resourceinspection.annotation.AppCompatShadowedAttributes;
+
+ @AppCompatShadowedAttributes
+ public final class NoShadowedInterfaceTestView extends View {
+ public NoShadowedInterfaceTestView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+ }
+ """
+ )
+ )
+ ).hadErrorContaining(
+ "@AppCompatShadowedAttributes is present on this view, but it does not implement any " +
+ "interfaces that indicate it has shadowed attributes."
+ )
+ }
+
private fun compile(vararg sources: JavaFileObject): Compilation {
return javac()
.withProcessors(ResourceInspectionProcessor())
@@ -881,4 +1457,17 @@
"""
)
}
+
+ private fun fakeInterface(name: String): JavaFileObject {
+ val packageName = name.substringBeforeLast('.')
+ val simpleName = name.substringAfterLast('.')
+ return java(
+ name,
+ """
+ package $packageName;
+
+ public interface $simpleName {}
+ """
+ )
+ }
}
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/XElement.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/XElement.kt
index b06d8c9..497b194 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/XElement.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/XElement.kt
@@ -40,6 +40,11 @@
* message. Without this information, developer gets no clue on where the error is.
*/
val fallbackLocationText: String
+
+ /**
+ * The documentation comment of the element, or null if there is none.
+ */
+ val docComment: String?
}
/**
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/XMessager.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/XMessager.kt
index 16f1bba..65561ab 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/XMessager.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/XMessager.kt
@@ -37,7 +37,11 @@
onPrintMessage(kind, msg, element)
}
- abstract fun onPrintMessage(kind: Diagnostic.Kind, msg: String, element: XElement? = null)
+ protected abstract fun onPrintMessage(
+ kind: Diagnostic.Kind,
+ msg: String,
+ element: XElement? = null
+ )
fun addMessageWatcher(watcher: XMessager) {
watchers.add(watcher)
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/XTypeElement.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/XTypeElement.kt
index 5109aff..aa692e1 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/XTypeElement.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/XTypeElement.kt
@@ -65,11 +65,49 @@
fun isInterface(): Boolean
/**
- * Returns `true` if this [XTypeElement] is declared as a Kotlin `object`
+ * Returns `true` if this [XTypeElement] represents a Kotlin functional interface,
+ * i.e. marked with the keyword `fun`
+ */
+ fun isFunctionalInterface(): Boolean
+
+ /**
+ * Returns `true` if this [XTypeElement] represents an ordinary class. ie not an enum, object,
+ * annotation, interface, or other type of specialty class.
+ */
+ fun isClass(): Boolean
+
+ /**
+ * Returns `true` if this [XTypeElement] represents a Kotlin data class
+ */
+ fun isDataClass(): Boolean
+
+ /**
+ * Returns `true` if this [XTypeElement] represents a Kotlin value class
+ */
+ fun isValueClass(): Boolean
+
+ /**
+ * Returns `true` if this [XTypeElement] represents a class with the Kotlin `expect` keyword
+ */
+ fun isExpect(): Boolean
+
+ /**
+ * Returns `true` if this [XTypeElement] represents a Kotlin annotation class or a Java
+ * annotation type.
+ */
+ fun isAnnotationClass(): Boolean
+
+ /**
+ * Returns `true` if this [XTypeElement] is a non-companion `object` in Kotlin
*/
fun isKotlinObject(): Boolean
/**
+ * Returns `true` if this [XTypeElement] is declared as a Kotlin `companion object`
+ */
+ fun isCompanionObject(): Boolean
+
+ /**
* All fields, including private supers.
* Room only ever reads fields this way.
*/
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacElement.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacElement.kt
index ba502a5..0a70f22 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacElement.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacElement.kt
@@ -86,4 +86,8 @@
MoreElements.getPackage(it.annotationType.asElement()).toString() == pkg
}
}
+
+ override val docComment: String? by lazy {
+ env.elementUtils.getDocComment(element)
+ }
}
\ No newline at end of file
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeElement.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeElement.kt
index acaffb7..1266ef0 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeElement.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeElement.kt
@@ -21,7 +21,6 @@
import androidx.room.compiler.processing.XHasModifiers
import androidx.room.compiler.processing.XMethodElement
import androidx.room.compiler.processing.XTypeElement
-import androidx.room.compiler.processing.javac.JavacTypeElement.JavacEnumTypeElement
import androidx.room.compiler.processing.javac.kotlin.KotlinMetadataElement
import com.google.auto.common.MoreElements
import com.google.auto.common.MoreTypes
@@ -58,8 +57,6 @@
element.enclosingType(env)
}
- override fun isInterface() = element.kind == ElementKind.INTERFACE
-
private val _allFieldsIncludingPrivateSupers by lazy {
element.getAllFieldsIncludingPrivateSupers(
env.elementUtils
@@ -77,6 +74,24 @@
}
override fun isKotlinObject() = kotlinMetadata?.isObject() == true
+ override fun isCompanionObject() = kotlinMetadata?.isCompanionObject() == true
+ override fun isDataClass() = kotlinMetadata?.isDataClass() == true
+ override fun isValueClass() = kotlinMetadata?.isValueClass() == true
+ override fun isFunctionalInterface() = kotlinMetadata?.isFunctionalInterface() == true
+ override fun isExpect() = kotlinMetadata?.isExpect() == true
+
+ override fun isAnnotationClass(): Boolean {
+ return kotlinMetadata?.isAnnotationClass()
+ ?: (element.kind == ElementKind.ANNOTATION_TYPE)
+ }
+
+ override fun isClass(): Boolean {
+ return kotlinMetadata?.isClass() ?: (element.kind == ElementKind.CLASS)
+ }
+
+ override fun isInterface(): Boolean {
+ return kotlinMetadata?.isInterface() ?: (element.kind == ElementKind.INTERFACE)
+ }
override fun findPrimaryConstructor(): JavacConstructorElement? {
val primarySignature = kotlinMetadata?.findPrimaryConstructorSignature() ?: return null
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt
index 2ae8d57..2b3fc32 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt
@@ -39,6 +39,7 @@
internal interface KmExecutable {
val parameters: List<KmValueParameter>
}
+
/**
* Represents the kotlin metadata of a function
*/
@@ -68,6 +69,7 @@
) {
val typeParameters
get() = type.typeArguments
+
fun isNullable() = Flag.Type.IS_NULLABLE(type.flags)
}
@@ -188,25 +190,42 @@
}
}
-internal fun KotlinClassMetadata.Class.isObject(): Boolean = ObjectReader().let {
- this@isObject.accept(it)
- it.isObject
+internal class KotlinMetadataClassFlags(val classMetadata: KotlinClassMetadata.Class) {
+
+ private val flags: Flags by lazy {
+ var theFlags: Flags = 0
+ classMetadata.accept(object : KmClassVisitor() {
+ override fun visit(flags: Flags, name: ClassName) {
+ theFlags = flags
+ super.visit(flags, name)
+ }
+ })
+ return@lazy theFlags
+ }
+
+ fun isObject(): Boolean = Flag.Class.IS_OBJECT(flags)
+
+ fun isCompanionObject(): Boolean = Flag.Class.IS_COMPANION_OBJECT(flags)
+
+ fun isAnnotationClass(): Boolean = Flag.Class.IS_ANNOTATION_CLASS(flags)
+
+ fun isInterface(): Boolean = Flag.Class.IS_INTERFACE(flags)
+
+ fun isClass(): Boolean = Flag.Class.IS_CLASS(flags)
+
+ fun isDataClass(): Boolean = Flag.Class.IS_DATA(flags)
+
+ fun isValueClass(): Boolean = Flag.Class.IS_INLINE(flags)
+
+ fun isFunctionalInterface(): Boolean = Flag.Class.IS_FUN(flags)
+
+ fun isExpect(): Boolean = Flag.Class.IS_EXPECT(flags)
}
internal fun KotlinClassMetadata.Class.readProperties(): List<KmProperty> =
mutableListOf<KmProperty>().apply { accept(PropertyReader(this)) }
/**
- * Reads whether the given class is a kotlin object
- */
-private class ObjectReader : KmClassVisitor() {
- var isObject: Boolean = false
- override fun visit(flags: Flags, name: ClassName) {
- isObject = Flag.Class.IS_OBJECT(flags)
- }
-}
-
-/**
* Reads the properties of a class declaration
*/
private class PropertyReader(
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinMetadataElement.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinMetadataElement.kt
index 963c20a..cf281c4 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinMetadataElement.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinMetadataElement.kt
@@ -45,6 +45,9 @@
private val functionList: List<KmFunction> by lazy { classMetadata.readFunctions() }
private val constructorList: List<KmConstructor> by lazy { classMetadata.readConstructors() }
private val propertyList: List<KmProperty> by lazy { classMetadata.readProperties() }
+ private val classFlags: KotlinMetadataClassFlags by lazy {
+ KotlinMetadataClassFlags(classMetadata)
+ }
private val ExecutableElement.descriptor: String
get() = descriptor()
@@ -53,7 +56,15 @@
it.isPrimary()
}?.descriptor
- fun isObject(): Boolean = classMetadata.isObject()
+ fun isObject(): Boolean = classFlags.isObject()
+ fun isCompanionObject(): Boolean = classFlags.isCompanionObject()
+ fun isAnnotationClass(): Boolean = classFlags.isAnnotationClass()
+ fun isClass(): Boolean = classFlags.isClass()
+ fun isInterface(): Boolean = classFlags.isInterface()
+ fun isDataClass(): Boolean = classFlags.isDataClass()
+ fun isValueClass(): Boolean = classFlags.isValueClass()
+ fun isFunctionalInterface(): Boolean = classFlags.isFunctionalInterface()
+ fun isExpect(): Boolean = classFlags.isExpect()
fun getFunctionMetadata(method: ExecutableElement): KmFunction? {
check(method.kind == ElementKind.METHOD) {
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspElement.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspElement.kt
index 82fef86..887ef7e 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspElement.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspElement.kt
@@ -61,4 +61,10 @@
KSFileAsOriginatingElement(it)
}
}
+
+ override val docComment: String? by lazy {
+ // TODO: Not yet implemented in KSP.
+ // https://github.com/google/ksp/issues/392
+ null
+ }
}
\ No newline at end of file
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspFileMemberContainer.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspFileMemberContainer.kt
index 9d91bb4..60df4da 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspFileMemberContainer.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspFileMemberContainer.kt
@@ -58,6 +58,12 @@
override val fallbackLocationText: String = ksFile.filePath
+ override val docComment: String? by lazy {
+ // TODO: Not yet implemented in KSP.
+ // https://github.com/google/ksp/issues/392
+ null
+ }
+
companion object {
private fun KSFile.findClassName(): String {
return annotations.firstOrNull {
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
index c7f17c6..404c5f5 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
@@ -40,6 +40,7 @@
import com.google.devtools.ksp.symbol.Modifier
import com.google.devtools.ksp.symbol.Origin
import com.squareup.javapoet.ClassName
+import javax.tools.Diagnostic
internal sealed class KspTypeElement(
env: KspProcessingEnv,
@@ -253,6 +254,40 @@
return declaration.classKind == ClassKind.OBJECT
}
+ override fun isCompanionObject(): Boolean {
+ return declaration.isCompanionObject
+ }
+
+ override fun isAnnotationClass(): Boolean {
+ return declaration.classKind == ClassKind.ANNOTATION_CLASS
+ }
+
+ override fun isClass(): Boolean {
+ return declaration.classKind == ClassKind.CLASS
+ }
+
+ override fun isDataClass(): Boolean {
+ return Modifier.DATA in declaration.modifiers
+ }
+
+ override fun isValueClass(): Boolean {
+ return Modifier.INLINE in declaration.modifiers
+ }
+
+ override fun isFunctionalInterface(): Boolean {
+ // TODO: Update this once KSP supports it
+ // https://github.com/google/ksp/issues/393
+ env.messager.printMessage(
+ Diagnostic.Kind.WARNING,
+ "XProcessing does not yet support checking for functional interfaces in KSP."
+ )
+ return false
+ }
+
+ override fun isExpect(): Boolean {
+ return Modifier.EXPECT in declaration.modifiers
+ }
+
override fun isFinal(): Boolean {
// workaround for https://github.com/android/kotlin/issues/128
return !isInterface() && !declaration.isOpen()
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticContinuationParameterElement.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticContinuationParameterElement.kt
index aad60a8..cab0ab2 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticContinuationParameterElement.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticContinuationParameterElement.kt
@@ -82,6 +82,9 @@
override val fallbackLocationText: String
get() = "return type of ${containing.fallbackLocationText}"
+ // Not applicable
+ override val docComment: String? get() = null
+
override fun asMemberOf(other: XType): XType {
check(other is KspType)
val continuation = env.resolver.requireContinuationClass()
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt
index 6789fe3..9921270 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt
@@ -80,6 +80,12 @@
)
}
+ override val docComment: String? by lazy {
+ // Not yet implemented in KSP.
+ // https://github.com/google/ksp/issues/392
+ null
+ }
+
final override fun asMemberOf(other: XType): XMethodType {
return KspSyntheticPropertyMethodType.create(
element = this,
@@ -227,6 +233,12 @@
return origin.field.asMemberOf(other)
}
+ override val docComment: String? by lazy {
+ // Not yet implemented in KSP.
+ // https://github.com/google/ksp/issues/392
+ null
+ }
+
override fun kindName(): String {
return "method parameter"
}
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
index faded70..b8727eb 100644
--- a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
@@ -202,6 +202,12 @@
inner class InnerKotlinClass
class NestedKotlinClass
}
+ annotation class KotlinAnnotation
+ data class DataClass(val foo: Int)
+ inline class InlineClass(val foo: Int)
+ fun interface FunInterface {
+ fun foo()
+ }
""".trimIndent()
)
val javaSrc = Source.java(
@@ -213,8 +219,15 @@
}
""".trimIndent()
)
+ val javaAnnotationSrc = Source.java(
+ "JavaAnnotation",
+ """
+ public @interface JavaAnnotation {
+ }
+ """.trimIndent()
+ )
runProcessorTest(
- sources = listOf(kotlinSrc, javaSrc)
+ sources = listOf(kotlinSrc, javaSrc, javaAnnotationSrc)
) { invocation ->
fun getModifiers(element: XTypeElement): Set<String> {
val result = mutableSetOf<String>()
@@ -224,8 +237,15 @@
if (element.isProtected()) result.add("protected")
if (element.isPublic()) result.add("public")
if (element.isKotlinObject()) result.add("object")
+ if (element.isCompanionObject()) result.add("companion")
+ if (element.isFunctionalInterface()) result.add("fun")
+ if (element.isClass()) result.add("class")
+ if (element.isDataClass()) result.add("data")
+ if (element.isValueClass()) result.add("value")
+ if (element.isExpect()) result.add("expect")
if (element.isInterface()) result.add("interface")
if (element.isStatic()) result.add("static")
+ if (element.isAnnotationClass()) result.add("annotation")
return result
}
@@ -235,32 +255,54 @@
)
assertThat(getModifiers("OpenClass"))
- .containsExactly("public")
+ .containsExactly("public", "class")
assertThat(getModifiers("AbstractClass"))
- .containsExactly("abstract", "public")
+ .containsExactly("abstract", "public", "class")
assertThat(getModifiers("MyObject"))
.containsExactly("final", "public", "object")
assertThat(getModifiers("MyInterface"))
.containsExactly("abstract", "interface", "public")
assertThat(getModifiers("Final"))
- .containsExactly("final", "public")
+ .containsExactly("final", "public", "class")
assertThat(getModifiers("PrivateClass"))
.containsExactlyElementsIn(
if (invocation.isKsp) {
- listOf("private", "final")
+ listOf("private", "final", "class")
} else {
// java does not support top level private classes.
- listOf("final")
+ listOf("final", "class")
}
)
assertThat(getModifiers("OuterKotlinClass.InnerKotlinClass"))
- .containsExactly("final", "public")
+ .containsExactly("final", "public", "class")
assertThat(getModifiers("OuterKotlinClass.NestedKotlinClass"))
- .containsExactly("final", "public", "static")
+ .containsExactly("final", "public", "static", "class")
assertThat(getModifiers("OuterJavaClass.InnerJavaClass"))
- .containsExactly("public")
+ .containsExactly("public", "class")
assertThat(getModifiers("OuterJavaClass.NestedJavaClass"))
- .containsExactly("public", "static")
+ .containsExactly("public", "static", "class")
+ assertThat(getModifiers("JavaAnnotation"))
+ .containsExactly("abstract", "public", "annotation")
+ assertThat(getModifiers("KotlinAnnotation")).apply {
+ // KSP vs KAPT metadata have a difference in final vs abstract modifiers
+ // for annotation types.
+ if (invocation.isKsp) {
+ containsExactly("final", "public", "annotation")
+ } else {
+ containsExactly("abstract", "public", "annotation")
+ }
+ }
+ assertThat(getModifiers("DataClass"))
+ .containsExactly("public", "final", "class", "data")
+ assertThat(getModifiers("InlineClass"))
+ .containsExactly("public", "final", "class", "value")
+
+ if (!invocation.isKsp) {
+ // TODO: Enable for ksp too once it supports fun interfaces
+ // https://github.com/google/ksp/issues/393
+ assertThat(getModifiers("FunInterface"))
+ .containsExactly("public", "abstract", "interface", "fun")
+ }
}
}
diff --git a/room/compiler/build.gradle b/room/compiler/build.gradle
index 64b72f3..84fc56d 100644
--- a/room/compiler/build.gradle
+++ b/room/compiler/build.gradle
@@ -36,13 +36,6 @@
main.java.srcDirs += antlrOut
}
-// Temporary hack to stop AS to adding two guavas into test's classpath
-configurations.all {
- resolutionStrategy {
- force GUAVA
- }
-}
-
configurations {
/**
* shadowed is used for dependencies which we jarjar into the library jar instead of adding it
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatNightModeAlertDialog.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatNightModeAlertDialog.java
index ddd9135..78117fec8 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatNightModeAlertDialog.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatNightModeAlertDialog.java
@@ -68,7 +68,7 @@
private AlertDialog createAlertDialog() {
AlertDialog.Builder b = new AlertDialog.Builder(this,
- R.style.Theme_AppCompat_DayNight_Dialog_Alert);
+ androidx.appcompat.R.style.Theme_AppCompat_DayNight_Dialog_Alert);
b.setTitle(R.string.dialog_title);
b.setMessage(R.string.dialog_content);
return b.create();
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatNightModeDialog.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatNightModeDialog.java
index d4d8ff1..4a62809 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatNightModeDialog.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatNightModeDialog.java
@@ -37,7 +37,8 @@
}
public void setModeNightFollowSystem(View view) {
- AppCompatDialog dialog = new AppCompatDialog(this, R.style.Theme_AppCompat_DayNight_Dialog);
+ AppCompatDialog dialog = new AppCompatDialog(this,
+ androidx.appcompat.R.style.Theme_AppCompat_DayNight_Dialog);
dialog.getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
dialog.setTitle(R.string.dialog_title);
dialog.setContentView(R.layout.dialog_content);
@@ -45,7 +46,8 @@
}
public void setModeNightNo(View view) {
- AppCompatDialog dialog = new AppCompatDialog(this, R.style.Theme_AppCompat_DayNight_Dialog);
+ AppCompatDialog dialog = new AppCompatDialog(this,
+ androidx.appcompat.R.style.Theme_AppCompat_DayNight_Dialog);
dialog.getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_NO);
dialog.setTitle(R.string.dialog_title);
dialog.setContentView(R.layout.dialog_content);
@@ -53,7 +55,8 @@
}
public void setModeNightYes(View view) {
- AppCompatDialog dialog = new AppCompatDialog(this, R.style.Theme_AppCompat_DayNight_Dialog);
+ AppCompatDialog dialog = new AppCompatDialog(this,
+ androidx.appcompat.R.style.Theme_AppCompat_DayNight_Dialog);
dialog.getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES);
dialog.setTitle(R.string.dialog_title);
dialog.setContentView(R.layout.dialog_content);
@@ -61,7 +64,8 @@
}
public void setModeNightAutoTime(View view) {
- AppCompatDialog dialog = new AppCompatDialog(this, R.style.Theme_AppCompat_DayNight_Dialog);
+ AppCompatDialog dialog = new AppCompatDialog(this,
+ androidx.appcompat.R.style.Theme_AppCompat_DayNight_Dialog);
dialog.getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_TIME);
dialog.setTitle(R.string.dialog_title);
dialog.setContentView(R.layout.dialog_content);
@@ -69,7 +73,8 @@
}
public void setModeNightAutoBattery(View view) {
- AppCompatDialog dialog = new AppCompatDialog(this, R.style.Theme_AppCompat_DayNight_Dialog);
+ AppCompatDialog dialog = new AppCompatDialog(this,
+ androidx.appcompat.R.style.Theme_AppCompat_DayNight_Dialog);
dialog.getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
dialog.setTitle(R.string.dialog_title);
dialog.setContentView(R.layout.dialog_content);
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatWidgetsSpinners.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatWidgetsSpinners.java
index cbd01a0..f05a835 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatWidgetsSpinners.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatWidgetsSpinners.java
@@ -37,11 +37,13 @@
// Fetch the Spinners and set an adapter
Spinner spinner = findViewById(R.id.widgets_spinner);
spinner.setAdapter(new ArrayAdapter<>(this,
- R.layout.support_simple_spinner_dropdown_item, Cheeses.sCheeseStrings));
+ androidx.appcompat.R.layout.support_simple_spinner_dropdown_item,
+ Cheeses.sCheeseStrings));
spinner = findViewById(R.id.widgets_spinner_underlined);
spinner.setAdapter(new ArrayAdapter<>(this,
- R.layout.support_simple_spinner_dropdown_item, Cheeses.sCheeseStrings));
+ androidx.appcompat.R.layout.support_simple_spinner_dropdown_item,
+ Cheeses.sCheeseStrings));
}
}
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/view/CardViewActivity.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/view/CardViewActivity.java
index 90a68ed..b3be31a 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/view/CardViewActivity.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/view/CardViewActivity.java
@@ -184,7 +184,7 @@
case R.id.selector:
return R.color.card_selector;
default:
- return R.color.cardview_light_background;
+ return androidx.cardview.R.color.cardview_light_background;
}
}
}
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/AnimatedRecyclerView.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/AnimatedRecyclerView.java
index 3c857c5..91bd52a 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/AnimatedRecyclerView.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/AnimatedRecyclerView.java
@@ -671,7 +671,7 @@
public MyAdapter(List<String> data) {
TypedValue val = new TypedValue();
AnimatedRecyclerView.this.getTheme().resolveAttribute(
- R.attr.selectableItemBackground, val, true);
+ androidx.appcompat.R.attr.selectableItemBackground, val, true);
mBackground = val.resourceId;
mData = data;
for (String itemText : mData) {
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/ListPopupWindowActivity.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/ListPopupWindowActivity.java
index 37d3f0e..d73d7db 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/ListPopupWindowActivity.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/ListPopupWindowActivity.java
@@ -98,11 +98,12 @@
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(parent.getContext()).inflate(
- R.layout.abc_popup_menu_item_layout, parent, false);
+ androidx.appcompat.R.layout.abc_popup_menu_item_layout,
+ parent, false);
ViewHolder viewHolder = new ViewHolder();
viewHolder.title = (TextView) convertView.findViewById(R.id.title);
- viewHolder.shortcut =
- (TextView) convertView.findViewById(R.id.shortcut);
+ viewHolder.shortcut = (TextView) convertView.findViewById(
+ androidx.appcompat.R.id.shortcut);
convertView.setTag(viewHolder);
}
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/RemoveLargeItemsDemo.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/RemoveLargeItemsDemo.java
index e803693..2e0b4f7 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/RemoveLargeItemsDemo.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/RemoveLargeItemsDemo.java
@@ -160,7 +160,7 @@
MyAdapter(List<Item> data) {
TypedValue val = new TypedValue();
RemoveLargeItemsDemo.this.getTheme().resolveAttribute(
- R.attr.selectableItemBackground, val, true);
+ androidx.appcompat.R.attr.selectableItemBackground, val, true);
mBackground = val.resourceId;
mData = data;
}
diff --git a/samples/SupportEmojiDemos/src/main/java/com/example/android/support/text/emoji/CustomTextView.java b/samples/SupportEmojiDemos/src/main/java/com/example/android/support/text/emoji/CustomTextView.java
index cd99ee4..9926c9e 100755
--- a/samples/SupportEmojiDemos/src/main/java/com/example/android/support/text/emoji/CustomTextView.java
+++ b/samples/SupportEmojiDemos/src/main/java/com/example/android/support/text/emoji/CustomTextView.java
@@ -22,7 +22,7 @@
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatTextView;
-import androidx.emoji2.viewshelper.EmojiTextViewHelper;
+import androidx.emoji2.viewsintegration.EmojiTextViewHelper;
/**
diff --git a/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/ErrorFragment.java b/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/ErrorFragment.java
index 32dea2b..332b738 100644
--- a/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/ErrorFragment.java
+++ b/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/ErrorFragment.java
@@ -32,7 +32,7 @@
setTitle("Leanback Sample App");
final Context context = getActivity();
setImageDrawable(ResourcesCompat.getDrawable(context.getResources(),
- R.drawable.lb_ic_sad_cloud, context.getTheme()));
+ androidx.leanback.R.drawable.lb_ic_sad_cloud, context.getTheme()));
setMessage("An error occurred.");
setDefaultBackground(TRANSLUCENT);
diff --git a/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/ErrorSupportFragment.java b/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/ErrorSupportFragment.java
index cfe3bcf..5eb1199 100644
--- a/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/ErrorSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/ErrorSupportFragment.java
@@ -35,7 +35,7 @@
setTitle("Leanback Sample App");
final Context context = getActivity();
setImageDrawable(ResourcesCompat.getDrawable(context.getResources(),
- R.drawable.lb_ic_sad_cloud, context.getTheme()));
+ androidx.leanback.R.drawable.lb_ic_sad_cloud, context.getTheme()));
setMessage("An error occurred.");
setDefaultBackground(TRANSLUCENT);
diff --git a/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/GuidedStepActivity.java b/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/GuidedStepActivity.java
index ee464d9..77a90b5 100644
--- a/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/GuidedStepActivity.java
+++ b/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/GuidedStepActivity.java
@@ -75,7 +75,8 @@
super.onCreate(savedInstanceState);
setContentView(R.layout.guided_step_activity);
if (savedInstanceState == null) {
- GuidedStepFragment.addAsRoot(this, new FirstStepFragment(), R.id.lb_guidedstep_host);
+ GuidedStepFragment.addAsRoot(this, new FirstStepFragment(),
+ R.id.lb_guidedstep_host);
}
}
@@ -128,7 +129,7 @@
.title(title)
.description(desc)
.editable(true)
- .icon(R.drawable.lb_ic_search_mic)
+ .icon(androidx.leanback.R.drawable.lb_ic_search_mic)
.build());
return action;
}
diff --git a/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/GuidedStepSupportActivity.java b/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/GuidedStepSupportActivity.java
index f0c9e63..f4d7143 100644
--- a/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/GuidedStepSupportActivity.java
+++ b/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/GuidedStepSupportActivity.java
@@ -131,7 +131,7 @@
.title(title)
.description(desc)
.editable(true)
- .icon(R.drawable.lb_ic_search_mic)
+ .icon(androidx.leanback.R.drawable.lb_ic_search_mic)
.build());
return action;
}
diff --git a/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/PlaybackFragment.java b/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/PlaybackFragment.java
index b2e0284..c482916 100644
--- a/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/PlaybackFragment.java
+++ b/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/PlaybackFragment.java
@@ -85,7 +85,7 @@
@Override
public void onActionClicked(Action action) {
- if (action.getId() == R.id.lb_control_picture_in_picture) {
+ if (action.getId() == androidx.leanback.R.id.lb_control_picture_in_picture) {
if (Build.VERSION.SDK_INT >= 24) {
getActivity().enterPictureInPictureMode();
}
diff --git a/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/PlaybackSupportFragment.java b/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/PlaybackSupportFragment.java
index 3574550..65dbf34 100644
--- a/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/PlaybackSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/PlaybackSupportFragment.java
@@ -88,7 +88,7 @@
@Override
public void onActionClicked(Action action) {
- if (action.getId() == R.id.lb_control_picture_in_picture) {
+ if (action.getId() == androidx.leanback.R.id.lb_control_picture_in_picture) {
if (Build.VERSION.SDK_INT >= 24) {
getActivity().enterPictureInPictureMode();
}
diff --git a/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/PlaybackTransportControlFragment.java b/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/PlaybackTransportControlFragment.java
index 4a7cdc1..e78dc5b 100644
--- a/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/PlaybackTransportControlFragment.java
+++ b/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/PlaybackTransportControlFragment.java
@@ -71,7 +71,7 @@
mGlue = new PlaybackTransportControlGlueSample(context, new PlayerAdapter()) {
@Override
public void onActionClicked(Action action) {
- if (action.getId() == R.id.lb_control_picture_in_picture) {
+ if (action.getId() == androidx.leanback.R.id.lb_control_picture_in_picture) {
if (Build.VERSION.SDK_INT >= 24) {
getActivity().enterPictureInPictureMode();
}
diff --git a/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/PlaybackTransportControlSupportFragment.java b/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/PlaybackTransportControlSupportFragment.java
index 0e53de0..70d46f8 100644
--- a/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/PlaybackTransportControlSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/PlaybackTransportControlSupportFragment.java
@@ -74,7 +74,7 @@
mGlue = new PlaybackTransportControlGlueSample(context, new PlayerAdapter()) {
@Override
public void onActionClicked(Action action) {
- if (action.getId() == R.id.lb_control_picture_in_picture) {
+ if (action.getId() == androidx.leanback.R.id.lb_control_picture_in_picture) {
if (Build.VERSION.SDK_INT >= 24) {
getActivity().enterPictureInPictureMode();
}
diff --git a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java
index 37b2fde..285633a 100644
--- a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java
+++ b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java
@@ -179,7 +179,7 @@
@Override
public boolean onCreateOptionsMenu(Menu menu) {
mTypeMenu = menu.addSubMenu("Type");
- mTypeMenu.setIcon(R.drawable.ic_large);
+ mTypeMenu.setIcon(androidx.slice.test.R.drawable.ic_large);
mTypeMenu.getItem().setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
mTypeMenu.add("Shortcut");
mTypeMenu.add("Small");
@@ -201,17 +201,17 @@
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getTitle().toString()) {
case "Shortcut":
- mTypeMenu.setIcon(R.drawable.ic_shortcut);
+ mTypeMenu.setIcon(androidx.slice.test.R.drawable.ic_shortcut);
mSelectedMode = SliceView.MODE_SHORTCUT;
updateSliceModes();
return true;
case "Small":
- mTypeMenu.setIcon(R.drawable.ic_small);
+ mTypeMenu.setIcon(androidx.slice.test.R.drawable.ic_small);
mSelectedMode = SliceView.MODE_SMALL;
updateSliceModes();
return true;
case "Large":
- mTypeMenu.setIcon(R.drawable.ic_large);
+ mTypeMenu.setIcon(androidx.slice.test.R.drawable.ic_large);
mSelectedMode = SliceView.MODE_LARGE;
updateSliceModes();
return true;
diff --git a/slices/core/src/main/res/values-af/strings.xml b/slices/core/src/main/res/values-af/strings.xml
index c6a4763..cea048b 100644
--- a/slices/core/src/main/res/values-af/strings.xml
+++ b/slices/core/src/main/res/values-af/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Laat <xliff:g id="APP_0">%1$s</xliff:g> toe om <xliff:g id="APP_2">%2$s</xliff:g>-skyfies te wys?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Dit kan inligting in <xliff:g id="APP">%1$s</xliff:g> lees"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Dit kan handelinge binne <xliff:g id="APP">%1$s</xliff:g> uitvoer"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Laat toe"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Weier"</string>
</resources>
diff --git a/slices/core/src/main/res/values-am/strings.xml b/slices/core/src/main/res/values-am/strings.xml
index 3fc492a..96be387 100644
--- a/slices/core/src/main/res/values-am/strings.xml
+++ b/slices/core/src/main/res/values-am/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> የ<xliff:g id="APP_2">%2$s</xliff:g> ቁራጮችን እንዲያሳይ ይፈቀድለት?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ከ<xliff:g id="APP">%1$s</xliff:g> የመጣ መረጃን ማንበብ ይችላል"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- በ<xliff:g id="APP">%1$s</xliff:g> ውስጥ እርምጃዎችን መውሰድ ይችላል"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"ፍቀድ"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"ከልክል"</string>
</resources>
diff --git a/slices/core/src/main/res/values-ar/strings.xml b/slices/core/src/main/res/values-ar/strings.xml
index 2d76a8d..c195f16 100644
--- a/slices/core/src/main/res/values-ar/strings.xml
+++ b/slices/core/src/main/res/values-ar/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"هل تريد السماح لتطبيق <xliff:g id="APP_0">%1$s</xliff:g> بعرض شرائح <xliff:g id="APP_2">%2$s</xliff:g>؟"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- إمكانية قراءة المعلومات من <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- إمكانية اتخاذ إجراءات داخل <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"سماح"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"رفض"</string>
</resources>
diff --git a/slices/core/src/main/res/values-as/strings.xml b/slices/core/src/main/res/values-as/strings.xml
index ea2a877..e8c88e0 100644
--- a/slices/core/src/main/res/values-as/strings.xml
+++ b/slices/core/src/main/res/values-as/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g>ক <xliff:g id="APP_2">%2$s</xliff:g>ৰ অংশ দেখুওৱাবলৈ অনুমতি দিবনে?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ই <xliff:g id="APP">%1$s</xliff:g>ৰ তথ্য পঢ়িব পাৰে"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ই <xliff:g id="APP">%1$s</xliff:g>ৰ ভিতৰত কাৰ্য কৰিব পাৰে"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"অনুমতি দিয়ক"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"অস্বীকাৰ কৰক"</string>
</resources>
diff --git a/slices/core/src/main/res/values-az/strings.xml b/slices/core/src/main/res/values-az/strings.xml
index 2f1bce4..bd71cb1 100644
--- a/slices/core/src/main/res/values-az/strings.xml
+++ b/slices/core/src/main/res/values-az/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> tətbiqinə <xliff:g id="APP_2">%2$s</xliff:g> hissələrini göstərmək üçün icazə verilsin?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- <xliff:g id="APP">%1$s</xliff:g> tətbiqindən məlumat oxuya bilər"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- <xliff:g id="APP">%1$s</xliff:g> daxilində əməliyyatlar edə bilər"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"İcazə verin"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Rədd edin"</string>
</resources>
diff --git a/slices/core/src/main/res/values-b+sr+Latn/strings.xml b/slices/core/src/main/res/values-b+sr+Latn/strings.xml
index 3e20b9e..476441d 100644
--- a/slices/core/src/main/res/values-b+sr+Latn/strings.xml
+++ b/slices/core/src/main/res/values-b+sr+Latn/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Želite li da dozvolite aplikaciji <xliff:g id="APP_0">%1$s</xliff:g> da prikazuje isečke iz aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Može da čita podatke iz aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Može da obavlja radnje u aplikaciji <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Dozvoli"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Odbij"</string>
</resources>
diff --git a/slices/core/src/main/res/values-be/strings.xml b/slices/core/src/main/res/values-be/strings.xml
index 84cd4a22..85988a8 100644
--- a/slices/core/src/main/res/values-be/strings.xml
+++ b/slices/core/src/main/res/values-be/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Дазволіць праграме <xliff:g id="APP_0">%1$s</xliff:g> паказваць фрагменты праграмы <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Можа счытваць інфармацыю з праграмы <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Можа выконваць дзеянні ў праграме <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Дазволіць"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Адмовіць"</string>
</resources>
diff --git a/slices/core/src/main/res/values-bg/strings.xml b/slices/core/src/main/res/values-bg/strings.xml
index dcd2606..1ff6667 100644
--- a/slices/core/src/main/res/values-bg/strings.xml
+++ b/slices/core/src/main/res/values-bg/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Ще разрешите ли на <xliff:g id="APP_0">%1$s</xliff:g> да показва части от <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Може да чете информация от <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Може да предприема действия в/ъв <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Разрешаване"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Отказ"</string>
</resources>
diff --git a/slices/core/src/main/res/values-bn/strings.xml b/slices/core/src/main/res/values-bn/strings.xml
index 4b46f9b..c9556dd 100644
--- a/slices/core/src/main/res/values-bn/strings.xml
+++ b/slices/core/src/main/res/values-bn/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> অ্যাপটিকে <xliff:g id="APP_2">%2$s</xliff:g> এর অংশ দেখানোর অনুমতি দেবেন?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- এটি <xliff:g id="APP">%1$s</xliff:g> এর তথ্য অ্যাক্সেস করতে পারবে"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- এটি <xliff:g id="APP">%1$s</xliff:g> এর মধ্যে কাজ করতে পারবে"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"অনুমতি দিন"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"খারিজ করুন"</string>
</resources>
diff --git a/slices/core/src/main/res/values-bs/strings.xml b/slices/core/src/main/res/values-bs/strings.xml
index b203a79..ed3104d5 100644
--- a/slices/core/src/main/res/values-bs/strings.xml
+++ b/slices/core/src/main/res/values-bs/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Dozvoliti aplikaciji <xliff:g id="APP_0">%1$s</xliff:g> prikazivanje isječaka aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Može čitati informacije iz aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Može poduzeti radnje u aplikaciji <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Dozvoli"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Odbij"</string>
</resources>
diff --git a/slices/core/src/main/res/values-ca/strings.xml b/slices/core/src/main/res/values-ca/strings.xml
index ac93488..5bff344 100644
--- a/slices/core/src/main/res/values-ca/strings.xml
+++ b/slices/core/src/main/res/values-ca/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Vols permetre que <xliff:g id="APP_0">%1$s</xliff:g> mostri porcions de l\'aplicació <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Pot llegir informació de l\'aplicació <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Pot dur a terme accions dins de l\'aplicació <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Permet"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Denega"</string>
</resources>
diff --git a/slices/core/src/main/res/values-cs/strings.xml b/slices/core/src/main/res/values-cs/strings.xml
index da1053b..432ed94 100644
--- a/slices/core/src/main/res/values-cs/strings.xml
+++ b/slices/core/src/main/res/values-cs/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Povolit aplikaci <xliff:g id="APP_0">%1$s</xliff:g> zobrazovat ukázky z aplikace <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Může číst informace z aplikace <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Může provádět akce v aplikaci <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Povolit"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Zamítnout"</string>
</resources>
diff --git a/slices/core/src/main/res/values-da/strings.xml b/slices/core/src/main/res/values-da/strings.xml
index 67a7ed0..eb148eb 100644
--- a/slices/core/src/main/res/values-da/strings.xml
+++ b/slices/core/src/main/res/values-da/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Vil du give <xliff:g id="APP_0">%1$s</xliff:g> tilladelse til at vise eksempler fra <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Den kan læse oplysninger fra <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Den kan foretage handlinger i <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Tillad"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Afvis"</string>
</resources>
diff --git a/slices/core/src/main/res/values-de/strings.xml b/slices/core/src/main/res/values-de/strings.xml
index 419fa20..b14bdb3 100644
--- a/slices/core/src/main/res/values-de/strings.xml
+++ b/slices/core/src/main/res/values-de/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> erlauben, Teile von <xliff:g id="APP_2">%2$s</xliff:g> anzuzeigen?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Darf Informationen aus <xliff:g id="APP">%1$s</xliff:g> lesen"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Darf Aktionen in <xliff:g id="APP">%1$s</xliff:g> ausführen"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Zulassen"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Ablehnen"</string>
</resources>
diff --git a/slices/core/src/main/res/values-el/strings.xml b/slices/core/src/main/res/values-el/strings.xml
index 898d2ea..8ae97bf 100644
--- a/slices/core/src/main/res/values-el/strings.xml
+++ b/slices/core/src/main/res/values-el/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Να επιτρέπεται στην εφαρμογή <xliff:g id="APP_0">%1$s</xliff:g> να εμφανίζει τμήματα της εφαρμογής <xliff:g id="APP_2">%2$s</xliff:g>;"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Μπορεί να διαβάζει πληροφορίες από την εφαρμογή <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Μπορεί να εκτελεί ενέργειες εντός της εφαρμογής <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Να επιτρέπεται"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Να μην επιτρέπεται"</string>
</resources>
diff --git a/slices/core/src/main/res/values-en-rAU/strings.xml b/slices/core/src/main/res/values-en-rAU/strings.xml
index b4c1f11..753ea3e 100644
--- a/slices/core/src/main/res/values-en-rAU/strings.xml
+++ b/slices/core/src/main/res/values-en-rAU/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Allow <xliff:g id="APP_0">%1$s</xliff:g> to show <xliff:g id="APP_2">%2$s</xliff:g> slices?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– It can read information from <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– It can take actions inside <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Allow"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Deny"</string>
</resources>
diff --git a/slices/core/src/main/res/values-en-rCA/strings.xml b/slices/core/src/main/res/values-en-rCA/strings.xml
index b4c1f11..753ea3e 100644
--- a/slices/core/src/main/res/values-en-rCA/strings.xml
+++ b/slices/core/src/main/res/values-en-rCA/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Allow <xliff:g id="APP_0">%1$s</xliff:g> to show <xliff:g id="APP_2">%2$s</xliff:g> slices?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– It can read information from <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– It can take actions inside <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Allow"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Deny"</string>
</resources>
diff --git a/slices/core/src/main/res/values-en-rGB/strings.xml b/slices/core/src/main/res/values-en-rGB/strings.xml
index b4c1f11..753ea3e 100644
--- a/slices/core/src/main/res/values-en-rGB/strings.xml
+++ b/slices/core/src/main/res/values-en-rGB/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Allow <xliff:g id="APP_0">%1$s</xliff:g> to show <xliff:g id="APP_2">%2$s</xliff:g> slices?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– It can read information from <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– It can take actions inside <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Allow"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Deny"</string>
</resources>
diff --git a/slices/core/src/main/res/values-en-rIN/strings.xml b/slices/core/src/main/res/values-en-rIN/strings.xml
index b4c1f11..753ea3e 100644
--- a/slices/core/src/main/res/values-en-rIN/strings.xml
+++ b/slices/core/src/main/res/values-en-rIN/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Allow <xliff:g id="APP_0">%1$s</xliff:g> to show <xliff:g id="APP_2">%2$s</xliff:g> slices?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– It can read information from <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– It can take actions inside <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Allow"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Deny"</string>
</resources>
diff --git a/slices/core/src/main/res/values-en-rXC/strings.xml b/slices/core/src/main/res/values-en-rXC/strings.xml
index efb1d5f..22c86bc 100644
--- a/slices/core/src/main/res/values-en-rXC/strings.xml
+++ b/slices/core/src/main/res/values-en-rXC/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Allow <xliff:g id="APP_0">%1$s</xliff:g> to show <xliff:g id="APP_2">%2$s</xliff:g> slices?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- It can read information from <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- It can take actions inside <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Allow"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Deny"</string>
</resources>
diff --git a/slices/core/src/main/res/values-es-rUS/strings.xml b/slices/core/src/main/res/values-es-rUS/strings.xml
index 31746f0..d004921 100644
--- a/slices/core/src/main/res/values-es-rUS/strings.xml
+++ b/slices/core/src/main/res/values-es-rUS/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"¿Permitir que <xliff:g id="APP_0">%1$s</xliff:g> muestre fragmentos de <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Puede leer información de <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Puede realizar acciones en <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Permitir"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Rechazar"</string>
</resources>
diff --git a/slices/core/src/main/res/values-es/strings.xml b/slices/core/src/main/res/values-es/strings.xml
index 3a65289..cdd8514 100644
--- a/slices/core/src/main/res/values-es/strings.xml
+++ b/slices/core/src/main/res/values-es/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"¿Permitir que <xliff:g id="APP_0">%1$s</xliff:g> muestre fragmentos de <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Puede leer información de <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Puede realizar acciones en <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Permitir"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Denegar"</string>
</resources>
diff --git a/slices/core/src/main/res/values-et/strings.xml b/slices/core/src/main/res/values-et/strings.xml
index 5462dd7..7d92095 100644
--- a/slices/core/src/main/res/values-et/strings.xml
+++ b/slices/core/src/main/res/values-et/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Kas lubada rakendusel <xliff:g id="APP_0">%1$s</xliff:g> näidata rakenduse <xliff:g id="APP_2">%2$s</xliff:g> lõike?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- See saab lugeda teavet rakendusest <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- See saab rakenduses <xliff:g id="APP">%1$s</xliff:g> toiminguid teha"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Lubamine"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Keelamine"</string>
</resources>
diff --git a/slices/core/src/main/res/values-eu/strings.xml b/slices/core/src/main/res/values-eu/strings.xml
index 8776fec..bea035d 100644
--- a/slices/core/src/main/res/values-eu/strings.xml
+++ b/slices/core/src/main/res/values-eu/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_2">%2$s</xliff:g> aplikazioaren zatiak erakusteko baimena eman nahi diozu <xliff:g id="APP_0">%1$s</xliff:g> aplikazioari?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- <xliff:g id="APP">%1$s</xliff:g> aplikazioaren informazioa irakur dezake."</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- <xliff:g id="APP">%1$s</xliff:g> aplikazioan ekintzak gauza ditzake."</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Baimendu"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Ukatu"</string>
</resources>
diff --git a/slices/core/src/main/res/values-fa/strings.xml b/slices/core/src/main/res/values-fa/strings.xml
index d5e0416..2abd384 100644
--- a/slices/core/src/main/res/values-fa/strings.xml
+++ b/slices/core/src/main/res/values-fa/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"به <xliff:g id="APP_0">%1$s</xliff:g> اجازه داده شود تکههای <xliff:g id="APP_2">%2$s</xliff:g> را نشان دهد؟"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- میتواند اطلاعات <xliff:g id="APP">%1$s</xliff:g> را بخواند"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- میتواند در <xliff:g id="APP">%1$s</xliff:g> اقدام انجام دهد"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"مجاز بودن"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"مجاز نبودن"</string>
</resources>
diff --git a/slices/core/src/main/res/values-fi/strings.xml b/slices/core/src/main/res/values-fi/strings.xml
index d682f1a..b826e98 100644
--- a/slices/core/src/main/res/values-fi/strings.xml
+++ b/slices/core/src/main/res/values-fi/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Saako <xliff:g id="APP_0">%1$s</xliff:g> näyttää osia sovelluksesta <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Se voi lukea tietoja sovelluksesta <xliff:g id="APP">%1$s</xliff:g>."</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Se voi suorittaa toimintoja sovelluksessa <xliff:g id="APP">%1$s</xliff:g>."</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Salli"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Estä"</string>
</resources>
diff --git a/slices/core/src/main/res/values-fr-rCA/strings.xml b/slices/core/src/main/res/values-fr-rCA/strings.xml
index a0e55d3..a5d3fd0 100644
--- a/slices/core/src/main/res/values-fr-rCA/strings.xml
+++ b/slices/core/src/main/res/values-fr-rCA/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Autoriser <xliff:g id="APP_0">%1$s</xliff:g> à afficher <xliff:g id="APP_2">%2$s</xliff:g> tranches?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Il peut lire de l\'information de <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Il peut effectuer des actions dans <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Autoriser"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Refuser"</string>
</resources>
diff --git a/slices/core/src/main/res/values-fr/strings.xml b/slices/core/src/main/res/values-fr/strings.xml
index 65f06bc..724da28 100644
--- a/slices/core/src/main/res/values-fr/strings.xml
+++ b/slices/core/src/main/res/values-fr/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Autoriser <xliff:g id="APP_0">%1$s</xliff:g> à afficher des éléments de <xliff:g id="APP_2">%2$s</xliff:g> ?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Accès aux informations de <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Capacité d\'action dans <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Autoriser"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Refuser"</string>
</resources>
diff --git a/slices/core/src/main/res/values-gl/strings.xml b/slices/core/src/main/res/values-gl/strings.xml
index 50befe5..5ef1215 100644
--- a/slices/core/src/main/res/values-gl/strings.xml
+++ b/slices/core/src/main/res/values-gl/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Queres permitir que <xliff:g id="APP_0">%1$s</xliff:g> mostre fragmentos de aplicación de <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Pode ler información da aplicación <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Pode levar a cabo accións dentro da aplicación <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Permitir"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Denegar"</string>
</resources>
diff --git a/slices/core/src/main/res/values-gu/strings.xml b/slices/core/src/main/res/values-gu/strings.xml
index 804b774..9b8f733 100644
--- a/slices/core/src/main/res/values-gu/strings.xml
+++ b/slices/core/src/main/res/values-gu/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g>ને <xliff:g id="APP_2">%2$s</xliff:g> સ્લાઇસ બતાવવાની મંજૂરી આપીએ?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- તે <xliff:g id="APP">%1$s</xliff:g>માંથી માહિતી વાંચી શકે છે"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- તે <xliff:g id="APP">%1$s</xliff:g>ની અંદર ક્રિયાઓ કરી શકે છે"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"મંજૂરી આપો"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"નકારો"</string>
</resources>
diff --git a/slices/core/src/main/res/values-hi/strings.xml b/slices/core/src/main/res/values-hi/strings.xml
index 9dfe2b0..f5215cb 100644
--- a/slices/core/src/main/res/values-hi/strings.xml
+++ b/slices/core/src/main/res/values-hi/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> को <xliff:g id="APP_2">%2$s</xliff:g> के हिस्से (स्लाइस) दिखाने की मंज़ूरी दें?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- यह <xliff:g id="APP">%1$s</xliff:g> से जानकारी पा सकता है"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- यह <xliff:g id="APP">%1$s</xliff:g> में कार्रवाई कर सकता है"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"अनुमति दें"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"अनुमति न दें"</string>
</resources>
diff --git a/slices/core/src/main/res/values-hr/strings.xml b/slices/core/src/main/res/values-hr/strings.xml
index 9e614b5..b7980bd 100644
--- a/slices/core/src/main/res/values-hr/strings.xml
+++ b/slices/core/src/main/res/values-hr/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Želite li dopustiti aplikaciji <xliff:g id="APP_0">%1$s</xliff:g> da prikazuje isječke aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– može čitati informacije aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– može vršiti radnje u aplikaciji <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Dopusti"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Odbij"</string>
</resources>
diff --git a/slices/core/src/main/res/values-hu/strings.xml b/slices/core/src/main/res/values-hu/strings.xml
index 004829f..89b800c 100644
--- a/slices/core/src/main/res/values-hu/strings.xml
+++ b/slices/core/src/main/res/values-hu/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Engedélyezi a(z) <xliff:g id="APP_0">%1$s</xliff:g> alkalmazásnak, hogy részleteket mutasson a(z) <xliff:g id="APP_2">%2$s</xliff:g> alkalmazásból?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Információkat olvashat a(z) <xliff:g id="APP">%1$s</xliff:g> alkalmazásból"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Műveleteket végezhet a(z) <xliff:g id="APP">%1$s</xliff:g> alkalmazáson belül"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Engedélyezés"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Elutasítás"</string>
</resources>
diff --git a/slices/core/src/main/res/values-hy/strings.xml b/slices/core/src/main/res/values-hy/strings.xml
index 1d716d7..2512ee9 100644
--- a/slices/core/src/main/res/values-hy/strings.xml
+++ b/slices/core/src/main/res/values-hy/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Թույլատրե՞լ <xliff:g id="APP_0">%1$s</xliff:g> հավելվածին ցուցադրել հատվածներ <xliff:g id="APP_2">%2$s</xliff:g> հավելվածից"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Կարող է կարդալ տեղեկություններ <xliff:g id="APP">%1$s</xliff:g> հավելվածից"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Կարող է կատարել գործողություններ <xliff:g id="APP">%1$s</xliff:g> հավելվածում"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Թույլատրել"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Մերժել"</string>
</resources>
diff --git a/slices/core/src/main/res/values-in/strings.xml b/slices/core/src/main/res/values-in/strings.xml
index 860ed1c..87afa02 100644
--- a/slices/core/src/main/res/values-in/strings.xml
+++ b/slices/core/src/main/res/values-in/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Izinkan <xliff:g id="APP_0">%1$s</xliff:g> menampilkan potongan <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Dapat membaca informasi dari <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Dapat mengambil tindakan di dalam <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Izinkan"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Tolak"</string>
</resources>
diff --git a/slices/core/src/main/res/values-is/strings.xml b/slices/core/src/main/res/values-is/strings.xml
index da79a76..5845ff1 100644
--- a/slices/core/src/main/res/values-is/strings.xml
+++ b/slices/core/src/main/res/values-is/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Viltu leyfa <xliff:g id="APP_0">%1$s</xliff:g> að sýna sneiðar úr <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Það getur lesið upplýsingar úr <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Það getur gripið til aðgerða í <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Leyfa"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Hafna"</string>
</resources>
diff --git a/slices/core/src/main/res/values-it/strings.xml b/slices/core/src/main/res/values-it/strings.xml
index 5518d66..58509f9 100644
--- a/slices/core/src/main/res/values-it/strings.xml
+++ b/slices/core/src/main/res/values-it/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Vuoi consentire all\'app <xliff:g id="APP_0">%1$s</xliff:g> di mostrare porzioni dell\'app <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Può leggere informazioni dell\'app <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Può compiere azioni nell\'app <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Consenti"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Rifiuta"</string>
</resources>
diff --git a/slices/core/src/main/res/values-iw/strings.xml b/slices/core/src/main/res/values-iw/strings.xml
index 2151548..4a6791f 100644
--- a/slices/core/src/main/res/values-iw/strings.xml
+++ b/slices/core/src/main/res/values-iw/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"האם לאפשר ל-<xliff:g id="APP_0">%1$s</xliff:g> להציג חלקים מ-<xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- תהיה לה אפשרות לקרוא מידע מהאפליקציה <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- תהיה לה יכולת לנקוט פעולה בתוך <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"אישור"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"אני לא מרשה"</string>
</resources>
diff --git a/slices/core/src/main/res/values-ja/strings.xml b/slices/core/src/main/res/values-ja/strings.xml
index 1c28f4c..e619da5 100644
--- a/slices/core/src/main/res/values-ja/strings.xml
+++ b/slices/core/src/main/res/values-ja/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_2">%2$s</xliff:g> のスライスの表示を <xliff:g id="APP_0">%1$s</xliff:g> に許可しますか?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- <xliff:g id="APP">%1$s</xliff:g> からの情報を読み取ることができます"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- <xliff:g id="APP">%1$s</xliff:g> 内部で操作することがあります"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"許可"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"拒否"</string>
</resources>
diff --git a/slices/core/src/main/res/values-ka/strings.xml b/slices/core/src/main/res/values-ka/strings.xml
index b78206c..2558632 100644
--- a/slices/core/src/main/res/values-ka/strings.xml
+++ b/slices/core/src/main/res/values-ka/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"ანიჭებთ ნებართვას <xliff:g id="APP_0">%1$s</xliff:g>-ს, აჩვენოს <xliff:g id="APP_2">%2$s</xliff:g>-ის ფრაგმენტები?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- მას შეუძლია ინფორმაციის <xliff:g id="APP">%1$s</xliff:g>-დან წაკითხვა"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- მას შეუძლია ქმედებების <xliff:g id="APP">%1$s</xliff:g>-ში განხორციელება"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"დაშვება"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"უარყოფა"</string>
</resources>
diff --git a/slices/core/src/main/res/values-kk/strings.xml b/slices/core/src/main/res/values-kk/strings.xml
index fcb0509..21f8465 100644
--- a/slices/core/src/main/res/values-kk/strings.xml
+++ b/slices/core/src/main/res/values-kk/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> қолданбасына <xliff:g id="APP_2">%2$s</xliff:g> қолданбасының үзінділерін көрсетуге рұқсат берілсін бе?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- <xliff:g id="APP">%1$s</xliff:g> қолданбасындағы ақпаратты оқи алады"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- <xliff:g id="APP">%1$s</xliff:g> қолданбасында әрекет ете алады"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Рұқсат беру"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Тыйым салу"</string>
</resources>
diff --git a/slices/core/src/main/res/values-km/strings.xml b/slices/core/src/main/res/values-km/strings.xml
index 5d0a988..1a5755b 100644
--- a/slices/core/src/main/res/values-km/strings.xml
+++ b/slices/core/src/main/res/values-km/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"អនុញ្ញាតឱ្យ <xliff:g id="APP_0">%1$s</xliff:g> បង្ហាញស្ថិតិប្រើប្រាស់របស់ <xliff:g id="APP_2">%2$s</xliff:g> ?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- វាអាចអានព័ត៌មានពី <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- វាអាចធ្វើសកម្មភាពនៅក្នុង <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"អនុញ្ញាត"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"បដិសេធ"</string>
</resources>
diff --git a/slices/core/src/main/res/values-kn/strings.xml b/slices/core/src/main/res/values-kn/strings.xml
index 7fe32e0..0f14a36 100644
--- a/slices/core/src/main/res/values-kn/strings.xml
+++ b/slices/core/src/main/res/values-kn/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_2">%2$s</xliff:g> ಸ್ಲೈಸ್ಗಳನ್ನು ತೋರಿಸಲು <xliff:g id="APP_0">%1$s</xliff:g> ಅನ್ನು ಅನುಮತಿಸುವುದೇ?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ಇದು <xliff:g id="APP">%1$s</xliff:g> ನಿಂದ ಮಾಹಿತಿಯನ್ನು ಓದಬಹುದು"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ಇದು <xliff:g id="APP">%1$s</xliff:g> ಒಳಗಡೆ ಕ್ರಿಯೆಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳಬಹುದು"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"ಅನುಮತಿಸಿ"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"ನಿರಾಕರಿಸಿ"</string>
</resources>
diff --git a/slices/core/src/main/res/values-ko/strings.xml b/slices/core/src/main/res/values-ko/strings.xml
index 93c62f0..81a6707 100644
--- a/slices/core/src/main/res/values-ko/strings.xml
+++ b/slices/core/src/main/res/values-ko/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g>에서 <xliff:g id="APP_2">%2$s</xliff:g>의 슬라이스를 표시하도록 허용하시겠습니까?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- <xliff:g id="APP">%1$s</xliff:g>의 정보를 읽을 수 있음"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- <xliff:g id="APP">%1$s</xliff:g>에서 작업할 수 있음"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"허용"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"거부"</string>
</resources>
diff --git a/slices/core/src/main/res/values-ky/strings.xml b/slices/core/src/main/res/values-ky/strings.xml
index 9615740..9a26322 100644
--- a/slices/core/src/main/res/values-ky/strings.xml
+++ b/slices/core/src/main/res/values-ky/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> колдонмосуна <xliff:g id="APP_2">%2$s</xliff:g> үлгүлөрүн көрсөтүүгө уруксат берилсинби?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- <xliff:g id="APP">%1$s</xliff:g> колдонмосунун маалыматын окуйт"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- <xliff:g id="APP">%1$s</xliff:g> колдонмосунда аракеттерди аткарат"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Уруксат берүү"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Тыюу салынат"</string>
</resources>
diff --git a/slices/core/src/main/res/values-lo/strings.xml b/slices/core/src/main/res/values-lo/strings.xml
index 9b18f5b..aeeedc9 100644
--- a/slices/core/src/main/res/values-lo/strings.xml
+++ b/slices/core/src/main/res/values-lo/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"ອະນຸຍາດ <xliff:g id="APP_0">%1$s</xliff:g> ໃຫ້ສະແດງ <xliff:g id="APP_2">%2$s</xliff:g> ສະໄລ້ບໍ?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ມັນສາມາດອ່ານຂໍ້ມູນຈາກ <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ມັນສາມາດໃຊ້ຄຳສັ່ງພາຍໃນ <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"ອະນຸຍາດ"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"ປະຕິເສດ"</string>
</resources>
diff --git a/slices/core/src/main/res/values-lt/strings.xml b/slices/core/src/main/res/values-lt/strings.xml
index 1e88cd6..604ee1d 100644
--- a/slices/core/src/main/res/values-lt/strings.xml
+++ b/slices/core/src/main/res/values-lt/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Leisti „<xliff:g id="APP_0">%1$s</xliff:g>“ rodyti „<xliff:g id="APP_2">%2$s</xliff:g>“ fragmentus?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Gali nuskaityti informaciją iš „<xliff:g id="APP">%1$s</xliff:g>“"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Gali imtis veiksmų programoje „<xliff:g id="APP">%1$s</xliff:g>“"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Leisti"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Atmesti"</string>
</resources>
diff --git a/slices/core/src/main/res/values-lv/strings.xml b/slices/core/src/main/res/values-lv/strings.xml
index 1f3ccde..60dbac8 100644
--- a/slices/core/src/main/res/values-lv/strings.xml
+++ b/slices/core/src/main/res/values-lv/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Vai atļaut lietotnei <xliff:g id="APP_0">%1$s</xliff:g> rādīt lietotnes <xliff:g id="APP_2">%2$s</xliff:g> sadaļas?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Var lasīt informāciju no lietotnes <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Var veikt darbības lietotnē <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Atļaut"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Neatļaut"</string>
</resources>
diff --git a/slices/core/src/main/res/values-mk/strings.xml b/slices/core/src/main/res/values-mk/strings.xml
index a5ccc53..fd0a8d2 100644
--- a/slices/core/src/main/res/values-mk/strings.xml
+++ b/slices/core/src/main/res/values-mk/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Да се дозволи <xliff:g id="APP_0">%1$s</xliff:g> да прикажува делови од <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Може да чита информации од <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Може да презема дејства во <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Дозволете"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Одбијте"</string>
</resources>
diff --git a/slices/core/src/main/res/values-ml/strings.xml b/slices/core/src/main/res/values-ml/strings.xml
index 21802b7..bb565fa 100644
--- a/slices/core/src/main/res/values-ml/strings.xml
+++ b/slices/core/src/main/res/values-ml/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_2">%2$s</xliff:g> സ്ലൈസുകൾ കാണിക്കാൻ <xliff:g id="APP_0">%1$s</xliff:g>-നെ അനുവദിക്കണോ?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ഇതിന് <xliff:g id="APP">%1$s</xliff:g>-ൽ നിന്ന് വിവരങ്ങൾ വായിക്കാനാകും"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ഇതിന് <xliff:g id="APP">%1$s</xliff:g>-നുള്ളിൽ പ്രവർത്തനങ്ങൾ ചെയ്യാനാകും"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"അനുവദിക്കുക"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"നിരസിക്കുക"</string>
</resources>
diff --git a/slices/core/src/main/res/values-mn/strings.xml b/slices/core/src/main/res/values-mn/strings.xml
index 8e0661a..ce2b5b9 100644
--- a/slices/core/src/main/res/values-mn/strings.xml
+++ b/slices/core/src/main/res/values-mn/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g>-д <xliff:g id="APP_2">%2$s</xliff:g>-н хэсгүүдийг харуулахыг зөвшөөрөх үү?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Энэ <xliff:g id="APP">%1$s</xliff:g>-с мэдээлэл унших боломжтой"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Энэ <xliff:g id="APP">%1$s</xliff:g> дотор үйлдэл хийх боломжтой"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Зөвшөөрөх"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Татгалзах"</string>
</resources>
diff --git a/slices/core/src/main/res/values-mr/strings.xml b/slices/core/src/main/res/values-mr/strings.xml
index ab48521..7ed173d 100644
--- a/slices/core/src/main/res/values-mr/strings.xml
+++ b/slices/core/src/main/res/values-mr/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> ला <xliff:g id="APP_2">%2$s</xliff:g> चे तुकडे दाखवण्याची अनुमती द्यायची का?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ते <xliff:g id="APP">%1$s</xliff:g> ची माहिती वाचू शकते"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ते <xliff:g id="APP">%1$s</xliff:g> मध्ये कृती करू शकते"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"अनुमती द्या"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"नकार द्या"</string>
</resources>
diff --git a/slices/core/src/main/res/values-ms/strings.xml b/slices/core/src/main/res/values-ms/strings.xml
index 4b20a63..e4dc766 100644
--- a/slices/core/src/main/res/values-ms/strings.xml
+++ b/slices/core/src/main/res/values-ms/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Benarkan <xliff:g id="APP_0">%1$s</xliff:g> menunjukkan hirisan <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Hos hirisan boleh membaca maklumat daripada <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Hos hirisan boleh mengambil tindakan dalam <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Benarkan"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Tolak"</string>
</resources>
diff --git a/slices/core/src/main/res/values-my/strings.xml b/slices/core/src/main/res/values-my/strings.xml
index 666640ef..109f680 100644
--- a/slices/core/src/main/res/values-my/strings.xml
+++ b/slices/core/src/main/res/values-my/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> အား <xliff:g id="APP_2">%2$s</xliff:g> ၏အချပ်များ ပြသခွင့်ပြုပါသလား။"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ၎င်းသည် <xliff:g id="APP">%1$s</xliff:g> မှ အချက်အလက်ကို ဖတ်နိုင်သည်"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ၎င်းသည် <xliff:g id="APP">%1$s</xliff:g> အတွင်း လုပ်ဆောင်ချက်များ ပြုလုပ်နိုင်သည်"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"ခွင့်ပြုရန်"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"ငြင်းပယ်ရန်"</string>
</resources>
diff --git a/slices/core/src/main/res/values-nb/strings.xml b/slices/core/src/main/res/values-nb/strings.xml
index 9448d03..d3246d5 100644
--- a/slices/core/src/main/res/values-nb/strings.xml
+++ b/slices/core/src/main/res/values-nb/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Vil du tillate at <xliff:g id="APP_0">%1$s</xliff:g> viser <xliff:g id="APP_2">%2$s</xliff:g>-utsnitt?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Den kan lese informasjon fra <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Den kan utføre handlinger i <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Tillat"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Ikke tillat"</string>
</resources>
diff --git a/slices/core/src/main/res/values-ne/strings.xml b/slices/core/src/main/res/values-ne/strings.xml
index bfa42445..baba49e 100644
--- a/slices/core/src/main/res/values-ne/strings.xml
+++ b/slices/core/src/main/res/values-ne/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> लाई <xliff:g id="APP_2">%2$s</xliff:g> का स्लाइसहरू देखाउन अनुमति दिने हो?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- यसले <xliff:g id="APP">%1$s</xliff:g> को जानकारी पढ्न सक्छ"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- यसले <xliff:g id="APP">%1$s</xliff:g> भित्र कारबाही गर्न सक्छ"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"अनुमति दिनुहोस्"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"नदिने"</string>
</resources>
diff --git a/slices/core/src/main/res/values-nl/strings.xml b/slices/core/src/main/res/values-nl/strings.xml
index 4d8006e..ffbb174 100644
--- a/slices/core/src/main/res/values-nl/strings.xml
+++ b/slices/core/src/main/res/values-nl/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> toestaan om segmenten van <xliff:g id="APP_2">%2$s</xliff:g> te tonen?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Deze kan informatie lezen van <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Deze kan acties uitvoeren in <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Toestaan"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Weigeren"</string>
</resources>
diff --git a/slices/core/src/main/res/values-or/strings.xml b/slices/core/src/main/res/values-or/strings.xml
index a757613..672f51c 100644
--- a/slices/core/src/main/res/values-or/strings.xml
+++ b/slices/core/src/main/res/values-or/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_2">%2$s</xliff:g> ସ୍ଲାଇସ୍କୁ ଦେଖାଇବା ପାଇଁ <xliff:g id="APP_0">%1$s</xliff:g>କୁ ଅନୁମତି ଦେବେ?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ଏହା <xliff:g id="APP">%1$s</xliff:g>ରୁ ସୂଚନାକୁ ପଢ଼ିପାରିବ"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ଏହା <xliff:g id="APP">%1$s</xliff:g> ଭିତରେ କାମ କରିପାରିବ"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"ଅଗ୍ରାହ୍ୟ କରନ୍ତୁ"</string>
</resources>
diff --git a/slices/core/src/main/res/values-pa/strings.xml b/slices/core/src/main/res/values-pa/strings.xml
index d68cc39..03c926e 100644
--- a/slices/core/src/main/res/values-pa/strings.xml
+++ b/slices/core/src/main/res/values-pa/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"ਕੀ <xliff:g id="APP_0">%1$s</xliff:g> ਨੂੰ <xliff:g id="APP_2">%2$s</xliff:g> ਦੇ ਹਿੱਸੇ ਦਿਖਾਉਣ ਦੇਣੇ ਹਨ?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ਇਹ <xliff:g id="APP">%1$s</xliff:g> ਵਿੱਚੋਂ ਜਾਣਕਾਰੀ ਪੜ੍ਹ ਸਕਦਾ ਹੈ"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ਇਸ <xliff:g id="APP">%1$s</xliff:g> ਦੇ ਅੰਦਰ ਕਾਰਵਾਈਆਂ ਕਰ ਸਕਦਾ ਹੈ"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"ਕਰਨ ਦਿਓ"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"ਅਸਵੀਕਾਰ ਕਰੋ"</string>
</resources>
diff --git a/slices/core/src/main/res/values-pl/strings.xml b/slices/core/src/main/res/values-pl/strings.xml
index ea32902..7ef7e74 100644
--- a/slices/core/src/main/res/values-pl/strings.xml
+++ b/slices/core/src/main/res/values-pl/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Zezwolić aplikacji <xliff:g id="APP_0">%1$s</xliff:g> na pokazywanie wycinków z aplikacji <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Może odczytywać informacje z aplikacji <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Może wykonywać działania w aplikacji <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Zezwól"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Odmów"</string>
</resources>
diff --git a/slices/core/src/main/res/values-pt-rBR/strings.xml b/slices/core/src/main/res/values-pt-rBR/strings.xml
index b58e786..4920aed 100644
--- a/slices/core/src/main/res/values-pt-rBR/strings.xml
+++ b/slices/core/src/main/res/values-pt-rBR/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Permitir que <xliff:g id="APP_0">%1$s</xliff:g> mostre partes do app <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Pode ler informações do app <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Pode realizar ações no app <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Permitir"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Negar"</string>
</resources>
diff --git a/slices/core/src/main/res/values-pt-rPT/strings.xml b/slices/core/src/main/res/values-pt-rPT/strings.xml
index 832b5e5..cdf0555 100644
--- a/slices/core/src/main/res/values-pt-rPT/strings.xml
+++ b/slices/core/src/main/res/values-pt-rPT/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Permitir que a app <xliff:g id="APP_0">%1$s</xliff:g> mostre partes da app <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Pode ler informações da app <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Pode realizar ações na app <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Permitir"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Recusar"</string>
</resources>
diff --git a/slices/core/src/main/res/values-pt/strings.xml b/slices/core/src/main/res/values-pt/strings.xml
index b58e786..4920aed 100644
--- a/slices/core/src/main/res/values-pt/strings.xml
+++ b/slices/core/src/main/res/values-pt/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Permitir que <xliff:g id="APP_0">%1$s</xliff:g> mostre partes do app <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Pode ler informações do app <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Pode realizar ações no app <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Permitir"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Negar"</string>
</resources>
diff --git a/slices/core/src/main/res/values-ro/strings.xml b/slices/core/src/main/res/values-ro/strings.xml
index 2db5e57..68da8f3 100644
--- a/slices/core/src/main/res/values-ro/strings.xml
+++ b/slices/core/src/main/res/values-ro/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Permiteți <xliff:g id="APP_0">%1$s</xliff:g> să afișeze porțiuni din <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Poate citi informații din <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Poate efectua acțiuni în <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Permiteți"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Refuzați"</string>
</resources>
diff --git a/slices/core/src/main/res/values-ru/strings.xml b/slices/core/src/main/res/values-ru/strings.xml
index 89dafbc..5a933ca 100644
--- a/slices/core/src/main/res/values-ru/strings.xml
+++ b/slices/core/src/main/res/values-ru/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Разрешить приложению \"<xliff:g id="APP_0">%1$s</xliff:g>\" показывать фрагменты приложения \"<xliff:g id="APP_2">%2$s</xliff:g>\"?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Ему станут доступны данные из приложения \"<xliff:g id="APP">%1$s</xliff:g>\"."</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Оно сможет совершать действия в приложении \"<xliff:g id="APP">%1$s</xliff:g>\"."</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Да"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Нет"</string>
</resources>
diff --git a/slices/core/src/main/res/values-si/strings.xml b/slices/core/src/main/res/values-si/strings.xml
index e5e8478..74ff957 100644
--- a/slices/core/src/main/res/values-si/strings.xml
+++ b/slices/core/src/main/res/values-si/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> හට කොටස් <xliff:g id="APP_2">%2$s</xliff:g>ක් පෙන්වීමට ඉඩ දෙන්නද?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- එයට <xliff:g id="APP">%1$s</xliff:g> වෙතින් තොරතුරු කියවිය හැකිය"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- එයට <xliff:g id="APP">%1$s</xliff:g> ඇතුළත ක්රියාමාර්ග ගත හැකිය"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"ඉඩ දෙන්න"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"ප්රතික්ෂේප කර."</string>
</resources>
diff --git a/slices/core/src/main/res/values-sk/strings.xml b/slices/core/src/main/res/values-sk/strings.xml
index 8070718..04053ff 100644
--- a/slices/core/src/main/res/values-sk/strings.xml
+++ b/slices/core/src/main/res/values-sk/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Povoliť aplikácii <xliff:g id="APP_0">%1$s</xliff:g> zobrazovať rezy z aplikácie <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Môže čítať informácie z aplikácie <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Môže vykonávať akcie v aplikácii <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Povoliť"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Zamietnuť"</string>
</resources>
diff --git a/slices/core/src/main/res/values-sl/strings.xml b/slices/core/src/main/res/values-sl/strings.xml
index b3ab6f4..88df9ec 100644
--- a/slices/core/src/main/res/values-sl/strings.xml
+++ b/slices/core/src/main/res/values-sl/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Ali aplikaciji <xliff:g id="APP_0">%1$s</xliff:g> dovolite prikazovanje izrezov iz aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– lahko bere podatke v aplikaciji <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– lahko izvaja dejanja v aplikaciji <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Dovoli"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Zavrni"</string>
</resources>
diff --git a/slices/core/src/main/res/values-sq/strings.xml b/slices/core/src/main/res/values-sq/strings.xml
index 9ae77dd..5e56aea 100644
--- a/slices/core/src/main/res/values-sq/strings.xml
+++ b/slices/core/src/main/res/values-sq/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Të lejohet <xliff:g id="APP_0">%1$s</xliff:g> që të shfaqë pjesë të <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Mund të lexojë informacion nga <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Mund të ndërmarrë veprime brenda <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Lejo"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Refuzo"</string>
</resources>
diff --git a/slices/core/src/main/res/values-sr/strings.xml b/slices/core/src/main/res/values-sr/strings.xml
index b7c29c5..1064600 100644
--- a/slices/core/src/main/res/values-sr/strings.xml
+++ b/slices/core/src/main/res/values-sr/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Желите ли да дозволите апликацији <xliff:g id="APP_0">%1$s</xliff:g> да приказује исечке из апликације <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Може да чита податке из апликације <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Може да обавља радње у апликацији <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Дозволи"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Одбиј"</string>
</resources>
diff --git a/slices/core/src/main/res/values-sv/strings.xml b/slices/core/src/main/res/values-sv/strings.xml
index 9be28b3..3a78a19 100644
--- a/slices/core/src/main/res/values-sv/strings.xml
+++ b/slices/core/src/main/res/values-sv/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Tillåter du att bitar av <xliff:g id="APP_2">%2$s</xliff:g> visas i <xliff:g id="APP_0">%1$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Kan läsa information från <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Kan vidta åtgärder i <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Tillåt"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Neka"</string>
</resources>
diff --git a/slices/core/src/main/res/values-sw/strings.xml b/slices/core/src/main/res/values-sw/strings.xml
index 28459cd..e6a72a0 100644
--- a/slices/core/src/main/res/values-sw/strings.xml
+++ b/slices/core/src/main/res/values-sw/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Ungependa kuruhusu <xliff:g id="APP_0">%1$s</xliff:g> ionyeshe vipengee <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Inaweza kusoma maelezo kutoka <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Inaweza kuchukua hatua ndani ya <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Ruhusu"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Kataa"</string>
</resources>
diff --git a/slices/core/src/main/res/values-ta/strings.xml b/slices/core/src/main/res/values-ta/strings.xml
index 36be75a..7f13957 100644
--- a/slices/core/src/main/res/values-ta/strings.xml
+++ b/slices/core/src/main/res/values-ta/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_2">%2$s</xliff:g> ஆப்ஸின் விழிப்பூட்டல்களைக் காண்பிக்க, <xliff:g id="APP_0">%1$s</xliff:g> ஆப்ஸை அனுமதிக்கவா?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- இது, <xliff:g id="APP">%1$s</xliff:g> பயன்பாட்டிலிருக்கும் தகவலைப் படிக்கும்"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- இது, <xliff:g id="APP">%1$s</xliff:g> பயன்பாட்டிற்குள் செயல்பாடுகளில் ஈடுபடும்"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"அனுமதி"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"நிராகரி"</string>
</resources>
diff --git a/slices/core/src/main/res/values-te/strings.xml b/slices/core/src/main/res/values-te/strings.xml
index ce51a47..acbfe1f 100644
--- a/slices/core/src/main/res/values-te/strings.xml
+++ b/slices/core/src/main/res/values-te/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_2">%2$s</xliff:g> స్లైస్లను చూపించడానికి <xliff:g id="APP_0">%1$s</xliff:g>ని అనుమతించాలా?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ఇది <xliff:g id="APP">%1$s</xliff:g> నుండి సమాచారాన్ని చదవగలుగుతుంది"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ఇది <xliff:g id="APP">%1$s</xliff:g> లోపల చర్యలు తీసుకోగలుగుతుంది"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"అనుమతించు"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"తిరస్కరించు"</string>
</resources>
diff --git a/slices/core/src/main/res/values-th/strings.xml b/slices/core/src/main/res/values-th/strings.xml
index 07371a0..b561742 100644
--- a/slices/core/src/main/res/values-th/strings.xml
+++ b/slices/core/src/main/res/values-th/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"อนุญาตให้ <xliff:g id="APP_0">%1$s</xliff:g> แสดงส่วนต่างๆ ของ <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- อ่านข้อมูลจาก <xliff:g id="APP">%1$s</xliff:g> ได้"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ดำเนินการใน <xliff:g id="APP">%1$s</xliff:g> ได้"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"อนุญาต"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"ปฏิเสธ"</string>
</resources>
diff --git a/slices/core/src/main/res/values-tl/strings.xml b/slices/core/src/main/res/values-tl/strings.xml
index e4bf3e0..3e0daf7 100644
--- a/slices/core/src/main/res/values-tl/strings.xml
+++ b/slices/core/src/main/res/values-tl/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Payagan ang <xliff:g id="APP_0">%1$s</xliff:g> na ipakita ang mga slice ng <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Nakakabasa ito ng impormasyon mula sa <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Nakakagawa ito ng mga pagkilos sa loob ng <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Payagan"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Tanggihan"</string>
</resources>
diff --git a/slices/core/src/main/res/values-tr/strings.xml b/slices/core/src/main/res/values-tr/strings.xml
index 2cbcfda..d8d3c87 100644
--- a/slices/core/src/main/res/values-tr/strings.xml
+++ b/slices/core/src/main/res/values-tr/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> uygulamasının, <xliff:g id="APP_2">%2$s</xliff:g> dilimlerini göstermesine izin verilsin mi?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- <xliff:g id="APP">%1$s</xliff:g> uygulamasından bilgileri okuyabilir"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- <xliff:g id="APP">%1$s</xliff:g> uygulamasında işlem yapabilir"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"İzin ver"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Reddet"</string>
</resources>
diff --git a/slices/core/src/main/res/values-uk/strings.xml b/slices/core/src/main/res/values-uk/strings.xml
index b842f5c..86dd1bd 100644
--- a/slices/core/src/main/res/values-uk/strings.xml
+++ b/slices/core/src/main/res/values-uk/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Дозволити додатку <xliff:g id="APP_0">%1$s</xliff:g> показувати фрагменти додатка <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Може переглядати інформацію з додатка <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Може виконувати дії в додатку <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Дозволити"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Заборонити"</string>
</resources>
diff --git a/slices/core/src/main/res/values-ur/strings.xml b/slices/core/src/main/res/values-ur/strings.xml
index 8999e25..39a9820 100644
--- a/slices/core/src/main/res/values-ur/strings.xml
+++ b/slices/core/src/main/res/values-ur/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> کو <xliff:g id="APP_2">%2$s</xliff:g> کے سلائسز دکھانے کی اجازت دیں؟"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- یہ <xliff:g id="APP">%1$s</xliff:g> کی معلومات پڑھ سکتا ہے"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- یہ <xliff:g id="APP">%1$s</xliff:g> کے اندر کارروائیاں کر سکتا ہے"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"اجازت دیں"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"مسترد کریں"</string>
</resources>
diff --git a/slices/core/src/main/res/values-uz/strings.xml b/slices/core/src/main/res/values-uz/strings.xml
index 9fcb4ce..1d6febd 100644
--- a/slices/core/src/main/res/values-uz/strings.xml
+++ b/slices/core/src/main/res/values-uz/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> ilovasiga <xliff:g id="APP_2">%2$s</xliff:g> ilovasidan fragmentlar ko‘rsatishga ruxsat berilsinmi?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– <xliff:g id="APP">%1$s</xliff:g> ma’lumotlarini o‘qiy oladi"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– <xliff:g id="APP">%1$s</xliff:g> ichida amallar bajara oladi"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Ruxsat"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Rad etish"</string>
</resources>
diff --git a/slices/core/src/main/res/values-vi/strings.xml b/slices/core/src/main/res/values-vi/strings.xml
index c067ac8..d8e71a5 100644
--- a/slices/core/src/main/res/values-vi/strings.xml
+++ b/slices/core/src/main/res/values-vi/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Cho phép <xliff:g id="APP_0">%1$s</xliff:g> hiển thị các lát của <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Có thể đọc thông tin từ <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Có thể thực hiện hành động bên trong <xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Cho phép"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Từ chối"</string>
</resources>
diff --git a/slices/core/src/main/res/values-zh-rCN/strings.xml b/slices/core/src/main/res/values-zh-rCN/strings.xml
index 6ab2d3e..2ec34bc 100644
--- a/slices/core/src/main/res/values-zh-rCN/strings.xml
+++ b/slices/core/src/main/res/values-zh-rCN/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"要允许“<xliff:g id="APP_0">%1$s</xliff:g>”显示“<xliff:g id="APP_2">%2$s</xliff:g>”图块吗?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- 可以读取“<xliff:g id="APP">%1$s</xliff:g>”中的信息"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- 可以在“<xliff:g id="APP">%1$s</xliff:g>”内执行操作"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"允许"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"拒绝"</string>
</resources>
diff --git a/slices/core/src/main/res/values-zh-rHK/strings.xml b/slices/core/src/main/res/values-zh-rHK/strings.xml
index 5cf6943..118c2ac 100644
--- a/slices/core/src/main/res/values-zh-rHK/strings.xml
+++ b/slices/core/src/main/res/values-zh-rHK/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"要允許「<xliff:g id="APP_0">%1$s</xliff:g>」顯示「<xliff:g id="APP_2">%2$s</xliff:g>」的快訊嗎?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- 可以讀取「<xliff:g id="APP">%1$s</xliff:g>」中的資料"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- 可以在「<xliff:g id="APP">%1$s</xliff:g>」內執行操作"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"允許"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"拒絕"</string>
</resources>
diff --git a/slices/core/src/main/res/values-zh-rTW/strings.xml b/slices/core/src/main/res/values-zh-rTW/strings.xml
index df1ab8b..53c802d 100644
--- a/slices/core/src/main/res/values-zh-rTW/strings.xml
+++ b/slices/core/src/main/res/values-zh-rTW/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"要允許「<xliff:g id="APP_0">%1$s</xliff:g>」顯示「<xliff:g id="APP_2">%2$s</xliff:g>」的區塊嗎?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- 它可以讀取「<xliff:g id="APP">%1$s</xliff:g>」的資訊"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- 它可以在「<xliff:g id="APP">%1$s</xliff:g>」內執行操作"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"允許"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"拒絕"</string>
</resources>
diff --git a/slices/core/src/main/res/values-zu/strings.xml b/slices/core/src/main/res/values-zu/strings.xml
index d9ada48..b1fac39 100644
--- a/slices/core/src/main/res/values-zu/strings.xml
+++ b/slices/core/src/main/res/values-zu/strings.xml
@@ -21,7 +21,6 @@
<string name="abc_slice_permission_title" msgid="4175332421259324948">"Vumela i-<xliff:g id="APP_0">%1$s</xliff:g> ukuthi ibonise izingcezu ze-<xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Ingafunda ulwazi kusukela ku-<xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Ingenza izenzo ngaphakathi kwe-<xliff:g id="APP">%1$s</xliff:g>"</string>
-
<string name="abc_slice_permission_allow" msgid="5024599872061409708">"Vumela"</string>
<string name="abc_slice_permission_deny" msgid="3819478292430407705">"Phika"</string>
</resources>
diff --git a/slices/view/src/main/res/values-my/strings.xml b/slices/view/src/main/res/values-my/strings.xml
index 4a3e3d4..5b9d57c 100644
--- a/slices/view/src/main/res/values-my/strings.xml
+++ b/slices/view/src/main/res/values-my/strings.xml
@@ -19,7 +19,7 @@
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">"နောက်ထပ်"</string>
- <string name="abc_slice_show_more" msgid="1567717014004692768">"နောက်ထပ် ပြပါ"</string>
+ <string name="abc_slice_show_more" msgid="1567717014004692768">"ပိုပြပါ"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"<xliff:g id="TIME">%1$s</xliff:g> က အပ်ဒိတ်လုပ်ထားသည်"</string>
<plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
<item quantity="other">ပြီးခဲ့သော<xliff:g id="ID_2">%d</xliff:g>မိနစ်</item>
diff --git a/startup/startup-runtime-lint/build.gradle b/startup/startup-runtime-lint/build.gradle
index 5423d95..22a35542 100644
--- a/startup/startup-runtime-lint/build.gradle
+++ b/startup/startup-runtime-lint/build.gradle
@@ -25,13 +25,7 @@
}
dependencies {
- // compileOnly because we use lintChecks and it doesn't allow other types of deps
- // this ugly hack exists because of b/63873667
- if (rootProject.hasProperty("android.injected.invoked.from.ide")) {
- compileOnly(LINT_API_LATEST)
- } else {
- compileOnly(LINT_API_MIN)
- }
+ compileOnly(LINT_API_MIN)
compileOnly(KOTLIN_STDLIB)
testImplementation(KOTLIN_STDLIB)
diff --git a/textclassifier/textclassifier/src/androidTest/java/androidx/textclassifier/widget/FloatingToolbarTest.java b/textclassifier/textclassifier/src/androidTest/java/androidx/textclassifier/widget/FloatingToolbarTest.java
index 8558cb1..9157ad0 100644
--- a/textclassifier/textclassifier/src/androidTest/java/androidx/textclassifier/widget/FloatingToolbarTest.java
+++ b/textclassifier/textclassifier/src/androidTest/java/androidx/textclassifier/widget/FloatingToolbarTest.java
@@ -71,6 +71,7 @@
import org.hamcrest.Matcher;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -204,6 +205,7 @@
assertFloatingToolbarIsShowing();
}
+ @Ignore // b/188568469
@Test
public void ui_itemClick() throws Exception {
final SupportMenu menu = new MenuBuilder(mContext);
@@ -219,6 +221,7 @@
onFloatingToolbar().check(matches(isDisplayed()));
}
+ @Ignore // b/188568469
@Test
public void ui_dismissOnItemClick() throws Exception {
final SupportMenu menu = new MenuBuilder(mContext);
@@ -239,6 +242,7 @@
assertFloatingToolbarIsDismissed();
}
+ @Ignore // b/188568469
@Test
@SuppressWarnings("deprecation") /* defaultDisplay */
public void ui_dismissOnOutsideClick() throws Exception {
@@ -321,6 +325,7 @@
onFloatingToolbar().check(matches(isDisplayed()));
}
+ @Ignore // b/188568469
@Test
public void ui_toggleOverflow() throws Exception {
onWidget().perform(showFloatingToolbar());
@@ -336,6 +341,7 @@
onFloatingToolbarOverflowPanel().check(matches(not(isDisplayed())));
}
+ @Ignore // b/188568469
@Test
public void ui_itemPanel() throws Exception {
final SupportMenu menu = new MenuBuilder(mContext);
@@ -383,6 +389,7 @@
onFloatingToolbarItem("C").check(matches(isDisplayed()));
}
+ @Ignore // b/188568469
@Test
public void ui_horizontalAlignment() throws Exception {
enableLtRMode();
diff --git a/tracing/tracing/build.gradle b/tracing/tracing/build.gradle
index fbd0e02..7582a61 100644
--- a/tracing/tracing/build.gradle
+++ b/tracing/tracing/build.gradle
@@ -29,7 +29,7 @@
}
dependencies {
- implementation("androidx.annotation:annotation:1.1.0")
+ implementation("androidx.annotation:annotation:1.2.0")
androidTestImplementation(KOTLIN_STDLIB)
androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
androidTestImplementation(ANDROIDX_TEST_CORE)
diff --git a/tracing/tracing/lint-baseline.xml b/tracing/tracing/lint-baseline.xml
index 2c1ddc6..e17f06f 100644
--- a/tracing/tracing/lint-baseline.xml
+++ b/tracing/tracing/lint-baseline.xml
@@ -1,15 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<issues format="5" by="lint 4.2.0-beta06" client="gradle" variant="debug" version="4.2.0-beta06">
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.tracing.Trace is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return android.os.Trace.isEnabled();"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/tracing/Trace.java"
- line="62"
- column="41"/>
- </issue>
-
</issues>
diff --git a/tracing/tracing/src/main/java/androidx/tracing/Trace.java b/tracing/tracing/src/main/java/androidx/tracing/Trace.java
index 9e63bc9..0520f2e 100644
--- a/tracing/tracing/src/main/java/androidx/tracing/Trace.java
+++ b/tracing/tracing/src/main/java/androidx/tracing/Trace.java
@@ -57,12 +57,10 @@
*/
@SuppressLint("NewApi")
public static boolean isEnabled() {
- try {
- if (sIsTagEnabledMethod == null) {
- return android.os.Trace.isEnabled();
- }
- } catch (NoSuchMethodError | NoClassDefFoundError ignore) {
+ if (Build.VERSION.SDK_INT >= 29) {
+ return TraceApi29Impl.isEnabled();
}
+
return isEnabledFallback();
}
diff --git a/tracing/tracing/src/main/java/androidx/tracing/TraceApi29Impl.java b/tracing/tracing/src/main/java/androidx/tracing/TraceApi29Impl.java
index 0665212..14ba157 100644
--- a/tracing/tracing/src/main/java/androidx/tracing/TraceApi29Impl.java
+++ b/tracing/tracing/src/main/java/androidx/tracing/TraceApi29Impl.java
@@ -16,6 +16,7 @@
package androidx.tracing;
+import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
@@ -35,6 +36,14 @@
}
/**
+ * Checks whether or not tracing is currently enabled.
+ */
+ @DoNotInline
+ public static boolean isEnabled() {
+ return android.os.Trace.isEnabled();
+ }
+
+ /**
* Writes a trace message to indicate that a given section of code has
* begun. Must be followed by a call to {@link #endAsyncSection(String, int)} with the same
* methodName and cookie.
diff --git a/versionedparcelable/versionedparcelable/api/restricted_current.txt b/versionedparcelable/versionedparcelable/api/restricted_current.txt
index 4e66658..7927248 100644
--- a/versionedparcelable/versionedparcelable/api/restricted_current.txt
+++ b/versionedparcelable/versionedparcelable/api/restricted_current.txt
@@ -70,8 +70,8 @@
method public <T extends android.os.Parcelable> T? readParcelable(T?, int);
method protected java.io.Serializable? readSerializable();
method public <T> java.util.Set<T!>? readSet(java.util.Set<T!>?, int);
- method @RequiresApi(api=android.os.Build.VERSION_CODES.LOLLIPOP) public android.util.Size? readSize(android.util.Size?, int);
- method @RequiresApi(api=android.os.Build.VERSION_CODES.LOLLIPOP) public android.util.SizeF? readSizeF(android.util.SizeF?, int);
+ method @RequiresApi(21) public android.util.Size? readSize(android.util.Size?, int);
+ method @RequiresApi(21) public android.util.SizeF? readSizeF(android.util.SizeF?, int);
method public android.util.SparseBooleanArray? readSparseBooleanArray(android.util.SparseBooleanArray?, int);
method protected abstract String? readString();
method public String? readString(String?, int);
@@ -121,8 +121,8 @@
method public void writeParcelable(android.os.Parcelable?, int);
method public void writeSerializable(java.io.Serializable?, int);
method public <T> void writeSet(java.util.Set<T!>?, int);
- method @RequiresApi(api=android.os.Build.VERSION_CODES.LOLLIPOP) public void writeSize(android.util.Size?, int);
- method @RequiresApi(api=android.os.Build.VERSION_CODES.LOLLIPOP) public void writeSizeF(android.util.SizeF?, int);
+ method @RequiresApi(21) public void writeSize(android.util.Size?, int);
+ method @RequiresApi(21) public void writeSizeF(android.util.SizeF?, int);
method public void writeSparseBooleanArray(android.util.SparseBooleanArray?, int);
method protected abstract void writeString(String?);
method public void writeString(String?, int);
diff --git a/versionedparcelable/versionedparcelable/build.gradle b/versionedparcelable/versionedparcelable/build.gradle
index 0358e3f..5ffba1b 100644
--- a/versionedparcelable/versionedparcelable/build.gradle
+++ b/versionedparcelable/versionedparcelable/build.gradle
@@ -26,7 +26,7 @@
}
dependencies {
- api("androidx.annotation:annotation:1.1.0")
+ api("androidx.annotation:annotation:1.2.0")
implementation("androidx.collection:collection:1.0.0")
androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
diff --git a/versionedparcelable/versionedparcelable/lint-baseline.xml b/versionedparcelable/versionedparcelable/lint-baseline.xml
index 92eccb0..c3c931a 100644
--- a/versionedparcelable/versionedparcelable/lint-baseline.xml
+++ b/versionedparcelable/versionedparcelable/lint-baseline.xml
@@ -24,72 +24,6 @@
</issue>
<issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.versionedparcelable.VersionedParcel is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" writeInt(val.getWidth());"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/versionedparcelable/VersionedParcel.java"
- line="537"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.versionedparcelable.VersionedParcel is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" writeInt(val.getHeight());"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/versionedparcelable/VersionedParcel.java"
- line="538"
- column="26"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.versionedparcelable.VersionedParcel is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" writeFloat(val.getWidth());"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/versionedparcelable/VersionedParcel.java"
- line="551"
- column="28"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.versionedparcelable.VersionedParcel is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" writeFloat(val.getHeight());"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/versionedparcelable/VersionedParcel.java"
- line="552"
- column="28"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.versionedparcelable.VersionedParcel is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new Size(width, height);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/versionedparcelable/VersionedParcel.java"
- line="1291"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 21; however, the containing class androidx.versionedparcelable.VersionedParcel is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return new SizeF(width, height);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/versionedparcelable/VersionedParcel.java"
- line="1308"
- column="20"/>
- </issue>
-
- <issue
id="LambdaLast"
message="Functional interface parameters (such as parameter 1, "val", in androidx.versionedparcelable.VersionedParcel.writeStrongInterface) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions"
errorLine1=" public void writeStrongInterface(@Nullable IInterface val, int fieldId) {"
diff --git a/versionedparcelable/versionedparcelable/src/androidTest/java/androidx/versionedparcelable/ParcelUtilsTest.java b/versionedparcelable/versionedparcelable/src/androidTest/java/androidx/versionedparcelable/ParcelUtilsTest.java
index 8ca1a22..cd2540b 100644
--- a/versionedparcelable/versionedparcelable/src/androidTest/java/androidx/versionedparcelable/ParcelUtilsTest.java
+++ b/versionedparcelable/versionedparcelable/src/androidTest/java/androidx/versionedparcelable/ParcelUtilsTest.java
@@ -79,6 +79,17 @@
assertThat(result).isNull();
}
+ @Test
+ public void putVersionedParcelableNullClearsKey() {
+ Bundle bundle = new Bundle();
+
+ ParcelUtils.putVersionedParcelable(bundle, "key", new ParcelUtilsParcelable());
+ assertThat(bundle.getBundle("key")).isNotNull();
+
+ ParcelUtils.putVersionedParcelable(bundle, "key", null);
+ assertThat(bundle.getBundle("key")).isNull();
+ }
+
@VersionedParcelize
public static class ParcelUtilsParcelable implements VersionedParcelable {
@ParcelField(1)
diff --git a/versionedparcelable/versionedparcelable/src/main/java/androidx/versionedparcelable/ParcelUtils.java b/versionedparcelable/versionedparcelable/src/main/java/androidx/versionedparcelable/ParcelUtils.java
index 7f01a16a..15b615e 100644
--- a/versionedparcelable/versionedparcelable/src/main/java/androidx/versionedparcelable/ParcelUtils.java
+++ b/versionedparcelable/versionedparcelable/src/main/java/androidx/versionedparcelable/ParcelUtils.java
@@ -98,11 +98,12 @@
public static void putVersionedParcelable(@NonNull Bundle b, @NonNull String key,
@Nullable VersionedParcelable obj) {
if (obj == null) {
- return;
+ b.putParcelable(key, null);
+ } else {
+ Bundle innerBundle = new Bundle();
+ innerBundle.putParcelable(INNER_BUNDLE_KEY, toParcelable(obj));
+ b.putParcelable(key, innerBundle);
}
- Bundle innerBundle = new Bundle();
- innerBundle.putParcelable(INNER_BUNDLE_KEY, toParcelable(obj));
- b.putParcelable(key, innerBundle);
}
/**
diff --git a/versionedparcelable/versionedparcelable/src/main/java/androidx/versionedparcelable/VersionedParcel.java b/versionedparcelable/versionedparcelable/src/main/java/androidx/versionedparcelable/VersionedParcel.java
index 683a8c39..4fca2f7 100644
--- a/versionedparcelable/versionedparcelable/src/main/java/androidx/versionedparcelable/VersionedParcel.java
+++ b/versionedparcelable/versionedparcelable/src/main/java/androidx/versionedparcelable/VersionedParcel.java
@@ -30,6 +30,7 @@
import android.util.SizeF;
import android.util.SparseBooleanArray;
+import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
@@ -529,28 +530,20 @@
* Flatten a Size into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
*/
- @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+ @RequiresApi(21)
public void writeSize(@Nullable Size val, int fieldId) {
setOutputField(fieldId);
- writeBoolean(val != null);
- if (val != null) {
- writeInt(val.getWidth());
- writeInt(val.getHeight());
- }
+ Api21Impl.writeSize(this, val);
}
/**
* Flatten a SizeF into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
*/
- @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+ @RequiresApi(21)
public void writeSizeF(@Nullable SizeF val, int fieldId) {
setOutputField(fieldId);
- writeBoolean(val != null);
- if (val != null) {
- writeFloat(val.getWidth());
- writeFloat(val.getHeight());
- }
+ Api21Impl.writeSizeF(this, val);
}
/**
@@ -1279,35 +1272,25 @@
/**
* Read a Size from the parcel at the current dataPosition().
*/
- @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+ @RequiresApi(21)
@Nullable
public Size readSize(@Nullable Size def, int fieldId) {
if (!readField(fieldId)) {
return def;
}
- if (readBoolean()) {
- int width = readInt();
- int height = readInt();
- return new Size(width, height);
- }
- return null;
+ return Api21Impl.readSize(this);
}
/**
* Read a SizeF from the parcel at the current dataPosition().
*/
- @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+ @RequiresApi(21)
@Nullable
public SizeF readSizeF(@Nullable SizeF def, int fieldId) {
if (!readField(fieldId)) {
return def;
}
- if (readBoolean()) {
- float width = readFloat();
- float height = readFloat();
- return new SizeF(width, height);
- }
- return null;
+ return Api21Impl.readSizeF(this);
}
/**
@@ -1702,4 +1685,47 @@
super(source);
}
}
+
+ @RequiresApi(21)
+ private static final class Api21Impl {
+ @DoNotInline
+ static void writeSize(@NonNull VersionedParcel self, @Nullable Size val) {
+ self.writeBoolean(val != null);
+ if (val != null) {
+ self.writeInt(val.getWidth());
+ self.writeInt(val.getHeight());
+ }
+ }
+
+ @DoNotInline
+ static void writeSizeF(@NonNull VersionedParcel self, @Nullable SizeF val) {
+ self.writeBoolean(val != null);
+ if (val != null) {
+ self.writeFloat(val.getWidth());
+ self.writeFloat(val.getHeight());
+ }
+ }
+
+ @DoNotInline
+ @Nullable
+ static Size readSize(@NonNull VersionedParcel self) {
+ if (self.readBoolean()) {
+ int width = self.readInt();
+ int height = self.readInt();
+ return new Size(width, height);
+ }
+ return null;
+ }
+
+ @DoNotInline
+ @Nullable
+ static SizeF readSizeF(@NonNull VersionedParcel self) {
+ if (self.readBoolean()) {
+ float width = self.readFloat();
+ float height = self.readFloat();
+ return new SizeF(width, height);
+ }
+ return null;
+ }
+ }
}
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 15cfc63..c1baf88 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 = 188565856)
public void testPageScrollPositionChangesSwipe() {
// Swipe one page to the left
verifyScrollCallbacksToHigherPage(ViewPagerActions.wrap(swipeLeft()), 1);
diff --git a/wear/compose/foundation/build.gradle b/wear/compose/foundation/build.gradle
index ad3829e..0024cfb 100644
--- a/wear/compose/foundation/build.gradle
+++ b/wear/compose/foundation/build.gradle
@@ -18,7 +18,6 @@
import androidx.build.LibraryVersions
import androidx.build.RunApiTasks
import androidx.build.AndroidXUiPlugin
-import static androidx.build.dependencies.DependenciesKt.*
plugins {
id("AndroidXPlugin")
@@ -32,7 +31,7 @@
dependencies {
kotlinPlugin(project(":compose:compiler:compiler"))
- implementation(KOTLIN_STDLIB)
+ implementation(libs.kotlinStdlib)
}
android {
diff --git a/wear/compose/material/build.gradle b/wear/compose/material/build.gradle
index 61b0b48..2dd6a56 100644
--- a/wear/compose/material/build.gradle
+++ b/wear/compose/material/build.gradle
@@ -18,7 +18,6 @@
import androidx.build.LibraryVersions
import androidx.build.RunApiTasks
import androidx.build.AndroidXUiPlugin
-import static androidx.build.dependencies.DependenciesKt.*
plugins {
id("AndroidXPlugin")
@@ -37,7 +36,7 @@
api(project(":compose:ui:ui-text"))
api(project(":compose:runtime:runtime"))
- implementation(KOTLIN_STDLIB)
+ implementation(libs.kotlinStdlib)
implementation(project(":compose:material:material"))
implementation(project(":compose:material:material-ripple"))
diff --git a/wear/compose/material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ChipTest.kt b/wear/compose/material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ChipTest.kt
index fc4ae01..fe6d6f3 100644
--- a/wear/compose/material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ChipTest.kt
+++ b/wear/compose/material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ChipTest.kt
@@ -21,6 +21,7 @@
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CornerSize
import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.testutils.assertShape
@@ -36,16 +37,21 @@
import androidx.compose.ui.test.assertHeightIsEqualTo
import androidx.compose.ui.test.assertIsEnabled
import androidx.compose.ui.test.assertIsNotEnabled
+import androidx.compose.ui.test.assertTopPositionInRootIsEqualTo
import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.getUnclippedBoundsInRoot
import androidx.compose.ui.test.junit4.ComposeContentTestRule
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onChild
import androidx.compose.ui.test.onChildAt
+import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
+import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.height
import org.junit.Assert.assertEquals
import org.junit.Rule
import org.junit.Test
@@ -228,6 +234,27 @@
fun gives_base_chip_correct_height() =
verifyHeight(ChipDefaults.Height)
+ @Test
+ fun has_icon_in_correct_location_when_only_single_line_of_text() {
+ val iconTag = "TestIcon"
+ val chipTag = "chip"
+ rule
+ .setContentWithThemeForSizeAssertions(useUnmergedTree = true) {
+ Chip(
+ onClick = {},
+ label = { Text("Blue green orange") },
+ icon = { CreateImage(iconTag) },
+ modifier = Modifier.testTag(chipTag)
+ )
+ }
+ val itemBounds = rule.onNodeWithTag(chipTag).getUnclippedBoundsInRoot()
+ val iconBounds = rule.onNodeWithTag(iconTag, useUnmergedTree = true)
+ .getUnclippedBoundsInRoot()
+
+ rule.onNodeWithContentDescription(iconTag, useUnmergedTree = true)
+ .assertTopPositionInRootIsEqualTo((itemBounds.height - iconBounds.height) / 2)
+ }
+
private fun verifyHeight(expectedHeight: Dp) {
rule.verifyHeight(expectedHeight) {
Chip(
@@ -254,6 +281,17 @@
)
@Test
+ fun three_slot_layout_gives_primary_enabled_colors() =
+ verifyThreeSlotColors(
+ TestChipColors.Primary,
+ ChipStatus.Enabled,
+ { MaterialTheme.colors.primary },
+ { MaterialTheme.colors.onPrimary },
+ { MaterialTheme.colors.onPrimary },
+ { MaterialTheme.colors.onPrimary }
+ )
+
+ @Test
fun gives_primary_disabled_colors() =
verifyColors(
TestChipColors.Primary,
@@ -263,6 +301,17 @@
)
@Test
+ fun three_slot_layout_gives_primary_disabled_colors() =
+ verifyThreeSlotColors(
+ TestChipColors.Primary,
+ ChipStatus.Disabled,
+ { MaterialTheme.colors.primary },
+ { MaterialTheme.colors.onPrimary },
+ { MaterialTheme.colors.onPrimary },
+ { MaterialTheme.colors.onPrimary }
+ )
+
+ @Test
fun gives_secondary_enabled_colors() =
verifyColors(
TestChipColors.Secondary,
@@ -272,6 +321,17 @@
)
@Test
+ fun three_slot_layout_gives_secondary_enabled_colors() =
+ verifyThreeSlotColors(
+ TestChipColors.Secondary,
+ ChipStatus.Enabled,
+ { MaterialTheme.colors.surface },
+ { MaterialTheme.colors.onSurface },
+ { MaterialTheme.colors.onSurface },
+ { MaterialTheme.colors.onSurface }
+ )
+
+ @Test
fun gives_secondary_disabled_colors() =
verifyColors(
TestChipColors.Secondary,
@@ -281,6 +341,17 @@
)
@Test
+ fun three_slot_layout_gives_secondary_disabled_colors() =
+ verifyThreeSlotColors(
+ TestChipColors.Secondary,
+ ChipStatus.Enabled,
+ { MaterialTheme.colors.surface },
+ { MaterialTheme.colors.onSurface },
+ { MaterialTheme.colors.onSurface },
+ { MaterialTheme.colors.onSurface }
+ )
+
+ @Test
fun allows_custom_enabled_background_color_override() {
val overrideColor = Color.Yellow
rule.setContentWithTheme {
@@ -344,6 +415,60 @@
}
@Test
+ fun allows_custom_enabled_secondary_label_color_override() {
+ val overrideColor = Color.Red
+ var actualContentColor = Color.Transparent
+ var actualSecondaryContentColor = Color.Transparent
+ var expectedContent = Color.Transparent
+ rule.setContentWithTheme {
+ expectedContent = MaterialTheme.colors.onPrimary
+ Chip(
+ onClick = {},
+ colors = ChipDefaults.chipColors(
+ secondaryContentColor = overrideColor
+ ),
+ label = {
+ actualContentColor = LocalContentColor.current
+ },
+ secondaryLabel = {
+ actualSecondaryContentColor = LocalContentColor.current
+ },
+ enabled = true,
+ modifier = Modifier.testTag("test-item")
+ )
+ }
+ assertEquals(expectedContent, actualContentColor)
+ assertEquals(overrideColor, actualSecondaryContentColor)
+ }
+
+ @Test
+ fun allows_custom_enabled_icon_tint_color_override() {
+ val overrideColor = Color.Red
+ var actualContentColor = Color.Transparent
+ var actualIconTintColor = Color.Transparent
+ var expectedContent = Color.Transparent
+ rule.setContentWithTheme {
+ expectedContent = MaterialTheme.colors.onPrimary
+ Chip(
+ onClick = {},
+ colors = ChipDefaults.chipColors(
+ iconTintColor = overrideColor
+ ),
+ label = {
+ actualContentColor = LocalContentColor.current
+ },
+ icon = {
+ actualIconTintColor = LocalContentColor.current
+ },
+ enabled = true,
+ modifier = Modifier.testTag("test-item")
+ )
+ }
+ assertEquals(expectedContent, actualContentColor)
+ assertEquals(overrideColor, actualIconTintColor)
+ }
+
+ @Test
fun allows_custom_disabled_content_color_override() {
val overrideColor = Color.Yellow
var actualContentColor = Color.Transparent
@@ -406,6 +531,114 @@
.assertContainsColor(expectedBackground, 50.0f)
}
}
+
+ private fun verifyThreeSlotColors(
+ testChipColors: TestChipColors,
+ status: ChipStatus,
+ backgroundColor: @Composable () -> Color,
+ contentColor: @Composable () -> Color,
+ secondaryContentColor: @Composable () -> Color,
+ iconColor: @Composable () -> Color
+ ) {
+ var expectedBackground = Color.Transparent
+ var expectedContent = Color.Transparent
+ var expectedSecondaryContent = Color.Transparent
+ var expectedIcon = Color.Transparent
+ var actualContent = Color.Transparent
+ var actualSecondaryContent = Color.Transparent
+ var actualIcon = Color.Transparent
+ var expectedAlpha = 0.0f
+
+ rule.setContentWithTheme {
+ expectedBackground = backgroundColor()
+ expectedContent = contentColor()
+ expectedSecondaryContent = secondaryContentColor()
+ expectedIcon = iconColor()
+ expectedAlpha = ContentAlpha.disabled
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(expectedBackground)
+ ) {
+ Chip(
+ onClick = {},
+ colors = testChipColors.chipColors(),
+ label = { actualContent = LocalContentColor.current },
+ secondaryLabel = { actualSecondaryContent = LocalContentColor.current },
+ icon = { actualIcon = LocalContentColor.current },
+ enabled = status.enabled(),
+ modifier = Modifier.testTag("test-item")
+ )
+ }
+ }
+
+ if (status.enabled()) {
+ assertEquals(expectedContent, actualContent)
+ assertEquals(expectedSecondaryContent, actualSecondaryContent)
+ assertEquals(expectedIcon, actualIcon)
+ } else {
+ assertEquals(expectedContent.copy(alpha = expectedAlpha), actualContent)
+ assertEquals(
+ expectedSecondaryContent.copy(alpha = expectedAlpha),
+ actualSecondaryContent
+ )
+ assertEquals(expectedIcon.copy(alpha = expectedAlpha), actualIcon)
+ }
+
+ if (expectedBackground != Color.Transparent) {
+ rule.onNodeWithTag("test-item").onChildAt(0)
+ .captureToImage()
+ .assertContainsColor(expectedBackground, 50.0f)
+ }
+ }
+}
+
+class ChipFontTest {
+ @get:Rule
+ val rule = createComposeRule()
+
+ @Test
+ fun gives_correct_text_style_base() {
+ var actualTextStyle = TextStyle.Default
+ var expectedTextStyle = TextStyle.Default
+ rule.setContentWithTheme {
+ expectedTextStyle = MaterialTheme.typography.button
+ Chip(
+ onClick = {},
+ colors = ChipDefaults.primaryChipColors(),
+ content = {
+ actualTextStyle = LocalTextStyle.current
+ },
+ enabled = true,
+ modifier = Modifier.testTag("test-item")
+ )
+ }
+ assertEquals(expectedTextStyle, actualTextStyle)
+ }
+
+ @Test
+ fun gives_correct_text_style_three_slot_chip() {
+ var actualLabelTextStyle = TextStyle.Default
+ var actualSecondaryLabelTextStyle = TextStyle.Default
+ var expectedTextStyle = TextStyle.Default
+ rule.setContentWithTheme {
+ expectedTextStyle = MaterialTheme.typography.button
+ Chip(
+ onClick = {},
+ colors = ChipDefaults.primaryChipColors(),
+ label = {
+ actualLabelTextStyle = LocalTextStyle.current
+ },
+ secondaryLabel = {
+ actualSecondaryLabelTextStyle = LocalTextStyle.current
+ },
+ enabled = true,
+ modifier = Modifier.testTag("test-item")
+ )
+ }
+ assertEquals(expectedTextStyle, actualLabelTextStyle)
+ assertEquals(expectedTextStyle, actualSecondaryLabelTextStyle)
+ }
}
private fun ComposeContentTestRule.verifyHeight(expected: Dp, content: @Composable () -> Unit) {
diff --git a/wear/compose/material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/MaterialTest.kt b/wear/compose/material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/MaterialTest.kt
index d79bd27..5f4fb02 100644
--- a/wear/compose/material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/MaterialTest.kt
+++ b/wear/compose/material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/MaterialTest.kt
@@ -19,16 +19,19 @@
import android.util.Log
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.sizeIn
import androidx.compose.material.Surface
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Add
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.graphics.ImageBitmap
import androidx.compose.ui.graphics.asAndroidBitmap
import androidx.compose.ui.graphics.toPixelMap
+import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.semantics.SemanticsActions
import androidx.compose.ui.test.SemanticsNodeInteraction
@@ -110,9 +113,13 @@
@Composable
fun CreateImage(iconLabel: String = "TestIcon") {
val testImage = Icons.Outlined.Add
- Image(testImage, iconLabel)
+ Image(
+ testImage, iconLabel,
+ modifier = Modifier.fillMaxSize().testTag(iconLabel),
+ contentScale = ContentScale.Fit,
+ alignment = Alignment.Center
+ )
}
-
/**
* assertContainsColor - uses a threshold on an ImageBitmap's color distribution
* to check that a UI element is predominantly the expected color.
diff --git a/wear/compose/material/src/androidMain/kotlin/androidx/wear/compose/material/Chip.kt b/wear/compose/material/src/androidMain/kotlin/androidx/wear/compose/material/Chip.kt
deleted file mode 100644
index f4f85c0..0000000
--- a/wear/compose/material/src/androidMain/kotlin/androidx/wear/compose/material/Chip.kt
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.wear.compose.material
-
-import androidx.compose.foundation.Indication
-import androidx.compose.foundation.LocalIndication
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.interaction.MutableInteractionSource
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
-import androidx.compose.material.ContentAlpha
-import androidx.compose.material.Surface
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.runtime.Immutable
-import androidx.compose.runtime.Stable
-import androidx.compose.runtime.State
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.rememberUpdatedState
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.paint
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.Shape
-import androidx.compose.ui.graphics.painter.ColorPainter
-import androidx.compose.ui.graphics.painter.Painter
-import androidx.compose.ui.semantics.Role
-import androidx.compose.ui.unit.dp
-
-/**
- * The most basic chip that provides a single content slot, used as the building block for other
- * chips.
- */
-@Composable
-fun Chip(
- onClick: () -> Unit,
- colors: ChipColors,
- modifier: Modifier = Modifier,
- enabled: Boolean = true,
- onClickLabel: String? = null,
- contentPadding: PaddingValues = ChipDefaults.ContentPadding,
- shape: Shape = MaterialTheme.shapes.small,
- interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
- indication: Indication? = LocalIndication.current,
- role: Role? = Role.Button,
- content: @Composable () -> Unit,
-) {
- Surface(
- modifier = modifier
- .height(ChipDefaults.Height),
- color = Color.Transparent,
- shape = shape,
- ) {
- // TODO: Due to b/178201337 the paint() modifier on the box doesn't make a call to draw the
- // box contents. As a result we need to have stacked boxes to enable us to paint the
- // background
- val painterModifier =
- Modifier
- .paint(
- painter = colors.background(enabled = enabled).value,
- )
-
- val contentBoxModifier = Modifier
- .clickable(
- enabled = enabled,
- onClickLabel = onClickLabel,
- onClick = onClick,
- role = role,
- indication = indication,
- interactionSource = interactionSource,
- )
- .padding(contentPadding)
-
- Box(
- modifier = painterModifier
- ) { }
- Box(
- modifier = contentBoxModifier
- ) {
- CompositionLocalProvider(
- LocalContentColor provides colors.contentColor(enabled = enabled).value,
- content = content
- )
- }
- }
-}
-
-/**
- * Represents the background and content colors used in a chip in different states.
- *
- * See [ChipDefaults.primaryChipColors] for the default colors used in a primary styled [Chip].
- * See [ChipDefaults.secondaryChipColors] for the default colors used in a secondary styled [Chip].
- */
-@Stable
-interface ChipColors {
- @Composable
- fun background(enabled: Boolean): State<Painter>
-
- /**
- * Represents the content color for this chip, depending on [enabled].
- *
- * @param enabled whether the chip is enabled
- */
- @Composable
- fun contentColor(enabled: Boolean): State<Color>
-
- /**
- * Represents the secondary content color for this chip, depending on [enabled].
- *
- * @param enabled whether the chip is enabled
- */
- @Composable
- fun secondaryContentColor(enabled: Boolean): State<Color>
-
- /**
- * Represents the icon tint color for this chip, depending on [enabled].
- */
- @Composable
- fun iconTintColor(enabled: Boolean): State<Color>
-}
-
-/**
- * Contains the default values used by [Chip]
- */
-public object ChipDefaults {
-
- @Composable
- public fun primaryChipColors(
- backgroundColor: Color = MaterialTheme.colors.primary,
- contentColor: Color = contentColorFor(backgroundColor)
- ): ChipColors {
- return chipColors(
- backgroundColor = backgroundColor,
- contentColor = contentColor
- )
- }
-
- @Composable
- public fun secondaryChipColors(
- backgroundColor: Color = MaterialTheme.colors.surface,
- contentColor: Color = contentColorFor(backgroundColor)
- ): ChipColors {
- return chipColors(
- backgroundColor = backgroundColor,
- contentColor = contentColor
- )
- }
-
- private val ChipHorizontalPadding = 16.dp
- private val ChipVerticalPadding = 6.dp
-
- /**
- * The default content padding used by [Chip]
- */
- public val ContentPadding = PaddingValues(
- start = ChipHorizontalPadding,
- top = ChipVerticalPadding,
- end = ChipHorizontalPadding,
- bottom = ChipVerticalPadding
- )
-
- /**
- * The default height applied for the [Chip].
- * Note that you can override it by applying Modifier.heightIn directly on [Chip].
- */
- internal val Height = 52.dp
-
- /**
- * The default size of the icon when used inside a [Chip].
- */
- internal val IconSize = 24.dp
-
- /**
- * The default size of the spacing between an icon and a text when they used inside a [Chip].
- */
- internal val IconSpacing = 8.dp
-
- /**
- * Creates a [ChipColors] that represents the default background and content colors used in
- * a [Chip].
- *
- * @param backgroundColor the background color of this [Chip] when enabled
- * @param contentColor the content color of this [Chip] when enabled
- * @param secondaryContentColor the content color of this [Chip] when enabled
- * @param iconTintColor the content color of this [Chip] when enabled
- * @param disabledBackgroundColor the background color of this [Chip] when not enabled
- * @param disabledContentColor the content color of this [Chip] when not enabled
- * @param disabledSecondaryContentColor the content color of this [Chip] when not enabled
- * @param disabledIconTintColor the content color of this [Chip] when not enabled
- */
- @Composable
- fun chipColors(
- backgroundColor: Color = MaterialTheme.colors.primary,
- contentColor: Color = contentColorFor(backgroundColor),
- secondaryContentColor: Color = contentColor,
- iconTintColor: Color = contentColor,
- disabledBackgroundColor: Color = backgroundColor.copy(alpha = ContentAlpha.disabled),
- disabledContentColor: Color = contentColor.copy(alpha = ContentAlpha.disabled),
- disabledSecondaryContentColor: Color =
- secondaryContentColor.copy(alpha = ContentAlpha.disabled),
- disabledIconTintColor: Color = disabledContentColor,
- ): ChipColors = DefaultChipColors(
- backgroundColor = backgroundColor,
- contentColor = contentColor,
- secondaryContentColor = secondaryContentColor,
- iconTintColor = iconTintColor,
- disabledBackgroundColor = disabledBackgroundColor,
- disabledContentColor = disabledContentColor,
- disabledSecondaryContentColor = disabledSecondaryContentColor,
- disabledIconTintColor = disabledIconTintColor,
- )
-}
-
-/**
- * Default [ChipColors] implementation.
- */
-@Immutable
-private class DefaultChipColors(
- private val backgroundColor: Color,
- private val contentColor: Color,
- private val secondaryContentColor: Color,
- private val iconTintColor: Color,
- private val disabledBackgroundColor: Color,
- private val disabledContentColor: Color,
- private val disabledSecondaryContentColor: Color,
- private val disabledIconTintColor: Color,
-) : ChipColors {
- @Composable
- override fun background(enabled: Boolean): State<Painter> {
- return rememberUpdatedState(
- if (enabled) ColorPainter(backgroundColor) else ColorPainter(disabledBackgroundColor)
- )
- }
-
- @Composable
- override fun contentColor(enabled: Boolean): State<Color> {
- return rememberUpdatedState(
- if (enabled) contentColor else disabledContentColor
- )
- }
-
- @Composable
- override fun secondaryContentColor(enabled: Boolean): State<Color> {
- return rememberUpdatedState(
- if (enabled) secondaryContentColor else disabledSecondaryContentColor
- )
- }
-
- @Composable
- override fun iconTintColor(enabled: Boolean): State<Color> {
- return rememberUpdatedState(if (enabled) iconTintColor else disabledIconTintColor)
- }
-
- override fun equals(other: Any?): Boolean {
- if (this === other) return true
- if (javaClass != other?.javaClass) return false
-
- other as DefaultChipColors
-
- if (backgroundColor != other.backgroundColor) return false
- if (contentColor != other.contentColor) return false
- if (secondaryContentColor != other.secondaryContentColor) return false
- if (iconTintColor != other.iconTintColor) return false
- if (disabledBackgroundColor != other.disabledBackgroundColor) return false
- if (disabledContentColor != other.disabledContentColor) return false
- if (disabledSecondaryContentColor != other.disabledSecondaryContentColor) return false
- if (disabledIconTintColor != other.disabledIconTintColor) return false
-
- return true
- }
-
- override fun hashCode(): Int {
- var result = backgroundColor.hashCode()
- result = 31 * result + contentColor.hashCode()
- result = 31 * result + secondaryContentColor.hashCode()
- result = 31 * result + iconTintColor.hashCode()
- result = 31 * result + disabledBackgroundColor.hashCode()
- result = 31 * result + disabledContentColor.hashCode()
- result = 31 * result + disabledSecondaryContentColor.hashCode()
- result = 31 * result + disabledIconTintColor.hashCode()
- return result
- }
-}
diff --git a/wear/compose/material/src/commonMain/kotlin/androidx/wear/compose/material/Chip.kt b/wear/compose/material/src/commonMain/kotlin/androidx/wear/compose/material/Chip.kt
new file mode 100644
index 0000000..f2b9c62
--- /dev/null
+++ b/wear/compose/material/src/commonMain/kotlin/androidx/wear/compose/material/Chip.kt
@@ -0,0 +1,505 @@
+/*
+ * 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.material
+
+import androidx.compose.foundation.Indication
+import androidx.compose.foundation.LocalIndication
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.material.ContentAlpha
+import androidx.compose.material.Surface
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.Immutable
+import androidx.compose.runtime.Stable
+import androidx.compose.runtime.State
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberUpdatedState
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.paint
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.graphics.painter.ColorPainter
+import androidx.compose.ui.graphics.painter.Painter
+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.unit.dp
+
+/**
+ * Base level Wear Material [Chip] that offers a single slot to take any content.
+ *
+ * Is used as the container for more opinionated [Chip] components that take specific content such
+ * as icons and labels.
+ *
+ * The [Chip] is Stadium shaped and has a max height designed to take no more than two lines of text
+ * of [Typography.button] style. The [Chip] can have an icon or image horizontally
+ * parallel to the two lines of text.
+ *
+ * The [Chip] can have different styles with configurable content colors, background colors
+ * including gradients, these are provided by [ChipColors] implementations.
+ *
+ * The recommended set of [ChipColors] styles can be obtained from [ChipDefaults], e.g.
+ * [ChipDefaults.primaryChipColors] to get a color scheme for a primary [Chip] which by default
+ * will have a solid background of [Colors.primary] and content color of
+ * [Colors.onPrimary].
+ *
+ * Chips can be enabled or disabled. A disabled chip will not respond to click events.
+ *
+ * @param onClick Will be called when the user clicks the chip
+ * @param colors [ChipColors] that will be used to resolve the background and content color for
+ * this chip in different states. See [ChipDefaults.chipColors].
+ * @param modifier Modifier to be applied to the chip
+ * @param enabled Controls the enabled state of the chip. When `false`, this chip will not
+ * be clickable
+ * @param onClickLabel Semantic / accessibility label for the [onClick] action
+ * @param contentPadding The spacing values to apply internally between the container and the
+ * content
+ * @param shape Defines the chip's shape. It is strongly recommended to use the default as this
+ * shape is a key characteristic of the Wear Material Theme
+ * @param interactionSource The [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this Chip. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this Chip in different [Interaction]s.
+ * @param indication Indication to be shown when surface is pressed. By default, indication from
+ * [LocalIndication] will be used. Pass `null` to show no indication, or current value from
+ * [LocalIndication] to show theme default
+ * @param role The type of user interface element. Accessibility services might use this
+ * to describe the element or do customizations
+ */
+@Composable
+fun Chip(
+ onClick: () -> Unit,
+ colors: ChipColors,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true,
+ onClickLabel: String? = null,
+ contentPadding: PaddingValues = ChipDefaults.ContentPadding,
+ shape: Shape = MaterialTheme.shapes.small,
+ interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+ indication: Indication? = LocalIndication.current,
+ role: Role? = Role.Button,
+ content: @Composable () -> Unit,
+) {
+ Surface(
+ modifier = modifier
+ .height(ChipDefaults.Height),
+ color = Color.Transparent,
+ shape = shape,
+ ) {
+ // TODO: Due to b/178201337 the paint() modifier on the box doesn't make a call to draw the
+ // box contents. As a result we need to have stacked boxes to enable us to paint the
+ // background
+ val painterModifier =
+ Modifier
+ .paint(
+ painter = colors.background(enabled = enabled).value,
+ )
+
+ val contentBoxModifier = Modifier
+ .clickable(
+ enabled = enabled,
+ onClickLabel = onClickLabel,
+ onClick = onClick,
+ role = role,
+ indication = indication,
+ interactionSource = interactionSource,
+ )
+ .padding(contentPadding)
+
+ Box(
+ modifier = painterModifier
+ ) { }
+ Box(
+ modifier = contentBoxModifier
+ ) {
+ CompositionLocalProvider(
+ LocalContentColor provides colors.contentColor(enabled = enabled).value,
+ LocalTextStyle provides MaterialTheme.typography.button,
+ content = content
+ )
+ }
+ }
+}
+
+/**
+ * Wear Material [Chip] that offers three slots and a specific layout for an icon, label and
+ * secondaryLabel. The icon and secondaryLabel are optional. The items are laid out with the icon,
+ * if provided, a the start of a row, with a column next containing the two label slots.
+ *
+ * The [Chip] is Stadium shaped and has a max height designed to take no more than two lines of text
+ * of [Typography.button] style. If no secondary label is provided then the label
+ * can be two lines of text. The label and secondary label should be consistently aligned.
+ *
+ * If a icon is provided then the labels should be "start" aligned, e.g. left aligned in ltr so that
+ * the text starts next to the icon.
+ *
+ * The [Chip] can have different styles with configurable content colors, background colors
+ * including gradients, these are provided by [ChipColors] implementations.
+ *
+ * The recommended set of [ChipColors] styles can be obtained from [ChipDefaults], e.g.
+ * [ChipDefaults.primaryChipColors] to get a color scheme for a primary [Chip] which by default
+ * will have a solid background of [Colors.primary] and content color of
+ * [Colors.onPrimary].
+ *
+ * Chips can be enabled or disabled. A disabled chip will not respond to click events.
+ *
+ * @param label A slot for providing the chips main label. The contents are expected to be text
+ * which is "start" aligned if there is an icon preset and "start" or "center" aligned if not.
+ * @param onClick Will be called when the user clicks the chip
+ * @param modifier Modifier to be applied to the chip
+ * @param secondaryLabel A slot for providing the chips secondary label. The contents are expected
+ * to be text which is "start" aligned if there is an icon preset and "start" or "center" aligned if
+ * not. label and secondaryLabel contents should be consistently aligned.
+ * @param colors [ChipColors] that will be used to resolve the background and content color for
+ * this chip in different states. See [ChipDefaults.chipColors]. Defaults to
+ * [ChipDefaults.primaryChipColors]
+ * @param enabled Controls the enabled state of the chip. When `false`, this chip will not
+ * be clickable
+ * @param onClickLabel Semantic / accessibility label for the [onClick] action
+ * @param interactionSource The [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this Chip. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this Chip in different [Interaction]s.
+ * @param indication Indication to be shown when surface is pressed. By default, indication from
+ * [LocalIndication] will be used. Pass `null` to show no indication, or current value from
+ * [LocalIndication] to show theme default
+ * @param contentPadding The spacing values to apply internally between the container and the
+ * content
+ */
+@Composable
+fun Chip(
+ label: @Composable () -> Unit,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ secondaryLabel: (@Composable () -> Unit)? = null,
+ icon: (@Composable () -> Unit)? = null,
+ colors: ChipColors = ChipDefaults.primaryChipColors(),
+ enabled: Boolean = true,
+ onClickLabel: String? = null,
+ interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+ indication: Indication? = LocalIndication.current,
+ contentPadding: PaddingValues = ChipDefaults.contentPadding(icon != null),
+) {
+ Chip(
+ onClick = onClick,
+ colors = colors,
+ modifier = modifier,
+ enabled = enabled,
+ onClickLabel = onClickLabel,
+ interactionSource = interactionSource,
+ indication = indication,
+ contentPadding = contentPadding
+ ) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier.fillMaxSize()
+ ) {
+ if (icon != null) {
+ Box(
+ modifier = Modifier.wrapContentSize(align = Alignment.Center)
+ ) {
+ CompositionLocalProvider(
+ LocalContentColor provides colors.iconTintColor(enabled).value,
+ content = icon
+ )
+ }
+ Spacer(modifier = Modifier.size(ChipDefaults.IconSpacing))
+ }
+ Column {
+ CompositionLocalProvider(
+ LocalContentColor provides colors.contentColor(enabled).value,
+ LocalTextStyle provides MaterialTheme.typography.button,
+ content = label
+ )
+ if (secondaryLabel != null) {
+ CompositionLocalProvider(
+ LocalContentColor provides colors.secondaryContentColor(enabled).value,
+ LocalTextStyle provides MaterialTheme.typography.button,
+ content = secondaryLabel
+ )
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Represents the background and content colors used in a chip in different states.
+ *
+ * See [ChipDefaults.primaryChipColors] for the default colors used in a primary styled [Chip].
+ * See [ChipDefaults.secondaryChipColors] for the default colors used in a secondary styled [Chip].
+ */
+@Stable
+interface ChipColors {
+ /**
+ * Represents the background treatment for this chip, depending on [enabled]. Backgrounds can
+ * be solid, transparent or have a gradient applied.
+ *
+ * @param enabled Whether the chip is enabled
+ */
+ @Composable
+ fun background(enabled: Boolean): State<Painter>
+
+ /**
+ * Represents the content color for this chip, depending on [enabled].
+ *
+ * @param enabled Whether the chip is enabled
+ */
+ @Composable
+ fun contentColor(enabled: Boolean): State<Color>
+
+ /**
+ * Represents the secondary content color for this chip, depending on [enabled].
+ *
+ * @param enabled Whether the chip is enabled
+ */
+ @Composable
+ fun secondaryContentColor(enabled: Boolean): State<Color>
+
+ /**
+ * Represents the icon tint color for this chip, depending on [enabled].
+ *
+ * @param enabled Whether the chip is enabled
+ */
+ @Composable
+ fun iconTintColor(enabled: Boolean): State<Color>
+}
+
+/**
+ * Contains the default values used by [Chip]
+ */
+public object ChipDefaults {
+
+ /**
+ * Creates a [ChipColors] that represents the default background and content colors for a
+ * primary [Chip]. Primary chips have a colored background with a contrasting content color. If
+ * a chip is disabled then the color will have an alpha([ContentAlpha.disabled]) value applied.
+ *
+ * @param backgroundColor The background color of this [Chip] when enabled
+ * @param contentColor The content color of this [Chip] when enabled
+ */
+ @Composable
+ public fun primaryChipColors(
+ backgroundColor: Color = MaterialTheme.colors.primary,
+ contentColor: Color = contentColorFor(backgroundColor)
+ ): ChipColors {
+ return chipColors(
+ backgroundColor = backgroundColor,
+ contentColor = contentColor
+ )
+ }
+
+ /**
+ * Creates a [ChipColors] that represents the default background and content colors for a
+ * secondary [Chip]. Secondary chips have a muted background with a contrasting content color.
+ * If a chip is disabled then the color will have an alpha([ContentAlpha.disabled]) value
+ * applied.
+ *
+ * @param backgroundColor The background color of this [Chip] when enabled
+ * @param contentColor The content color of this [Chip] when enabled
+ */
+ @Composable
+ public fun secondaryChipColors(
+ backgroundColor: Color = MaterialTheme.colors.surface,
+ contentColor: Color = contentColorFor(backgroundColor)
+ ): ChipColors {
+ return chipColors(
+ backgroundColor = backgroundColor,
+ contentColor = contentColor
+ )
+ }
+
+ private val ChipHorizontalPadding = 16.dp
+ private val ChipWithIconHorizontalPadding = 12.dp
+ private val ChipVerticalPadding = 6.dp
+
+ /**
+ * Creates a [PaddingValues] for a [Chip] based on whether the chip has a icon. For chips with
+ * icons a smaller start and end padding are applied to compensate for the space that the icon
+ * consumes.
+ *
+ * @param hasIcon Whether the [Chip] has an icon.
+ */
+ public fun contentPadding(
+ hasIcon: Boolean
+ ): PaddingValues {
+ return if (hasIcon) ContentWithIconPadding else ContentPadding
+ }
+
+ /**
+ * The default content padding used by [Chip]
+ */
+ public val ContentPadding = PaddingValues(
+ start = ChipHorizontalPadding,
+ top = ChipVerticalPadding,
+ end = ChipHorizontalPadding,
+ bottom = ChipVerticalPadding
+ )
+
+ /**
+ * The content padding used by a [Chip] which includes an icon
+ */
+ public val ContentWithIconPadding = PaddingValues(
+ start = ChipWithIconHorizontalPadding,
+ top = ChipVerticalPadding,
+ end = ChipWithIconHorizontalPadding,
+ bottom = ChipVerticalPadding
+ )
+
+ /**
+ * The default height applied for the [Chip].
+ * Note that you can override it by applying Modifier.heightIn directly on [Chip].
+ */
+ internal val Height = 52.dp
+
+ /**
+ * The default size of the icon when used inside a [Chip].
+ */
+ public val IconSize = 24.dp
+
+ /**
+ * The size of the icon when used inside a Large "Avatar" [Chip].
+ */
+ public val LargeIconSize = 32.dp
+
+ /**
+ * The size of the icon when used inside a "Compact" [Chip].
+ */
+ public val SmallIconSize = 20.dp
+
+ /**
+ * The default size of the spacing between an icon and a text when they are used inside a
+ * [Chip].
+ */
+ internal val IconSpacing = 8.dp
+
+ /**
+ * Creates a [ChipColors] that represents the default background and content colors used in
+ * a [Chip].
+ *
+ * @param backgroundColor The background color of this [Chip] when enabled
+ * @param contentColor The content color of this [Chip] when enabled
+ * @param secondaryContentColor The content color of this [Chip] when enabled
+ * @param iconTintColor The content color of this [Chip] when enabled
+ * @param disabledBackgroundColor The background color of this [Chip] when not enabled
+ * @param disabledContentColor The content color of this [Chip] when not enabled
+ * @param disabledSecondaryContentColor The content color of this [Chip] when not enabled
+ * @param disabledIconTintColor The content color of this [Chip] when not enabled
+ */
+ @Composable
+ fun chipColors(
+ backgroundColor: Color = MaterialTheme.colors.primary,
+ contentColor: Color = contentColorFor(backgroundColor),
+ secondaryContentColor: Color = contentColor,
+ iconTintColor: Color = contentColor,
+ disabledBackgroundColor: Color = backgroundColor.copy(alpha = ContentAlpha.disabled),
+ disabledContentColor: Color = contentColor.copy(alpha = ContentAlpha.disabled),
+ disabledSecondaryContentColor: Color =
+ secondaryContentColor.copy(alpha = ContentAlpha.disabled),
+ disabledIconTintColor: Color = disabledContentColor,
+ ): ChipColors = DefaultChipColors(
+ backgroundColor = backgroundColor,
+ contentColor = contentColor,
+ secondaryContentColor = secondaryContentColor,
+ iconTintColor = iconTintColor,
+ disabledBackgroundColor = disabledBackgroundColor,
+ disabledContentColor = disabledContentColor,
+ disabledSecondaryContentColor = disabledSecondaryContentColor,
+ disabledIconTintColor = disabledIconTintColor,
+ )
+}
+
+/**
+ * Default [ChipColors] implementation.
+ */
+@Immutable
+private class DefaultChipColors(
+ private val backgroundColor: Color,
+ private val contentColor: Color,
+ private val secondaryContentColor: Color,
+ private val iconTintColor: Color,
+ private val disabledBackgroundColor: Color,
+ private val disabledContentColor: Color,
+ private val disabledSecondaryContentColor: Color,
+ private val disabledIconTintColor: Color,
+) : ChipColors {
+ @Composable
+ override fun background(enabled: Boolean): State<Painter> {
+ return rememberUpdatedState(
+ if (enabled) ColorPainter(backgroundColor) else ColorPainter(disabledBackgroundColor)
+ )
+ }
+
+ @Composable
+ override fun contentColor(enabled: Boolean): State<Color> {
+ return rememberUpdatedState(
+ if (enabled) contentColor else disabledContentColor
+ )
+ }
+
+ @Composable
+ override fun secondaryContentColor(enabled: Boolean): State<Color> {
+ return rememberUpdatedState(
+ if (enabled) secondaryContentColor else disabledSecondaryContentColor
+ )
+ }
+
+ @Composable
+ override fun iconTintColor(enabled: Boolean): State<Color> {
+ return rememberUpdatedState(if (enabled) iconTintColor else disabledIconTintColor)
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as DefaultChipColors
+
+ if (backgroundColor != other.backgroundColor) return false
+ if (contentColor != other.contentColor) return false
+ if (secondaryContentColor != other.secondaryContentColor) return false
+ if (iconTintColor != other.iconTintColor) return false
+ if (disabledBackgroundColor != other.disabledBackgroundColor) return false
+ if (disabledContentColor != other.disabledContentColor) return false
+ if (disabledSecondaryContentColor != other.disabledSecondaryContentColor) return false
+ if (disabledIconTintColor != other.disabledIconTintColor) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = backgroundColor.hashCode()
+ result = 31 * result + contentColor.hashCode()
+ result = 31 * result + secondaryContentColor.hashCode()
+ result = 31 * result + iconTintColor.hashCode()
+ result = 31 * result + disabledBackgroundColor.hashCode()
+ result = 31 * result + disabledContentColor.hashCode()
+ result = 31 * result + disabledSecondaryContentColor.hashCode()
+ result = 31 * result + disabledIconTintColor.hashCode()
+ return result
+ }
+}
diff --git a/wear/compose/material/src/androidMain/kotlin/androidx/wear/compose/material/Colors.kt b/wear/compose/material/src/commonMain/kotlin/androidx/wear/compose/material/Colors.kt
similarity index 100%
rename from wear/compose/material/src/androidMain/kotlin/androidx/wear/compose/material/Colors.kt
rename to wear/compose/material/src/commonMain/kotlin/androidx/wear/compose/material/Colors.kt
diff --git a/wear/compose/material/src/androidMain/kotlin/androidx/wear/compose/material/ContentAlpha.kt b/wear/compose/material/src/commonMain/kotlin/androidx/wear/compose/material/ContentAlpha.kt
similarity index 100%
rename from wear/compose/material/src/androidMain/kotlin/androidx/wear/compose/material/ContentAlpha.kt
rename to wear/compose/material/src/commonMain/kotlin/androidx/wear/compose/material/ContentAlpha.kt
diff --git a/wear/compose/material/src/androidMain/kotlin/androidx/wear/compose/material/ContentColor.kt b/wear/compose/material/src/commonMain/kotlin/androidx/wear/compose/material/ContentColor.kt
similarity index 100%
rename from wear/compose/material/src/androidMain/kotlin/androidx/wear/compose/material/ContentColor.kt
rename to wear/compose/material/src/commonMain/kotlin/androidx/wear/compose/material/ContentColor.kt
diff --git a/wear/compose/material/src/androidMain/kotlin/androidx/wear/compose/material/MaterialTextSelectionColors.kt b/wear/compose/material/src/commonMain/kotlin/androidx/wear/compose/material/MaterialTextSelectionColors.kt
similarity index 100%
rename from wear/compose/material/src/androidMain/kotlin/androidx/wear/compose/material/MaterialTextSelectionColors.kt
rename to wear/compose/material/src/commonMain/kotlin/androidx/wear/compose/material/MaterialTextSelectionColors.kt
diff --git a/wear/compose/material/src/androidMain/kotlin/androidx/wear/compose/material/MaterialTheme.kt b/wear/compose/material/src/commonMain/kotlin/androidx/wear/compose/material/MaterialTheme.kt
similarity index 100%
rename from wear/compose/material/src/androidMain/kotlin/androidx/wear/compose/material/MaterialTheme.kt
rename to wear/compose/material/src/commonMain/kotlin/androidx/wear/compose/material/MaterialTheme.kt
diff --git a/wear/compose/material/src/androidMain/kotlin/androidx/wear/compose/material/Shapes.kt b/wear/compose/material/src/commonMain/kotlin/androidx/wear/compose/material/Shapes.kt
similarity index 100%
rename from wear/compose/material/src/androidMain/kotlin/androidx/wear/compose/material/Shapes.kt
rename to wear/compose/material/src/commonMain/kotlin/androidx/wear/compose/material/Shapes.kt
diff --git a/wear/compose/material/src/androidMain/kotlin/androidx/wear/compose/material/Typography.kt b/wear/compose/material/src/commonMain/kotlin/androidx/wear/compose/material/Typography.kt
similarity index 100%
rename from wear/compose/material/src/androidMain/kotlin/androidx/wear/compose/material/Typography.kt
rename to wear/compose/material/src/commonMain/kotlin/androidx/wear/compose/material/Typography.kt
diff --git a/wear/tiles/tiles-proto/build.gradle b/wear/tiles/tiles-proto/build.gradle
index f1b0186..8aceec1 100644
--- a/wear/tiles/tiles-proto/build.gradle
+++ b/wear/tiles/tiles-proto/build.gradle
@@ -14,13 +14,12 @@
* limitations under the License.
*/
-import androidx.build.LibraryVersions
-import androidx.build.RunApiTasks
-
-import static androidx.build.dependencies.DependenciesKt.*
import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
import androidx.build.Publish
+import androidx.build.RunApiTasks
import androidx.build.shadow.AndroidXDontIncludeResourceTransformer
+import static androidx.build.dependencies.DependenciesKt.PROTOBUF_COMPILER
plugins {
id("AndroidXPlugin")
@@ -38,7 +37,7 @@
dependencies {
implementation("androidx.annotation:annotation:1.1.0")
- shadowed(PROTOBUF_LITE)
+ shadowed(libs.protobufLite)
}
sourceSets {
@@ -57,9 +56,9 @@
relocate "com.google.protobuf", "androidx.wear.tiles.protobuf"
- // PROTOBUF_LITE ships with a standard set of proto files in the JAR, which clash if this
+ // libs.protobufLite ships with a standard set of proto files in the JAR, which clash if this
// library is included from two different downstream libraries. exclude("*.proto") (or
- // **/*.proto etc etc) doesn't exclude the ones from PROTOBUF_LITE, so take a more heavy handed
+ // **/*.proto etc etc) doesn't exclude the ones from libs.protobufLite, so take a more heavy handed
// approach and use a transformer to strip those files.
// TODO: move back to DontIncludeResourceTransformer.class once Shadow plugin version >6.1.0
transform(AndroidXDontIncludeResourceTransformer.class) {
@@ -82,7 +81,7 @@
protobuf {
protoc {
- artifact = PROTOBUF_COMPILER
+ artifact = PROTOBUF_COMPILER // TODO(b/188537796): Switch this to `libs.protobufCompiler`
}
// Generates the java proto-lite code for the protos in this project. See
diff --git a/wear/tiles/tiles-renderer/build.gradle b/wear/tiles/tiles-renderer/build.gradle
index 622d6c7..ae9634b 100644
--- a/wear/tiles/tiles-renderer/build.gradle
+++ b/wear/tiles/tiles-renderer/build.gradle
@@ -16,8 +16,6 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
-import static androidx.build.dependencies.DependenciesKt.*
-
import androidx.build.LibraryGroups
import androidx.build.LibraryType
import androidx.build.LibraryVersions
@@ -31,32 +29,32 @@
dependencies {
api("androidx.annotation:annotation:1.1.0")
- api(GUAVA_LISTENABLE_FUTURE)
+ api(libs.guavaListenableFuture)
implementation "androidx.concurrent:concurrent-futures:1.1.0"
implementation "androidx.core:core:1.3.2"
implementation(project(":wear:tiles:tiles"))
implementation(project(path: ":wear:tiles:tiles-proto", configuration: "shadow"))
- implementation(KOTLIN_COROUTINES_CORE)
- implementation(KOTLIN_COROUTINES_ANDROID)
+ implementation(libs.kotlinCoroutinesCore)
+ implementation(libs.kotlinCoroutinesAndroid)
androidTestImplementation(project(path: ":wear:tiles:tiles-proto", configuration: "shadow"))
androidTestImplementation(project(":test-screenshot"))
- androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
- androidTestImplementation(ANDROIDX_TEST_CORE)
- androidTestImplementation(ANDROIDX_TEST_RUNNER)
- androidTestImplementation(ANDROIDX_TEST_RULES)
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.testCore)
+ androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.testRules)
androidTestImplementation("com.google.protobuf:protobuf-java:3.10.0")
- testImplementation(ANDROIDX_TEST_EXT_JUNIT)
- testImplementation(ANDROIDX_TEST_EXT_TRUTH)
- testImplementation(ANDROIDX_TEST_CORE)
- testImplementation(ANDROIDX_TEST_RUNNER)
- testImplementation(ANDROIDX_TEST_RULES)
- testImplementation(KOTLIN_COROUTINES_TEST)
- testImplementation(ROBOLECTRIC)
- testImplementation(MOCKITO_CORE)
- testImplementation(TRUTH)
+ testImplementation(libs.testExtJunit)
+ testImplementation(libs.testExtTruth)
+ testImplementation(libs.testCore)
+ testImplementation(libs.testRunner)
+ testImplementation(libs.testRules)
+ testImplementation(libs.kotlinCoroutinesTest)
+ testImplementation(libs.robolectric)
+ testImplementation(libs.mockitoCore)
+ testImplementation(libs.truth)
}
android {
diff --git a/wear/tiles/tiles/build.gradle b/wear/tiles/tiles/build.gradle
index 1856407..cedca9fc 100644
--- a/wear/tiles/tiles/build.gradle
+++ b/wear/tiles/tiles/build.gradle
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-import static androidx.build.dependencies.DependenciesKt.*
-
import androidx.build.LibraryGroups
import androidx.build.LibraryType
import androidx.build.LibraryVersions
@@ -27,21 +25,21 @@
dependencies {
api("androidx.annotation:annotation:1.1.0")
- api(GUAVA_LISTENABLE_FUTURE)
+ api(libs.guavaListenableFuture)
implementation("androidx.annotation:annotation-experimental:1.1.0")
implementation(project(path: ":wear:tiles:tiles-proto", configuration: "shadow"))
- compileOnly(KOTLIN_STDLIB) // For annotation-experimental
+ compileOnly(libs.kotlinStdlib) // For annotation-experimental
- testImplementation(ANDROIDX_TEST_EXT_JUNIT)
- testImplementation(ANDROIDX_TEST_EXT_TRUTH)
- testImplementation(ANDROIDX_TEST_CORE)
- testImplementation(ANDROIDX_TEST_RUNNER)
- testImplementation(ANDROIDX_TEST_RULES)
+ testImplementation(libs.testExtJunit)
+ testImplementation(libs.testExtTruth)
+ testImplementation(libs.testCore)
+ testImplementation(libs.testRunner)
+ testImplementation(libs.testRules)
testImplementation("androidx.concurrent:concurrent-futures:1.1.0")
- testImplementation(ROBOLECTRIC)
- testImplementation(MOCKITO_CORE)
+ testImplementation(libs.robolectric)
+ testImplementation(libs.mockitoCore)
}
android {
diff --git a/wear/wear-complications-data/api/restricted_current.txt b/wear/wear-complications-data/api/restricted_current.txt
index 8463171..4b1188f 100644
--- a/wear/wear-complications-data/api/restricted_current.txt
+++ b/wear/wear-complications-data/api/restricted_current.txt
@@ -165,7 +165,7 @@
property public final java.util.Map<androidx.wear.complications.data.ComplicationType,android.graphics.RectF> perComplicationTypeBounds;
}
- @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final class ComplicationHelperActivity extends android.app.Activity implements androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback {
+ @RequiresApi(android.os.Build.VERSION_CODES.N) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final class ComplicationHelperActivity extends android.app.Activity implements androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback {
ctor public ComplicationHelperActivity();
method public static android.content.Intent createPermissionRequestHelperIntent(android.content.Context, android.content.ComponentName);
method public static android.content.Intent createProviderChooserHelperIntent(android.content.Context, android.content.ComponentName, int, java.util.Collection<androidx.wear.complications.data.ComplicationType!>, String?);
diff --git a/wear/wear-complications-data/build.gradle b/wear/wear-complications-data/build.gradle
index d004c40..0f1ba1b 100644
--- a/wear/wear-complications-data/build.gradle
+++ b/wear/wear-complications-data/build.gradle
@@ -16,7 +16,6 @@
import androidx.build.RunApiTasks
-import static androidx.build.dependencies.DependenciesKt.*
import androidx.build.LibraryGroups
import androidx.build.LibraryVersions
import androidx.build.Publish
@@ -29,23 +28,23 @@
dependencies {
api("androidx.annotation:annotation:1.1.0")
- api(KOTLIN_STDLIB)
- api(KOTLIN_COROUTINES_ANDROID)
+ api(libs.kotlinStdlib)
+ api(libs.kotlinCoroutinesAndroid)
implementation("androidx.core:core:1.1.0")
implementation("androidx.preference:preference:1.1.0")
- testImplementation(ANDROIDX_TEST_CORE)
- testImplementation(ANDROIDX_TEST_RUNNER)
- testImplementation(ANDROIDX_TEST_RULES)
- testImplementation(ROBOLECTRIC)
- testImplementation(MOCKITO_CORE)
- testImplementation(TRUTH)
+ testImplementation(libs.testCore)
+ testImplementation(libs.testRunner)
+ testImplementation(libs.testRules)
+ testImplementation(libs.robolectric)
+ testImplementation(libs.mockitoCore)
+ testImplementation(libs.truth)
testImplementation("junit:junit:4.13")
- androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
- androidTestImplementation(ANDROIDX_TEST_CORE)
- androidTestImplementation(ANDROIDX_TEST_RUNNER)
- androidTestImplementation(ANDROIDX_TEST_RULES)
- androidTestImplementation(TRUTH)
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.testCore)
+ androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.testRules)
+ androidTestImplementation(libs.truth)
}
android {
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 de5f491..10b577e 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
@@ -16,7 +16,6 @@
package androidx.wear.complications;
-import android.annotation.TargetApi;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.ComponentName;
@@ -30,6 +29,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.core.app.ActivityCompat;
import androidx.wear.complications.data.ComplicationType;
@@ -57,7 +57,7 @@
*
* @hide
*/
-@TargetApi(Build.VERSION_CODES.N)
+@RequiresApi(Build.VERSION_CODES.N)
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@SuppressWarnings("ForbiddenSuperClass")
public final class ComplicationHelperActivity extends Activity
diff --git a/wear/wear-complications-provider/build.gradle b/wear/wear-complications-provider/build.gradle
index 60d0420..d56365c 100644
--- a/wear/wear-complications-provider/build.gradle
+++ b/wear/wear-complications-provider/build.gradle
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-import static androidx.build.dependencies.DependenciesKt.*
import androidx.build.LibraryGroups
import androidx.build.LibraryVersions
import androidx.build.Publish
@@ -32,12 +31,12 @@
implementation("androidx.core:core:1.1.0")
implementation("androidx.preference:preference:1.1.0")
- testImplementation(ANDROIDX_TEST_CORE)
- testImplementation(ANDROIDX_TEST_RUNNER)
- testImplementation(ANDROIDX_TEST_RULES)
- testImplementation(ROBOLECTRIC)
- testImplementation(MOCKITO_CORE)
- testImplementation(TRUTH)
+ testImplementation(libs.testCore)
+ testImplementation(libs.testRunner)
+ testImplementation(libs.testRules)
+ testImplementation(libs.robolectric)
+ testImplementation(libs.mockitoCore)
+ testImplementation(libs.truth)
testImplementation("junit:junit:4.13")
}
diff --git a/wear/wear-complications-provider/samples/build.gradle b/wear/wear-complications-provider/samples/build.gradle
index 5115613..4a8fea2 100644
--- a/wear/wear-complications-provider/samples/build.gradle
+++ b/wear/wear-complications-provider/samples/build.gradle
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-import static androidx.build.dependencies.DependenciesKt.*
-
plugins {
id("AndroidXPlugin")
id("com.android.library")
@@ -25,8 +23,8 @@
dependencies {
implementation("androidx.core:core:1.1.0")
api(project(":wear:wear-complications-provider"))
- api(GUAVA_ANDROID)
- api(KOTLIN_STDLIB)
+ api(libs.guavaAndroid)
+ api(libs.kotlinStdlib)
}
android {
diff --git a/wear/wear-input/build.gradle b/wear/wear-input/build.gradle
index c0d602d..b205ac4 100644
--- a/wear/wear-input/build.gradle
+++ b/wear/wear-input/build.gradle
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-import static androidx.build.dependencies.DependenciesKt.*
import androidx.build.LibraryGroups
import androidx.build.LibraryVersions
import androidx.build.Publish
@@ -27,14 +26,14 @@
dependencies {
api("androidx.annotation:annotation:1.1.0")
- api(KOTLIN_STDLIB)
+ api(libs.kotlinStdlib)
- testImplementation(ANDROIDX_TEST_EXT_JUNIT)
- testImplementation(ANDROIDX_TEST_CORE)
- testImplementation(ANDROIDX_TEST_RUNNER)
- testImplementation(ANDROIDX_TEST_RULES)
- testImplementation(ROBOLECTRIC)
- testImplementation(MOCKITO_CORE)
+ testImplementation(libs.testExtJunit)
+ testImplementation(libs.testCore)
+ testImplementation(libs.testRunner)
+ testImplementation(libs.testRules)
+ testImplementation(libs.robolectric)
+ testImplementation(libs.mockitoCore)
testImplementation(project(":wear:wear-input-testing"))
compileOnly(fileTree(dir: "../wear_stubs", include: ["com.google.android.wearable-stubs.jar"]))
diff --git a/wear/wear-ongoing/build.gradle b/wear/wear-ongoing/build.gradle
index 41733c4..cc047e2 100644
--- a/wear/wear-ongoing/build.gradle
+++ b/wear/wear-ongoing/build.gradle
@@ -1,4 +1,3 @@
-import static androidx.build.dependencies.DependenciesKt.*
import androidx.build.LibraryGroups
import androidx.build.LibraryVersions
import androidx.build.Publish
@@ -14,10 +13,10 @@
api("androidx.core:core:1.5.0-alpha04")
api("androidx.versionedparcelable:versionedparcelable:1.1.1")
- testImplementation(KOTLIN_STDLIB)
- testImplementation(ANDROIDX_TEST_CORE)
- testImplementation(ANDROIDX_TEST_RUNNER)
- testImplementation(ROBOLECTRIC)
+ testImplementation(libs.kotlinStdlib)
+ testImplementation(libs.testCore)
+ testImplementation(libs.testRunner)
+ testImplementation(libs.robolectric)
implementation "androidx.core:core-ktx:1.5.0-alpha04"
diff --git a/wear/wear-phone-interactions/build.gradle b/wear/wear-phone-interactions/build.gradle
index b6e4126..de575f6 100644
--- a/wear/wear-phone-interactions/build.gradle
+++ b/wear/wear-phone-interactions/build.gradle
@@ -18,8 +18,6 @@
import androidx.build.LibraryVersions
import androidx.build.Publish
-import static androidx.build.dependencies.DependenciesKt.*
-
plugins {
id("AndroidXPlugin")
id("com.android.library")
@@ -29,15 +27,15 @@
dependencies {
api("androidx.annotation:annotation:1.1.0")
api("androidx.core:core:1.5.0-beta01")
- api(KOTLIN_STDLIB)
+ api(libs.kotlinStdlib)
- testImplementation(ANDROIDX_TEST_CORE)
- testImplementation(ANDROIDX_TEST_EXT_JUNIT)
- testImplementation(ANDROIDX_TEST_RUNNER)
- testImplementation(ANDROIDX_TEST_RULES)
- testImplementation(ROBOLECTRIC)
- testImplementation(MOCKITO_CORE)
- testImplementation(MOCKITO_KOTLIN)
+ testImplementation(libs.testCore)
+ testImplementation(libs.testExtJunit)
+ testImplementation(libs.testRunner)
+ testImplementation(libs.testRules)
+ testImplementation(libs.robolectric)
+ testImplementation(libs.mockitoCore)
+ testImplementation(libs.mockitoKotlin)
}
android {
diff --git a/wear/wear-remote-interactions/build.gradle b/wear/wear-remote-interactions/build.gradle
index 3b5f727..c1a1071 100644
--- a/wear/wear-remote-interactions/build.gradle
+++ b/wear/wear-remote-interactions/build.gradle
@@ -18,8 +18,6 @@
import androidx.build.LibraryVersions
import androidx.build.Publish
-import static androidx.build.dependencies.DependenciesKt.*
-
plugins {
id("AndroidXPlugin")
id("com.android.library")
@@ -28,21 +26,21 @@
dependencies {
api("androidx.annotation:annotation:1.1.0")
- api(KOTLIN_STDLIB)
- androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
- androidTestImplementation(ANDROIDX_TEST_CORE)
- androidTestImplementation(ANDROIDX_TEST_RUNNER)
- androidTestImplementation(ANDROIDX_TEST_RULES)
+ api(libs.kotlinStdlib)
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.testCore)
+ androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.testRules)
androidTestImplementation 'junit:junit:4.12'
- testImplementation(ANDROIDX_TEST_EXT_JUNIT)
- testImplementation(ANDROIDX_TEST_CORE)
- testImplementation(ANDROIDX_TEST_RULES)
- testImplementation(ANDROIDX_TEST_RUNNER)
- testImplementation(ROBOLECTRIC)
- testImplementation(MOCKITO_CORE)
- testImplementation(MOCKITO_KOTLIN)
+ testImplementation(libs.testExtJunit)
+ testImplementation(libs.testCore)
+ testImplementation(libs.testRules)
+ testImplementation(libs.testRunner)
+ testImplementation(libs.robolectric)
+ testImplementation(libs.mockitoCore)
+ testImplementation(libs.mockitoKotlin)
- implementation(PLAY_SERVICES_BASE)
+ implementation(libs.playServicesBase)
}
android {
diff --git a/wear/wear-watchface-client/build.gradle b/wear/wear-watchface-client/build.gradle
index 91ad998..0285903 100644
--- a/wear/wear-watchface-client/build.gradle
+++ b/wear/wear-watchface-client/build.gradle
@@ -16,8 +16,6 @@
import androidx.build.RunApiTasks
-
-import static androidx.build.dependencies.DependenciesKt.*
import androidx.build.LibraryGroups
import androidx.build.LibraryVersions
import androidx.build.Publish
@@ -34,23 +32,23 @@
api(project(":wear:wear-watchface-data"))
api(project(":wear:wear-watchface-style"))
api(project(":wear:wear-complications-data"))
- api(KOTLIN_COROUTINES_ANDROID)
+ api(libs.kotlinCoroutinesAndroid)
androidTestImplementation(project(":test-screenshot"))
androidTestImplementation(project(":wear:wear-watchface-samples"))
- androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
- androidTestImplementation(ANDROIDX_TEST_CORE)
- androidTestImplementation(ANDROIDX_TEST_RUNNER)
- androidTestImplementation(ANDROIDX_TEST_RULES)
- androidTestImplementation(MOCKITO_CORE, excludes.bytebuddy) // DexMaker has it"s own MockMaker
- androidTestImplementation(DEXMAKER_MOCKITO, excludes.bytebuddy) // DexMaker has it"s own MockMaker
- androidTestImplementation(TRUTH)
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.testCore)
+ androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.testRules)
+ androidTestImplementation(libs.mockitoCore, excludes.bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(libs.dexmakerMockito, excludes.bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(libs.truth)
- testImplementation(ANDROIDX_TEST_EXT_JUNIT)
- testImplementation(ANDROIDX_TEST_CORE)
- testImplementation(ANDROIDX_TEST_RULES)
- testImplementation(ROBOLECTRIC)
- testImplementation(TRUTH)
+ testImplementation(libs.testExtJunit)
+ testImplementation(libs.testCore)
+ testImplementation(libs.testRules)
+ testImplementation(libs.robolectric)
+ testImplementation(libs.truth)
implementation("androidx.core:core:1.1.0")
}
diff --git a/wear/wear-watchface-client/guava/build.gradle b/wear/wear-watchface-client/guava/build.gradle
index a751ec3..91f266d 100644
--- a/wear/wear-watchface-client/guava/build.gradle
+++ b/wear/wear-watchface-client/guava/build.gradle
@@ -19,8 +19,6 @@
import androidx.build.LibraryVersions
import androidx.build.Publish
-import static androidx.build.dependencies.DependenciesKt.*
-
plugins {
id("AndroidXPlugin")
id("com.android.library")
@@ -29,17 +27,17 @@
dependencies {
api(project(":wear:wear-watchface-client"))
- api(KOTLIN_COROUTINES_GUAVA)
+ api(libs.kotlinCoroutinesGuava)
implementation("androidx.concurrent:concurrent-futures:1.0.0")
androidTestImplementation project(":wear:wear-watchface-samples")
- androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
- androidTestImplementation(ANDROIDX_TEST_CORE)
- androidTestImplementation(ANDROIDX_TEST_RUNNER)
- androidTestImplementation(ANDROIDX_TEST_RULES)
- androidTestImplementation(MOCKITO_CORE, excludes.bytebuddy) // DexMaker has it"s own MockMaker
- androidTestImplementation(DEXMAKER_MOCKITO, excludes.bytebuddy) // DexMaker has it"s own MockMaker
- androidTestImplementation(TRUTH)
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.testCore)
+ androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.testRules)
+ androidTestImplementation(libs.mockitoCore, excludes.bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(libs.dexmakerMockito, excludes.bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(libs.truth)
}
androidx {
diff --git a/wear/wear-watchface-complications-rendering/build.gradle b/wear/wear-watchface-complications-rendering/build.gradle
index 5a2bfe3..708f68d 100644
--- a/wear/wear-watchface-complications-rendering/build.gradle
+++ b/wear/wear-watchface-complications-rendering/build.gradle
@@ -16,8 +16,6 @@
import androidx.build.RunApiTasks
-
-import static androidx.build.dependencies.DependenciesKt.*
import androidx.build.LibraryGroups
import androidx.build.LibraryVersions
import androidx.build.Publish
@@ -35,16 +33,16 @@
implementation("androidx.core:core:1.1.0")
implementation("androidx.preference:preference:1.1.0")
- androidTestImplementation(ANDROIDX_TEST_CORE)
- androidTestImplementation(ANDROIDX_TEST_RUNNER)
- androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
- androidTestImplementation(TRUTH)
- testImplementation(ANDROIDX_TEST_CORE)
- testImplementation(ANDROIDX_TEST_RUNNER)
- testImplementation(ANDROIDX_TEST_RULES)
- testImplementation(ROBOLECTRIC)
- testImplementation(MOCKITO_CORE)
- testImplementation(TRUTH)
+ androidTestImplementation(libs.testCore)
+ androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.truth)
+ testImplementation(libs.testCore)
+ testImplementation(libs.testRunner)
+ testImplementation(libs.testRules)
+ testImplementation(libs.robolectric)
+ testImplementation(libs.mockitoCore)
+ testImplementation(libs.truth)
testImplementation("junit:junit:4.13")
testImplementation(project(":wear:wear-watchface"))
}
diff --git a/wear/wear-watchface-data/api/restricted_current.txt b/wear/wear-watchface-data/api/restricted_current.txt
index 9090fcf..dc55cb7 100644
--- a/wear/wear-watchface-data/api/restricted_current.txt
+++ b/wear/wear-watchface-data/api/restricted_current.txt
@@ -106,7 +106,7 @@
method public static android.support.wearable.complications.ComplicationText makeTimeAsComplicationText(android.content.Context);
}
- @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final class ContentDescriptionLabel implements android.os.Parcelable {
+ @RequiresApi(android.os.Build.VERSION_CODES.KITKAT) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final class ContentDescriptionLabel implements android.os.Parcelable {
ctor public ContentDescriptionLabel(android.graphics.Rect, android.support.wearable.complications.ComplicationTextTemplate);
ctor public ContentDescriptionLabel(android.graphics.Rect, android.support.wearable.complications.ComplicationText);
ctor public ContentDescriptionLabel(android.content.Context, android.graphics.Rect, android.support.wearable.complications.ComplicationData);
diff --git a/wear/wear-watchface-data/build.gradle b/wear/wear-watchface-data/build.gradle
index b87291a..008d072 100644
--- a/wear/wear-watchface-data/build.gradle
+++ b/wear/wear-watchface-data/build.gradle
@@ -18,8 +18,6 @@
import androidx.build.LibraryVersions
import androidx.build.Publish
-import static androidx.build.dependencies.DependenciesKt.*
-
plugins {
id("AndroidXPlugin")
id("com.android.library")
@@ -30,7 +28,7 @@
api("androidx.annotation:annotation:1.1.0")
api("androidx.versionedparcelable:versionedparcelable:1.1.0")
api(project(":wear:wear-complications-data"))
- api(KOTLIN_STDLIB)
+ api(libs.kotlinStdlib)
implementation("androidx.core:core:1.1.0")
annotationProcessor(project(":versionedparcelable:versionedparcelable-compiler"))
diff --git a/wear/wear-watchface-data/src/main/java/android/support/wearable/watchface/accessibility/ContentDescriptionLabel.java b/wear/wear-watchface-data/src/main/java/android/support/wearable/watchface/accessibility/ContentDescriptionLabel.java
index fbc0738..ddb401f 100644
--- a/wear/wear-watchface-data/src/main/java/android/support/wearable/watchface/accessibility/ContentDescriptionLabel.java
+++ b/wear/wear-watchface-data/src/main/java/android/support/wearable/watchface/accessibility/ContentDescriptionLabel.java
@@ -16,7 +16,6 @@
package android.support.wearable.watchface.accessibility;
-import android.annotation.TargetApi;
import android.app.PendingIntent;
import android.content.Context;
import android.graphics.Rect;
@@ -32,6 +31,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import org.jetbrains.annotations.NotNull;
@@ -43,7 +43,7 @@
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-@TargetApi(VERSION_CODES.KITKAT)
+@RequiresApi(VERSION_CODES.KITKAT)
@SuppressWarnings("BanParcelableUsage")
public final class ContentDescriptionLabel implements Parcelable {
diff --git a/wear/wear-watchface-editor/build.gradle b/wear/wear-watchface-editor/build.gradle
index f226b93..44d6921 100644
--- a/wear/wear-watchface-editor/build.gradle
+++ b/wear/wear-watchface-editor/build.gradle
@@ -18,8 +18,6 @@
import androidx.build.LibraryVersions
import androidx.build.Publish
-import static androidx.build.dependencies.DependenciesKt.*
-
plugins {
id("AndroidXPlugin")
id("com.android.library")
@@ -32,21 +30,21 @@
api("androidx.activity:activity:1.2.0")
api(project(":wear:wear-watchface-client"))
api(project(":wear:wear-watchface-data"))
- api(KOTLIN_STDLIB)
- api(KOTLIN_COROUTINES_ANDROID)
+ api(libs.kotlinStdlib)
+ api(libs.kotlinCoroutinesAndroid)
implementation("androidx.core:core:1.1.0")
androidTestImplementation(project(":wear:wear-watchface-complications-rendering"))
androidTestImplementation(project(":wear:wear-watchface-editor-guava"))
- androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
- androidTestImplementation(ANDROIDX_TEST_CORE)
- androidTestImplementation(ANDROIDX_TEST_RUNNER)
- androidTestImplementation(ANDROIDX_TEST_RULES)
- androidTestImplementation(MOCKITO_CORE, excludes.bytebuddy) // DexMaker has it"s own MockMaker
- androidTestImplementation(DEXMAKER_MOCKITO, excludes.bytebuddy) // DexMaker has it"s own MockMaker
- androidTestImplementation(KOTLIN_COROUTINES_TEST)
- androidTestImplementation(TRUTH)
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.testCore)
+ androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.testRules)
+ androidTestImplementation(libs.mockitoCore, excludes.bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(libs.dexmakerMockito, excludes.bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(libs.kotlinCoroutinesTest)
+ androidTestImplementation(libs.truth)
}
android {
diff --git a/wear/wear-watchface-editor/guava/build.gradle b/wear/wear-watchface-editor/guava/build.gradle
index a11ce0d..e3b65a5 100644
--- a/wear/wear-watchface-editor/guava/build.gradle
+++ b/wear/wear-watchface-editor/guava/build.gradle
@@ -19,8 +19,6 @@
import androidx.build.LibraryVersions
import androidx.build.Publish
-import static androidx.build.dependencies.DependenciesKt.*
-
plugins {
id("AndroidXPlugin")
id("com.android.library")
@@ -29,16 +27,16 @@
dependencies {
api(project(":wear:wear-watchface-editor"))
- api(KOTLIN_COROUTINES_GUAVA)
+ api(libs.kotlinCoroutinesGuava)
implementation("androidx.concurrent:concurrent-futures:1.0.0")
- androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
- androidTestImplementation(ANDROIDX_TEST_CORE)
- androidTestImplementation(ANDROIDX_TEST_RUNNER)
- androidTestImplementation(ANDROIDX_TEST_RULES)
- androidTestImplementation(MOCKITO_CORE, excludes.bytebuddy) // DexMaker has it"s own MockMaker
- androidTestImplementation(DEXMAKER_MOCKITO, excludes.bytebuddy) // DexMaker has it"s own MockMaker
- androidTestImplementation(TRUTH)
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.testCore)
+ androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.testRules)
+ androidTestImplementation(libs.mockitoCore, excludes.bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(libs.dexmakerMockito, excludes.bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(libs.truth)
}
androidx {
diff --git a/wear/wear-watchface-editor/samples/build.gradle b/wear/wear-watchface-editor/samples/build.gradle
index 6ae54c5..382433c 100644
--- a/wear/wear-watchface-editor/samples/build.gradle
+++ b/wear/wear-watchface-editor/samples/build.gradle
@@ -18,8 +18,6 @@
import androidx.build.LibraryType
import androidx.build.LibraryVersions
-import static androidx.build.dependencies.DependenciesKt.*
-
plugins {
id("AndroidXPlugin")
id("com.android.library")
@@ -31,7 +29,7 @@
api("androidx.fragment:fragment:1.3.0")
implementation("androidx.wear:wear:1.1.0-rc01")
api(project(":wear:wear-watchface-editor"))
- api(KOTLIN_STDLIB)
+ api(libs.kotlinStdlib)
}
androidx {
diff --git a/wear/wear-watchface-style/build.gradle b/wear/wear-watchface-style/build.gradle
index 2dc619d..8e708cf 100644
--- a/wear/wear-watchface-style/build.gradle
+++ b/wear/wear-watchface-style/build.gradle
@@ -16,8 +16,6 @@
import androidx.build.RunApiTasks
-
-import static androidx.build.dependencies.DependenciesKt.*
import androidx.build.LibraryGroups
import androidx.build.LibraryVersions
import androidx.build.Publish
@@ -31,17 +29,17 @@
dependencies {
api("androidx.annotation:annotation:1.1.0")
api(project(":wear:wear-watchface-data"))
- api(KOTLIN_STDLIB)
+ api(libs.kotlinStdlib)
implementation("androidx.core:core:1.1.0")
implementation("androidx.preference:preference:1.1.0")
- testImplementation(ANDROIDX_TEST_EXT_JUNIT)
- testImplementation(ANDROIDX_TEST_CORE)
- testImplementation(ANDROIDX_TEST_RULES)
- testImplementation(MOCKITO_CORE)
- testImplementation(ROBOLECTRIC)
- testImplementation(TRUTH)
+ testImplementation(libs.testExtJunit)
+ testImplementation(libs.testCore)
+ testImplementation(libs.testRules)
+ testImplementation(libs.mockitoCore)
+ testImplementation(libs.robolectric)
+ testImplementation(libs.truth)
}
android {
diff --git a/wear/wear-watchface/build.gradle b/wear/wear-watchface/build.gradle
index 340abf2..13f5296 100644
--- a/wear/wear-watchface/build.gradle
+++ b/wear/wear-watchface/build.gradle
@@ -19,8 +19,6 @@
import androidx.build.Publish
import androidx.build.RunApiTasks
-import static androidx.build.dependencies.DependenciesKt.*
-
plugins {
id("AndroidXPlugin")
id("com.android.library")
@@ -32,29 +30,29 @@
api(project(":wear:wear-complications-data"))
api(project(":wear:wear-watchface-data"))
api(project(":wear:wear-watchface-style"))
- api(KOTLIN_STDLIB)
- api(KOTLIN_COROUTINES_ANDROID)
+ api(libs.kotlinStdlib)
+ api(libs.kotlinCoroutinesAndroid)
implementation("androidx.core:core:1.1.0")
androidTestImplementation(project(":test-screenshot"))
androidTestImplementation(project(":wear:wear-watchface-samples"))
- androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
- androidTestImplementation(ANDROIDX_TEST_CORE)
- androidTestImplementation(ANDROIDX_TEST_RUNNER)
- androidTestImplementation(ANDROIDX_TEST_RULES)
- androidTestImplementation(MOCKITO_CORE, excludes.bytebuddy) // DexMaker has it"s own MockMaker
- androidTestImplementation(DEXMAKER_MOCKITO, excludes.bytebuddy) // DexMaker has it"s own MockMaker
- androidTestImplementation(TRUTH)
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.testCore)
+ androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.testRules)
+ androidTestImplementation(libs.mockitoCore, excludes.bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(libs.dexmakerMockito, excludes.bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(libs.truth)
testImplementation(project(":wear:wear-watchface-complications-rendering"))
- testImplementation(ANDROIDX_TEST_EXT_JUNIT)
- testImplementation(ANDROIDX_TEST_CORE)
- testImplementation(ANDROIDX_TEST_RULES)
- testImplementation(MOCKITO_CORE)
- testImplementation(MOCKITO_KOTLIN)
- testImplementation(ROBOLECTRIC)
- testImplementation(TRUTH)
+ testImplementation(libs.testExtJunit)
+ testImplementation(libs.testCore)
+ testImplementation(libs.testRules)
+ testImplementation(libs.mockitoCore)
+ testImplementation(libs.mockitoKotlin)
+ testImplementation(libs.robolectric)
+ testImplementation(libs.truth)
}
android {
diff --git a/wear/wear-watchface/guava/build.gradle b/wear/wear-watchface/guava/build.gradle
index 28f0610..e9f5714 100644
--- a/wear/wear-watchface/guava/build.gradle
+++ b/wear/wear-watchface/guava/build.gradle
@@ -19,8 +19,6 @@
import androidx.build.LibraryVersions
import androidx.build.Publish
-import static androidx.build.dependencies.DependenciesKt.*
-
plugins {
id("AndroidXPlugin")
id("com.android.library")
@@ -29,21 +27,21 @@
dependencies {
api(project(":wear:wear-watchface"))
- api(GUAVA_LISTENABLE_FUTURE)
+ api(libs.guavaListenableFuture)
- androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
- androidTestImplementation(ANDROIDX_TEST_CORE)
- androidTestImplementation(ANDROIDX_TEST_RUNNER)
- androidTestImplementation(MOCKITO_CORE, excludes.bytebuddy) // DexMaker has it"s own MockMaker
- androidTestImplementation(DEXMAKER_MOCKITO, excludes.bytebuddy) // DexMaker has it"s own MockMaker
- androidTestImplementation(TRUTH)
- testImplementation(ANDROIDX_TEST_CORE)
- testImplementation(ANDROIDX_TEST_RUNNER)
- testImplementation(ANDROIDX_TEST_RULES)
- testImplementation(MOCKITO_CORE, excludes.bytebuddy) // DexMaker has it"s own MockMaker
- testImplementation(DEXMAKER_MOCKITO, excludes.bytebuddy) // DexMaker has it"s own MockMaker
- testImplementation(ROBOLECTRIC)
- testImplementation(TRUTH)
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.testCore)
+ androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.mockitoCore, excludes.bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(libs.dexmakerMockito, excludes.bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(libs.truth)
+ testImplementation(libs.testCore)
+ testImplementation(libs.testRunner)
+ testImplementation(libs.testRules)
+ testImplementation(libs.mockitoCore, excludes.bytebuddy) // DexMaker has it"s own MockMaker
+ testImplementation(libs.dexmakerMockito, excludes.bytebuddy) // DexMaker has it"s own MockMaker
+ testImplementation(libs.robolectric)
+ testImplementation(libs.truth)
}
androidx {
diff --git a/wear/wear-watchface/samples/app/build.gradle b/wear/wear-watchface/samples/app/build.gradle
index 32a0f15..318233d 100644
--- a/wear/wear-watchface/samples/app/build.gradle
+++ b/wear/wear-watchface/samples/app/build.gradle
@@ -18,8 +18,6 @@
import androidx.build.LibraryType
import androidx.build.LibraryVersions
-import static androidx.build.dependencies.DependenciesKt.*
-
plugins {
id("AndroidXPlugin")
id("com.android.application")
diff --git a/wear/wear-watchface/samples/build.gradle b/wear/wear-watchface/samples/build.gradle
index 3c7bc22..77f0fd1 100644
--- a/wear/wear-watchface/samples/build.gradle
+++ b/wear/wear-watchface/samples/build.gradle
@@ -18,8 +18,6 @@
import androidx.build.LibraryType
import androidx.build.LibraryVersions
-import static androidx.build.dependencies.DependenciesKt.*
-
plugins {
id("AndroidXPlugin")
id("com.android.library")
@@ -31,7 +29,7 @@
api(project(":wear:wear-watchface"))
implementation(project(":wear:wear-watchface-complications-rendering"))
implementation(project(":wear:wear-watchface-editor-samples"))
- api(KOTLIN_STDLIB)
+ api(libs.kotlinStdlib)
}
androidx {
diff --git a/wear/wear-watchface/samples/minimal/build.gradle b/wear/wear-watchface/samples/minimal/build.gradle
index c1464dd..f4f7ce0 100644
--- a/wear/wear-watchface/samples/minimal/build.gradle
+++ b/wear/wear-watchface/samples/minimal/build.gradle
@@ -18,8 +18,6 @@
import androidx.build.LibraryType
import androidx.build.LibraryVersions
-import static androidx.build.dependencies.DependenciesKt.*
-
plugins {
id("AndroidXPlugin")
id("com.android.application")
@@ -28,7 +26,7 @@
dependencies {
api(project(":wear:wear-watchface"))
api(project(":wear:wear-watchface-guava"))
- implementation(GUAVA_ANDROID)
+ implementation(libs.guavaAndroid)
}
androidx {
diff --git a/wear/wear/build.gradle b/wear/wear/build.gradle
index 80eb984..737681c 100644
--- a/wear/wear/build.gradle
+++ b/wear/wear/build.gradle
@@ -1,4 +1,3 @@
-import static androidx.build.dependencies.DependenciesKt.*
import androidx.build.LibraryGroups
import androidx.build.LibraryVersions
import androidx.build.Publish
@@ -18,19 +17,19 @@
api("androidx.versionedparcelable:versionedparcelable:1.1.1")
androidTestImplementation(project(":test-screenshot"))
- androidTestImplementation(KOTLIN_STDLIB)
- androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
- androidTestImplementation(ANDROIDX_TEST_CORE)
- androidTestImplementation(ANDROIDX_TEST_RUNNER)
- androidTestImplementation(ANDROIDX_TEST_RULES)
- androidTestImplementation(ESPRESSO_CORE, excludes.espresso)
- androidTestImplementation(MOCKITO_CORE, excludes.bytebuddy) // DexMaker has it"s own MockMaker
- androidTestImplementation(DEXMAKER_MOCKITO, excludes.bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(libs.kotlinStdlib)
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.testCore)
+ androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.testRules)
+ androidTestImplementation(libs.espressoCore, excludes.espresso)
+ androidTestImplementation(libs.mockitoCore, excludes.bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(libs.dexmakerMockito, excludes.bytebuddy) // DexMaker has it"s own MockMaker
- testImplementation(KOTLIN_STDLIB)
- testImplementation(ANDROIDX_TEST_CORE)
- testImplementation(ANDROIDX_TEST_RUNNER)
- testImplementation(ROBOLECTRIC)
+ testImplementation(libs.kotlinStdlib)
+ testImplementation(libs.testCore)
+ testImplementation(libs.testRunner)
+ testImplementation(libs.robolectric)
implementation("androidx.core:core-ktx:1.5.0-alpha04")
diff --git a/work/workmanager-lint/build.gradle b/work/workmanager-lint/build.gradle
index 557fb01..7329d99 100644
--- a/work/workmanager-lint/build.gradle
+++ b/work/workmanager-lint/build.gradle
@@ -25,13 +25,7 @@
}
dependencies {
- // compileOnly because we use lintChecks and it doesn't allow other types of deps
- // this ugly hack exists because of b/63873667
- if (rootProject.hasProperty("android.injected.invoked.from.ide")) {
- compileOnly(libs.androidLintApi)
- } else {
- compileOnly(LINT_API_MIN)
- }
+ compileOnly(LINT_API_MIN)
compileOnly(libs.kotlinStdlib)
testImplementation(libs.kotlinStdlib)