Merge "Update SqlParser to correctly detect top level star projection with a prefix." into androidx-main
diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml
index a0c4ba9..6a0bcc3 100644
--- a/.github/workflows/integration_tests.yml
+++ b/.github/workflows/integration_tests.yml
@@ -7,7 +7,7 @@
jobs:
run_integration_tests:
runs-on: ubuntu-latest
- if: ${{ github.event.workflow_run.conclusion == 'success' }}
+ if: ${{ !github.event.repository.fork && github.event.workflow_run.conclusion == 'success' }}
name: Run integration tests on FTL
steps:
- name: Set up JDK 11
@@ -33,7 +33,7 @@
teardown:
runs-on: ubuntu-latest
needs: [run_integration_tests]
- if: always()
+ if: ${{ !github.event.repository.fork && always() }} # always() is required so that this job will run irrespective of status of upstream 'run_integration_test' job.
steps:
- name: Parse workflow status
id: workflow-status
diff --git a/.github/workflows/register_workflow_start.yml b/.github/workflows/register_workflow_start.yml
index 8a66d98..ec447a7 100644
--- a/.github/workflows/register_workflow_start.yml
+++ b/.github/workflows/register_workflow_start.yml
@@ -6,6 +6,7 @@
jobs:
ping_androidx_dev:
+ if: ${{ !github.event.repository.fork }}
runs-on: ubuntu-latest
name: "Start webhook"
steps:
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/ShareActionProvider.java b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/ShareActionProvider.java
index e9903ea..2e034d2 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/ShareActionProvider.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/ShareActionProvider.java
@@ -40,7 +40,7 @@
* overflow menu, it creates a submenu with the appropriate sharing
* actions.
*
- * <h3 id="add-share-action">Adding a share action</h3>
+ * ### Adding a share action
*
* <p>To add a "share" action to your activity, put a
* <code>ShareActionProvider</code> in the app bar's menu resource. For
@@ -101,7 +101,7 @@
* myShareActionProvider.setShareIntent(myShareIntent);</pre></li>
* </ol>
*
- * <h3 id="rankings">Share target rankings</h3>
+ * ### Share target rankings
*
* <p>The share action provider retains a ranking for each share target,
* based on how often the user chooses each one. The more often a user
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSessionLocalCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSessionLocalCtsTest.java
index f987118..8905e0e0 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSessionLocalCtsTest.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSessionLocalCtsTest.java
@@ -41,6 +41,7 @@
import androidx.appsearch.testutil.AppSearchEmail;
import androidx.appsearch.testutil.SimpleTestLogger;
import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.FlakyTest;
import com.google.common.util.concurrent.ListenableFuture;
@@ -347,6 +348,7 @@
// TODO(b/194207451) This test can be moved to CtsTestBase if customized logger is
// supported for platform backend.
+ @FlakyTest(bugId = 204478878)
@Test
public void testSetSchemaStats_withSchemaMigration() throws Exception {
SimpleTestLogger logger = new SimpleTestLogger();
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt
index 66ddef2..2dd0f5f 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt
@@ -36,10 +36,6 @@
name = "linux.ftrace",
target_buffer = 0,
ftrace_config = FtraceConfig(
- // These parameters affect only the kernel trace buffer size and how
- // frequently it gets moved into the userspace buffer defined above.
- buffer_size_kb = 16384,
- drain_period_ms = 250,
ftrace_events = listOf(
// We need to do process tracking to ensure kernel ftrace events targeted at short-lived
// threads are associated correctly
@@ -146,8 +142,8 @@
atraceApps: List<String>
) = TraceConfig(
buffers = listOf(
- BufferConfig(size_kb = 16384, FillPolicy.RING_BUFFER),
- BufferConfig(size_kb = 16384, FillPolicy.RING_BUFFER)
+ BufferConfig(size_kb = 32768, FillPolicy.RING_BUFFER),
+ BufferConfig(size_kb = 4096, FillPolicy.RING_BUFFER)
),
data_sources = listOf(
ftraceDataSource(atraceApps),
@@ -155,6 +151,13 @@
LINUX_SYS_STATS_DATASOURCE,
TraceConfig.DataSource(DataSourceConfig("android.surfaceflinger.frametimeline"))
),
+ // periodically dump to file, so we don't overrun our ring buffer
+ // buffers are expected to be big enough for 5 seconds, so conservatively set 2.5 dump
+ write_into_file = true,
+ file_write_period_ms = 2500,
+
+ // multiple of file_write_period_ms, enables trace processor to work in batches
+ flush_period_ms = 5000
)
@RequiresApi(21) // needed for shell access
diff --git a/benchmark/integration-tests/macrobenchmark-target/build.gradle b/benchmark/integration-tests/macrobenchmark-target/build.gradle
index 7ad8481..0661058 100644
--- a/benchmark/integration-tests/macrobenchmark-target/build.gradle
+++ b/benchmark/integration-tests/macrobenchmark-target/build.gradle
@@ -33,8 +33,8 @@
dependencies {
implementation(libs.kotlinStdlib)
implementation(libs.constraintLayout)
- implementation("androidx.appcompat:appcompat:1.2.0")
- implementation("androidx.activity:activity:1.3.0")
- implementation("androidx.recyclerview:recyclerview:1.1.0")
+ implementation(project(":appcompat:appcompat"))
+ implementation(project(":activity:activity"))
+ implementation(project(":recyclerview:recyclerview"))
implementation(libs.material)
}
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
index a106f01..87a4d07 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
@@ -534,10 +534,9 @@
packageApplicationProvider.get().let { packageTask ->
AffectedModuleDetector.configureTaskGuard(packageTask)
// Skip copying AndroidTest apks if they have no source code (no tests to run).
- if (testApk && !project.hasAndroidTestSourceCode()) {
- return
+ if (!testApk || project.hasAndroidTestSourceCode()) {
+ addToTestZips(project, packageTask)
}
- addToTestZips(project, packageTask)
}
project.tasks.withType(ListingFileRedirectTask::class.java).forEach {
AffectedModuleDetector.configureTaskGuard(it)
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaRunner.kt b/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaRunner.kt
index d559e19..c7090c2 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaRunner.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaRunner.kt
@@ -17,7 +17,6 @@
package androidx.build.metalava
import androidx.build.checkapi.ApiLocation
-import androidx.build.dependencies.getDependencyAsString
import androidx.build.java.JavaCompileInputs
import androidx.build.logging.TERMINAL_RED
import androidx.build.logging.TERMINAL_RESET
@@ -98,7 +97,7 @@
VersionCatalogsExtension::class.java
).find("libs").get()
val dependency = dependencies.create(
- getDependencyAsString(libs.findDependency("metalava").get())
+ libs.findDependency("metalava").get().get()
)
it.dependencies.add(dependency)
}
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/studio/StudioTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/studio/StudioTask.kt
index e51c320..0fb1a3a 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/studio/StudioTask.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/studio/StudioTask.kt
@@ -16,10 +16,7 @@
package androidx.build.studio
-import androidx.build.OperatingSystem
import androidx.build.StudioType
-import androidx.build.getOperatingSystem
-import androidx.build.getSdkPath
import androidx.build.getSupportRootFolder
import androidx.build.studioType
import com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
@@ -34,7 +31,6 @@
import org.gradle.internal.service.ServiceRegistry
import org.gradle.process.ExecOperations
import java.io.File
-import java.nio.file.Files
import javax.inject.Inject
/**
@@ -172,33 +168,6 @@
}
/**
- * Attempts to symlink the system-images and emulator SDK directories to a canonical SDK.
- */
- private fun setupSymlinksIfNeeded() {
- val paths = listOf("system-images", "emulator")
-
- val localSdkPath = project.getSdkPath()
- val canonicalSdkPath = when (getOperatingSystem()) {
- OperatingSystem.MAC -> File(System.getProperty("user.home"), "Library/Android/sdk")
- OperatingSystem.LINUX -> File(System.getProperty("user.home"), "Android/Sdk")
- else -> null
- } ?: return
-
- if (!canonicalSdkPath.exists()) {
- // In the future, we might want to try a little harder to locate a canonical SDK path.
- return
- }
-
- paths.forEach { path ->
- val link = File(localSdkPath, path)
- val target = File(canonicalSdkPath, path)
- if (target.exists() && !link.exists()) {
- Files.createSymbolicLink(link.toPath(), target.toPath())
- }
- }
- }
-
- /**
* Launches Studio if the user accepts / has accepted the license agreement.
*/
private fun launch() {
@@ -213,10 +182,6 @@
""".trimIndent()
)
}
-
- // This seems like as good a time as any to set up SDK symlinks...
- setupSymlinksIfNeeded()
-
println("Launching studio...")
launchStudio()
} else {
diff --git a/buildSrc/public/src/main/kotlin/androidx/build/dependencies/Dependencies.kt b/buildSrc/public/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
index 6371113..b55ed1a 100644
--- a/buildSrc/public/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
+++ b/buildSrc/public/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
@@ -16,9 +16,6 @@
package androidx.build.dependencies
-import org.gradle.api.artifacts.MinimalExternalModuleDependency
-import org.gradle.api.provider.Provider
-
internal lateinit var guavaVersion: String
val GUAVA_VERSION get() = guavaVersion
@@ -31,9 +28,3 @@
internal lateinit var agpVersion: String
val AGP_LATEST get() = "com.android.tools.build:gradle:$agpVersion"
-
-@Suppress("UnstableApiUsage")
-fun getDependencyAsString(dependencyProvider: Provider<MinimalExternalModuleDependency>): String {
- val dependency = dependencyProvider.get()
- return dependency.module.toString() + ":" + dependency.versionConstraint.toString()
-}
\ No newline at end of file
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/CaptureProcessorPipeline.java b/camera/camera-core/src/main/java/androidx/camera/core/CaptureProcessorPipeline.java
index f614281..20dd85a 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/CaptureProcessorPipeline.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/CaptureProcessorPipeline.java
@@ -27,6 +27,7 @@
import androidx.camera.core.impl.ImageProxyBundle;
import androidx.camera.core.impl.ImageReaderProxy;
import androidx.camera.core.impl.TagBundle;
+import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.core.util.Preconditions;
import com.google.common.util.concurrent.ListenableFuture;
@@ -35,15 +36,17 @@
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
/**
* A CaptureProcessor which can link two CaptureProcessors.
*/
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
class CaptureProcessorPipeline implements CaptureProcessor {
+ private static final String TAG = "CaptureProcessorPipeline";
private final CaptureProcessor mPreCaptureProcessor;
private final CaptureProcessor mPostCaptureProcessor;
- private final Executor mExecutor;
+ final Executor mExecutor;
private final int mMaxImages;
private ImageReaderProxy mIntermediateImageReader = null;
private ImageInfo mSourceImageInfo = null;
@@ -120,12 +123,17 @@
// Register the ImageAvailableListener to receive the processed image from the
// pre-processing CaptureProcessor.
mIntermediateImageReader.setOnImageAvailableListener(
- new ImageReaderProxy.OnImageAvailableListener() {
- @Override
- public void onImageAvailable(@NonNull ImageReaderProxy imageReader) {
- postProcess(imageReader.acquireNextImage());
+ imageReader -> {
+ ImageProxy image = imageReader.acquireNextImage();
+ try {
+ mExecutor.execute(() -> postProcess(image));
+ } catch (RejectedExecutionException e) {
+ Logger.e(TAG, "The executor for post-processing might have been "
+ + "shutting down or terminated!");
+ image.close();
}
- }, mExecutor);
+ },
+ CameraXExecutors.directExecutor());
}
void postProcess(ImageProxy imageProxy) {
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/Logger.java b/camera/camera-core/src/main/java/androidx/camera/core/Logger.java
index 1d4aa96..56bebf3 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/Logger.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/Logger.java
@@ -21,7 +21,6 @@
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
@@ -70,6 +69,14 @@
}
/**
+ * Returns {@code true} if logging with the truncated tag {@code truncatedTag} is
+ * enabled at the {@code logLevel} level.
+ */
+ private static boolean isLogLevelEnabled(@NonNull String truncatedTag, int logLevel) {
+ return sMinLogLevel <= logLevel || Log.isLoggable(truncatedTag, logLevel);
+ }
+
+ /**
* Sets the minimum logging level to use in {@link Logger}. After calling this method, only logs
* at the level {@code logLevel} and above are output.
*/
@@ -99,7 +106,7 @@
* {@link Log#DEBUG} at least.
*/
public static boolean isDebugEnabled(@NonNull String tag) {
- return sMinLogLevel <= Log.DEBUG || Log.isLoggable(truncateTag(tag), Log.DEBUG);
+ return isLogLevelEnabled(truncateTag(tag), Log.DEBUG);
}
/**
@@ -109,7 +116,7 @@
* {@link Log#INFO} at least.
*/
public static boolean isInfoEnabled(@NonNull String tag) {
- return sMinLogLevel <= Log.INFO || Log.isLoggable(truncateTag(tag), Log.INFO);
+ return isLogLevelEnabled(truncateTag(tag), Log.INFO);
}
/**
@@ -119,7 +126,7 @@
* {@link Log#WARN} at least.
*/
public static boolean isWarnEnabled(@NonNull String tag) {
- return sMinLogLevel <= Log.WARN || Log.isLoggable(truncateTag(tag), Log.WARN);
+ return isLogLevelEnabled(truncateTag(tag), Log.WARN);
}
/**
@@ -129,7 +136,7 @@
* {@link Log#ERROR} at least.
*/
public static boolean isErrorEnabled(@NonNull String tag) {
- return sMinLogLevel <= Log.ERROR || Log.isLoggable(truncateTag(tag), Log.ERROR);
+ return isLogLevelEnabled(truncateTag(tag), Log.ERROR);
}
/**
@@ -137,7 +144,10 @@
* {@linkplain #isDebugEnabled(String) loggable}.
*/
public static void d(@NonNull String tag, @NonNull String message) {
- d(tag, message, null);
+ final String truncatedTag = truncateTag(tag);
+ if (isLogLevelEnabled(truncatedTag, Log.DEBUG)) {
+ Log.d(truncatedTag, message);
+ }
}
/**
@@ -145,9 +155,10 @@
* {@linkplain #isDebugEnabled(String) loggable}.
*/
public static void d(@NonNull String tag, @NonNull String message,
- @Nullable final Throwable throwable) {
- if (isDebugEnabled(tag)) {
- Log.d(truncateTag(tag), message, throwable);
+ @NonNull final Throwable throwable) {
+ final String truncatedTag = truncateTag(tag);
+ if (isLogLevelEnabled(truncatedTag, Log.DEBUG)) {
+ Log.d(truncatedTag, message, throwable);
}
}
@@ -156,7 +167,10 @@
* {@linkplain #isInfoEnabled(String) loggable}.
*/
public static void i(@NonNull String tag, @NonNull String message) {
- i(tag, message, null);
+ final String truncatedTag = truncateTag(tag);
+ if (isLogLevelEnabled(truncatedTag, Log.INFO)) {
+ Log.i(truncatedTag, message);
+ }
}
/**
@@ -164,9 +178,10 @@
* {@linkplain #isInfoEnabled(String) loggable}.
*/
public static void i(@NonNull String tag, @NonNull String message,
- @Nullable final Throwable throwable) {
- if (isInfoEnabled(tag)) {
- Log.i(truncateTag(tag), message, throwable);
+ @NonNull final Throwable throwable) {
+ final String truncatedTag = truncateTag(tag);
+ if (isLogLevelEnabled(truncatedTag, Log.INFO)) {
+ Log.i(truncatedTag, message, throwable);
}
}
@@ -175,7 +190,10 @@
* {@linkplain #isWarnEnabled(String) loggable}.
*/
public static void w(@NonNull String tag, @NonNull String message) {
- w(tag, message, null);
+ final String truncatedTag = truncateTag(tag);
+ if (isLogLevelEnabled(truncatedTag, Log.WARN)) {
+ Log.w(truncatedTag, message);
+ }
}
/**
@@ -183,9 +201,10 @@
* {@linkplain #isWarnEnabled(String) loggable}.
*/
public static void w(@NonNull String tag, @NonNull String message,
- @Nullable final Throwable throwable) {
- if (isWarnEnabled(tag)) {
- Log.w(truncateTag(tag), message, throwable);
+ @NonNull final Throwable throwable) {
+ final String truncatedTag = truncateTag(tag);
+ if (isLogLevelEnabled(truncatedTag, Log.WARN)) {
+ Log.w(truncatedTag, message, throwable);
}
}
@@ -194,7 +213,10 @@
* {@linkplain #isErrorEnabled(String) loggable}.
*/
public static void e(@NonNull String tag, @NonNull String message) {
- e(tag, message, null);
+ final String truncatedTag = truncateTag(tag);
+ if (isLogLevelEnabled(truncatedTag, Log.ERROR)) {
+ Log.e(truncatedTag, message);
+ }
}
/**
@@ -202,9 +224,10 @@
* {@linkplain #isErrorEnabled(String) loggable}.
*/
public static void e(@NonNull String tag, @NonNull String message,
- @Nullable final Throwable throwable) {
- if (isErrorEnabled(tag)) {
- Log.e(truncateTag(tag), message, throwable);
+ @NonNull final Throwable throwable) {
+ final String truncatedTag = truncateTag(tag);
+ if (isLogLevelEnabled(truncatedTag, Log.ERROR)) {
+ Log.e(truncatedTag, message, throwable);
}
}
@@ -215,7 +238,7 @@
*/
@NonNull
private static String truncateTag(@NonNull String tag) {
- if (MAX_TAG_LENGTH < tag.length() && Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N && MAX_TAG_LENGTH < tag.length()) {
return tag.substring(0, MAX_TAG_LENGTH);
}
return tag;
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/VideoCapabilities.java b/camera/camera-video/src/main/java/androidx/camera/video/VideoCapabilities.java
index 5b9ec7f..65626a4 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/VideoCapabilities.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/VideoCapabilities.java
@@ -26,6 +26,8 @@
import androidx.camera.core.impl.CamcorderProfileProvider;
import androidx.camera.core.impl.CamcorderProfileProxy;
import androidx.camera.core.impl.CameraInfoInternal;
+import androidx.camera.video.internal.compat.quirk.DeviceQuirks;
+import androidx.camera.video.internal.compat.quirk.VideoQualityNotSupportQuirk;
import androidx.core.util.Preconditions;
import java.util.ArrayDeque;
@@ -71,7 +73,7 @@
// SortedQualities is from size large to small
// Get CamcorderProfile
- if (!camcorderProfileProvider.hasProfile(quality)) {
+ if (!camcorderProfileProvider.hasProfile(quality) || !isDeviceValidQuality(quality)) {
continue;
}
CamcorderProfileProxy profile = camcorderProfileProvider.get(quality);
@@ -151,4 +153,10 @@
Preconditions.checkArgument(QualitySelector.containsQuality(quality),
"Unknown quality: " + quality);
}
+
+ private boolean isDeviceValidQuality(@QualitySelector.VideoQuality int quality) {
+ VideoQualityNotSupportQuirk quirk = DeviceQuirks.get(VideoQualityNotSupportQuirk.class);
+ return quirk == null || !quirk.isProblematicVideoQuality(quality);
+ }
+
}
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/DeviceQuirksLoader.java b/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/DeviceQuirksLoader.java
index 09543f98..92846e72 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/DeviceQuirksLoader.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/DeviceQuirksLoader.java
@@ -53,6 +53,9 @@
if (CameraUseInconsistentTimebaseQuirk.load()) {
quirks.add(new CameraUseInconsistentTimebaseQuirk());
}
+ if (VideoQualityNotSupportQuirk.load()) {
+ quirks.add(new VideoQualityNotSupportQuirk());
+ }
return quirks;
}
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/VideoQualityNotSupportQuirk.java b/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/VideoQualityNotSupportQuirk.java
new file mode 100644
index 0000000..5d461ba
--- /dev/null
+++ b/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/VideoQualityNotSupportQuirk.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.video.internal.compat.quirk;
+
+import android.media.CamcorderProfile;
+import android.media.MediaRecorder.VideoEncoder;
+import android.os.Build;
+
+import androidx.annotation.RequiresApi;
+import androidx.camera.core.impl.CamcorderProfileProvider;
+import androidx.camera.core.impl.Quirk;
+import androidx.camera.video.QualitySelector;
+import androidx.camera.video.VideoCapabilities;
+
+/**
+ * Quirk denotes that quality {@link VideoCapabilities} queried by {@link CamcorderProfileProvider}
+ * does not work on video recording on device, and need to exclude it.
+ *
+ * <p>On Huawei Mate20 and Mate20 Pro, {@link CamcorderProfile} indicates it can support
+ * resolutions 3840x2160 for {@link VideoEncoder#H264}, and it can create the video
+ * encoder by the corresponding format. However, there is not any video frame output from Camera
+ * . The CaptureSession is opened and configured, but something error in the HAL of these devices
+ * . Hence use a quirk to exclude the problematic resolution quality. See b/202080832#comment8.
+ *
+ */
+@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
+public class VideoQualityNotSupportQuirk implements Quirk {
+ static boolean load() {
+ return isHuaweiMate20() || isHuaweiMate20Pro();
+ }
+
+ private static boolean isHuaweiMate20() {
+ return "Huawei".equalsIgnoreCase(Build.BRAND) && "HMA-L29".equalsIgnoreCase(Build.MODEL);
+ }
+
+ private static boolean isHuaweiMate20Pro() {
+ return "Huawei".equalsIgnoreCase(Build.BRAND) && "LYA-AL00".equalsIgnoreCase(Build.MODEL);
+ }
+
+ /** Checks if the given mime type is a problematic quality. */
+ public boolean isProblematicVideoQuality(@QualitySelector.VideoQuality int quality) {
+ return quality == QualitySelector.QUALITY_UHD;
+ }
+}
diff --git a/car/app/app/api/current.txt b/car/app/app/api/current.txt
index 47ba617..9353a32 100644
--- a/car/app/app/api/current.txt
+++ b/car/app/app/api/current.txt
@@ -221,6 +221,7 @@
package androidx.car.app.hardware.common {
@androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class CarUnit {
+ method public static String toString(int);
field public static final int IMPERIAL_GALLON = 204; // 0xcc
field public static final int KILOMETER = 3; // 0x3
field public static final int KILOMETERS_PER_HOUR = 102; // 0x66
diff --git a/car/app/app/api/public_plus_experimental_current.txt b/car/app/app/api/public_plus_experimental_current.txt
index 4eaeb9c..42a1550 100644
--- a/car/app/app/api/public_plus_experimental_current.txt
+++ b/car/app/app/api/public_plus_experimental_current.txt
@@ -224,6 +224,7 @@
package androidx.car.app.hardware.common {
@androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class CarUnit {
+ method public static String toString(int);
field public static final int IMPERIAL_GALLON = 204; // 0xcc
field public static final int KILOMETER = 3; // 0x3
field public static final int KILOMETERS_PER_HOUR = 102; // 0x66
diff --git a/car/app/app/api/restricted_current.txt b/car/app/app/api/restricted_current.txt
index 47ba617..9353a32 100644
--- a/car/app/app/api/restricted_current.txt
+++ b/car/app/app/api/restricted_current.txt
@@ -221,6 +221,7 @@
package androidx.car.app.hardware.common {
@androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class CarUnit {
+ method public static String toString(int);
field public static final int IMPERIAL_GALLON = 204; // 0xcc
field public static final int KILOMETER = 3; // 0x3
field public static final int KILOMETERS_PER_HOUR = 102; // 0x66
diff --git a/car/app/app/src/main/java/androidx/car/app/hardware/common/CarUnit.java b/car/app/app/src/main/java/androidx/car/app/hardware/common/CarUnit.java
index e92e551..adde31a 100644
--- a/car/app/app/src/main/java/androidx/car/app/hardware/common/CarUnit.java
+++ b/car/app/app/src/main/java/androidx/car/app/hardware/common/CarUnit.java
@@ -19,6 +19,7 @@
import static androidx.annotation.RestrictTo.Scope.LIBRARY;
import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
import androidx.car.app.annotations.CarProtocol;
import androidx.car.app.annotations.RequiresCarApi;
@@ -127,4 +128,35 @@
public static final int MILES_PER_HOUR = 103;
private CarUnit() {}
+
+ /** Get a user friendly representation of the unit. */
+ @NonNull
+ public static String toString(int unit) {
+ switch (unit) {
+ case MILLIMETER:
+ return "MILLIMETER";
+ case METER:
+ return "METER";
+ case KILOMETER:
+ return "KILOMETER";
+ case MILE:
+ return "MILE";
+ case MILLILITER:
+ return "MILLILITER";
+ case LITER:
+ return "LITER";
+ case US_GALLON :
+ return "US_GALLON ";
+ case IMPERIAL_GALLON:
+ return "IMPERIAL_GALLON";
+ case METERS_PER_SEC:
+ return "METERS_PER_SEC";
+ case KILOMETERS_PER_HOUR:
+ return "KILOMETERS_PER_HOUR";
+ case MILES_PER_HOUR :
+ return "MILES_PER_HOUR ";
+ default:
+ return "UNKNOWN";
+ }
+ }
}
diff --git a/car/app/app/src/main/java/androidx/car/app/model/PlaceMarker.java b/car/app/app/src/main/java/androidx/car/app/model/PlaceMarker.java
index 30ea12b..b21f963 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/PlaceMarker.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/PlaceMarker.java
@@ -63,7 +63,7 @@
* Represents a marker image.
*
* <p>To minimize scaling artifacts across a wide range of car screens, apps should provide
- * images targeting a 72 x 72 dp bounding box. If necessary, the icon will be scaled down while
+ * images targeting a 72 x 72 dp bounding box. If necessary, the image will be scaled down while
* preserving its aspect ratio.
*/
public static final int TYPE_IMAGE = 1;
diff --git a/compose/integration-tests/macrobenchmark-target/build.gradle b/compose/integration-tests/macrobenchmark-target/build.gradle
index 3ff9864..623a666a 100644
--- a/compose/integration-tests/macrobenchmark-target/build.gradle
+++ b/compose/integration-tests/macrobenchmark-target/build.gradle
@@ -19,12 +19,12 @@
kotlinPlugin(project(":compose:compiler:compiler"))
implementation(libs.kotlinStdlib)
+ implementation(project(":activity:activity-compose"))
implementation(project(":compose:foundation:foundation-layout"))
implementation(project(":compose:material:material"))
implementation(project(":compose:runtime:runtime"))
implementation(project(":compose:ui:ui"))
implementation(project(":compose:ui:ui-tooling"))
- implementation("androidx.activity:activity-compose:1.3.1")
}
android.defaultConfig.minSdkVersion 21
diff --git a/core/core/src/main/java/androidx/core/app/TaskStackBuilder.java b/core/core/src/main/java/androidx/core/app/TaskStackBuilder.java
index a059eac..3a881a6c 100644
--- a/core/core/src/main/java/androidx/core/app/TaskStackBuilder.java
+++ b/core/core/src/main/java/androidx/core/app/TaskStackBuilder.java
@@ -60,7 +60,7 @@
* task.</p>
*
* <div class="special reference">
- * <h3>About Navigation</h3>
+ * ### About Navigation
* For more detailed information about tasks, the back stack, and navigation design guidelines,
* please read
* <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back Stack</a>
diff --git a/core/core/src/main/java/androidx/core/content/FileProvider.java b/core/core/src/main/java/androidx/core/content/FileProvider.java
index b8e5c80..e5995d6 100644
--- a/core/core/src/main/java/androidx/core/content/FileProvider.java
+++ b/core/core/src/main/java/androidx/core/content/FileProvider.java
@@ -80,7 +80,7 @@
* <li><a href="#Permissions">Granting Temporary Permissions to a URI</a></li>
* <li><a href="#ServeUri">Serving a Content URI to Another App</a></li>
* </ol>
- * <h3 id="ProviderDefinition">Defining a FileProvider</h3>
+ * ### Defining a FileProvider
* <p>
* Since the default functionality of FileProvider includes content URI generation for files, you
* don't need to define a subclass in code. Instead, you can include a FileProvider in your app
@@ -114,7 +114,7 @@
* If you want to override any of the default behavior of FileProvider methods, extend
* the FileProvider class and use the fully-qualified class name in the <code>android:name</code>
* attribute of the <code><provider></code> element.
- * <h3 id="SpecifyFiles">Specifying Available Files</h3>
+ * ### Specifying Available Files
* A FileProvider can only generate a content URI for files in directories that you specify
* beforehand. To specify a directory, specify its storage area and path in XML, using child
* elements of the <code><paths></code> element.
@@ -245,7 +245,7 @@
* android:resource="@xml/file_paths" />
*</provider>
*</pre>
- * <h3 id="GetUri">Generating the Content URI for a File</h3>
+ * ### Generating the Content URI for a File
* <p>
* To share a file with another app using a content URI, your app has to generate the content URI.
* To generate the content URI, create a new {@link File} for the file, then pass the {@link File}
@@ -268,7 +268,7 @@
* As a result of the previous snippet,
* {@link #getUriForFile(Context, String, File) getUriForFile()} returns the content URI
* <code>content://com.mydomain.fileprovider/my_images/default_image.jpg</code>.
- * <h3 id="Permissions">Granting Temporary Permissions to a URI</h3>
+ * ### Granting Temporary Permissions to a URI
* To grant an access permission to a content URI returned from
* {@link #getUriForFile(Context, String, File) getUriForFile()}, you can either grant the
* permission to a specific package or include the permission in an intent, as shown in the
@@ -324,7 +324,7 @@
* automatically removed. Permissions granted to one {@link android.app.Activity} in a client
* app are automatically extended to other components of that app.
* </p>
- * <h3 id="ServeUri">Serving a Content URI to Another App</h3>
+ * ### Serving a Content URI to Another App
* <p>
* There are a variety of ways to serve the content URI for a file to a client app. One common way
* is for the client app to start your app by calling
@@ -351,7 +351,7 @@
* {@link Intent}. Set the action to {@link Intent#ACTION_SEND} and put the URI in data by calling
* {@link Intent#setData setData()}.
* </p>
- * <h3 id="">More Information</h3>
+ * ### More Information
* <p>
* To learn more about FileProvider, see the Android training class
* <a href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files Securely with URIs</a>.
diff --git a/core/core/src/main/java/androidx/core/view/ActionProvider.java b/core/core/src/main/java/androidx/core/view/ActionProvider.java
index 14c710d..468e67f 100644
--- a/core/core/src/main/java/androidx/core/view/ActionProvider.java
+++ b/core/core/src/main/java/androidx/core/view/ActionProvider.java
@@ -58,7 +58,7 @@
* </code></pre>
* </li></ul></p>
*
- * <h3>Creating a custom action provider</h3>
+ * ### Creating a custom action provider
*
* <p>To create a custom action provider, extend ActionProvider and implement
* its callback methods as necessary. In particular, implement the following
diff --git a/datastore/datastore-preferences-proto/build.gradle b/datastore/datastore-preferences-proto/build.gradle
index d643f9d..33d33fa 100644
--- a/datastore/datastore-preferences-proto/build.gradle
+++ b/datastore/datastore-preferences-proto/build.gradle
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-import androidx.build.dependencies.DependenciesKt
import androidx.build.LibraryGroups
import androidx.build.Publish
@@ -31,7 +30,7 @@
protobuf {
protoc {
- artifact = DependenciesKt.getDependencyAsString(libs.protobufCompiler)
+ artifact = libs.protobufCompiler.get()
}
// Generates the java proto-lite code for the protos in this project. See
diff --git a/datastore/datastore-proto/build.gradle b/datastore/datastore-proto/build.gradle
index 5acd326..f16a115 100644
--- a/datastore/datastore-proto/build.gradle
+++ b/datastore/datastore-proto/build.gradle
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-import androidx.build.dependencies.DependenciesKt
import androidx.build.LibraryGroups
import androidx.build.Publish
import androidx.build.RunApiTasks
@@ -40,7 +39,7 @@
protobuf {
protoc {
- artifact = DependenciesKt.getDependencyAsString(libs.protobufCompiler)
+ artifact = libs.protobufCompiler.get()
}
// Generates the java proto-lite code for the protos in this project. See
// https://github.com/google/protobuf-gradle-plugin#customizing-protobuf-compilation
diff --git a/datastore/datastore-sampleapp/build.gradle b/datastore/datastore-sampleapp/build.gradle
index 9d7572c..2059f64 100644
--- a/datastore/datastore-sampleapp/build.gradle
+++ b/datastore/datastore-sampleapp/build.gradle
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-
-import androidx.build.dependencies.DependenciesKt
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
@@ -52,7 +50,7 @@
protobuf {
protoc {
- artifact = DependenciesKt.getDependencyAsString(libs.protobufCompiler)
+ artifact = libs.protobufCompiler.get()
}
// Generates the java proto-lite code for the protos in this project. See
diff --git a/playground-common/gradle/wrapper/gradle-wrapper.properties b/playground-common/gradle/wrapper/gradle-wrapper.properties
index a0f7639..38b2653 100644
--- a/playground-common/gradle/wrapper/gradle-wrapper.properties
+++ b/playground-common/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-rc-1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotated.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotated.kt
index 18b7559..9ad903b 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotated.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotated.kt
@@ -105,6 +105,18 @@
fun hasAnyAnnotation(vararg annotations: KClass<out Annotation>) =
annotations.any(this::hasAnnotation)
+ /**
+ * Returns `true` if this element has all the [annotations].
+ */
+ fun hasAllAnnotations(vararg annotations: ClassName): Boolean =
+ annotations.all(this::hasAnnotation)
+
+ /**
+ * Returns `true` if this element has all the [annotations].
+ */
+ fun hasAllAnnotations(vararg annotations: KClass<out Annotation>): Boolean =
+ annotations.all(this::hasAnnotation)
+
@Deprecated(
replaceWith = ReplaceWith("getAnnotation(annotation)"),
message = "Use getAnnotation(not repeatable) or getAnnotations (repeatable)"
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XElementTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XElementTest.kt
index aeaed8f..b231e22 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XElementTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XElementTest.kt
@@ -31,6 +31,7 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
+import kotlin.reflect.KClass
@RunWith(JUnit4::class)
class XElementTest {
@@ -271,6 +272,53 @@
}
@Test
+ fun hasAllAnnotations() {
+ val source = Source.java(
+ "foo.bar.Baz",
+ """
+ package foo.bar;
+ import org.junit.*;
+ import org.junit.runner.*;
+ import org.junit.runners.*;
+ import androidx.room.compiler.processing.testcode.OtherAnnotation;
+
+ @RunWith(JUnit4.class)
+ class Baz {
+ @OtherAnnotation(value="xx")
+ String testField;
+
+ @org.junit.Test
+ @OtherAnnotation(value="yy")
+ void testMethod() {}
+ }
+ """.trimIndent()
+ )
+ runProcessorTest(
+ listOf(source)
+ ) {
+ val element = it.processingEnv.requireTypeElement("foo.bar.Baz")
+ assertThat(element.hasAllAnnotations(*arrayOf<KClass<Annotation>>())).isTrue()
+ assertThat(element.hasAllAnnotations(RunWith::class)).isTrue()
+ assertThat(element.hasAllAnnotations(RunWith::class, Test::class)).isFalse()
+
+ element.getMethod("testMethod").let { method ->
+ assertThat(method.hasAllAnnotations(*arrayOf<KClass<Annotation>>())).isTrue()
+ assertThat(method.hasAllAnnotations(Test::class)).isTrue()
+ assertThat(method.hasAllAnnotations(Test::class, OtherAnnotation::class)).isTrue()
+ assertThat(method.hasAllAnnotations(Test::class, OtherAnnotation::class,
+ RunWith::class)).isFalse()
+ }
+ element.getField("testField").let { field ->
+ assertThat(field.hasAllAnnotations(*arrayOf<KClass<Annotation>>())).isTrue()
+ assertThat(field.hasAllAnnotations(OtherAnnotation::class)).isTrue()
+ assertThat(field.hasAllAnnotations(OtherAnnotation::class, Test::class)).isFalse()
+ assertThat(field.hasAllAnnotations(OtherAnnotation::class, OtherAnnotation::class))
+ .isTrue()
+ }
+ }
+ }
+
+ @Test
fun nonType() {
val source = Source.java(
"foo.bar.Baz",
diff --git a/settings.gradle b/settings.gradle
index b6fcfd3..5de4f86 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -245,8 +245,8 @@
includeProject(":benchmark:benchmark-macro", "benchmark/benchmark-macro", [BuildType.MAIN, BuildType.COMPOSE])
includeProject(":benchmark:benchmark-macro-junit4", "benchmark/benchmark-macro-junit4", [BuildType.MAIN, BuildType.COMPOSE])
includeProject(":benchmark:integration-tests:dry-run-benchmark", "benchmark/integration-tests/dry-run-benchmark", [BuildType.MAIN])
-includeProject(":benchmark:integration-tests:macrobenchmark", "benchmark/integration-tests/macrobenchmark", [BuildType.MAIN, BuildType.COMPOSE])
-includeProject(":benchmark:integration-tests:macrobenchmark-target", "benchmark/integration-tests/macrobenchmark-target", [BuildType.MAIN, BuildType.COMPOSE])
+includeProject(":benchmark:integration-tests:macrobenchmark", "benchmark/integration-tests/macrobenchmark", [BuildType.MAIN])
+includeProject(":benchmark:integration-tests:macrobenchmark-target", "benchmark/integration-tests/macrobenchmark-target", [BuildType.MAIN])
includeProject(":benchmark:integration-tests:test-module-sample", "benchmark/integration-tests/test-module-sample", [BuildType.MAIN, BuildType.COMPOSE])
includeProject(":benchmark:integration-tests:startup-benchmark", "benchmark/integration-tests/startup-benchmark", [BuildType.MAIN])
includeProject(":biometric:biometric", "biometric/biometric", [BuildType.MAIN])
diff --git a/viewpager/viewpager/src/androidTest/java/androidx/viewpager/widget/ViewPagerWithTitleStripTest.java b/viewpager/viewpager/src/androidTest/java/androidx/viewpager/widget/ViewPagerWithTitleStripTest.java
index ae5c889..87412ed 100644
--- a/viewpager/viewpager/src/androidTest/java/androidx/viewpager/widget/ViewPagerWithTitleStripTest.java
+++ b/viewpager/viewpager/src/androidTest/java/androidx/viewpager/widget/ViewPagerWithTitleStripTest.java
@@ -30,6 +30,7 @@
/**
* Provides assertions that depend on the non-interactive nature of <code>PagerTabStrip</code>.
*/
+@FlakyTest(bugId = 179887413)
public class ViewPagerWithTitleStripTest
extends BaseViewPagerTest<ViewPagerWithTitleStripActivity> {
public ViewPagerWithTitleStripTest() {
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/InlineSliderScreenshotTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/InlineSliderScreenshotTest.kt
new file mode 100644
index 0000000..66062fe
--- /dev/null
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/InlineSliderScreenshotTest.kt
@@ -0,0 +1,204 @@
+/*
+ * 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 android.os.Build
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Star
+import androidx.compose.material.icons.filled.ThumbUp
+import androidx.compose.testutils.assertAgainstGolden
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.screenshot.AndroidXScreenshotTestRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestName
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+class InlineSliderScreenshotTest {
+
+ @get:Rule
+ val rule = createComposeRule()
+
+ @get:Rule
+ val screenshotRule = AndroidXScreenshotTestRule(SCREENSHOT_GOLDEN_PATH)
+
+ @get:Rule
+ val testName = TestName()
+
+ @Test
+ fun inlineslider_not_segmented() {
+ rule.setContentWithTheme {
+ InlineSlider(
+ modifier = Modifier.testTag(TEST_TAG),
+ value = 2f,
+ segmented = false,
+ onValueChange = { },
+ valueRange = 1f..4f,
+ steps = 2
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG)
+ .captureToImage()
+ .assertAgainstGolden(screenshotRule, testName.methodName)
+ }
+
+ @Test
+ fun inlineslider_segmented() {
+ rule.setContentWithTheme {
+ InlineSlider(
+ modifier = Modifier.testTag(TEST_TAG),
+ value = 2f,
+ segmented = true,
+ onValueChange = { },
+ valueRange = 1f..4f,
+ steps = 2
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG)
+ .captureToImage()
+ .assertAgainstGolden(screenshotRule, testName.methodName)
+ }
+
+ @Test
+ fun inlineslider_segmented_with_custom_colors() {
+ rule.setContentWithTheme {
+ InlineSlider(
+ modifier = Modifier.testTag(TEST_TAG),
+ value = 2f,
+ segmented = true,
+ colors = InlineSliderDefaults.colors(
+ backgroundColor = Color.Green,
+ spacerColor = Color.Yellow,
+ selectedBarColor = Color.Magenta,
+ unselectedBarColor = Color.White,
+ disabledBackgroundColor = Color.DarkGray,
+ disabledSpacerColor = Color.LightGray,
+ disabledSelectedBarColor = Color.Red,
+ disabledUnselectedBarColor = Color.Blue
+ ),
+ onValueChange = { },
+ valueRange = 1f..4f,
+ steps = 2
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG)
+ .captureToImage()
+ .assertAgainstGolden(screenshotRule, testName.methodName)
+ }
+
+ @Test
+ fun inlineslider_custom_icons() {
+ rule.setContentWithTheme {
+ InlineSlider(
+ modifier = Modifier.testTag(TEST_TAG),
+ value = 2f,
+ onValueChange = { },
+ valueRange = 1f..4f,
+ decreaseIcon = {
+ Icon(
+ imageVector = Icons.Default.Star,
+ contentDescription = ""
+ )
+ },
+ increaseIcon = {
+ Icon(
+ imageVector = Icons.Filled.ThumbUp,
+ contentDescription = ""
+ )
+ },
+ steps = 2
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG)
+ .captureToImage()
+ .assertAgainstGolden(screenshotRule, testName.methodName)
+ }
+
+ @Test
+ fun inlineslider_segmented_with_custom_colors_disabled() {
+ rule.setContentWithTheme {
+ InlineSlider(
+ modifier = Modifier.testTag(TEST_TAG),
+ value = 2f,
+ enabled = false,
+ segmented = true,
+ colors = InlineSliderDefaults.colors(
+ backgroundColor = Color.Green,
+ spacerColor = Color.Yellow,
+ selectedBarColor = Color.Magenta,
+ unselectedBarColor = Color.White,
+ disabledBackgroundColor = Color.DarkGray,
+ disabledSpacerColor = Color.LightGray,
+ disabledSelectedBarColor = Color.Red,
+ disabledUnselectedBarColor = Color.Blue
+ ),
+ onValueChange = { },
+ valueRange = 1f..4f,
+ steps = 2
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG)
+ .captureToImage()
+ .assertAgainstGolden(screenshotRule, testName.methodName)
+ }
+
+ @Test
+ fun inlineslider_custom_icons_disabled() {
+ rule.setContentWithTheme {
+ InlineSlider(
+ modifier = Modifier.testTag(TEST_TAG),
+ value = 2f,
+ enabled = false,
+ onValueChange = { },
+ valueRange = 1f..4f,
+ decreaseIcon = {
+ Icon(
+ imageVector = Icons.Default.Star,
+ contentDescription = ""
+ )
+ },
+ increaseIcon = {
+ Icon(
+ imageVector = Icons.Filled.ThumbUp,
+ contentDescription = ""
+ )
+ },
+ steps = 2
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG)
+ .captureToImage()
+ .assertAgainstGolden(screenshotRule, testName.methodName)
+ }
+}
\ No newline at end of file
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/InlineSliderTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/InlineSliderTest.kt
index 156e9f1..54dce95 100644
--- a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/InlineSliderTest.kt
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/InlineSliderTest.kt
@@ -16,13 +16,24 @@
package androidx.wear.compose.material
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Star
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.semantics.ProgressBarRangeInfo
+import androidx.compose.ui.test.assertLeftPositionInRootIsEqualTo
import androidx.compose.ui.test.assertRangeInfoEquals
+import androidx.compose.ui.test.click
+import androidx.compose.ui.test.getUnclippedBoundsInRoot
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.onRoot
+import androidx.compose.ui.test.performTouchInput
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.width
+import com.google.common.truth.Truth
import org.junit.Rule
import org.junit.Test
@@ -160,4 +171,179 @@
rule.onNodeWithTag(TEST_TAG)
.assertRangeInfoEquals(ProgressBarRangeInfo(0.6f, range, 4))
}
+
+ @Test
+ fun decreases_value_by_clicking_left() {
+ val state = mutableStateOf(2f)
+ rule.setContentWithTheme {
+ InlineSlider(
+ modifier = Modifier.testTag(TEST_TAG),
+ value = state.value,
+ onValueChange = { state.value = it },
+ valueRange = 1f..4f,
+ steps = 2
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).performTouchInput { click(Offset(15f, height / 2f)) }
+ rule.runOnIdle {
+ Truth.assertThat(state.value).isWithin(0.001f).of(1f)
+ }
+ }
+
+ @Test
+ fun increases_value_by_clicking_right() {
+ val state = mutableStateOf(2f)
+ rule.setContentWithTheme {
+ InlineSlider(
+ modifier = Modifier.testTag(TEST_TAG),
+ value = state.value,
+ onValueChange = { state.value = it },
+ valueRange = 1f..4f,
+ steps = 2
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).performTouchInput { click(Offset(width - 15f, height / 2f)) }
+ rule.runOnIdle {
+ Truth.assertThat(state.value).isWithin(0.001f).of(3f)
+ }
+ }
+
+ @Test
+ fun ignores_left_click_when_disabled() {
+ val state = mutableStateOf(2f)
+ rule.setContentWithTheme {
+ InlineSlider(
+ modifier = Modifier.testTag(TEST_TAG),
+ value = state.value,
+ enabled = false,
+ onValueChange = { state.value = it },
+ valueRange = 1f..4f,
+ steps = 2
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).performTouchInput { click(Offset(15f, height / 2f)) }
+ rule.runOnIdle {
+ Truth.assertThat(state.value).isWithin(0.001f).of(2f)
+ }
+ }
+
+ @Test
+ fun ignores_right_click_when_disabled() {
+ val state = mutableStateOf(2f)
+ rule.setContentWithTheme {
+ InlineSlider(
+ modifier = Modifier.testTag(TEST_TAG),
+ value = state.value,
+ enabled = false,
+ onValueChange = { state.value = it },
+ valueRange = 1f..4f,
+ steps = 2
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).performTouchInput { click(Offset(width - 15f, height / 2f)) }
+ rule.runOnIdle {
+ Truth.assertThat(state.value).isWithin(0.001f).of(2f)
+ }
+ }
+
+ @Test
+ fun reaches_min_clicking_left() {
+ val state = mutableStateOf(1f)
+ rule.setContentWithTheme {
+ InlineSlider(
+ modifier = Modifier.testTag(TEST_TAG),
+ value = state.value,
+ onValueChange = { state.value = it },
+ valueRange = 1f..4f,
+ steps = 2
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).performTouchInput { click(Offset(15f, height / 2f)) }
+ rule.runOnIdle {
+ Truth.assertThat(state.value).isWithin(0.001f).of(1f)
+ }
+ }
+
+ @Test
+ fun reaches_max_clicking_right() {
+ val state = mutableStateOf(4f)
+ rule.setContentWithTheme {
+ InlineSlider(
+ modifier = Modifier.testTag(TEST_TAG),
+ value = state.value,
+ onValueChange = { state.value = it },
+ valueRange = 1f..4f,
+ steps = 2
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).performTouchInput { click(Offset(width - 15f, height / 2f)) }
+ rule.runOnIdle {
+ Truth.assertThat(state.value).isWithin(0.001f).of(4f)
+ }
+ }
+
+ @Test
+ fun sets_custom_decrease_icon() {
+ val iconTag = "iconTag_test"
+
+ rule.setContentWithTheme {
+ InlineSlider(
+ modifier = Modifier.testTag(TEST_TAG),
+ value = 0f,
+ steps = 5,
+ onValueChange = { },
+ decreaseIcon = {
+ Icon(
+ modifier = Modifier.testTag(iconTag),
+ imageVector = Icons.Default.Star,
+ contentDescription = ""
+ )
+ }
+ )
+ }
+
+ rule.waitForIdle()
+ rule.onNodeWithTag(iconTag, true)
+ .assertExists()
+ .assertLeftPositionInRootIsEqualTo(IconsOuterHorizontalMargin)
+ }
+
+ @Test
+ fun sets_custom_increase_icon() {
+ val iconTag = "iconTag_test"
+
+ rule.setContentWithTheme {
+ InlineSlider(
+ modifier = Modifier.testTag(TEST_TAG),
+ value = 0f,
+ steps = 5,
+ onValueChange = { },
+ increaseIcon = {
+ Icon(
+ modifier = Modifier.testTag(iconTag),
+ imageVector = Icons.Default.Star,
+ contentDescription = ""
+ )
+ }
+ )
+ }
+ val unclippedBoundsInRoot = rule.onRoot().getUnclippedBoundsInRoot()
+
+ rule.waitForIdle()
+ rule.onNodeWithTag(iconTag, true)
+ .assertExists()
+ .assertLeftPositionInRootIsEqualTo(
+ unclippedBoundsInRoot.width -
+ IconsOuterHorizontalMargin - DefaultIconWidth
+ )
+ }
+
+ private val IconsOuterHorizontalMargin = 8.dp
+ private val DefaultIconWidth = 24.dp
}
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/Slider.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/Slider.kt
index 4db4d33..3877a46 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/Slider.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/Slider.kt
@@ -276,7 +276,7 @@
selectedBarColor: Color = MaterialTheme.colors.secondary,
unselectedBarColor: Color = MaterialTheme.colors.onSurface.copy(0.1f),
disabledBackgroundColor: Color = backgroundColor.copy(alpha = ContentAlpha.disabled),
- disabledSpacerColor: Color = spacerColor,
+ disabledSpacerColor: Color = spacerColor.copy(alpha = ContentAlpha.disabled),
disabledSelectedBarColor: Color = selectedBarColor.copy(alpha = ContentAlpha.disabled),
disabledUnselectedBarColor: Color = unselectedBarColor.copy(alpha = 0.05f),
): InlineSliderColors = DefaultInlineSliderColors(
diff --git a/wear/tiles/tiles-proto/build.gradle b/wear/tiles/tiles-proto/build.gradle
index 90014de..6d9735e 100644
--- a/wear/tiles/tiles-proto/build.gradle
+++ b/wear/tiles/tiles-proto/build.gradle
@@ -15,10 +15,8 @@
*/
import androidx.build.LibraryGroups
-import androidx.build.LibraryVersions
import androidx.build.Publish
import androidx.build.RunApiTasks
-import androidx.build.dependencies.DependenciesKt
import com.github.jengelman.gradle.plugins.shadow.transformers.DontIncludeResourceTransformer
plugins {
@@ -80,7 +78,7 @@
protobuf {
protoc {
- artifact = DependenciesKt.getDependencyAsString(libs.protobufCompiler)
+ artifact = libs.protobufCompiler.get()
}
// Generates the java proto-lite code for the protos in this project. See
diff --git a/webkit/OWNERS b/webkit/OWNERS
index 4a97867..8ced73f 100644
--- a/webkit/OWNERS
+++ b/webkit/OWNERS
@@ -1,6 +1,3 @@
# Bug component: 460423
-changwan@google.com
-laisminchillo@google.com
ntfschr@google.com
-tobiasjs@google.com
torne@google.com