Merge "Remove Google compile testing from Room compiler" into androidx-main
diff --git a/activity/activity-lint/src/main/java/androidx/activity/lint/ActivityResultFragmentVersionDetector.kt b/activity/activity-lint/src/main/java/androidx/activity/lint/ActivityResultFragmentVersionDetector.kt
index 989efba4..2b809b3 100644
--- a/activity/activity-lint/src/main/java/androidx/activity/lint/ActivityResultFragmentVersionDetector.kt
+++ b/activity/activity-lint/src/main/java/androidx/activity/lint/ActivityResultFragmentVersionDetector.kt
@@ -195,7 +195,8 @@
 
         if (library.isNotEmpty()) {
             val currentVersion = library.substringAfter("androidx.fragment:fragment:")
-            if (library != currentVersion && FRAGMENT_VERSION.compareVersions(currentVersion)) {
+                .substringBeforeLast("-")
+            if (library != currentVersion && currentVersion < FRAGMENT_VERSION) {
                 locations.forEach { location ->
                     context.report(
                         ISSUE, expression, location,
@@ -221,12 +222,4 @@
         }
         return ""
     }
-
-    private fun String.compareVersions(other: String): Boolean {
-        return when {
-            length < other.length -> true
-            length > other.length -> false
-            else -> this > other
-        }
-    }
 }
diff --git a/activity/activity-lint/src/test/java/androidx/activity/lint/ActivityResultFragmentVersionDetectorTest.kt b/activity/activity-lint/src/test/java/androidx/activity/lint/ActivityResultFragmentVersionDetectorTest.kt
index 5686ef3..9c2cc3b 100644
--- a/activity/activity-lint/src/test/java/androidx/activity/lint/ActivityResultFragmentVersionDetectorTest.kt
+++ b/activity/activity-lint/src/test/java/androidx/activity/lint/ActivityResultFragmentVersionDetectorTest.kt
@@ -82,6 +82,78 @@
     }
 
     @Test
+    fun expectPassNewerStableVersion() {
+        lint().files(
+            kotlin(
+                """
+                package com.example
+
+                import androidx.activity.result.ActivityResultCaller
+                import androidx.activity.result.contract.ActivityResultContract
+
+                val launcher = ActivityResultCaller().registerForActivityResult(ActivityResultContract())
+            """
+            ),
+            gradle(
+                "build.gradle",
+                """
+                dependencies {
+                    api("androidx.fragment:fragment:1.4.0")
+                }
+            """
+            ).indented()
+        ).run().expectClean()
+    }
+
+    @Test
+    fun expectPassNewerSnapshotVersions() {
+        lint().files(
+            kotlin(
+                """
+                package com.example
+
+                import androidx.activity.result.ActivityResultCaller
+                import androidx.activity.result.contract.ActivityResultContract
+
+                val launcher = ActivityResultCaller().registerForActivityResult(ActivityResultContract())
+            """
+            ),
+            gradle(
+                "build.gradle",
+                """
+                dependencies {
+                    api("androidx.fragment:fragment:1.4.0-SNAPSHOT")
+                }
+            """
+            ).indented()
+        ).run().expectClean()
+    }
+
+    @Test
+    fun expectPassNewerAlphaVersions() {
+        lint().files(
+            kotlin(
+                """
+                package com.example
+
+                import androidx.activity.result.ActivityResultCaller
+                import androidx.activity.result.contract.ActivityResultContract
+
+                val launcher = ActivityResultCaller().registerForActivityResult(ActivityResultContract())
+            """
+            ),
+            gradle(
+                "build.gradle",
+                """
+                dependencies {
+                    api("androidx.fragment:fragment:1.4.0-alpha01")
+                }
+            """
+            ).indented()
+        ).run().expectClean()
+    }
+
+    @Test
     fun expectPassRegisterForActivityResultProject() {
         lint().files(
             kotlin(
@@ -112,7 +184,7 @@
             gradle(
                 """
                 dependencies {
-                    api("androidx.fragment:fragment:1.3.0-alpha05")
+                    api("androidx.fragment:fragment:1.2.4")
                 }
             """
             ),
@@ -144,7 +216,7 @@
             gradle(
                 """
                 dependencies {
-                    api("androidx.fragment:fragment:1.3.0-alpha05")
+                    api("androidx.fragment:fragment:1.2.4")
                 }
             """
             ),
@@ -180,7 +252,7 @@
             gradle(
                 """
                 dependencies {
-                    api("androidx.fragment:fragment:1.3.0-alpha05")
+                    api("androidx.fragment:fragment:1.2.4")
                 }
             """
             ),
@@ -232,14 +304,14 @@
                 "build.gradle",
                 """
                 dependencies {
-                    implementation("androidx.fragment:fragment-ktx:1.3.0-alpha05")
+                    implementation("androidx.fragment:fragment-ktx:1.2.4")
                 }
             """
             ).indented()
         ).withDependencyGraph(
             """
-                +--- androidx.fragment:fragment-ktx:1.3.0-alpha05
-                     \--- androidx.fragment:fragment:1.3.0-alpha05
+                +--- androidx.fragment:fragment-ktx:1.2.4
+                     \--- androidx.fragment:fragment:1.2.4
             """.trimIndent()
         )
 
diff --git a/appcompat/appcompat/src/main/res/values-ar/strings.xml b/appcompat/appcompat/src/main/res/values-ar/strings.xml
index 3613bd9..639b63b 100644
--- a/appcompat/appcompat/src/main/res/values-ar/strings.xml
+++ b/appcompat/appcompat/src/main/res/values-ar/strings.xml
@@ -31,7 +31,7 @@
     <string name="abc_activity_chooser_view_see_all" msgid="1189761859438369441">"عرض الكل"</string>
     <string name="abc_shareactionprovider_share_with_application" msgid="9055268688411532828">"مشاركة مع <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="abc_shareactionprovider_share_with" msgid="8875138169939072951">"مشاركة مع"</string>
-    <string name="abc_capital_on" msgid="884982626291842264">"تفعيل"</string>
+    <string name="abc_capital_on" msgid="884982626291842264">"مفعّلة"</string>
     <string name="abc_capital_off" msgid="4215997306490295099">"إيقاف"</string>
     <string name="search_menu_title" msgid="6264217191555673260">"البحث"</string>
     <string name="abc_prepend_shortcut_label" msgid="5520303668377388990">"القائمة+"</string>
diff --git a/appcompat/appcompat/src/main/res/values-nl/strings.xml b/appcompat/appcompat/src/main/res/values-nl/strings.xml
index 2a6959d..0e299d6 100644
--- a/appcompat/appcompat/src/main/res/values-nl/strings.xml
+++ b/appcompat/appcompat/src/main/res/values-nl/strings.xml
@@ -28,7 +28,7 @@
     <string name="abc_searchview_description_submit" msgid="1486535517437947103">"Zoekopdracht verzenden"</string>
     <string name="abc_searchview_description_voice" msgid="2293578557972875415">"Gesproken zoekopdracht"</string>
     <string name="abc_activitychooserview_choose_application" msgid="2165779757652331008">"Een app selecteren"</string>
-    <string name="abc_activity_chooser_view_see_all" msgid="1189761859438369441">"Alles weergeven"</string>
+    <string name="abc_activity_chooser_view_see_all" msgid="1189761859438369441">"Alles tonen"</string>
     <string name="abc_shareactionprovider_share_with_application" msgid="9055268688411532828">"Delen met <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="abc_shareactionprovider_share_with" msgid="8875138169939072951">"Delen met"</string>
     <string name="abc_capital_on" msgid="884982626291842264">"AAN"</string>
diff --git a/browser/browser/src/main/res/values-iw/strings.xml b/browser/browser/src/main/res/values-iw/strings.xml
index a0b8a11..f991a3ec 100644
--- a/browser/browser/src/main/res/values-iw/strings.xml
+++ b/browser/browser/src/main/res/values-iw/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="fallback_menu_item_open_in_browser" msgid="3413186855122069269">"פתיחה בדפדפן"</string>
-    <string name="fallback_menu_item_copy_link" msgid="4566929209979330987">"להעתקת הקישור"</string>
+    <string name="fallback_menu_item_copy_link" msgid="4566929209979330987">"העתקת הקישור"</string>
     <string name="fallback_menu_item_share_link" msgid="7145444925855055364">"לשיתוף הקישור"</string>
     <string name="copy_toast_msg" msgid="3260749812566568062">"הקישור הועתק ללוח"</string>
 </resources>
diff --git a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
index 937d8f7..623c266 100644
--- a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
@@ -35,11 +35,11 @@
     val BIOMETRIC = Version("1.2.0-alpha03")
     val BROWSER = Version("1.4.0-alpha01")
     val BUILDSRC_TESTS = Version("1.0.0-alpha01")
-    val CAMERA = Version("1.1.0-alpha03")
-    val CAMERA_EXTENSIONS = Version("1.0.0-alpha23")
+    val CAMERA = Version("1.1.0-alpha04")
+    val CAMERA_EXTENSIONS = Version("1.0.0-alpha24")
     val CAMERA_PIPE = Version("1.0.0-alpha01")
     val CAMERA_VIDEO = Version("1.0.0-alpha01")
-    val CAMERA_VIEW = Version("1.0.0-alpha23")
+    val CAMERA_VIEW = Version("1.0.0-alpha24")
     val CARDVIEW = Version("1.1.0-alpha01")
     val CAR_APP = Version("1.1.0-alpha01")
     // Pre-release before confirming to the same version as the rest of the CAR_APP library group.
diff --git a/busytown/androidx_incremental.sh b/busytown/androidx_incremental.sh
new file mode 120000
index 0000000..c2e0027
--- /dev/null
+++ b/busytown/androidx_incremental.sh
@@ -0,0 +1 @@
+androidx.sh
\ No newline at end of file
diff --git a/car/app/app-samples/helloworld/automotive/src/main/AndroidManifest.xml b/car/app/app-samples/helloworld/automotive/src/main/AndroidManifest.xml
index 6fa3c62..f47864d 100644
--- a/car/app/app-samples/helloworld/automotive/src/main/AndroidManifest.xml
+++ b/car/app/app-samples/helloworld/automotive/src/main/AndroidManifest.xml
@@ -19,7 +19,10 @@
     package="androidx.car.app.sample.helloworld"
     android:versionCode="1"
     android:versionName="1.0">
-  <application
+
+    <uses-feature android:name="android.software.car.templates_host" />
+
+    <application
       android:label="@string/app_name"
       android:icon="@drawable/ic_launcher">
     <meta-data android:name="com.google.android.gms.car.application"
diff --git a/car/app/app-samples/navigation/automotive/src/main/AndroidManifest.xml b/car/app/app-samples/navigation/automotive/src/main/AndroidManifest.xml
index 14ec293..07bbd24 100644
--- a/car/app/app-samples/navigation/automotive/src/main/AndroidManifest.xml
+++ b/car/app/app-samples/navigation/automotive/src/main/AndroidManifest.xml
@@ -28,7 +28,9 @@
   <uses-permission android:name="androidx.car.app.ACCESS_SURFACE"/>
   <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
 
-  <application
+  <uses-feature android:name="android.software.car.templates_host" />
+
+    <application
       android:label="@string/app_name"
       android:icon="@drawable/ic_launcher">
 
diff --git a/car/app/app-samples/places/automotive/src/main/AndroidManifest.xml b/car/app/app-samples/places/automotive/src/main/AndroidManifest.xml
index 48d79ae..9ea01b1 100644
--- a/car/app/app-samples/places/automotive/src/main/AndroidManifest.xml
+++ b/car/app/app-samples/places/automotive/src/main/AndroidManifest.xml
@@ -27,6 +27,8 @@
   <!-- For PlaceListMapTemplate -->
   <uses-permission android:name="androidx.car.app.MAP_TEMPLATES"/>
 
+  <uses-feature android:name="android.software.car.templates_host" />
+
   <application
       android:label="@string/app_name"
       android:icon="@drawable/ic_launcher">
diff --git a/car/app/app-samples/showcase/automotive/src/main/AndroidManifest.xml b/car/app/app-samples/showcase/automotive/src/main/AndroidManifest.xml
index fd89d70..5870edc 100644
--- a/car/app/app-samples/showcase/automotive/src/main/AndroidManifest.xml
+++ b/car/app/app-samples/showcase/automotive/src/main/AndroidManifest.xml
@@ -32,6 +32,8 @@
   <uses-permission android:name="androidx.car.app.NAVIGATION_TEMPLATES"/>
   <uses-permission android:name="androidx.car.app.ACCESS_SURFACE"/>
 
+  <uses-feature android:name="android.software.car.templates_host" />
+
   <application
       android:label="@string/app_name"
       android:icon="@drawable/ic_launcher">
diff --git a/compose/ui/ui/api/1.0.0-beta05.txt b/compose/ui/ui/api/1.0.0-beta05.txt
index a926e4a..ce5c32e 100644
--- a/compose/ui/ui/api/1.0.0-beta05.txt
+++ b/compose/ui/ui/api/1.0.0-beta05.txt
@@ -2396,6 +2396,9 @@
     method public operator <T> void set(androidx.compose.ui.semantics.SemanticsPropertyKey<T> key, T? value);
   }
 
+  public final class SemanticsSortKt {
+  }
+
 }
 
 package androidx.compose.ui.state {
diff --git a/compose/ui/ui/api/current.txt b/compose/ui/ui/api/current.txt
index a926e4a..ce5c32e 100644
--- a/compose/ui/ui/api/current.txt
+++ b/compose/ui/ui/api/current.txt
@@ -2396,6 +2396,9 @@
     method public operator <T> void set(androidx.compose.ui.semantics.SemanticsPropertyKey<T> key, T? value);
   }
 
