PlatformTextInputAdapter.android.kt
/*
* Copyright 2023 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.text.input
import android.view.View
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputConnection
import androidx.compose.runtime.Immutable
import androidx.compose.ui.text.ExperimentalTextApi
/**
* Defines a plugin to the Compose text input system. Instances of this interface should be
* stateless singleton `object`s. They act as both:
* - factories to create instances of [PlatformTextInputAdapter] that know how to talk to
* platform-specific IME APIs, as well as
* - keys into the cache of adapter instances managed by the [PlatformTextInputPluginRegistry].
*
* To register a plugin with the system, call [PlatformTextInputPluginRegistry.rememberAdapter]
* from a composable, probably an implementation of a text field. [createAdapter] will be called
* if necessary to instantiate the adapter.
*
* Implementations are intended to be used only by your text editor implementation, and probably not
* exposed as public API.
*/
@ExperimentalTextApi
@Immutable
actual fun interface PlatformTextInputPlugin<T : PlatformTextInputAdapter> {
/**
* Creates a new instance of a [PlatformTextInputAdapter] hosted by [view].
*
* The [PlatformTextInputAdapter] implementation should call
* [PlatformTextInput.requestInputFocus] when it's ready to start processing text input in order
* to become the active delegate for the platform's IME APIs, and
* [PlatformTextInput.releaseInputFocus] to notify the platform that it is no longer processing
* input.
*/
fun createAdapter(platformTextInput: PlatformTextInput, view: View): T
}
/**
* An adapter for platform-specific IME APIs to implement a text editor. Instances of this interface
* should be created by implementing a singleton [PlatformTextInputPlugin] `object` and passing it
* to [PlatformTextInputPluginRegistry.rememberAdapter]. Instances will be created lazily and cached
* as long as they are used at least once in a given composition. This allows implementations to
* coordinate state between different text fields.
*
* Implementations of this interface are expected to:
* - Call [PlatformTextInput.requestInputFocus] on the [PlatformTextInput] passed to the adapter's
* [PlatformTextInputPlugin] when they are ready to begin processing text input. Platform APIs will
* not be delegated to an adapter unless it holds input focus.
* - Implement [createInputConnection] to create an [InputConnection] that talks to the IME.
* - Return a [TextInputForTests] instance from [inputForTests] that implements text operations
* defined by the Compose UI testing framework.
* - Optionally implement [onDisposed] to clean up any resources when the adapter is no longer used
* in the composition and will be removed from the [PlatformTextInputPluginRegistry]'s cache.
*
* Implementations are intended to be used only by your text editor implementation, and probably not
* exposed as public API. Your adapter can define whatever internal API it needs to communicate with
* the rest of your text editor code.
*/
@ExperimentalTextApi
actual interface PlatformTextInputAdapter {
// TODO(b/267235947) When fleshing out the desktop actual, we might want to pull some of these
// members up into the expect interface (e.g. maybe inputForTests).
/**
* The [TextInputForTests] used to inject text editing commands by the testing framework.
* This should only be called from tests, never in production.
*/
val inputForTests: TextInputForTests?
/** Delegate for [View.onCreateInputConnection]. */
fun createInputConnection(outAttrs: EditorInfo): InputConnection?
/**
* Called when this adapter is not remembered by any composables is removed from the
* [PlatformTextInputPluginRegistry].
*/
fun onDisposed() {}
}
@OptIn(ExperimentalTextApi::class)
internal actual fun PlatformTextInputAdapter.dispose() {
onDisposed()
}