1 /*
2  * Copyright 2023 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 
17 @file:Suppress("DEPRECATION")
18 
19 package androidx.compose.foundation.text.input.internal
20 
21 import androidx.compose.foundation.internal.checkPrecondition
22 import androidx.compose.foundation.text.LegacyTextFieldState
23 import androidx.compose.foundation.text.selection.TextFieldSelectionManager
24 import androidx.compose.ui.layout.LayoutCoordinates
25 import androidx.compose.ui.platform.PlatformTextInputSession
26 import androidx.compose.ui.platform.SoftwareKeyboardController
27 import androidx.compose.ui.platform.ViewConfiguration
28 import androidx.compose.ui.text.input.PlatformTextInputService
29 import kotlinx.coroutines.Job
30 
createLegacyPlatformTextInputServiceAdapternull31 internal expect fun createLegacyPlatformTextInputServiceAdapter():
32     LegacyPlatformTextInputServiceAdapter
33 
34 /**
35  * An implementation of the legacy [PlatformTextInputService] interface that delegates to a
36  * [LegacyAdaptingPlatformTextInputModifierNode].
37  *
38  * For this class to work, exactly one [LegacyAdaptingPlatformTextInputModifier] must be attached to
39  * a layout node and passed an instance of this class. This class will only function when such a
40  * modifier is attached to the modifier system, otherwise many of its operations will no-op.
41  *
42  * Note that, contrary to the original design intent of a [PlatformTextInputService], every text
43  * field has its own instance of this class, so it does not need to worry about multiple consumers.
44  */
45 internal abstract class LegacyPlatformTextInputServiceAdapter : PlatformTextInputService {
46 
47     protected var textInputModifierNode: LegacyPlatformTextInputNode? = null
48         private set
49 
50     fun registerModifier(node: LegacyPlatformTextInputNode) {
51         checkPrecondition(textInputModifierNode == null) {
52             "Expected textInputModifierNode to be null"
53         }
54         textInputModifierNode = node
55     }
56 
57     fun unregisterModifier(node: LegacyPlatformTextInputNode) {
58         checkPrecondition(textInputModifierNode === node) {
59             "Expected textInputModifierNode to be $node but was $textInputModifierNode"
60         }
61         textInputModifierNode = null
62     }
63 
64     final override fun showSoftwareKeyboard() {
65         textInputModifierNode?.softwareKeyboardController?.show()
66     }
67 
68     final override fun hideSoftwareKeyboard() {
69         textInputModifierNode?.softwareKeyboardController?.hide()
70     }
71 
72     abstract fun startStylusHandwriting()
73 
74     interface LegacyPlatformTextInputNode {
75         val softwareKeyboardController: SoftwareKeyboardController?
76         val layoutCoordinates: LayoutCoordinates?
77         val legacyTextFieldState: LegacyTextFieldState?
78         val textFieldSelectionManager: TextFieldSelectionManager?
79         val viewConfiguration: ViewConfiguration
80 
81         fun launchTextInputSession(block: suspend PlatformTextInputSession.() -> Nothing): Job?
82     }
83 }
84