Add singleLine IME Option
Added a KeyboardOptions object since there will be more
configuration options such as autoCorrect, keyboard capitalization,
maybe suggestions, maybe password.
Test: Added new tests
Test: ./gradlew compose:foundation:foundation:test
Test: ./gradlew compose:foundation:foundation:connectedAndroidTest
Test: ./gradlew compose:foundation:foundation-text:test
Test: ./gradlew compose:foundation:foundation-text:connectedAndroidTest
Test: ./gradlew compose:ui:ui-text:test
Test: ./gradlew compose:ui:ui-text:connectedAndroidTest
Test: ./gradlew compose:ui:ui:test
Test: ./gradlew compose:ui:ui:connectedAndroidTest
RelNote: Added single line keyboard option to CoreTextField
Bug: 170482203
Change-Id: I72e6d9f84abbf4ff6a9ede5355de4c30d37c3d8c
diff --git a/compose/foundation/foundation-text/api/current.txt b/compose/foundation/foundation-text/api/current.txt
index cdc3cf3..46efe42 100644
--- a/compose/foundation/foundation-text/api/current.txt
+++ b/compose/foundation/foundation-text/api/current.txt
@@ -2,7 +2,7 @@
package androidx.compose.foundation.text {
public final class CoreTextFieldKt {
- method @androidx.compose.runtime.Composable public static void CoreTextField-J0BxG4A(androidx.compose.ui.text.input.TextFieldValue value, optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.ui.text.input.KeyboardType keyboardType, optional androidx.compose.ui.text.input.ImeAction imeAction, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional long cursorColor, optional boolean softWrap, optional int maxLines);
+ method @androidx.compose.runtime.Composable public static void CoreTextField-wQ2hrV0(androidx.compose.ui.text.input.TextFieldValue value, optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.ui.text.input.KeyboardType keyboardType, optional androidx.compose.ui.text.input.ImeAction imeAction, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional long cursorColor, optional boolean softWrap, optional int maxLines, optional androidx.compose.ui.text.input.KeyboardOptions keyboardOptions);
method @VisibleForTesting public static void setBlinkingCursorEnabled(boolean p);
}
diff --git a/compose/foundation/foundation-text/api/public_plus_experimental_current.txt b/compose/foundation/foundation-text/api/public_plus_experimental_current.txt
index cdc3cf3..46efe42 100644
--- a/compose/foundation/foundation-text/api/public_plus_experimental_current.txt
+++ b/compose/foundation/foundation-text/api/public_plus_experimental_current.txt
@@ -2,7 +2,7 @@
package androidx.compose.foundation.text {
public final class CoreTextFieldKt {
- method @androidx.compose.runtime.Composable public static void CoreTextField-J0BxG4A(androidx.compose.ui.text.input.TextFieldValue value, optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.ui.text.input.KeyboardType keyboardType, optional androidx.compose.ui.text.input.ImeAction imeAction, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional long cursorColor, optional boolean softWrap, optional int maxLines);
+ method @androidx.compose.runtime.Composable public static void CoreTextField-wQ2hrV0(androidx.compose.ui.text.input.TextFieldValue value, optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.ui.text.input.KeyboardType keyboardType, optional androidx.compose.ui.text.input.ImeAction imeAction, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional long cursorColor, optional boolean softWrap, optional int maxLines, optional androidx.compose.ui.text.input.KeyboardOptions keyboardOptions);
method @VisibleForTesting public static void setBlinkingCursorEnabled(boolean p);
}
diff --git a/compose/foundation/foundation-text/api/restricted_current.txt b/compose/foundation/foundation-text/api/restricted_current.txt
index cdc3cf3..46efe42 100644
--- a/compose/foundation/foundation-text/api/restricted_current.txt
+++ b/compose/foundation/foundation-text/api/restricted_current.txt
@@ -2,7 +2,7 @@
package androidx.compose.foundation.text {
public final class CoreTextFieldKt {
- method @androidx.compose.runtime.Composable public static void CoreTextField-J0BxG4A(androidx.compose.ui.text.input.TextFieldValue value, optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.ui.text.input.KeyboardType keyboardType, optional androidx.compose.ui.text.input.ImeAction imeAction, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional long cursorColor, optional boolean softWrap, optional int maxLines);
+ method @androidx.compose.runtime.Composable public static void CoreTextField-wQ2hrV0(androidx.compose.ui.text.input.TextFieldValue value, optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.ui.text.input.KeyboardType keyboardType, optional androidx.compose.ui.text.input.ImeAction imeAction, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional long cursorColor, optional boolean softWrap, optional int maxLines, optional androidx.compose.ui.text.input.KeyboardOptions keyboardOptions);
method @VisibleForTesting public static void setBlinkingCursorEnabled(boolean p);
}
diff --git a/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/src/main/java/androidx/compose/foundation/text/demos/KeyboardOptionsDemo.kt b/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/src/main/java/androidx/compose/foundation/text/demos/KeyboardOptionsDemo.kt
new file mode 100644
index 0000000..de95e3aa
--- /dev/null
+++ b/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/src/main/java/androidx/compose/foundation/text/demos/KeyboardOptionsDemo.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2019 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.foundation.text.demos
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.ScrollableColumn
+import androidx.compose.foundation.layout.defaultMinSizeConstraints
+import androidx.compose.foundation.text.CoreTextField
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.savedinstancestate.savedInstanceState
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.ExperimentalTextApi
+import androidx.compose.ui.text.SoftwareKeyboardController
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardOptions
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.text.input.TextFieldValue
+import androidx.compose.ui.unit.dp
+
+@OptIn(ExperimentalTextApi::class)
+private class Data(
+ val keyboardOptions: KeyboardOptions,
+ val keyboardType: KeyboardType,
+ val name: String,
+ val imeAction: ImeAction = ImeAction.Unspecified
+)
+
+@OptIn(ExperimentalTextApi::class)
+private val KeyboardOptionsList = listOf(
+ Data(
+ keyboardOptions = KeyboardOptions(singleLine = true),
+ keyboardType = KeyboardType.Text,
+ name = "singleLine/Text"
+ ),
+ Data(
+ keyboardOptions = KeyboardOptions(singleLine = false),
+ keyboardType = KeyboardType.Text,
+ name = "multiLine/Text"
+ ),
+ Data(
+ keyboardOptions = KeyboardOptions(singleLine = true),
+ keyboardType = KeyboardType.Text,
+ imeAction = ImeAction.Search,
+ name = "singleLine/Text/Search"
+ ),
+ Data(
+ keyboardOptions = KeyboardOptions(singleLine = true),
+ keyboardType = KeyboardType.Number,
+ name = "singleLine/Number"
+ ),
+ Data(
+ keyboardOptions = KeyboardOptions(singleLine = false),
+ keyboardType = KeyboardType.Number,
+ name = "multiLine/Number"
+ ),
+)
+
+@OptIn(ExperimentalTextApi::class)
+@Composable
+fun KeyboardOptionsDemo() {
+ ScrollableColumn {
+ for (data in KeyboardOptionsList) {
+ TagLine(tag = "${data.name}")
+ MyTextField(data)
+ }
+ }
+}
+
+@Composable
+@OptIn(
+ ExperimentalFoundationApi::class,
+ ExperimentalTextApi::class
+)
+private fun MyTextField(data: Data) {
+ val controller = remember { mutableStateOf<SoftwareKeyboardController?>(null) }
+ val state = savedInstanceState(saver = TextFieldValue.Saver) { TextFieldValue() }
+ CoreTextField(
+ modifier = demoTextFieldModifiers.defaultMinSizeConstraints(100.dp),
+ value = state.value,
+ keyboardType = data.keyboardType,
+ imeAction = data.imeAction,
+ keyboardOptions = data.keyboardOptions,
+ onValueChange = { state.value = it },
+ textStyle = TextStyle(fontSize = fontSize8),
+ onTextInputStarted = { controller.value = it },
+ onImeActionPerformed = {
+ controller.value?.hideSoftwareKeyboard()
+ },
+ cursorColor = Color.Red
+ )
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/src/main/java/androidx/compose/foundation/text/demos/TextDemos.kt b/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/src/main/java/androidx/compose/foundation/text/demos/TextDemos.kt
index 670c653..392f211 100644
--- a/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/src/main/java/androidx/compose/foundation/text/demos/TextDemos.kt
+++ b/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/src/main/java/androidx/compose/foundation/text/demos/TextDemos.kt
@@ -38,6 +38,7 @@
ComposableDemo("TextField in Scroller") { TextFieldWithScrollerDemo() },
ComposableDemo("Soft Wrap") { SoftWrapDemo() },
ComposableDemo("Min/Max Lines") { CoreTextFieldMinMaxDemo() },
+ ComposableDemo("Keyboard Options") { KeyboardOptionsDemo() }
)
),
ComposableDemo("Text Accessibility") { TextAccessibilityDemo() }
diff --git a/compose/foundation/foundation-text/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/CoreTextFieldInputServiceIntegrationTest.kt b/compose/foundation/foundation-text/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/CoreTextFieldInputServiceIntegrationTest.kt
new file mode 100644
index 0000000..bfb5964
--- /dev/null
+++ b/compose/foundation/foundation-text/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/CoreTextFieldInputServiceIntegrationTest.kt
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2020 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.foundation.text
+
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.ExperimentalFocus
+import androidx.compose.ui.focus.isFocused
+import androidx.compose.ui.focusObserver
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.text.ExperimentalTextApi
+import androidx.compose.ui.text.InternalTextApi
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardOptions
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.text.input.PlatformTextInputService
+import androidx.compose.ui.text.input.TextFieldValue
+import androidx.compose.ui.text.input.TextInputService
+import androidx.compose.ui.text.input.textInputServiceFactory
+import androidx.test.filters.LargeTest
+import androidx.ui.test.createComposeRule
+import androidx.ui.test.onNodeWithTag
+import androidx.ui.test.performClick
+import com.google.common.truth.Truth.assertThat
+import com.nhaarman.mockitokotlin2.any
+import com.nhaarman.mockitokotlin2.eq
+import com.nhaarman.mockitokotlin2.mock
+import com.nhaarman.mockitokotlin2.times
+import com.nhaarman.mockitokotlin2.verify
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(
+ ExperimentalTextApi::class,
+ InternalTextApi::class,
+ ExperimentalFocus::class
+)
+@LargeTest
+@RunWith(JUnit4::class)
+class CoreTextFieldInputServiceIntegrationTest {
+
+ @get:Rule
+ val rule = createComposeRule()
+
+ @Test
+ fun textField_KeyboardOptions_isPassedTo_platformTextInputService() {
+ val platformTextInputService = mock<PlatformTextInputService>()
+ @Suppress("DEPRECATION_ERROR")
+ textInputServiceFactory = { TextInputService(platformTextInputService) }
+
+ val testTag = "KeyboardOption"
+ val value = TextFieldValue("abc")
+ val keyboardOptions = KeyboardOptions(singleLine = true)
+ val keyboardType = KeyboardType.Phone
+ val imeAction = ImeAction.Search
+ var focused = false
+
+ rule.setContent {
+ CoreTextField(
+ value = value,
+ keyboardOptions = keyboardOptions,
+ keyboardType = keyboardType,
+ imeAction = imeAction,
+ modifier = Modifier
+ .testTag(testTag)
+ .focusObserver { focused = it.isFocused },
+ onValueChange = {}
+ )
+ }
+
+ rule.onNodeWithTag(testTag).performClick()
+
+ rule.runOnIdle {
+ assertThat(focused).isTrue()
+
+ verify(platformTextInputService, times(1)).startInput(
+ eq(value),
+ eq(keyboardType),
+ eq(imeAction),
+ eq(keyboardOptions),
+ any(), // onEditCommand
+ any() // onImeActionPerformed
+ )
+ }
+ }
+}
diff --git a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
index a942674..926d215 100644
--- a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
+++ b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
@@ -81,6 +81,7 @@
import androidx.compose.ui.semantics.text
import androidx.compose.ui.semantics.textSelectionRange
import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.InternalTextApi
import androidx.compose.ui.text.SoftwareKeyboardController
import androidx.compose.ui.text.TextDelegate
@@ -90,6 +91,7 @@
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.input.EditProcessor
import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardOptions
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.NO_SESSION
import androidx.compose.ui.text.input.OffsetMap
@@ -152,7 +154,8 @@
@Composable
@OptIn(
ExperimentalFocus::class,
- InternalTextApi::class
+ InternalTextApi::class,
+ ExperimentalTextApi::class
)
fun CoreTextField(
value: TextFieldValue,
@@ -167,7 +170,8 @@
onTextInputStarted: (SoftwareKeyboardController) -> Unit = {},
cursorColor: Color = Color.Unspecified,
softWrap: Boolean = true,
- maxLines: Int = Int.MAX_VALUE
+ maxLines: Int = Int.MAX_VALUE,
+ keyboardOptions: KeyboardOptions = KeyboardOptions.Default
) {
require(maxLines > 0) {
"maxLines should be greater than 0"
@@ -244,6 +248,7 @@
state.processor,
keyboardType,
imeAction,
+ keyboardOptions,
onValueChangeWrapper,
onImeActionPerformedWrapper
)
diff --git a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldDelegate.kt b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldDelegate.kt
index e541372..8eb3f9b 100644
--- a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldDelegate.kt
+++ b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldDelegate.kt
@@ -24,6 +24,7 @@
import androidx.compose.ui.graphics.Paint
import androidx.compose.ui.layout.LayoutCoordinates
import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.InternalTextApi
import androidx.compose.ui.text.Paragraph
import androidx.compose.ui.text.SpanStyle
@@ -39,6 +40,7 @@
import androidx.compose.ui.text.input.INVALID_SESSION
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.InputSessionToken
+import androidx.compose.ui.text.input.KeyboardOptions
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.OffsetMap
import androidx.compose.ui.text.input.SetSelectionEditOp
@@ -86,7 +88,10 @@
private fun Float.toIntPx(): Int = ceil(this).roundToInt()
/** @suppress **/
-@OptIn(InternalTextApi::class)
+@OptIn(
+ InternalTextApi::class,
+ ExperimentalTextApi::class
+)
@InternalTextApi
class TextFieldDelegate {
companion object {
@@ -276,6 +281,7 @@
editProcessor: EditProcessor,
keyboardType: KeyboardType,
imeAction: ImeAction,
+ keyboardOptions: KeyboardOptions,
onValueChange: (TextFieldValue) -> Unit,
onImeActionPerformed: (ImeAction) -> Unit
): InputSessionToken {
@@ -283,6 +289,7 @@
value = TextFieldValue(value.text, value.selection, value.composition),
keyboardType = keyboardType,
imeAction = imeAction,
+ keyboardOptions = keyboardOptions,
onEditCommand = { onEditCommand(it, editProcessor, onValueChange) },
onImeActionPerformed = onImeActionPerformed
) ?: INVALID_SESSION
diff --git a/compose/foundation/foundation-text/src/test/kotlin/androidx/compose/foundation/text/TextFieldDelegateTest.kt b/compose/foundation/foundation-text/src/test/kotlin/androidx/compose/foundation/text/TextFieldDelegateTest.kt
index d8f4d2b..1c91499 100644
--- a/compose/foundation/foundation-text/src/test/kotlin/androidx/compose/foundation/text/TextFieldDelegateTest.kt
+++ b/compose/foundation/foundation-text/src/test/kotlin/androidx/compose/foundation/text/TextFieldDelegateTest.kt
@@ -24,6 +24,7 @@
import androidx.compose.ui.layout.LayoutCoordinates
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.InternalTextApi
+import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.MultiParagraphIntrinsics
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextDelegate
@@ -37,6 +38,7 @@
import androidx.compose.ui.text.input.FinishComposingTextEditOp
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.text.input.KeyboardOptions
import androidx.compose.ui.text.input.OffsetMap
import androidx.compose.ui.text.input.SetSelectionEditOp
import androidx.compose.ui.text.input.TextFieldValue
@@ -65,7 +67,10 @@
import org.junit.runners.JUnit4
import org.mockito.ArgumentMatchers.anyLong
-@OptIn(InternalTextApi::class)
+@OptIn(
+ InternalTextApi::class,
+ ExperimentalTextApi::class
+)
@RunWith(JUnit4::class)
class TextFieldDelegateTest {
@@ -157,10 +162,19 @@
@Test
fun on_focus() {
val editorState = TextFieldValue(text = "Hello, World", selection = TextRange(1))
+ val keyboardOptions = KeyboardOptions(singleLine = true)
+ val keyboardType = KeyboardType.Phone
+ val imeAction = ImeAction.Search
TextFieldDelegate.onFocus(
- textInputService, editorState, processor,
- KeyboardType.Text, ImeAction.Unspecified, onValueChange, onEditorActionPerformed
+ textInputService = textInputService,
+ value = editorState,
+ editProcessor = processor,
+ keyboardType = keyboardType,
+ imeAction = imeAction,
+ keyboardOptions = keyboardOptions,
+ onValueChange = onValueChange,
+ onImeActionPerformed = onEditorActionPerformed
)
verify(textInputService).startInput(
eq(
@@ -169,8 +183,9 @@
selection = editorState.selection
)
),
- eq(KeyboardType.Text),
- eq(ImeAction.Unspecified),
+ eq(keyboardType),
+ eq(imeAction),
+ eq(keyboardOptions),
any(),
eq(onEditorActionPerformed)
)
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/SoftwareKeyboardTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/SoftwareKeyboardTest.kt
index ded0103..eee18da 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/SoftwareKeyboardTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/SoftwareKeyboardTest.kt
@@ -51,7 +51,7 @@
val textInputService = mock<TextInputService>()
val inputSessionToken = 10 // any positive number is fine.
- whenever(textInputService.startInput(any(), any(), any(), any(), any()))
+ whenever(textInputService.startInput(any(), any(), any(), any(), any(), any()))
.thenReturn(inputSessionToken)
val onTextInputStarted: (SoftwareKeyboardController) -> Unit = mock()
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/TextFieldOnValueChangeTextFieldValueTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/TextFieldOnValueChangeTextFieldValueTest.kt
index c795a76..6e0279c 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/TextFieldOnValueChangeTextFieldValueTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/TextFieldOnValueChangeTextFieldValueTest.kt
@@ -66,7 +66,7 @@
val textInputService = mock<TextInputService>()
val inputSessionToken = 10 // any positive number is fine.
- whenever(textInputService.startInput(any(), any(), any(), any(), any()))
+ whenever(textInputService.startInput(any(), any(), any(), any(), any(), any()))
.thenReturn(inputSessionToken)
rule.setContent {
@@ -102,6 +102,7 @@
value = any(),
keyboardType = any(),
imeAction = any(),
+ keyboardOptions = any(),
onEditCommand = onEditCommandCaptor.capture(),
onImeActionPerformed = any()
)
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/TextFieldTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/TextFieldTest.kt
index 255743c..0439062 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/TextFieldTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/TextFieldTest.kt
@@ -149,7 +149,7 @@
val textInputService = mock<TextInputService>()
val inputSessionToken = 10 // any positive number is fine.
- whenever(textInputService.startInput(any(), any(), any(), any(), any()))
+ whenever(textInputService.startInput(any(), any(), any(), any(), any(), any()))
.thenReturn(inputSessionToken)
rule.setContent {
@@ -170,6 +170,7 @@
value = any(),
keyboardType = any(),
imeAction = any(),
+ keyboardOptions = any(),
onEditCommand = onEditCommandCaptor.capture(),
onImeActionPerformed = any()
)
@@ -221,7 +222,7 @@
val textInputService = mock<TextInputService>()
val inputSessionToken = 10 // any positive number is fine.
- whenever(textInputService.startInput(any(), any(), any(), any(), any()))
+ whenever(textInputService.startInput(any(), any(), any(), any(), any(), any()))
.thenReturn(inputSessionToken)
rule.setContent {
@@ -242,6 +243,7 @@
value = any(),
keyboardType = any(),
imeAction = any(),
+ keyboardOptions = any(),
onEditCommand = onEditCommandCaptor.capture(),
onImeActionPerformed = any()
)
@@ -280,7 +282,7 @@
val textInputService = mock<TextInputService>()
val inputSessionToken = 10 // any positive number is fine.
- whenever(textInputService.startInput(any(), any(), any(), any(), any()))
+ whenever(textInputService.startInput(any(), any(), any(), any(), any(), any()))
.thenReturn(inputSessionToken)
val onTextLayout: (TextLayoutResult) -> Unit = mock()
@@ -310,6 +312,7 @@
value = any(),
keyboardType = any(),
imeAction = any(),
+ keyboardOptions = any(),
onEditCommand = onEditCommandCaptor.capture(),
onImeActionPerformed = any()
)
diff --git a/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/text/TextFieldToggleTextTestCase.kt b/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/text/TextFieldToggleTextTestCase.kt
index b5ccede..944a9fe 100644
--- a/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/text/TextFieldToggleTextTestCase.kt
+++ b/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/text/TextFieldToggleTextTestCase.kt
@@ -31,10 +31,12 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.InternalTextApi
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.EditOperation
import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardOptions
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PlatformTextInputService
import androidx.compose.ui.text.input.TextFieldValue
@@ -98,11 +100,13 @@
}
}
+ @OptIn(ExperimentalTextApi::class)
private class TestPlatformTextInputService : PlatformTextInputService {
override fun startInput(
value: TextFieldValue,
keyboardType: KeyboardType,
imeAction: ImeAction,
+ keyboardOptions: KeyboardOptions,
onEditCommand: (List<EditOperation>) -> Unit,
onImeActionPerformed: (ImeAction) -> Unit
) { /*do nothing*/ }
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/OutlinedTextFieldTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/OutlinedTextFieldTest.kt
index 986006d..11559b0 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/OutlinedTextFieldTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/OutlinedTextFieldTest.kt
@@ -610,6 +610,7 @@
value = any(),
keyboardType = eq(KeyboardType.Email),
imeAction = eq(ImeAction.Go),
+ keyboardOptions = any(),
onEditCommand = any(),
onImeActionPerformed = any()
)
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt
index 96d2e60..5c39c09 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt
@@ -763,6 +763,7 @@
value = any(),
keyboardType = eq(KeyboardType.Email),
imeAction = eq(ImeAction.Go),
+ keyboardOptions = any(),
onEditCommand = any(),
onImeActionPerformed = any()
)
diff --git a/compose/ui/ui-text/api/current.txt b/compose/ui/ui-text/api/current.txt
index d0156749..45bc91f 100644
--- a/compose/ui/ui-text/api/current.txt
+++ b/compose/ui/ui-text/api/current.txt
@@ -72,6 +72,9 @@
method public static inline <R> R withStyle(androidx.compose.ui.text.AnnotatedString.Builder, androidx.compose.ui.text.ParagraphStyle style, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.AnnotatedString.Builder,? extends R> block);
}
+ @kotlin.RequiresOptIn(level=kotlin.RequiresOptIn.Level, message="This is an experimental text API that may change without warning.") @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget}) public @interface ExperimentalTextApi {
+ }
+
@kotlin.RequiresOptIn(level=kotlin.RequiresOptIn.Level, message="This is internal API that may change frequently and without warning.") @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget}) public @interface InternalTextApi {
}
@@ -780,6 +783,20 @@
method public void onImeAction(androidx.compose.ui.text.input.ImeAction imeAction);
}
+ @androidx.compose.runtime.Immutable @androidx.compose.ui.text.ExperimentalTextApi public final class KeyboardOptions {
+ ctor public KeyboardOptions(boolean singleLine);
+ method public boolean component1();
+ method @androidx.compose.runtime.Immutable @androidx.compose.ui.text.ExperimentalTextApi public androidx.compose.ui.text.input.KeyboardOptions copy(boolean singleLine);
+ method public boolean getSingleLine();
+ property public final boolean singleLine;
+ field public static final androidx.compose.ui.text.input.KeyboardOptions.Companion Companion;
+ }
+
+ public static final class KeyboardOptions.Companion {
+ method public androidx.compose.ui.text.input.KeyboardOptions getDefault();
+ property public final androidx.compose.ui.text.input.KeyboardOptions Default;
+ }
+
public enum KeyboardType {
enum_constant public static final androidx.compose.ui.text.input.KeyboardType Ascii;
enum_constant public static final androidx.compose.ui.text.input.KeyboardType Email;
@@ -826,7 +843,7 @@
method public void notifyFocusedRect(androidx.compose.ui.geometry.Rect rect);
method public void onStateUpdated(androidx.compose.ui.text.input.TextFieldValue value);
method public void showSoftwareKeyboard();
- method public void startInput(androidx.compose.ui.text.input.TextFieldValue value, androidx.compose.ui.text.input.KeyboardType keyboardType, androidx.compose.ui.text.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.compose.ui.text.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+ method public void startInput(androidx.compose.ui.text.input.TextFieldValue value, androidx.compose.ui.text.input.KeyboardType keyboardType, androidx.compose.ui.text.input.ImeAction imeAction, androidx.compose.ui.text.input.KeyboardOptions keyboardOptions, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.compose.ui.text.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed);
method public void stopInput();
}
@@ -897,7 +914,7 @@
method public void notifyFocusedRect(int token, androidx.compose.ui.geometry.Rect rect);
method public void onStateUpdated(int token, androidx.compose.ui.text.input.TextFieldValue value);
method public void showSoftwareKeyboard(int token);
- method public int startInput(androidx.compose.ui.text.input.TextFieldValue value, androidx.compose.ui.text.input.KeyboardType keyboardType, androidx.compose.ui.text.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.compose.ui.text.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+ method public int startInput(androidx.compose.ui.text.input.TextFieldValue value, androidx.compose.ui.text.input.KeyboardType keyboardType, androidx.compose.ui.text.input.ImeAction imeAction, androidx.compose.ui.text.input.KeyboardOptions keyboardOptions, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.compose.ui.text.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed);
method public void stopInput(int token);
}
diff --git a/compose/ui/ui-text/api/public_plus_experimental_current.txt b/compose/ui/ui-text/api/public_plus_experimental_current.txt
index d0156749..45bc91f 100644
--- a/compose/ui/ui-text/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui-text/api/public_plus_experimental_current.txt
@@ -72,6 +72,9 @@
method public static inline <R> R withStyle(androidx.compose.ui.text.AnnotatedString.Builder, androidx.compose.ui.text.ParagraphStyle style, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.AnnotatedString.Builder,? extends R> block);
}
+ @kotlin.RequiresOptIn(level=kotlin.RequiresOptIn.Level, message="This is an experimental text API that may change without warning.") @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget}) public @interface ExperimentalTextApi {
+ }
+
@kotlin.RequiresOptIn(level=kotlin.RequiresOptIn.Level, message="This is internal API that may change frequently and without warning.") @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget}) public @interface InternalTextApi {
}
@@ -780,6 +783,20 @@
method public void onImeAction(androidx.compose.ui.text.input.ImeAction imeAction);
}
+ @androidx.compose.runtime.Immutable @androidx.compose.ui.text.ExperimentalTextApi public final class KeyboardOptions {
+ ctor public KeyboardOptions(boolean singleLine);
+ method public boolean component1();
+ method @androidx.compose.runtime.Immutable @androidx.compose.ui.text.ExperimentalTextApi public androidx.compose.ui.text.input.KeyboardOptions copy(boolean singleLine);
+ method public boolean getSingleLine();
+ property public final boolean singleLine;
+ field public static final androidx.compose.ui.text.input.KeyboardOptions.Companion Companion;
+ }
+
+ public static final class KeyboardOptions.Companion {
+ method public androidx.compose.ui.text.input.KeyboardOptions getDefault();
+ property public final androidx.compose.ui.text.input.KeyboardOptions Default;
+ }
+
public enum KeyboardType {
enum_constant public static final androidx.compose.ui.text.input.KeyboardType Ascii;
enum_constant public static final androidx.compose.ui.text.input.KeyboardType Email;
@@ -826,7 +843,7 @@
method public void notifyFocusedRect(androidx.compose.ui.geometry.Rect rect);
method public void onStateUpdated(androidx.compose.ui.text.input.TextFieldValue value);
method public void showSoftwareKeyboard();
- method public void startInput(androidx.compose.ui.text.input.TextFieldValue value, androidx.compose.ui.text.input.KeyboardType keyboardType, androidx.compose.ui.text.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.compose.ui.text.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+ method public void startInput(androidx.compose.ui.text.input.TextFieldValue value, androidx.compose.ui.text.input.KeyboardType keyboardType, androidx.compose.ui.text.input.ImeAction imeAction, androidx.compose.ui.text.input.KeyboardOptions keyboardOptions, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.compose.ui.text.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed);
method public void stopInput();
}
@@ -897,7 +914,7 @@
method public void notifyFocusedRect(int token, androidx.compose.ui.geometry.Rect rect);
method public void onStateUpdated(int token, androidx.compose.ui.text.input.TextFieldValue value);
method public void showSoftwareKeyboard(int token);
- method public int startInput(androidx.compose.ui.text.input.TextFieldValue value, androidx.compose.ui.text.input.KeyboardType keyboardType, androidx.compose.ui.text.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.compose.ui.text.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+ method public int startInput(androidx.compose.ui.text.input.TextFieldValue value, androidx.compose.ui.text.input.KeyboardType keyboardType, androidx.compose.ui.text.input.ImeAction imeAction, androidx.compose.ui.text.input.KeyboardOptions keyboardOptions, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.compose.ui.text.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed);
method public void stopInput(int token);
}
diff --git a/compose/ui/ui-text/api/restricted_current.txt b/compose/ui/ui-text/api/restricted_current.txt
index d0156749..45bc91f 100644
--- a/compose/ui/ui-text/api/restricted_current.txt
+++ b/compose/ui/ui-text/api/restricted_current.txt
@@ -72,6 +72,9 @@
method public static inline <R> R withStyle(androidx.compose.ui.text.AnnotatedString.Builder, androidx.compose.ui.text.ParagraphStyle style, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.AnnotatedString.Builder,? extends R> block);
}
+ @kotlin.RequiresOptIn(level=kotlin.RequiresOptIn.Level, message="This is an experimental text API that may change without warning.") @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget}) public @interface ExperimentalTextApi {
+ }
+
@kotlin.RequiresOptIn(level=kotlin.RequiresOptIn.Level, message="This is internal API that may change frequently and without warning.") @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget}) public @interface InternalTextApi {
}
@@ -780,6 +783,20 @@
method public void onImeAction(androidx.compose.ui.text.input.ImeAction imeAction);
}
+ @androidx.compose.runtime.Immutable @androidx.compose.ui.text.ExperimentalTextApi public final class KeyboardOptions {
+ ctor public KeyboardOptions(boolean singleLine);
+ method public boolean component1();
+ method @androidx.compose.runtime.Immutable @androidx.compose.ui.text.ExperimentalTextApi public androidx.compose.ui.text.input.KeyboardOptions copy(boolean singleLine);
+ method public boolean getSingleLine();
+ property public final boolean singleLine;
+ field public static final androidx.compose.ui.text.input.KeyboardOptions.Companion Companion;
+ }
+
+ public static final class KeyboardOptions.Companion {
+ method public androidx.compose.ui.text.input.KeyboardOptions getDefault();
+ property public final androidx.compose.ui.text.input.KeyboardOptions Default;
+ }
+
public enum KeyboardType {
enum_constant public static final androidx.compose.ui.text.input.KeyboardType Ascii;
enum_constant public static final androidx.compose.ui.text.input.KeyboardType Email;
@@ -826,7 +843,7 @@
method public void notifyFocusedRect(androidx.compose.ui.geometry.Rect rect);
method public void onStateUpdated(androidx.compose.ui.text.input.TextFieldValue value);
method public void showSoftwareKeyboard();
- method public void startInput(androidx.compose.ui.text.input.TextFieldValue value, androidx.compose.ui.text.input.KeyboardType keyboardType, androidx.compose.ui.text.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.compose.ui.text.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+ method public void startInput(androidx.compose.ui.text.input.TextFieldValue value, androidx.compose.ui.text.input.KeyboardType keyboardType, androidx.compose.ui.text.input.ImeAction imeAction, androidx.compose.ui.text.input.KeyboardOptions keyboardOptions, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.compose.ui.text.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed);
method public void stopInput();
}
@@ -897,7 +914,7 @@
method public void notifyFocusedRect(int token, androidx.compose.ui.geometry.Rect rect);
method public void onStateUpdated(int token, androidx.compose.ui.text.input.TextFieldValue value);
method public void showSoftwareKeyboard(int token);
- method public int startInput(androidx.compose.ui.text.input.TextFieldValue value, androidx.compose.ui.text.input.KeyboardType keyboardType, androidx.compose.ui.text.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.compose.ui.text.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+ method public int startInput(androidx.compose.ui.text.input.TextFieldValue value, androidx.compose.ui.text.input.KeyboardType keyboardType, androidx.compose.ui.text.input.ImeAction imeAction, androidx.compose.ui.text.input.KeyboardOptions keyboardOptions, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.compose.ui.text.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed);
method public void stopInput(int token);
}
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/ExperimentalTextApi.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/ExperimentalTextApi.kt
new file mode 100644
index 0000000..c8559ed
--- /dev/null
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/ExperimentalTextApi.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2020 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
+
+@RequiresOptIn(
+ level = RequiresOptIn.Level.ERROR,
+ message = "This is an experimental text API that may change without warning."
+)
+@Target(
+ AnnotationTarget.CLASS,
+ AnnotationTarget.FUNCTION,
+ AnnotationTarget.PROPERTY
+)
+annotation class ExperimentalTextApi
\ No newline at end of file
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/KeyboardOptions.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/KeyboardOptions.kt
new file mode 100644
index 0000000..132f359
--- /dev/null
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/KeyboardOptions.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2020 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 androidx.compose.runtime.Immutable
+import androidx.compose.ui.text.ExperimentalTextApi
+
+/**
+ * The keyboard configuration options for text field. It is not guaranteed if a software keyboard
+ * will comply with the options provided here.
+ *
+ * @param singleLine signals the keyboard that the text field is single line and keyboard should
+ * not show enter action.
+ */
+@ExperimentalTextApi
+@Immutable
+data class KeyboardOptions(val singleLine: Boolean) {
+ companion object {
+ val Default = KeyboardOptions(
+ singleLine = false
+ )
+ }
+}
\ No newline at end of file
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/TextInputService.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/TextInputService.kt
index 22097e8..af755c7 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/TextInputService.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/TextInputService.kt
@@ -17,6 +17,7 @@
package androidx.compose.ui.text.input
import androidx.compose.ui.geometry.Rect
+import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.InternalTextApi
import androidx.compose.ui.util.annotation.VisibleForTesting
@@ -43,6 +44,7 @@
* Provide a communication with platform text input service.
*/
// Open for testing purposes.
+@OptIn(ExperimentalTextApi::class)
open class TextInputService(private val platformTextInputService: PlatformTextInputService) {
private var nextSessionToken: Int = 1
@@ -61,6 +63,7 @@
value: TextFieldValue,
keyboardType: KeyboardType,
imeAction: ImeAction,
+ keyboardOptions: KeyboardOptions,
onEditCommand: (List<EditOperation>) -> Unit,
onImeActionPerformed: (ImeAction) -> Unit
): InputSessionToken {
@@ -68,6 +71,7 @@
value,
keyboardType,
imeAction,
+ keyboardOptions,
onEditCommand,
onImeActionPerformed
)
@@ -120,6 +124,7 @@
/**
* Platform specific text input service.
*/
+@OptIn(ExperimentalTextApi::class)
interface PlatformTextInputService {
/**
* Start text input session for given client.
@@ -128,6 +133,7 @@
value: TextFieldValue,
keyboardType: KeyboardType,
imeAction: ImeAction,
+ keyboardOptions: KeyboardOptions,
onEditCommand: (List<EditOperation>) -> Unit,
onImeActionPerformed: (ImeAction) -> Unit
)
diff --git a/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/TextInputServiceTest.kt b/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/TextInputServiceTest.kt
index 1e812de..48ae334 100644
--- a/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/TextInputServiceTest.kt
+++ b/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/TextInputServiceTest.kt
@@ -20,6 +20,7 @@
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardOptions
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PlatformTextInputService
import androidx.compose.ui.text.input.TextFieldValue
@@ -35,6 +36,7 @@
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
+@OptIn(ExperimentalTextApi::class)
@RunWith(JUnit4::class)
class TextInputServiceTest {
@@ -48,6 +50,7 @@
TextFieldValue(),
KeyboardType.Text,
ImeAction.NoAction,
+ KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
)
@@ -55,6 +58,7 @@
TextFieldValue(),
KeyboardType.Text,
ImeAction.NoAction,
+ KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
)
@@ -72,6 +76,7 @@
TextFieldValue(),
KeyboardType.Text,
ImeAction.NoAction,
+ KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
)
@@ -90,6 +95,7 @@
TextFieldValue(),
KeyboardType.Text,
ImeAction.NoAction,
+ KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
)
@@ -99,6 +105,7 @@
TextFieldValue(),
KeyboardType.Text,
ImeAction.NoAction,
+ KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
)
@@ -117,6 +124,7 @@
TextFieldValue(),
KeyboardType.Text,
ImeAction.NoAction,
+ KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
)
@@ -135,6 +143,7 @@
TextFieldValue(),
KeyboardType.Text,
ImeAction.NoAction,
+ KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
)
@@ -144,6 +153,7 @@
TextFieldValue(),
KeyboardType.Text,
ImeAction.NoAction,
+ KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
)
@@ -162,6 +172,7 @@
TextFieldValue(),
KeyboardType.Text,
ImeAction.NoAction,
+ KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
)
@@ -181,6 +192,7 @@
TextFieldValue(),
KeyboardType.Text,
ImeAction.NoAction,
+ KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
)
@@ -190,6 +202,7 @@
TextFieldValue(),
KeyboardType.Text,
ImeAction.NoAction,
+ KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
)
@@ -209,6 +222,7 @@
TextFieldValue(),
KeyboardType.Text,
ImeAction.NoAction,
+ KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
)
@@ -228,6 +242,7 @@
TextFieldValue(),
KeyboardType.Text,
ImeAction.NoAction,
+ KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
)
@@ -237,6 +252,7 @@
TextFieldValue(),
KeyboardType.Text,
ImeAction.NoAction,
+ KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
)
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/TextInputServiceAndroid.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/TextInputServiceAndroid.kt
index ff90fba..eb87d61 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/TextInputServiceAndroid.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/TextInputServiceAndroid.kt
@@ -24,12 +24,14 @@
import android.view.inputmethod.InputConnection
import android.view.inputmethod.InputMethodManager
import androidx.compose.ui.geometry.Rect
+import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.TextRange
import kotlin.math.roundToInt
/**
* Provide Android specific input service with the Operating System.
*/
+@OptIn(ExperimentalTextApi::class)
internal class TextInputServiceAndroid(val view: View) : PlatformTextInputService {
/** True if the currently editable composable has connected */
private var editorHasFocus = false
@@ -44,8 +46,8 @@
private var state = TextFieldValue(text = "", selection = TextRange.Zero)
private var keyboardType = KeyboardType.Text
private var imeAction = ImeAction.Unspecified
+ private var keyboardOptions = KeyboardOptions.Default
private var ic: RecordingInputConnection? = null
-
private var focusedRect: android.graphics.Rect? = null
/**
@@ -78,7 +80,7 @@
if (!editorHasFocus) {
return null
}
- fillEditorInfo(keyboardType, imeAction, outAttrs)
+ fillEditorInfo(keyboardType, imeAction, keyboardOptions, outAttrs)
return RecordingInputConnection(
initState = state,
@@ -103,6 +105,7 @@
value: TextFieldValue,
keyboardType: KeyboardType,
imeAction: ImeAction,
+ keyboardOptions: KeyboardOptions,
onEditCommand: (List<EditOperation>) -> Unit,
onImeActionPerformed: (ImeAction) -> Unit
) {
@@ -111,6 +114,7 @@
state = value
this.keyboardType = keyboardType
this.imeAction = imeAction
+ this.keyboardOptions = keyboardOptions
this.onEditCommand = onEditCommand
this.onImeActionPerformed = onImeActionPerformed
@@ -168,10 +172,20 @@
private fun fillEditorInfo(
keyboardType: KeyboardType,
imeAction: ImeAction,
+ keyboardOptions: KeyboardOptions,
outInfo: EditorInfo
) {
outInfo.imeOptions = when (imeAction) {
- ImeAction.Unspecified -> EditorInfo.IME_ACTION_UNSPECIFIED
+ ImeAction.Unspecified -> {
+ if (keyboardOptions.singleLine) {
+ // this is the last resort to enable single line
+ // Android IME still show return key even if multi line is not send
+ // TextView.java#onCreateInputConnection
+ EditorInfo.IME_ACTION_DONE
+ } else {
+ EditorInfo.IME_ACTION_UNSPECIFIED
+ }
+ }
ImeAction.NoAction -> EditorInfo.IME_ACTION_NONE
ImeAction.Go -> EditorInfo.IME_ACTION_GO
ImeAction.Next -> EditorInfo.IME_ACTION_NEXT
@@ -204,7 +218,14 @@
}
else -> throw IllegalArgumentException("Unknown KeyboardType: $keyboardType")
}
- outInfo.imeOptions =
- outInfo.imeOptions or outInfo.imeOptions or EditorInfo.IME_FLAG_NO_FULLSCREEN
+
+ if (!keyboardOptions.singleLine) {
+ // TextView.java#setInputTypeSingleLine
+ outInfo.inputType = outInfo.inputType or InputType.TYPE_TEXT_FLAG_MULTI_LINE
+ // TextView.java#onCreateInputConnection
+ outInfo.imeOptions = outInfo.imeOptions or EditorInfo.IME_FLAG_NO_ENTER_ACTION
+ }
+
+ outInfo.imeOptions = outInfo.imeOptions or EditorInfo.IME_FLAG_NO_FULLSCREEN
}
}
\ No newline at end of file
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopPlatformInput.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopPlatformInput.kt
index bab8084..f8102ed 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopPlatformInput.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopPlatformInput.kt
@@ -16,11 +16,13 @@
package androidx.compose.ui.platform
import androidx.compose.ui.geometry.Rect
+import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.input.BackspaceKeyEditOp
import androidx.compose.ui.text.input.CommitTextEditOp
import androidx.compose.ui.text.input.DeleteSurroundingTextInCodePointsEditOp
import androidx.compose.ui.text.input.EditOperation
import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardOptions
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.MoveCursorEditOp
import androidx.compose.ui.text.input.PlatformTextInputService
@@ -47,6 +49,7 @@
fun locationOnScreen(): Point
}
+@OptIn(ExperimentalTextApi::class)
internal class DesktopPlatformInput(val component: DesktopComponent) :
PlatformTextInputService {
data class CurrentInput(
@@ -66,6 +69,7 @@
value: TextFieldValue,
keyboardType: KeyboardType,
imeAction: ImeAction,
+ keyboardOptions: KeyboardOptions,
onEditCommand: (List<EditOperation>) -> Unit,
onImeActionPerformed: (ImeAction) -> Unit
) {
diff --git a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/input/TextInputServiceAndroidTest.kt b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/input/TextInputServiceAndroidTest.kt
index dd0a6d5..9c44467 100644
--- a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/input/TextInputServiceAndroidTest.kt
+++ b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/input/TextInputServiceAndroidTest.kt
@@ -21,7 +21,9 @@
import android.view.View
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
+import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardOptions
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.TextInputServiceAndroid
@@ -30,11 +32,13 @@
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.whenever
import org.junit.Assert.assertTrue
+import org.junit.Assert.assertFalse
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
+@OptIn(ExperimentalTextApi::class)
@SmallTest
@RunWith(JUnit4::class)
class TextInputServiceAndroidTest {
@@ -58,6 +62,7 @@
TextFieldValue(""),
KeyboardType.Text,
ImeAction.Unspecified,
+ KeyboardOptions.Default,
onEditCommand = {},
onImeActionPerformed = {}
)
@@ -78,6 +83,7 @@
TextFieldValue(""),
KeyboardType.Ascii,
ImeAction.Unspecified,
+ KeyboardOptions.Default,
onEditCommand = {},
onImeActionPerformed = {}
)
@@ -99,6 +105,7 @@
TextFieldValue(""),
KeyboardType.Number,
ImeAction.Unspecified,
+ KeyboardOptions.Default,
onEditCommand = {},
onImeActionPerformed = {}
)
@@ -119,6 +126,7 @@
TextFieldValue(""),
KeyboardType.Phone,
ImeAction.Unspecified,
+ KeyboardOptions.Default,
onEditCommand = {},
onImeActionPerformed = {}
)
@@ -139,6 +147,7 @@
TextFieldValue(""),
KeyboardType.Uri,
ImeAction.Unspecified,
+ KeyboardOptions.Default,
onEditCommand = {},
onImeActionPerformed = {}
)
@@ -160,6 +169,7 @@
TextFieldValue(""),
KeyboardType.Email,
ImeAction.Unspecified,
+ KeyboardOptions.Default,
onEditCommand = {},
onImeActionPerformed = {}
)
@@ -181,6 +191,7 @@
TextFieldValue(""),
KeyboardType.Password,
ImeAction.Unspecified,
+ KeyboardOptions.Default,
onEditCommand = {},
onImeActionPerformed = {}
)
@@ -202,6 +213,7 @@
TextFieldValue(""),
KeyboardType.NumberPassword,
ImeAction.Unspecified,
+ KeyboardOptions.Default,
onEditCommand = {},
onImeActionPerformed = {}
)
@@ -223,6 +235,7 @@
TextFieldValue(""),
KeyboardType.Ascii,
ImeAction.NoAction,
+ KeyboardOptions.Default,
onEditCommand = {},
onImeActionPerformed = {}
)
@@ -244,6 +257,7 @@
TextFieldValue(""),
KeyboardType.Ascii,
ImeAction.Go,
+ KeyboardOptions.Default,
onEditCommand = {},
onImeActionPerformed = {}
)
@@ -265,6 +279,7 @@
TextFieldValue(""),
KeyboardType.Ascii,
ImeAction.Next,
+ KeyboardOptions.Default,
onEditCommand = {},
onImeActionPerformed = {}
)
@@ -286,6 +301,7 @@
TextFieldValue(""),
KeyboardType.Ascii,
ImeAction.Previous,
+ KeyboardOptions.Default,
onEditCommand = {},
onImeActionPerformed = {}
)
@@ -307,6 +323,7 @@
TextFieldValue(""),
KeyboardType.Ascii,
ImeAction.Search,
+ KeyboardOptions.Default,
onEditCommand = {},
onImeActionPerformed = {}
)
@@ -328,6 +345,7 @@
TextFieldValue(""),
KeyboardType.Ascii,
ImeAction.Send,
+ KeyboardOptions.Default,
onEditCommand = {},
onImeActionPerformed = {}
)
@@ -349,6 +367,7 @@
TextFieldValue(""),
KeyboardType.Ascii,
ImeAction.Done,
+ KeyboardOptions.Default,
onEditCommand = {},
onImeActionPerformed = {}
)
@@ -363,4 +382,58 @@
)
}
}
+
+ @Test
+ fun test_fill_editor_info_multi_line() {
+ textInputService.startInput(
+ TextFieldValue(""),
+ KeyboardType.Ascii,
+ ImeAction.Done,
+ KeyboardOptions(singleLine = false),
+ onEditCommand = {},
+ onImeActionPerformed = {}
+ )
+
+ EditorInfo().let { info ->
+ textInputService.createInputConnection(info)
+ assertFalse((InputType.TYPE_TEXT_FLAG_MULTI_LINE and info.inputType) == 0)
+ assertFalse((EditorInfo.IME_FLAG_NO_ENTER_ACTION and info.imeOptions) == 0)
+ }
+ }
+
+ @Test
+ fun test_fill_editor_info_single_line() {
+ textInputService.startInput(
+ TextFieldValue(""),
+ KeyboardType.Ascii,
+ ImeAction.Done,
+ KeyboardOptions(singleLine = true),
+ onEditCommand = {},
+ onImeActionPerformed = {}
+ )
+
+ EditorInfo().let { info ->
+ textInputService.createInputConnection(info)
+ assertTrue((InputType.TYPE_TEXT_FLAG_MULTI_LINE and info.inputType) == 0)
+ assertTrue((EditorInfo.IME_FLAG_NO_ENTER_ACTION and info.imeOptions) == 0)
+ }
+ }
+
+ @Test
+ fun test_fill_editor_info_single_line_changes_ime_from_unspecified_to_done() {
+ textInputService.startInput(
+ TextFieldValue(""),
+ KeyboardType.Text,
+ ImeAction.Unspecified,
+ KeyboardOptions(singleLine = true),
+ onEditCommand = {},
+ onImeActionPerformed = {}
+ )
+
+ EditorInfo().let { info ->
+ textInputService.createInputConnection(info)
+ assertFalse((EditorInfo.IME_ACTION_DONE and info.imeOptions) == 0)
+ assertTrue((EditorInfo.IME_ACTION_UNSPECIFIED and info.imeOptions) == 0)
+ }
+ }
}
\ No newline at end of file
diff --git a/ui/ui-test/src/commonMain/kotlin/androidx/ui/test/TextInputServiceForTests.kt b/ui/ui-test/src/commonMain/kotlin/androidx/ui/test/TextInputServiceForTests.kt
index 8cd58f7..0c38043 100644
--- a/ui/ui-test/src/commonMain/kotlin/androidx/ui/test/TextInputServiceForTests.kt
+++ b/ui/ui-test/src/commonMain/kotlin/androidx/ui/test/TextInputServiceForTests.kt
@@ -16,10 +16,12 @@
package androidx.ui.test
+import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.input.EditOperation
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.InputSessionToken
+import androidx.compose.ui.text.input.KeyboardOptions
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PlatformTextInputService
import androidx.compose.ui.text.input.TextInputService
@@ -31,6 +33,7 @@
* accept input from the IME. Here we grab that callback so we can fetch it commands the same
* way IME would do.
*/
+@OptIn(ExperimentalTextApi::class)
internal class TextInputServiceForTests(
platformTextInputService: PlatformTextInputService
) : TextInputService(platformTextInputService) {
@@ -42,6 +45,7 @@
value: TextFieldValue,
keyboardType: KeyboardType,
imeAction: ImeAction,
+ keyboardOptions: KeyboardOptions,
onEditCommand: (List<EditOperation>) -> Unit,
onImeActionPerformed: (ImeAction) -> Unit
): InputSessionToken {
@@ -51,6 +55,7 @@
value,
keyboardType,
imeAction,
+ keyboardOptions,
onEditCommand,
onImeActionPerformed
)