1 /* 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 17 package androidx.compose.ui.autofill 18 19 import androidx.compose.ui.ComposeUiFlags 20 import androidx.compose.ui.ExperimentalComposeUiApi 21 import androidx.compose.ui.geometry.Rect 22 import androidx.compose.ui.platform.makeSynchronizedObject 23 import androidx.compose.ui.platform.synchronized 24 import androidx.compose.ui.semantics.generateSemanticsId 25 26 /** 27 * Autofill API. 28 * 29 * This interface is available to all composables via a CompositionLocal. The composable can then 30 * request or cancel autofill as required. For instance, the TextField can call 31 * [requestAutofillForNode] when it gains focus, and [cancelAutofillForNode] when it loses focus. 32 */ 33 @Deprecated( 34 """ 35 You no longer have to call these apis when focus changes. They will be called 36 automatically when you Use the new semantics based APIs for autofill. Use the 37 androidx.compose.ui.autofill.ContentType and androidx.compose.ui.autofill.ContentDataType 38 semantics properties instead. 39 """ 40 ) 41 interface Autofill { 42 43 /** 44 * Request autofill for the specified node. 45 * 46 * @param autofillNode The node that needs to be auto-filled. 47 * 48 * This function is usually called when an autofill-able component gains focus. 49 */ requestAutofillForNodenull50 fun requestAutofillForNode(autofillNode: @Suppress("Deprecation") AutofillNode) 51 52 /** 53 * Cancel a previously supplied autofill request. 54 * 55 * @param autofillNode The node that needs to be auto-filled. 56 * 57 * This function is usually called when an autofill-able component loses focus. 58 */ 59 fun cancelAutofillForNode(autofillNode: @Suppress("Deprecation") AutofillNode) 60 } 61 62 /** 63 * Every autofill-able composable will have an [AutofillNode]. (An autofill node will be created for 64 * every semantics node that adds autofill properties). This node is used to request/cancel 65 * autofill, and it holds the [onFill] lambda which is called by the autofill framework. 66 * 67 * @property autofillTypes A list of autofill types for this node. These types are conveyed to the 68 * autofill framework and it is used to call [onFill] with the appropriate value. If you don't set 69 * this property, the autofill framework will use heuristics to guess the type. This property is a 70 * list because some fields can have multiple types. For instance, userid in a login form can 71 * either be a username or an email address. TODO(b/138731416): Check with the autofill service 72 * team if the order matters, and how duplicate types are handled. 73 * @property boundingBox The screen coordinates of the composable being auto-filled. This data is 74 * used by the autofill framework to decide where to show the autofill popup. 75 * @property onFill The callback that is called by the autofill framework to perform autofill. 76 * @property id A virtual id that is automatically generated for each node. 77 */ 78 @Deprecated( 79 """ 80 Use the new semantics-based Autofill APIs androidx.compose.ui.autofill.ContentType and 81 androidx.compose.ui.autofill.ContentDataType instead. 82 """ 83 ) 84 class AutofillNode( 85 val autofillTypes: List<@Suppress("Deprecation") AutofillType> = listOf(), 86 var boundingBox: Rect? = null, 87 val onFill: ((String) -> Unit)? 88 ) { 89 internal companion object { 90 /*@GuardedBy("this")*/ 91 private var previousId = 0 92 93 private val lock = makeSynchronizedObject(this) 94 95 private fun generateId() = synchronized(lock) { ++previousId } 96 } 97 98 val id: Int = 99 @OptIn(ExperimentalComposeUiApi::class) 100 if (ComposeUiFlags.isSemanticAutofillEnabled) generateSemanticsId() else generateId() 101 102 override fun equals(other: Any?): Boolean { 103 if (this === other) return true 104 if (other !is @Suppress("Deprecation") AutofillNode) return false 105 106 if (autofillTypes != other.autofillTypes) return false 107 if (boundingBox != other.boundingBox) return false 108 if (onFill !== other.onFill) return false 109 110 return true 111 } 112 113 override fun hashCode(): Int { 114 var result = autofillTypes.hashCode() 115 result = 31 * result + (boundingBox?.hashCode() ?: 0) 116 result = 31 * result + (onFill?.hashCode() ?: 0) 117 return result 118 } 119 } 120