Merge "feat: supress Experimental Carousel features until we launch RC candidate" into androidx-main
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/CarouselTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/CarouselTest.kt
index c6569aa..d240598 100644
--- a/tv/tv-material/src/androidTest/java/androidx/tv/material3/CarouselTest.kt
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/CarouselTest.kt
@@ -76,7 +76,7 @@
 import kotlin.math.abs
 import kotlinx.coroutines.delay
 import org.junit.Rule
-import org.junit.Test
+// import org.junit.Test
 
 private const val delayBetweenItems = 2500L
 private const val animationTime = 900L
@@ -86,7 +86,7 @@
     @get:Rule
     val rule = createComposeRule()
 
-    @Test
+    // @Test
     fun carousel_autoScrolls() {
         rule.setContent {
             SampleCarousel {
@@ -103,7 +103,7 @@
         rule.onNodeWithText("Text 3").assertIsDisplayed()
     }
 
-    @Test
+    // @Test
     fun carousel_onFocus_stopsScroll() {
         rule.setContent {
             SampleCarousel {
@@ -124,7 +124,7 @@
         rule.onNodeWithText("Text 1").onParent().assertIsFocused()
     }
 
-    @Test
+    // @Test
     fun carousel_onUserTriggeredPause_stopsScroll() {
         rule.setContent {
             val carouselState = rememberCarouselState()
@@ -143,7 +143,7 @@
         rule.onNodeWithText("Text 1").assertIsDisplayed()
     }
 
-    @Test
+    // @Test
     fun carousel_onUserTriggeredPauseAndResume_resumeScroll() {
         var pauseHandle: ScrollPauseHandle? = null
         rule.setContent {
@@ -176,7 +176,7 @@
         rule.onNodeWithText("Text 2").assertIsDisplayed()
     }
 
-    @Test
+    // @Test
     fun carousel_onMultipleUserTriggeredPauseAndResume_resumesScroll() {
         var pauseHandle1: ScrollPauseHandle? = null
         var pauseHandle2: ScrollPauseHandle? = null
@@ -220,7 +220,7 @@
         rule.onNodeWithText("Text 2").assertIsDisplayed()
     }
 
-    @Test
+    // @Test
     fun carousel_onRepeatedResumesOnSamePauseHandle_ignoresSubsequentResumeCalls() {
         var pauseHandle1: ScrollPauseHandle? = null
         rule.setContent {
@@ -259,7 +259,7 @@
         rule.onNodeWithText("Text 1").assertIsDisplayed()
     }
 
-    @Test
+    // @Test
     fun carousel_outOfFocus_resumesScroll() {
         rule.setContent {
             Column {
@@ -282,7 +282,7 @@
         rule.onNodeWithText("Text 2").assertIsDisplayed()
     }
 
-    @Test
+    // @Test
     fun carousel_pagerIndicatorDisplayed() {
         rule.setContent {
             SampleCarousel {
@@ -293,7 +293,7 @@
         rule.onNodeWithTag("indicator").assertIsDisplayed()
     }
 
-    @Test
+    // @Test
     fun carousel_withAnimatedContent_successfulTransition() {
         rule.setContent {
             SampleCarousel {
@@ -313,7 +313,7 @@
         rule.onNodeWithText("PLAY").assertIsDisplayed()
     }
 
-    @Test
+    // @Test
     fun carousel_withAnimatedContent_successfulFocusIn() {
         rule.setContent {
             SampleCarousel {
@@ -335,7 +335,7 @@
             .assertIsFocused()
     }
 
-    @Test
+    // @Test
     fun carousel_parentContainerGainsFocus_onBackPress() {
         rule.setContent {
             Box(modifier = Modifier
@@ -370,7 +370,7 @@
         rule.onNodeWithTag("box-container").assertIsFocused()
     }
 
-    @Test
+    // @Test
     fun carousel_withCarouselItem_parentContainerGainsFocusOnBackPress() {
         rule.setContent {
             Box(modifier = Modifier
@@ -407,7 +407,7 @@
         rule.onNodeWithTag("box-container").assertIsFocused()
     }
 
-    @Test
+    // @Test
     fun carousel_scrollToRegainFocus_checkBringIntoView() {
         val focusRequester = FocusRequester()
         rule.setContent {
@@ -500,7 +500,7 @@
         assertThat(checkNodeCompletelyVisible(rule, "featured-carousel")).isTrue()
     }
 
-    @Test
+    // @Test
     fun carousel_zeroItemCount_shouldNotCrash() {
         val testTag = "emptyCarousel"
         rule.setContent {
@@ -510,7 +510,7 @@
         rule.onNodeWithTag(testTag).assertExists()
     }
 
-    @Test
+    // @Test
     fun carousel_oneItemCount_shouldNotCrash() {
         val testTag = "emptyCarousel"
         rule.setContent {
@@ -520,7 +520,7 @@
         rule.onNodeWithTag(testTag).assertExists()
     }
 
-    @Test
+    // @Test
     fun carousel_manualScrollingWithFocusableItemsOnTop_focusStaysWithinCarousel() {
         rule.setContent {
             Column {
@@ -577,7 +577,7 @@
         rule.onNodeWithText("Button-1").assertIsFocused()
     }
 
-    @Test
+    // @Test
     fun carousel_manualScrollingFastMultipleKeyPresses_focusStaysWithinCarousel() {
         val carouselState = CarouselState()
         val tabs = listOf("Tab 1", "Tab 2", "Tab 3")
@@ -640,7 +640,7 @@
         rule.onNodeWithText("Play ${finalItem + 3}", useUnmergedTree = true).assertIsFocused()
     }
 
-    @Test
+    // @Test
     fun carousel_manualScrollingDpadLongPress_moveOnlyOneSlide() {
         rule.setContent {
             SampleCarousel(itemCount = 6) { index ->
@@ -685,7 +685,7 @@
         rule.onNodeWithText("Button 1").assertIsFocused()
     }
 
-    @Test
+    // @Test
     fun carousel_manualScrollingLtr_RightMovesToNextSlideLeftMovesToPrevSlide() {
         rule.setContent {
             SampleCarousel { index ->
@@ -731,7 +731,7 @@
         rule.onNodeWithText("Button 1").assertIsDisplayed()
     }
 
-    @Test
+    // @Test
     fun carousel_manualScrollingRtl_LeftMovesToNextSlideRightMovesToPrevSlide() {
         rule.setContent {
             CompositionLocalProvider(
@@ -780,7 +780,7 @@
         rule.onNodeWithText("Button 1").assertIsDisplayed()
     }
 
-    @Test
+    // @Test
     fun carousel_itemCountChangesDuringAnimation_shouldNotCrash() {
         val itemDisplayDurationMs: Long = 100
         var itemChanges = 0
@@ -813,7 +813,7 @@
         rule.waitUntil(timeoutMillis = 5000) { itemChanges > minSuccessfulItemChanges }
     }
 
-    @Test
+    // @Test
     fun carousel_slideWithTwoButtonsInARow_focusMovesWithinSlideAndChangesSlideOnlyOnFocusExit() {
         rule.setContent {
             // No AutoScrolling
@@ -834,7 +834,7 @@
         rule.onNodeWithText("Left Button 2").assertIsFocused()
     }
 
-    @Test
+    // @Test
     fun carousel_manualScrollingLtr_loopsAroundWhenNoAdjacentFocusableItemsArePresent() {
         rule.setContent {
             // No AutoScrolling
@@ -860,7 +860,7 @@
     }
 
     @OptIn(ExperimentalComposeUiApi::class)
-    @Test
+    // @Test
     fun carousel_manualScrollingLtr_focusMovesToAdjacentItemsOutsideCarousel() {
         rule.setContent {
             val focusRequester = remember { FocusRequester() }
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/BringIntoViewIfChildrenAreFocused.kt b/tv/tv-material/src/main/java/androidx/tv/material3/BringIntoViewIfChildrenAreFocused.kt
index b9decd5..572fbfe 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/BringIntoViewIfChildrenAreFocused.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/BringIntoViewIfChildrenAreFocused.kt
@@ -16,39 +16,28 @@
 
 package androidx.tv.material3
 
-import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.relocation.BringIntoViewResponder
-import androidx.compose.foundation.relocation.bringIntoViewResponder
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.composed
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.geometry.Rect
-import androidx.compose.ui.layout.onSizeChanged
-import androidx.compose.ui.platform.debugInspectorInfo
-
-@OptIn(ExperimentalFoundationApi::class)
-internal fun Modifier.bringIntoViewIfChildrenAreFocused(): Modifier = composed(
-    inspectorInfo = debugInspectorInfo { name = "bringIntoViewIfChildrenAreFocused" },
-    factory = {
-        var myRect: Rect = Rect.Zero
-        this
-            .onSizeChanged {
-                myRect = Rect(Offset.Zero, Offset(it.width.toFloat(), it.height.toFloat()))
-            }
-            .bringIntoViewResponder(
-                remember {
-                    object : BringIntoViewResponder {
-                        // return the current rectangle and ignoring the child rectangle received.
-                        @ExperimentalFoundationApi
-                        override fun calculateRectForParent(localRect: Rect): Rect = myRect
-
-                        // The container is not expected to be scrollable. Hence the child is
-                        // already in view with respect to the container.
-                        @ExperimentalFoundationApi
-                        override suspend fun bringChildIntoView(localRect: () -> Rect?) {}
-                    }
-                }
-            )
-    }
-)
+// @OptIn(ExperimentalFoundationApi::class)
+// internal fun Modifier.bringIntoViewIfChildrenAreFocused(): Modifier = composed(
+//     inspectorInfo = debugInspectorInfo { name = "bringIntoViewIfChildrenAreFocused" },
+//     factory = {
+//         var myRect: Rect = Rect.Zero
+//         this
+//             .onSizeChanged {
+//                 myRect = Rect(Offset.Zero, Offset(it.width.toFloat(), it.height.toFloat()))
+//             }
+//            .bringIntoViewResponder(
+//                remember {
+//                    object : BringIntoViewResponder {
+//                        // return the current rectangle and ignoring the child rectangle received.
+//                        @ExperimentalFoundationApi
+//                        override fun calculateRectForParent(localRect: Rect): Rect = myRect
+//
+//                        // The container is not expected to be scrollable. Hence the child is
+//                        // already in view with respect to the container.
+//                        @ExperimentalFoundationApi
+//                        override suspend fun bringChildIntoView(localRect: () -> Rect?) {}
+//                    }
+//                }
+//            )
+//     }
+// )
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/Carousel.kt b/tv/tv-material/src/main/java/androidx/tv/material3/Carousel.kt
index 1cc9e95..9aec264 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/Carousel.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/Carousel.kt
@@ -22,7 +22,6 @@
 import androidx.compose.animation.AnimatedContentScope
 import androidx.compose.animation.AnimatedVisibilityScope
 import androidx.compose.animation.ContentTransform
-import androidx.compose.animation.ExperimentalAnimationApi
 import androidx.compose.animation.core.tween
 import androidx.compose.animation.fadeIn
 import androidx.compose.animation.fadeOut
@@ -49,7 +48,6 @@
 import androidx.compose.runtime.setValue
 import androidx.compose.runtime.snapshotFlow
 import androidx.compose.ui.Alignment
-import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.focus.FocusDirection
 import androidx.compose.ui.focus.FocusDirection.Companion.Left
@@ -86,6 +84,10 @@
 /**
  * Composes a hero card rotator to highlight a piece of content.
  *
+ * Note: The animations and focus management features have been dropped temporarily due to
+ * some technical challenges. If you need them, consider using the previous version of the
+ * library (1.0.0-alpha10) or kindly wait until the next alpha version (1.1.0-alpha01).
+ *
  * Examples:
  * @sample androidx.tv.samples.SimpleCarousel
  * @sample androidx.tv.samples.CarouselIndicatorWithRectangleShape
@@ -102,7 +104,7 @@
  * @param carouselIndicator indicator showing the position of the current item among all items.
  * @param content defines the items for a given index.
  */
-@OptIn(ExperimentalComposeUiApi::class)
+// @OptIn(ExperimentalComposeUiApi::class)
 @ExperimentalTvMaterial3Api
 @Composable
 fun Carousel(
@@ -144,14 +146,14 @@
 
     Box(modifier = modifier
         .carouselSemantics(itemCount = itemCount, state = carouselState)
-        .bringIntoViewIfChildrenAreFocused()
+        // .bringIntoViewIfChildrenAreFocused()
         .focusRequester(carouselOuterBoxFocusRequester)
         .onFocusChanged {
             focusState = it
             // When the carousel gains focus for the first time
-            if (it.isFocused && isAutoScrollActive) {
-                focusManager.moveFocus(FocusDirection.Enter)
-            }
+//            if (it.isFocused && isAutoScrollActive) {
+//                focusManager.moveFocus(FocusDirection.Enter)
+//            }
         }
         .handleKeyEvents(
             carouselState = carouselState,
@@ -181,7 +183,7 @@
                     // Outer box is focused
                     if (!isAutoScrollActive && focusState?.isFocused == true) {
                         carouselOuterBoxFocusRequester.requestFocus()
-                        focusManager.moveFocus(FocusDirection.Enter)
+//                        focusManager.moveFocus(FocusDirection.Enter)
                     }
                 }
             }
@@ -209,9 +211,9 @@
     return !accessibilityManager.isEnabled && !(carouselIsFocused || carouselHasFocus)
 }
 
-@OptIn(ExperimentalAnimationApi::class)
+// @OptIn(ExperimentalAnimationApi::class)
 private suspend fun AnimatedVisibilityScope.onAnimationCompletion(action: suspend () -> Unit) {
-    snapshotFlow { transition.currentState == transition.targetState }.first { it }
+//    snapshotFlow { transition.currentState == transition.targetState }.first { it }
     action.invoke()
 }
 
@@ -246,7 +248,10 @@
     onAutoScrollChange(doAutoScroll)
 }
 
-@OptIn(ExperimentalTvMaterial3Api::class, ExperimentalComposeUiApi::class)
+@OptIn(
+    ExperimentalTvMaterial3Api::class,
+//    ExperimentalComposeUiApi::class
+)
 private fun Modifier.handleKeyEvents(
     carouselState: CarouselState,
     outerBoxFocusRequester: FocusRequester,
@@ -289,7 +294,7 @@
                 }
 
             !focusManager.moveFocus(direction) &&
-                currentCarouselBoxFocusState()?.hasFocus == true -> {
+                    currentCarouselBoxFocusState()?.hasFocus == true -> {
                 // if focus search was unsuccessful, interpret as input for slide change
                 updateItemBasedOnLayout(direction, isLtr)
                 KeyEventPropagation.StopPropagation
@@ -302,7 +307,7 @@
         // Ignore KeyUp action type
         it.type == KeyUp -> KeyEventPropagation.ContinuePropagation
         it.key == Key.Back -> {
-            focusManager.moveFocus(FocusDirection.Exit)
+//            focusManager.moveFocus(FocusDirection.Exit)
             KeyEventPropagation.ContinuePropagation
         }
 
@@ -313,14 +318,14 @@
     }
 }.focusProperties {
     // allow exit along horizontal axis only for first and last slide.
-    exit = {
-        when {
-            shouldFocusExitCarousel(it, carouselState, itemCount, isLtr) ->
-                FocusRequester.Default
-
-            else -> FocusRequester.Cancel
-        }
-    }
+//    exit = {
+//        when {
+//            shouldFocusExitCarousel(it, carouselState, itemCount, isLtr) ->
+//                FocusRequester.Default
+//
+//            else -> FocusRequester.Cancel
+//        }
+//    }
 }
 
 @OptIn(ExperimentalTvMaterial3Api::class)
@@ -490,9 +495,9 @@
      * Transition applied when bringing it into view and removing it from the view
      */
     val contentTransform: ContentTransform
-    @Composable get() =
-        fadeIn(animationSpec = tween(100))
-            .togetherWith(fadeOut(animationSpec = tween(100)))
+        @Composable get() =
+            fadeIn(animationSpec = tween(100))
+                .togetherWith(fadeOut(animationSpec = tween(100)))
 
     /**
      * An indicator showing the position of the current active item among the items of the