Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ import androidx.compose.runtime.ProvidedValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.LocalSaveableStateRegistry
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.ExperimentalMediaQueryApi
import androidx.compose.ui.InternalComposeUiApi
import androidx.compose.ui.LocalUiMediaScope
import androidx.lifecycle.LifecycleOwner
import androidx.savedstate.compose.LocalSavedStateRegistryOwner

Expand Down Expand Up @@ -66,7 +68,7 @@ val LocalPlatformPrefetchScheduler = staticCompositionLocalOf<PlatformPrefetchSc
error("CompositionLocal LocalPlatformPrefetchScheduler not present")
}

@OptIn(InternalComposeApi::class)
@OptIn(ExperimentalMediaQueryApi::class)
@Composable
internal fun ProvidePlatformCompositionLocals(
vararg values: ProvidedValue<*>,
Expand Down Expand Up @@ -94,6 +96,7 @@ internal fun ProvidePlatformCompositionLocals(
LocalPlatformScreenReader provides platformContext.screenReader,
LocalPlatformWindowInsets provides platformContext.windowInsets,
LocalPlatformPrefetchScheduler provides platformContext.prefetchScheduler,
LocalUiMediaScope provides platformContext.mediaEnvironment,
androidx.lifecycle.compose.LocalLifecycleOwner provides platformContext.architectureComponentsOwner.lifecycleOwner,
LocalSavedStateRegistryOwner provides platformContext.architectureComponentsOwner.savedStateRegistryOwner,
LocalSaveableStateRegistry provides saveableStateRegistry,
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package androidx.compose.ui.platform

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.ComposeUiFlags
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.ExperimentalMediaQueryApi
import androidx.compose.ui.FrameRateCategory
import androidx.compose.ui.InternalComposeUiApi
import androidx.compose.ui.UiMediaScope
import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.focus.FocusManager
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.hapticfeedback.HapticFeedback
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.input.InputMode
import androidx.compose.ui.input.InputModeManager
import androidx.compose.ui.input.pointer.PointerIcon
Expand All @@ -45,6 +49,7 @@ import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.ImeOptions
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.intl.LocaleList
import androidx.compose.ui.unit.Dp
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ViewModelStoreOwner
Expand Down Expand Up @@ -156,7 +161,7 @@ interface PlatformContext {
}

val textToolbar: TextToolbar get() = EmptyTextToolbar
val hapticFeedback: HapticFeedback get() = DefaultHapticFeedback
val hapticFeedback: HapticFeedback get() = NoOpHapticFeedback
fun setPointerIcon(pointerIcon: PointerIcon) = Unit

val parentFocusManager: FocusManager get() = EmptyFocusManager
Expand Down Expand Up @@ -217,6 +222,18 @@ interface PlatformContext {
*/
val prefetchScheduler: PlatformPrefetchScheduler get() = NoOpPlatformPrefetchScheduler

/**
* Media-related information exposed to the composition.
*
* This provides platform-specific environment details such as window posture,
* pointer precision, keyboard type, and device capabilities. The default
* implementation is a no-op environment that reports neutral values so code
* using media state remains safe on platforms that do not provide a richer
* implementation.
*/
@OptIn(ExperimentalMediaQueryApi::class)
val mediaEnvironment: UiMediaScope get() = EmptyMediaEnvironment

interface RootForTestListener {
fun onRootForTestCreated(root: PlatformRootForTest)
fun onRootForTestDisposed(root: PlatformRootForTest)
Expand Down Expand Up @@ -389,3 +406,27 @@ internal class DelegateRootForTestListener : PlatformContext.RootForTestListener
}
}
}

private object NoOpHapticFeedback : HapticFeedback {
override fun performHapticFeedback(hapticFeedbackType: HapticFeedbackType) = Unit
}

@OptIn(ExperimentalMediaQueryApi::class)
private object EmptyMediaEnvironment : UiMediaScope {
override val windowPosture: UiMediaScope.Posture
get() = UiMediaScope.Posture.Flat
override val windowWidth: Dp
get() = Dp.Unspecified
override val windowHeight: Dp
get() = Dp.Unspecified
override val pointerPrecision: UiMediaScope.PointerPrecision
get() = UiMediaScope.PointerPrecision.None
override val keyboardKind: UiMediaScope.KeyboardKind
get() = UiMediaScope.KeyboardKind.None
override val hasMicrophone: Boolean
get() = false
override val hasCamera: Boolean
get() = false
override val viewingDistance: UiMediaScope.ViewingDistance
get() = UiMediaScope.ViewingDistance.Near
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ internal class WebHapticFeedback : HapticFeedback {
private val SoftTickVibrationPattern = vibrationPatternOf(6)
private val LongPressVibrationPattern = vibrationPatternOf(0, 30)
private val VirtualKeyVibrationPattern = vibrationPatternOf(0, 20)

fun webHapticFeedbackOrDefault(): HapticFeedback = if (isVibrationSupported()) WebHapticFeedback() else DefaultHapticFeedback
}

override fun performHapticFeedback(hapticFeedbackType: HapticFeedbackType) {
Expand Down Expand Up @@ -81,7 +79,7 @@ private fun vibrate(pattern: JsArray<JsNumber>) {
js("window.navigator.vibrate(pattern)")
}

private fun isVibrationSupported(): Boolean = js(
internal fun isVibrationSupported(): Boolean = js(
//language=javascript
"""
typeof window !== 'undefined' &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ import androidx.compose.ui.platform.PlatformOutOfFrameExecutor
import androidx.compose.ui.platform.PlatformPrefetchScheduler
import androidx.compose.ui.platform.WebPrefetchScheduler
import androidx.compose.ui.platform.isIdleCallbackSupported
import androidx.compose.ui.platform.isVibrationSupported
import androidx.compose.ui.scene.ComposeSceneDragAndDropNode
import androidx.compose.ui.scene.ComposeScenePointer
import androidx.compose.ui.scene.PointerEventResult
Expand Down Expand Up @@ -309,7 +310,7 @@ internal class ComposeWindow(
}

override val hapticFeedback by lazy(LazyThreadSafetyMode.NONE) {
WebHapticFeedback.webHapticFeedbackOrDefault()
if (isVibrationSupported()) WebHapticFeedback() else super.hapticFeedback
}

override val prefetchScheduler: PlatformPrefetchScheduler =
Expand Down
Loading