### Compose UI for Copying and Pasting Text Source: https://developer.android.com/develop/ui/compose/touch-input/copy-and-paste A basic Jetpack Compose UI example demonstrating how to enable text copying from a `SelectionContainer` and pasting into a `BasicTextField`. It utilizes `ClipboardManager` for the copy action and shows how text can be pasted via touch and hold or cursor handle. ```kotlin import androidx.compose.foundation.layout.Column import androidx.compose.foundation.text.BasicTextField import androidx.compose.material3.Card import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.text.input.rememberTextFieldState import androidx.compose.foundation.text.selection.SelectionContainer @Composable fun CopyPasteTextExample() { val textFieldState = rememberTextFieldState() Column { Card { SelectionContainer { Text("You can copy this text") } } BasicTextField(state = textFieldState) } } ``` -------------------------------- ### Handling Key Events in Activity with onKeyUp Source: https://developer.android.com/develop/ui/compose/touch-input/input-compatibility-on-large-screens_hl=de This example shows how to override the `onKeyUp` callback in an Activity to handle specific key codes like Enter or Spacebar for actions such as sending messages or controlling media playback. It calls the superclass method for unhandled key codes. ```kotlin override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean { return when (keyCode) { KeyEvent.KEYCODE_ENTER -> { sendChatMessage() true } KeyEvent.KEYCODE_SPACE -> { playOrPauseMedia() true } else -> super.onKeyUp(keyCode, event) } } ``` -------------------------------- ### Override onKeyUp for Key Event Handling Source: https://developer.android.com/develop/ui/compose/touch-input/input-compatibility-on-large-screens This example shows how to override the `onKeyUp` callback to handle key releases for specific keycodes like Enter or Spacebar. This approach is useful for actions that should trigger upon key release, preventing multiple triggers if a key is held down. It falls back to the superclass implementation for unhandled keycodes. ```kotlin override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean { return when (keyCode) { KeyEvent.KEYCODE_ENTER -> { sendChatMessage() true } KeyEvent.KEYCODE_SPACE -> { playOrPauseMedia() true } else -> super.onKeyUp(keyCode, event) } } ``` -------------------------------- ### Get Pointer Tilt using MotionEvent in Android Compose Source: https://developer.android.com/develop/ui/compose/touch-input/stylus-input/advanced-stylus-features_hl=id This code explains how to get the tilt angle of a stylus relative to the screen using the `MotionEvent` API in Android Compose. It uses the `getAxisValue(AXIS_TILT)` method, as there is no direct shortcut for the first pointer. ```kotlin val tilt = event.getAxisValue(AXIS_TILT) ``` -------------------------------- ### Declare and Initialize GLFrontBufferedRenderer Source: https://developer.android.com/develop/ui/compose/touch-input/stylus-input/advanced-stylus-features_hl=id This Kotlin code snippet illustrates how to declare and instantiate `GLFrontBufferedRenderer`. It requires a `SurfaceView` and the previously defined callbacks to optimize rendering to both front and double buffers. ```kotlin var glFrontBufferRenderer = GLFrontBufferedRenderer(surfaceView, callbacks) ``` -------------------------------- ### Predict Motion Events using MotionEventPredictor in Android Source: https://developer.android.com/develop/ui/compose/touch-input/stylus-input/advanced-stylus-features_hl=id This snippet illustrates how to predict the next motion event using the MotionEventPredictor. It checks for ACTION_MOVE events and uses the 'predict()' method to get a predicted MotionEvent, which can then be used to inject artificial points. ```kotlin when (motionEvent.action) { MotionEvent.ACTION_MOVE -> { val predictedMotionEvent = motionEventPredictor?.predict() if(predictedMotionEvent != null) { // use predicted MotionEvent to inject a new artificial point } } } ``` -------------------------------- ### Get Pointer Pressure using MotionEvent in Android Compose Source: https://developer.android.com/develop/ui/compose/touch-input/stylus-input/advanced-stylus-features_hl=id This code demonstrates how to obtain the pressure applied by a pointer on the screen using the `MotionEvent` API in Android Compose. It includes the shortcut `getPressure()` for the first pointer and the general `getAxisValue(AXIS_PRESSURE)` for any pointer index. ```kotlin // For the first pointer val pressure = event.getPressure() // For a specific pointer index val specificPressure = event.getAxisValue(AXIS_PRESSURE) ``` -------------------------------- ### Implement GLFrontBufferRenderer Callbacks Source: https://developer.android.com/develop/ui/compose/touch-input/stylus-input/advanced-stylus-features_hl=id Demonstrates how to implement the `GLFrontBufferRenderer.Callback` interface in Kotlin. This involves overriding `onDrawFrontBufferedLayer` for front-buffer rendering and `onDrawMultiDoubleBufferedLayer` for double-buffer rendering, optimizing data processing for streams. ```kotlin val callback = object: GLFrontBufferedRenderer.Callback { override fun onDrawFrontBufferedLayer( eglManager: EGLManager, bufferInfo: BufferInfo, transform: FloatArray, param: DATA_TYPE ) { // OpenGL for front buffer, short, affecting small area of the screen. } override fun onDrawMultiDoubleBufferedLayer( eglManager: EGLManager, bufferInfo: BufferInfo, transform: FloatArray, params: Collection ) { // OpenGL full scene rendering. } } ``` -------------------------------- ### Get Pointer Orientation using MotionEvent in Android Compose Source: https://developer.android.com/develop/ui/compose/touch-input/stylus-input/advanced-stylus-features_hl=id This snippet illustrates how to retrieve the orientation of a pointer, particularly useful for styluses, using the `MotionEvent` API in Android Compose. It shows the `getOrientation()` shortcut for the first pointer and the `getAxisValue(AXIS_ORIENTATION)` method for any pointer index. ```kotlin // For the first pointer val orientation = event.getOrientation() // For a specific pointer index val specificOrientation = event.getAxisValue(AXIS_ORIENTATION) ``` -------------------------------- ### Launch Content Capture Activity with Jetpack Compose Source: https://developer.android.com/develop/ui/compose/touch-input/stylus-input/create-a-note-taking-app_hl=ja This snippet demonstrates how to launch the content capture activity using an `ActivityResultLauncher` within a Jetpack Compose UI. It defines a `CaptureButton` composable that triggers the launch when clicked. The `registerForActivityResult` callback handles the result, checking for success and extracting the content URI. ```kotlin private val startForResult = registerForActivityResult( ActivityResultContracts.StartActivityForResult()) { result: ActivityResult -> if (result.resultCode == Intent.CAPTURE_CONTENT_FOR_NOTE_SUCCESS) { val uri = result.data?.data // Use the URI to paste the captured content into the note. } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { NotesTheme { Surface(color = MaterialTheme.colorScheme.background) { CaptureButton( onClick = { Log.i("ContentCapture", "Launching intent...") startForResult.launch(Intent(ACTION_LAUNCH_CAPTURE_CONTENT_ACTIVITY_FOR_NOTE)) }) } } } } @Composable fun CaptureButton(onClick: () -> Unit) { Button(onClick = onClick) {Text("Capture Content")} } ``` -------------------------------- ### Get Stylus Hover Distance using MotionEvent in Android Compose Source: https://developer.android.com/develop/ui/compose/touch-input/stylus-input/advanced-stylus-features_hl=id This snippet shows how to determine the distance of a stylus from the screen using the `MotionEvent` API in Android Compose. It utilizes the `getAxisValue(AXIS_DISTANCE)` method, which returns a value indicating how far the stylus nib is from the screen surface. ```kotlin val distance = event.getAxisValue(AXIS_DISTANCE) ``` -------------------------------- ### Launch Content Capture Activity - Kotlin Source: https://developer.android.com/develop/ui/compose/touch-input/stylus-input/create-a-note-taking-app_hl=id This snippet demonstrates how to launch the content capture activity using `ActivityResultLauncher` and the `ACTION_LAUNCH_CAPTURE_CONTENT_ACTIVITY_FOR_NOTE` intent. It registers for the result and handles the success case by retrieving the content URI. ```kotlin private val startForResult = registerForActivityResult( ActivityResultContracts.StartActivityForResult()) { result: ActivityResult -> if (result.resultCode == Intent.CAPTURE_CONTENT_FOR_NOTE_SUCCESS) { val uri = result.data?.data // Use the URI to paste the captured content into the note. } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { NotesTheme { Surface(color = MaterialTheme.colorScheme.background) { CaptureButton( onClick = { Log.i("ContentCapture", "Launching intent...") startForResult.launch(Intent(ACTION_LAUNCH_CAPTURE_CONTENT_ACTIVITY_FOR_NOTE)) } ) } } } } @Composable fun CaptureButton(onClick: () -> Unit) { Button(onClick = onClick) { Text("Capture Content") } } ``` -------------------------------- ### Add Low-Latency Rendering Dependency Source: https://developer.android.com/develop/ui/compose/touch-input/stylus-input/advanced-stylus-features_hl=id This snippet shows how to add the necessary dependency for the low-latency graphics core library to your app's build.gradle file. This enables front-buffer rendering capabilities. ```gradle dependencies { implementation "androidx.graphics:graphics-core:1.0.0-alpha03" } ``` -------------------------------- ### Get Pointer Position using MotionEvent in Android Compose Source: https://developer.android.com/develop/ui/compose/touch-input/stylus-input/advanced-stylus-features_hl=id This snippet shows how to retrieve the X and Y coordinates of a pointer on the screen using the `MotionEvent` API in Android Compose. It provides direct methods `getX()` and `getY()` for the first pointer, as well as the more general `getAxisValue` method for any pointer. ```kotlin // For the first pointer val x = event.getX() val y = event.getY() // For a specific pointer index val specificX = event.getAxisValue(AXIS_X) val specificY = event.getAxisValue(AXIS_Y) ``` -------------------------------- ### Make Composable Focusable with Modifier - Jetpack Compose Source: https://developer.android.com/develop/ui/compose/touch-input/input-compatibility-on-large-screens_hl=pl Enables keyboard navigation for custom composables that are not focusable by default. It uses the `focusable()` modifier to allow the Android framework to manage focus, and `onFocusChanged` to react to focus state changes, for example, changing background color. ```kotlin var color by remember { mutableStateOf(Green) } Box( Modifier .background(color) .onFocusChanged { color = if (it.isFocused) Blue else Green } .focusable() ) { Text("Focusable 1") } FocusSnippets.kt ``` -------------------------------- ### Handling Right-Click Events with Jetpack Compose Source: https://developer.android.com/develop/ui/compose/touch-input/input-compatibility-on-large-screens_hl=pl This Jetpack Compose code demonstrates how to handle right-click events by registering an `OnContextClickListener` on an Android View. It shows how to wrap a `FrameLayout` using `AndroidView` and attach a listener that triggers a context menu when a right-click occurs. ```kotlin Box(modifier = Modifier.fillMaxSize()) { AndroidView( modifier = Modifier.fillMaxSize(), factory = { context -> val rootView = FrameLayout(context) val onContextClickListener = View.OnContextClickListener { view -> showContextMenu() true } rootView.setOnContextClickListener(onContextClickListener) rootView }), ) } ``` -------------------------------- ### Using Custom Brush State Saver in Compose Source: https://developer.android.com/develop/ui/compose/touch-input/stylus-input/ink-api-state-preservation_hl=ja Demonstrates how to use a custom Saver, `brushStateSaver`, with `rememberSaveable` to preserve the state of a mutable Brush object across configuration changes in Jetpack Compose. ```kotlin val currentBrush = rememberSaveable(saver = brushStateSaver(Converters())) { mutableStateOf(defaultBrush) } ``` -------------------------------- ### Handle Touch Events for Rendering Source: https://developer.android.com/develop/ui/compose/touch-input/stylus-input/advanced-stylus-features_hl=id This Kotlin code demonstrates handling `MotionEvent` actions to control rendering with `GLFrontBufferRenderer`. It uses `ACTION_DOWN` and `ACTION_MOVE` to trigger front-buffer rendering and `ACTION_UP` to commit changes via double-buffer rendering. `requestUnbufferedDispatch` is used to ensure immediate event delivery. ```kotlin when (motionEvent.action) { MotionEvent.ACTION_DOWN -> { // Deliver input events as soon as they arrive. view.requestUnbufferedDispatch(motionEvent) // Pointer is in contact with the screen. glFrontBufferRenderer.renderFrontBufferedLayer(DATA_TYPE) } MotionEvent.ACTION_MOVE -> { // Pointer is moving. glFrontBufferRenderer.renderFrontBufferedLayer(DATA_TYPE) } MotionEvent.ACTION_UP -> { // Pointer is not in contact in the screen. glFrontBufferRenderer.commit() } MotionEvent.CANCEL -> { // Cancel front buffer; remove last motion set from the screen. glFrontBufferRenderer.cancel() } } ``` -------------------------------- ### Memuat Kuas Kustom dengan Android Ink API (Kotlin) Source: https://developer.android.com/develop/ui/compose/touch-input/stylus-input/ink-api-brush-apis_hl=id Contoh kode Kotlin ini menunjukkan cara memuat kuas kustom dari sumber daya mentah aplikasi Android. Ini mendefinisikan kelas `CustomBrushes` yang memuat berbagai kuas yang ditentukan dalam file `R.raw` dan memetakannya ke ikon yang sesuai di `R.drawable`. Kuas yang dimuat kemudian dapat digunakan seperti kuas standar. ```kotlin class CustomBrushes(val context: Context) { private const val TAG = "CustomBrushes" val brushes by lazy { loadCustomBrushes(context) } @OptIn(ExperimentalInkCustomBrushApi::class) private fun loadCustomBrushes(): List { val brushFiles = mapOf( "Calligraphy" to (R.raw.calligraphy to R.drawable.draw_24px), "Flag Banner" to (R.raw.flag_banner to R.drawable.flag_24px), "Graffiti" to (R.raw.graffiti to R.drawable.format_paint_24px) // ... ) val loadedBrushes = brushFiles.mapNotNull { val (name, pair) -> val (resourceId, icon) = pair val brushFamily = context.resources.openRawResource(resourceId).use { inputStream -> BrushFamily.decode(inputStream) } CustomBrush(name, icon, brushFamily.copy(clientBrushFamilyId = name)) } return loadedBrushes } } data class CustomBrush( val name: String, val icon: Int, val brushFamily: BrushFamily ) ``` -------------------------------- ### Serialize and Deserialize Brush and Stroke Data (Kotlin) Source: https://developer.android.com/develop/ui/compose/touch-input/stylus-input/ink-api-state-preservation_hl=fr This snippet demonstrates the Kotlin code for the Converters object, which includes functions to serialize and deserialize Brush and Stroke objects. It maps stock brushes to their serialized enum values and handles the conversion of brush properties and stroke inputs. Dependencies include `Brush`, `Stroke`, `SerializedBrush`, `SerializedStroke`, `StockBrushes`, `StrokeInputBatch`, `ByteArrayOutputStream`, and `ByteArrayInputStream`. ```kotlin object Converters { private val stockBrushToEnumValues = mapOf( StockBrushes.marker() to SerializedStockBrush.Marker, StockBrushes.pressurePen() to SerializedStockBrush.PressurePen, StockBrushes.highlighter() to SerializedStockBrush.Highlighter, StockBrushes.dashedLine() to SerializedStockBrush.DashedLine, ) private val enumToStockBrush = stockBrushToEnumValues.entries.associate { (key, value) -> value to key } private fun serializeBrush(brush: Brush): SerializedBrush { return SerializedBrush( size = brush.size, color = brush.colorLong, epsilon = brush.epsilon, stockBrush = stockBrushToEnumValues[brush.family] ?: SerializedStockBrush.Marker, ) } fun serializeStroke(stroke: Stroke): SerializedStroke { val serializedBrush = serializeBrush(stroke.brush) val encodedSerializedInputs = ByteArrayOutputStream().use { stroke.inputs.encode(it) it.toByteArray() } return SerializedStroke( inputs = encodedSerializedInputs, brush = serializedBrush ) } private fun deserializeStroke( serializedStroke: SerializedStroke, ): Stroke? { val inputs = ByteArrayInputStream(serializedStroke.inputs).use { StrokeInputBatch.decode(it) } val brush = deserializeBrush(serializedStroke.brush, customBrushes) return Stroke(brush = brush, inputs = inputs) } private fun deserializeBrush( serializedBrush: SerializedBrush, ): Brush { val stockBrushFamily = enumToStockBrush[serializedBrush.stockBrush] val brushFamily = customBrush?.brushFamily ?: stockBrushFamily ?: StockBrushes.marker() return Brush.createWithColorLong( family = brushFamily, colorLong = serializedBrush.color, size = serializedBrush.size, epsilon = serializedBrush.epsilon, ) } } ``` -------------------------------- ### Load Custom Brushes with Android Ink API (Kotlin) Source: https://developer.android.com/develop/ui/compose/touch-input/stylus-input/ink-api-brush-apis_hl=pt-BR This Kotlin code demonstrates how to load custom brush families from gzipped binary encoded protocol buffers. It maps resource IDs to brush names and icons, deserializes the `BrushFamily`, and creates `CustomBrush` objects. Dependencies include Android Context and Ink API experimental features. ```kotlin class CustomBrushes(val context: Context) { private const val TAG = "CustomBrushes" val brushes by lazy { loadCustomBrushes(context) } @OptIn(ExperimentalInkCustomBrushApi::class) private fun loadCustomBrushes(): List { val brushFiles = mapOf( "Calligraphy" to (R.raw.calligraphy to R.drawable.draw_24px), "Flag Banner" to (R.raw.flag_banner to R.drawable.flag_24px), "Graffiti" to (R.raw.graffiti to R.drawable.format_paint_24px) // ... ) val loadedBrushes = brushFiles.mapNotNull { (name, pair) -> val (resourceId, icon) = pair val brushFamily = context.resources.openRawResource(resourceId).use { BrushFamily.decode(inputStream) } CustomBrush(name, icon, brushFamily.copy(clientBrushFamilyId = name)) } return loadedBrushes } } data class CustomBrush( val name: String, val icon: Int, val brushFamily: BrushFamily ) ``` -------------------------------- ### Implement Drag and Drop Support in Android Source: https://developer.android.com/develop/ui/compose/touch-input/input-compatibility-on-large-screens_hl=vi Enable users to drag and drop items between apps, particularly useful in multi-window environments like desktops and split-screen mode on tablets and phones. Consider the types of items users might drag into your app, such as photos for an editor or audio files for a player. ```kotlin // To add drag and drop support, see Drag and drop // and take a look at the Android on ChromeOS — Implementing Drag & Drop blog post. // Special considerations for ChromeOS: // - Remember to request permission with `requestDragAndDropPermissions()` to access items dragged in from outside the app // - An item must have the `View.DRAG_FLAG_GLOBAL` flag in order to be dragged out to other applications // See Start a drag event ``` -------------------------------- ### Copy Text with ClipEntry using ClipboardManager in Android Source: https://developer.android.com/develop/ui/compose/touch-input/copy-and-paste Shows a more granular approach to copying text to the Android clipboard using `ClipEntry` and `ClipData`. This method allows for creating a `ClipData` object from plain text and setting it as a `ClipEntry` on the clipboard, suitable for sensitive content. ```kotlin import androidx.compose.material3.Button import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.platform.LocalClipboardManager import android.content.ClipData import android.content.ClipEntry @Composable fun CopySensitiveTextButton() { // Retrieve a ClipboardManager object val clipboardManager = LocalClipboardManager.current Button( onClick = { val clipData = ClipData.newPlainText("plain text", "Hello, clipboard") val clipEntry = ClipEntry(clipData) clipboardManager.setClip(clipEntry) } ) { Text("Click to copy a text") } } ``` -------------------------------- ### Serialize Stroke with Storage Module Source: https://developer.android.com/develop/ui/compose/touch-input/stylus-input/ink-api-state-preservation_hl=ja Serializes a Stroke object, including its Brush and StrokeInputBatch, into a format suitable for persistent storage. It utilizes the storage module's encode function for the input batch. ```kotlin fun serializeStroke(stroke: Stroke): SerializedStroke { val serializedBrush = serializeBrush(stroke.brush) val encodedSerializedInputs = ByteArrayOutputStream().use { stroke.inputs.encode(it) it.toByteArray() } return SerializedStroke( inputs = encodedSerializedInputs, brush = serializedBrush ) } ``` -------------------------------- ### Record Motion Events with MotionEventPredictor in Android Source: https://developer.android.com/develop/ui/compose/touch-input/stylus-input/advanced-stylus-features_hl=id This code demonstrates how to feed motion event data into the MotionEventPredictor. The 'record()' method stores MotionEvent objects, capturing the user's actions for prediction. ```kotlin motionEventPredictor.record(motionEvent) ``` -------------------------------- ### Handle Content Capture Results Source: https://developer.android.com/develop/ui/compose/touch-input/stylus-input/create-a-note-taking-app_hl=ja This code snippet focuses on the result handling part of the content capture process. It shows how to register an `ActivityResultLauncher` and specifically checks if the `resultCode` indicates successful content capture (`Intent.CAPTURE_CONTENT_FOR_NOTE_SUCCESS`). If successful, it retrieves the content URI from the intent data. ```kotlin registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult -> if (result.resultCode == Intent.CAPTURE_CONTENT_FOR_NOTE_SUCCESS) { val uri = result.data?.data // Use the URI to paste the captured content into the note. } } ``` -------------------------------- ### Deserialize Stroke with Storage Module Source: https://developer.android.com/develop/ui/compose/touch-input/stylus-input/ink-api-state-preservation_hl=ja Deserializes a Stroke object from its serialized representation. It reconstructs the StrokeInputBatch using the storage module's decode function and recreates the Brush from serialized properties. ```kotlin fun deserializeStroke(serializedStroke: SerializedStroke): Stroke { val inputs = ByteArrayInputStream(serializedStroke.inputs).use { StrokeInputBatch.decode(it) } val brush = deserializeBrush(serializedStroke.brush) return Stroke(brush = brush, inputs = inputs) } ``` -------------------------------- ### Handle Lock Screen Dismissal in Kotlin Source: https://developer.android.com/develop/ui/compose/touch-input/stylus-input/create-a-note-taking-app_hl=id This Kotlin code demonstrates how to request the dismissal of the keyguard (lock screen) to access the note-taking app. It utilizes `KeyguardManager` and provides callbacks for success, failure, or cancellation of the unlock operation. ```kotlin val keyguardManager = getSystemService(KEYGUARD_SERVICE) as KeyguardManager keyguardManager.requestDismissKeyguard( this, object : KeyguardDismissCallback() { override fun onDismissError() { // Unlock failed. Dismissing keyguard is not feasible. } override fun onDismissSucceeded() { // Unlock succeeded. Device is now unlocked. } override fun onDismissCancelled() { // Unlock failed. User cancelled operation or request otherwise cancelled. } } ) ``` -------------------------------- ### Deserialize Stroke from Storage (Ink API) Source: https://developer.android.com/develop/ui/compose/touch-input/stylus-input/ink-api-state-preservation_hl=vi This Kotlin function `deserializeStroke` shows how to reconstruct a `Stroke` object from its serialized form. It takes a `SerializedStroke` object, decodes the `StrokeInputBatch` from the stored byte array, and reconstructs the `Brush` object using the deserialized brush data. Finally, it creates the complete `Stroke` object using the reconstructed brush and input batch, enabling the restoration of user drawings. ```kotlin fun deserializeStroke(serializedStroke: SerializedStroke): Stroke { val inputs = ByteArrayInputStream(serializedStroke.inputs).use { StrokeInputBatch.decode(it) } val brush = deserializeBrush(serializedStroke.brush) return Stroke(brush = brush, inputs = inputs) } ``` -------------------------------- ### Copy Text with ClipboardManager in Android Source: https://developer.android.com/develop/ui/compose/touch-input/copy-and-paste Demonstrates how to copy simple text to the Android clipboard using the ClipboardManager. The `setText()` method directly copies a String. This is useful for basic text sharing between applications or within an app. ```kotlin import androidx.compose.material3.Button import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.platform.LocalClipboardManager @Composable fun CopyTextButton() { // Retrieve a ClipboardManager object val clipboardManager = LocalClipboardManager.current Button( onClick = { // Copy "Hello, clipboard" to the clipboard clipboardManager.setText("Hello, clipboard") } ) { Text("Click to copy a text") } } ``` -------------------------------- ### Configuring System Bars for Transient Behavior (Kotlin) Source: https://developer.android.com/develop/ui/compose/touch-input/stylus-input/advanced-stylus-features_hl=id This code configures the behavior of hidden system bars to be transient and appear only on swipe. It utilizes the `WindowInsetsControllerCompat` to set the system bars behavior to `BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE`. This prevents navigation gestures from triggering unwanted touch events on full-screen apps. ```kotlin // Configure the behavior of the hidden system bars. windowInsetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE ``` -------------------------------- ### Handle Hover Events in Android UI Compose Source: https://developer.android.com/develop/ui/compose/touch-input/input-compatibility-on-large-screens_hl=vi Implement hover event handling to provide visual feedback and indicate interactive behavior for UI elements. This is crucial for custom components to enhance user experience by changing pointer icons or highlighting elements under the pointer. ```kotlin import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.size import androidx.compose.material3.Text import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.pointer.PointerEventType import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.unit.dp @Composable private fun LogPointerEvents(filter: PointerEventType? = null) { var log by remember { mutableStateOf("") } Column { Text(log) Box( Modifier .size(100.dp) .background(Color.Red) .pointerInput(filter) { awaitPointerEventScope { while (true) { val event = awaitPointerEvent() // handle pointer event if (filter == null || event.type == filter) { log = "${event.type}, ${event.changes.first().position}" } } } } ) } } ```