+  public final class SemanticsSortKt {
+  }
+
 }
 
 package androidx.compose.ui.state {
diff --git a/compose/ui/ui/api/public_plus_experimental_1.0.0-beta05.txt b/compose/ui/ui/api/public_plus_experimental_1.0.0-beta05.txt
index d101503..6383220 100644
--- a/compose/ui/ui/api/public_plus_experimental_1.0.0-beta05.txt
+++ b/compose/ui/ui/api/public_plus_experimental_1.0.0-beta05.txt
@@ -2535,6 +2535,9 @@
     method public operator <T> void set(androidx.compose.ui.semantics.SemanticsPropertyKey<T> key, T? value);
   }
 
+  public final class SemanticsSortKt {
+  }
+
 }
 
 package androidx.compose.ui.state {
diff --git a/compose/ui/ui/api/public_plus_experimental_current.txt b/compose/ui/ui/api/public_plus_experimental_current.txt
index d101503..6383220 100644
--- a/compose/ui/ui/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui/api/public_plus_experimental_current.txt
@@ -2535,6 +2535,9 @@
     method public operator <T> void set(androidx.compose.ui.semantics.SemanticsPropertyKey<T> key, T? value);
   }
 
+  public final class SemanticsSortKt {
+  }
+
 }
 
 package androidx.compose.ui.state {
diff --git a/compose/ui/ui/api/restricted_1.0.0-beta05.txt b/compose/ui/ui/api/restricted_1.0.0-beta05.txt
index 8864bcd..313e7c8 100644
--- a/compose/ui/ui/api/restricted_1.0.0-beta05.txt
+++ b/compose/ui/ui/api/restricted_1.0.0-beta05.txt
@@ -2426,6 +2426,9 @@
     method public operator <T> void set(androidx.compose.ui.semantics.SemanticsPropertyKey<T> key, T? value);
   }
 
