[go: nahoru, domu]

blob: cb8003e8e0941d8b4b0d25239062f6a6bcde1046 [file] [log] [blame]
Seigo Nonaka4b211592019-04-07 14:11:28 -07001/*
2 * Copyright 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Siyamed Sinire9b57be2019-11-02 01:25:03 -070017package androidx.ui.input
Seigo Nonaka4b211592019-04-07 14:11:28 -070018
19import android.content.Context
Seigo Nonaka4b211592019-04-07 14:11:28 -070020import android.text.InputType
21import android.view.View
22import android.view.inputmethod.EditorInfo
23import android.view.inputmethod.InputConnection
24import android.view.inputmethod.InputMethodManager
George Mount842c8c12020-01-08 16:03:42 -080025import androidx.ui.geometry.Rect
Seigo Nonakadd60a5c2019-07-10 11:23:36 -070026import androidx.ui.text.TextRange
27import kotlin.math.roundToInt
Seigo Nonaka4b211592019-04-07 14:11:28 -070028
29/**
30 * Provide Android specific input service with the Operating System.
31 */
Siyamed Sinir9da613b2019-11-15 20:39:19 -080032internal class TextInputServiceAndroid(val view: View) : PlatformTextInputService {
Louis Pullen-Freilich5da28bd2019-10-15 17:05:07 +010033 /** True if the currently editable composable has connected */
Seigo Nonaka4b211592019-04-07 14:11:28 -070034 private var editorHasFocus = false
35
36 /**
Louis Pullen-Freilich5da28bd2019-10-15 17:05:07 +010037 * The following three observers are set when the editable composable has initiated the input
Seigo Nonaka4b211592019-04-07 14:11:28 -070038 * session
39 */
Seigo Nonaka615f32d2019-06-18 15:33:38 -070040 private var onEditCommand: (List<EditOperation>) -> Unit = {}
Seigo Nonakac04f629d2019-07-11 13:20:30 -070041 private var onImeActionPerformed: (ImeAction) -> Unit = {}
Seigo Nonaka4b211592019-04-07 14:11:28 -070042
Siyamed Sinirc2e55592020-06-09 09:37:23 -070043 private var state = TextFieldValue(text = "", selection = TextRange(0, 0))
Seigo Nonaka6e6e2ee2019-07-01 17:18:41 -070044 private var keyboardType = KeyboardType.Text
Seigo Nonakac04f629d2019-07-11 13:20:30 -070045 private var imeAction = ImeAction.Unspecified
Seigo Nonaka4e45c462019-07-01 12:12:59 -070046 private var ic: RecordingInputConnection? = null
47
Seigo Nonaka4b211592019-04-07 14:11:28 -070048 /**
49 * The editable buffer used for BaseInputConnection.
50 */
Ralston Da Silvadff6b622019-08-07 15:29:06 -070051 private lateinit var imm: InputMethodManager
Seigo Nonaka4b211592019-04-07 14:11:28 -070052
53 /**
54 * Creates new input connection.
55 */
56 fun createInputConnection(outAttrs: EditorInfo): InputConnection? {
57 if (!editorHasFocus) {
58 return null
59 }
Seigo Nonakac04f629d2019-07-11 13:20:30 -070060 fillEditorInfo(keyboardType, imeAction, outAttrs)
Seigo Nonaka4b211592019-04-07 14:11:28 -070061
Seigo Nonaka4e45c462019-07-01 12:12:59 -070062 return RecordingInputConnection(
63 initState = state,
64 eventListener = object : InputEventListener {
65 override fun onEditOperations(editOps: List<EditOperation>) {
66 onEditCommand(editOps)
67 }
Seigo Nonakac04f629d2019-07-11 13:20:30 -070068
69 override fun onImeAction(imeAction: ImeAction) {
70 onImeActionPerformed(imeAction)
71 }
Seigo Nonaka615f32d2019-06-18 15:33:38 -070072 }
Seigo Nonaka4e45c462019-07-01 12:12:59 -070073 ).also { ic = it }
Seigo Nonaka4b211592019-04-07 14:11:28 -070074 }
75
76 /**
77 * Returns true if some editable component is focused.
78 */
79 fun isEditorFocused(): Boolean = editorHasFocus
80
81 override fun startInput(
Siyamed Sinirc2e55592020-06-09 09:37:23 -070082 value: TextFieldValue,
Seigo Nonaka6e6e2ee2019-07-01 17:18:41 -070083 keyboardType: KeyboardType,
Seigo Nonakac04f629d2019-07-11 13:20:30 -070084 imeAction: ImeAction,
Seigo Nonaka615f32d2019-06-18 15:33:38 -070085 onEditCommand: (List<EditOperation>) -> Unit,
Seigo Nonakac04f629d2019-07-11 13:20:30 -070086 onImeActionPerformed: (ImeAction) -> Unit
Seigo Nonaka4b211592019-04-07 14:11:28 -070087 ) {
Ralston Da Silvadff6b622019-08-07 15:29:06 -070088 imm = view.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
Seigo Nonaka4b211592019-04-07 14:11:28 -070089 editorHasFocus = true
Siyamed Sinirc2e55592020-06-09 09:37:23 -070090 state = value
Seigo Nonaka6e6e2ee2019-07-01 17:18:41 -070091 this.keyboardType = keyboardType
Seigo Nonakac04f629d2019-07-11 13:20:30 -070092 this.imeAction = imeAction
Seigo Nonaka615f32d2019-06-18 15:33:38 -070093 this.onEditCommand = onEditCommand
Seigo Nonakac04f629d2019-07-11 13:20:30 -070094 this.onImeActionPerformed = onImeActionPerformed
Seigo Nonaka4b211592019-04-07 14:11:28 -070095
96 view.requestFocus()
97 view.post {
98 imm.restartInput(view)
99 imm.showSoftInput(view, 0)
100 }
101 }
102
103 override fun stopInput() {
104 editorHasFocus = false
Seigo Nonaka615f32d2019-06-18 15:33:38 -0700105 onEditCommand = {}
Seigo Nonakac04f629d2019-07-11 13:20:30 -0700106 onImeActionPerformed = {}
Seigo Nonaka4b211592019-04-07 14:11:28 -0700107
108 imm.restartInput(view)
Seigo Nonaka6425fde2020-02-27 16:20:33 -0800109 editorHasFocus = false
Seigo Nonaka4b211592019-04-07 14:11:28 -0700110 }
Seigo Nonaka97c9f0b2019-07-01 14:22:07 -0700111
112 override fun showSoftwareKeyboard() {
113 imm.showSoftInput(view, 0)
114 }
Seigo Nonaka4e45c462019-07-01 12:12:59 -0700115
Seigo Nonaka6425fde2020-02-27 16:20:33 -0800116 override fun hideSoftwareKeyboard() {
117 imm.hideSoftInputFromWindow(view.windowToken, 0)
118 }
119
Siyamed Sinirc2e55592020-06-09 09:37:23 -0700120 override fun onStateUpdated(value: TextFieldValue) {
121 this.state = value
Seigo Nonaka4e45c462019-07-01 12:12:59 -0700122 ic?.updateInputState(this.state, imm, view)
123 }
Seigo Nonaka6e6e2ee2019-07-01 17:18:41 -0700124
Seigo Nonakadd60a5c2019-07-10 11:23:36 -0700125 override fun notifyFocusedRect(rect: Rect) {
126 view.requestRectangleOnScreen(android.graphics.Rect(
127 rect.left.roundToInt(),
128 rect.top.roundToInt(),
129 rect.right.roundToInt(),
130 rect.bottom.roundToInt()))
131 }
132
Seigo Nonaka6e6e2ee2019-07-01 17:18:41 -0700133 /**
134 * Fills necessary info of EditorInfo.
135 */
Seigo Nonakac04f629d2019-07-11 13:20:30 -0700136 private fun fillEditorInfo(
137 keyboardType: KeyboardType,
138 imeAction: ImeAction,
139 outInfo: EditorInfo
140 ) {
141 outInfo.imeOptions = when (imeAction) {
142 ImeAction.Unspecified -> EditorInfo.IME_ACTION_UNSPECIFIED
143 ImeAction.NoAction -> EditorInfo.IME_ACTION_NONE
144 ImeAction.Go -> EditorInfo.IME_ACTION_GO
145 ImeAction.Next -> EditorInfo.IME_ACTION_NEXT
146 ImeAction.Previous -> EditorInfo.IME_ACTION_PREVIOUS
147 ImeAction.Search -> EditorInfo.IME_ACTION_SEARCH
148 ImeAction.Send -> EditorInfo.IME_ACTION_SEND
149 ImeAction.Done -> EditorInfo.IME_ACTION_DONE
150 else -> throw IllegalArgumentException("Unknown ImeAction: $imeAction")
151 }
Seigo Nonaka6e6e2ee2019-07-01 17:18:41 -0700152 when (keyboardType) {
153 KeyboardType.Text -> outInfo.inputType = InputType.TYPE_CLASS_TEXT
Siyamed Sinir3a952ea2019-07-08 16:50:50 -0700154 KeyboardType.Ascii -> {
Seigo Nonaka6e6e2ee2019-07-01 17:18:41 -0700155 outInfo.inputType = InputType.TYPE_CLASS_TEXT
Seigo Nonakac04f629d2019-07-11 13:20:30 -0700156 outInfo.imeOptions = outInfo.imeOptions or EditorInfo.IME_FLAG_FORCE_ASCII
Seigo Nonaka6e6e2ee2019-07-01 17:18:41 -0700157 }
158 KeyboardType.Number -> outInfo.inputType = InputType.TYPE_CLASS_NUMBER
159 KeyboardType.Phone -> outInfo.inputType = InputType.TYPE_CLASS_PHONE
Siyamed Sinir3a952ea2019-07-08 16:50:50 -0700160 KeyboardType.Uri ->
Seigo Nonaka6e6e2ee2019-07-01 17:18:41 -0700161 outInfo.inputType = InputType.TYPE_CLASS_TEXT or EditorInfo.TYPE_TEXT_VARIATION_URI
162 KeyboardType.Email ->
163 outInfo.inputType =
164 InputType.TYPE_CLASS_TEXT or EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
Seigo Nonaka813dc152019-07-15 17:15:05 -0700165 KeyboardType.Password -> {
166 outInfo.inputType =
167 InputType.TYPE_CLASS_TEXT or EditorInfo.TYPE_TEXT_VARIATION_PASSWORD
168 }
169 KeyboardType.NumberPassword -> {
170 outInfo.inputType =
171 InputType.TYPE_CLASS_NUMBER or EditorInfo.TYPE_NUMBER_VARIATION_PASSWORD
172 }
Seigo Nonaka6e6e2ee2019-07-01 17:18:41 -0700173 else -> throw IllegalArgumentException("Unknown KeyboardType: $keyboardType")
174 }
Seigo Nonakac04f629d2019-07-11 13:20:30 -0700175 outInfo.imeOptions =
176 outInfo.imeOptions or outInfo.imeOptions or EditorInfo.IME_FLAG_NO_FULLSCREEN
Seigo Nonaka6e6e2ee2019-07-01 17:18:41 -0700177 }
Seigo Nonakaa7e05d72019-09-30 17:31:25 -0700178}