Merge "Remove synchronization from methods in androidx.core" into androidx-main
diff --git a/.github/workflows/presubmit.yml b/.github/workflows/presubmit.yml
index 2bd8dca..b081506a 100644
--- a/.github/workflows/presubmit.yml
+++ b/.github/workflows/presubmit.yml
@@ -557,27 +557,6 @@
wrapper-directory: ${{ env.project-root }}/gradle/wrapper
wrapper-cache-enabled: true
- - name: Set up Cloud SDK
- uses: google-github-actions/setup-gcloud@master
- if: ${{ github.repository == 'androidX/androidx' }}
- with:
- project_id: ${{ secrets.GCP_PROJECT_ID }}
- service_account_key: ${{ secrets.GCP_SA_KEY }}
- export_default_credentials: true
- - name: "Run application tests on Firebase Test Lab"
- uses: eskatos/gradle-command-action@v1
- if: ${{ github.repository == 'androidX/androidx' }}
- env:
- JAVA_HOME: ${{ steps.setup-java.outputs.path }}
- with:
- arguments: firebaseTestLabTests ${{ needs.setup.outputs.gradlew_flags }}
- build-root-directory: ${{ env.project-root }}
- configuration-cache-enabled: true
- dependencies-cache-enabled: true
- gradle-executable: ${{ env.project-root }}/gradlew
- wrapper-directory: ${{ env.project-root }}/gradle/wrapper
- wrapper-cache-enabled: true
-
- name: "upload build artifacts"
continue-on-error: true
if: always()
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/LayoutInflaterFactoryTestCase.java b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/LayoutInflaterFactoryTestCase.java
index 15d4194..8b17ada 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/LayoutInflaterFactoryTestCase.java
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/LayoutInflaterFactoryTestCase.java
@@ -43,7 +43,6 @@
import androidx.test.annotation.UiThreadTest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
-import androidx.test.rule.ActivityTestRule;
import org.junit.Before;
import org.junit.Rule;
@@ -52,9 +51,11 @@
@RunWith(AndroidJUnit4.class)
public class LayoutInflaterFactoryTestCase {
+
+ @SuppressWarnings("deprecation")
@Rule
- public final ActivityTestRule<LayoutInflaterFactoryTestActivity> mActivityTestRule =
- new ActivityTestRule<>(LayoutInflaterFactoryTestActivity.class);
+ public final androidx.test.rule.ActivityTestRule<LayoutInflaterFactoryTestActivity> mTestRule =
+ new androidx.test.rule.ActivityTestRule<>(LayoutInflaterFactoryTestActivity.class);
@Before
public void setup() {
@@ -66,7 +67,7 @@
@Test
@SmallTest
public void testAndroidThemeInflation() {
- final LayoutInflater inflater = LayoutInflater.from(mActivityTestRule.getActivity());
+ final LayoutInflater inflater = LayoutInflater.from(mTestRule.getActivity());
assertThemedContext(inflater.inflate(R.layout.layout_android_theme, null));
}
@@ -74,7 +75,7 @@
@Test
@SmallTest
public void testAppThemeInflation() {
- final LayoutInflater inflater = LayoutInflater.from(mActivityTestRule.getActivity());
+ final LayoutInflater inflater = LayoutInflater.from(mTestRule.getActivity());
assertThemedContext(inflater.inflate(R.layout.layout_app_theme, null));
}
@@ -83,7 +84,7 @@
@Test
@SmallTest
public void testAndroidThemeWithChildrenInflation() {
- LayoutInflater inflater = LayoutInflater.from(mActivityTestRule.getActivity());
+ LayoutInflater inflater = LayoutInflater.from(mTestRule.getActivity());
final ViewGroup root = (ViewGroup) inflater.inflate(
R.layout.layout_android_theme_children, null);
assertThemedContext(root);
@@ -93,7 +94,7 @@
@Test
@SmallTest
public void testAndroidThemeWithIncludeInflation() {
- LayoutInflater inflater = LayoutInflater.from(mActivityTestRule.getActivity());
+ LayoutInflater inflater = LayoutInflater.from(mTestRule.getActivity());
final ViewGroup root = (ViewGroup) inflater.inflate(
R.layout.layout_android_theme_with_include, null);
assertThemedContext(root.findViewById(R.id.included_view));
@@ -102,8 +103,19 @@
@UiThreadTest
@Test
@SmallTest
+ public void testAndroidThemeWithMergeInflation() {
+ LayoutInflater inflater = LayoutInflater.from(mTestRule.getActivity());
+ final ViewGroup root = (ViewGroup) inflater.inflate(
+ R.layout.layout_android_theme_with_merge, null);
+ assertThemedContext(root.findViewById(R.id.merged_view));
+ assertThemedContext(root.findViewById(R.id.merged_view_2));
+ }
+
+ @UiThreadTest
+ @Test
+ @SmallTest
public void testThemedInflationWithUnattachedParent() {
- final Context activity = mActivityTestRule.getActivity();
+ final Context activity = mTestRule.getActivity();
// Create a parent but not attached
final LinearLayout parent = new LinearLayout(activity);
@@ -205,15 +217,15 @@
@Test
@SmallTest
public void testDeclarativeOnClickWithContextWrapper() {
- LayoutInflater inflater = LayoutInflater.from(mActivityTestRule.getActivity());
+ LayoutInflater inflater = LayoutInflater.from(mTestRule.getActivity());
View view = inflater.inflate(R.layout.layout_button_themed_onclick, null);
assertTrue(view.performClick());
- assertTrue(mActivityTestRule.getActivity().wasDeclarativeOnClickCalled());
+ assertTrue(mTestRule.getActivity().wasDeclarativeOnClickCalled());
}
private void verifyAppCompatWidgetInflation(final int layout, final Class<?> expectedClass) {
- LayoutInflater inflater = LayoutInflater.from(mActivityTestRule.getActivity());
+ LayoutInflater inflater = LayoutInflater.from(mTestRule.getActivity());
View view = inflater.inflate(layout, null);
assertSame("View is " + expectedClass.getSimpleName(), expectedClass,
view.getClass());
diff --git a/appcompat/appcompat/src/androidTest/res/layout/layout_android_theme_merged_views.xml b/appcompat/appcompat/src/androidTest/res/layout/layout_android_theme_merged_views.xml
new file mode 100644
index 0000000..37c5c1e
--- /dev/null
+++ b/appcompat/appcompat/src/androidTest/res/layout/layout_android_theme_merged_views.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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.
+-->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <TextView
+ android:id="@+id/merged_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Test" />
+
+ <TextView
+ android:id="@+id/merged_view_2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Test 2" />
+
+</merge>
\ No newline at end of file
diff --git a/appcompat/appcompat/src/androidTest/res/layout/layout_android_theme_with_merge.xml b/appcompat/appcompat/src/androidTest/res/layout/layout_android_theme_with_merge.xml
new file mode 100644
index 0000000..c9d3511
--- /dev/null
+++ b/appcompat/appcompat/src/androidTest/res/layout/layout_android_theme_with_merge.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:theme="@style/MagentaThemeOverlay">
+
+ <include layout="@layout/layout_android_theme_merged_views"
+ android:id="@+id/included_view" />
+
+</FrameLayout>
\ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/androidx/build/AndroidXPlaygroundRootPlugin.kt b/buildSrc/src/main/kotlin/androidx/build/AndroidXPlaygroundRootPlugin.kt
index e229ac9..b7b0d63 100644
--- a/buildSrc/src/main/kotlin/androidx/build/AndroidXPlaygroundRootPlugin.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/AndroidXPlaygroundRootPlugin.kt
@@ -17,7 +17,6 @@
package androidx.build
import androidx.build.AndroidXRootPlugin.Companion.PROJECT_OR_ARTIFACT_EXT_NAME
-import androidx.build.ftl.FirebaseTestLabHelper
import androidx.build.gradle.getByType
import androidx.build.gradle.isRoot
import com.android.build.gradle.LibraryExtension
@@ -71,9 +70,8 @@
config = PlaygroundProperties.load(rootProject)
repos = PlaygroundRepositories(config)
rootProject.repositories.addPlaygroundRepositories()
- val ftlUtilities = FirebaseTestLabHelper(target)
rootProject.subprojects {
- configureSubProject(it, ftlUtilities)
+ configureSubProject(it)
}
// TODO(b/185539993): Re-enable InvalidFragmentVersionForActivityResult which was
@@ -99,10 +97,7 @@
}
}
- private fun configureSubProject(
- project: Project,
- firebaseTestLabHelper: FirebaseTestLabHelper
- ) {
+ private fun configureSubProject(project: Project) {
project.repositories.addPlaygroundRepositories()
project.extra.set(PROJECT_OR_ARTIFACT_EXT_NAME, projectOrArtifactClosure)
project.configurations.all { configuration ->
@@ -110,7 +105,6 @@
substitution.replaceIfSnapshot()
}
}
- firebaseTestLabHelper.setupFTL(project)
}
/**
diff --git a/buildSrc/src/main/kotlin/androidx/build/ftl/FirebaseTestLabHelper.kt b/buildSrc/src/main/kotlin/androidx/build/ftl/FirebaseTestLabHelper.kt
deleted file mode 100644
index 04ab48b..0000000
--- a/buildSrc/src/main/kotlin/androidx/build/ftl/FirebaseTestLabHelper.kt
+++ /dev/null
@@ -1,80 +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.build.ftl
-
-import androidx.build.gradle.isRoot
-import com.android.build.gradle.TestedExtension
-import org.gradle.api.Project
-
-/**
- * Helper class to setup Firebase Test Lab for instrumentation tests
- */
-internal class FirebaseTestLabHelper(
- private val rootProject: Project
-) {
- init {
- check(rootProject.isRoot) {
- "FTL Utilities can only be created for root projects"
- }
- }
-
- private val anchorTask by lazy {
- rootProject.tasks.register(ANCHOR_TASK_NAME) {
- it.description = "Anchor task that depends on all firebase test lab tests"
- it.group = "Verification"
- }
- }
-
- fun setupFTL(project: Project) {
- AGP_PLUGIN_IDS.forEach { agpPluginId ->
- // using base plugin at this stage does not work as base plugin is applied before the
- // Android Extension is created.
- // see the comment on [AGP_PLUGIN_IDS] for details.
- project.pluginManager.withPlugin(agpPluginId) {
- project.extensions.findByType(TestedExtension::class.java)?.let {
- configure(project, it)
- }
- }
- }
- }
-
- private fun configure(project: Project, testedExtension: TestedExtension) {
- testedExtension.testVariants.all { testVariant ->
- RunTestOnFTLTask.create(project, testVariant)?.let { ftlTask ->
- anchorTask.configure { it.dependsOn(ftlTask) }
- }
- }
- }
-
- companion object {
- const val ANCHOR_TASK_NAME = "firebaseTestLabTests"
-
- /**
- * AGP base plugin is applied before the extension is created so instead we use plugin
- * ids here.
- * see: https://github.com/google/ksp/issues/314
- * see: https://github.com/google/ksp/pull/318
- */
- private val AGP_PLUGIN_IDS = listOf(
- "com.android.application",
- // TODO enable library and dynamic feature when we can synthesize
- // an APK for them
- // "com.android.library",
- // "com.android.dynamic-feature"
- )
- }
-}
\ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/androidx/build/ftl/GCloudCLIWrapper.kt b/buildSrc/src/main/kotlin/androidx/build/ftl/GCloudCLIWrapper.kt
deleted file mode 100644
index 385e271..0000000
--- a/buildSrc/src/main/kotlin/androidx/build/ftl/GCloudCLIWrapper.kt
+++ /dev/null
@@ -1,260 +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.build.ftl
-
-import androidx.build.ftl.GCloudCLIWrapper.RunTestParameters.Companion.TEST_OUTPUT_FILE_NAME
-import com.google.gson.Gson
-import com.google.gson.annotations.SerializedName
-import com.google.gson.reflect.TypeToken
-import org.gradle.api.GradleException
-import org.gradle.process.ExecOperations
-import java.io.ByteArrayOutputStream
-import java.io.File
-import java.util.Locale
-import java.util.UUID
-
-/**
- * Wrapper around GCloud CLI.
- *
- * https://cloud.google.com/sdk/gcloud
- *
- * Note that this wrapper requires gcloud to be available on the host machine.
- *
- * documentation for FTL:
- * https://cloud.google.com/sdk/gcloud/reference/firebase/test/android/run
- */
-@Suppress("UnstableApiUsage") // ExecOperations
-internal class GCloudCLIWrapper(
- private val execOperations: ExecOperations
-) {
- private val gson = Gson()
-
- /**
- * Path to the gcloud executable, derived from `which gcloud` call.
- */
- private val gcloud: String by lazy {
- findExecutable("gcloud")
- }
-
- /**
- * Path to the gsutil executable, derived from `which gsutil` call.
- */
- private val gsutil: String by lazy {
- findExecutable("gsutil")
- }
-
- private inline fun <reified T> executeGcloud(
- vararg params: String
- ): T {
- val output = ByteArrayOutputStream()
- val errorOutput = ByteArrayOutputStream()
- val execResult = execOperations.exec {
- it.executable = gcloud
- it.args = params.toList() + "--format=json"
- it.standardOutput = output
- it.errorOutput = errorOutput
- it.isIgnoreExitValue = true
- }
- if (execResult.exitValue != 0) {
- System.err.println("GCloud command failed: ${errorOutput.toString(Charsets.UTF_8)}")
- }
- // still try to parse the because when it fails (e.g. test failure), it returns a non-0
- // exit code but still prints the output. We are interested in the output.
- val commandOutput = output.toString(Charsets.UTF_8)
- return gson.parse(commandOutput)
- }
-
- private fun execGsUtil(
- vararg params: String
- ): String {
- val output = ByteArrayOutputStream()
- execOperations.exec {
- it.executable = gsutil
- it.args = params.toList()
- it.standardOutput = output
- }
- return output.toString(Charsets.UTF_8)
- }
-
- /**
- * https://cloud.google.com/sdk/gcloud/reference/firebase/test/android/run
- */
- fun runTest(
- params: RunTestParameters
- ): List<TestResult> {
- val testResults = executeGcloud<List<TestResult>>(
- "firebase", "test", "android", "run",
- "--type", "instrumentation",
- "--test", params.testApk.canonicalPath,
- "--app", params.testedApk.canonicalPath,
- "--num-flaky-test-attempts", "2",
- "--results-bucket=${params.bucketName}",
- "--results-dir=${params.resultsBucketDir}",
- "--results-history-name=${params.projectPath}"
- )
- // copy the test results from the bucket to the build directory
- execGsUtil(
- "cp", "-r", params.cloudBucketPath() + "/*", params.resultsLocalDir.canonicalPath
- )
- // finally, write the command response into the directory as well
- val testResultOutput = params.resultsLocalDir.resolve(TEST_OUTPUT_FILE_NAME)
- testResultOutput.bufferedWriter(Charsets.UTF_8).use {
- gson.toJson(
- testResults,
- it
- )
- }
- return testResults
- }
-
- /**
- * find the given executable's path in the PATH via `which` command.
- */
- private fun findExecutable(name: String): String {
- val output = ByteArrayOutputStream()
- val result = execOperations.exec {
- it.commandLine("which", name)
- it.standardOutput = output
- it.isIgnoreExitValue = true
- }
- if (result.exitValue != 0) {
- throw GradleException(
- """
- Unable to find $name CLI executable.
- `which $name` returned exit code ${result.exitValue}.
- Make sure gcloud CLI is installed, authenticated and is part of your PATH.
- See https://cloud.google.com/sdk/gcloud for installation instructions.
- """.trimIndent()
- )
- }
- return output.toString(Charsets.UTF_8).trim()
- }
-
- /**
- * Data structure format for gcloud FTL command
- */
- internal data class TestResult(
- @SerializedName("axis_value")
- val axisValue: String,
- val outcome: String,
- @SerializedName("test_details")
- val testDetails: String
- ) {
- val passed
- get() = outcome.toLowerCase(Locale.US) in SUCCESS_OUTCOMES
-
- companion object {
- private val SUCCESS_OUTCOMES = listOf("passed", "flaky")
- }
- }
-
- /**
- * Parameters for invoking a test on the Firebase Test Lab
- */
- internal data class RunTestParameters(
- /**
- * The project path for which we are executing the tests for.
- */
- val projectPath: String,
- /**
- * The tested APK file
- */
- val testedApk: File,
- /**
- * The test APK file which includes the instrumentation tests
- */
- val testApk: File,
- /**
- * The name of the GS bucket to save the results
- */
- val bucketName: String = DEFAULT_BUCKET_NAME,
- /**
- * The GS Bucket directory where the results will be saved
- */
- val resultsBucketDir: String = buildRelativeResultDirPath(projectPath),
- /**
- * The local directory where we will download the test results
- */
- val resultsLocalDir: File,
- ) {
-
- /**
- * Returns the path to the Google Cloud bucket where the test run results are saved
- */
- fun cloudBucketPath(): String {
- return "gs://$bucketName/$resultsBucketDir"
- }
-
- companion object {
- const val DEFAULT_BUCKET_NAME = "androidx-ftl-test-results"
-
- /**
- * The file into which the result of the gcloud command will be written.
- */
- const val TEST_OUTPUT_FILE_NAME = "testResults.json"
-
- /**
- * Generates a relative path for test results.
- *
- * If run on Github Actions CI, this method will use the environment variables to
- * create a unique path for the action.
- * If run locally, this will create a random UUID for the directory.
- */
- private fun buildRelativeResultDirPath(
- projectPath: String
- ): String {
- // github action env variables:
- // https://docs.github.com/en/actions/reference/environment-variables
- val inGithubActions = System.getenv().containsKey("GITHUB_ACTIONS")
- val pathValues = if (inGithubActions) {
- val workflowName = requireEnvValue("GITHUB_WORKFLOW")
- val runNumber = requireEnvValue("GITHUB_RUN_NUMBER")
- val runId = requireEnvValue("GITHUB_RUN_ID")
- val ref = System.getenv("GITHUB_REF")
- listOfNotNull(
- "github",
- projectPath,
- ref,
- workflowName,
- runNumber,
- runId,
- )
- } else {
- listOf(
- "local",
- projectPath,
- UUID.randomUUID().toString()
- )
- }
- return pathValues.joinToString("/")
- }
-
- private fun requireEnvValue(name: String): String {
- return System.getenv(name) ?: throw GradleException(
- "Cannot find required environment variable: $name"
- )
- }
- }
- }
-}
-
-private inline fun <reified T> Gson.parse(
- input: String
-): T {
- val typeToken = object : TypeToken<T>() {}.type
- return this.fromJson(input, typeToken)
-}
\ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/androidx/build/ftl/RunTestOnFTLTask.kt b/buildSrc/src/main/kotlin/androidx/build/ftl/RunTestOnFTLTask.kt
deleted file mode 100644
index 8ec207d..0000000
--- a/buildSrc/src/main/kotlin/androidx/build/ftl/RunTestOnFTLTask.kt
+++ /dev/null
@@ -1,185 +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.build.ftl
-
-import androidx.build.getDistributionDirectory
-import androidx.build.getSupportRootFolder
-import com.android.build.gradle.api.ApkVariant
-import com.android.build.gradle.api.ApkVariantOutput
-import com.android.build.gradle.api.TestVariant
-import org.gradle.api.DefaultTask
-import org.gradle.api.GradleException
-import org.gradle.api.Project
-import org.gradle.api.file.DirectoryProperty
-import org.gradle.api.file.RegularFileProperty
-import org.gradle.api.provider.Property
-import org.gradle.api.tasks.CacheableTask
-import org.gradle.api.tasks.Copy
-import org.gradle.api.tasks.InputFile
-import org.gradle.api.tasks.OutputDirectory
-import org.gradle.api.tasks.PathSensitive
-import org.gradle.api.tasks.PathSensitivity
-import org.gradle.api.tasks.TaskAction
-import org.gradle.api.tasks.TaskProvider
-import org.gradle.process.ExecOperations
-import org.gradle.workers.WorkAction
-import org.gradle.workers.WorkParameters
-import org.gradle.workers.WorkerExecutor
-import javax.inject.Inject
-
-/**
- * Task to run instrumentation tests on FTL.
- *
- * This task is only enabled on playground projects and requires gcloud CLI to be available on
- * the device with the right permissions.
- *
- * Due to the limitations of FTL, this task only support application instrumentation tests for now.
- */
-@Suppress("UnstableApiUsage") // for gradle property APIs
-@CacheableTask
-abstract class RunTestOnFTLTask @Inject constructor(
- private val workerExecutor: WorkerExecutor
-) : DefaultTask() {
- /**
- * The test APK for the instrumentation test.
- */
- @get:[InputFile PathSensitive(PathSensitivity.NONE)]
- abstract val testApk: RegularFileProperty
-
- /**
- * The tested application APK.
- */
- @get:[InputFile PathSensitive(PathSensitivity.NONE)]
- abstract val testedApk: RegularFileProperty
-
- /**
- * Output file to write the results
- */
- @get:OutputDirectory
- abstract val testResults: DirectoryProperty
-
- @TaskAction
- fun executeTest() {
- workerExecutor.noIsolation().submit(
- RunFTLTestWorkAction::class.java
- ) {
- it.testApk.set(testApk)
- it.testedApk.set(testedApk)
- it.testResults.set(testResults)
- it.projectPath.set(project.relativeResultPath())
- }
- }
-
- interface RunFTLTestParams : WorkParameters {
- val projectPath: Property<String>
- val testApk: RegularFileProperty
- val testedApk: RegularFileProperty
- val testResults: DirectoryProperty
- }
-
- abstract class RunFTLTestWorkAction @Inject constructor(
- private val execOperations: ExecOperations
- ) : WorkAction<RunFTLTestParams> {
- override fun execute() {
- val localTestResultDir = parameters.testResults.asFile.get()
- localTestResultDir.apply {
- deleteRecursively()
- mkdirs()
- }
- val testApk = parameters.testApk.asFile.get()
- val testedApk = parameters.testedApk.asFile.get()
- val gcloud = GCloudCLIWrapper(execOperations)
- val params = GCloudCLIWrapper.RunTestParameters(
- testedApk = testedApk,
- testApk = testApk,
- projectPath = parameters.projectPath.get(),
- resultsLocalDir = localTestResultDir
-
- )
- val result = gcloud.runTest(params)
- val failed = result.filterNot {
- it.passed
- }
- if (failed.isNotEmpty()) {
- throw GradleException("These tests failed: $failed")
- }
- }
- }
-
- companion object {
- private const val TASK_SUFFIX = "OnFirebaseTestLab"
-
- /**
- * Creates an FTL test runner task and returns it.
- * Note that only application tests are supported hence this will return `null` for
- * library projects.
- */
- fun create(project: Project, testVariant: TestVariant): TaskProvider<RunTestOnFTLTask>? {
- // TODO add support for library project, which might require synthesizing another
- // APK :facepalm:
- // see: // https://stackoverflow.com/questions/59827750/execute-instrumented-test-for-an-android-library-with-firebase-test-lab
- val testedVariant = testVariant.testedVariant as? ApkVariant
- ?: return null
- val taskName = testVariant.name + TASK_SUFFIX
- val testResultDir = project.layout.buildDirectory.dir(
- "ftl-results"
- )
- // create task to copy results into dist directory
- val copyToDistTask = project.tasks.register(
- "copyResultsOf${taskName}ToDist",
- Copy::class.java
- ) {
- it.description = "Copy test results from $taskName into DIST folder"
- it.group = "build"
- it.from(testResultDir)
- it.into(
- project.getDistributionDirectory()
- .resolve("ftl-results/${project.relativeResultPath()}/$taskName")
- )
- }
- return project.tasks.register(taskName, RunTestOnFTLTask::class.java) { task ->
- task.description = "Run ${testVariant.name} tests on Firebase Test Lab"
- task.group = "Verification"
- task.testResults.set(testResultDir)
- task.dependsOn(testVariant.packageApplicationProvider)
- task.dependsOn(testedVariant.packageApplicationProvider)
-
- task.testApk.set(
- testVariant.outputs
- .withType(ApkVariantOutput::class.java)
- .firstOrNull()
- ?.outputFile
- )
- task.testedApk.set(
- testedVariant.outputs
- .withType(ApkVariantOutput::class.java)
- .firstOrNull()
- ?.outputFile
- )
- task.finalizedBy(copyToDistTask)
- }
- }
- }
-}
-
-/**
- * Returns the relative path of the project wrt the support root. This path is used for both
- * local dist path and cloud bucket paths.
- */
-private fun Project.relativeResultPath() = projectDir.relativeTo(
- project.getSupportRootFolder()
-).path
\ No newline at end of file
diff --git a/camera/camera-view/api/current.txt b/camera/camera-view/api/current.txt
index 160857f..d9c61fc 100644
--- a/camera/camera-view/api/current.txt
+++ b/camera/camera-view/api/current.txt
@@ -75,5 +75,13 @@
enum_constant public static final androidx.camera.view.PreviewView.StreamState STREAMING;
}
+ public abstract class RotationReceiver {
+ ctor public RotationReceiver(android.content.Context);
+ method public boolean canDetectOrientation();
+ method public void disable();
+ method public void enable();
+ method public abstract void onRotationChanged(int);
+ }
+
}
diff --git a/camera/camera-view/api/public_plus_experimental_current.txt b/camera/camera-view/api/public_plus_experimental_current.txt
index 2faf2d6..a02bc5e 100644
--- a/camera/camera-view/api/public_plus_experimental_current.txt
+++ b/camera/camera-view/api/public_plus_experimental_current.txt
@@ -83,6 +83,14 @@
enum_constant public static final androidx.camera.view.PreviewView.StreamState STREAMING;
}
+ public abstract class RotationReceiver {
+ ctor public RotationReceiver(android.content.Context);
+ method public boolean canDetectOrientation();
+ method public void disable();
+ method public void enable();
+ method public abstract void onRotationChanged(int);
+ }
+
}
package androidx.camera.view.transform {
diff --git a/camera/camera-view/api/restricted_current.txt b/camera/camera-view/api/restricted_current.txt
index 56cdeaa..a47bbc3 100644
--- a/camera/camera-view/api/restricted_current.txt
+++ b/camera/camera-view/api/restricted_current.txt
@@ -75,5 +75,13 @@
enum_constant public static final androidx.camera.view.PreviewView.StreamState STREAMING;
}
+ public abstract class RotationReceiver {
+ ctor public RotationReceiver(android.content.Context);
+ method public boolean canDetectOrientation();
+ method public void disable();
+ method public void enable();
+ method public abstract void onRotationChanged(int);
+ }
+
}
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java b/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
index 2cab702..98d607f 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
@@ -205,7 +205,7 @@
// Synthetic access
@SuppressWarnings("WeakerAccess")
@NonNull
- final SensorRotationListener mSensorRotationListener;
+ final RotationReceiver mRotationReceiver;
@Nullable
private final DisplayRotationListener mDisplayRotationListener;
@@ -242,7 +242,7 @@
// Listen to motion sensor reading and set target rotation for ImageCapture and
// VideoCapture.
- mSensorRotationListener = new SensorRotationListener(mAppContext) {
+ mRotationReceiver = new RotationReceiver(mAppContext) {
@Override
public void onRotationChanged(int rotation) {
mImageAnalysis.setTargetRotation(rotation);
@@ -272,7 +272,7 @@
* Gets a {@link ListenableFuture} that completes when camera initialization completes.
*
* <p> This future may fail with an {@link InitializationException} and associated cause that
- * can be retrieved by {@link Throwable#getCause()). The cause will be a
+ * can be retrieved by {@link Throwable#getCause()}. The cause will be a
* {@link CameraUnavailableException} if it fails to access any camera during initialization.
*
* <p> In the rare case that the future fails with {@link CameraUnavailableException}, the
@@ -419,14 +419,14 @@
private void startListeningToRotationEvents() {
getDisplayManager().registerDisplayListener(mDisplayRotationListener,
new Handler(Looper.getMainLooper()));
- if (mSensorRotationListener.canDetectOrientation()) {
- mSensorRotationListener.enable();
+ if (mRotationReceiver.canDetectOrientation()) {
+ mRotationReceiver.enable();
}
}
private void stopListeningToRotationEvents() {
getDisplayManager().unregisterDisplayListener(mDisplayRotationListener);
- mSensorRotationListener.disable();
+ mRotationReceiver.disable();
}
private DisplayManager getDisplayManager() {
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/RotationReceiver.java b/camera/camera-view/src/main/java/androidx/camera/view/RotationReceiver.java
new file mode 100644
index 0000000..b64fad4
--- /dev/null
+++ b/camera/camera-view/src/main/java/androidx/camera/view/RotationReceiver.java
@@ -0,0 +1,137 @@
+/*
+ * 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.view;
+
+import android.content.Context;
+import android.hardware.SensorManager;
+import android.view.OrientationEventListener;
+import android.view.Surface;
+
+import androidx.annotation.NonNull;
+import androidx.camera.core.UseCase;
+
+/**
+ * Helper class for receiving rotation updates from the {@link SensorManager} when the
+ * orientation of the device has changed.
+ *
+ * <p> This class is an wrapper of {@link OrientationEventListener} that notifies the app about
+ * physical orientation changes in the format of {@link Surface} rotation. It's useful when the
+ * device UI is in a fixed portrait or landscape orientation, while the app still wants to set the
+ * {@link UseCase} target rotation based on the device's physical orientation.
+ *
+ * <pre><code>
+ * rotationReceiver = new RotationReceiver(context) {
+ * public void onRotationChanged(int rotation) {
+ * mImageCapture.setTargetRotation(rotation);
+ * }
+ * };
+ * if (rotationReceiver.canDetectOrientation()) {
+ * rotationReceiver.enable();
+ * }
+ *
+ * // Disable it when it's no longer needed.
+ * rotationReceiver.disable();
+ * </code></pre>
+ *
+ * @see OrientationEventListener
+ */
+public abstract class RotationReceiver {
+
+ private static final int INVALID_SURFACE_ROTATION = -1;
+
+ // Synthetic access
+ @SuppressWarnings("WeakerAccess")
+ int mRotation = INVALID_SURFACE_ROTATION;
+
+ private final OrientationEventListener mOrientationEventListener;
+
+ public RotationReceiver(@NonNull Context context) {
+ mOrientationEventListener = new OrientationEventListener(context) {
+ @Override
+ public void onOrientationChanged(int orientation) {
+ if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
+ // Short-circuit if orientation is unknown. Unknown rotation can't be handled
+ // so it shouldn't be sent.
+ return;
+ }
+
+ int newRotation;
+ if (orientation >= 315 || orientation < 45) {
+ newRotation = Surface.ROTATION_0;
+ } else if (orientation >= 225) {
+ newRotation = Surface.ROTATION_90;
+ } else if (orientation >= 135) {
+ newRotation = Surface.ROTATION_180;
+ } else {
+ newRotation = Surface.ROTATION_270;
+ }
+ if (mRotation != newRotation) {
+ mRotation = newRotation;
+ onRotationChanged(newRotation);
+ }
+ }
+ };
+ }
+
+ /**
+ * Checks if the RotationReceiver can detect orientation changes.
+ *
+ * @see OrientationEventListener#canDetectOrientation()
+ */
+ public boolean canDetectOrientation() {
+ return mOrientationEventListener.canDetectOrientation();
+ }
+
+ /**
+ * Enables the RotationReceiver so it will monitor the sensor and call onRotationChanged when
+ * the device orientation changes.
+ *
+ * <p> By default, the receiver is not enabled.
+ *
+ * @see OrientationEventListener#enable()
+ */
+ public void enable() {
+ mOrientationEventListener.enable();
+ }
+
+ /**
+ * Disables the RotationReceiver.
+ *
+ * @see OrientationEventListener#disable()
+ */
+ public void disable() {
+ mOrientationEventListener.disable();
+ }
+
+ /**
+ * Called when the physical rotation of the device changes.
+ *
+ * <p> The rotation is one of the {@link Surface} rotations mapped from orientation
+ * degrees.
+ *
+ * <table summary="Orientation degrees to Surface rotation mapping">
+ * <tr><th>Orientation degrees</th><th>Surface rotation</th></tr>
+ * <tr><td>[-45°, 45°)</td><td>{@link Surface#ROTATION_0}</td></tr>
+ * <tr><td>[45°, 135°)</td><td>{@link Surface#ROTATION_270}</td></tr>
+ * <tr><td>[135°, 225°)</td><td>{@link Surface#ROTATION_180}</td></tr>
+ * <tr><td>[225°, 315°)</td><td>{@link Surface#ROTATION_90}</td></tr>
+ * </table>
+ *
+ * @see OrientationEventListener#onOrientationChanged(int)
+ */
+ public abstract void onRotationChanged(int rotation);
+}
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/SensorRotationListener.java b/camera/camera-view/src/main/java/androidx/camera/view/SensorRotationListener.java
deleted file mode 100644
index d0919d4..0000000
--- a/camera/camera-view/src/main/java/androidx/camera/view/SensorRotationListener.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.camera.view;
-
-import android.content.Context;
-import android.view.OrientationEventListener;
-import android.view.Surface;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-
-/**
- * Listens to motion sensor reading and converts the orientation degrees to {@link Surface}
- * rotation.
- *
- * @hide
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public abstract class SensorRotationListener extends OrientationEventListener {
-
- public static final int INVALID_SURFACE_ROTATION = -1;
-
- private int mRotation = INVALID_SURFACE_ROTATION;
-
- public SensorRotationListener(@NonNull Context context) {
- super(context);
- }
-
- @Override
- public void onOrientationChanged(int orientation) {
- if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
- // Short-circuit if orientation is unknown. Unknown rotation can't be handled so it
- // shouldn't be sent.
- return;
- }
-
- int newRotation;
- if (orientation >= 315 || orientation < 45) {
- newRotation = Surface.ROTATION_0;
- } else if (orientation >= 225) {
- newRotation = Surface.ROTATION_90;
- } else if (orientation >= 135) {
- newRotation = Surface.ROTATION_180;
- } else {
- newRotation = Surface.ROTATION_270;
- }
- if (mRotation != newRotation) {
- mRotation = newRotation;
- onRotationChanged(newRotation);
- }
- }
-
- /**
- * Invoked when rotation changes.
- *
- * <p> The output rotation is defined as the UI Surface rotation, or what the Surface rotation
- * should be if the app's orientation is not locked.
- */
- public abstract void onRotationChanged(int rotation);
-}
diff --git a/camera/camera-view/src/test/java/androidx/camera/view/CameraControllerTest.kt b/camera/camera-view/src/test/java/androidx/camera/view/CameraControllerTest.kt
index 916d316..fe3a1c0 100644
--- a/camera/camera-view/src/test/java/androidx/camera/view/CameraControllerTest.kt
+++ b/camera/camera-view/src/test/java/androidx/camera/view/CameraControllerTest.kt
@@ -64,7 +64,7 @@
val controller = LifecycleCameraController(context)
// Act.
- controller.mSensorRotationListener.onRotationChanged(Surface.ROTATION_180)
+ controller.mRotationReceiver.onRotationChanged(Surface.ROTATION_180)
// Assert.
assertThat(controller.mImageAnalysis.targetRotation).isEqualTo(Surface.ROTATION_180)
diff --git a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java
index 46cb4308..9fab3a8f 100644
--- a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java
+++ b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java
@@ -51,7 +51,7 @@
import androidx.camera.view.CameraController;
import androidx.camera.view.LifecycleCameraController;
import androidx.camera.view.PreviewView;
-import androidx.camera.view.SensorRotationListener;
+import androidx.camera.view.RotationReceiver;
import androidx.camera.view.video.ExperimentalVideo;
import androidx.camera.view.video.OnVideoSavedCallback;
import androidx.camera.view.video.OutputFileOptions;
@@ -89,7 +89,7 @@
private ToggleButton mTapToFocusToggle;
private TextView mZoomStateText;
private TextView mTorchStateText;
- private RotationListener mSensorRotationListener;
+ private SensorRotationReceiver mSensorRotationReceiver;
private TextView mLuminance;
private boolean mIsAnalyzerSet = true;
@@ -123,8 +123,8 @@
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
mExecutorService = Executors.newSingleThreadExecutor();
- mSensorRotationListener = new RotationListener(requireContext());
- mSensorRotationListener.enable();
+ mSensorRotationReceiver = new SensorRotationReceiver(requireContext());
+ mSensorRotationReceiver.enable();
mCameraController = new LifecycleCameraController(requireContext());
checkFailedFuture(mCameraController.getInitializationFuture());
runSafely(() -> mCameraController.bindToLifecycle(getViewLifecycleOwner()));
@@ -321,8 +321,8 @@
if (mExecutorService != null) {
mExecutorService.shutdown();
}
- if (mSensorRotationListener != null) {
- mSensorRotationListener.disable();
+ if (mSensorRotationReceiver != null) {
+ mSensorRotationReceiver.disable();
}
}
@@ -451,11 +451,11 @@
/**
* Listens to accelerometer rotation change and pass it to tests.
*/
- static class RotationListener extends SensorRotationListener {
+ static class SensorRotationReceiver extends RotationReceiver {
private int mRotation;
- RotationListener(@NonNull Context context) {
+ SensorRotationReceiver(@NonNull Context context) {
super(context);
}
@@ -498,7 +498,7 @@
*/
@RestrictTo(RestrictTo.Scope.TESTS)
int getSensorRotation() {
- return mSensorRotationListener.getRotation();
+ return mSensorRotationReceiver.getRotation();
}
@VisibleForTesting
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollTest.kt
index ed52e33..cd74198 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollTest.kt
@@ -15,6 +15,7 @@
*/
package androidx.compose.foundation
+import android.os.Build
import android.os.Handler
import android.os.Looper
import androidx.annotation.RequiresApi
@@ -24,16 +25,23 @@
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
+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.text.BasicText
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.mutableStateOf
import androidx.compose.testutils.assertPixels
+import androidx.compose.testutils.assertShape
import androidx.compose.testutils.runBlockingWithManualClock
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.drawBehind
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.platform.InspectableValue
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.platform.isDebugInspectorInfoEnabled
@@ -822,4 +830,73 @@
)
}
}
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ @Test
+ fun horizontalScroller_doesNotClipVerticalOverdraw() {
+ rule.setContent {
+ Box(Modifier.size(60.dp).testTag("container").background(Color.Gray)) {
+ Row(
+ Modifier
+ .padding(20.dp)
+ .fillMaxSize()
+ .horizontalScroll(rememberScrollState(20))
+ ) {
+ repeat(4) {
+ Box(Modifier.size(20.dp).drawOutsideOfBounds())
+ }
+ }
+ }
+ }
+
+ rule.onNodeWithTag("container")
+ .captureToImage()
+ .assertShape(
+ density = rule.density,
+ shape = RectangleShape,
+ shapeColor = Color.Red,
+ backgroundColor = Color.Gray,
+ horizontalPadding = 20.dp,
+ verticalPadding = 0.dp
+ )
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ @Test
+ fun verticalScroller_doesNotClipHorizontalOverdraw() {
+ rule.setContent {
+ Box(Modifier.size(60.dp).testTag("container").background(Color.Gray)) {
+ Column(
+ Modifier
+ .padding(20.dp)
+ .fillMaxSize()
+ .verticalScroll(rememberScrollState(20))
+ ) {
+ repeat(4) {
+ Box(Modifier.size(20.dp).drawOutsideOfBounds())
+ }
+ }
+ }
+ }
+
+ rule.onNodeWithTag("container")
+ .captureToImage()
+ .assertShape(
+ density = rule.density,
+ shape = RectangleShape,
+ shapeColor = Color.Red,
+ backgroundColor = Color.Gray,
+ horizontalPadding = 0.dp,
+ verticalPadding = 20.dp
+ )
+ }
+
+ private fun Modifier.drawOutsideOfBounds() = drawBehind {
+ val inflate = 20.dp.roundToPx().toFloat()
+ drawRect(
+ Color.Red,
+ Offset(-inflate, -inflate),
+ Size(size.width + inflate * 2, size.height + inflate * 2)
+ )
+ }
}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyColumnTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyColumnTest.kt
index c9037c3..5803e10 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyColumnTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyColumnTest.kt
@@ -29,6 +29,7 @@
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.layout.requiredSizeIn
@@ -44,12 +45,15 @@
import androidx.compose.testutils.WithTouchSlop
import androidx.compose.testutils.assertIsEqualTo
import androidx.compose.testutils.assertPixels
+import androidx.compose.testutils.assertShape
import androidx.compose.testutils.runBlockingWithManualClock
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.ExperimentalTestApi
@@ -1440,6 +1444,36 @@
.assertTopPositionInRootIsEqualTo(containerSize - itemSizeDp)
}
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ @Test
+ fun lazyColumnDoesNotClipHorizontalOverdraw() {
+ rule.setContent {
+ Box(Modifier.size(60.dp).testTag("container").background(Color.Gray)) {
+ LazyColumn(
+ Modifier
+ .padding(20.dp)
+ .fillMaxSize(),
+ rememberLazyListState(1)
+ ) {
+ items(4) {
+ Box(Modifier.size(20.dp).drawOutsideOfBounds())
+ }
+ }
+ }
+ }
+
+ rule.onNodeWithTag("container")
+ .captureToImage()
+ .assertShape(
+ density = rule.density,
+ shape = RectangleShape,
+ shapeColor = Color.Red,
+ backgroundColor = Color.Gray,
+ horizontalPadding = 0.dp,
+ verticalPadding = 20.dp
+ )
+ }
+
private fun SemanticsNodeInteraction.assertTopPositionIsAlmost(expected: Dp) {
getUnclippedBoundsInRoot().top.assertIsEqualTo(expected, tolerance = 1.dp)
}
@@ -1486,3 +1520,12 @@
)
}
}
+
+internal fun Modifier.drawOutsideOfBounds() = drawBehind {
+ val inflate = 20.dp.roundToPx().toFloat()
+ drawRect(
+ Color.Red,
+ Offset(-inflate, -inflate),
+ Size(size.width + inflate * 2, size.height + inflate * 2)
+ )
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyRowTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyRowTest.kt
index ecd3cba..e2b6fc5 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyRowTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyRowTest.kt
@@ -16,6 +16,7 @@
package androidx.compose.foundation.lazy
+import android.os.Build
import androidx.compose.animation.core.snap
import androidx.compose.foundation.AutoTestFrameClock
import androidx.compose.foundation.background
@@ -24,6 +25,8 @@
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.layout.requiredSizeIn
@@ -35,11 +38,13 @@
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.testutils.assertIsEqualTo
+import androidx.compose.testutils.assertShape
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.SemanticsNodeInteraction
@@ -49,6 +54,7 @@
import androidx.compose.ui.test.assertLeftPositionInRootIsEqualTo
import androidx.compose.ui.test.assertPositionInRootIsEqualTo
import androidx.compose.ui.test.assertWidthIsEqualTo
+import androidx.compose.ui.test.captureToImage
import androidx.compose.ui.test.center
import androidx.compose.ui.test.down
import androidx.compose.ui.test.getUnclippedBoundsInRoot
@@ -63,6 +69,7 @@
import androidx.compose.ui.unit.dp
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
import com.google.common.truth.Truth
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.Dispatchers
@@ -1132,6 +1139,36 @@
.assertLeftPositionInRootIsEqualTo(containerSize - itemSizeDp)
}
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ @Test
+ fun lazyRowDoesNotClipHorizontalOverdraw() {
+ rule.setContent {
+ Box(Modifier.size(60.dp).testTag("container").background(Color.Gray)) {
+ LazyRow(
+ Modifier
+ .padding(20.dp)
+ .fillMaxSize(),
+ rememberLazyListState(1)
+ ) {
+ items(4) {
+ Box(Modifier.size(20.dp).drawOutsideOfBounds())
+ }
+ }
+ }
+ }
+
+ rule.onNodeWithTag("container")
+ .captureToImage()
+ .assertShape(
+ density = rule.density,
+ shape = RectangleShape,
+ shapeColor = Color.Red,
+ backgroundColor = Color.Gray,
+ horizontalPadding = 20.dp,
+ verticalPadding = 0.dp
+ )
+ }
+
private fun LazyListState.scrollBy(offset: Dp) {
runBlocking(Dispatchers.Main + AutoTestFrameClock()) {
animateScrollBy(with(rule.density) { offset.roundToPx().toFloat() }, snap())
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt
index 4720d13..4b7f5ee 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt
@@ -40,7 +40,11 @@
import androidx.compose.runtime.structuralEqualityPolicy
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
-import androidx.compose.ui.draw.clipToBounds
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.geometry.Rect
+import androidx.compose.ui.geometry.Size
+import androidx.compose.ui.graphics.Outline
+import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.layout.LayoutModifier
import androidx.compose.ui.layout.Measurable
import androidx.compose.ui.layout.MeasureResult
@@ -53,7 +57,9 @@
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.verticalScrollAxisRange
import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch
import kotlin.math.roundToInt
@@ -294,7 +300,7 @@
state = state
)
val layout = ScrollingLayoutModifier(state, reverseScrolling, isVertical)
- semantics.then(scrolling).clipToBounds().then(layout)
+ semantics.then(scrolling).clipScrollableContainer(isVertical).then(layout)
},
inspectorInfo = debugInspectorInfo {
name = "scroll"
@@ -356,3 +362,60 @@
}
}
}
+
+/**
+ * In the scrollable containers we want to clip the main axis sides in order to not display the
+ * content which is scrolled out. But once we apply clipToBounds() modifier on such containers it
+ * causes unexpected behavior as we also clip the content on the cross axis sides. It is
+ * unexpected as Compose components are not clipping by default. The most common case how it
+ * could be reproduced is a horizontally scrolling list of Cards. Cards have the elevation by
+ * default and such Cards will be drawn with clipped shadows on top and bottom. This was harder
+ * to reproduce in the Views system as usually scrolling containers like RecyclerView didn't have
+ * an opaque background which means the ripple was drawn on the surface on the first parent with
+ * background. In Compose as we don't clip by default we draw shadows right in place.
+ * We faced similar issue in Compose already with Androids Popups and Dialogs where we decided to
+ * just predefine some constant with a maximum elevation size we are not going to clip. We are
+ * going to reuse this technique here. This will improve how it works in most common cases. If the
+ * user will need to have a larger unclipped area for some reason they can always add the needed
+ * padding inside the scrollable area.
+ */
+internal fun Modifier.clipScrollableContainer(isVertical: Boolean) =
+ then(if (isVertical) VerticalScrollableClipModifier else HorizontalScrollableClipModifier)
+
+private val MaxSupportedElevation = 30.dp
+
+private val HorizontalScrollableClipModifier = Modifier.clip(object : Shape {
+ override fun createOutline(
+ size: Size,
+ layoutDirection: LayoutDirection,
+ density: Density
+ ): Outline {
+ val inflateSize = with(density) { MaxSupportedElevation.roundToPx().toFloat() }
+ return Outline.Rectangle(
+ Rect(
+ left = 0f,
+ top = -inflateSize,
+ right = size.width,
+ bottom = size.height + inflateSize
+ )
+ )
+ }
+})
+
+private val VerticalScrollableClipModifier = Modifier.clip(object : Shape {
+ override fun createOutline(
+ size: Size,
+ layoutDirection: LayoutDirection,
+ density: Density
+ ): Outline {
+ val inflateSize = with(density) { MaxSupportedElevation.roundToPx().toFloat() }
+ return Outline.Rectangle(
+ Rect(
+ left = -inflateSize,
+ top = 0f,
+ right = size.width + inflateSize,
+ bottom = size.height
+ )
+ )
+ }
+})
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyList.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyList.kt
index 141341d..f8d7ba5 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyList.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyList.kt
@@ -17,6 +17,7 @@
package androidx.compose.foundation.lazy
import androidx.compose.foundation.assertNotNestingScrollableContainers
+import androidx.compose.foundation.clipScrollableContainer
import androidx.compose.foundation.gestures.FlingBehavior
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.scrollable
@@ -31,7 +32,6 @@
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.layout.SubcomposeLayout
import androidx.compose.ui.layout.SubcomposeLayoutState
import androidx.compose.ui.platform.LocalLayoutDirection
@@ -89,7 +89,7 @@
flingBehavior = flingBehavior,
state = state
)
- .clipToBounds()
+ .clipScrollableContainer(isVertical)
.padding(contentPadding)
.then(state.remeasurementModifier)
) { constraints ->
diff --git a/compose/material/material/api/1.0.0-beta08.txt b/compose/material/material/api/1.0.0-beta08.txt
index 7cedeb6..ff9ea09 100644
--- a/compose/material/material/api/1.0.0-beta08.txt
+++ b/compose/material/material/api/1.0.0-beta08.txt
@@ -250,9 +250,22 @@
method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.material.ElevationOverlay> getLocalElevationOverlay();
}
- public enum FabPosition {
- enum_constant public static final androidx.compose.material.FabPosition Center;
- enum_constant public static final androidx.compose.material.FabPosition End;
+ public final inline class FabPosition {
+ ctor public FabPosition();
+ method public static inline boolean equals-impl(int p, Object? p1);
+ method public static boolean equals-impl0(int p1, int p2);
+ method public int getValue();
+ method public static inline int hashCode-impl(int p);
+ method public static String toString-impl(int $this);
+ property public final int value;
+ field public static final androidx.compose.material.FabPosition.Companion Companion;
+ }
+
+ public static final class FabPosition.Companion {
+ method public int getCenter-5ygKITE();
+ method public int getEnd-5ygKITE();
+ property public final int Center;
+ property public final int End;
}
public final class FloatingActionButtonDefaults {
@@ -366,7 +379,7 @@
}
public final class ScaffoldKt {
- method @androidx.compose.runtime.Composable public static void Scaffold-axyFlp8(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material.ScaffoldState scaffoldState, optional kotlin.jvm.functions.Function0<kotlin.Unit> topBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> bottomBar, optional kotlin.jvm.functions.Function1<? super androidx.compose.material.SnackbarHostState,kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit> floatingActionButton, optional androidx.compose.material.FabPosition floatingActionButtonPosition, optional boolean isFloatingActionButtonDocked, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? drawerContent, optional boolean drawerGesturesEnabled, optional androidx.compose.ui.graphics.Shape drawerShape, optional float drawerElevation, optional long drawerBackgroundColor, optional long drawerContentColor, optional long drawerScrimColor, optional long backgroundColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void Scaffold-axyFlp8(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material.ScaffoldState scaffoldState, optional kotlin.jvm.functions.Function0<kotlin.Unit> topBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> bottomBar, optional kotlin.jvm.functions.Function1<? super androidx.compose.material.SnackbarHostState,kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit> floatingActionButton, optional int floatingActionButtonPosition, optional boolean isFloatingActionButtonDocked, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? drawerContent, optional boolean drawerGesturesEnabled, optional androidx.compose.ui.graphics.Shape drawerShape, optional float drawerElevation, optional long drawerBackgroundColor, optional long drawerContentColor, optional long drawerScrimColor, optional long backgroundColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static androidx.compose.material.ScaffoldState rememberScaffoldState(optional androidx.compose.material.DrawerState drawerState, optional androidx.compose.material.SnackbarHostState snackbarHostState);
}
diff --git a/compose/material/material/api/current.ignore b/compose/material/material/api/current.ignore
new file mode 100644
index 0000000..ae87caf
--- /dev/null
+++ b/compose/material/material/api/current.ignore
@@ -0,0 +1,13 @@
+// Baseline format: 1.0
+ChangedSuperclass: androidx.compose.material.FabPosition:
+ Class androidx.compose.material.FabPosition superclass changed from java.lang.Enum to java.lang.Object
+
+
+RemovedField: androidx.compose.material.FabPosition#Center:
+ Removed enum constant androidx.compose.material.FabPosition.Center
+RemovedField: androidx.compose.material.FabPosition#End:
+ Removed enum constant androidx.compose.material.FabPosition.End
+
+
+RemovedMethod: androidx.compose.material.ScaffoldKt#Scaffold-axyFlp8(androidx.compose.ui.Modifier, androidx.compose.material.ScaffoldState, kotlin.jvm.functions.Function0<kotlin.Unit>, kotlin.jvm.functions.Function0<kotlin.Unit>, kotlin.jvm.functions.Function1<? super androidx.compose.material.SnackbarHostState,kotlin.Unit>, kotlin.jvm.functions.Function0<kotlin.Unit>, androidx.compose.material.FabPosition, boolean, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>, boolean, androidx.compose.ui.graphics.Shape, float, long, long, long, long, long, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit>):
+ Removed method androidx.compose.material.ScaffoldKt.Scaffold-axyFlp8(androidx.compose.ui.Modifier,androidx.compose.material.ScaffoldState,kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.jvm.functions.Function1<? super androidx.compose.material.SnackbarHostState,kotlin.Unit>,kotlin.jvm.functions.Function0<kotlin.Unit>,androidx.compose.material.FabPosition,boolean,kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>,boolean,androidx.compose.ui.graphics.Shape,float,long,long,long,long,long,kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit>)
diff --git a/compose/material/material/api/current.txt b/compose/material/material/api/current.txt
index 7cedeb6..ff9ea09 100644
--- a/compose/material/material/api/current.txt
+++ b/compose/material/material/api/current.txt
@@ -250,9 +250,22 @@
method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.material.ElevationOverlay> getLocalElevationOverlay();
}
- public enum FabPosition {
- enum_constant public static final androidx.compose.material.FabPosition Center;
- enum_constant public static final androidx.compose.material.FabPosition End;
+ public final inline class FabPosition {
+ ctor public FabPosition();
+ method public static inline boolean equals-impl(int p, Object? p1);
+ method public static boolean equals-impl0(int p1, int p2);
+ method public int getValue();
+ method public static inline int hashCode-impl(int p);
+ method public static String toString-impl(int $this);
+ property public final int value;
+ field public static final androidx.compose.material.FabPosition.Companion Companion;
+ }
+
+ public static final class FabPosition.Companion {
+ method public int getCenter-5ygKITE();
+ method public int getEnd-5ygKITE();
+ property public final int Center;
+ property public final int End;
}
public final class FloatingActionButtonDefaults {
@@ -366,7 +379,7 @@
}
public final class ScaffoldKt {
- method @androidx.compose.runtime.Composable public static void Scaffold-axyFlp8(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material.ScaffoldState scaffoldState, optional kotlin.jvm.functions.Function0<kotlin.Unit> topBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> bottomBar, optional kotlin.jvm.functions.Function1<? super androidx.compose.material.SnackbarHostState,kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit> floatingActionButton, optional androidx.compose.material.FabPosition floatingActionButtonPosition, optional boolean isFloatingActionButtonDocked, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? drawerContent, optional boolean drawerGesturesEnabled, optional androidx.compose.ui.graphics.Shape drawerShape, optional float drawerElevation, optional long drawerBackgroundColor, optional long drawerContentColor, optional long drawerScrimColor, optional long backgroundColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void Scaffold-axyFlp8(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material.ScaffoldState scaffoldState, optional kotlin.jvm.functions.Function0<kotlin.Unit> topBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> bottomBar, optional kotlin.jvm.functions.Function1<? super androidx.compose.material.SnackbarHostState,kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit> floatingActionButton, optional int floatingActionButtonPosition, optional boolean isFloatingActionButtonDocked, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? drawerContent, optional boolean drawerGesturesEnabled, optional androidx.compose.ui.graphics.Shape drawerShape, optional float drawerElevation, optional long drawerBackgroundColor, optional long drawerContentColor, optional long drawerScrimColor, optional long backgroundColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static androidx.compose.material.ScaffoldState rememberScaffoldState(optional androidx.compose.material.DrawerState drawerState, optional androidx.compose.material.SnackbarHostState snackbarHostState);
}
diff --git a/compose/material/material/api/public_plus_experimental_1.0.0-beta08.txt b/compose/material/material/api/public_plus_experimental_1.0.0-beta08.txt
index 5dd28c8..57df28b 100644
--- a/compose/material/material/api/public_plus_experimental_1.0.0-beta08.txt
+++ b/compose/material/material/api/public_plus_experimental_1.0.0-beta08.txt
@@ -115,7 +115,7 @@
}
public final class BottomSheetScaffoldKt {
- method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static void BottomSheetScaffold-0Ttp7_s(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> sheetContent, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material.BottomSheetScaffoldState scaffoldState, optional kotlin.jvm.functions.Function0<kotlin.Unit>? topBar, optional kotlin.jvm.functions.Function1<? super androidx.compose.material.SnackbarHostState,kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit>? floatingActionButton, optional androidx.compose.material.FabPosition floatingActionButtonPosition, optional boolean sheetGesturesEnabled, optional androidx.compose.ui.graphics.Shape sheetShape, optional float sheetElevation, optional long sheetBackgroundColor, optional long sheetContentColor, optional float sheetPeekHeight, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? drawerContent, optional boolean drawerGesturesEnabled, optional androidx.compose.ui.graphics.Shape drawerShape, optional float drawerElevation, optional long drawerBackgroundColor, optional long drawerContentColor, optional long drawerScrimColor, optional long backgroundColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
+ method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static void BottomSheetScaffold-0Ttp7_s(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> sheetContent, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material.BottomSheetScaffoldState scaffoldState, optional kotlin.jvm.functions.Function0<kotlin.Unit>? topBar, optional kotlin.jvm.functions.Function1<? super androidx.compose.material.SnackbarHostState,kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit>? floatingActionButton, optional int floatingActionButtonPosition, optional boolean sheetGesturesEnabled, optional androidx.compose.ui.graphics.Shape sheetShape, optional float sheetElevation, optional long sheetBackgroundColor, optional long sheetContentColor, optional float sheetPeekHeight, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? drawerContent, optional boolean drawerGesturesEnabled, optional androidx.compose.ui.graphics.Shape drawerShape, optional float drawerElevation, optional long drawerBackgroundColor, optional long drawerContentColor, optional long drawerScrimColor, optional long backgroundColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static androidx.compose.material.BottomSheetScaffoldState rememberBottomSheetScaffoldState(optional androidx.compose.material.DrawerState drawerState, optional androidx.compose.material.BottomSheetState bottomSheetState, optional androidx.compose.material.SnackbarHostState snackbarHostState);
method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static androidx.compose.material.BottomSheetState rememberBottomSheetState(androidx.compose.material.BottomSheetValue initialValue, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional kotlin.jvm.functions.Function1<? super androidx.compose.material.BottomSheetValue,java.lang.Boolean> confirmStateChange);
}
@@ -357,9 +357,22 @@
@kotlin.RequiresOptIn(message="This material API is experimental and is likely to change or to be removed in" + " the future.") public @interface ExperimentalMaterialApi {
}
- public enum FabPosition {
- enum_constant public static final androidx.compose.material.FabPosition Center;
- enum_constant public static final androidx.compose.material.FabPosition End;
+ public final inline class FabPosition {
+ ctor public FabPosition();
+ method public static inline boolean equals-impl(int p, Object? p1);
+ method public static boolean equals-impl0(int p1, int p2);
+ method public int getValue();
+ method public static inline int hashCode-impl(int p);
+ method public static String toString-impl(int $this);
+ property public final int value;
+ field public static final androidx.compose.material.FabPosition.Companion Companion;
+ }
+
+ public static final class FabPosition.Companion {
+ method public int getCenter-5ygKITE();
+ method public int getEnd-5ygKITE();
+ property public final int Center;
+ property public final int End;
}
@androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public final class FixedThreshold implements androidx.compose.material.ThresholdConfig {
@@ -506,7 +519,7 @@
}
public final class ScaffoldKt {
- method @androidx.compose.runtime.Composable public static void Scaffold-axyFlp8(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material.ScaffoldState scaffoldState, optional kotlin.jvm.functions.Function0<kotlin.Unit> topBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> bottomBar, optional kotlin.jvm.functions.Function1<? super androidx.compose.material.SnackbarHostState,kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit> floatingActionButton, optional androidx.compose.material.FabPosition floatingActionButtonPosition, optional boolean isFloatingActionButtonDocked, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? drawerContent, optional boolean drawerGesturesEnabled, optional androidx.compose.ui.graphics.Shape drawerShape, optional float drawerElevation, optional long drawerBackgroundColor, optional long drawerContentColor, optional long drawerScrimColor, optional long backgroundColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void Scaffold-axyFlp8(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material.ScaffoldState scaffoldState, optional kotlin.jvm.functions.Function0<kotlin.Unit> topBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> bottomBar, optional kotlin.jvm.functions.Function1<? super androidx.compose.material.SnackbarHostState,kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit> floatingActionButton, optional int floatingActionButtonPosition, optional boolean isFloatingActionButtonDocked, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? drawerContent, optional boolean drawerGesturesEnabled, optional androidx.compose.ui.graphics.Shape drawerShape, optional float drawerElevation, optional long drawerBackgroundColor, optional long drawerContentColor, optional long drawerScrimColor, optional long backgroundColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static androidx.compose.material.ScaffoldState rememberScaffoldState(optional androidx.compose.material.DrawerState drawerState, optional androidx.compose.material.SnackbarHostState snackbarHostState);
}
diff --git a/compose/material/material/api/public_plus_experimental_current.txt b/compose/material/material/api/public_plus_experimental_current.txt
index 5dd28c8..57df28b 100644
--- a/compose/material/material/api/public_plus_experimental_current.txt
+++ b/compose/material/material/api/public_plus_experimental_current.txt
@@ -115,7 +115,7 @@
}
public final class BottomSheetScaffoldKt {
- method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static void BottomSheetScaffold-0Ttp7_s(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> sheetContent, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material.BottomSheetScaffoldState scaffoldState, optional kotlin.jvm.functions.Function0<kotlin.Unit>? topBar, optional kotlin.jvm.functions.Function1<? super androidx.compose.material.SnackbarHostState,kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit>? floatingActionButton, optional androidx.compose.material.FabPosition floatingActionButtonPosition, optional boolean sheetGesturesEnabled, optional androidx.compose.ui.graphics.Shape sheetShape, optional float sheetElevation, optional long sheetBackgroundColor, optional long sheetContentColor, optional float sheetPeekHeight, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? drawerContent, optional boolean drawerGesturesEnabled, optional androidx.compose.ui.graphics.Shape drawerShape, optional float drawerElevation, optional long drawerBackgroundColor, optional long drawerContentColor, optional long drawerScrimColor, optional long backgroundColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
+ method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static void BottomSheetScaffold-0Ttp7_s(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> sheetContent, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material.BottomSheetScaffoldState scaffoldState, optional kotlin.jvm.functions.Function0<kotlin.Unit>? topBar, optional kotlin.jvm.functions.Function1<? super androidx.compose.material.SnackbarHostState,kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit>? floatingActionButton, optional int floatingActionButtonPosition, optional boolean sheetGesturesEnabled, optional androidx.compose.ui.graphics.Shape sheetShape, optional float sheetElevation, optional long sheetBackgroundColor, optional long sheetContentColor, optional float sheetPeekHeight, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? drawerContent, optional boolean drawerGesturesEnabled, optional androidx.compose.ui.graphics.Shape drawerShape, optional float drawerElevation, optional long drawerBackgroundColor, optional long drawerContentColor, optional long drawerScrimColor, optional long backgroundColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static androidx.compose.material.BottomSheetScaffoldState rememberBottomSheetScaffoldState(optional androidx.compose.material.DrawerState drawerState, optional androidx.compose.material.BottomSheetState bottomSheetState, optional androidx.compose.material.SnackbarHostState snackbarHostState);
method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static androidx.compose.material.BottomSheetState rememberBottomSheetState(androidx.compose.material.BottomSheetValue initialValue, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional kotlin.jvm.functions.Function1<? super androidx.compose.material.BottomSheetValue,java.lang.Boolean> confirmStateChange);
}
@@ -357,9 +357,22 @@
@kotlin.RequiresOptIn(message="This material API is experimental and is likely to change or to be removed in" + " the future.") public @interface ExperimentalMaterialApi {
}
- public enum FabPosition {
- enum_constant public static final androidx.compose.material.FabPosition Center;
- enum_constant public static final androidx.compose.material.FabPosition End;
+ public final inline class FabPosition {
+ ctor public FabPosition();
+ method public static inline boolean equals-impl(int p, Object? p1);
+ method public static boolean equals-impl0(int p1, int p2);
+ method public int getValue();
+ method public static inline int hashCode-impl(int p);
+ method public static String toString-impl(int $this);
+ property public final int value;
+ field public static final androidx.compose.material.FabPosition.Companion Companion;
+ }
+
+ public static final class FabPosition.Companion {
+ method public int getCenter-5ygKITE();
+ method public int getEnd-5ygKITE();
+ property public final int Center;
+ property public final int End;
}
@androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public final class FixedThreshold implements androidx.compose.material.ThresholdConfig {
@@ -506,7 +519,7 @@
}
public final class ScaffoldKt {
- method @androidx.compose.runtime.Composable public static void Scaffold-axyFlp8(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material.ScaffoldState scaffoldState, optional kotlin.jvm.functions.Function0<kotlin.Unit> topBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> bottomBar, optional kotlin.jvm.functions.Function1<? super androidx.compose.material.SnackbarHostState,kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit> floatingActionButton, optional androidx.compose.material.FabPosition floatingActionButtonPosition, optional boolean isFloatingActionButtonDocked, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? drawerContent, optional boolean drawerGesturesEnabled, optional androidx.compose.ui.graphics.Shape drawerShape, optional float drawerElevation, optional long drawerBackgroundColor, optional long drawerContentColor, optional long drawerScrimColor, optional long backgroundColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void Scaffold-axyFlp8(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material.ScaffoldState scaffoldState, optional kotlin.jvm.functions.Function0<kotlin.Unit> topBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> bottomBar, optional kotlin.jvm.functions.Function1<? super androidx.compose.material.SnackbarHostState,kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit> floatingActionButton, optional int floatingActionButtonPosition, optional boolean isFloatingActionButtonDocked, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? drawerContent, optional boolean drawerGesturesEnabled, optional androidx.compose.ui.graphics.Shape drawerShape, optional float drawerElevation, optional long drawerBackgroundColor, optional long drawerContentColor, optional long drawerScrimColor, optional long backgroundColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static androidx.compose.material.ScaffoldState rememberScaffoldState(optional androidx.compose.material.DrawerState drawerState, optional androidx.compose.material.SnackbarHostState snackbarHostState);
}
diff --git a/compose/material/material/api/restricted_1.0.0-beta08.txt b/compose/material/material/api/restricted_1.0.0-beta08.txt
index 7cedeb6..ff9ea09 100644
--- a/compose/material/material/api/restricted_1.0.0-beta08.txt
+++ b/compose/material/material/api/restricted_1.0.0-beta08.txt
@@ -250,9 +250,22 @@
method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.material.ElevationOverlay> getLocalElevationOverlay();
}
- public enum FabPosition {
- enum_constant public static final androidx.compose.material.FabPosition Center;
- enum_constant public static final androidx.compose.material.FabPosition End;
+ public final inline class FabPosition {
+ ctor public FabPosition();
+ method public static inline boolean equals-impl(int p, Object? p1);
+ method public static boolean equals-impl0(int p1, int p2);
+ method public int getValue();
+ method public static inline int hashCode-impl(int p);
+ method public static String toString-impl(int $this);
+ property public final int value;
+ field public static final androidx.compose.material.FabPosition.Companion Companion;
+ }
+
+ public static final class FabPosition.Companion {
+ method public int getCenter-5ygKITE();
+ method public int getEnd-5ygKITE();
+ property public final int Center;
+ property public final int End;
}
public final class FloatingActionButtonDefaults {
@@ -366,7 +379,7 @@
}
public final class ScaffoldKt {
- method @androidx.compose.runtime.Composable public static void Scaffold-axyFlp8(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material.ScaffoldState scaffoldState, optional kotlin.jvm.functions.Function0<kotlin.Unit> topBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> bottomBar, optional kotlin.jvm.functions.Function1<? super androidx.compose.material.SnackbarHostState,kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit> floatingActionButton, optional androidx.compose.material.FabPosition floatingActionButtonPosition, optional boolean isFloatingActionButtonDocked, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? drawerContent, optional boolean drawerGesturesEnabled, optional androidx.compose.ui.graphics.Shape drawerShape, optional float drawerElevation, optional long drawerBackgroundColor, optional long drawerContentColor, optional long drawerScrimColor, optional long backgroundColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void Scaffold-axyFlp8(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material.ScaffoldState scaffoldState, optional kotlin.jvm.functions.Function0<kotlin.Unit> topBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> bottomBar, optional kotlin.jvm.functions.Function1<? super androidx.compose.material.SnackbarHostState,kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit> floatingActionButton, optional int floatingActionButtonPosition, optional boolean isFloatingActionButtonDocked, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? drawerContent, optional boolean drawerGesturesEnabled, optional androidx.compose.ui.graphics.Shape drawerShape, optional float drawerElevation, optional long drawerBackgroundColor, optional long drawerContentColor, optional long drawerScrimColor, optional long backgroundColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static androidx.compose.material.ScaffoldState rememberScaffoldState(optional androidx.compose.material.DrawerState drawerState, optional androidx.compose.material.SnackbarHostState snackbarHostState);
}
diff --git a/compose/material/material/api/restricted_current.ignore b/compose/material/material/api/restricted_current.ignore
new file mode 100644
index 0000000..ae87caf
--- /dev/null
+++ b/compose/material/material/api/restricted_current.ignore
@@ -0,0 +1,13 @@
+// Baseline format: 1.0
+ChangedSuperclass: androidx.compose.material.FabPosition:
+ Class androidx.compose.material.FabPosition superclass changed from java.lang.Enum to java.lang.Object
+
+
+RemovedField: androidx.compose.material.FabPosition#Center:
+ Removed enum constant androidx.compose.material.FabPosition.Center
+RemovedField: androidx.compose.material.FabPosition#End:
+ Removed enum constant androidx.compose.material.FabPosition.End
+
+
+RemovedMethod: androidx.compose.material.ScaffoldKt#Scaffold-axyFlp8(androidx.compose.ui.Modifier, androidx.compose.material.ScaffoldState, kotlin.jvm.functions.Function0<kotlin.Unit>, kotlin.jvm.functions.Function0<kotlin.Unit>, kotlin.jvm.functions.Function1<? super androidx.compose.material.SnackbarHostState,kotlin.Unit>, kotlin.jvm.functions.Function0<kotlin.Unit>, androidx.compose.material.FabPosition, boolean, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>, boolean, androidx.compose.ui.graphics.Shape, float, long, long, long, long, long, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit>):
+ Removed method androidx.compose.material.ScaffoldKt.Scaffold-axyFlp8(androidx.compose.ui.Modifier,androidx.compose.material.ScaffoldState,kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.jvm.functions.Function1<? super androidx.compose.material.SnackbarHostState,kotlin.Unit>,kotlin.jvm.functions.Function0<kotlin.Unit>,androidx.compose.material.FabPosition,boolean,kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>,boolean,androidx.compose.ui.graphics.Shape,float,long,long,long,long,long,kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit>)
diff --git a/compose/material/material/api/restricted_current.txt b/compose/material/material/api/restricted_current.txt
index 7cedeb6..ff9ea09 100644
--- a/compose/material/material/api/restricted_current.txt
+++ b/compose/material/material/api/restricted_current.txt
@@ -250,9 +250,22 @@
method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.material.ElevationOverlay> getLocalElevationOverlay();
}
- public enum FabPosition {
- enum_constant public static final androidx.compose.material.FabPosition Center;
- enum_constant public static final androidx.compose.material.FabPosition End;
+ public final inline class FabPosition {
+ ctor public FabPosition();
+ method public static inline boolean equals-impl(int p, Object? p1);
+ method public static boolean equals-impl0(int p1, int p2);
+ method public int getValue();
+ method public static inline int hashCode-impl(int p);
+ method public static String toString-impl(int $this);
+ property public final int value;
+ field public static final androidx.compose.material.FabPosition.Companion Companion;
+ }
+
+ public static final class FabPosition.Companion {
+ method public int getCenter-5ygKITE();
+ method public int getEnd-5ygKITE();
+ property public final int Center;
+ property public final int End;
}
public final class FloatingActionButtonDefaults {
@@ -366,7 +379,7 @@
}
public final class ScaffoldKt {
- method @androidx.compose.runtime.Composable public static void Scaffold-axyFlp8(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material.ScaffoldState scaffoldState, optional kotlin.jvm.functions.Function0<kotlin.Unit> topBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> bottomBar, optional kotlin.jvm.functions.Function1<? super androidx.compose.material.SnackbarHostState,kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit> floatingActionButton, optional androidx.compose.material.FabPosition floatingActionButtonPosition, optional boolean isFloatingActionButtonDocked, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? drawerContent, optional boolean drawerGesturesEnabled, optional androidx.compose.ui.graphics.Shape drawerShape, optional float drawerElevation, optional long drawerBackgroundColor, optional long drawerContentColor, optional long drawerScrimColor, optional long backgroundColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void Scaffold-axyFlp8(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material.ScaffoldState scaffoldState, optional kotlin.jvm.functions.Function0<kotlin.Unit> topBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> bottomBar, optional kotlin.jvm.functions.Function1<? super androidx.compose.material.SnackbarHostState,kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit> floatingActionButton, optional int floatingActionButtonPosition, optional boolean isFloatingActionButtonDocked, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? drawerContent, optional boolean drawerGesturesEnabled, optional androidx.compose.ui.graphics.Shape drawerShape, optional float drawerElevation, optional long drawerBackgroundColor, optional long drawerContentColor, optional long drawerScrimColor, optional long backgroundColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static androidx.compose.material.ScaffoldState rememberScaffoldState(optional androidx.compose.material.DrawerState drawerState, optional androidx.compose.material.SnackbarHostState snackbarHostState);
}
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SliderTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SliderTest.kt
index dbda4a7..c8d1bd0 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SliderTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SliderTest.kt
@@ -20,6 +20,7 @@
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.PressInteraction
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.requiredSize
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -369,6 +370,23 @@
}
@Test
+ fun slider_min_size() {
+ rule.setMaterialContent {
+ Box(Modifier.requiredSize(0.dp)) {
+ Slider(
+ modifier = Modifier.testTag(tag),
+ value = 0f,
+ onValueChange = { }
+ )
+ }
+ }
+
+ rule.onNodeWithTag(tag)
+ .assertWidthIsEqualTo(ThumbRadius * 2)
+ .assertHeightIsEqualTo(ThumbRadius * 2)
+ }
+
+ @Test
fun slider_noUnwantedCallbackCalls() {
val state = mutableStateOf(0f)
val callCount = mutableStateOf(0f)
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/BottomSheetScaffold.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/BottomSheetScaffold.kt
index acce578..ad8e5d9 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/BottomSheetScaffold.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/BottomSheetScaffold.kt
@@ -406,7 +406,7 @@
val fabOffsetX = when (floatingActionButtonPosition) {
FabPosition.Center -> (placeable.width - fabPlaceable.width) / 2
- FabPosition.End -> placeable.width - fabPlaceable.width - FabEndSpacing.roundToPx()
+ else -> placeable.width - fabPlaceable.width - FabEndSpacing.roundToPx()
}
val fabOffsetY = sheetOffsetY - fabPlaceable.height / 2
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Scaffold.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Scaffold.kt
index c261b7d..0c38d82 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Scaffold.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Scaffold.kt
@@ -69,19 +69,28 @@
/**
* The possible positions for a [FloatingActionButton] attached to a [Scaffold].
*/
-enum class FabPosition {
- /**
- * Position FAB at the bottom of the screen in the center, above the [BottomAppBar] (if it
- * exists)
- */
+@Suppress("INLINE_CLASS_DEPRECATED", "EXPERIMENTAL_FEATURE_WARNING")
+inline class FabPosition internal constructor(val value: Int) {
+ companion object {
+ /**
+ * Position FAB at the bottom of the screen in the center, above the [BottomAppBar] (if it
+ * exists)
+ */
+ val Center = FabPosition(0)
- Center,
+ /**
+ * Position FAB at the bottom of the screen at the end, above the [BottomAppBar] (if it
+ * exists)
+ */
+ val End = FabPosition(1)
+ }
- /**
- * Position FAB at the bottom of the screen at the end, above the [BottomAppBar] (if it
- * exists)
- */
- End
+ override fun toString(): String {
+ return when (this) {
+ Center -> "FabPosition.Center"
+ else -> "FabPosition.End"
+ }
+ }
}
/**
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt
index f2a1a77..090084f 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt
@@ -39,6 +39,7 @@
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.requiredSizeIn
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.progressSemantics
@@ -140,7 +141,9 @@
if (steps == 0) emptyList() else List(steps + 2) { it.toFloat() / (steps + 1) }
}
BoxWithConstraints(
- modifier.sliderSemantics(value, tickFractions, enabled, onValueChange, valueRange, steps)
+ modifier
+ .requiredSizeIn(minWidth = ThumbRadius * 2, minHeight = ThumbRadius * 2)
+ .sliderSemantics(value, tickFractions, enabled, onValueChange, valueRange, steps)
) {
val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl
val maxPx = constraints.maxWidth.toFloat()
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 e8ff224..76af048 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
@@ -3081,9 +3081,10 @@
value: Int,
noinline block: T.(value: Int) -> Unit
) = with(composer) {
+ val inserting = inserting
if (inserting || rememberedValue() != value) {
updateRememberedValue(value)
- composer.apply(value, block)
+ if (!inserting) apply(value, block)
}
}
@@ -3102,9 +3103,10 @@
value: V,
block: T.(value: V) -> Unit
) = with(composer) {
+ val inserting = inserting
if (inserting || rememberedValue() != value) {
updateRememberedValue(value)
- composer.apply(value, block)
+ if (!inserting) apply(value, block)
}
}
diff --git a/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/CompositionTests.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/CompositionTests.kt
index 7e07357..bc34c6e 100644
--- a/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/CompositionTests.kt
+++ b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/CompositionTests.kt
@@ -2944,6 +2944,65 @@
stateA++
advance()
}
+
+ /**
+ * set should set the value every time, update should only set after initial composition.
+ */
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ fun composeNodeSetVsUpdate() = runBlockingTest {
+ localRecomposerTest { recomposer ->
+ class SetUpdateNode(property: String) {
+ var changeCount = 0
+ var property: String = property
+ set(value) {
+ field = value
+ changeCount++
+ }
+ }
+ class SetUpdateNodeApplier : AbstractApplier<SetUpdateNode>(SetUpdateNode("root")) {
+ override fun insertTopDown(index: Int, instance: SetUpdateNode) {}
+ override fun insertBottomUp(index: Int, instance: SetUpdateNode) {}
+ override fun remove(index: Int, count: Int) {}
+ override fun move(from: Int, to: Int, count: Int) {}
+ override fun onClear() {}
+ }
+ val composition = Composition(SetUpdateNodeApplier(), recomposer)
+ val nodes = mutableListOf<SetUpdateNode>()
+ fun makeNode(property: String) = SetUpdateNode(property).also { nodes += it }
+
+ var value by mutableStateOf("initial")
+
+ composition.setContent {
+ ComposeNode<SetUpdateNode, SetUpdateNodeApplier>(
+ factory = { makeNode(value) },
+ update = {
+ set(value) { property = value }
+ }
+ )
+ ComposeNode<SetUpdateNode, SetUpdateNodeApplier>(
+ factory = { makeNode(value) },
+ update = {
+ update(value) { property = value }
+ }
+ )
+ }
+
+ assertEquals("initial", nodes[0].property, "node 0 initial composition value")
+ assertEquals("initial", nodes[1].property, "node 1 initial composition value")
+ assertEquals(1, nodes[0].changeCount, "node 0 initial composition changeCount")
+ assertEquals(0, nodes[1].changeCount, "node 1 initial composition changeCount")
+
+ value = "changed"
+ Snapshot.sendApplyNotifications()
+ advanceUntilIdle()
+
+ assertEquals("changed", nodes[0].property, "node 0 recomposition value")
+ assertEquals("changed", nodes[1].property, "node 1 recomposition value")
+ assertEquals(2, nodes[0].changeCount, "node 0 recomposition changeCount")
+ assertEquals(1, nodes[1].changeCount, "node 1 recomposition changeCount")
+ }
+ }
}
var stateA by mutableStateOf(1000)
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/vector/VectorTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/vector/VectorTest.kt
index 60dfe8c..383b749 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/vector/VectorTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/vector/VectorTest.kt
@@ -305,6 +305,44 @@
rule.onNodeWithTag(testTag).captureToImage().assertPixels { Color.Blue }
}
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ @Test
+ fun testVectorChangeSize() {
+ val size = mutableStateOf(200)
+ val color = mutableStateOf(Color.Magenta)
+
+ rule.setContent {
+ val background = Modifier.background(Color.Red).paint(
+ createTestVectorPainter(size.value, color.value),
+ alignment = Alignment.TopStart
+ )
+ AtLeastSize(size = 400, modifier = background) {
+ }
+ }
+
+ takeScreenShot(400).apply {
+ assertEquals(getPixel(100, 100), Color.Magenta.toArgb())
+ assertEquals(getPixel(300, 300), Color.Red.toArgb())
+ }
+
+ size.value = 400
+ color.value = Color.Cyan
+
+ takeScreenShot(400).apply {
+ assertEquals(getPixel(100, 100), Color.Cyan.toArgb())
+ assertEquals(getPixel(300, 300), Color.Cyan.toArgb())
+ }
+
+ size.value = 50
+ color.value = Color.Yellow
+
+ takeScreenShot(400).apply {
+ assertEquals(getPixel(10, 10), Color.Yellow.toArgb())
+ assertEquals(getPixel(100, 100), Color.Red.toArgb())
+ assertEquals(getPixel(300, 300), Color.Red.toArgb())
+ }
+ }
+
@Composable
private fun VectorTint(
size: Int = 200,
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/platform/AndroidViewCompatTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/platform/AndroidViewCompatTest.kt
index 3aa73c6..b55814c 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/platform/AndroidViewCompatTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/platform/AndroidViewCompatTest.kt
@@ -639,6 +639,50 @@
.assertPixels(expectedColorProvider = offsetColorProvider)
}
+ @Test
+ fun testInvalidationsDuringDraw_withLayerInBetween() {
+ var view: InvalidateDuringComputeScroll? = null
+ rule.setContent {
+ val context = LocalContext.current
+ view = remember { InvalidateDuringComputeScroll(context) }
+ // Note having a graphics layer here will cause the updateDisplayList to not happen
+ // in the initial redraw traversal.
+ AndroidView(factory = { view!! }, modifier = Modifier.graphicsLayer().graphicsLayer())
+ }
+
+ val invalidatesDuringScroll = 4
+ rule.runOnIdle {
+ view!!.apply {
+ draws = 0
+ this.invalidatesDuringScroll = invalidatesDuringScroll
+ invalidate()
+ }
+ }
+
+ rule.runOnIdle { assertEquals(invalidatesDuringScroll + 1, view!!.draws) }
+ }
+
+ @Test
+ fun testInvalidationsDuringDraw_sameLayerAsAndroidComposeView() {
+ var view: InvalidateDuringComputeScroll? = null
+ rule.setContent {
+ val context = LocalContext.current
+ view = remember { InvalidateDuringComputeScroll(context) }
+ AndroidView(factory = { view!! })
+ }
+
+ val invalidatesDuringScroll = 4
+ rule.runOnIdle {
+ view!!.apply {
+ draws = 0
+ this.invalidatesDuringScroll = invalidatesDuringScroll
+ invalidate()
+ }
+ }
+
+ rule.runOnIdle { assertEquals(invalidatesDuringScroll + 1, view!!.draws) }
+ }
+
class ColoredSquareView(context: Context) : View(context) {
var size: Int = 100
set(value) {
@@ -696,6 +740,23 @@
}
}
+ class InvalidateDuringComputeScroll(context: Context) : View(context) {
+ var draws = 0
+ var invalidatesDuringScroll = 0
+
+ override fun computeScroll() {
+ if (invalidatesDuringScroll > 0) {
+ --invalidatesDuringScroll
+ invalidate()
+ }
+ }
+
+ override fun onDraw(canvas: Canvas?) {
+ super.onDraw(canvas)
+ ++draws
+ }
+ }
+
fun Modifier.layoutConstraints(childConstraints: Constraints): Modifier =
this.then(object : LayoutModifier {
override fun MeasureScope.measure(
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
index cdff2ff..d22435d 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
@@ -191,7 +191,12 @@
override val autofillTree = AutofillTree()
// OwnedLayers that are dirty and should be redrawn.
- internal val dirtyLayers = mutableListOf<OwnedLayer>()
+ private val dirtyLayers = mutableListOf<OwnedLayer>()
+ // OwnerLayers that invalidated themselves during their last draw. They will be redrawn
+ // during the next AndroidComposeView dispatchDraw pass.
+ private var postponedDirtyLayers: MutableList<OwnedLayer>? = null
+
+ private var isDrawingContent = false
private val motionEventAdapter = MotionEventAdapter()
private val pointerInputEventProcessor = PointerInputEventProcessor(root)
@@ -639,6 +644,7 @@
}
measureAndLayout()
+ isDrawingContent = true
// we don't have to observe here because the root has a layer modifier
// that will observe all children. The AndroidComposeView has only the
// root, so it doesn't have to invalidate itself based on model changes.
@@ -649,7 +655,6 @@
val layer = dirtyLayers[i]
layer.updateDisplayList()
}
- dirtyLayers.clear()
}
if (ViewLayer.shouldUseDispatchDraw) {
@@ -662,6 +667,33 @@
super.dispatchDraw(canvas)
canvas.restoreToCount(saveCount)
}
+
+ dirtyLayers.clear()
+ isDrawingContent = false
+
+ // updateDisplayList operations performed above (during root.draw and during the explicit
+ // layer.updateDisplayList() calls) can result in the same layers being invalidated. These
+ // layers have been added to postponedDirtyLayers and will be redrawn during the next
+ // dispatchDraw.
+ if (postponedDirtyLayers != null) {
+ val postponed = postponedDirtyLayers!!
+ dirtyLayers.addAll(postponed)
+ postponed.clear()
+ }
+ }
+
+ internal fun notifyLayerIsDirty(layer: OwnedLayer, isDirty: Boolean) {
+ if (!isDirty) {
+ // It is correct to remove the layer here regardless of this if, but for performance
+ // we are hackily not doing the removal here in order to just do clear() a bit later.
+ if (!isDrawingContent) require(dirtyLayers.remove(layer))
+ } else if (!isDrawingContent) {
+ dirtyLayers += layer
+ } else {
+ val postponed = postponedDirtyLayers
+ ?: mutableListOf<OwnedLayer>().also { postponedDirtyLayers = it }
+ postponed += layer
+ }
}
/**
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/RenderNodeLayer.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/RenderNodeLayer.android.kt
index 061407a..94f6758 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/RenderNodeLayer.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/RenderNodeLayer.android.kt
@@ -50,6 +50,12 @@
* True when the RenderNodeLayer has been invalidated and not yet drawn.
*/
private var isDirty = false
+ set(value) {
+ if (value != field) {
+ field = value
+ ownerView.notifyLayerIsDirty(this, value)
+ }
+ }
private val outlineResolver = OutlineResolver(ownerView.density)
private var isDestroyed = false
private var drawnWithZ = false
@@ -180,7 +186,6 @@
override fun invalidate() {
if (!isDirty && !isDestroyed) {
ownerView.invalidate()
- ownerView.dirtyLayers += this
isDirty = true
}
}
@@ -213,23 +218,21 @@
}
} else {
drawBlock(canvas)
+ isDirty = false
}
- isDirty = false
}
override fun updateDisplayList() {
if (isDirty || !renderNode.hasDisplayList) {
- val clipPath = if (renderNode.clipToOutline) outlineResolver.clipPath else null
-
- renderNode.record(canvasHolder, clipPath, drawBlock)
-
isDirty = false
+ val clipPath = if (renderNode.clipToOutline) outlineResolver.clipPath else null
+ renderNode.record(canvasHolder, clipPath, drawBlock)
}
}
override fun destroy() {
isDestroyed = true
- ownerView.dirtyLayers -= this
+ isDirty = false
ownerView.requestClearInvalidObservations()
}
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ViewLayer.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ViewLayer.android.kt
index 2ce77b3..2c33801 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ViewLayer.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ViewLayer.android.kt
@@ -56,7 +56,12 @@
private val manualClipPath: Path? get() =
if (!clipToOutline) null else outlineResolver.clipPath
var isInvalidated = false
- private set
+ private set(value) {
+ if (value != field) {
+ field = value
+ ownerView.notifyLayerIsDirty(this, value)
+ }
+ }
private var drawnWithZ = false
private val canvasHolder = CanvasHolder()
@@ -225,6 +230,7 @@
}
override fun dispatchDraw(canvas: android.graphics.Canvas) {
+ isInvalidated = false
canvasHolder.drawInto(canvas) {
val clipPath = manualClipPath
if (clipPath != null) {
@@ -235,7 +241,6 @@
if (clipPath != null) {
restore()
}
- isInvalidated = false
}
}
@@ -243,7 +248,6 @@
if (!isInvalidated) {
isInvalidated = true
super.invalidate()
- ownerView.dirtyLayers += this
ownerView.invalidate()
}
}
@@ -255,14 +259,14 @@
container.postOnAnimation {
container.removeView(this)
}
- ownerView.dirtyLayers -= this
+ isInvalidated = false
ownerView.requestClearInvalidObservations()
}
override fun updateDisplayList() {
if (isInvalidated && !shouldUseDispatchDraw) {
- updateDisplayList(this)
isInvalidated = false
+ updateDisplayList(this)
}
}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/vector/DrawCache.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/vector/DrawCache.kt
index 99a0886..c11e511 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/vector/DrawCache.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/vector/DrawCache.kt
@@ -16,7 +16,6 @@
package androidx.compose.ui.graphics.vector
-import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Canvas
import androidx.compose.ui.graphics.Color
@@ -43,6 +42,7 @@
private var cachedCanvas: Canvas? = null
private var scopeDensity: Density? = null
private var layoutDirection: LayoutDirection = LayoutDirection.Ltr
+ private var size: IntSize = IntSize.Zero
private val cacheScope = CanvasDrawScope()
@@ -72,6 +72,7 @@
mCachedImage = targetImage
cachedCanvas = targetCanvas
}
+ this.size = size
cacheScope.draw(density, layoutDirection, targetCanvas, size.toSize()) {
clear()
block()
@@ -92,7 +93,7 @@
"drawCachedImage must be invoked first before attempting to draw the result " +
"into another destination"
}
- target.drawImage(targetImage, Offset.Zero, alpha = alpha, colorFilter = colorFilter)
+ target.drawImage(targetImage, srcSize = size, alpha = alpha, colorFilter = colorFilter)
}
/**
diff --git a/development/build_log_simplifier/message-flakes.ignore b/development/build_log_simplifier/message-flakes.ignore
index 843e9d4..f19cee7 100644
--- a/development/build_log_simplifier/message-flakes.ignore
+++ b/development/build_log_simplifier/message-flakes.ignore
@@ -75,3 +75,29 @@
warning: ATTENTION!
# b/185474400
at org.gradle.*
+# > Task :internal-testutils-common:lintAnalyze
+Scanning .*:
+Failure reading binary cache file .*\.android\/cache\/api\-versions\-[0-9]+\-[0-9A-Z]+rev[0-9]+\.bin
+Please delete the file and restart the IDE\/lint\: .*\.android\/cache\/api\-versions\-[0-9]+\-[0-9]+rev[0-9]+\.bin
+java\.io\.FileNotFoundException\: .*\.android\/cache\/api\-versions\-[0-9]+\-[0-9]+rev[0-9]+\.bin \(No such file or directory\)
+at com\.google\.common\.io\.Files\$FileByteSource\.openStream\(Files\.java\:[0-9]+\)
+at com\.google\.common\.io\.Files\$FileByteSource\.read\(Files\.java\:[0-9]+\)
+at com\.google\.common\.io\.Files\.toByteArray\(Files\.java\:[0-9]+\)
+at com\.android\.tools\.lint\.checks\.ApiDatabase\.readData\(ApiDatabase\.java\:[0-9]+\)
+at com\.android\.tools\.lint\.checks\.ApiLookup\.\<init\>\(ApiLookup\.java\:[0-9]+\)
+at com\.android\.tools\.lint\.checks\.ApiLookup\.get\(ApiLookup\.java\:[0-9]+\)
+at com\.android\.tools\.lint\.checks\.ApiDetector\.beforeCheckRootProject\(ApiDetector\.kt\:[0-9]+\)
+at com\.android\.tools\.lint\.client\.api\.LintDriver\.checkProject\(LintDriver\.kt\:[0-9]+\)
+at com\.android\.tools\.lint\.client\.api\.LintDriver\.checkProjectRoot\(LintDriver\.kt\:[0-9]+\)
+at com\.android\.tools\.lint\.client\.api\.LintDriver\.access\$checkProjectRoot\(LintDriver\.kt\:[0-9]+\)
+at com\.android\.tools\.lint\.client\.api\.LintDriver\$analyzeOnly\$[0-9]+\.invoke\(LintDriver\.kt\:[0-9]+\)
+at com\.android\.tools\.lint\.client\.api\.LintDriver\.doAnalyze\(LintDriver\.kt\:[0-9]+\)
+at com\.android\.tools\.lint\.client\.api\.LintDriver\.analyzeOnly\(LintDriver\.kt\:[0-9]+\)
+at com\.android\.tools\.lint\.LintCliClient\$analyzeOnly\$[0-9]+\.invoke\(LintCliClient\.kt\:[0-9]+\)
+at com\.android\.tools\.lint\.LintCliClient\.run\(LintCliClient\.kt\:[0-9]+\)
+at com\.android\.tools\.lint\.LintCliClient\.run\$default\(LintCliClient\.kt\:[0-9]+\)
+at com\.android\.tools\.lint\.LintCliClient\.analyzeOnly\(LintCliClient\.kt\:[0-9]+\)
+at com\.android\.tools\.lint\.Main\.run\(Main\.java\:[0-9]+\)
+at com\.android\.build\.gradle\.internal\.lint\.AndroidLintWorkAction\.invokeLintMainRunMethod\(AndroidLintWorkAction\.kt\:[0-9]+\)
+at com\.android\.build\.gradle\.internal\.lint\.AndroidLintWorkAction\.runLint\(AndroidLintWorkAction\.kt\:[0-9]+\)
+at com\.android\.build\.gradle\.internal\.lint\.AndroidLintWorkAction\.execute\(AndroidLintWorkAction\.kt\:[0-9]+\)
diff --git a/development/referenceDocs/stageReferenceDocsWithDackka.sh b/development/referenceDocs/stageReferenceDocsWithDackka.sh
index b5689aa..cc34502 100755
--- a/development/referenceDocs/stageReferenceDocsWithDackka.sh
+++ b/development/referenceDocs/stageReferenceDocsWithDackka.sh
@@ -26,6 +26,7 @@
# "collection"
"navigation"
"paging"
+ "window"
)
readonly kotlinLibraryDirs=(
# "benchmark"
@@ -33,6 +34,7 @@
# "collection"
"navigation"
# "paging"
+ "window"
)
diff --git a/docs-tip-of-tree/build.gradle b/docs-tip-of-tree/build.gradle
index 69af6e3..1ffc337 100644
--- a/docs-tip-of-tree/build.gradle
+++ b/docs-tip-of-tree/build.gradle
@@ -208,6 +208,7 @@
docs(project(":room:room-guava"))
docs(project(":room:room-ktx"))
docs(project(":room:room-migration"))
+ docs(project(":room:room-paging"))
docs(project(":room:room-runtime"))
docs(project(":room:room-rxjava2"))
docs(project(":room:room-rxjava3"))
diff --git a/navigation/integration-tests/testapp/src/main/java/androidx/navigation/testapp/HelpActivity.kt b/navigation/integration-tests/testapp/src/main/java/androidx/navigation/testapp/HelpActivity.kt
index 55f03b2..5eb47d1 100644
--- a/navigation/integration-tests/testapp/src/main/java/androidx/navigation/testapp/HelpActivity.kt
+++ b/navigation/integration-tests/testapp/src/main/java/androidx/navigation/testapp/HelpActivity.kt
@@ -78,6 +78,7 @@
}
class BottomSheetNavigationView : BottomSheetDialogFragment() {
+ @Suppress("DEPRECATION")
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
diff --git a/navigation/navigation-common/api/current.txt b/navigation/navigation-common/api/current.txt
index dda39ab..a889a60 100644
--- a/navigation/navigation-common/api/current.txt
+++ b/navigation/navigation-common/api/current.txt
@@ -226,7 +226,7 @@
}
@androidx.navigation.NavDestinationDsl public class NavDestinationBuilder<D extends androidx.navigation.NavDestination> {
- ctor public NavDestinationBuilder(androidx.navigation.Navigator<? extends D> navigator, @IdRes int id);
+ ctor @Deprecated public NavDestinationBuilder(androidx.navigation.Navigator<? extends D> navigator, @IdRes int id);
ctor public NavDestinationBuilder(androidx.navigation.Navigator<? extends D> navigator, String? route);
method public final void action(int actionId, kotlin.jvm.functions.Function1<? super androidx.navigation.NavActionBuilder,kotlin.Unit> actionBuilder);
method public final void argument(String name, kotlin.jvm.functions.Function1<? super androidx.navigation.NavArgumentBuilder,kotlin.Unit> argumentBuilder);
@@ -281,7 +281,7 @@
}
@androidx.navigation.NavDestinationDsl public class NavGraphBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.NavGraph> {
- ctor public NavGraphBuilder(androidx.navigation.NavigatorProvider provider, @IdRes int id, @IdRes int startDestination);
+ ctor @Deprecated public NavGraphBuilder(androidx.navigation.NavigatorProvider provider, @IdRes int id, @IdRes int startDestination);
ctor public NavGraphBuilder(androidx.navigation.NavigatorProvider provider, String startDestination, String? route);
method public final void addDestination(androidx.navigation.NavDestination destination);
method public androidx.navigation.NavGraph build();
@@ -292,9 +292,9 @@
}
public final class NavGraphBuilderKt {
- method public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
method public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
- method public static inline void navigation(androidx.navigation.NavGraphBuilder, @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline void navigation(androidx.navigation.NavGraphBuilder, @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
method public static inline void navigation(androidx.navigation.NavGraphBuilder, String startDestination, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
}
diff --git a/navigation/navigation-common/api/public_plus_experimental_current.txt b/navigation/navigation-common/api/public_plus_experimental_current.txt
index bd49a55..3dc13449 100644
--- a/navigation/navigation-common/api/public_plus_experimental_current.txt
+++ b/navigation/navigation-common/api/public_plus_experimental_current.txt
@@ -263,7 +263,7 @@
}
@androidx.navigation.NavDestinationDsl public class NavDestinationBuilder<D extends androidx.navigation.NavDestination> {
- ctor public NavDestinationBuilder(androidx.navigation.Navigator<? extends D> navigator, @IdRes int id);
+ ctor @Deprecated public NavDestinationBuilder(androidx.navigation.Navigator<? extends D> navigator, @IdRes int id);
ctor public NavDestinationBuilder(androidx.navigation.Navigator<? extends D> navigator, String? route);
method public final void action(int actionId, kotlin.jvm.functions.Function1<? super androidx.navigation.NavActionBuilder,kotlin.Unit> actionBuilder);
method public final void argument(String name, kotlin.jvm.functions.Function1<? super androidx.navigation.NavArgumentBuilder,kotlin.Unit> argumentBuilder);
@@ -322,7 +322,7 @@
}
@androidx.navigation.NavDestinationDsl public class NavGraphBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.NavGraph> {
- ctor public NavGraphBuilder(androidx.navigation.NavigatorProvider provider, @IdRes int id, @IdRes int startDestination);
+ ctor @Deprecated public NavGraphBuilder(androidx.navigation.NavigatorProvider provider, @IdRes int id, @IdRes int startDestination);
ctor public NavGraphBuilder(androidx.navigation.NavigatorProvider provider, String startDestination, String? route);
method public final void addDestination(androidx.navigation.NavDestination destination);
method public androidx.navigation.NavGraph build();
@@ -333,9 +333,9 @@
}
public final class NavGraphBuilderKt {
- method public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
method public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
- method public static inline void navigation(androidx.navigation.NavGraphBuilder, @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline void navigation(androidx.navigation.NavGraphBuilder, @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
method public static inline void navigation(androidx.navigation.NavGraphBuilder, String startDestination, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
}
diff --git a/navigation/navigation-common/api/restricted_current.txt b/navigation/navigation-common/api/restricted_current.txt
index dda39ab..a889a60 100644
--- a/navigation/navigation-common/api/restricted_current.txt
+++ b/navigation/navigation-common/api/restricted_current.txt
@@ -226,7 +226,7 @@
}
@androidx.navigation.NavDestinationDsl public class NavDestinationBuilder<D extends androidx.navigation.NavDestination> {
- ctor public NavDestinationBuilder(androidx.navigation.Navigator<? extends D> navigator, @IdRes int id);
+ ctor @Deprecated public NavDestinationBuilder(androidx.navigation.Navigator<? extends D> navigator, @IdRes int id);
ctor public NavDestinationBuilder(androidx.navigation.Navigator<? extends D> navigator, String? route);
method public final void action(int actionId, kotlin.jvm.functions.Function1<? super androidx.navigation.NavActionBuilder,kotlin.Unit> actionBuilder);
method public final void argument(String name, kotlin.jvm.functions.Function1<? super androidx.navigation.NavArgumentBuilder,kotlin.Unit> argumentBuilder);
@@ -281,7 +281,7 @@
}
@androidx.navigation.NavDestinationDsl public class NavGraphBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.NavGraph> {
- ctor public NavGraphBuilder(androidx.navigation.NavigatorProvider provider, @IdRes int id, @IdRes int startDestination);
+ ctor @Deprecated public NavGraphBuilder(androidx.navigation.NavigatorProvider provider, @IdRes int id, @IdRes int startDestination);
ctor public NavGraphBuilder(androidx.navigation.NavigatorProvider provider, String startDestination, String? route);
method public final void addDestination(androidx.navigation.NavDestination destination);
method public androidx.navigation.NavGraph build();
@@ -292,9 +292,9 @@
}
public final class NavGraphBuilderKt {
- method public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
method public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
- method public static inline void navigation(androidx.navigation.NavGraphBuilder, @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline void navigation(androidx.navigation.NavGraphBuilder, @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
method public static inline void navigation(androidx.navigation.NavGraphBuilder, String startDestination, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
}
diff --git a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDestinationBuilderTest.kt b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDestinationBuilderTest.kt
index 68fa76a..6572323 100644
--- a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDestinationBuilderTest.kt
+++ b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDestinationBuilderTest.kt
@@ -124,6 +124,7 @@
* a NavDestination directly to allow for testing NavDestinationBuilder in
* isolation.
*/
+@Suppress("DEPRECATION")
fun NavigatorProvider.navDestination(
@IdRes id: Int,
builder: NavDestinationBuilder<NavDestination>.() -> Unit
diff --git a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavGraphBuilderTest.kt b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavGraphBuilderTest.kt
index cb75a08..69d1eda 100644
--- a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavGraphBuilderTest.kt
+++ b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavGraphBuilderTest.kt
@@ -32,6 +32,7 @@
addNavigator(NoOpNavigator())
}
+ @Suppress("DEPRECATION")
@Test
fun navigation() {
val graph = provider.navigation(startDestination = DESTINATION_ID) {
@@ -54,6 +55,7 @@
.isTrue()
}
+ @Suppress("DEPRECATION")
@Test
fun navigationUnaryPlus() {
val graph = provider.navigation(startDestination = DESTINATION_ID) {
@@ -80,6 +82,7 @@
.isTrue()
}
+ @Suppress("DEPRECATION")
@Test
fun navigationAddDestination() {
val graph = provider.navigation(startDestination = DESTINATION_ID) {
@@ -108,6 +111,7 @@
.isTrue()
}
+ @Suppress("DEPRECATION")
@Test(expected = IllegalStateException::class)
fun navigationMissingStartDestination() {
provider.navigation(startDestination = 0) {
@@ -124,6 +128,7 @@
fail("NavGraph should throw IllegalStateException if no startDestinationRoute is set")
}
+ @Suppress("DEPRECATION")
@Test
fun navigationNested() {
val graph = provider.navigation(startDestination = DESTINATION_ID) {
@@ -158,6 +163,7 @@
* Create a base NavDestination. Generally, only subtypes of NavDestination should be
* added to a NavGraph (hence why this is not in the common-ktx library)
*/
+@Suppress("DEPRECATION")
fun NavGraphBuilder.navDestination(
@IdRes id: Int,
builder: NavDestinationBuilder<NavDestination>.() -> Unit
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NavDestinationBuilder.kt b/navigation/navigation-common/src/main/java/androidx/navigation/NavDestinationBuilder.kt
index f5453fd..22c9fa3 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavDestinationBuilder.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavDestinationBuilder.kt
@@ -51,6 +51,10 @@
*
* @return the newly constructed [NavDestination]
*/
+ @Deprecated(
+ "Use routes to build your NavDestination instead",
+ ReplaceWith("NavDestinationBuilder(navigator, route = id.toString())")
+ )
public constructor(navigator: Navigator<out D>, @IdRes id: Int) :
this(navigator, id, null)
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NavGraphBuilder.kt b/navigation/navigation-common/src/main/java/androidx/navigation/NavGraphBuilder.kt
index 28a4c0a..d69f5d2 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavGraphBuilder.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavGraphBuilder.kt
@@ -27,6 +27,14 @@
*
* @return the newly constructed NavGraph
*/
+@Suppress("Deprecation")
+@Deprecated(
+ "Use routes to build your NavGraph instead",
+ ReplaceWith(
+ "navigation(startDestination = startDestination.toString(), route = id.toString()) " +
+ "{ builder.invoke() }"
+ )
+)
public inline fun NavigatorProvider.navigation(
@IdRes id: Int = 0,
@IdRes startDestination: Int,
@@ -58,6 +66,14 @@
*
* @return the newly constructed nested NavGraph
*/
+@Suppress("Deprecation")
+@Deprecated(
+ "Use routes to build your nested NavGraph instead",
+ ReplaceWith(
+ "navigation(startDestination = startDestination.toString(), route = id.toString()) " +
+ "{ builder.invoke() }"
+ )
+)
public inline fun NavGraphBuilder.navigation(
@IdRes id: Int,
@IdRes startDestination: Int,
@@ -100,6 +116,14 @@
*
* @return the newly created NavGraph
*/
+ @Suppress("Deprecation")
+ @Deprecated(
+ "Use routes to build your NavGraph instead",
+ ReplaceWith(
+ "NavGraphBuilder(provider, startDestination = startDestination.toString(), " +
+ "route = id.toString())"
+ )
+ )
public constructor(
provider: NavigatorProvider,
@IdRes id: Int,
diff --git a/navigation/navigation-dynamic-features-fragment/api/current.txt b/navigation/navigation-dynamic-features-fragment/api/current.txt
index e6dd027..d42b4d5 100644
--- a/navigation/navigation-dynamic-features-fragment/api/current.txt
+++ b/navigation/navigation-dynamic-features-fragment/api/current.txt
@@ -15,7 +15,7 @@
}
@androidx.navigation.NavDestinationDsl public final class DynamicFragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.FragmentNavigator.Destination> {
- ctor public DynamicFragmentNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator navigator, @IdRes int id, String fragmentClassName);
+ ctor @Deprecated public DynamicFragmentNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator navigator, @IdRes int id, String fragmentClassName);
ctor public DynamicFragmentNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator navigator, String route, String fragmentClassName);
method public androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator.Destination build();
method public String? getModuleName();
@@ -24,7 +24,7 @@
}
public final class DynamicFragmentNavigatorDestinationBuilderKt {
- method public static inline void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String fragmentClassName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String fragmentClassName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
method public static inline void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, String fragmentClassName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id);
method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
diff --git a/navigation/navigation-dynamic-features-fragment/api/public_plus_experimental_current.txt b/navigation/navigation-dynamic-features-fragment/api/public_plus_experimental_current.txt
index e6dd027..d42b4d5 100644
--- a/navigation/navigation-dynamic-features-fragment/api/public_plus_experimental_current.txt
+++ b/navigation/navigation-dynamic-features-fragment/api/public_plus_experimental_current.txt
@@ -15,7 +15,7 @@
}
@androidx.navigation.NavDestinationDsl public final class DynamicFragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.FragmentNavigator.Destination> {
- ctor public DynamicFragmentNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator navigator, @IdRes int id, String fragmentClassName);
+ ctor @Deprecated public DynamicFragmentNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator navigator, @IdRes int id, String fragmentClassName);
ctor public DynamicFragmentNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator navigator, String route, String fragmentClassName);
method public androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator.Destination build();
method public String? getModuleName();
@@ -24,7 +24,7 @@
}
public final class DynamicFragmentNavigatorDestinationBuilderKt {
- method public static inline void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String fragmentClassName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String fragmentClassName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
method public static inline void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, String fragmentClassName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id);
method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
diff --git a/navigation/navigation-dynamic-features-fragment/api/restricted_current.txt b/navigation/navigation-dynamic-features-fragment/api/restricted_current.txt
index e6dd027..d42b4d5 100644
--- a/navigation/navigation-dynamic-features-fragment/api/restricted_current.txt
+++ b/navigation/navigation-dynamic-features-fragment/api/restricted_current.txt
@@ -15,7 +15,7 @@
}
@androidx.navigation.NavDestinationDsl public final class DynamicFragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.FragmentNavigator.Destination> {
- ctor public DynamicFragmentNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator navigator, @IdRes int id, String fragmentClassName);
+ ctor @Deprecated public DynamicFragmentNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator navigator, @IdRes int id, String fragmentClassName);
ctor public DynamicFragmentNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator navigator, String route, String fragmentClassName);
method public androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator.Destination build();
method public String? getModuleName();
@@ -24,7 +24,7 @@
}
public final class DynamicFragmentNavigatorDestinationBuilderKt {
- method public static inline void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String fragmentClassName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String fragmentClassName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
method public static inline void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, String fragmentClassName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id);
method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
diff --git a/navigation/navigation-dynamic-features-fragment/src/androidTest/java/androidx/navigation/dynamicfeatures/fragment/DynamicFragmentNavigatorDestinationBuilderTest.kt b/navigation/navigation-dynamic-features-fragment/src/androidTest/java/androidx/navigation/dynamicfeatures/fragment/DynamicFragmentNavigatorDestinationBuilderTest.kt
index 30da2f9..9a18178 100644
--- a/navigation/navigation-dynamic-features-fragment/src/androidTest/java/androidx/navigation/dynamicfeatures/fragment/DynamicFragmentNavigatorDestinationBuilderTest.kt
+++ b/navigation/navigation-dynamic-features-fragment/src/androidTest/java/androidx/navigation/dynamicfeatures/fragment/DynamicFragmentNavigatorDestinationBuilderTest.kt
@@ -40,6 +40,7 @@
)
private val fragmentManager get() = rule.withActivity { supportFragmentManager }
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
public fun reified() {
@@ -56,6 +57,7 @@
.isEqualTo(TestFragment::class.java.name)
}
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
public fun moduleName() {
@@ -77,6 +79,7 @@
.isEqualTo(MODULE_NAME)
}
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
public fun no_moduleName() {
diff --git a/navigation/navigation-dynamic-features-fragment/src/main/java/androidx/navigation/dynamicfeatures/fragment/DynamicFragmentNavigatorDestinationBuilder.kt b/navigation/navigation-dynamic-features-fragment/src/main/java/androidx/navigation/dynamicfeatures/fragment/DynamicFragmentNavigatorDestinationBuilder.kt
index dd0b7f2..d337aa2 100644
--- a/navigation/navigation-dynamic-features-fragment/src/main/java/androidx/navigation/dynamicfeatures/fragment/DynamicFragmentNavigatorDestinationBuilder.kt
+++ b/navigation/navigation-dynamic-features-fragment/src/main/java/androidx/navigation/dynamicfeatures/fragment/DynamicFragmentNavigatorDestinationBuilder.kt
@@ -29,6 +29,11 @@
* Construct a new [DynamicFragmentNavigator.Destination]
* @param id Destination id.
*/
+@Suppress("Deprecation")
+@Deprecated(
+ "Use routes to create your DynamicFragmentDestination instead",
+ ReplaceWith("fragment(route = id.toString())")
+)
public inline fun <reified F : Fragment> DynamicNavGraphBuilder.fragment(
@IdRes id: Int
): Unit = fragment<F>(id) {}
@@ -37,6 +42,11 @@
* Construct a new [DynamicFragmentNavigator.Destination]
* @param id Destination id.
*/
+@Suppress("Deprecation")
+@Deprecated(
+ "Use routes to create your DynamicFragmentDestination instead",
+ ReplaceWith("fragment(route = id.toString()) { builder.invoke() }")
+)
public inline fun <reified F : Fragment> DynamicNavGraphBuilder.fragment(
@IdRes id: Int,
builder: DynamicFragmentNavigatorDestinationBuilder.() -> Unit
@@ -47,6 +57,11 @@
* @param id Destination id.
* @param fragmentClassName Fully qualified class name of destination Fragment.
*/
+@Suppress("Deprecation")
+@Deprecated(
+ "Use routes to create your DynamicFragmentDestination instead",
+ ReplaceWith("fragment(route = id.toString(), fragmentClassName) { builder.invoke() }")
+)
public inline fun DynamicNavGraphBuilder.fragment(
@IdRes id: Int,
fragmentClassName: String,
@@ -102,6 +117,14 @@
private var fragmentClassName: String
+ @Suppress("Deprecation")
+ @Deprecated(
+ "Use routes to create your DynamicFragmentDestinationBuilder instead",
+ ReplaceWith(
+ "DynamicFragmentNavigatorDestinationBuilder(navigator, route = id.toString(), " +
+ "fragmentClassName)"
+ )
+ )
public constructor(
navigator: DynamicFragmentNavigator,
@IdRes id: Int,
diff --git a/navigation/navigation-dynamic-features-runtime/api/current.txt b/navigation/navigation-dynamic-features-runtime/api/current.txt
index 9807b58..ea49279 100644
--- a/navigation/navigation-dynamic-features-runtime/api/current.txt
+++ b/navigation/navigation-dynamic-features-runtime/api/current.txt
@@ -15,7 +15,7 @@
}
@androidx.navigation.NavDestinationDsl public final class DynamicActivityNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.ActivityNavigator.Destination> {
- ctor public DynamicActivityNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.DynamicActivityNavigator activityNavigator, @IdRes int id);
+ ctor @Deprecated public DynamicActivityNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.DynamicActivityNavigator activityNavigator, @IdRes int id);
ctor public DynamicActivityNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.DynamicActivityNavigator activityNavigator, String route);
method public androidx.navigation.dynamicfeatures.DynamicActivityNavigator.Destination build();
method public String? getAction();
@@ -39,7 +39,7 @@
}
public final class DynamicActivityNavigatorDestinationBuilderKt {
- method public static inline void activity(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline void activity(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
method public static inline void activity(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
}
@@ -87,7 +87,7 @@
}
@androidx.navigation.NavDestinationDsl public final class DynamicIncludeNavGraphBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph> {
- ctor public DynamicIncludeNavGraphBuilder(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator dynamicIncludeGraphNavigator, @IdRes int id, String moduleName, String graphResourceName);
+ ctor @Deprecated public DynamicIncludeNavGraphBuilder(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator dynamicIncludeGraphNavigator, @IdRes int id, String moduleName, String graphResourceName);
ctor public DynamicIncludeNavGraphBuilder(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator dynamicIncludeGraphNavigator, String route, String moduleName, String graphResourceName);
method public androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph build();
method public String? getGraphPackage();
@@ -96,8 +96,8 @@
}
public final class DynamicIncludeNavGraphBuilderKt {
- method public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String moduleName, String graphResourceName);
- method public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String moduleName, String graphResourceName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicIncludeNavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String moduleName, String graphResourceName);
+ method @Deprecated public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String moduleName, String graphResourceName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicIncludeNavGraphBuilder,kotlin.Unit> builder);
method public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, String moduleName, String graphResourceName);
method public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, String moduleName, String graphResourceName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicIncludeNavGraphBuilder,kotlin.Unit> builder);
}
@@ -120,7 +120,7 @@
}
@androidx.navigation.NavDestinationDsl public final class DynamicNavGraphBuilder extends androidx.navigation.NavGraphBuilder {
- ctor public DynamicNavGraphBuilder(androidx.navigation.NavigatorProvider provider, @IdRes int id, @IdRes int startDestination);
+ ctor @Deprecated public DynamicNavGraphBuilder(androidx.navigation.NavigatorProvider provider, @IdRes int id, @IdRes int startDestination);
ctor public DynamicNavGraphBuilder(androidx.navigation.NavigatorProvider provider, String startDestination, optional String? route);
method public String? getModuleName();
method public int getProgressDestination();
@@ -134,19 +134,20 @@
}
public final class DynamicNavGraphBuilderKt {
- method public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
- method public static inline void navigation(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline void navigation(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
method public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
method public static inline void navigation(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String startDestination, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
}
public final class NavControllerKt {
- method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
}
public final class NavHostKt {
- method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
}
}
diff --git a/navigation/navigation-dynamic-features-runtime/api/public_plus_experimental_current.txt b/navigation/navigation-dynamic-features-runtime/api/public_plus_experimental_current.txt
index 9807b58..ea49279 100644
--- a/navigation/navigation-dynamic-features-runtime/api/public_plus_experimental_current.txt
+++ b/navigation/navigation-dynamic-features-runtime/api/public_plus_experimental_current.txt
@@ -15,7 +15,7 @@
}
@androidx.navigation.NavDestinationDsl public final class DynamicActivityNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.ActivityNavigator.Destination> {
- ctor public DynamicActivityNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.DynamicActivityNavigator activityNavigator, @IdRes int id);
+ ctor @Deprecated public DynamicActivityNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.DynamicActivityNavigator activityNavigator, @IdRes int id);
ctor public DynamicActivityNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.DynamicActivityNavigator activityNavigator, String route);
method public androidx.navigation.dynamicfeatures.DynamicActivityNavigator.Destination build();
method public String? getAction();
@@ -39,7 +39,7 @@
}
public final class DynamicActivityNavigatorDestinationBuilderKt {
- method public static inline void activity(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline void activity(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
method public static inline void activity(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
}
@@ -87,7 +87,7 @@
}
@androidx.navigation.NavDestinationDsl public final class DynamicIncludeNavGraphBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph> {
- ctor public DynamicIncludeNavGraphBuilder(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator dynamicIncludeGraphNavigator, @IdRes int id, String moduleName, String graphResourceName);
+ ctor @Deprecated public DynamicIncludeNavGraphBuilder(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator dynamicIncludeGraphNavigator, @IdRes int id, String moduleName, String graphResourceName);
ctor public DynamicIncludeNavGraphBuilder(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator dynamicIncludeGraphNavigator, String route, String moduleName, String graphResourceName);
method public androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph build();
method public String? getGraphPackage();
@@ -96,8 +96,8 @@
}
public final class DynamicIncludeNavGraphBuilderKt {
- method public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String moduleName, String graphResourceName);
- method public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String moduleName, String graphResourceName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicIncludeNavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String moduleName, String graphResourceName);
+ method @Deprecated public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String moduleName, String graphResourceName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicIncludeNavGraphBuilder,kotlin.Unit> builder);
method public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, String moduleName, String graphResourceName);
method public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, String moduleName, String graphResourceName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicIncludeNavGraphBuilder,kotlin.Unit> builder);
}
@@ -120,7 +120,7 @@
}
@androidx.navigation.NavDestinationDsl public final class DynamicNavGraphBuilder extends androidx.navigation.NavGraphBuilder {
- ctor public DynamicNavGraphBuilder(androidx.navigation.NavigatorProvider provider, @IdRes int id, @IdRes int startDestination);
+ ctor @Deprecated public DynamicNavGraphBuilder(androidx.navigation.NavigatorProvider provider, @IdRes int id, @IdRes int startDestination);
ctor public DynamicNavGraphBuilder(androidx.navigation.NavigatorProvider provider, String startDestination, optional String? route);
method public String? getModuleName();
method public int getProgressDestination();
@@ -134,19 +134,20 @@
}
public final class DynamicNavGraphBuilderKt {
- method public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
- method public static inline void navigation(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline void navigation(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
method public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
method public static inline void navigation(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String startDestination, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
}
public final class NavControllerKt {
- method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
}
public final class NavHostKt {
- method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
}
}
diff --git a/navigation/navigation-dynamic-features-runtime/api/restricted_current.txt b/navigation/navigation-dynamic-features-runtime/api/restricted_current.txt
index 9807b58..ea49279 100644
--- a/navigation/navigation-dynamic-features-runtime/api/restricted_current.txt
+++ b/navigation/navigation-dynamic-features-runtime/api/restricted_current.txt
@@ -15,7 +15,7 @@
}
@androidx.navigation.NavDestinationDsl public final class DynamicActivityNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.ActivityNavigator.Destination> {
- ctor public DynamicActivityNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.DynamicActivityNavigator activityNavigator, @IdRes int id);
+ ctor @Deprecated public DynamicActivityNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.DynamicActivityNavigator activityNavigator, @IdRes int id);
ctor public DynamicActivityNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.DynamicActivityNavigator activityNavigator, String route);
method public androidx.navigation.dynamicfeatures.DynamicActivityNavigator.Destination build();
method public String? getAction();
@@ -39,7 +39,7 @@
}
public final class DynamicActivityNavigatorDestinationBuilderKt {
- method public static inline void activity(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline void activity(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
method public static inline void activity(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
}
@@ -87,7 +87,7 @@
}
@androidx.navigation.NavDestinationDsl public final class DynamicIncludeNavGraphBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph> {
- ctor public DynamicIncludeNavGraphBuilder(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator dynamicIncludeGraphNavigator, @IdRes int id, String moduleName, String graphResourceName);
+ ctor @Deprecated public DynamicIncludeNavGraphBuilder(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator dynamicIncludeGraphNavigator, @IdRes int id, String moduleName, String graphResourceName);
ctor public DynamicIncludeNavGraphBuilder(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator dynamicIncludeGraphNavigator, String route, String moduleName, String graphResourceName);
method public androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph build();
method public String? getGraphPackage();
@@ -96,8 +96,8 @@
}
public final class DynamicIncludeNavGraphBuilderKt {
- method public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String moduleName, String graphResourceName);
- method public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String moduleName, String graphResourceName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicIncludeNavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String moduleName, String graphResourceName);
+ method @Deprecated public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String moduleName, String graphResourceName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicIncludeNavGraphBuilder,kotlin.Unit> builder);
method public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, String moduleName, String graphResourceName);
method public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, String moduleName, String graphResourceName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicIncludeNavGraphBuilder,kotlin.Unit> builder);
}
@@ -120,7 +120,7 @@
}
@androidx.navigation.NavDestinationDsl public final class DynamicNavGraphBuilder extends androidx.navigation.NavGraphBuilder {
- ctor public DynamicNavGraphBuilder(androidx.navigation.NavigatorProvider provider, @IdRes int id, @IdRes int startDestination);
+ ctor @Deprecated public DynamicNavGraphBuilder(androidx.navigation.NavigatorProvider provider, @IdRes int id, @IdRes int startDestination);
ctor public DynamicNavGraphBuilder(androidx.navigation.NavigatorProvider provider, String startDestination, optional String? route);
method public String? getModuleName();
method public int getProgressDestination();
@@ -134,19 +134,20 @@
}
public final class DynamicNavGraphBuilderKt {
- method public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
- method public static inline void navigation(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline void navigation(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
method public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
method public static inline void navigation(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String startDestination, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
}
public final class NavControllerKt {
- method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
}
public final class NavHostKt {
- method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+ method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
}
}
diff --git a/navigation/navigation-dynamic-features-runtime/src/androidTest/java/androidx/navigation/dynamicfeatures/DynamicActivityNavigatorDestinationBuilderTest.kt b/navigation/navigation-dynamic-features-runtime/src/androidTest/java/androidx/navigation/dynamicfeatures/DynamicActivityNavigatorDestinationBuilderTest.kt
index 5fd5b65..613d5b3 100644
--- a/navigation/navigation-dynamic-features-runtime/src/androidTest/java/androidx/navigation/dynamicfeatures/DynamicActivityNavigatorDestinationBuilderTest.kt
+++ b/navigation/navigation-dynamic-features-runtime/src/androidTest/java/androidx/navigation/dynamicfeatures/DynamicActivityNavigatorDestinationBuilderTest.kt
@@ -46,6 +46,7 @@
)
}
+ @Suppress("DEPRECATION")
@Test
fun module() {
val graph = navController.createGraph(startDestination = DESTINATION_ID) {
@@ -60,6 +61,7 @@
.isEqualTo(MODULE_NAME)
}
+ @Suppress("DEPRECATION")
@Test
fun noModule() {
val graph = navController.createGraph(startDestination = DESTINATION_ID) {
@@ -71,6 +73,7 @@
).isNull()
}
+ @Suppress("DEPRECATION")
@Test
fun activity() {
val graph = navController.createGraph(startDestination = DESTINATION_ID) {
@@ -90,6 +93,7 @@
)
}
+ @Suppress("DEPRECATION")
@Test
fun noActivity() {
val graph = navController.createGraph(startDestination = DESTINATION_ID) {
@@ -102,6 +106,7 @@
).isNull()
}
+ @Suppress("DEPRECATION")
@Test
fun modulePackage() {
val graph = navController.createGraph(startDestination = DESTINATION_ID) {
diff --git a/navigation/navigation-dynamic-features-runtime/src/androidTest/java/androidx/navigation/dynamicfeatures/DynamicIncludeNavGraphBuilderTest.kt b/navigation/navigation-dynamic-features-runtime/src/androidTest/java/androidx/navigation/dynamicfeatures/DynamicIncludeNavGraphBuilderTest.kt
index aa3b07d..fe10518 100644
--- a/navigation/navigation-dynamic-features-runtime/src/androidTest/java/androidx/navigation/dynamicfeatures/DynamicIncludeNavGraphBuilderTest.kt
+++ b/navigation/navigation-dynamic-features-runtime/src/androidTest/java/androidx/navigation/dynamicfeatures/DynamicIncludeNavGraphBuilderTest.kt
@@ -44,6 +44,7 @@
navigatorProvider += NoOpNavigator()
}
+ @Suppress("DEPRECATION")
@Test
fun includeDynamic() {
val graph = navController.navigatorProvider.navigation(startDestination = GRAPH_ID) {
@@ -65,6 +66,7 @@
.isEqualTo(GRAPH_RESOURCE_NAME)
}
+ @Suppress("DEPRECATION")
fun includeDynamic_emptyModuleName() {
navController.navigatorProvider.navigation(startDestination = GRAPH_ID) {
try {
@@ -76,6 +78,7 @@
}
}
+ @Suppress("DEPRECATION")
@Test
fun includeDynamic_graphPackage_null() {
val graph = navController.navigatorProvider.navigation(startDestination = GRAPH_ID) {
@@ -87,6 +90,7 @@
.that(includeDynamic.graphPackage).isEqualTo("${context.packageName}.$MODULE_NAME")
}
+ @Suppress("DEPRECATION")
@Test
fun includeDynamic_graphPackage_empty() {
navController.navigatorProvider.navigation(startDestination = GRAPH_ID) {
@@ -101,6 +105,7 @@
}
}
+ @Suppress("DEPRECATION")
@Test
fun includeDynamic_graphResourceName_empty() {
navController.navigatorProvider.navigation(startDestination = GRAPH_ID) {
diff --git a/navigation/navigation-dynamic-features-runtime/src/androidTest/java/androidx/navigation/dynamicfeatures/DynamicNavGraphBuilderTest.kt b/navigation/navigation-dynamic-features-runtime/src/androidTest/java/androidx/navigation/dynamicfeatures/DynamicNavGraphBuilderTest.kt
index de954ca..b190825 100644
--- a/navigation/navigation-dynamic-features-runtime/src/androidTest/java/androidx/navigation/dynamicfeatures/DynamicNavGraphBuilderTest.kt
+++ b/navigation/navigation-dynamic-features-runtime/src/androidTest/java/androidx/navigation/dynamicfeatures/DynamicNavGraphBuilderTest.kt
@@ -44,6 +44,7 @@
addNavigator(NoOpNavigator())
}
+ @Suppress("DEPRECATION")
@Test
fun navigation() {
val graph = provider.navigation(startDestination = DESTINATION_ID) {
@@ -59,6 +60,7 @@
.isEqualTo(MODULE_NAME)
}
+ @Suppress("DEPRECATION")
fun navigation_emptyModuleName() {
val graph = provider.navigation(startDestination = DESTINATION_ID) {
}
@@ -66,6 +68,7 @@
.that(graph !is DynamicGraphNavigator.DynamicNavGraph)
}
+ @Suppress("DEPRECATION")
@Test
fun progressDestination() {
val graph = provider.navigation(startDestination = DESTINATION_ID) {
@@ -83,6 +86,7 @@
.isTrue()
}
+ @Suppress("DEPRECATION")
@Test
fun progressDestination_notSet() {
val graph = provider.navigation(startDestination = DESTINATION_ID) {
@@ -155,6 +159,7 @@
* Create a base NavDestination. Generally, only subtypes of NavDestination should be
* added to a NavGraph (hence why this is not in the common-ktx library)
*/
+@Suppress("DEPRECATION")
fun DynamicNavGraphBuilder.navDestination(
@IdRes id: Int,
builder: NavDestinationBuilder<NavDestination>.() -> Unit
diff --git a/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicActivityNavigatorDestinationBuilder.kt b/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicActivityNavigatorDestinationBuilder.kt
index 67dde4b..7fefcef 100644
--- a/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicActivityNavigatorDestinationBuilder.kt
+++ b/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicActivityNavigatorDestinationBuilder.kt
@@ -30,6 +30,11 @@
* Construct a new [DynamicActivityNavigator.Destination]
* @param id Destination id.
*/
+@Suppress("Deprecation")
+@Deprecated(
+ "Use routes to build your DynamicActivityDestination instead",
+ ReplaceWith("activity(route = id.toString()) { builder.invoke() }")
+)
public inline fun DynamicNavGraphBuilder.activity(
@IdRes id: Int,
builder: DynamicActivityNavigatorDestinationBuilder.() -> Unit
@@ -62,6 +67,13 @@
NavDestinationBuilder<ActivityNavigator.Destination> {
private var activityNavigator: DynamicActivityNavigator
+ @Suppress("Deprecation")
+ @Deprecated(
+ "Use routes to build your DynamicActivityDestination instead",
+ ReplaceWith(
+ "DynamicActivityNavigatorDestinationBuilder(activityNavigator, route = id.toString())"
+ )
+ )
public constructor(
activityNavigator: DynamicActivityNavigator,
@IdRes id: Int
diff --git a/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicIncludeNavGraphBuilder.kt b/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicIncludeNavGraphBuilder.kt
index 4b8cc85..a59d702 100644
--- a/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicIncludeNavGraphBuilder.kt
+++ b/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicIncludeNavGraphBuilder.kt
@@ -33,6 +33,11 @@
* @param graphResourceName Graph's resource name without the `navigation` qualifier. This
* must not be an empty string.
*/
+@Suppress("Deprecation")
+@Deprecated(
+ "Use routes to include your DynamicNavGraph instead",
+ ReplaceWith("includeDynamic(route = id.toString(), moduleName, graphResourceName)")
+)
public inline fun DynamicNavGraphBuilder.includeDynamic(
@IdRes id: Int,
moduleName: String,
@@ -49,6 +54,13 @@
* must not be an empty string.
* @param builder Another builder for chaining.
*/
+@Suppress("Deprecation")
+@Deprecated(
+ "Use routes to include your DynamicNavGraph instead",
+ ReplaceWith(
+ "includeDynamic(route = id.toString(), moduleName, graphResourceName) { builder.invoke() }"
+ )
+)
public inline fun DynamicNavGraphBuilder.includeDynamic(
@IdRes id: Int,
moduleName: String,
@@ -112,6 +124,14 @@
private var moduleName: String
private var graphResourceName: String
+ @Suppress("Deprecation")
+ @Deprecated(
+ "Use routes to create your DynamicIncludeNavGraphBuilder instead",
+ ReplaceWith(
+ "DynamicIncludeNavGraphBuilder(dynamicIncludeGraphNavigator, route = id.toString(), " +
+ "moduleName, graphResourceName)"
+ )
+ )
public constructor(
dynamicIncludeGraphNavigator: DynamicIncludeGraphNavigator,
@IdRes id: Int,
diff --git a/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicNavGraphBuilder.kt b/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicNavGraphBuilder.kt
index 1919a1f..367d36f 100644
--- a/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicNavGraphBuilder.kt
+++ b/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicNavGraphBuilder.kt
@@ -32,6 +32,14 @@
* @param startDestination Id start destination in the graph
* @param builder Another builder for chaining.
*/
+@Suppress("Deprecation")
+@Deprecated(
+ "Use routes to create your DynamicNavGraph instead",
+ ReplaceWith(
+ "navigation(startDestination = startDestination.toString(), route = id.toString()) " +
+ "{ builder.invoke() }"
+ )
+)
public inline fun NavigatorProvider.navigation(
@IdRes id: Int = 0,
@IdRes startDestination: Int,
@@ -49,6 +57,14 @@
* @param startDestination Id start destination in the graph
* @param builder Another builder for chaining.
*/
+@Suppress("Deprecation")
+@Deprecated(
+ "Use routes to create your DynamicNavGraph instead",
+ ReplaceWith(
+ "navigation(startDestination = startDestination.toString(), route = id.toString()) " +
+ "{ builder.invoke() }"
+ )
+)
public inline fun DynamicNavGraphBuilder.navigation(
@IdRes id: Int,
@IdRes startDestination: Int,
@@ -105,6 +121,14 @@
@IdRes private var startDestinationId: Int = 0
private var startDestinationRoute: String? = null
+ @Suppress("Deprecation")
+ @Deprecated(
+ "Use routes to create your DynamicNavGraphBuilder instead",
+ ReplaceWith(
+ "DynamicNavGraphBuilder(provider, startDestination = startDestination.toString(), " +
+ "route = id.toString())"
+ )
+ )
public constructor(
provider: NavigatorProvider,
@IdRes id: Int,
diff --git a/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/NavController.kt b/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/NavController.kt
index f9e3d8f..f35e4e4 100644
--- a/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/NavController.kt
+++ b/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/NavController.kt
@@ -23,6 +23,14 @@
/**
* Construct a new [androidx.navigation.NavGraph] that supports dynamic navigation destinations
*/
+@Suppress("Deprecation")
+@Deprecated(
+ "Use routes to create your dynamic NavGraph instead",
+ ReplaceWith(
+ "createGraph(startDestination = startDestination.toString(), route = id.toString()) " +
+ "{ builder.invoke() }"
+ )
+)
public inline fun NavController.createGraph(
@IdRes id: Int = 0,
@IdRes startDestination: Int,
diff --git a/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/NavHost.kt b/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/NavHost.kt
index 800645a..9bd3e8ee 100644
--- a/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/NavHost.kt
+++ b/navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/NavHost.kt
@@ -23,8 +23,25 @@
/**
* Construct a new [androidx.navigation.NavGraph] that supports dynamic navigation destinations
*/
+@Suppress("Deprecation")
+@Deprecated(
+ "Use routes to create your dynamic NavGraph instead",
+ ReplaceWith(
+ "createGraph(startDestination = startDestination.toString(), route = id.toString()) " +
+ "{ builder.invoke() }"
+ )
+)
public inline fun NavHost.createGraph(
@IdRes id: Int = 0,
@IdRes startDestination: Int,
builder: DynamicNavGraphBuilder.() -> Unit
): NavGraph = navController.createGraph(id, startDestination, builder)
+
+/**
+ * Construct a new [androidx.navigation.NavGraph] that supports dynamic navigation destinations
+ */
+public inline fun NavHost.createGraph(
+ startDestination: String,
+ route: String? = null,
+ builder: DynamicNavGraphBuilder.() -> Unit
+): NavGraph = navController.createGraph(startDestination, route, builder)
diff --git a/navigation/navigation-fragment/api/current.txt b/navigation/navigation-fragment/api/current.txt
index ce7ec82..dd116f0 100644
--- a/navigation/navigation-fragment/api/current.txt
+++ b/navigation/navigation-fragment/api/current.txt
@@ -23,13 +23,16 @@
}
@androidx.navigation.NavDestinationDsl public final class DialogFragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.DialogFragmentNavigator.Destination> {
- ctor public DialogFragmentNavigatorDestinationBuilder(androidx.navigation.fragment.DialogFragmentNavigator navigator, @IdRes int id, kotlin.reflect.KClass<? extends androidx.fragment.app.DialogFragment> fragmentClass);
+ ctor @Deprecated public DialogFragmentNavigatorDestinationBuilder(androidx.navigation.fragment.DialogFragmentNavigator navigator, @IdRes int id, kotlin.reflect.KClass<? extends androidx.fragment.app.DialogFragment> fragmentClass);
+ ctor public DialogFragmentNavigatorDestinationBuilder(androidx.navigation.fragment.DialogFragmentNavigator navigator, String route, kotlin.reflect.KClass<? extends androidx.fragment.app.DialogFragment> fragmentClass);
method public androidx.navigation.fragment.DialogFragmentNavigator.Destination build();
}
public final class DialogFragmentNavigatorDestinationBuilderKt {
method public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, @IdRes int id);
method public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.DialogFragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
+ method public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, String route);
+ method public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.DialogFragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
}
public final class FragmentKt {
@@ -67,7 +70,7 @@
}
@androidx.navigation.NavDestinationDsl public final class FragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.FragmentNavigator.Destination> {
- ctor public FragmentNavigatorDestinationBuilder(androidx.navigation.fragment.FragmentNavigator navigator, @IdRes int id, kotlin.reflect.KClass<? extends androidx.fragment.app.Fragment> fragmentClass);
+ ctor @Deprecated public FragmentNavigatorDestinationBuilder(androidx.navigation.fragment.FragmentNavigator navigator, @IdRes int id, kotlin.reflect.KClass<? extends androidx.fragment.app.Fragment> fragmentClass);
ctor public FragmentNavigatorDestinationBuilder(androidx.navigation.fragment.FragmentNavigator navigator, String route, kotlin.reflect.KClass<? extends androidx.fragment.app.Fragment> fragmentClass);
method public androidx.navigation.fragment.FragmentNavigator.Destination build();
}
diff --git a/navigation/navigation-fragment/api/public_plus_experimental_current.txt b/navigation/navigation-fragment/api/public_plus_experimental_current.txt
index ce7ec82..dd116f0 100644
--- a/navigation/navigation-fragment/api/public_plus_experimental_current.txt
+++ b/navigation/navigation-fragment/api/public_plus_experimental_current.txt
@@ -23,13 +23,16 @@
}
@androidx.navigation.NavDestinationDsl public final class DialogFragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.DialogFragmentNavigator.Destination> {
- ctor public DialogFragmentNavigatorDestinationBuilder(androidx.navigation.fragment.DialogFragmentNavigator navigator, @IdRes int id, kotlin.reflect.KClass<? extends androidx.fragment.app.DialogFragment> fragmentClass);
+ ctor @Deprecated public DialogFragmentNavigatorDestinationBuilder(androidx.navigation.fragment.DialogFragmentNavigator navigator, @IdRes int id, kotlin.reflect.KClass<? extends androidx.fragment.app.DialogFragment> fragmentClass);
+ ctor public DialogFragmentNavigatorDestinationBuilder(androidx.navigation.fragment.DialogFragmentNavigator navigator, String route, kotlin.reflect.KClass<? extends androidx.fragment.app.DialogFragment> fragmentClass);
method public androidx.navigation.fragment.DialogFragmentNavigator.Destination build();
}
public final class DialogFragmentNavigatorDestinationBuilderKt {
method public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, @IdRes int id);
method public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.DialogFragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
+ method public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, String route);
+ method public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.DialogFragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
}
public final class FragmentKt {
@@ -67,7 +70,7 @@
}
@androidx.navigation.NavDestinationDsl public final class FragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.FragmentNavigator.Destination> {
- ctor public FragmentNavigatorDestinationBuilder(androidx.navigation.fragment.FragmentNavigator navigator, @IdRes int id, kotlin.reflect.KClass<? extends androidx.fragment.app.Fragment> fragmentClass);
+ ctor @Deprecated public FragmentNavigatorDestinationBuilder(androidx.navigation.fragment.FragmentNavigator navigator, @IdRes int id, kotlin.reflect.KClass<? extends androidx.fragment.app.Fragment> fragmentClass);
ctor public FragmentNavigatorDestinationBuilder(androidx.navigation.fragment.FragmentNavigator navigator, String route, kotlin.reflect.KClass<? extends androidx.fragment.app.Fragment> fragmentClass);
method public androidx.navigation.fragment.FragmentNavigator.Destination build();
}
diff --git a/navigation/navigation-fragment/api/restricted_current.txt b/navigation/navigation-fragment/api/restricted_current.txt
index ce7ec82..dd116f0 100644
--- a/navigation/navigation-fragment/api/restricted_current.txt
+++ b/navigation/navigation-fragment/api/restricted_current.txt
@@ -23,13 +23,16 @@
}
@androidx.navigation.NavDestinationDsl public final class DialogFragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.DialogFragmentNavigator.Destination> {
- ctor public DialogFragmentNavigatorDestinationBuilder(androidx.navigation.fragment.DialogFragmentNavigator navigator, @IdRes int id, kotlin.reflect.KClass<? extends androidx.fragment.app.DialogFragment> fragmentClass);
+ ctor @Deprecated public DialogFragmentNavigatorDestinationBuilder(androidx.navigation.fragment.DialogFragmentNavigator navigator, @IdRes int id, kotlin.reflect.KClass<? extends androidx.fragment.app.DialogFragment> fragmentClass);
+ ctor public DialogFragmentNavigatorDestinationBuilder(androidx.navigation.fragment.DialogFragmentNavigator navigator, String route, kotlin.reflect.KClass<? extends androidx.fragment.app.DialogFragment> fragmentClass);
method public androidx.navigation.fragment.DialogFragmentNavigator.Destination build();
}
public final class DialogFragmentNavigatorDestinationBuilderKt {
method public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, @IdRes int id);
method public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.DialogFragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
+ method public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, String route);
+ method public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.DialogFragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
}
public final class FragmentKt {
@@ -67,7 +70,7 @@
}
@androidx.navigation.NavDestinationDsl public final class FragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.FragmentNavigator.Destination> {
- ctor public FragmentNavigatorDestinationBuilder(androidx.navigation.fragment.FragmentNavigator navigator, @IdRes int id, kotlin.reflect.KClass<? extends androidx.fragment.app.Fragment> fragmentClass);
+ ctor @Deprecated public FragmentNavigatorDestinationBuilder(androidx.navigation.fragment.FragmentNavigator navigator, @IdRes int id, kotlin.reflect.KClass<? extends androidx.fragment.app.Fragment> fragmentClass);
ctor public FragmentNavigatorDestinationBuilder(androidx.navigation.fragment.FragmentNavigator navigator, String route, kotlin.reflect.KClass<? extends androidx.fragment.app.Fragment> fragmentClass);
method public androidx.navigation.fragment.FragmentNavigator.Destination build();
}
diff --git a/navigation/navigation-fragment/src/androidTest/java/androidx/navigation/fragment/DialogFragmentNavigatorDestinationBuilderTest.kt b/navigation/navigation-fragment/src/androidTest/java/androidx/navigation/fragment/DialogFragmentNavigatorDestinationBuilderTest.kt
index fed4875..7532fdb 100644
--- a/navigation/navigation-fragment/src/androidTest/java/androidx/navigation/fragment/DialogFragmentNavigatorDestinationBuilderTest.kt
+++ b/navigation/navigation-fragment/src/androidTest/java/androidx/navigation/fragment/DialogFragmentNavigatorDestinationBuilderTest.kt
@@ -36,6 +36,7 @@
val activityRule = androidx.test.rule.ActivityTestRule<TestActivity>(TestActivity::class.java)
private val fragmentManager get() = activityRule.activity.supportFragmentManager
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test fun fragment() {
val navHostFragment = NavHostFragment()
@@ -53,6 +54,7 @@
.isEqualTo(BuilderTestDialogFragment::class.java.name)
}
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test fun fragmentWithBody() {
val navHostFragment = NavHostFragment()
@@ -74,8 +76,48 @@
.that(graph[DESTINATION_ID].label)
.isEqualTo(LABEL)
}
+
+ @UiThreadTest
+ @Test fun fragmentRoute() {
+ val navHostFragment = NavHostFragment()
+ fragmentManager.beginTransaction()
+ .add(android.R.id.content, navHostFragment)
+ .commitNow()
+ val graph = navHostFragment.createGraph(startDestination = DESTINATION_ROUTE) {
+ dialog<BuilderTestDialogFragment>(DESTINATION_ROUTE)
+ }
+ assertWithMessage("Destination should be added to the graph")
+ .that(DESTINATION_ROUTE in graph)
+ .isTrue()
+ assertWithMessage("DialogFragment class should be set to BuilderTestDialogFragment")
+ .that((graph[DESTINATION_ROUTE] as DialogFragmentNavigator.Destination).className)
+ .isEqualTo(BuilderTestDialogFragment::class.java.name)
+ }
+
+ @UiThreadTest
+ @Test fun fragmentWithBodyRoute() {
+ val navHostFragment = NavHostFragment()
+ fragmentManager.beginTransaction()
+ .add(android.R.id.content, navHostFragment)
+ .commitNow()
+ val graph = navHostFragment.createGraph(startDestination = DESTINATION_ROUTE) {
+ dialog<BuilderTestDialogFragment>(DESTINATION_ROUTE) {
+ label = LABEL
+ }
+ }
+ assertWithMessage("Destination should be added to the graph")
+ .that(DESTINATION_ROUTE in graph)
+ .isTrue()
+ assertWithMessage("DialogFragment class should be set to BuilderTestDialogFragment")
+ .that((graph[DESTINATION_ROUTE] as DialogFragmentNavigator.Destination).className)
+ .isEqualTo(BuilderTestDialogFragment::class.java.name)
+ assertWithMessage("DialogFragment should have label set")
+ .that(graph[DESTINATION_ROUTE].label)
+ .isEqualTo(LABEL)
+ }
}
private const val DESTINATION_ID = 1
+private const val DESTINATION_ROUTE = "destination"
private const val LABEL = "Test"
class BuilderTestDialogFragment : DialogFragment()
diff --git a/navigation/navigation-fragment/src/androidTest/java/androidx/navigation/fragment/FragmentNavigatorDestinationBuilderTest.kt b/navigation/navigation-fragment/src/androidTest/java/androidx/navigation/fragment/FragmentNavigatorDestinationBuilderTest.kt
index 6e28a13..616174b 100644
--- a/navigation/navigation-fragment/src/androidTest/java/androidx/navigation/fragment/FragmentNavigatorDestinationBuilderTest.kt
+++ b/navigation/navigation-fragment/src/androidTest/java/androidx/navigation/fragment/FragmentNavigatorDestinationBuilderTest.kt
@@ -37,6 +37,7 @@
val activityRule = androidx.test.rule.ActivityTestRule<TestActivity>(TestActivity::class.java)
private val fragmentManager get() = activityRule.activity.supportFragmentManager
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test fun fragment() {
val navHostFragment = NavHostFragment()
@@ -57,6 +58,7 @@
)
}
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test fun fragmentWithBody() {
val navHostFragment = NavHostFragment()
diff --git a/navigation/navigation-fragment/src/androidTest/java/androidx/navigation/fragment/NavGraphViewModelLazyTest.kt b/navigation/navigation-fragment/src/androidTest/java/androidx/navigation/fragment/NavGraphViewModelLazyTest.kt
index f3c50e7..73b3b9bf 100644
--- a/navigation/navigation-fragment/src/androidTest/java/androidx/navigation/fragment/NavGraphViewModelLazyTest.kt
+++ b/navigation/navigation-fragment/src/androidTest/java/androidx/navigation/fragment/NavGraphViewModelLazyTest.kt
@@ -56,6 +56,7 @@
navigatorProvider += TestNavigator()
}
+ @Suppress("DEPRECATION")
@Test
fun vmInitialization() {
val scenario = launchFragmentInContainer<TestVMFragment>()
diff --git a/navigation/navigation-fragment/src/main/java/androidx/navigation/fragment/DialogFragmentNavigatorDestinationBuilder.kt b/navigation/navigation-fragment/src/main/java/androidx/navigation/fragment/DialogFragmentNavigatorDestinationBuilder.kt
index 465cf75..cf58061 100644
--- a/navigation/navigation-fragment/src/main/java/androidx/navigation/fragment/DialogFragmentNavigatorDestinationBuilder.kt
+++ b/navigation/navigation-fragment/src/main/java/androidx/navigation/fragment/DialogFragmentNavigatorDestinationBuilder.kt
@@ -27,6 +27,11 @@
/**
* Construct a new [DialogFragmentNavigator.Destination]
*/
+@Suppress("Deprecation")
+@Deprecated(
+ "Use routes to create your DialogFragmentDestination instead",
+ ReplaceWith("dialog<F>(route = id.toString())")
+)
public inline fun <reified F : DialogFragment> NavGraphBuilder.dialog(
@IdRes id: Int
): Unit = dialog<F>(id) {}
@@ -34,6 +39,11 @@
/**
* Construct a new [DialogFragmentNavigator.Destination]
*/
+@Suppress("Deprecation")
+@Deprecated(
+ "Use routes to create your DialogFragmentDestination instead",
+ ReplaceWith("dialog<F>(route = id.toString()) { builder.invoke() }")
+)
public inline fun <reified F : DialogFragment> NavGraphBuilder.dialog(
@IdRes id: Int,
builder: DialogFragmentNavigatorDestinationBuilder.() -> Unit
@@ -44,16 +54,59 @@
F::class
).apply(builder)
)
+/**
+ * Construct a new [DialogFragmentNavigator.Destination]
+ */
+public inline fun <reified F : DialogFragment> NavGraphBuilder.dialog(
+ route: String
+): Unit = dialog<F>(route) {}
+
+/**
+ * Construct a new [DialogFragmentNavigator.Destination]
+ */
+public inline fun <reified F : DialogFragment> NavGraphBuilder.dialog(
+ route: String,
+ builder: DialogFragmentNavigatorDestinationBuilder.() -> Unit
+): Unit = destination(
+ DialogFragmentNavigatorDestinationBuilder(
+ provider[DialogFragmentNavigator::class],
+ route,
+ F::class
+ ).apply(builder)
+)
/**
* DSL for constructing a new [DialogFragmentNavigator.Destination]
*/
@NavDestinationDsl
-public class DialogFragmentNavigatorDestinationBuilder(
- navigator: DialogFragmentNavigator,
- @IdRes id: Int,
- private val fragmentClass: KClass<out DialogFragment>
-) : NavDestinationBuilder<DialogFragmentNavigator.Destination>(navigator, id) {
+public class DialogFragmentNavigatorDestinationBuilder :
+ NavDestinationBuilder<DialogFragmentNavigator.Destination> {
+
+ private var fragmentClass: KClass<out DialogFragment>
+
+ @Suppress("Deprecation")
+ @Deprecated(
+ "Use routes to build your DialogFragmentNavigatorDestination instead",
+ ReplaceWith(
+ "DialogFragmentNavigatorDestinationBuilder(navigator, route = id.toString(), " +
+ "fragmentClass) "
+ )
+ )
+ public constructor(
+ navigator: DialogFragmentNavigator,
+ @IdRes id: Int,
+ fragmentClass: KClass<out DialogFragment>
+ ) : super(navigator, id) {
+ this.fragmentClass = fragmentClass
+ }
+
+ public constructor(
+ navigator: DialogFragmentNavigator,
+ route: String,
+ fragmentClass: KClass<out DialogFragment>
+ ) : super(navigator, route) {
+ this.fragmentClass = fragmentClass
+ }
override fun build(): DialogFragmentNavigator.Destination =
super.build().also { destination ->
diff --git a/navigation/navigation-fragment/src/main/java/androidx/navigation/fragment/FragmentNavigatorDestinationBuilder.kt b/navigation/navigation-fragment/src/main/java/androidx/navigation/fragment/FragmentNavigatorDestinationBuilder.kt
index 60eda99..e0060d9 100644
--- a/navigation/navigation-fragment/src/main/java/androidx/navigation/fragment/FragmentNavigatorDestinationBuilder.kt
+++ b/navigation/navigation-fragment/src/main/java/androidx/navigation/fragment/FragmentNavigatorDestinationBuilder.kt
@@ -27,6 +27,11 @@
/**
* Construct a new [FragmentNavigator.Destination]
*/
+@Suppress("Deprecation")
+@Deprecated(
+ "Use routes to create your FragmentDestination instead",
+ ReplaceWith("fragment<F>(route = id.toString())")
+)
public inline fun <reified F : Fragment> NavGraphBuilder.fragment(
@IdRes id: Int
): Unit = fragment<F>(id) {}
@@ -34,6 +39,11 @@
/**
* Construct a new [FragmentNavigator.Destination]
*/
+@Suppress("Deprecation")
+@Deprecated(
+ "Use routes to create your FragmentDestination instead",
+ ReplaceWith("fragment<F>(route = id.toString()) { builder.invoke() }")
+)
public inline fun <reified F : Fragment> NavGraphBuilder.fragment(
@IdRes id: Int,
builder: FragmentNavigatorDestinationBuilder.() -> Unit
@@ -75,6 +85,13 @@
private var fragmentClass: KClass<out Fragment>
+ @Suppress("Deprecation")
+ @Deprecated(
+ "Use routes to build your FragmentNavigatorDestination instead",
+ ReplaceWith(
+ "FragmentNavigatorDestinationBuilder(navigator, route = id.toString(), fragmentClass) "
+ )
+ )
public constructor(
navigator: FragmentNavigator,
@IdRes id: Int,
diff --git a/navigation/navigation-runtime/api/current.txt b/navigation/navigation-runtime/api/current.txt
index 03eef05..33808c0 100644
--- a/navigation/navigation-runtime/api/current.txt
+++ b/navigation/navigation-runtime/api/current.txt
@@ -59,7 +59,7 @@
}
@androidx.navigation.NavDestinationDsl public final class ActivityNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.ActivityNavigator.Destination> {
- ctor public ActivityNavigatorDestinationBuilder(androidx.navigation.ActivityNavigator navigator, @IdRes int id);
+ ctor @Deprecated public ActivityNavigatorDestinationBuilder(androidx.navigation.ActivityNavigator navigator, @IdRes int id);
ctor public ActivityNavigatorDestinationBuilder(androidx.navigation.ActivityNavigator navigator, String route);
method public androidx.navigation.ActivityNavigator.Destination build();
method public String? getAction();
@@ -80,7 +80,7 @@
}
public final class ActivityNavigatorDestinationBuilderKt {
- method public static inline void activity(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.ActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline void activity(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.ActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
method public static inline void activity(androidx.navigation.NavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.ActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
}
@@ -152,7 +152,7 @@
}
public final class NavControllerKt {
- method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
}
@@ -189,7 +189,7 @@
}
public final class NavHostKt {
- method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
}
diff --git a/navigation/navigation-runtime/api/public_plus_experimental_current.txt b/navigation/navigation-runtime/api/public_plus_experimental_current.txt
index f98c73a..1a5eb2b 100644
--- a/navigation/navigation-runtime/api/public_plus_experimental_current.txt
+++ b/navigation/navigation-runtime/api/public_plus_experimental_current.txt
@@ -61,7 +61,7 @@
}
@androidx.navigation.NavDestinationDsl public final class ActivityNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.ActivityNavigator.Destination> {
- ctor public ActivityNavigatorDestinationBuilder(androidx.navigation.ActivityNavigator navigator, @IdRes int id);
+ ctor @Deprecated public ActivityNavigatorDestinationBuilder(androidx.navigation.ActivityNavigator navigator, @IdRes int id);
ctor public ActivityNavigatorDestinationBuilder(androidx.navigation.ActivityNavigator navigator, String route);
method public androidx.navigation.ActivityNavigator.Destination build();
method public String? getAction();
@@ -82,7 +82,7 @@
}
public final class ActivityNavigatorDestinationBuilderKt {
- method public static inline void activity(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.ActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline void activity(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.ActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
method public static inline void activity(androidx.navigation.NavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.ActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
}
@@ -166,7 +166,7 @@
}
public final class NavControllerKt {
- method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
}
@@ -203,7 +203,7 @@
}
public final class NavHostKt {
- method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
}
diff --git a/navigation/navigation-runtime/api/restricted_current.txt b/navigation/navigation-runtime/api/restricted_current.txt
index 03eef05..33808c0 100644
--- a/navigation/navigation-runtime/api/restricted_current.txt
+++ b/navigation/navigation-runtime/api/restricted_current.txt
@@ -59,7 +59,7 @@
}
@androidx.navigation.NavDestinationDsl public final class ActivityNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.ActivityNavigator.Destination> {
- ctor public ActivityNavigatorDestinationBuilder(androidx.navigation.ActivityNavigator navigator, @IdRes int id);
+ ctor @Deprecated public ActivityNavigatorDestinationBuilder(androidx.navigation.ActivityNavigator navigator, @IdRes int id);
ctor public ActivityNavigatorDestinationBuilder(androidx.navigation.ActivityNavigator navigator, String route);
method public androidx.navigation.ActivityNavigator.Destination build();
method public String? getAction();
@@ -80,7 +80,7 @@
}
public final class ActivityNavigatorDestinationBuilderKt {
- method public static inline void activity(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.ActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline void activity(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.ActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
method public static inline void activity(androidx.navigation.NavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.ActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
}
@@ -152,7 +152,7 @@
}
public final class NavControllerKt {
- method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
}
@@ -189,7 +189,7 @@
}
public final class NavHostKt {
- method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+ method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
}
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ActivityNavigatorDestinationBuilderTest.kt b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ActivityNavigatorDestinationBuilderTest.kt
index 53c3aea..6e1ae7a 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ActivityNavigatorDestinationBuilderTest.kt
+++ b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ActivityNavigatorDestinationBuilderTest.kt
@@ -32,6 +32,7 @@
private val navController =
NavController(ApplicationProvider.getApplicationContext() as android.content.Context)
+ @Suppress("DEPRECATION")
@Test
fun activity() {
val graph = navController.createGraph(startDestination = DESTINATION_ID) {
@@ -50,6 +51,7 @@
)
}
+ @Suppress("DEPRECATION")
@Test
fun activityPackage() {
val graph = navController.createGraph(startDestination = DESTINATION_ID) {
@@ -65,6 +67,7 @@
.isEqualTo(PACKAGE_NAME)
}
+ @Suppress("DEPRECATION")
@Test
fun activityClass() {
val graph = navController.createGraph(startDestination = DESTINATION_ID) {
@@ -83,6 +86,7 @@
)
}
+ @Suppress("DEPRECATION")
@Test
fun action() {
val graph = navController.createGraph(startDestination = DESTINATION_ID) {
@@ -101,6 +105,7 @@
)
}
+ @Suppress("DEPRECATION")
@Test
fun data() {
val graph = navController.createGraph(startDestination = DESTINATION_ID) {
@@ -119,6 +124,7 @@
)
}
+ @Suppress("DEPRECATION")
@Test
fun dataPattern() {
val graph = navController.createGraph(startDestination = DESTINATION_ID) {
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavBackStackEntryLifecycleTest.kt b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavBackStackEntryLifecycleTest.kt
index 1c9b115..f276f45 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavBackStackEntryLifecycleTest.kt
+++ b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavBackStackEntryLifecycleTest.kt
@@ -43,6 +43,7 @@
/**
* Test that navigating between siblings correctly stops the previous sibling.
*/
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testLifecycle() {
@@ -105,6 +106,7 @@
* Test that navigating from a sibling to a FloatingWindow sibling leaves the previous
* destination started.
*/
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testLifecycleWithDialog() {
@@ -167,6 +169,7 @@
* Test that navigating from within a nested navigation graph to one of the graph's
* siblings correctly stops both the previous destination and its graph.
*/
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testLifecycleNested() {
@@ -232,6 +235,7 @@
* FloatingWindow siblings correctly moves both the previous destination and its graph to
* started.
*/
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testLifecycleNestedWithDialog() {
@@ -299,6 +303,7 @@
* Test that navigating from within a nested navigation graph to one of the graph's
* siblings correctly stops both the previous destination and its graph.
*/
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testLifecycleNestedOrdering() {
@@ -394,6 +399,7 @@
* FloatingWindow siblings correctly moves both the previous destination and its graph to
* started.
*/
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testLifecycleNestedOrderingWithDialog() {
@@ -476,6 +482,7 @@
* Test that popping the last destination in a graph while navigating to a new
* destination in that graph keeps the graph around
*/
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testLifecycleReplaceLastDestination() {
@@ -533,6 +540,7 @@
* Test that popping the last destination in a graph while navigating correctly
* cleans up the previous navigation graph
*/
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testLifecycleOrphanedGraph() {
@@ -590,6 +598,7 @@
* Test that navigating to a new instance of a graph leaves the previous instance in its
* current state.
*/
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testLifecycleNestedRepeated() {
@@ -663,6 +672,7 @@
* Test that navigating to a new instance of a graph back to back with its previous
* instance creates a brand new graph instance
*/
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testLifecycleNestedRepeatedBackToBack() {
@@ -722,6 +732,7 @@
* last destination from the previous instance of the graph correctly cleans up
* the orphaned graph and creates a new graph instance.
*/
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testLifecycleNestedRepeatedBackToBackWithOrphanedGraph() {
@@ -789,6 +800,7 @@
* Test that navigating to a new instance of a graph via a deep link to a FloatingWindow
* destination leaves the previous instance in its current state.
*/
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testLifecycleNestedRepeatedWithDialog() {
@@ -861,6 +873,7 @@
.isEqualTo(Lifecycle.State.RESUMED)
}
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testLifecycleToDestroyedWhenInitialized() {
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavBackStackEntryTest.kt b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavBackStackEntryTest.kt
index bcd0b19..b061ee6 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavBackStackEntryTest.kt
+++ b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavBackStackEntryTest.kt
@@ -42,6 +42,7 @@
@RunWith(AndroidJUnit4::class)
class NavBackStackEntryTest {
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testGetViewModelStoreOwner() {
@@ -61,6 +62,7 @@
assertThat(store).isNotNull()
}
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testGetViewModelStoreOwnerAndroidViewModel() {
@@ -81,6 +83,7 @@
assertThat(viewModel).isNotNull()
}
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testGetViewModelStoreOwnerSavedStateViewModel() {
@@ -116,6 +119,7 @@
assertThat(restoredState).isEqualTo("test")
}
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testSaveRestoreGetViewModelStoreOwner() {
@@ -165,6 +169,7 @@
}
}
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testGetViewModelStoreOwnerSameGraph() {
@@ -188,6 +193,7 @@
assertThat(sameGraphOwner.viewModelStore).isSameInstanceAs(viewStore)
}
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testGetSavedStateHandleRestored() {
@@ -278,6 +284,7 @@
}
}
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testOnClearedWhenHostCleared() {
@@ -304,6 +311,7 @@
.isTrue()
}
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testOnClearedWhenPopped() {
@@ -338,6 +346,7 @@
.isTrue()
}
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testOnClearedWhenHostClearedAfterSaveState() {
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt
index d3f9e3a..c2e4857 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt
+++ b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt
@@ -173,6 +173,7 @@
navController.setGraph(R.navigation.nav_start_destination, args)
}
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testStartDestinationWithArgsProgrammatic() {
@@ -238,6 +239,7 @@
}
}
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testSetViewModelStoreOwnerAfterGraphSet() {
@@ -260,6 +262,7 @@
}
}
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testSetSameViewModelStoreOwnerAfterGraphSet() {
@@ -1977,6 +1980,7 @@
navController.navigate(R.id.second_test)
}
+ @Suppress("DEPRECATION")
@Test
fun createGraph() {
val graph = navController.createGraph(startDestination = DESTINATION_ID) {
@@ -1988,7 +1992,7 @@
@UiThreadTest
@Test
- @Suppress("EXPERIMENTAL_API_USAGE")
+ @Suppress("DEPRECATION", "EXPERIMENTAL_API_USAGE")
fun currentBackStackEntryFlow() = runBlocking {
navController.graph = navController.createGraph(startDestination = 1) {
test(1)
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavDeepLinkBuilderTest.kt b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavDeepLinkBuilderTest.kt
index 951a236..0b21a08 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavDeepLinkBuilderTest.kt
+++ b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavDeepLinkBuilderTest.kt
@@ -105,6 +105,7 @@
assertEquals("Expected one Intent", 1, taskStackBuilder.intentCount)
}
+ @Suppress("DEPRECATION")
@Test
fun fromContextSetGraphProgrammatic() {
val deepLinkBuilder = NavDeepLinkBuilder(targetContext)
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavHostTest.kt b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavHostTest.kt
index 37ecb1e..5ef8394 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavHostTest.kt
+++ b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavHostTest.kt
@@ -35,6 +35,7 @@
get() = [email protected]
}
+ @Suppress("DEPRECATION")
@Test
fun createGraph() {
val graph = navHost.createGraph(startDestination = DESTINATION_ID) {
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/FloatingTestNavigator.kt b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/FloatingTestNavigator.kt
index 689f7c6..94ea1b6 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/FloatingTestNavigator.kt
+++ b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/FloatingTestNavigator.kt
@@ -59,6 +59,7 @@
/**
* DSL for constructing a new [TestNavigator.Destination] from a [FloatingTestNavigator].
*/
+@Suppress("DEPRECATION")
@NavDestinationDsl
class FloatingTestNavigatorDestinationBuilder(
navigator: FloatingTestNavigator,
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigatorDestinationBuilder.kt b/navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigatorDestinationBuilder.kt
index 1089b72..c0cc861 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigatorDestinationBuilder.kt
+++ b/navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigatorDestinationBuilder.kt
@@ -28,6 +28,11 @@
/**
* Construct a new [ActivityNavigator.Destination]
*/
+@Suppress("Deprecation")
+@Deprecated(
+ "Use routes to build your ActivityDestination instead",
+ ReplaceWith("activity(route = id.toString()) { builder.invoke() }")
+)
public inline fun NavGraphBuilder.activity(
@IdRes id: Int,
builder: ActivityNavigatorDestinationBuilder.() -> Unit
@@ -59,6 +64,11 @@
NavDestinationBuilder<ActivityNavigator.Destination> {
private var context: Context
+ @Suppress("Deprecation")
+ @Deprecated(
+ "Use routes to create your ActivityNavigatorDestinationBuilder instead",
+ ReplaceWith("ActivityNavigatorDestinationBuilder(navigator, route = id.toString())")
+ )
public constructor(navigator: ActivityNavigator, @IdRes id: Int) : super(navigator, id) {
context = navigator.context
}
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt b/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt
index 24b4764..fc4bde0 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt
+++ b/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt
@@ -1949,6 +1949,14 @@
* @param startDestination the route for the start destination
* @param builder the builder used to construct the graph
*/
+@Suppress("Deprecation")
+@Deprecated(
+ "Use routes to create your NavGraph instead",
+ ReplaceWith(
+ "createGraph(startDestination = startDestination.toString(), route = id.toString()) " +
+ "{ builder.invoke() }"
+ )
+)
public inline fun NavController.createGraph(
@IdRes id: Int = 0,
@IdRes startDestination: Int,
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavHost.kt b/navigation/navigation-runtime/src/main/java/androidx/navigation/NavHost.kt
index bb6b996..f3e159b 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavHost.kt
+++ b/navigation/navigation-runtime/src/main/java/androidx/navigation/NavHost.kt
@@ -53,6 +53,14 @@
/**
* Construct a new [NavGraph]
*/
+@Suppress("Deprecation")
+@Deprecated(
+ "Use routes to create your NavGraph instead",
+ ReplaceWith(
+ "createGraph(startDestination = startDestination.toString(), route = id.toString()) " +
+ "{ builder.invoke() }"
+ )
+)
public inline fun NavHost.createGraph(
@IdRes id: Int = 0,
@IdRes startDestination: Int,
diff --git a/navigation/navigation-testing/src/androidTest/java/androidx/navigation/testing/TestNavHostControllerTest.kt b/navigation/navigation-testing/src/androidTest/java/androidx/navigation/testing/TestNavHostControllerTest.kt
index 2612a35..76aa369 100644
--- a/navigation/navigation-testing/src/androidTest/java/androidx/navigation/testing/TestNavHostControllerTest.kt
+++ b/navigation/navigation-testing/src/androidTest/java/androidx/navigation/testing/TestNavHostControllerTest.kt
@@ -76,6 +76,7 @@
assertThat(backStack[1].destination).isInstanceOf(TestNavigator.Destination::class.java)
}
+ @Suppress("DEPRECATION")
@UiThreadTest
@Test
fun testDsl() {
diff --git a/navigation/navigation-ui/src/androidTest/java/androidx/navigation/ui/AppBarConfigurationTest.kt b/navigation/navigation-ui/src/androidTest/java/androidx/navigation/ui/AppBarConfigurationTest.kt
index 1f393b1..c2576ae 100644
--- a/navigation/navigation-ui/src/androidTest/java/androidx/navigation/ui/AppBarConfigurationTest.kt
+++ b/navigation/navigation-ui/src/androidTest/java/androidx/navigation/ui/AppBarConfigurationTest.kt
@@ -42,6 +42,7 @@
context = InstrumentationRegistry.getInstrumentation().targetContext
}
+ @Suppress("DEPRECATION")
@Test
fun testTopLevelFromGraph() {
val navGraph = NavController(context).apply {
diff --git a/playground-common/playground.properties b/playground-common/playground.properties
index 3e7dfa5..945474e 100644
--- a/playground-common/playground.properties
+++ b/playground-common/playground.properties
@@ -26,7 +26,7 @@
kotlin.code.style=official
# Disable docs
androidx.enableDocumentation=false
-androidx.playground.snapshotBuildId=7378367
+androidx.playground.snapshotBuildId=7396899
androidx.playground.metalavaBuildId=7255182
androidx.playground.dokkaBuildId=7299536
androidx.studio.type=playground
diff --git a/profileinstaller/integration-tests/init-macrobenchmark-target/README.md b/profileinstaller/integration-tests/init-macrobenchmark-target/README.md
new file mode 100644
index 0000000..1bed279
--- /dev/null
+++ b/profileinstaller/integration-tests/init-macrobenchmark-target/README.md
@@ -0,0 +1 @@
+Benchmark startup overhead introduced by profileinstaller's use of startup library
\ No newline at end of file
diff --git a/profileinstaller/integration-tests/init-macrobenchmark-target/build.gradle b/profileinstaller/integration-tests/init-macrobenchmark-target/build.gradle
new file mode 100644
index 0000000..411e5df
--- /dev/null
+++ b/profileinstaller/integration-tests/init-macrobenchmark-target/build.gradle
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import static androidx.build.dependencies.DependenciesKt.*
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.application")
+ id("kotlin-android")
+}
+
+android {
+ buildTypes {
+ release {
+ minifyEnabled true
+ shrinkResources true
+ proguardFiles getDefaultProguardFile("proguard-android-optimize.txt")
+ }
+ }
+}
+
+dependencies {
+ implementation(KOTLIN_STDLIB)
+ implementation(project(":profileinstaller:profileinstaller"))
+}
diff --git a/profileinstaller/integration-tests/init-macrobenchmark-target/src/main/AndroidManifest.xml b/profileinstaller/integration-tests/init-macrobenchmark-target/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..f2fbc15
--- /dev/null
+++ b/profileinstaller/integration-tests/init-macrobenchmark-target/src/main/AndroidManifest.xml
@@ -0,0 +1,48 @@
+<!--
+ ~ Copyright 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="androidx.profileinstaller.integration.macrobenchmark.target">
+
+ <application
+ android:label="Profileinstaller Macrobenchmark Target"
+ android:allowBackup="false"
+ android:supportsRtl="true"
+ tools:ignore="MissingApplicationIcon">
+
+ <!-- Profileable to enable macrobenchmark profiling -->
+ <!--suppress AndroidElementNotAllowed -->
+ <profileable android:shell="true"/>
+
+ <!--
+ Activities need to be exported so the macrobenchmark can discover them
+ under the new package visibility changes for Android 11.
+ -->
+ <activity
+ android:name=".SimpleTextActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="profileinstaller.init.macrobenchmark.TARGET" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/profileinstaller/integration-tests/init-macrobenchmark-target/src/main/java/androidx/profileinstaller/integration/macrobenchmark/target/SimpleTextActivity.kt b/profileinstaller/integration-tests/init-macrobenchmark-target/src/main/java/androidx/profileinstaller/integration/macrobenchmark/target/SimpleTextActivity.kt
new file mode 100644
index 0000000..c19d537
--- /dev/null
+++ b/profileinstaller/integration-tests/init-macrobenchmark-target/src/main/java/androidx/profileinstaller/integration/macrobenchmark/target/SimpleTextActivity.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.profileinstaller.integration.macrobenchmark.target
+
+import android.app.Activity
+import android.os.Bundle
+import android.widget.TextView
+
+class SimpleTextActivity : Activity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+
+ val notice = findViewById<TextView>(R.id.txtNotice)
+ notice.setText(R.string.app_notice)
+ }
+}
diff --git a/profileinstaller/integration-tests/init-macrobenchmark-target/src/main/res/layout/activity_main.xml b/profileinstaller/integration-tests/init-macrobenchmark-target/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..42146bc
--- /dev/null
+++ b/profileinstaller/integration-tests/init-macrobenchmark-target/src/main/res/layout/activity_main.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:id="@+id/txtNotice"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="50sp"
+ tools:text="profileinstaller benchmark️" />
+
+</FrameLayout>
diff --git a/profileinstaller/integration-tests/init-macrobenchmark-target/src/main/res/values/donottranslate-strings.xml b/profileinstaller/integration-tests/init-macrobenchmark-target/src/main/res/values/donottranslate-strings.xml
new file mode 100644
index 0000000..c2c1ed3
--- /dev/null
+++ b/profileinstaller/integration-tests/init-macrobenchmark-target/src/main/res/values/donottranslate-strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <string name="app_notice">profileinstaller macrobenchmark app.</string>
+</resources>
diff --git a/profileinstaller/integration-tests/init-macrobenchmark/build.gradle b/profileinstaller/integration-tests/init-macrobenchmark/build.gradle
new file mode 100644
index 0000000..33e00c2
--- /dev/null
+++ b/profileinstaller/integration-tests/init-macrobenchmark/build.gradle
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.Publish
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.library")
+ id("kotlin-android")
+}
+
+android {
+ defaultConfig {
+ minSdkVersion 28
+ }
+}
+
+dependencies {
+ androidTestImplementation(project(":profileinstaller:profileinstaller"))
+ androidTestImplementation(project(":benchmark:benchmark-macro-junit4"))
+ androidTestImplementation(project(":internal-testutils-macrobenchmark"))
+ androidTestImplementation(ANDROIDX_TEST_RULES)
+ androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
+ androidTestImplementation(ANDROIDX_TEST_CORE)
+ androidTestImplementation(ANDROIDX_TEST_RUNNER)
+}
+
+def installReleaseTarget = tasks.getByPath(
+ ":profileinstaller:integration-tests:init-macrobenchmark-target:installRelease"
+)
+
+// Define a task dependency so the app is installed before we run macro benchmarks.
+tasks.getByPath(":profileinstaller:integration-tests:init-macrobenchmark:connectedCheck")
+ .dependsOn(installReleaseTarget)
diff --git a/profileinstaller/integration-tests/init-macrobenchmark/src/androidTest/AndroidManifest.xml b/profileinstaller/integration-tests/init-macrobenchmark/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..c1bd315
--- /dev/null
+++ b/profileinstaller/integration-tests/init-macrobenchmark/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<manifest package="androidx.profileinstaller.integration.macrobenchmark.test"/>
diff --git a/profileinstaller/integration-tests/init-macrobenchmark/src/androidTest/java/androidx/profileinstaller/integration/macrobenchmark/ProfileinstallerStartupBenchmark.kt b/profileinstaller/integration-tests/init-macrobenchmark/src/androidTest/java/androidx/profileinstaller/integration/macrobenchmark/ProfileinstallerStartupBenchmark.kt
new file mode 100644
index 0000000..83d0a926
--- /dev/null
+++ b/profileinstaller/integration-tests/init-macrobenchmark/src/androidTest/java/androidx/profileinstaller/integration/macrobenchmark/ProfileinstallerStartupBenchmark.kt
@@ -0,0 +1,53 @@
+/*
+ * 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.profileinstaller.integration.macrobenchmark
+
+import androidx.benchmark.macro.CompilationMode
+import androidx.benchmark.macro.StartupMode
+import androidx.benchmark.macro.junit4.MacrobenchmarkRule
+import androidx.test.filters.LargeTest
+import androidx.testutils.createStartupCompilationParams
+import androidx.testutils.measureStartup
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@LargeTest
+@RunWith(Parameterized::class)
+class ProfileinstallerStartupBenchmark(
+ private val startupMode: StartupMode,
+ private val compilationMode: CompilationMode
+) {
+ @get:Rule
+ val benchmarkRule = MacrobenchmarkRule()
+
+ @Test
+ fun startup() = benchmarkRule.measureStartup(
+ compilationMode = compilationMode,
+ startupMode = startupMode,
+ packageName = "androidx.profileinstaller.integration.macrobenchmark.target"
+ ) {
+ action = "profileinstaller.init.macrobenchmark.TARGET"
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "startup={0},compilation={1}")
+ @JvmStatic
+ fun parameters() = createStartupCompilationParams()
+ }
+}
\ No newline at end of file
diff --git a/profileinstaller/integration-tests/init-macrobenchmark/src/main/AndroidManifest.xml b/profileinstaller/integration-tests/init-macrobenchmark/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..ccd5d59
--- /dev/null
+++ b/profileinstaller/integration-tests/init-macrobenchmark/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<manifest package="androidx.profileinstaller.integration.macrobenchmark" />
diff --git a/profileinstaller/profileinstaller/integration-tests/testapp/build.gradle b/profileinstaller/integration-tests/testapp/build.gradle
similarity index 100%
rename from profileinstaller/profileinstaller/integration-tests/testapp/build.gradle
rename to profileinstaller/integration-tests/testapp/build.gradle
diff --git a/profileinstaller/profileinstaller/integration-tests/testapp/cli/all_compose_profile.txt b/profileinstaller/integration-tests/testapp/cli/all_compose_profile.txt
similarity index 100%
rename from profileinstaller/profileinstaller/integration-tests/testapp/cli/all_compose_profile.txt
rename to profileinstaller/integration-tests/testapp/cli/all_compose_profile.txt
diff --git a/profileinstaller/profileinstaller/integration-tests/testapp/cli/build_bundle_launch.sh b/profileinstaller/integration-tests/testapp/cli/build_bundle_launch.sh
similarity index 91%
rename from profileinstaller/profileinstaller/integration-tests/testapp/cli/build_bundle_launch.sh
rename to profileinstaller/integration-tests/testapp/cli/build_bundle_launch.sh
index cfcb5dc..ad3ab2b 100755
--- a/profileinstaller/profileinstaller/integration-tests/testapp/cli/build_bundle_launch.sh
+++ b/profileinstaller/integration-tests/testapp/cli/build_bundle_launch.sh
@@ -19,20 +19,20 @@
SCRIPT=`realpath $0`
SCRIPT_DIR=`dirname $SCRIPT`
-SUPPORT_DIR=$SCRIPT_DIR/../../../../../
+SUPPORT_DIR=$SCRIPT_DIR/../../../../
TMP_DIR=`mktemp -d`
pushd $SUPPORT_DIR
echo "===START=== Rebuilding apk..."
ANDROIDX_PROJECTS=COMPOSE ./gradlew \
- :profileinstaller:profileinstaller:integration-tests:testapp:clean
+ :profileinstaller:integration-tests:testapp:clean
if [ $DEBUG = true ]; then
ANDROIDX_PROJECTS=COMPOSE ./gradlew \
- :profileinstaller:profileinstaller:integration-tests:testapp:assembleDebug
+ :profileinstaller:integration-tests:testapp:assembleDebug
else
ANDROIDX_PROJECTS=COMPOSE ./gradlew \
- :profileinstaller:profileinstaller:integration-tests:testapp:assembleRelease
+ :profileinstaller:integration-tests:testapp:assembleRelease
fi
echo "===/DONE=== Rebuilding apk..."
diff --git a/profileinstaller/profileinstaller/integration-tests/testapp/cli/instructions.md b/profileinstaller/integration-tests/testapp/cli/instructions.md
similarity index 100%
rename from profileinstaller/profileinstaller/integration-tests/testapp/cli/instructions.md
rename to profileinstaller/integration-tests/testapp/cli/instructions.md
diff --git a/profileinstaller/profileinstaller/integration-tests/testapp/cli/profgen-cli.jar b/profileinstaller/integration-tests/testapp/cli/profgen-cli.jar
similarity index 100%
rename from profileinstaller/profileinstaller/integration-tests/testapp/cli/profgen-cli.jar
rename to profileinstaller/integration-tests/testapp/cli/profgen-cli.jar
Binary files differ
diff --git a/profileinstaller/profileinstaller/integration-tests/testapp/cli/repackage.py b/profileinstaller/integration-tests/testapp/cli/repackage.py
similarity index 94%
rename from profileinstaller/profileinstaller/integration-tests/testapp/cli/repackage.py
rename to profileinstaller/integration-tests/testapp/cli/repackage.py
index 9a5db31..3b30a3f 100755
--- a/profileinstaller/profileinstaller/integration-tests/testapp/cli/repackage.py
+++ b/profileinstaller/integration-tests/testapp/cli/repackage.py
@@ -14,13 +14,13 @@
PATH_TO_APKSIGNER = 'apksigner'
SCRIPT_PATH = Path(__file__).parent.absolute()
-SUPPORT_PATH = (SCRIPT_PATH / Path("../../../../..")).resolve()
+SUPPORT_PATH = (SCRIPT_PATH / Path("../../../..")).resolve()
ROOT_DIR = (SUPPORT_PATH / Path("../..")).resolve()
BUILD_OUT_DIR = (Path(SUPPORT_PATH) / Path(
- "../../out/androidx/profileinstaller/profileinstaller/integration-tests/"
+ "../../out/androidx/profileinstaller/integration-tests/"
"testapp/build/outputs/apk/")).resolve()
MAPPING_OUT_PATH = (Path(SUPPORT_PATH) / Path(
- "../../out/androidx/profileinstaller/profileinstaller/integration-tests/"
+ "../../out/androidx/profileinstaller/integration-tests/"
"testapp/build/outputs/mapping/release/mapping.txt")).resolve()
APK_PREFIX = "testapp"
@@ -119,6 +119,8 @@
working_dir.mkdir()
working_apk = working_dir / Path("working.apk")
shutil.copyfile(apk_src, working_apk)
+ print(f"copying to {SUPPORT_PATH / Path('baseline.prof')}")
+ shutil.copyfile(profile, SUPPORT_PATH / Path("baseline.prof"))
with ZipFile(working_apk, 'a') as zip:
profile_destination = Path('assets/dexopt/') / Path(APK_PROFILE_FILE)
if str(profile_destination) in [it.filename for it in zip.infolist()]:
@@ -155,4 +157,4 @@
profile = profile_from(args.profile)
jar = jar_from(args.jar)
output_apk = output_apk_from(args.output)
- generate_apk(apk_src, profile, jar, output_apk, args.debug, args.apk_signer)
\ No newline at end of file
+ generate_apk(apk_src, profile, jar, output_apk, args.debug, args.apk_signer)
diff --git a/profileinstaller/profileinstaller/integration-tests/testapp/src/main/AndroidManifest.xml b/profileinstaller/integration-tests/testapp/src/main/AndroidManifest.xml
similarity index 100%
rename from profileinstaller/profileinstaller/integration-tests/testapp/src/main/AndroidManifest.xml
rename to profileinstaller/integration-tests/testapp/src/main/AndroidManifest.xml
diff --git a/profileinstaller/profileinstaller/integration-tests/testapp/src/main/java/androidx/profileinstaller/integration/testapp/MainActivity.kt b/profileinstaller/integration-tests/testapp/src/main/java/androidx/profileinstaller/integration/testapp/MainActivity.kt
similarity index 100%
rename from profileinstaller/profileinstaller/integration-tests/testapp/src/main/java/androidx/profileinstaller/integration/testapp/MainActivity.kt
rename to profileinstaller/integration-tests/testapp/src/main/java/androidx/profileinstaller/integration/testapp/MainActivity.kt
diff --git a/profileinstaller/profileinstaller/integration-tests/testapp/OWNERS b/profileinstaller/profileinstaller/integration-tests/testapp/OWNERS
deleted file mode 100644
index 42abc4e..0000000
--- a/profileinstaller/profileinstaller/integration-tests/testapp/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
[email protected]
[email protected]
diff --git a/room/OWNERS b/room/OWNERS
index 3ea2934..6d57c2e 100644
--- a/room/OWNERS
+++ b/room/OWNERS
@@ -1,5 +1,6 @@
[email protected]
[email protected]
[email protected]
[email protected]
-per-file settings.gradle = [email protected], [email protected]
+per-file settings.gradle = [email protected]
diff --git a/room/room-paging/api/current.txt b/room/room-paging/api/current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/room/room-paging/api/current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/room/room-paging/api/public_plus_experimental_current.txt b/room/room-paging/api/public_plus_experimental_current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/room/room-paging/api/public_plus_experimental_current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/room/room-paging/api/res-current.txt b/room/room-paging/api/res-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/room/room-paging/api/res-current.txt
diff --git a/room/room-paging/api/restricted_current.txt b/room/room-paging/api/restricted_current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/room/room-paging/api/restricted_current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/room/room-paging/build.gradle b/room/room-paging/build.gradle
new file mode 100644
index 0000000..e9645b8
--- /dev/null
+++ b/room/room-paging/build.gradle
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 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.
+ */
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryType
+import androidx.build.LibraryVersions
+import androidx.build.Publish
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.library")
+ id("org.jetbrains.kotlin.android")
+}
+
+dependencies {
+ api(KOTLIN_STDLIB)
+ // Add dependencies here
+}
+
+androidx {
+ name = "Room Paging"
+ type = LibraryType.PUBLISHED_LIBRARY
+ mavenGroup = LibraryGroups.ROOM
+ inceptionYear = "2021"
+ description = "Room Paging integration"
+ publish = Publish.NONE
+}
diff --git a/room/room-paging/src/androidTest/AndroidManifest.xml b/room/room-paging/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..50ba2eb
--- /dev/null
+++ b/room/room-paging/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="androidx.room.paging.test">
+
+</manifest>
diff --git a/room/room-paging/src/main/AndroidManifest.xml b/room/room-paging/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..fa18cd8
--- /dev/null
+++ b/room/room-paging/src/main/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="androidx.room.paging">
+
+</manifest>
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index 935a639..ba10801 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -504,7 +504,9 @@
includeProject(":preference:preference-ktx", "preference/preference-ktx", [BuildType.MAIN])
includeProject(":print:print", "print/print", [BuildType.MAIN])
includeProject(":profileinstaller:profileinstaller", "profileinstaller/profileinstaller", [BuildType.MAIN, BuildType.COMPOSE])
-includeProject(":profileinstaller:profileinstaller:integration-tests:testapp", "profileinstaller/profileinstaller/integration-tests/testapp", [BuildType.COMPOSE])
+includeProject(":profileinstaller:integration-tests:init-macrobenchmark", "profileinstaller/integration-tests/init-macrobenchmark", [BuildType.MAIN])
+includeProject(":profileinstaller:integration-tests:init-macrobenchmark-target", "profileinstaller/integration-tests/init-macrobenchmark-target", [BuildType.MAIN])
+includeProject(":profileinstaller:integration-tests:testapp", "profileinstaller/integration-tests/testapp", [BuildType.COMPOSE])
includeProject(":recommendation:recommendation", "recommendation/recommendation", [BuildType.MAIN])
includeProject(":recyclerview:recyclerview", "recyclerview/recyclerview", [BuildType.MAIN])
includeProject(":recyclerview:recyclerview-benchmark", "recyclerview/recyclerview-benchmark", [BuildType.MAIN])
@@ -527,6 +529,7 @@
includeProject(":room:room-guava", "room/guava", [BuildType.MAIN])
includeProject(":room:room-ktx", "room/ktx", [BuildType.MAIN])
includeProject(":room:room-migration", "room/migration", [BuildType.MAIN])
+includeProject(":room:room-paging", "room/room-paging", [BuildType.MAIN])
includeProject(":room:room-runtime", "room/runtime", [BuildType.MAIN])
includeProject(":room:room-rxjava2", "room/rxjava2", [BuildType.MAIN])
includeProject(":room:room-rxjava3", "room/rxjava3", [BuildType.MAIN])
diff --git a/testutils/testutils-navigation/src/androidTest/java/androidx/testutils/TestNavigatorDestinationBuilderTest.kt b/testutils/testutils-navigation/src/androidTest/java/androidx/testutils/TestNavigatorDestinationBuilderTest.kt
index fb2d187..20383a3 100644
--- a/testutils/testutils-navigation/src/androidTest/java/androidx/testutils/TestNavigatorDestinationBuilderTest.kt
+++ b/testutils/testutils-navigation/src/androidTest/java/androidx/testutils/TestNavigatorDestinationBuilderTest.kt
@@ -31,6 +31,7 @@
class TestNavigatorDestinationBuilderTest {
private val provider = TestNavigatorProvider()
+ @Suppress("DEPRECATION")
@Test
fun test() {
val graph = provider.navigation(startDestination = DESTINATION_ID) {
@@ -53,6 +54,7 @@
)
}
+ @Suppress("DEPRECATION")
@Test
fun testWithBody() {
val graph = provider.navigation(startDestination = DESTINATION_ID) {
diff --git a/testutils/testutils-navigation/src/main/java/androidx/testutils/TestNavigatorDestinationBuilder.kt b/testutils/testutils-navigation/src/main/java/androidx/testutils/TestNavigatorDestinationBuilder.kt
index f8b90e7..a9bcbad 100644
--- a/testutils/testutils-navigation/src/main/java/androidx/testutils/TestNavigatorDestinationBuilder.kt
+++ b/testutils/testutils-navigation/src/main/java/androidx/testutils/TestNavigatorDestinationBuilder.kt
@@ -37,6 +37,7 @@
/**
* Construct a new [TestNavigator.Destination]
*/
+@Suppress("DEPRECATION")
inline fun NavGraphBuilder.test(
@IdRes id: Int,
builder: TestNavigatorDestinationBuilder.() -> Unit
@@ -62,6 +63,7 @@
*/
@NavDestinationDsl
class TestNavigatorDestinationBuilder : NavDestinationBuilder<TestNavigator.Destination> {
+ @Suppress("DEPRECATION")
constructor(navigator: TestNavigator, @IdRes id: Int = 0) : super(navigator, id)
constructor(navigator: TestNavigator, route: String) : super(navigator, route)
}
diff --git a/versionedparcelable/versionedparcelable-compiler/build.gradle b/versionedparcelable/versionedparcelable-compiler/build.gradle
index 72cbdae..83f50b6 100644
--- a/versionedparcelable/versionedparcelable-compiler/build.gradle
+++ b/versionedparcelable/versionedparcelable-compiler/build.gradle
@@ -18,15 +18,13 @@
import androidx.build.LibraryType
import androidx.build.LibraryVersions
-import static androidx.build.dependencies.DependenciesKt.*
-
plugins {
id("AndroidXPlugin")
id("java-library")
}
dependencies {
- implementation(JAVAPOET)
+ implementation(libs.javapoet)
}
androidx {
diff --git a/versionedparcelable/versionedparcelable/build.gradle b/versionedparcelable/versionedparcelable/build.gradle
index 5ffba1b..b093782 100644
--- a/versionedparcelable/versionedparcelable/build.gradle
+++ b/versionedparcelable/versionedparcelable/build.gradle
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-import static androidx.build.dependencies.DependenciesKt.*
-
import androidx.build.LibraryGroups
import androidx.build.LibraryVersions
import androidx.build.Publish
@@ -29,12 +27,12 @@
api("androidx.annotation:annotation:1.2.0")
implementation("androidx.collection:collection:1.0.0")
- androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
- androidTestImplementation(ANDROIDX_TEST_CORE)
- androidTestImplementation(ANDROIDX_TEST_RUNNER)
- androidTestImplementation(MOCKITO_CORE, excludes.bytebuddy)
- androidTestImplementation(DEXMAKER_MOCKITO, excludes.bytebuddy)
- androidTestImplementation(TRUTH)
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.testCore)
+ androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.mockitoCore, excludes.bytebuddy)
+ androidTestImplementation(libs.dexmakerMockito, excludes.bytebuddy)
+ androidTestImplementation(libs.truth)
androidTestAnnotationProcessor project(":versionedparcelable:versionedparcelable-compiler")
}
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 addff08..48a160f 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
@@ -19,6 +19,7 @@
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CornerSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
@@ -37,6 +38,7 @@
import androidx.compose.ui.test.assertIsEnabled
import androidx.compose.ui.test.assertIsNotEnabled
import androidx.compose.ui.test.assertTopPositionInRootIsEqualTo
+import androidx.compose.ui.test.assertWidthIsEqualTo
import androidx.compose.ui.test.captureToImage
import androidx.compose.ui.test.getUnclippedBoundsInRoot
import androidx.compose.ui.test.junit4.ComposeContentTestRule
@@ -45,6 +47,7 @@
import androidx.compose.ui.test.onChildAt
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.onRoot
import androidx.compose.ui.test.performClick
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.Dp
@@ -254,6 +257,108 @@
.assertTopPositionInRootIsEqualTo((itemBounds.height - iconBounds.height) / 2)
}
+ @Test
+ fun icon_only_compact_chip_has_correct_default_width_and_height() {
+ val iconTag = "TestIcon"
+ val chipTag = "chip"
+ rule
+ .setContentWithThemeForSizeAssertions(useUnmergedTree = true) {
+ CompactChip(
+ onClick = {},
+ modifier = Modifier.testTag(chipTag),
+ icon = { CreateImage(iconTag) }
+ )
+ }
+
+ rule.onRoot().assertWidthIsEqualTo(52.dp).assertHeightIsEqualTo(32.dp)
+ }
+
+ @Test
+ fun label_only_compact_chip_has_correct_default_height() {
+ val chipTag = "chip"
+ rule
+ .setContentWithThemeForSizeAssertions(useUnmergedTree = true) {
+ CompactChip(
+ onClick = {},
+ modifier = Modifier.testTag(chipTag),
+ label = { Text("Test") }
+ )
+ }
+
+ rule.onRoot().assertHeightIsEqualTo(32.dp)
+ }
+
+ @Test
+ fun no_content_compact_chip_has_correct_default_width_and_height() {
+ val chipTag = "chip"
+ rule
+ .setContentWithThemeForSizeAssertions(useUnmergedTree = true) {
+ CompactChip(
+ onClick = {},
+ modifier = Modifier.testTag(chipTag),
+ )
+ }
+
+ rule.onRoot().assertWidthIsEqualTo(52.dp).assertHeightIsEqualTo(32.dp)
+ }
+
+ @Test
+ fun icon_only_compact_chip_can_have_width_overridden() {
+ val iconTag = "TestIcon"
+ val chipTag = "chip"
+ rule
+ .setContentWithThemeForSizeAssertions(useUnmergedTree = true) {
+ CompactChip(
+ onClick = {},
+ modifier = Modifier.testTag(chipTag).width(100.dp),
+ icon = { CreateImage(iconTag) }
+ )
+ }
+
+ rule.onRoot().assertWidthIsEqualTo(100.dp)
+ }
+
+ @Test
+ fun has_icon_in_correct_location_when_compact_chip() {
+ val iconTag = "TestIcon"
+ val chipTag = "chip"
+ rule
+ .setContentWithThemeForSizeAssertions(useUnmergedTree = true) {
+ CompactChip(
+ 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)
+ }
+
+ @Test
+ fun has_icon_in_correct_location_when_icon_only_chip() {
+ val iconTag = "TestIcon"
+ val chipTag = "chip"
+ rule
+ .setContentWithThemeForSizeAssertions(useUnmergedTree = true) {
+ CompactChip(
+ onClick = {},
+ modifier = Modifier.testTag(chipTag),
+ icon = { CreateImage(iconTag) }
+ )
+ }
+ 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(
@@ -281,7 +386,7 @@
@Test
fun three_slot_layout_gives_primary_enabled_colors() =
- verifyThreeSlotColors(
+ verifySlotColors(
TestChipColors.Primary,
ChipStatus.Enabled,
{ MaterialTheme.colors.primary },
@@ -291,6 +396,18 @@
)
@Test
+ fun compact_chip_gives_primary_enabled_colors() =
+ verifySlotColors(
+ TestChipColors.Primary,
+ ChipStatus.Enabled,
+ { MaterialTheme.colors.primary },
+ { MaterialTheme.colors.onPrimary },
+ { MaterialTheme.colors.onPrimary },
+ { MaterialTheme.colors.onPrimary },
+ compactChip = true
+ )
+
+ @Test
fun gives_primary_disabled_colors() =
verifyColors(
TestChipColors.Primary,
@@ -301,7 +418,7 @@
@Test
fun three_slot_layout_gives_primary_disabled_colors() =
- verifyThreeSlotColors(
+ verifySlotColors(
TestChipColors.Primary,
ChipStatus.Disabled,
{ MaterialTheme.colors.primary },
@@ -321,7 +438,7 @@
@Test
fun three_slot_layout_gives_secondary_enabled_colors() =
- verifyThreeSlotColors(
+ verifySlotColors(
TestChipColors.Secondary,
ChipStatus.Enabled,
{ MaterialTheme.colors.surface },
@@ -341,7 +458,7 @@
@Test
fun three_slot_layout_gives_secondary_disabled_colors() =
- verifyThreeSlotColors(
+ verifySlotColors(
TestChipColors.Secondary,
ChipStatus.Enabled,
{ MaterialTheme.colors.surface },
@@ -351,6 +468,18 @@
)
@Test
+ fun compact_chip_gives_secondary_disabled_colors() =
+ verifySlotColors(
+ TestChipColors.Secondary,
+ ChipStatus.Enabled,
+ { MaterialTheme.colors.surface },
+ { MaterialTheme.colors.onSurface },
+ { MaterialTheme.colors.onSurface },
+ { MaterialTheme.colors.onSurface },
+ compactChip = true
+ )
+
+ @Test
fun allows_custom_enabled_background_color_override() {
val overrideColor = Color.Yellow
rule.setContentWithTheme {
@@ -531,13 +660,14 @@
}
}
- private fun verifyThreeSlotColors(
+ private fun verifySlotColors(
testChipColors: TestChipColors,
status: ChipStatus,
backgroundColor: @Composable () -> Color,
contentColor: @Composable () -> Color,
secondaryContentColor: @Composable () -> Color,
- iconColor: @Composable () -> Color
+ iconColor: @Composable () -> Color,
+ compactChip: Boolean = false
) {
var expectedBackground = Color.Transparent
var expectedContent = Color.Transparent
@@ -559,28 +689,43 @@
.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 (compactChip) {
+ CompactChip(
+ onClick = {},
+ colors = testChipColors.chipColors(),
+ label = { actualContent = LocalContentColor.current },
+ icon = { actualIcon = LocalContentColor.current },
+ enabled = status.enabled(),
+ modifier = Modifier.testTag("test-item")
+ )
+ } else {
+ 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)
+ if (! compactChip) {
+ assertEquals(expectedSecondaryContent, actualSecondaryContent)
+ }
assertEquals(expectedIcon, actualIcon)
} else {
assertEquals(expectedContent.copy(alpha = expectedAlpha), actualContent)
- assertEquals(
- expectedSecondaryContent.copy(alpha = expectedAlpha),
- actualSecondaryContent
- )
+ if (! compactChip) {
+ assertEquals(
+ expectedSecondaryContent.copy(alpha = expectedAlpha),
+ actualSecondaryContent
+ )
+ }
assertEquals(expectedIcon.copy(alpha = expectedAlpha), actualIcon)
}
diff --git a/wear/compose/material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/MaterialThemeTest.kt b/wear/compose/material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/MaterialThemeTest.kt
new file mode 100644
index 0000000..32c54d7
--- /dev/null
+++ b/wear/compose/material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/MaterialThemeTest.kt
@@ -0,0 +1,456 @@
+/*
+ * 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.layout.Column
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+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.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.sp
+import org.junit.Assert.assertEquals
+import org.junit.Rule
+import org.junit.Test
+
+class MaterialThemeTest {
+ @get:Rule
+ val rule = createComposeRule()
+
+ @Test
+ fun sets_default_color() {
+ var expectedBackground = Color.Transparent
+ rule.setContentWithTheme {
+ expectedBackground = MaterialTheme.colors.primary
+ Chip(
+ onClick = {},
+ colors = ChipDefaults.primaryChipColors(), // make sure using the primary color
+ label = { Text("Test") },
+ )
+ }
+
+ rule.onNodeWithText("Test")
+ .captureToImage()
+ .assertContainsColor(expectedBackground, 50.0f)
+ }
+
+ @Test
+ fun overrides_color_when_nested() {
+ // MaterialTheme in 'setWearContent' sets the primary background
+ // to cornflower blue. The nested theme should override that for primary.
+ rule.setContentWithTheme {
+ MaterialTheme(colors = MaterialTheme.colors.copy(primary = Color.Cyan)) {
+ Chip(
+ onClick = {},
+ colors = ChipDefaults.primaryChipColors(), // make sure using the primary color
+ label = { Text("Test") },
+ )
+ }
+ }
+
+ rule.onNodeWithText("Test")
+ .captureToImage()
+ .assertContainsColor(Color.Cyan, 50.0f)
+ }
+
+ @Test
+ fun can_be_overridden_by_component_color_explicitly() {
+ rule.setContentWithTheme {
+ Chip(
+ onClick = {},
+ colors = ChipDefaults.primaryChipColors(backgroundColor = Color.Yellow),
+ label = { Text("Test") },
+ )
+ }
+
+ rule.onNodeWithText("Test")
+ .captureToImage()
+ .assertContainsColor(Color.Yellow, 50.0f)
+ }
+
+ @Test
+ fun sets_default_textstyle() {
+ var expectedStyle: TextStyle? = null
+
+ rule.setContentWithTheme {
+ expectedStyle = MaterialTheme.typography.button
+ Chip(
+ onClick = {},
+ label = { Text("Test") },
+ )
+ }
+
+ assertTextStyleEquals(expectedStyle!!, rule.textStyleOf("Test"))
+ }
+
+ @Test
+ fun overrides_textstyle_when_nested() {
+ val override = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 16.sp,
+ letterSpacing = 0.sp
+ )
+ rule.setContentWithTheme {
+ MaterialTheme(
+ typography = MaterialTheme.typography
+ .copy(button = override)
+ ) {
+ Chip(
+ onClick = {},
+ label = { Text("Test") },
+ )
+ }
+ }
+
+ assertTextStyleEquals(override, rule.textStyleOf("Test"))
+ }
+
+ @Test
+ fun sets_primary_color_dynamically() =
+ verifyBackgroundColorIsDynamic(
+ initial = { MaterialTheme.colors.primary },
+ selectChipColors = { ChipDefaults.primaryChipColors() },
+ updateThemeColors = { colors, primary -> colors.copy(primary = primary) }
+ )
+
+ @Test
+ fun sets_primaryvariant_color_dynamically() =
+ verifyBackgroundColorIsDynamic(
+ initial = { MaterialTheme.colors.primaryVariant },
+ selectChipColors = {
+ ChipDefaults
+ .primaryChipColors(backgroundColor = MaterialTheme.colors.primaryVariant)
+ },
+ updateThemeColors =
+ { colors, primaryVariant -> colors.copy(primaryVariant = primaryVariant) }
+ )
+
+ @Test
+ fun sets_secondary_color_dynamically() =
+ verifyBackgroundColorIsDynamic(
+ initial = { MaterialTheme.colors.secondary },
+ selectChipColors = {
+ ChipDefaults
+ .secondaryChipColors(backgroundColor = MaterialTheme.colors.secondary)
+ },
+ updateThemeColors = { colors, secondary -> colors.copy(secondary = secondary) }
+ )
+
+ @Test
+ fun sets_secondaryvariant_color_dynamically() =
+ verifyBackgroundColorIsDynamic(
+ initial = { MaterialTheme.colors.secondaryVariant },
+ selectChipColors = {
+ ChipDefaults
+ .secondaryChipColors(backgroundColor = MaterialTheme.colors.secondaryVariant)
+ },
+ updateThemeColors =
+ { colors, secondaryVariant -> colors.copy(secondaryVariant = secondaryVariant) }
+ )
+
+ @Test
+ fun sets_error_color_dynamically() =
+ verifyBackgroundColorIsDynamic(
+ initial = { MaterialTheme.colors.error },
+ selectChipColors = {
+ ChipDefaults
+ .secondaryChipColors(backgroundColor = MaterialTheme.colors.error)
+ },
+ updateThemeColors = { colors, error -> colors.copy(error = error) }
+ )
+
+ @Test
+ fun sets_colors_dynamically() {
+ var initialBackground = Color.Transparent
+ val overrideBackground = Color.Cyan
+
+ rule.setContentWithTheme {
+ initialBackground = MaterialTheme.colors.primary
+ val colors = Colors()
+ val rememberedColors = remember { mutableStateOf(colors) }
+ MaterialTheme(colors = rememberedColors.value) {
+ Column {
+ Chip(
+ onClick = {},
+ colors = ChipDefaults.primaryChipColors(),
+ label = { Text("Test") },
+ )
+ Chip(
+ onClick = {
+ rememberedColors.value = colors.copy(primary = overrideBackground)
+ },
+ label = { },
+ modifier = Modifier.testTag("button")
+ )
+ }
+ }
+ }
+
+ rule.onNodeWithText("Test")
+ .captureToImage()
+ .assertContainsColor(initialBackground, 60.0f)
+ rule.onNodeWithTag("button")
+ .performClick()
+ rule.onNodeWithText("Test")
+ .captureToImage()
+ .assertContainsColor(overrideBackground, 60.0f)
+ }
+
+ @Test
+ fun sets_button_textstyle_dynamically() =
+ verifyTextStyleIsDynamic(
+ selectStyle = { it.button },
+ updateTextStyle = { typography, button -> typography.copy(button = button) }
+ )
+
+ @Test
+ fun sets_display1_textstyle_dynamically() =
+ verifyTextStyleIsDynamic(
+ selectStyle = { it.display1 },
+ updateTextStyle = { typography, display1 -> typography.copy(display1 = display1) }
+ )
+
+ @Test
+ fun sets_display2_textstyle_dynamically() =
+ verifyTextStyleIsDynamic(
+ selectStyle = { it.display2 },
+ updateTextStyle = { typography, display2 -> typography.copy(display2 = display2) }
+ )
+
+ @Test
+ fun sets_display3_textstyle_dynamically() =
+ verifyTextStyleIsDynamic(
+ selectStyle = { it.display3 },
+ updateTextStyle = { typography, display3 -> typography.copy(display3 = display3) }
+ )
+
+ @Test
+ fun sets_title1_textstyle_dynamically() =
+ verifyTextStyleIsDynamic(
+ selectStyle = { it.title1 },
+ updateTextStyle = { typography, title1 -> typography.copy(title1 = title1) }
+ )
+
+ @Test
+ fun sets_title2_textstyle_dynamically() =
+ verifyTextStyleIsDynamic(
+ selectStyle = { it.title2 },
+ updateTextStyle = { typography, title2 -> typography.copy(title2 = title2) }
+ )
+
+ @Test
+ fun sets_title3_textstyle_dynamically() =
+ verifyTextStyleIsDynamic(
+ selectStyle = { it.title3 },
+ updateTextStyle = { typography, title3 -> typography.copy(title3 = title3) }
+ )
+
+ @Test
+ fun sets_body1_textstyle_dynamically() =
+ verifyTextStyleIsDynamic(
+ selectStyle = { it.body1 },
+ updateTextStyle = { typography, body1 -> typography.copy(body1 = body1) }
+ )
+
+ @Test
+ fun sets_body2_textstyle_dynamically() =
+ verifyTextStyleIsDynamic(
+ selectStyle = { it.body2 },
+ updateTextStyle = { typography, body2 -> typography.copy(body2 = body2) }
+ )
+
+ @Test
+ fun sets_caption1_textstyle_dynamically() =
+ verifyTextStyleIsDynamic(
+ selectStyle = { it.caption1 },
+ updateTextStyle = { typography, caption1 -> typography.copy(caption1 = caption1) }
+ )
+
+ @Test
+ fun sets_caption2_textstyle_dynamically() =
+ verifyTextStyleIsDynamic(
+ selectStyle = { it.caption2 },
+ updateTextStyle = { typography, caption2 -> typography.copy(caption2 = caption2) }
+ )
+
+ @Test
+ fun sets_typography_dynamically() {
+ val initialStyle = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Bold,
+ fontSize = 14.sp,
+ letterSpacing = 0.sp
+ )
+ val overrideTextStyle = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 8.sp,
+ letterSpacing = 0.sp
+ )
+
+ rule.setContentWithTheme {
+ val typography = Typography()
+ val rememberedTypography = remember { mutableStateOf(typography) }
+ MaterialTheme(typography = rememberedTypography.value) {
+ Column {
+ Chip(
+ onClick = {},
+ colors = ChipDefaults.primaryChipColors(),
+ label = { Text("Test") },
+ )
+ Chip(
+ onClick = {
+ rememberedTypography.value =
+ typography.copy(button = overrideTextStyle)
+ },
+ label = { },
+ modifier = Modifier.testTag("button")
+ )
+ }
+ }
+ }
+
+ assertTextStyleEquals(initialStyle, rule.textStyleOf("Test"))
+ rule.onNodeWithTag("button").performClick()
+ assertTextStyleEquals(overrideTextStyle, rule.textStyleOf("Test"))
+ }
+
+ private fun verifyBackgroundColorIsDynamic(
+ initial: @Composable () -> Color,
+ selectChipColors: @Composable () -> ChipColors,
+ updateThemeColors: (Colors, Color) -> Colors
+ ) {
+ var initialColor = Color.Transparent
+ val overrideColor = Color.Cyan
+ val colors = Colors()
+
+ rule.setContentWithTheme {
+ initialColor = initial()
+ val dynamicColor = remember { mutableStateOf(initialColor) }
+ val themeColors = updateThemeColors(colors, dynamicColor.value)
+ MaterialTheme(colors = themeColors) {
+ Column {
+ Chip(
+ onClick = {},
+ colors = selectChipColors(),
+ label = { Text("Test") },
+ )
+ Chip(
+ onClick = { dynamicColor.value = overrideColor },
+ label = { },
+ modifier = Modifier.testTag("button")
+ )
+ }
+ }
+ }
+
+ rule.onNodeWithText("Test")
+ .captureToImage()
+ .assertContainsColor(initialColor, 60.0f)
+ rule.onNodeWithTag("button")
+ .performClick()
+ rule.onNodeWithText("Test")
+ .captureToImage()
+ .assertContainsColor(overrideColor, 60.0f)
+ }
+
+ private fun verifyContentColorIsDynamic(
+ initial: @Composable () -> Color,
+ selectChipColors: @Composable () -> ChipColors,
+ updateThemeColors: (Colors, Color) -> Colors
+ ) {
+ var initialColor = Color.White
+ val overrideColor = Color.Cyan
+ val colors = Colors()
+
+ rule.setContentWithTheme {
+ initialColor = initial()
+ val dynamicColor = remember { mutableStateOf(initialColor) }
+ val themeColors = updateThemeColors(colors, dynamicColor.value)
+ MaterialTheme(colors = themeColors) {
+ Column {
+ Chip(
+ onClick = {},
+ colors = selectChipColors(),
+ label = { Text("Test") },
+ )
+ Chip(
+ onClick = { dynamicColor.value = overrideColor },
+ label = { Text("Test") },
+ modifier = Modifier.testTag("button")
+ )
+ }
+ }
+ }
+
+ assertEquals(initialColor, rule.textStyleOf("Test").color)
+ rule.onNodeWithTag("button")
+ .performClick()
+ assertEquals(overrideColor, rule.textStyleOf("Test").color)
+ }
+
+ private fun verifyTextStyleIsDynamic(
+ selectStyle: (Typography) -> TextStyle,
+ updateTextStyle: (Typography, TextStyle) -> Typography
+ ) {
+ var initialStyle = TextStyle()
+ val overrideTextStyle = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 8.sp,
+ letterSpacing = 0.sp
+ )
+ val typography = Typography()
+
+ rule.setContentWithTheme {
+ initialStyle = selectStyle(typography)
+ val dynamicStyle = remember { mutableStateOf(initialStyle) }
+ val rememberedTypography =
+ updateTextStyle(typography, dynamicStyle.value)
+ MaterialTheme(
+ // WearChip always uses 'button' style for text, so assign the style under test to button.
+ typography = rememberedTypography.copy(button = selectStyle(rememberedTypography))
+ ) {
+ Column {
+ Chip(
+ onClick = {},
+ label = { Text("Test") },
+ )
+ Chip(
+ onClick = { dynamicStyle.value = overrideTextStyle },
+ label = { },
+ modifier = Modifier.testTag("button")
+ )
+ }
+ }
+ }
+
+ assertTextStyleEquals(initialStyle, rule.textStyleOf("Test"))
+ rule.onNodeWithTag("button").performClick()
+ assertTextStyleEquals(overrideTextStyle, rule.textStyleOf("Test"))
+ }
+}
\ No newline at end of file
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
index 35e949e..fce5d9c 100644
--- 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
@@ -15,8 +15,6 @@
*/
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
@@ -29,9 +27,11 @@
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material.ContentAlpha
import androidx.compose.material.Surface
+import androidx.compose.material.ripple.rememberRipple
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.Immutable
@@ -75,7 +75,6 @@
* @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
@@ -84,9 +83,6 @@
* [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
*/
@@ -96,11 +92,9 @@
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,
) {
@@ -122,10 +116,9 @@
val contentBoxModifier = Modifier
.clickable(
enabled = enabled,
- onClickLabel = onClickLabel,
onClick = onClick,
role = role,
- indication = indication,
+ indication = rememberRipple(),
interactionSource = interactionSource,
)
.padding(contentPadding)
@@ -148,7 +141,7 @@
/**
* 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.
+ * if provided, at 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
@@ -167,26 +160,25 @@
*
* 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
+ * @param label A slot for providing the chip's 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
+ * @param secondaryLabel A slot for providing the chip's 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 icon A slot for providing the chip's icon. The contents are expected to be a horizontally
+ * and vertically aligned icon of size [ChipDefaults.IconSize] or [ChipDefaults.LargeIconSize].
* @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
*/
@@ -199,9 +191,7 @@
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(
@@ -209,9 +199,7 @@
colors = colors,
modifier = modifier,
enabled = enabled,
- onClickLabel = onClickLabel,
interactionSource = interactionSource,
- indication = indication,
contentPadding = contentPadding
) {
Row(
@@ -248,6 +236,94 @@
}
/**
+ * A compact Wear Material Chip that offers two slots and a specific layout for an icon and label.
+ * Both the icon and label are optional however it is expected that at least one will be provided.
+ *
+ * The [CompactChip] is Stadium shaped and has a max height designed to take no more than one line
+ * of text of [Typography.button] style and/or one 24x24 icon. The default max height is
+ * [ChipDefaults.CompactChipHeight].
+ *
+ * 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 items are laid out as follows.
+ *
+ * 1. If a label is provided then the chip will be laid out with the optional icon at the start of a
+ * row followed by the label with a default max height of [ChipDefaults.CompactChipHeight].
+ *
+ * 2. If only an icon is provided it will be laid out vertically and horizontally centered with a
+ * default height of [ChipDefaults.CompactChipHeight] and the default width of
+ * [ChipDefaults.IconOnlyCompactChipWidth]
+ *
+ * The [CompactChip] 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 modifier Modifier to be applied to the chip
+ * @param label A slot for providing the chip's 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 icon A slot for providing the chip's icon. The contents are expected to be a horizontally
+ * and vertically aligned icon of size [ChipDefaults.IconSize] or [ChipDefaults.LargeIconSize].
+ * @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 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 contentPadding The spacing values to apply internally between the container and the
+ * content
+ */
+@Composable
+fun CompactChip(
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ label: (@Composable () -> Unit)? = null,
+ icon: (@Composable () -> Unit)? = null,
+ colors: ChipColors = ChipDefaults.primaryChipColors(),
+ enabled: Boolean = true,
+ interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+ contentPadding: PaddingValues = ChipDefaults.contentPadding(icon != null),
+) {
+ if (label != null) {
+ Chip(
+ label = label,
+ onClick = onClick,
+ modifier = modifier.height(ChipDefaults.CompactChipHeight),
+ icon = icon,
+ colors = colors,
+ enabled = enabled,
+ interactionSource = interactionSource,
+ contentPadding = contentPadding
+ )
+ } else {
+ Chip(
+ onClick = onClick,
+ modifier = modifier
+ .height(ChipDefaults.CompactChipHeight)
+ .width(ChipDefaults.IconOnlyCompactChipWidth),
+ colors = colors,
+ enabled = enabled,
+ interactionSource = interactionSource,
+ contentPadding = contentPadding
+ ) {
+ if (icon != null) {
+ icon()
+ }
+ }
+ }
+}
+
+/**
* 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].
@@ -377,6 +453,18 @@
internal val Height = 52.dp
/**
+ * The height applied for the [CompactChip].
+ * Note that you can override it by applying Modifier.height directly on [CompactChip].
+ */
+ internal val CompactChipHeight = 32.dp
+
+ /**
+ * The default width applied for the [CompactChip] when it has no label provided.
+ * Note that you can override it by applying Modifier.width directly on [CompactChip].
+ */
+ internal val IconOnlyCompactChipWidth = 52.dp
+
+ /**
* The default size of the icon when used inside a [Chip].
*/
public val IconSize = 24.dp
diff --git a/wear/wear-complications-data/api/restricted_current.txt b/wear/wear-complications-data/api/restricted_current.txt
index 4b1188f..77a59ce 100644
--- a/wear/wear-complications-data/api/restricted_current.txt
+++ b/wear/wear-complications-data/api/restricted_current.txt
@@ -1,5 +1,5 @@
// Signature format: 4.0
-package android.support.wearable.complications {
+package @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) android.support.wearable.complications {
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final class ComplicationData implements android.os.Parcelable {
method public int describeContents();
diff --git a/wear/wear-complications-data/src/main/java/android/support/wearable/complications/package-info.java b/wear/wear-complications-data/src/main/java/android/support/wearable/complications/package-info.java
new file mode 100644
index 0000000..7aa7905
--- /dev/null
+++ b/wear/wear-complications-data/src/main/java/android/support/wearable/complications/package-info.java
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+/**
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+package android.support.wearable.complications;
+
+import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import androidx.annotation.RestrictTo;
diff --git a/wear/wear-ongoing/api/current.txt b/wear/wear-ongoing/api/current.txt
index edd5ae4..9eb1123 100644
--- a/wear/wear-ongoing/api/current.txt
+++ b/wear/wear-ongoing/api/current.txt
@@ -12,6 +12,7 @@
method public androidx.wear.ongoing.Status? getStatus();
method public String? getTag();
method public long getTimestamp();
+ method public String? getTitle();
method public android.app.PendingIntent getTouchIntent();
method public static androidx.wear.ongoing.OngoingActivity? recoverOngoingActivity(android.content.Context, java.util.function.Predicate<androidx.wear.ongoing.OngoingActivity!>);
method public static androidx.wear.ongoing.OngoingActivity? recoverOngoingActivity(android.content.Context);
@@ -31,6 +32,7 @@
method public androidx.wear.ongoing.OngoingActivity.Builder setStaticIcon(android.graphics.drawable.Icon);
method public androidx.wear.ongoing.OngoingActivity.Builder setStaticIcon(@DrawableRes int);
method public androidx.wear.ongoing.OngoingActivity.Builder setStatus(androidx.wear.ongoing.Status);
+ method public androidx.wear.ongoing.OngoingActivity.Builder setTitle(String);
method public androidx.wear.ongoing.OngoingActivity.Builder setTouchIntent(android.app.PendingIntent);
}
diff --git a/wear/wear-ongoing/api/public_plus_experimental_current.txt b/wear/wear-ongoing/api/public_plus_experimental_current.txt
index edd5ae4..9eb1123 100644
--- a/wear/wear-ongoing/api/public_plus_experimental_current.txt
+++ b/wear/wear-ongoing/api/public_plus_experimental_current.txt
@@ -12,6 +12,7 @@
method public androidx.wear.ongoing.Status? getStatus();
method public String? getTag();
method public long getTimestamp();
+ method public String? getTitle();
method public android.app.PendingIntent getTouchIntent();
method public static androidx.wear.ongoing.OngoingActivity? recoverOngoingActivity(android.content.Context, java.util.function.Predicate<androidx.wear.ongoing.OngoingActivity!>);
method public static androidx.wear.ongoing.OngoingActivity? recoverOngoingActivity(android.content.Context);
@@ -31,6 +32,7 @@
method public androidx.wear.ongoing.OngoingActivity.Builder setStaticIcon(android.graphics.drawable.Icon);
method public androidx.wear.ongoing.OngoingActivity.Builder setStaticIcon(@DrawableRes int);
method public androidx.wear.ongoing.OngoingActivity.Builder setStatus(androidx.wear.ongoing.Status);
+ method public androidx.wear.ongoing.OngoingActivity.Builder setTitle(String);
method public androidx.wear.ongoing.OngoingActivity.Builder setTouchIntent(android.app.PendingIntent);
}
diff --git a/wear/wear-ongoing/api/restricted_current.txt b/wear/wear-ongoing/api/restricted_current.txt
index edd5ae4..9eb1123 100644
--- a/wear/wear-ongoing/api/restricted_current.txt
+++ b/wear/wear-ongoing/api/restricted_current.txt
@@ -12,6 +12,7 @@
method public androidx.wear.ongoing.Status? getStatus();
method public String? getTag();
method public long getTimestamp();
+ method public String? getTitle();
method public android.app.PendingIntent getTouchIntent();
method public static androidx.wear.ongoing.OngoingActivity? recoverOngoingActivity(android.content.Context, java.util.function.Predicate<androidx.wear.ongoing.OngoingActivity!>);
method public static androidx.wear.ongoing.OngoingActivity? recoverOngoingActivity(android.content.Context);
@@ -31,6 +32,7 @@
method public androidx.wear.ongoing.OngoingActivity.Builder setStaticIcon(android.graphics.drawable.Icon);
method public androidx.wear.ongoing.OngoingActivity.Builder setStaticIcon(@DrawableRes int);
method public androidx.wear.ongoing.OngoingActivity.Builder setStatus(androidx.wear.ongoing.Status);
+ method public androidx.wear.ongoing.OngoingActivity.Builder setTitle(String);
method public androidx.wear.ongoing.OngoingActivity.Builder setTouchIntent(android.app.PendingIntent);
}
diff --git a/wear/wear-ongoing/src/main/java/androidx/wear/ongoing/OngoingActivity.java b/wear/wear-ongoing/src/main/java/androidx/wear/ongoing/OngoingActivity.java
index c51d447..dd65d05 100644
--- a/wear/wear-ongoing/src/main/java/androidx/wear/ongoing/OngoingActivity.java
+++ b/wear/wear-ongoing/src/main/java/androidx/wear/ongoing/OngoingActivity.java
@@ -106,6 +106,7 @@
private LocusIdCompat mLocusId;
private int mOngoingActivityId = DEFAULT_ID;
private String mCategory;
+ private String mTitle;
static final int DEFAULT_ID = -1;
@@ -242,6 +243,16 @@
}
/**
+ * Sets the Title of this {@link OngoingActivity}, this could be used by the launcher to
+ * override the app's title.
+ */
+ @NonNull
+ public Builder setTitle(@NonNull String title) {
+ mTitle = title;
+ return this;
+ }
+
+ /**
* Combine all options provided and the information in the notification if needed,
* return a new {@link OngoingActivity} object.
*
@@ -288,7 +299,8 @@
locusId == null ? null : locusId.getId(),
mOngoingActivityId,
category,
- SystemClock.elapsedRealtime()
+ SystemClock.elapsedRealtime(),
+ mTitle
));
}
}
@@ -384,6 +396,14 @@
}
/**
+ * Get the title of this {@link OngoingActivity} if set.
+ */
+ @Nullable
+ public String getTitle() {
+ return mData.getTitle();
+ }
+
+ /**
* Notify the system that this activity should be shown as an Ongoing Activity.
*
* This will modify the notification builder associated with this Ongoing Activity, so needs
diff --git a/wear/wear-ongoing/src/main/java/androidx/wear/ongoing/OngoingActivityData.java b/wear/wear-ongoing/src/main/java/androidx/wear/ongoing/OngoingActivityData.java
index 9e06859..75bc162 100644
--- a/wear/wear-ongoing/src/main/java/androidx/wear/ongoing/OngoingActivityData.java
+++ b/wear/wear-ongoing/src/main/java/androidx/wear/ongoing/OngoingActivityData.java
@@ -17,7 +17,6 @@
import android.app.PendingIntent;
import android.graphics.drawable.Icon;
-import android.os.SystemClock;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -65,6 +64,10 @@
@ParcelField(value = 8)
long mTimestamp;
+ @Nullable
+ @ParcelField(value = 9, defaultValue = "null")
+ String mTitle;
+
// Required by VersionedParcelable
OngoingActivityData() {
}
@@ -77,7 +80,8 @@
@Nullable String locusId,
int ongoingActivityId,
@Nullable String category,
- long timestamp
+ long timestamp,
+ @Nullable String title
) {
mAnimatedIcon = animatedIcon;
mStaticIcon = staticIcon;
@@ -87,81 +91,52 @@
mOngoingActivityId = ongoingActivityId;
mCategory = category;
mTimestamp = timestamp;
+ mTitle = title;
}
- /**
- * Get the animated icon that can be used on some surfaces to represent this
- * {@link OngoingActivity}. For example, in the WatchFace.
- */
@Nullable
- public Icon getAnimatedIcon() {
+ Icon getAnimatedIcon() {
return mAnimatedIcon;
}
- /**
- * Get the static icon that can be used on some surfaces to represent this
- * {@link OngoingActivity}. For example in the WatchFace in ambient mode. If not set, returns
- * the small icon of the corresponding Notification.
- */
@NonNull
- public Icon getStaticIcon() {
+ Icon getStaticIcon() {
return mStaticIcon;
}
- /**
- * Get the status of this ongoing activity, the status may be displayed on the UI to
- * show progress of the Ongoing Activity. If not set, returns the content text of the
- * corresponding Notification.
- */
@Nullable
- public OngoingActivityStatus getStatus() {
+ OngoingActivityStatus getStatus() {
return mStatus;
}
- /**
- * Get the intent to be used to go back to the activity when the user interacts with the
- * Ongoing Activity in other surfaces (for example, taps the Icon on the WatchFace). If not
- * set, returns the touch intent of the corresponding Notification.
- */
@NonNull
- public PendingIntent getTouchIntent() {
+ PendingIntent getTouchIntent() {
return mTouchIntent;
}
- /**
- * Get the LocusId of this {@link OngoingActivity}, this can be used by the launcher to
- * identify the corresponding launcher item and display it accordingly. If not set, returns
- * the one in the corresponding Notification.
- */
@Nullable
- public LocusIdCompat getLocusId() {
+ LocusIdCompat getLocusId() {
return mLocusId == null ? null : new LocusIdCompat(mLocusId);
}
- /**
- * Give the id to this {@link OngoingActivity}, as a way to reference it in
- * [fromExistingOngoingActivity]
- */
- public int getOngoingActivityId() {
+ int getOngoingActivityId() {
return mOngoingActivityId;
}
- /**
- * Get the Category of this {@link OngoingActivity} if set, otherwise the category of the
- * corresponding notification.
- */
@Nullable
- public String getCategory() {
+ String getCategory() {
return mCategory;
}
- /**
- * Get the time (in {@link SystemClock#elapsedRealtime()} time) the OngoingActivity was built.
- */
- public long getTimestamp() {
+ long getTimestamp() {
return mTimestamp;
}
+ @Nullable
+ String getTitle() {
+ return mTitle;
+ }
+
// Status is mutable, by the library.
void setStatus(@NonNull OngoingActivityStatus status) {
mStatus = status;
diff --git a/wear/wear-ongoing/src/test/java/androidx/wear/ongoing/OngoingActivityTest.kt b/wear/wear-ongoing/src/test/java/androidx/wear/ongoing/OngoingActivityTest.kt
index 1519bf6..93290b7 100644
--- a/wear/wear-ongoing/src/test/java/androidx/wear/ongoing/OngoingActivityTest.kt
+++ b/wear/wear-ongoing/src/test/java/androidx/wear/ongoing/OngoingActivityTest.kt
@@ -34,6 +34,7 @@
)
private val NotificationId = 4321
private val ChannelId = "ChannelId"
+ private val Title = "AppTitle"
private lateinit var context: Context
private lateinit var notificationManager: NotificationManager
@@ -78,6 +79,7 @@
.setOngoingActivityId(OaId)
.setStatus(BasicStatus)
.setTouchIntent(PendingIntentValue)
+ .setTitle(Title)
.build()
oa.apply(context)
@@ -91,6 +93,7 @@
assertEquals(OaId, received.ongoingActivityId)
// TODO(ssancho): check status
assertEquals(PendingIntentValue, received.touchIntent)
+ assertEquals(Title, received.title)
}
@Test
@@ -103,6 +106,7 @@
.setOngoingActivityId(OaId)
.setStatus(BasicStatus)
.setTouchIntent(PendingIntentValue)
+ .setTitle(Title)
.build()
oa.apply(context)
notificationManager.notify(NotificationId, builder.build())
@@ -126,6 +130,7 @@
assertEquals(OaId, received.ongoingActivityId)
// TODO(ssancho): check status
assertEquals(PendingIntentValue, received.touchIntent)
+ assertEquals(Title, received.title)
notificationManager.cancel(NotificationId)
}
@@ -193,6 +198,7 @@
.setOngoingActivityId(OaId)
.setStatus(BasicStatus)
.setTouchIntent(PendingIntentValue)
+ .setTitle(Title)
.build()
oa.apply(context)
val notification = builder.build()
@@ -209,6 +215,7 @@
assertEquals(OaId, received.ongoingActivityId)
// TODO(ssancho): check status
assertEquals(PendingIntentValue, received.touchIntent)
+ assertEquals(Title, received.title)
}
@Test
diff --git a/wear/wear-watchface-data/api/restricted_current.txt b/wear/wear-watchface-data/api/restricted_current.txt
index 58265360..12e7670 100644
--- a/wear/wear-watchface-data/api/restricted_current.txt
+++ b/wear/wear-watchface-data/api/restricted_current.txt
@@ -1,5 +1,5 @@
// Signature format: 4.0
-package android.support.wearable.watchface {
+package @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) android.support.wearable.watchface {
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final class Constants {
field public static final String ACTION_REQUEST_STATE = "com.google.android.wearable.watchfaces.action.REQUEST_STATE";
@@ -93,7 +93,7 @@
}
-package android.support.wearable.watchface.accessibility {
+package @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) android.support.wearable.watchface.accessibility {
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public class AccessibilityUtils {
method public static android.support.wearable.complications.TimeDependentText generateContentDescription(android.content.Context, android.support.wearable.complications.ComplicationData);
diff --git a/wear/wear-watchface-data/src/main/java/android/support/wearable/watchface/accessibility/package-info.java b/wear/wear-watchface-data/src/main/java/android/support/wearable/watchface/accessibility/package-info.java
new file mode 100644
index 0000000..45c6efc
--- /dev/null
+++ b/wear/wear-watchface-data/src/main/java/android/support/wearable/watchface/accessibility/package-info.java
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+/**
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+package android.support.wearable.watchface.accessibility;
+
+import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import androidx.annotation.RestrictTo;
diff --git a/wear/wear-watchface-data/src/main/java/android/support/wearable/watchface/package-info.java b/wear/wear-watchface-data/src/main/java/android/support/wearable/watchface/package-info.java
new file mode 100644
index 0000000..4b57c76
--- /dev/null
+++ b/wear/wear-watchface-data/src/main/java/android/support/wearable/watchface/package-info.java
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+/**
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+package android.support.wearable.watchface;
+
+import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import androidx.annotation.RestrictTo;
diff --git a/wear/wear-watchface-editor/src/androidTest/java/androidx/wear/watchface/editor/EditingSessionTest.kt b/wear/wear-watchface-editor/src/androidTest/java/androidx/wear/watchface/editor/EditingSessionTest.kt
index ef2ef3f..fe73ba9 100644
--- a/wear/wear-watchface-editor/src/androidTest/java/androidx/wear/watchface/editor/EditingSessionTest.kt
+++ b/wear/wear-watchface-editor/src/androidTest/java/androidx/wear/watchface/editor/EditingSessionTest.kt
@@ -1110,6 +1110,9 @@
val editorObserver = TestEditorObserver()
val observerId = EditorService.globalEditorService.registerObserver(editorObserver)
+ val oldWFColorStyleSetting = editorDelegate.userStyle[colorStyleSetting]!!.id.value
+ val oldWFWatchHandStyleSetting = editorDelegate.userStyle[watchHandStyleSetting]!!.id.value
+
scenario.onActivity { activity ->
runBlocking {
// Select [blueStyleOption] and [gothicStyleOption].
@@ -1135,11 +1138,12 @@
assertThat(result.watchFaceId.id).isEqualTo(testInstanceId.id)
assertTrue(result.shouldCommitChanges)
- // The style change should also have been applied to the watchface
+ // The style change shouldn't be applied to the watchface as it gets reverted to the old
+ // one when editor closes.
assertThat(editorDelegate.userStyle[colorStyleSetting]!!.id.value)
- .isEqualTo(blueStyleOption.id.value)
+ .isEqualTo(oldWFColorStyleSetting)
assertThat(editorDelegate.userStyle[watchHandStyleSetting]!!.id.value)
- .isEqualTo(gothicStyleOption.id.value)
+ .isEqualTo(oldWFWatchHandStyleSetting)
assertThat(result.previewComplicationsData.size).isEqualTo(2)
val leftComplicationData = result.previewComplicationsData[LEFT_COMPLICATION_ID] as
@@ -1514,7 +1518,8 @@
mockWatchFaceHostApi,
watchState,
currentUserStyleRepository,
- ComplicationsManager(emptyList(), currentUserStyleRepository)
+ ComplicationsManager(emptyList(), currentUserStyleRepository),
+ Calendar.getInstance()
)
assertThat(activity.onCreateException).isInstanceOf(IllegalStateException::class.java)
diff --git a/wear/wear-watchface-editor/src/main/java/androidx/wear/watchface/editor/EditorSession.kt b/wear/wear-watchface-editor/src/main/java/androidx/wear/watchface/editor/EditorSession.kt
index c974e38..eef4f27 100644
--- a/wear/wear-watchface-editor/src/main/java/androidx/wear/watchface/editor/EditorSession.kt
+++ b/wear/wear-watchface-editor/src/main/java/androidx/wear/watchface/editor/EditorSession.kt
@@ -77,7 +77,10 @@
* Interface for manipulating watch face state during an editing session for a watch face editing
* session. The editor should adjust [userStyle] and call [openComplicationProviderChooser] to
* configure the watch face and call [close] when done. This reports the updated [EditorState] to
- * the [EditorListener]s registered via [EditorServiceClient.addListener].
+ * the [EditorListener]s registered via [EditorServiceClient.addListener]. Style changes applied
+ * during the editor session are temporary and will be reverted when the editor session completes.
+ * In the event that the editor sessions results in a new watch face configuration that will be
+ * subsequently reapplied when the new configuration is provided by the system.
*/
public abstract class EditorSession : AutoCloseable {
/** The [ComponentName] of the watch face being edited. */
@@ -91,7 +94,8 @@
@get:RequiresApi(Build.VERSION_CODES.R)
public abstract val watchFaceId: WatchFaceId
- /** The current [UserStyle]. Assigning to this will cause the style to update. */
+ /** The current [UserStyle]. Assigning to this will cause the style to update. However, styling
+ * changes to the watch face will be reverted upon exit. */
public abstract var userStyle: UserStyle
/** The UTC reference preview time for this watch face in milliseconds since the epoch. */
@@ -113,10 +117,10 @@
* because there are circumstances where [ComponentActivity.onStop] doesn't get called but the
* UX requires us to commit changes.
*
- * If false upon exit for an on watch face editor, the original UserStyle is restored. Note we
- * need SysUI's help to revert any complication provider changes. Caveat some providers have
- * their own config (e.g. the world clock has a timezone setting) and that config currently
- * can't be reverted.
+ * Regardless of the value, on completion of the editor session, the original UserStyle is
+ * restored. Note we need SysUI's help to revert any complication provider changes. Caveat
+ * some providers have their own config (e.g. the world clock has a timezone setting) and
+ * that config currently can't be reverted.
*/
@get:UiThread
@get:JvmName("isCommitChangesOnClose")
@@ -665,8 +669,11 @@
if (this::editorDelegate.isInitialized) {
editorDelegate.onDestroy()
}
- // Revert any changes to the UserStyle if needed.
- if (!commitChangesOnClose && this::previousWatchFaceUserStyle.isInitialized) {
+ // Revert any changes to the user style that was set during the editing session. The
+ // system will update the user style and communicate it to the active watch face if
+ // needed. This guarantees that the system is always the source of truth for the current
+ // style.
+ if (this::previousWatchFaceUserStyle.isInitialized) {
userStyle = previousWatchFaceUserStyle
}
}
diff --git a/wear/wear-watchface/api/current.txt b/wear/wear-watchface/api/current.txt
index 53b8d81..3e4c282 100644
--- a/wear/wear-watchface/api/current.txt
+++ b/wear/wear-watchface/api/current.txt
@@ -21,7 +21,7 @@
}
public interface CanvasComplicationFactory {
- method @UiThread public androidx.wear.watchface.CanvasComplication create(androidx.wear.watchface.WatchState, androidx.wear.watchface.CanvasComplication.InvalidateCallback);
+ method @WorkerThread public androidx.wear.watchface.CanvasComplication create(androidx.wear.watchface.WatchState, androidx.wear.watchface.CanvasComplication.InvalidateCallback);
}
public final class Complication {
@@ -121,14 +121,7 @@
enum_constant public static final androidx.wear.watchface.DrawMode MUTE;
}
- public final class MutableObservableWatchData<T> extends androidx.wear.watchface.ObservableWatchData<T> {
- ctor public MutableObservableWatchData(T? initialValue);
- ctor public MutableObservableWatchData();
- method @UiThread public void setValue(T v);
- property @UiThread public T value;
- }
-
- public class ObservableWatchData<T> {
+ public abstract sealed class ObservableWatchData<T> {
method @UiThread public final void addObserver(androidx.wear.watchface.Observer<T> observer);
method @UiThread public T getValue();
method @UiThread public final T getValueOr(T p);
@@ -138,6 +131,13 @@
property @UiThread public T value;
}
+ public static final class ObservableWatchData.MutableObservableWatchData<T> extends androidx.wear.watchface.ObservableWatchData<T> {
+ ctor public ObservableWatchData.MutableObservableWatchData(T? initialValue);
+ ctor public ObservableWatchData.MutableObservableWatchData();
+ method @UiThread public void setValue(T v);
+ property @UiThread public T value;
+ }
+
public interface Observer<T> {
method public void onChanged(T);
}
diff --git a/wear/wear-watchface/api/public_plus_experimental_current.txt b/wear/wear-watchface/api/public_plus_experimental_current.txt
index 0049d9a..b12e928 100644
--- a/wear/wear-watchface/api/public_plus_experimental_current.txt
+++ b/wear/wear-watchface/api/public_plus_experimental_current.txt
@@ -21,7 +21,7 @@
}
public interface CanvasComplicationFactory {
- method @UiThread public androidx.wear.watchface.CanvasComplication create(androidx.wear.watchface.WatchState, androidx.wear.watchface.CanvasComplication.InvalidateCallback);
+ method @WorkerThread public androidx.wear.watchface.CanvasComplication create(androidx.wear.watchface.WatchState, androidx.wear.watchface.CanvasComplication.InvalidateCallback);
}
public final class Complication {
@@ -121,14 +121,7 @@
enum_constant public static final androidx.wear.watchface.DrawMode MUTE;
}
- public final class MutableObservableWatchData<T> extends androidx.wear.watchface.ObservableWatchData<T> {
- ctor public MutableObservableWatchData(T? initialValue);
- ctor public MutableObservableWatchData();
- method @UiThread public void setValue(T v);
- property @UiThread public T value;
- }
-
- public class ObservableWatchData<T> {
+ public abstract sealed class ObservableWatchData<T> {
method @UiThread public final void addObserver(androidx.wear.watchface.Observer<T> observer);
method @UiThread public T getValue();
method @UiThread public final T getValueOr(T p);
@@ -138,6 +131,13 @@
property @UiThread public T value;
}
+ public static final class ObservableWatchData.MutableObservableWatchData<T> extends androidx.wear.watchface.ObservableWatchData<T> {
+ ctor public ObservableWatchData.MutableObservableWatchData(T? initialValue);
+ ctor public ObservableWatchData.MutableObservableWatchData();
+ method @UiThread public void setValue(T v);
+ property @UiThread public T value;
+ }
+
public interface Observer<T> {
method public void onChanged(T);
}
diff --git a/wear/wear-watchface/api/restricted_current.txt b/wear/wear-watchface/api/restricted_current.txt
index 95a9235..23a2893 100644
--- a/wear/wear-watchface/api/restricted_current.txt
+++ b/wear/wear-watchface/api/restricted_current.txt
@@ -21,7 +21,7 @@
}
public interface CanvasComplicationFactory {
- method @UiThread public androidx.wear.watchface.CanvasComplication create(androidx.wear.watchface.WatchState, androidx.wear.watchface.CanvasComplication.InvalidateCallback);
+ method @WorkerThread public androidx.wear.watchface.CanvasComplication create(androidx.wear.watchface.WatchState, androidx.wear.watchface.CanvasComplication.InvalidateCallback);
}
public final class Complication {
@@ -122,13 +122,6 @@
enum_constant public static final androidx.wear.watchface.DrawMode MUTE;
}
- public final class MutableObservableWatchData<T> extends androidx.wear.watchface.ObservableWatchData<T> {
- ctor public MutableObservableWatchData(T? initialValue);
- ctor public MutableObservableWatchData();
- method @UiThread public void setValue(T v);
- property @UiThread public T value;
- }
-
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final class MutableWatchState {
method public androidx.wear.watchface.WatchState asWatchState();
method public long getAnalogPreviewReferenceTimeMillis();
@@ -136,31 +129,31 @@
method public long getDigitalPreviewReferenceTimeMillis();
method public boolean getHasBurnInProtection();
method public boolean getHasLowBitAmbient();
- method public androidx.wear.watchface.MutableObservableWatchData<java.lang.Integer> getInterruptionFilter();
- method public androidx.wear.watchface.MutableObservableWatchData<java.lang.Boolean> isAmbient();
- method public androidx.wear.watchface.MutableObservableWatchData<java.lang.Boolean> isBatteryLowAndNotCharging();
+ method public androidx.wear.watchface.ObservableWatchData.MutableObservableWatchData<java.lang.Integer> getInterruptionFilter();
+ method public androidx.wear.watchface.ObservableWatchData.MutableObservableWatchData<java.lang.Boolean> isAmbient();
+ method public androidx.wear.watchface.ObservableWatchData.MutableObservableWatchData<java.lang.Boolean> isBatteryLowAndNotCharging();
method public boolean isHeadless();
- method public androidx.wear.watchface.MutableObservableWatchData<java.lang.Boolean> isVisible();
+ method public androidx.wear.watchface.ObservableWatchData.MutableObservableWatchData<java.lang.Boolean> isVisible();
method public void setAnalogPreviewReferenceTimeMillis(long p);
method public void setChinHeight(@Px int value);
method public void setDigitalPreviewReferenceTimeMillis(long p);
method public void setHasBurnInProtection(boolean p);
method public void setHasLowBitAmbient(boolean p);
method public void setHeadless(boolean p);
- method public void setInterruptionFilter(androidx.wear.watchface.MutableObservableWatchData<java.lang.Integer> p);
+ method public void setInterruptionFilter(androidx.wear.watchface.ObservableWatchData.MutableObservableWatchData<java.lang.Integer> p);
property public final long analogPreviewReferenceTimeMillis;
property @Px public final int chinHeight;
property public final long digitalPreviewReferenceTimeMillis;
property public final boolean hasBurnInProtection;
property public final boolean hasLowBitAmbient;
- property public final androidx.wear.watchface.MutableObservableWatchData<java.lang.Integer> interruptionFilter;
- property public final androidx.wear.watchface.MutableObservableWatchData<java.lang.Boolean> isAmbient;
- property public final androidx.wear.watchface.MutableObservableWatchData<java.lang.Boolean> isBatteryLowAndNotCharging;
+ property public final androidx.wear.watchface.ObservableWatchData.MutableObservableWatchData<java.lang.Integer> interruptionFilter;
+ property public final androidx.wear.watchface.ObservableWatchData.MutableObservableWatchData<java.lang.Boolean> isAmbient;
+ property public final androidx.wear.watchface.ObservableWatchData.MutableObservableWatchData<java.lang.Boolean> isBatteryLowAndNotCharging;
property public final boolean isHeadless;
- property public final androidx.wear.watchface.MutableObservableWatchData<java.lang.Boolean> isVisible;
+ property public final androidx.wear.watchface.ObservableWatchData.MutableObservableWatchData<java.lang.Boolean> isVisible;
}
- public class ObservableWatchData<T> {
+ public abstract sealed class ObservableWatchData<T> {
method @UiThread public final void addObserver(androidx.wear.watchface.Observer<T> observer);
method @UiThread public T getValue();
method @UiThread public final T getValueOr(T p);
@@ -170,6 +163,13 @@
property @UiThread public T value;
}
+ public static final class ObservableWatchData.MutableObservableWatchData<T> extends androidx.wear.watchface.ObservableWatchData<T> {
+ ctor public ObservableWatchData.MutableObservableWatchData(T? initialValue);
+ ctor public ObservableWatchData.MutableObservableWatchData();
+ method @UiThread public void setValue(T v);
+ property @UiThread public T value;
+ }
+
public interface Observer<T> {
method public void onChanged(T);
}
@@ -368,7 +368,7 @@
}
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final class WatchFaceImpl {
- ctor @UiThread public WatchFaceImpl(androidx.wear.watchface.WatchFace watchface, androidx.wear.watchface.WatchFaceHostApi watchFaceHostApi, androidx.wear.watchface.WatchState watchState, androidx.wear.watchface.style.CurrentUserStyleRepository currentUserStyleRepository, androidx.wear.watchface.ComplicationsManager complicationsManager);
+ ctor @UiThread public WatchFaceImpl(androidx.wear.watchface.WatchFace watchface, androidx.wear.watchface.WatchFaceHostApi watchFaceHostApi, androidx.wear.watchface.WatchState watchState, androidx.wear.watchface.style.CurrentUserStyleRepository currentUserStyleRepository, androidx.wear.watchface.ComplicationsManager complicationsManager, android.icu.util.Calendar calendar);
method public long getPreviewReferenceTimeMillis();
property public final long previewReferenceTimeMillis;
}
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/CanvasComplicationFactory.java b/wear/wear-watchface/src/main/java/androidx/wear/watchface/CanvasComplicationFactory.java
index 133b6d0..6d46712 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/CanvasComplicationFactory.java
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/CanvasComplicationFactory.java
@@ -17,7 +17,7 @@
package androidx.wear.watchface;
import androidx.annotation.NonNull;
-import androidx.annotation.UiThread;
+import androidx.annotation.WorkerThread;
/**
* Factory for creating a CanvasComplication. This decouples construction of Complications and
@@ -26,7 +26,9 @@
// TODO(b/188035300): Put links into the comments.
public interface CanvasComplicationFactory {
/**
- * Creates a CanvasComplication.
+ * Creates a CanvasComplication. This will be called on a background thread, however all
+ * CanvasComplication rendering will be done on the UI thread and there's a memory barrier
+ * between construction and usage so no special threading primitives are required.
*
* @param watchState The current WatchState
* @param invalidateCallback The CanvasComplication.InvalidateCallback the constructed
@@ -36,7 +38,7 @@
* @return The constructed CanvasComplication.
*/
@NonNull
- @UiThread
+ @WorkerThread
@SuppressWarnings("ExecutorRegistration") // This is UI thread only.
CanvasComplication create(
@NonNull WatchState watchState,
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/Complication.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/Complication.kt
index 017b5675..062cdca 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/Complication.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/Complication.kt
@@ -29,6 +29,7 @@
import androidx.wear.complications.DefaultComplicationProviderPolicy
import androidx.wear.complications.data.ComplicationData
import androidx.wear.complications.data.ComplicationType
+import androidx.wear.watchface.ObservableWatchData.MutableObservableWatchData
import androidx.wear.watchface.data.ComplicationBoundsType
import androidx.wear.watchface.style.UserStyleSetting
import androidx.wear.watchface.style.UserStyleSetting.ComplicationsUserStyleSetting
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/ComplicationsManager.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/ComplicationsManager.kt
index 5a13a2d..a89c976 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/ComplicationsManager.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/ComplicationsManager.kt
@@ -33,6 +33,7 @@
import androidx.wear.complications.data.ComplicationType
import androidx.wear.complications.data.EmptyComplicationData
import androidx.wear.utility.TraceEvent
+import androidx.wear.watchface.ObservableWatchData.MutableObservableWatchData
import androidx.wear.watchface.control.data.IdTypeAndDefaultProviderPolicyWireFormat
import androidx.wear.watchface.data.ComplicationBoundsType
import androidx.wear.watchface.style.CurrentUserStyleRepository
@@ -152,6 +153,7 @@
}
/** Finish initialization. */
+ @WorkerThread
internal fun init(
watchFaceHostApi: WatchFaceHostApi,
calendar: Calendar,
@@ -164,6 +166,9 @@
for ((_, complication) in complications) {
complication.init(complicationInvalidateListener)
+
+ // Force lazy construction of renderers.
+ complication.renderer
}
// Activate complications.
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/ObservableWatchData.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/ObservableWatchData.kt
index ba4ac3f..12b1443 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/ObservableWatchData.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/ObservableWatchData.kt
@@ -24,7 +24,7 @@
* @param T The type of data held by this instance.
* @param _value The initial value or `null` if there isn't an initial value.
*/
-public open class ObservableWatchData<T : Any> internal constructor(internal var _value: T?) {
+public sealed class ObservableWatchData<T : Any> constructor(internal var _value: T?) {
private var iterating = false
private val observers = ArrayList<Observer<T>>()
@@ -104,26 +104,26 @@
"<unset>"
}
}
-}
-
-/**
- * [ObservableWatchData] which publicly exposes [setValue(T)] method.
- *
- * @param T The type of data held by this instance
- */
-public class MutableObservableWatchData<T : Any>(initialValue: T?) :
- ObservableWatchData<T>(initialValue) {
- public constructor() : this(null)
/**
- * Mutable observable value. Assigning a different value will trigger [Observer.onChanged]
- * callbacks.
+ * [ObservableWatchData] which publicly exposes [setValue(T)] method.
+ *
+ * @param T The type of data held by this instance
*/
- override var value: T
- @UiThread
- get() = _value!!
- @UiThread
- public set(v) {
- super.value = v
- }
+ public class MutableObservableWatchData<T : Any>(initialValue: T?) :
+ ObservableWatchData<T>(initialValue) {
+ public constructor() : this(null)
+
+ /**
+ * Mutable observable value. Assigning a different value will trigger [Observer.onChanged]
+ * callbacks.
+ */
+ override var value: T
+ @UiThread
+ get() = _value!!
+ @UiThread
+ public set(v) {
+ super.value = v
+ }
+ }
}
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/Renderer.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/Renderer.kt
index ff7ebb2..6dfc3f8 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/Renderer.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/Renderer.kt
@@ -102,7 +102,8 @@
/**
* The base class for [CanvasRenderer] and [GlesRenderer]. Renderers are constructed on a background
- * thread but all rendering is done on the UiThread.
+ * thread but all rendering is done on the UiThread. There is a memory barrier between construction
+ * and rendering so no special threading primitives are required.
*
* @param surfaceHolder The [SurfaceHolder] that [renderInternal] will draw into.
* @param currentUserStyleRepository The associated [CurrentUserStyleRepository].
@@ -306,7 +307,9 @@
*
* A CanvasRenderer is expected to be constructed on the background thread associated with
* [WatchFaceService.getBackgroundThreadHandler] inside a call to
- * [WatchFaceService.createWatchFace]. All rendering is be done on the UiThread.
+ * [WatchFaceService.createWatchFace]. All rendering is be done on the UiThread. There is a
+ * memory barrier between construction and rendering so no special threading primitives are
+ * required.
*
* @param surfaceHolder The [SurfaceHolder] from which a [Canvas] to will be obtained and passed
* into [render].
@@ -463,7 +466,9 @@
*
* A GlesRenderer is expected to be constructed on the background thread associated with
* [WatchFaceService.getBackgroundThreadHandler] inside a call to
- * [WatchFaceService.createWatchFace]. All rendering is be done on the UiThread.
+ * [WatchFaceService.createWatchFace]. All rendering is be done on the UiThread. There is a
+ * memory barrier between construction and rendering so no special threading primitives are
+ * required.
*
* Two linked [EGLContext]s are created [eglBackgroundThreadContext] and [eglUiThreadContext]
* which are associated with background and UiThread respectively. OpenGL objects created on
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFace.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFace.kt
index 3865712..ff3c3a2 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFace.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFace.kt
@@ -19,7 +19,6 @@
import android.annotation.SuppressLint
import android.app.NotificationManager
import android.content.ComponentName
-import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.graphics.Bitmap
@@ -32,7 +31,6 @@
import android.os.Bundle
import android.support.wearable.watchface.SharedMemoryImage
import android.support.wearable.watchface.WatchFaceStyle
-import android.util.Base64
import android.view.Gravity
import android.view.Surface.FRAME_RATE_COMPATIBILITY_DEFAULT
import androidx.annotation.ColorInt
@@ -41,7 +39,6 @@
import androidx.annotation.Px
import androidx.annotation.RequiresApi
import androidx.annotation.RestrictTo
-import androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP
import androidx.annotation.UiThread
import androidx.annotation.VisibleForTesting
import androidx.wear.complications.SystemProviders
@@ -49,6 +46,7 @@
import androidx.wear.complications.data.ComplicationType
import androidx.wear.complications.data.toApiComplicationData
import androidx.wear.utility.TraceEvent
+import androidx.wear.watchface.ObservableWatchData.MutableObservableWatchData
import androidx.wear.watchface.control.data.ComplicationRenderParams
import androidx.wear.watchface.control.data.WatchFaceRenderParams
import androidx.wear.watchface.data.ComplicationStateWireFormat
@@ -58,10 +56,7 @@
import androidx.wear.watchface.style.UserStyleData
import androidx.wear.watchface.style.UserStyleSchema
import androidx.wear.watchface.style.WatchFaceLayer
-import androidx.wear.watchface.style.data.UserStyleWireFormat
import kotlinx.coroutines.CompletableDeferred
-import java.io.FileNotFoundException
-import java.io.InputStreamReader
import java.security.InvalidParameterException
import kotlin.math.max
@@ -94,35 +89,6 @@
}
}
-private fun readPrefs(context: Context, fileName: String): UserStyleWireFormat {
- val hashMap = HashMap<String, ByteArray>()
- try {
- val reader = InputStreamReader(context.openFileInput(fileName)).buffered()
- reader.use {
- while (true) {
- val key = reader.readLine() ?: break
- val value = reader.readLine() ?: break
- hashMap[key] = Base64.decode(value, Base64.NO_WRAP)
- }
- }
- } catch (e: FileNotFoundException) {
- // We don't need to do anything special here.
- }
- return UserStyleWireFormat(hashMap)
-}
-
-private fun writePrefs(context: Context, fileName: String, style: UserStyle) {
- val writer = context.openFileOutput(fileName, Context.MODE_PRIVATE).bufferedWriter()
- writer.use {
- for ((key, value) in style.selectedOptions) {
- writer.write(key.id.value)
- writer.newLine()
- writer.write(Base64.encodeToString(value.id.value, Base64.NO_WRAP))
- writer.newLine()
- }
- }
-}
-
/**
* The return value of [WatchFaceService.createWatchFace] which brings together rendering, styling,
* complications and state observers.
@@ -241,7 +207,7 @@
* Interface for getting the current system time.
* @hide
*/
- @RestrictTo(LIBRARY_GROUP)
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public interface SystemTimeProvider {
/** Returns the current system time in milliseconds. */
public fun getSystemTimeMillis(): Long
@@ -370,7 +336,7 @@
}
/** @hide */
- @RestrictTo(LIBRARY_GROUP)
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public fun setSystemTimeProvider(systemTimeProvider: SystemTimeProvider): WatchFace = apply {
this.systemTimeProvider = systemTimeProvider
}
@@ -384,7 +350,12 @@
private val watchFaceHostApi: WatchFaceHostApi,
private val watchState: WatchState,
internal val currentUserStyleRepository: CurrentUserStyleRepository,
- internal var complicationsManager: ComplicationsManager
+ internal var complicationsManager: ComplicationsManager,
+
+ /** @hide */
+ @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @get:VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ public val calendar: Calendar
) {
internal companion object {
internal const val NO_DEFAULT_PROVIDER = SystemProviders.NO_PROVIDER
@@ -459,11 +430,6 @@
private var muteMode = false
private var nextDrawTimeMillis: Long = 0
- /** @hide */
- @RestrictTo(LIBRARY_GROUP)
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- public val calendar: Calendar = Calendar.getInstance()
-
private val pendingUpdateTime: CancellableUniqueTask =
CancellableUniqueTask(watchFaceHostApi.getUiThreadHandler())
@@ -602,35 +568,6 @@
}
init {
- // If the system has a stored user style then Home/SysUI is in charge of style
- // persistence, otherwise we need to do our own.
- val storedUserStyle = watchFaceHostApi.getInitialUserStyle()
- if (storedUserStyle != null) {
- TraceEvent("WatchFaceImpl.init apply userStyle").use {
- currentUserStyleRepository.userStyle =
- UserStyle(UserStyleData(storedUserStyle), currentUserStyleRepository.schema)
- }
- } else {
- TraceEvent("WatchFaceImpl.init apply userStyle from prefs").use {
- // The system doesn't support preference persistence we need to do it ourselves.
- val preferencesFile =
- "watchface_prefs_${watchFaceHostApi.getContext().javaClass.name}.txt"
-
- currentUserStyleRepository.userStyle = UserStyle(
- UserStyleData(readPrefs(watchFaceHostApi.getContext(), preferencesFile)),
- currentUserStyleRepository.schema
- )
-
- currentUserStyleRepository.addUserStyleChangeListener(
- object : CurrentUserStyleRepository.UserStyleChangeListener {
- @SuppressLint("SyntheticAccessor")
- override fun onUserStyleChanged(userStyle: UserStyle) {
- writePrefs(watchFaceHostApi.getContext(), preferencesFile, userStyle)
- }
- })
- }
- }
-
renderer.watchFaceHostApi = watchFaceHostApi
renderer.uiThreadInit()
@@ -640,34 +577,6 @@
}
)
- // We need to inhibit an immediate callback during initialization because members are not
- // fully constructed and it will fail. It's also superfluous because we're going to render
- // anyway.
- var initFinished = false
- complicationsManager.init(
- watchFaceHostApi, calendar, renderer,
- object : Complication.InvalidateListener {
- @SuppressWarnings("SyntheticAccessor")
- override fun onInvalidate() {
- // This could be called on any thread.
- watchFaceHostApi.getUiThreadHandler().runOnHandlerWithTracing("onInvalidate") {
- // Ensure we render a frame if the Complication needs rendering, e.g.
- // because it loaded an image. However if we're animating there's no need
- // to trigger an extra invalidation.
- if (initFinished && (
- !renderer.shouldAnimate() || computeDelayTillNextFrame(
- nextDrawTimeMillis,
- systemTimeProvider.getSystemTimeMillis()
- ) > MIN_PERCEPTABLE_DELAY_MILLIS
- )
- ) {
- watchFaceHostApi.invalidate()
- }
- }
- }
- }
- )
-
if (!watchState.isHeadless) {
WatchFace.registerEditorDelegate(componentName, WFEditorDelegate())
}
@@ -678,8 +587,19 @@
}
watchState.interruptionFilter.addObserver(interruptionFilterObserver)
watchState.isVisible.addObserver(visibilityObserver)
+ }
- initFinished = true
+ internal fun invalidateIfNotAnimating() {
+ // Ensure we render a frame if the Complication needs rendering, e.g.
+ // because it loaded an image. However if we're animating there's no need
+ // to trigger an extra invalidation.
+ if (!renderer.shouldAnimate() || computeDelayTillNextFrame(
+ nextDrawTimeMillis,
+ systemTimeProvider.getSystemTimeMillis()
+ ) > MIN_PERCEPTABLE_DELAY_MILLIS
+ ) {
+ watchFaceHostApi.invalidate()
+ }
}
internal fun createWFEditorDelegate() = WFEditorDelegate() as WatchFace.EditorDelegate
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
index 5b988bc..567c93a 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
@@ -22,6 +22,7 @@
import android.content.Intent
import android.graphics.Canvas
import android.graphics.Rect
+import android.icu.util.Calendar
import android.os.Build
import android.os.Bundle
import android.os.Handler
@@ -35,6 +36,7 @@
import android.support.wearable.watchface.IWatchFaceService
import android.support.wearable.watchface.accessibility.AccessibilityUtils
import android.support.wearable.watchface.accessibility.ContentDescriptionLabel
+import android.util.Base64
import android.util.Log
import android.view.Choreographer
import android.view.Surface
@@ -79,8 +81,9 @@
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.withContext
import java.io.FileDescriptor
+import java.io.FileNotFoundException
+import java.io.InputStreamReader
import java.io.PrintWriter
import java.util.concurrent.CountDownLatch
@@ -155,7 +158,8 @@
* [UserStyleSetting]. To enable support for styling override [createUserStyleSchema].
*
* WatchFaces are initially constructed on a background thread before being used exclusively on
- * the ui thread afterwards.
+ * the ui thread afterwards. There is a memory barrier between construction and rendering so no
+ * special threading primitives are required.
*
* To aid debugging watch face animations, WatchFaceService allows you to speed up or slow down
* time, and to loop between two instants. This is controlled by MOCK_TIME_INTENT intents
@@ -281,7 +285,8 @@
* library on the UiThread. If possible any expensive initialization should be done on a
* background thread to avoid blocking the UiThread. This will be called from a background
* thread but the [WatchFace] and its [Renderer] should be accessed exclusively from the
- * UiThread afterwards.
+ * UiThread afterwards. There is a memory barrier between construction and rendering so no
+ * special threading primitives are required.
*
* Warning watch face initialization will fail if createWatchFace takes longer than
* [MAX_CREATE_WATCHFACE_TIME_MILLIS] milliseconds.
@@ -316,8 +321,6 @@
/** This is open for testing. */
internal open fun getUiThreadHandlerImpl(): Handler = Handler(Looper.getMainLooper())
- internal var backgroundThread: HandlerThread? = null
-
/**
* Returns the lazily constructed background thread [Handler]. During initialization
* [createUserStyleSchema], [createComplicationsManager] and [createWatchFace] are posted on
@@ -325,16 +328,15 @@
*/
public fun getBackgroundThreadHandler(): Handler = getBackgroundThreadHandlerImpl()
- /** This is open for testing. */
- internal open fun getBackgroundThreadHandlerImpl(): Handler {
- if (backgroundThread == null) {
- backgroundThread = HandlerThread("WatchFaceBackground").apply {
- start()
- }
- }
- return Handler(backgroundThread!!.looper)
+ internal val backgroundThread = lazy {
+ HandlerThread("WatchFaceBackground").apply { start() }
}
+ private val _backgroundThreadHandler by lazy { Handler(backgroundThread.value.looper) }
+
+ /** This is open for testing. */
+ internal open fun getBackgroundThreadHandlerImpl() = _backgroundThreadHandler
+
/** This is open to allow mocking. */
internal open fun getMutableWatchState() = MutableWatchState()
@@ -358,6 +360,10 @@
attachBaseContext(context)
}
+ /**
+ * Reads WallpaperInteractiveWatchFaceInstanceParams from a file. This is only used in the
+ * android R flow.
+ */
internal open fun readDirectBootPrefs(
context: Context,
fileName: String
@@ -375,6 +381,10 @@
}
}
+ /**
+ * Writes WallpaperInteractiveWatchFaceInstanceParams to a file. This is only used in the
+ * android R flow.
+ */
internal open fun writeDirectBootPrefs(
context: Context,
fileName: String,
@@ -387,6 +397,37 @@
}
}
+ /** Reads user style from a file. This is only used in the pre-android R flow. */
+ internal fun readPrefs(context: Context, fileName: String): UserStyleWireFormat {
+ val hashMap = HashMap<String, ByteArray>()
+ try {
+ val reader = InputStreamReader(context.openFileInput(fileName)).buffered()
+ reader.use {
+ while (true) {
+ val key = reader.readLine() ?: break
+ val value = reader.readLine() ?: break
+ hashMap[key] = Base64.decode(value, Base64.NO_WRAP)
+ }
+ }
+ } catch (e: FileNotFoundException) {
+ // We don't need to do anything special here.
+ }
+ return UserStyleWireFormat(hashMap)
+ }
+
+ /** Reads the user style to a file. This is only used in the pre-android R flow. */
+ internal fun writePrefs(context: Context, fileName: String, style: UserStyle) {
+ val writer = context.openFileOutput(fileName, Context.MODE_PRIVATE).bufferedWriter()
+ writer.use {
+ for ((key, value) in style.selectedOptions) {
+ writer.write(key.id.value)
+ writer.newLine()
+ writer.write(Base64.encodeToString(value.id.value, Base64.NO_WRAP))
+ writer.newLine()
+ }
+ }
+ }
+
/** This is the old pre Android R flow that's needed for backwards compatibility. */
internal class WslFlow(private val engineWrapper: EngineWrapper) {
class PendingComplicationData(val complicationId: Int, val data: ComplicationData)
@@ -1032,7 +1073,9 @@
}
internal fun quitBackgroundThreadIfCreated() {
- backgroundThread?.quitSafely()
+ if (backgroundThread.isInitialized()) {
+ backgroundThread.value.quitSafely()
+ }
}
@UiThread
@@ -1293,9 +1336,12 @@
"milliseconds."
}
+ val calendar = Calendar.getInstance()
+ val initStyleAndComplicationsDone = CompletableDeferred<Unit>()
+
// WatchFaceImpl (which registers broadcast observers) needs to be constructed
// on the UIThread.
- withContext(uiThreadCoroutineScope.coroutineContext) {
+ uiThreadCoroutineScope.launch {
pendingInitialComplications?.let {
for (idAndData in it) {
complicationsManager.onComplicationDataUpdate(
@@ -1305,20 +1351,35 @@
}
}
- require(getUiThreadHandler().looper.isCurrentThread)
TraceEvent("WatchFaceImpl.init").use {
- deferredWatchFaceImpl.complete(
- WatchFaceImpl(
- watchFace,
- this@EngineWrapper,
- watchState,
- currentUserStyleRepository,
- complicationsManager
- )
+ val watchFaceImpl = WatchFaceImpl(
+ watchFace,
+ this@EngineWrapper,
+ watchState,
+ currentUserStyleRepository,
+ complicationsManager,
+ calendar
)
+
+ // Make sure no UI thread rendering (a consequence of completing
+ // deferredWatchFaceImpl) occurs before initStyleAndComplications has
+ // executed. NB usually we won't have to wait at all.
+ initStyleAndComplicationsDone.await()
+ deferredWatchFaceImpl.complete(watchFaceImpl)
asyncWatchFaceConstructionPending = false
}
}
+
+ // Perform more initialization on the background thread.
+ initStyleAndComplications(
+ complicationsManager,
+ currentUserStyleRepository,
+ watchFace.renderer,
+ calendar
+ )
+
+ // Now init has completed, it's OK to complete deferredWatchFaceImpl.
+ initStyleAndComplicationsDone.complete(Unit)
} catch (e: Exception) {
Log.e(TAG, "WatchFace crashed during init", e)
deferredWatchFaceImpl.completeExceptionally(e)
@@ -1326,6 +1387,68 @@
}
}
+ /**
+ * It is OK to call this from a worker thread because we carefully ensure there's no
+ * concurrent writes to the ComplicationsManager. No UI thread rendering can be done until
+ * after this has completed.
+ */
+ @WorkerThread
+ internal fun initStyleAndComplications(
+ complicationsManager: ComplicationsManager,
+ currentUserStyleRepository: CurrentUserStyleRepository,
+ renderer: Renderer,
+ calendar: Calendar
+ ) = TraceEvent("initStyleAndComplications").use {
+ // If the system has a stored user style then Home/SysUI is in charge of style
+ // persistence, otherwise we need to do our own.
+ val storedUserStyle = getInitialUserStyle()
+ if (storedUserStyle != null) {
+ TraceEvent("WatchFaceImpl.init apply userStyle").use {
+ currentUserStyleRepository.userStyle =
+ UserStyle(UserStyleData(storedUserStyle), currentUserStyleRepository.schema)
+ }
+ } else {
+ TraceEvent("WatchFaceImpl.init apply userStyle from prefs").use {
+ // The system doesn't support preference persistence we need to do it ourselves.
+ val preferencesFile = "watchface_prefs_${_context.javaClass.name}.txt"
+
+ currentUserStyleRepository.userStyle = UserStyle(
+ UserStyleData(readPrefs(_context, preferencesFile)),
+ currentUserStyleRepository.schema
+ )
+
+ currentUserStyleRepository.addUserStyleChangeListener(
+ object : CurrentUserStyleRepository.UserStyleChangeListener {
+ @SuppressLint("SyntheticAccessor")
+ override fun onUserStyleChanged(userStyle: UserStyle) {
+ writePrefs(_context, preferencesFile, userStyle)
+ }
+ }
+ )
+ }
+ }
+
+ // We need to inhibit an immediate callback during initialization because members are
+ // not fully constructed and it will fail. It's also superfluous because we're going
+ // to render soon anyway.
+ var initFinished = false
+ complicationsManager.init(
+ this, calendar, renderer,
+ object : Complication.InvalidateListener {
+ @SuppressWarnings("SyntheticAccessor")
+ override fun onInvalidate() {
+ // This could be called on any thread.
+ uiThreadHandler.runOnHandlerWithTracing("onInvalidate") {
+ if (initFinished) {
+ getWatchFaceImplOrNull()?.invalidateIfNotAnimating()
+ }
+ }
+ }
+ }
+ )
+ initFinished = true
+ }
+
override fun onVisibilityChanged(visible: Boolean): Unit = TraceEvent(
"onVisibilityChanged"
).use {
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchState.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchState.kt
index a32f6ce..d67a288 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchState.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchState.kt
@@ -20,6 +20,7 @@
import androidx.annotation.Px
import androidx.annotation.RestrictTo
import androidx.annotation.UiThread
+import androidx.wear.watchface.ObservableWatchData.MutableObservableWatchData
/**
* Describes the current state of the wearable including some hardware details such as whether or
diff --git a/wear/wear-watchface/src/test/java/androidx/wear/watchface/ObservableWatchDataTest.kt b/wear/wear-watchface/src/test/java/androidx/wear/watchface/ObservableWatchDataTest.kt
index b29815d..8f796dd 100644
--- a/wear/wear-watchface/src/test/java/androidx/wear/watchface/ObservableWatchDataTest.kt
+++ b/wear/wear-watchface/src/test/java/androidx/wear/watchface/ObservableWatchDataTest.kt
@@ -16,6 +16,7 @@
package androidx.wear.watchface
+import androidx.wear.watchface.ObservableWatchData.MutableObservableWatchData
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@@ -30,7 +31,7 @@
@Config(manifest = Config.NONE)
@RunWith(WatchFaceTestRunner::class)
-class ObservableWatchDataTest {
+public class ObservableWatchDataTest {
@Mock
private lateinit var observer: Observer<Int>
@@ -41,39 +42,39 @@
private lateinit var observer3: Observer<Int>
@Before
- fun setUp() {
+ public fun setUp() {
MockitoAnnotations.initMocks(this)
}
@Test
- fun initialValue() {
+ public fun initialValue() {
val data = MutableObservableWatchData(10)
assertThat(data.value).isEqualTo(10)
}
@Test
- fun mutatedValue() {
+ public fun mutatedValue() {
val data = MutableObservableWatchData(10)
data.value = 20
assertThat(data.value).isEqualTo(20)
}
@Test
- fun addObserverNoData() {
+ public fun addObserverNoData() {
val data = MutableObservableWatchData<Int>()
data.addObserver(observer)
verify(observer, never()).onChanged(any())
}
@Test
- fun addObserver() {
+ public fun addObserver() {
val data = MutableObservableWatchData(10)
data.addObserver(observer)
verify(observer).onChanged(10)
}
@Test
- fun addObserverAndAssign() {
+ public fun addObserverAndAssign() {
val data = MutableObservableWatchData(10)
data.addObserver(observer)
verify(observer).onChanged(10)
@@ -83,7 +84,7 @@
}
@Test
- fun addObserverNoDataThenAssign() {
+ public fun addObserverNoDataThenAssign() {
val data = MutableObservableWatchData<Int>()
data.addObserver(observer)
@@ -92,7 +93,7 @@
}
@Test
- fun addAndRemoveObserver() {
+ public fun addAndRemoveObserver() {
val data = MutableObservableWatchData(10)
data.addObserver(observer)
data.removeObserver(observer)
@@ -103,7 +104,7 @@
}
@Test
- fun removeObserverDuringCallback() {
+ public fun removeObserverDuringCallback() {
val data = MutableObservableWatchData(10)
data.addObserver(observer)
data.addObserver(observer2)
@@ -124,7 +125,7 @@
}
@Test
- fun addObserverInObserver() {
+ public fun addObserverInObserver() {
val data = MutableObservableWatchData(10)
var observersAdded = 0
var addedObserverObservations = 0