+  public final class SemanticsSortKt {
+  }
+
 }
 
 package androidx.compose.ui.state {
diff --git a/compose/ui/ui/api/restricted_current.txt b/compose/ui/ui/api/restricted_current.txt
index 8864bcd..313e7c8 100644
--- a/compose/ui/ui/api/restricted_current.txt
+++ b/compose/ui/ui/api/restricted_current.txt
@@ -2426,6 +2426,9 @@
     method public operator <T> void set(androidx.compose.ui.semantics.SemanticsPropertyKey<T> key, T? value);
   }
 
+  public final class SemanticsSortKt {
+  }
+
 }
 
 package androidx.compose.ui.state {
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/semantics/SemanticsTests.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/semantics/SemanticsTests.kt
index 3528238..b76d2e9 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/semantics/SemanticsTests.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/semantics/SemanticsTests.kt
@@ -17,14 +17,25 @@
 package androidx.compose.ui.semantics
 
 import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.offset
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.requiredSize
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.Stable
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.layout.Layout
 import androidx.compose.ui.layout.MeasurePolicy
+import androidx.compose.ui.layout.SubcomposeLayout
 import androidx.compose.ui.platform.InspectableValue
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.LocalLayoutDirection
 import androidx.compose.ui.platform.ValueElement
 import androidx.compose.ui.platform.isDebugInspectorInfoEnabled
 import androidx.compose.ui.platform.testTag
@@ -41,6 +52,11 @@
 import androidx.compose.ui.test.onNodeWithContentDescription
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.util.fastForEach
+import androidx.compose.ui.util.fastMap
 import androidx.compose.ui.zIndex
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
@@ -702,7 +718,7 @@
         val child2 = "child2"
         rule.setContent {
             SimpleTestLayout(
-                Modifier.testTag(TestTag).semantics {}
+                Modifier.testTag(TestTag)
             ) {
                 SimpleTestLayout(
                     Modifier.zIndex(1f).semantics { contentDescription = child1 }
@@ -722,6 +738,437 @@
             root.children[1].config.getOrNull(SemanticsProperties.ContentDescription)
         )
     }
+
+    @Test
+    fun testChildrenSortedByBounds_vertical_zIndex() {
+        val child1 = "child1"
+        val child2 = "child2"
+        rule.setContent {
+            Column(
+                Modifier.testTag(TestTag)
+            ) {
+                SimpleTestLayout(
+                    Modifier
+                        .requiredSize(50.dp)
+                        .zIndex(1f)
+                        .semantics { contentDescription = child1 }
+                ) {}
+                SimpleTestLayout(
+                    Modifier.requiredSize(50.dp).semantics { contentDescription = child2 }
+                ) {}
+            }
+        }
+
+        val root = rule.onNodeWithTag(TestTag).fetchSemanticsNode("can't find node $TestTag")
+        assertEquals(2, root.childrenSortedByBounds.size)
+        assertEquals(
+            child1,
+            root.childrenSortedByBounds[0].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+        assertEquals(
+            child2,
+            root.childrenSortedByBounds[1].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+    }
+
+    @Test
+    fun testChildrenSortedByBounds_horizontal_zIndex() {
+        val child1 = "child1"
+        val child2 = "child2"
+        rule.setContent {
+            Row(
+                Modifier.testTag(TestTag)
+            ) {
+                SimpleTestLayout(
+                    Modifier
+                        .requiredSize(50.dp)
+                        .zIndex(1f)
+                        .semantics { contentDescription = child1 }
+                ) {}
+                SimpleTestLayout(
+                    Modifier.requiredSize(50.dp).semantics { contentDescription = child2 }
+                ) {}
+            }
+        }
+
+        val root = rule.onNodeWithTag(TestTag).fetchSemanticsNode("can't find node $TestTag")
+        assertEquals(2, root.childrenSortedByBounds.size)
+        assertEquals(
+            child1,
+            root.childrenSortedByBounds[0].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+        assertEquals(
+            child2,
+            root.childrenSortedByBounds[1].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+    }
+
+    @Test
+    fun testChildrenSortedByBounds_vertical_offset() {
+        val child1 = "child1"
+        val child2 = "child2"
+        rule.setContent {
+            Box(
+                Modifier.testTag(TestTag)
+            ) {
+                SimpleTestLayout(
+                    Modifier
+                        .requiredSize(50.dp)
+                        .offset(x = 0.dp, y = 50.dp)
+                        .semantics { contentDescription = child1 }
+                ) {}
+                SimpleTestLayout(
+                    Modifier.requiredSize(50.dp).semantics { contentDescription = child2 }
+                ) {}
+            }
+        }
+
+        val root = rule.onNodeWithTag(TestTag).fetchSemanticsNode("can't find node $TestTag")
+        assertEquals(2, root.childrenSortedByBounds.size)
+        assertEquals(
+            child2,
+            root.childrenSortedByBounds[0].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+        assertEquals(
+            child1,
+            root.childrenSortedByBounds[1].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+    }
+
+    @Test
+    fun testChildrenSortedByBounds_horizontal_offset() {
+        val child1 = "child1"
+        val child2 = "child2"
+        rule.setContent {
+            Box(
+                Modifier.testTag(TestTag)
+            ) {
+                SimpleTestLayout(
+                    Modifier
+                        .requiredSize(50.dp)
+                        .offset(x = 50.dp, y = 0.dp)
+                        .semantics { contentDescription = child1 }
+                ) {}
+                SimpleTestLayout(
+                    Modifier.requiredSize(50.dp).semantics { contentDescription = child2 }
+                ) {}
+            }
+        }
+
+        val root = rule.onNodeWithTag(TestTag).fetchSemanticsNode("can't find node $TestTag")
+        assertEquals(2, root.childrenSortedByBounds.size)
+        assertEquals(
+            child2,
+            root.childrenSortedByBounds[0].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+        assertEquals(
+            child1,
+            root.childrenSortedByBounds[1].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+    }
+
+    @Test
+    fun testChildrenSortedByBounds_vertical_offset_overlapped() {
+        val child1 = "child1"
+        val child2 = "child2"
+        rule.setContent {
+            Box(
+                Modifier.testTag(TestTag)
+            ) {
+                SimpleTestLayout(
+                    Modifier
+                        .requiredSize(50.dp)
+                        .offset(x = 0.dp, y = 20.dp)
+                        .semantics { contentDescription = child1 }
+                ) {}
+                SimpleTestLayout(
+                    Modifier.requiredSize(50.dp).semantics { contentDescription = child2 }
+                ) {}
+            }
+        }
+
+        val root = rule.onNodeWithTag(TestTag).fetchSemanticsNode("can't find node $TestTag")
+        assertEquals(2, root.childrenSortedByBounds.size)
+        assertEquals(
+            child2,
+            root.childrenSortedByBounds[0].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+        assertEquals(
+            child1,
+            root.childrenSortedByBounds[1].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+    }
+
+    @Test
+    fun testChildrenSortedByBounds_horizontal_offset_overlapped() {
+        val child1 = "child1"
+        val child2 = "child2"
+        rule.setContent {
+            Box(
+                Modifier.testTag(TestTag)
+            ) {
+                SimpleTestLayout(
+                    Modifier
+                        .requiredSize(50.dp)
+                        .offset(x = 20.dp, y = 0.dp)
+                        .semantics { contentDescription = child1 }
+                ) {}
+                SimpleTestLayout(
+                    Modifier
+                        .requiredSize(50.dp)
+                        .offset(x = 0.dp, y = 20.dp)
+                        .semantics { contentDescription = child2 }
+                ) {}
+            }
+        }
+
+        val root = rule.onNodeWithTag(TestTag).fetchSemanticsNode("can't find node $TestTag")
+        assertEquals(2, root.childrenSortedByBounds.size)
+        assertEquals(
+            child2,
+            root.childrenSortedByBounds[0].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+        assertEquals(
+            child1,
+            root.childrenSortedByBounds[1].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+    }
+
+    @Test
+    fun testChildrenSortedByBounds_vertical_offset_overlapped_withPadding() {
+        val child1 = "child1"
+        val child2 = "child2"
+        rule.setContent {
+            Box(
+                Modifier.testTag(TestTag)
+            ) {
+                SimpleTestLayout(
+                    Modifier
+                        .requiredSize(100.dp)
+                        .offset(x = 25.dp, y = 20.dp)
+                        .semantics { contentDescription = child1 }
+                ) {}
+                SimpleTestLayout(
+                    Modifier
+                        .requiredSize(100.dp)
+                        .padding(25.dp)
+                        .semantics { contentDescription = child2 }
+                ) {}
+            }
+        }
+
+        val root = rule.onNodeWithTag(TestTag).fetchSemanticsNode("can't find node $TestTag")
+        assertEquals(2, root.childrenSortedByBounds.size)
+        assertEquals(
+            child1,
+            root.childrenSortedByBounds[0].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+        assertEquals(
+            child2,
+            root.childrenSortedByBounds[1].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+    }
+
+    @Test
+    fun testChildrenSortedByBounds_horizontal_offset_overlapped_withPadding() {
+        val child1 = "child1"
+        val child2 = "child2"
+        rule.setContent {
+            Box(
+                Modifier.testTag(TestTag)
+            ) {
+                SimpleTestLayout(
+                    Modifier
+                        .requiredSize(100.dp)
+                        .offset(x = 20.dp, y = 25.dp)
+                        .semantics { contentDescription = child1 }
+                ) {}
+                SimpleTestLayout(
+                    Modifier
+                        .requiredSize(100.dp)
+                        .padding(25.dp)
+                        .semantics { contentDescription = child2 }
+                ) {}
+            }
+        }
+
+        val root = rule.onNodeWithTag(TestTag).fetchSemanticsNode("can't find node $TestTag")
+        assertEquals(2, root.childrenSortedByBounds.size)
+        assertEquals(
+            child1,
+            root.childrenSortedByBounds[0].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+        assertEquals(
+            child2,
+            root.childrenSortedByBounds[1].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+    }
+
+    @Test
+    fun testChildrenSortedByBounds_vertical_subcompose() {
+        val child1 = "child1"
+        val child2 = "child2"
+        val density = Density(1f)
+        val size = with(density) { 100.dp.roundToPx() }.toFloat()
+        rule.setContent {
+            CompositionLocalProvider(LocalDensity provides density) {
+                SimpleSubcomposeLayout(
+                    Modifier.testTag(TestTag),
+                    {
+                        SimpleTestLayout(
+                            Modifier
+                                .requiredSize(100.dp)
+                                .semantics { contentDescription = child1 }
+                        ) {}
+                    },
+                    Offset(0f, size),
+                    {
+                        SimpleTestLayout(
+                            Modifier
+                                .requiredSize(100.dp)
+                                .semantics { contentDescription = child2 }
+                        ) {}
+                    },
+                    Offset(0f, 0f)
+                )
+            }
+        }
+
+        val root = rule.onNodeWithTag(TestTag).fetchSemanticsNode("can't find node $TestTag")
+        assertEquals(2, root.childrenSortedByBounds.size)
+        assertEquals(
+            child2,
+            root.childrenSortedByBounds[0].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+        assertEquals(
+            child1,
+            root.childrenSortedByBounds[1].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+    }
+
+    @Test
+    fun testChildrenSortedByBounds_horizontal_subcompose() {
+        val child1 = "child1"
+        val child2 = "child2"
+        val density = Density(1f)
+        val size = with(density) { 100.dp.roundToPx() }.toFloat()
+        rule.setContent {
+            CompositionLocalProvider(LocalDensity provides density) {
+                SimpleSubcomposeLayout(
+                    Modifier.testTag(TestTag),
+                    {
+                        SimpleTestLayout(
+                            Modifier
+                                .requiredSize(100.dp)
+                                .semantics { contentDescription = child1 }
+                        ) {}
+                    },
+                    Offset(size, 0f),
+                    {
+                        SimpleTestLayout(
+                            Modifier
+                                .requiredSize(100.dp)
+                                .semantics { contentDescription = child2 }
+                        ) {}
+                    },
+                    Offset(0f, 0f)
+                )
+            }
+        }
+
+        val root = rule.onNodeWithTag(TestTag).fetchSemanticsNode("can't find node $TestTag")
+        assertEquals(2, root.childrenSortedByBounds.size)
+        assertEquals(
+            child2,
+            root.childrenSortedByBounds[0].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+        assertEquals(
+            child1,
+            root.childrenSortedByBounds[1].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+    }
+
+    @Test
+    fun testChildrenSortedByBounds_rtl() {
+        val child1 = "child1"
+        val child2 = "child2"
+        val child3 = "child3"
+        val rtlChild1 = "rtlChild1"
+        val rtlChild2 = "rtlChild2"
+        val rtlChild3 = "rtlChild3"
+        rule.setContent {
+            Column(Modifier.testTag(TestTag)) {
+                Row {
+                    SimpleTestLayout(
+                        Modifier
+                            .requiredSize(100.dp)
+                            .semantics { contentDescription = child1 }
+                    ) {}
+                    SimpleTestLayout(
+                        Modifier
+                            .requiredSize(100.dp)
+                            .semantics { contentDescription = child2 }
+                    ) {}
+                    SimpleTestLayout(
+                        Modifier
+                            .requiredSize(100.dp)
+                            .semantics { contentDescription = child3 }
+                    ) {}
+                }
+                CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) {
+                    // Will display rtlChild3 rtlChild2 rtlChild1
+                    Row {
+                        SimpleTestLayout(
+                            Modifier
+                                .requiredSize(100.dp)
+                                .semantics { contentDescription = rtlChild1 }
+                        ) {}
+                        SimpleTestLayout(
+                            Modifier
+                                .requiredSize(100.dp)
+                                .semantics { contentDescription = rtlChild2 }
+                        ) {}
+                        SimpleTestLayout(
+                            Modifier
+                                .requiredSize(100.dp)
+                                .semantics { contentDescription = rtlChild3 }
+                        ) {}
+                    }
+                }
+            }
+        }
+
+        val root = rule.onNodeWithTag(TestTag).fetchSemanticsNode("can't find node $TestTag")
+        assertEquals(6, root.childrenSortedByBounds.size)
+
+        // Ltr
+        assertEquals(
+            child1,
+            root.childrenSortedByBounds[0].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+        assertEquals(
+            child2,
+            root.childrenSortedByBounds[1].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+        assertEquals(
+            child3,
+            root.childrenSortedByBounds[2].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+
+        // Rtl
+        assertEquals(
+            rtlChild1,
+            root.childrenSortedByBounds[3].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+        assertEquals(
+            rtlChild2,
+            root.childrenSortedByBounds[4].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+        assertEquals(
+            rtlChild3,
+            root.childrenSortedByBounds[5].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+    }
 }
 
 private fun SemanticsNodeInteraction.assertDoesNotHaveProperty(property: SemanticsPropertyKey<*>) {
@@ -788,3 +1235,45 @@
         }
     }
 }
+
+/**
+ * A simple SubComposeLayout which lays [contentOne] at [positionOne] and lays [contentTwo] at
+ * [positionTwo]. [contentOne] is placed first and [contentTwo] is placed second. Therefore, the
+ * semantics node for [contentOne] is before semantics node for [contentTwo] in
+ * [SemanticsNode.children].
+ */
+@Composable
+private fun SimpleSubcomposeLayout(
+    modifier: Modifier = Modifier,
+    contentOne: @Composable () -> Unit,
+    positionOne: Offset,
+    contentTwo: @Composable () -> Unit,
+    positionTwo: Offset
+) {
+    SubcomposeLayout(modifier) { constraints ->
+        val layoutWidth = constraints.maxWidth
+        val layoutHeight = constraints.maxHeight
+
+        val looseConstraints = constraints.copy(minWidth = 0, minHeight = 0)
+
+        layout(layoutWidth, layoutHeight) {
+            val placeablesOne = subcompose(TestSlot.First, contentOne).fastMap {
+                it.measure(looseConstraints)
+            }
+
+            val placeablesTwo = subcompose(TestSlot.Second, contentTwo).fastMap {
+                it.measure(looseConstraints)
+            }
+
+            // Placing to control drawing order to match default elevation of each placeable
+            placeablesOne.fastForEach {
+                it.place(positionOne.x.toInt(), positionOne.y.toInt())
+            }
+            placeablesTwo.fastForEach {
+                it.place(positionTwo.x.toInt(), positionTwo.y.toInt())
+            }
+        }
+    }
+}
+
+private enum class TestSlot { First, Second }
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
index febefb3..cb3b8ea 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
@@ -295,7 +295,7 @@
         }
         info.packageName = view.context.packageName
 
-        semanticsNode.children.fastForEach { child ->
+        semanticsNode.childrenSortedByBounds.fastForEach { child ->
             if (currentSemanticsNodes.contains(child.id)) {
                 val holder = view.androidViewsHandler.layoutNodeToHolder[child.layoutNode]
                 if (holder != null) {
@@ -1991,7 +1991,7 @@
         fun concatenateChildrenContentDescriptionAndText(node: SemanticsNode): List<String> {
             val childDescriptions = mutableListOf<String>()
 
-            node.unmergedChildren().fastForEach { childNode ->
+            node.unmergedChildren(true).fastForEach { childNode ->
                 // Don't merge child that merges its children because that child node will be focused
                 // separately
                 if (childNode.unmergedConfig.isMergingSemanticsOfDescendants) {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsNode.kt
index f131652..024cf1c 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsNode.kt
@@ -142,7 +142,7 @@
      * In addition, if mergeDescendants and mergingEnabled are both true, then it
      * also includes the semantics properties of descendant nodes.
      */
-    // TODO(aelias): This is too expensive for a val (full subtree recreation every call);
+    // TODO(b/184376083): This is too expensive for a val (full subtree recreation every call);
     //               optimize this when the merging algorithm is improved.
     val config: SemanticsConfiguration
         get() {
@@ -171,10 +171,14 @@
     private val isMergingSemanticsOfDescendants: Boolean
         get() = mergingEnabled && unmergedConfig.isMergingSemanticsOfDescendants
 
-    internal fun unmergedChildren(): List<SemanticsNode> {
+    internal fun unmergedChildren(sortByBounds: Boolean = false): List<SemanticsNode> {
         val unmergedChildren: MutableList<SemanticsNode> = mutableListOf()
 
-        val semanticsChildren = this.layoutNode.findOneLayerOfSemanticsWrappers()
+        val semanticsChildren = if (sortByBounds) {
+            this.layoutNode.findOneLayerOfSemanticsWrappersSortedByBounds()
+        } else {
+            this.layoutNode.findOneLayerOfSemanticsWrappers()
+        }
         semanticsChildren.fastForEach { semanticsChild ->
             unmergedChildren.add(SemanticsNode(semanticsChild, mergingEnabled))
         }
@@ -182,30 +186,45 @@
         return unmergedChildren
     }
 
-    /** Contains the children in inverse hit test order (i.e. paint order).
+    /**
+     * Contains the children in inverse hit test order (i.e. paint order).
      *
      * Note that if mergingEnabled and mergeDescendants are both true, then there
      * are no children (except those that are themselves mergeDescendants).
      */
-    // TODO(aelias): This is too expensive for a val (full subtree recreation every call);
+    // TODO(b/184376083): This is too expensive for a val (full subtree recreation every call);
     //               optimize this when the merging algorithm is improved.
     val children: List<SemanticsNode>
-        get() {
-            // Replacing semantics never appear to have any children in the merged tree.
-            if (mergingEnabled && unmergedConfig.isClearingSemantics) {
-                return listOf()
-            }
+        get() = getChildren(sortByBounds = false)
 
-            if (isMergingSemanticsOfDescendants) {
-                // In most common merging scenarios like Buttons, this will return nothing.
-                // In cases like a clickable Row itself containing a Button, this will
-                // return the Button as a child.
-                return findOneLayerOfMergingSemanticsNodes()
-            }
+    /**
+     * Contains the children sorted by bounds: top to down, left to right(right to left in RTL
+     * mode).
+     *
+     * Note that if mergingEnabled and mergeDescendants are both true, then there
+     * are no children (except those that are themselves mergeDescendants).
+     */
+    // TODO(b/184376083): This is too expensive for a val (full subtree recreation every call);
+    //               optimize this when the merging algorithm is improved.
+    internal val childrenSortedByBounds: List<SemanticsNode>
+        get() = getChildren(sortByBounds = true)
 
-            return unmergedChildren()
+    private fun getChildren(sortByBounds: Boolean): List<SemanticsNode> {
+        // Replacing semantics never appear to have any children in the merged tree.
+        if (mergingEnabled && unmergedConfig.isClearingSemantics) {
+            return listOf()
         }
 
+        if (isMergingSemanticsOfDescendants) {
+            // In most common merging scenarios like Buttons, this will return nothing.
+            // In cases like a clickable Row itself containing a Button, this will
+            // return the Button as a child.
+            return findOneLayerOfMergingSemanticsNodes(sortByBounds = sortByBounds)
+        }
+
+        return unmergedChildren(sortByBounds)
+    }
+
     /**
      * Visits the immediate children of this node.
      *
@@ -264,13 +283,14 @@
         }
 
     private fun findOneLayerOfMergingSemanticsNodes(
-        list: MutableList<SemanticsNode> = mutableListOf<SemanticsNode>()
+        list: MutableList<SemanticsNode> = mutableListOf(),
+        sortByBounds: Boolean = false
     ): List<SemanticsNode> {
-        unmergedChildren().fastForEach { child ->
-            if (child.isMergingSemanticsOfDescendants == true) {
+        unmergedChildren(sortByBounds).fastForEach { child ->
+            if (child.isMergingSemanticsOfDescendants) {
                 list.add(child)
             } else {
-                if (child.unmergedConfig.isClearingSemantics == false) {
+                if (!child.unmergedConfig.isClearingSemantics) {
                     child.findOneLayerOfMergingSemanticsNodes(list)
                 }
             }
@@ -328,7 +348,7 @@
 }
 
 private fun LayoutNode.findOneLayerOfSemanticsWrappers(
-    list: MutableList<SemanticsWrapper> = mutableListOf<SemanticsWrapper>()
+    list: MutableList<SemanticsWrapper> = mutableListOf()
 ): List<SemanticsWrapper> {
     zSortedChildren.forEach { child ->
         val outerSemantics = child.outerSemantics
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsSort.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsSort.kt
new file mode 100644
index 0000000..10d921f
--- /dev/null
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsSort.kt
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.ui.semantics
+
+import androidx.compose.ui.layout.boundsInRoot
+import androidx.compose.ui.node.LayoutNode
+import androidx.compose.ui.node.LayoutNodeWrapper
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.util.fastForEach
+import androidx.compose.ui.util.fastMap
+
+// This part is a copy from ViewGroup#addChildrenForAccessibility.
+internal fun LayoutNode.findOneLayerOfSemanticsWrappersSortedByBounds(
+    list: MutableList<SemanticsWrapper> = mutableListOf()
+): List<SemanticsWrapper> {
+    fun sortWithStrategy(holders: List<NodeLocationHolder>): List<NodeLocationHolder> {
+        // This is gross but the least risky solution. The current comparison
+        // strategy breaks transitivity but produces very good results. Coming
+        // up with a new strategy requires time which we do not have, so ...
+        return try {
+            NodeLocationHolder.comparisonStrategy = NodeLocationHolder.ComparisonStrategy.Stripe
+            holders.toMutableList().apply { sort() }
+        } catch (iae: IllegalArgumentException) {
+            // Note that in practice this occurs extremely rarely in a couple
+            // of pathological cases.
+            NodeLocationHolder.comparisonStrategy = NodeLocationHolder.ComparisonStrategy.Location
+            holders.toMutableList().apply { sort() }
+        }
+    }
+
+    val holders = children.fastMap { NodeLocationHolder(this, it) }
+    val sortedChildren = sortWithStrategy(holders).fastMap { it.node }
+
+    sortedChildren.fastForEach { child ->
+        val outerSemantics = child.outerSemantics
+        if (outerSemantics != null) {
+            list.add(outerSemantics)
+        } else {
+            child.findOneLayerOfSemanticsWrappersSortedByBounds(list)
+        }
+    }
+    return list
+}
+
+internal class NodeLocationHolder internal constructor(
+    internal val subtreeRoot: LayoutNode,
+    internal val node: LayoutNode
+) : Comparable<NodeLocationHolder> {
+    internal companion object {
+        internal var comparisonStrategy = ComparisonStrategy.Stripe
+    }
+
+    internal enum class ComparisonStrategy { Stripe, Location }
+
+    private val location =
+        subtreeRoot.innerLayoutNodeWrapper.localBoundingBoxOf(node.findWrapperToGetBounds())
+    private val layoutDirection = subtreeRoot.layoutDirection
+
+    override fun compareTo(other: NodeLocationHolder): Int {
+        if (comparisonStrategy == ComparisonStrategy.Stripe) {
+            // First is above second.
+            if (location.bottom - other.location.top <= 0) {
+                return -1
+            }
+            // First is below second.
+            if (location.top - other.location.bottom >= 0) {
+                return 1
+            }
+        }
+
+        // We are ordering left-to-right, top-to-bottom.
+        if (layoutDirection == LayoutDirection.Ltr) {
+            val leftDifference = location.left - other.location.left
+            if (leftDifference != 0f) {
+                return if (leftDifference < 0) -1 else 1
+            }
+        } else { // RTL
+            val rightDifference = location.right - other.location.right
+            if (rightDifference != 0f) {
+                return if (rightDifference < 0) 1 else -1
+            }
+        }
+        // We are ordering left-to-right, top-to-bottom.
+        val topDifference = location.top - other.location.top
+        if (topDifference != 0f) {
+            return if (topDifference < 0) -1 else 1
+        }
+        // Break tie by height.
+        val heightDifference = location.height - other.location.height
+        if (heightDifference != 0f) {
+            return if (heightDifference < 0) 1 else -1
+        }
+        // Break tie by width.
+        val widthDifference = location.width - other.location.width
+        if (widthDifference != 0f) {
+            return if (widthDifference < 0) 1 else -1
+        }
+
+        // Find a child of each view with different screen bounds.
+        val view1Bounds = node.findWrapperToGetBounds().boundsInRoot()
+        val view2Bounds = other.node.findWrapperToGetBounds().boundsInRoot()
+        val child1 = node.findNodeByPredicateTraversal {
+            val tempRect = it.findWrapperToGetBounds().boundsInRoot()
+            view1Bounds != tempRect
+        }
+        val child2 = other.node.findNodeByPredicateTraversal {
+            val tempRect = it.findWrapperToGetBounds().boundsInRoot()
+            view2Bounds != tempRect
+        }
+        // Compare the children recursively
+        if ((child1 != null) && (child2 != null)) {
+            val childHolder1 = NodeLocationHolder(subtreeRoot, child1)
+            val childHolder2 = NodeLocationHolder(other.subtreeRoot, child2)
+            return childHolder1.compareTo(childHolder2)
+        }
+
+        // If only one has a child, use that one
+        if (child1 != null) {
+            return 1
+        }
+
+        if (child2 != null) {
+            return -1
+        }
+
+        // Break tie somehow
+        return -1
+    }
+}
+
+internal fun LayoutNode.findNodeByPredicateTraversal(
+    predicate: (LayoutNode) -> Boolean
+): LayoutNode? {
+    if (predicate(this)) {
+        return this
+    }
+
+    children.fastForEach {
+        val result = it.findNodeByPredicateTraversal(predicate)
+        if (result != null) {
+            return result
+        }
+    }
+
+    return null
+}
+
+/**
+ * If this node has semantics, we use the semantics wrapper to get bounds. Otherwise, we use
+ * innerLayoutNodeWrapper because it seems the bounds after padding is the effective content.
+ */
+internal fun LayoutNode.findWrapperToGetBounds(): LayoutNodeWrapper {
+    return outerMergingSemantics ?: outerSemantics ?: innerLayoutNodeWrapper
+}
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimationTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimationTest.kt
index 802a75e..a595660 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimationTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimationTest.kt
@@ -828,6 +828,41 @@
         assertThat(fragment1.loadedAnimation).isEqualTo(EXIT)
     }
 
+    @Test
+    fun removePopExitAnimationWithSetPrimaryNavigation() {
+        waitForAnimationReady()
+        val fm = activityRule.activity.supportFragmentManager
+        val fragment1 = AnimationFragment()
+        val fragment2 = AnimationFragment()
+
+        fm.beginTransaction()
+            .setReorderingAllowed(true)
+            .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+            .add(R.id.fragmentContainer, fragment1, "fragment1")
+            .setPrimaryNavigationFragment(fragment1)
+            .addToBackStack("fragment1")
+            .commit()
+        activityRule.waitForExecution()
+
+        fm.beginTransaction()
+            .setReorderingAllowed(true)
+            .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+            .replace(R.id.fragmentContainer, fragment2, "fragment2")
+            .setPrimaryNavigationFragment(fragment2)
+            .addToBackStack("fragment2")
+            .commit()
+        activityRule.waitForExecution()
+
+        assertThat(fragment1.loadedAnimation).isEqualTo(EXIT)
+        assertThat(fragment2.loadedAnimation).isEqualTo(ENTER)
+
+        fm.popBackStack()
+        activityRule.waitForExecution()
+
+        assertThat(fragment1.loadedAnimation).isEqualTo(POP_ENTER)
+        assertThat(fragment2.loadedAnimation).isEqualTo(POP_EXIT)
+    }
+
     private fun assertEnterPopExit(fragment: AnimationFragment) {
         assertFragmentAnimation(fragment, 1, true, ENTER)
 
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java b/fragment/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java
index 68d5867..c67ee5a 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java
@@ -416,29 +416,34 @@
             if (f != null) {
                 f.mBeingSaved = mBeingSaved;
                 f.setPopDirection(false);
-                f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                 f.setNextTransition(mTransition);
                 f.setSharedElementNames(mSharedElementSourceNames, mSharedElementTargetNames);
             }
             switch (op.mCmd) {
                 case OP_ADD:
+                    f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                     mManager.setExitAnimationOrder(f, false);
                     mManager.addFragment(f);
                     break;
                 case OP_REMOVE:
+                    f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                     mManager.removeFragment(f);
                     break;
                 case OP_HIDE:
+                    f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                     mManager.hideFragment(f);
                     break;
                 case OP_SHOW:
+                    f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                     mManager.setExitAnimationOrder(f, false);
                     mManager.showFragment(f);
                     break;
                 case OP_DETACH:
+                    f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                     mManager.detachFragment(f);
                     break;
                 case OP_ATTACH:
+                    f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                     mManager.setExitAnimationOrder(f, false);
                     mManager.attachFragment(f);
                     break;
@@ -480,30 +485,35 @@
             if (f != null) {
                 f.mBeingSaved = mBeingSaved;
                 f.setPopDirection(true);
-                f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                 f.setNextTransition(FragmentManager.reverseTransit(mTransition));
                 // Reverse the target and source names for pop operations
                 f.setSharedElementNames(mSharedElementTargetNames, mSharedElementSourceNames);
             }
             switch (op.mCmd) {
                 case OP_ADD:
+                    f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                     mManager.setExitAnimationOrder(f, true);
                     mManager.removeFragment(f);
                     break;
                 case OP_REMOVE:
+                    f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                     mManager.addFragment(f);
                     break;
                 case OP_HIDE:
+                    f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                     mManager.showFragment(f);
                     break;
                 case OP_SHOW:
+                    f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                     mManager.setExitAnimationOrder(f, true);
                     mManager.hideFragment(f);
                     break;
                 case OP_DETACH:
+                    f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                     mManager.attachFragment(f);
                     break;
                 case OP_ATTACH:
+                    f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                     mManager.setExitAnimationOrder(f, true);
                     mManager.detachFragment(f);
                     break;
diff --git a/media2/media2-widget/src/main/res/values-iw/strings.xml b/media2/media2-widget/src/main/res/values-iw/strings.xml
index 955c8fc..68731ca 100644
--- a/media2/media2-widget/src/main/res/values-iw/strings.xml
+++ b/media2/media2-widget/src/main/res/values-iw/strings.xml
@@ -26,7 +26,7 @@
     <string name="MediaControlView_subtitle_track_number_text" msgid="2241078077382492349">"טראק <xliff:g id="TRACK_NUMBER">%1$d</xliff:g>"</string>
     <string name="MediaControlView_subtitle_track_number_and_lang_text" msgid="2268860463481696609">"טראק <xliff:g id="TRACK_NUMBER">%1$d</xliff:g> – <xliff:g id="LANG">%2$s</xliff:g>"</string>
     <string name="MediaControlView_audio_track_number_text" msgid="4263103361854223806">"טראק <xliff:g id="AUDIO_NUMBER">%1$d</xliff:g>"</string>
-    <string name="mcv2_non_music_title_unknown_text" msgid="2032814146738922144">"כותרת הסרטון לא ידועה"</string>
+    <string name="mcv2_non_music_title_unknown_text" msgid="2032814146738922144">"שם הסרטון לא ידוע"</string>
     <string name="mcv2_music_title_unknown_text" msgid="6037645626002038645">"שם השיר לא ידוע"</string>
     <string name="mcv2_music_artist_unknown_text" msgid="5393558204040775454">"אומן לא ידוע"</string>
     <string name="mcv2_playback_error_text" msgid="6061787693725630293">"לא ניתן להפעיל את הפריט שביקשת"</string>
@@ -37,7 +37,7 @@
     <string name="mcv2_seek_bar_desc" msgid="24915699029009384">"התקדמות ההפעלה"</string>
     <string name="mcv2_settings_button_desc" msgid="811917224044739656">"הגדרות"</string>
     <string name="mcv2_cc_is_on" msgid="5427119422911561783">"הכתוביות מופעלות. כדי להסתירן, יש ללחוץ."</string>
-    <string name="mcv2_cc_is_off" msgid="2380791179816122456">"הכתוביות כבויות. כדי להציגן, יש ללחוץ."</string>
+    <string name="mcv2_cc_is_off" msgid="2380791179816122456">"הכתוביות מושבתות. צריך ללחוץ כדי להציג אותן."</string>
     <string name="mcv2_replay_button_desc" msgid="3128622733570179596">"הפעלה מחדש"</string>
     <string name="mcv2_play_button_desc" msgid="4881308324856085359">"הפעלה"</string>
     <string name="mcv2_pause_button_desc" msgid="7391720675120766278">"השהיה"</string>
diff --git a/preference/preference/res/values-ar/strings.xml b/preference/preference/res/values-ar/strings.xml
index 65864a0..c1f2e6c 100644
--- a/preference/preference/res/values-ar/strings.xml
+++ b/preference/preference/res/values-ar/strings.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="v7_preference_on" msgid="89551595707643515">"تفعيل"</string>
+    <string name="v7_preference_on" msgid="89551595707643515">"مفعّلة"</string>
     <string name="v7_preference_off" msgid="3140233346420563315">"إيقاف"</string>
     <string name="expand_button_title" msgid="2427401033573778270">"إعدادات متقدمة"</string>
     <string name="summary_collapsed_preference_list" msgid="9167775378838880170">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>، <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
diff --git a/preference/preference/res/values-fr-rCA/strings.xml b/preference/preference/res/values-fr-rCA/strings.xml
index e92d40a..56f7a88 100644
--- a/preference/preference/res/values-fr-rCA/strings.xml
+++ b/preference/preference/res/values-fr-rCA/strings.xml
@@ -3,7 +3,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="v7_preference_on" msgid="89551595707643515">"ACTIVÉ"</string>
     <string name="v7_preference_off" msgid="3140233346420563315">"DÉSACTIVÉ"</string>
-    <string name="expand_button_title" msgid="2427401033573778270">"Avancé"</string>
+    <string name="expand_button_title" msgid="2427401033573778270">"Paramètres avancés"</string>
     <string name="summary_collapsed_preference_list" msgid="9167775378838880170">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
     <string name="copy" msgid="6083905920877235314">"Copier"</string>
     <string name="preference_copied" msgid="6685851473431805375">"« <xliff:g id="SUMMARY">%1$s</xliff:g> » copié dans le presse-papiers."</string>
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacElement.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacElement.kt
index 7397551..47eb36b 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacElement.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacElement.kt
@@ -35,21 +35,26 @@
         annotation: KClass<T>,
         containerAnnotation: KClass<out Annotation>?
     ): List<XAnnotationBox<T>> {
-        return if (containerAnnotation == null) {
+        // if there is a container annotation and annotation is repeated, we'll get the container.
+        if (containerAnnotation != null) {
             MoreElements
-                .getAnnotationMirror(element, annotation.java)
-                .orNull()
-                ?.box(env, annotation.java)
-                ?.let {
-                    listOf(it)
-                }
-        } else {
-            val container = MoreElements
                 .getAnnotationMirror(element, containerAnnotation.java)
                 .orNull()
                 ?.box(env, containerAnnotation.java)
-            container?.getAsAnnotationBoxArray<T>("value")?.toList()
-        } ?: emptyList()
+                ?.let { containerBox ->
+                    // found a container, return
+                    return containerBox.getAsAnnotationBoxArray<T>("value").toList()
+                }
+        }
+        // if there is no container annotation or annotation is not repeated, we'll see the
+        // individual value
+        return MoreElements
+            .getAnnotationMirror(element, annotation.java)
+            .orNull()
+            ?.box(env, annotation.java)
+            ?.let {
+                listOf(it)
+            } ?: emptyList()
     }
 
     override fun hasAnnotation(
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationBoxTest.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationBoxTest.kt
index 06a3390..e0c3ef4 100644
--- a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationBoxTest.kt
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationBoxTest.kt
@@ -568,6 +568,54 @@
         }
     }
 
+    @Test
+    fun javaRepeatableAnnotation_notRepeated() {
+        val javaSrc = Source.java(
+            "JavaSubject",
+            """
+            import ${RepeatableJavaAnnotation::class.qualifiedName};
+            @RepeatableJavaAnnotation("x")
+            public class JavaSubject {}
+            """.trimIndent()
+        )
+        val kotlinSrc = Source.kotlin(
+            "KotlinSubject.kt",
+            """
+            import ${RepeatableJavaAnnotation::class.qualifiedName}
+            @RepeatableJavaAnnotation("x")
+            public class KotlinSubject
+            """.trimIndent()
+        )
+        runTest(
+            sources = listOf(javaSrc, kotlinSrc)
+        ) { invocation ->
+            listOf("JavaSubject", "KotlinSubject")
+                .map(invocation.processingEnv::requireTypeElement)
+                .forEach { subject ->
+                    if (invocation.isKsp && preCompiled) {
+                        // TODO remove once https://github.com/google/ksp/issues/356 is fixed
+                        // KSP cannot read array of annotation values in compiled code
+                    } else {
+                        val annotations = subject.getAnnotations(
+                            RepeatableJavaAnnotation::class
+                        )
+                        assertThat(
+                            subject.hasAnnotation(
+                                RepeatableJavaAnnotation::class
+                            )
+                        ).isTrue()
+                        val values = annotations
+                            .map {
+                                it.value.value
+                            }
+                        assertWithMessage(subject.qualifiedName)
+                            .that(values)
+                            .containsExactly("x")
+                    }
+                }
+        }
+    }
+
     // helper function to read what we need
     private fun XAnnotated.getSuppressValues(): Array<String>? {
         return this.getAnnotation(TestSuppressWarnings::class)?.value?.value
diff --git a/slices/core/src/main/res/values-iw/strings.xml b/slices/core/src/main/res/values-iw/strings.xml
index 78b02aa..3064619 100644
--- a/slices/core/src/main/res/values-iw/strings.xml
+++ b/slices/core/src/main/res/values-iw/strings.xml
@@ -22,6 +22,6 @@
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- תהיה לה אפשרות לקרוא מידע מ-<xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- תהיה לה יכולת לנקוט פעולה בתוך <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"יש לאשר ל-<xliff:g id="APP">%1$s</xliff:g> להראות חלקים מכל אפליציה שהיא"</string>
-    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"יש אישור"</string>
+    <string name="abc_slice_permission_allow" msgid="5024599872061409708">"אישור"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"אני לא מרשה"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-nl/strings.xml b/slices/core/src/main/res/values-nl/strings.xml
index a847b8c..46b2c9f 100644
--- a/slices/core/src/main/res/values-nl/strings.xml
+++ b/slices/core/src/main/res/values-nl/strings.xml
@@ -17,11 +17,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> wil segmenten van <xliff:g id="APP_2">%2$s</xliff:g> weergeven"</string>
-    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> toestaan om segmenten van <xliff:g id="APP_2">%2$s</xliff:g> weer te geven?"</string>
+    <string name="abc_slices_permission_request" msgid="3604847235923472451">"<xliff:g id="APP_0">%1$s</xliff:g> wil segmenten van <xliff:g id="APP_2">%2$s</xliff:g> tonen"</string>
+    <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> toestaan om segmenten van <xliff:g id="APP_2">%2$s</xliff:g> te tonen?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Deze kan informatie lezen van <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Deze kan acties uitvoeren in <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> toestaan om segmenten van apps weer te geven"</string>
+    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> toestaan om segmenten van apps te tonen"</string>
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Toestaan"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Weigeren"</string>
 </resources>
diff --git a/slices/view/src/main/res/values-nl/strings.xml b/slices/view/src/main/res/values-nl/strings.xml
index b5d2edc..a5a10b3 100644
--- a/slices/view/src/main/res/values-nl/strings.xml
+++ b/slices/view/src/main/res/values-nl/strings.xml
@@ -19,7 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Meer"</string>
-    <string name="abc_slice_show_more" msgid="1567717014004692768">"Meer weergeven"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Meer tonen"</string>
     <string name="abc_slice_updated" msgid="8155085405396453848">"Geüpdatet: <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
       <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> min geleden</item>
diff --git a/textclassifier/textclassifier/src/main/res/values-iw/strings.xml b/textclassifier/textclassifier/src/main/res/values-iw/strings.xml
index df4b5d1..a2bab86 100644
--- a/textclassifier/textclassifier/src/main/res/values-iw/strings.xml
+++ b/textclassifier/textclassifier/src/main/res/values-iw/strings.xml
@@ -21,7 +21,7 @@
     <string name="dial" msgid="2101464860090311277">"ביצוע שיחה"</string>
     <string name="dial_desc" msgid="1195407206406821463">"התקשרות למספר הטלפון שנבחר"</string>
     <string name="browse" msgid="4753676368851695348">"פתיחה"</string>
-    <string name="browse_desc" msgid="728882176434276995">"פתיחה של כתובת האתר שנבחרה"</string>
+    <string name="browse_desc" msgid="728882176434276995">"‏פתיחה של כתובת ה-URL שנבחרה"</string>
     <string name="sms" msgid="2214738262605167054">"התכתבות בהודעות"</string>
     <string name="sms_desc" msgid="7733202356868441148">"שליחת הודעה למספר הטלפון שנבחר"</string>
     <string name="add_contact" msgid="386263007484061034">"הוספה"</string>