1 /* 2 * Copyright 2020 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.node 18 19 import androidx.annotation.RestrictTo 20 import androidx.collection.IntObjectMap 21 import androidx.compose.runtime.Applier 22 import androidx.compose.ui.InternalComposeUiApi 23 import androidx.compose.ui.autofill.AutofillManager 24 import androidx.compose.ui.draganddrop.DragAndDropManager 25 import androidx.compose.ui.focus.FocusDirection 26 import androidx.compose.ui.focus.FocusOwner 27 import androidx.compose.ui.geometry.Offset 28 import androidx.compose.ui.graphics.Canvas 29 import androidx.compose.ui.graphics.GraphicsContext 30 import androidx.compose.ui.graphics.layer.GraphicsLayer 31 import androidx.compose.ui.hapticfeedback.HapticFeedback 32 import androidx.compose.ui.input.InputModeManager 33 import androidx.compose.ui.input.key.KeyEvent 34 import androidx.compose.ui.input.pointer.PointerIconService 35 import androidx.compose.ui.input.pointer.PositionCalculator 36 import androidx.compose.ui.layout.Placeable 37 import androidx.compose.ui.layout.PlacementScope 38 import androidx.compose.ui.modifier.ModifierLocalManager 39 import androidx.compose.ui.platform.AccessibilityManager 40 import androidx.compose.ui.platform.Clipboard 41 import androidx.compose.ui.platform.PlatformTextInputModifierNode 42 import androidx.compose.ui.platform.PlatformTextInputSessionScope 43 import androidx.compose.ui.platform.SoftwareKeyboardController 44 import androidx.compose.ui.platform.TextToolbar 45 import androidx.compose.ui.platform.ViewConfiguration 46 import androidx.compose.ui.platform.WindowInfo 47 import androidx.compose.ui.semantics.SemanticsOwner 48 import androidx.compose.ui.spatial.RectManager 49 import androidx.compose.ui.text.font.Font 50 import androidx.compose.ui.text.font.FontFamily 51 import androidx.compose.ui.unit.Constraints 52 import androidx.compose.ui.unit.Density 53 import androidx.compose.ui.unit.LayoutDirection 54 import androidx.compose.ui.viewinterop.InteropView 55 import kotlin.coroutines.CoroutineContext 56 import kotlinx.coroutines.Job 57 58 /** 59 * Owner implements the connection to the underlying view system. On Android, this connects to 60 * Android [views][android.view.View] and all layout, draw, input, and accessibility is hooked 61 * through them. 62 */ 63 internal interface Owner : PositionCalculator { 64 65 /** The root layout node in the component tree. */ 66 val root: LayoutNode 67 68 /** A mapping of semantic id to LayoutNode. */ 69 val layoutNodes: IntObjectMap<LayoutNode> 70 71 /** Draw scope reused for drawing speed up. */ 72 val sharedDrawScope: LayoutNodeDrawScope 73 74 val rootForTest: RootForTest 75 76 /** Provide haptic feedback to the user. Use the Android version of haptic feedback. */ 77 val hapticFeedBack: HapticFeedback 78 79 /** 80 * Provide information about the current input mode, and a way to programmatically change the 81 * input mode. 82 */ 83 val inputModeManager: InputModeManager 84 85 /** Provide clipboard manager to the user. Use the Android version of clipboard manager. */ 86 val clipboardManager: @Suppress("Deprecation") androidx.compose.ui.platform.ClipboardManager 87 88 /** 89 * Provide clipboard manager with suspend function to the user. Use the Android version of 90 * clipboard manager. 91 */ 92 val clipboard: Clipboard 93 94 /** 95 * Provide accessibility manager to the user. Use the Android version of accessibility manager. 96 */ 97 val accessibilityManager: AccessibilityManager 98 99 /** 100 * Provide access to a GraphicsContext instance used to create GraphicsLayers for providing 101 * isolation boundaries for rendering portions of a Composition hierarchy as well as for 102 * achieving certain visual effects like masks and blurs 103 */ 104 val graphicsContext: GraphicsContext 105 106 /** Provide toolbar for text-related actions, such as copy, paste, cut etc. */ 107 val textToolbar: TextToolbar 108 109 /** 110 * A data structure used to store autofill information. It is used by components that want to 111 * provide autofill semantics. 112 */ 113 val autofillTree: @Suppress("Deprecation") androidx.compose.ui.autofill.AutofillTree 114 115 /** 116 * The [Autofill][androidx.compose.ui.autofill.Autofill] class can be used to perform autofill 117 * operations. It is used as a CompositionLocal. 118 */ 119 val autofill: @Suppress("Deprecation") androidx.compose.ui.autofill.Autofill? 120 121 /** 122 * The [AutofillManager] class can be used to perform autofill operations. It is used as a 123 * CompositionLocal. 124 */ 125 val autofillManager: AutofillManager? 126 127 val density: Density 128 129 val textInputService: @Suppress("Deprecation") androidx.compose.ui.text.input.TextInputService 130 131 val softwareKeyboardController: SoftwareKeyboardController 132 133 val pointerIconService: PointerIconService 134 135 /** 136 * Semantics owner that provides access to 137 * [SemanticsInfo][androidx.compose.ui.semantics.SemanticsInfo] and 138 * [SemanticListeners][androidx.compose.ui.semantics.SemanticsListener]. 139 */ 140 val semanticsOwner: SemanticsOwner 141 142 /** Provide a focus owner that controls focus within Compose. */ 143 val focusOwner: FocusOwner 144 145 /** Provide information about the window that hosts this [Owner]. */ 146 val windowInfo: WindowInfo 147 148 /** Provides a queryable and observable index of nodes' bounding rectangles */ 149 val rectManager: RectManager 150 151 @Deprecated( 152 "fontLoader is deprecated, use fontFamilyResolver", 153 replaceWith = ReplaceWith("fontFamilyResolver") 154 ) 155 @Suppress("DEPRECATION") 156 val fontLoader: Font.ResourceLoader 157 158 val fontFamilyResolver: FontFamily.Resolver 159 160 val layoutDirection: LayoutDirection 161 162 /** `true` when layout should draw debug bounds. */ 163 var showLayoutBounds: Boolean 164 @RestrictTo(RestrictTo.Scope.LIBRARY) @InternalCoreApi set 165 166 /** 167 * Called by [LayoutNode] to request the Owner a new measurement+layout. [forceRequest] defines 168 * whether the node should bypass the logic that would reject measure requests, and therefore 169 * force the measure request to be evaluated even when it's already pending measure. 170 * 171 * [affectsLookahead] specifies whether this measure request is for the lookahead pass. 172 */ onRequestMeasurenull173 fun onRequestMeasure( 174 layoutNode: LayoutNode, 175 affectsLookahead: Boolean = false, 176 forceRequest: Boolean = false, 177 scheduleMeasureAndLayout: Boolean = true 178 ) 179 180 /** 181 * Called by [LayoutNode] to request the Owner a new layout. [forceRequest] defines whether the 182 * node should bypass the logic that would reject relayout requests, and therefore force the 183 * relayout request to be evaluated even when it's already pending measure/layout. 184 * 185 * [affectsLookahead] specifies whether this relayout request is for the lookahead pass pass. 186 */ 187 fun onRequestRelayout( 188 layoutNode: LayoutNode, 189 affectsLookahead: Boolean = false, 190 forceRequest: Boolean = false 191 ) 192 193 /** 194 * Called when graphics layers have changed the position of children and the 195 * OnGloballyPositionedModifiers must be called. 196 */ 197 fun requestOnPositionedCallback(layoutNode: LayoutNode) 198 199 /** 200 * Called by [LayoutNode] when it is attached to the view system and now has an owner. This is 201 * used by [Owner] to track which nodes are associated with it. It will only be called when 202 * [node] is not already attached to an owner. 203 */ 204 fun onPreAttach(node: LayoutNode) 205 206 /** 207 * Called by [LayoutNode] when all children have been attached, and the modifier node's attach 208 * lifecycles have been run. It will only be called after [onPreAttach]. 209 */ 210 fun onPostAttach(node: LayoutNode) 211 212 /** 213 * Called by [LayoutNode] when it is detached from the view system, such as during 214 * [LayoutNode.removeAt]. This will only be called for [node]s that are already 215 * [LayoutNode.attach]ed. 216 */ 217 fun onDetach(node: LayoutNode) 218 219 /** 220 * Returns the position relative to the containing window of the [localPosition], the position 221 * relative to the [Owner]. If the [Owner] is rotated, scaled, or otherwise transformed relative 222 * to the window, this will not be a simple translation. 223 */ 224 fun calculatePositionInWindow(localPosition: Offset): Offset 225 226 /** 227 * Returns the position relative to the [Owner] of the [positionInWindow], the position relative 228 * to the window. If the [Owner] is rotated, scaled, or otherwise transformed relative to the 229 * window, this will not be a simple translation. 230 */ 231 fun calculateLocalPosition(positionInWindow: Offset): Offset 232 233 /** 234 * Ask the system to provide focus to this owner. 235 * 236 * @return true if the system granted focus to this owner. False otherwise. 237 */ 238 fun requestFocus(): Boolean 239 240 /** Ask the system to request autofill values to this owner. */ 241 fun requestAutofill(node: LayoutNode) 242 243 /** 244 * Iterates through all LayoutNodes that have requested layout and measures and lays them out. 245 * If [sendPointerUpdate] is `true` then a simulated PointerEvent may be sent to update pointer 246 * input handlers. 247 * 248 * This method can dispatch ViewTreeObserver events during its execution. Do not call it during 249 * a view's onLayout as an associated listener may invoke side effects that may requestLayout 250 * during layout, potentially putting the view hierarchy into an invalid state. 251 */ 252 fun measureAndLayout(sendPointerUpdate: Boolean = true) 253 254 /** 255 * Measures and lays out only the passed [layoutNode]. It will be remeasured with the passed 256 * [constraints]. 257 * 258 * This method can dispatch ViewTreeObserver events during its execution. Do not call it during 259 * a view's onLayout as an associated listener may invoke side effects that may requestLayout 260 * during layout, potentially putting the view hierarchy into an invalid state. 261 */ 262 fun measureAndLayout(layoutNode: LayoutNode, constraints: Constraints) 263 264 /** Makes sure the passed [layoutNode] and its subtree is remeasured and has the final sizes. */ 265 fun forceMeasureTheSubtree(layoutNode: LayoutNode, affectsLookahead: Boolean = false) 266 267 /** Creates an [OwnedLayer] which will be drawing the passed [drawBlock]. */ 268 fun createLayer( 269 drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit, 270 invalidateParentLayer: () -> Unit, 271 explicitLayer: GraphicsLayer? = null, 272 forceUseOldLayers: Boolean = false 273 ): OwnedLayer 274 275 /** 276 * The semantics have changed. This function will be called when a SemanticsNode is added to or 277 * deleted from the Semantics tree. It will also be called when a SemanticsNode in the Semantics 278 * tree has some property change. 279 */ 280 fun onSemanticsChange() 281 282 /** The position and/or size of the [layoutNode] changed. */ 283 fun onLayoutChange(layoutNode: LayoutNode) 284 285 fun onLayoutNodeDeactivated(layoutNode: LayoutNode) 286 287 /** 288 * Called to do internal upkeep when a [layoutNode] is reused. The modifier nodes of this layout 289 * node have not been attached by the time this method finishes running. 290 */ 291 fun onPreLayoutNodeReused(layoutNode: LayoutNode, oldSemanticsId: Int) {} 292 293 /** 294 * Called to do internal upkeep when a [layoutNode] is reused. This is only called after 295 * [onPreLayoutNodeReused], at which point the modifier nodes of this layout node have been 296 * attached. 297 */ onPostLayoutNodeReusednull298 fun onPostLayoutNodeReused(layoutNode: LayoutNode, oldSemanticsId: Int) {} 299 300 /** 301 * The position and/or size of an interop view (typically, an android.view.View) has changed. On 302 * Android, this schedules view tree layout observer callback to be invoked for the underlying 303 * platform view hierarchy. 304 */ onInteropViewLayoutChangenull305 @InternalComposeUiApi fun onInteropViewLayoutChange(view: InteropView) 306 307 /** The [FocusDirection] represented by the specified keyEvent. */ 308 fun getFocusDirection(keyEvent: KeyEvent): FocusDirection? 309 310 val measureIteration: Long 311 312 /** The [ViewConfiguration] to use in the application. */ 313 val viewConfiguration: ViewConfiguration 314 315 /** 316 * Performs snapshot observation for blocks like draw and layout which should be re-invoked 317 * automatically when the snapshot value has been changed. 318 */ 319 val snapshotObserver: OwnerSnapshotObserver 320 321 val modifierLocalManager: ModifierLocalManager 322 323 /** CoroutineContext for launching coroutines in Modifier Nodes. */ 324 val coroutineContext: CoroutineContext 325 326 /** The scope used to place the outermost layout. */ 327 val placementScope: Placeable.PlacementScope 328 get() = PlacementScope(this) // default implementation for test owners 329 330 /** 331 * Registers a call to be made when the [Applier.onEndChanges] is called. [listener] should be 332 * called in [onEndApplyChanges] and then removed after being called. 333 */ 334 fun registerOnEndApplyChangesListener(listener: () -> Unit) 335 336 /** 337 * Called when [Applier.onEndChanges] executes. This must call all listeners registered in 338 * [registerOnEndApplyChangesListener] and then remove them so that they are not called again. 339 */ 340 fun onEndApplyChanges() 341 342 /** [listener] will be notified after the current or next layout has finished. */ 343 fun registerOnLayoutCompletedListener(listener: OnLayoutCompletedListener) 344 345 val dragAndDropManager: DragAndDropManager 346 347 /** 348 * Starts a new text input session and suspends until it's closed. For more information see 349 * [PlatformTextInputModifierNode.establishTextInputSession]. 350 * 351 * Implementations must ensure that new requests cancel any active request. They must also 352 * ensure that the previous request is finished running all cancellation tasks before starting 353 * the new session, to ensure that no session code overlaps (e.g. using [Job.cancelAndJoin]). 354 */ 355 suspend fun textInputSession( 356 session: suspend PlatformTextInputSessionScope.() -> Nothing 357 ): Nothing 358 359 /** 360 * Tracks sensitive content on the screen to protect user privacy. Increment sensitive component 361 * count by 1. Implementation may protect user privacy by not showing sensitive content 362 * (username, password etc) to remote viewer during screen share. 363 */ 364 fun incrementSensitiveComponentCount() {} 365 366 /** 367 * Tracks sensitive content on the screen to protect user privacy. Decrement sensitive component 368 * count by 1. Implementation may protect user privacy by not showing sensitive content 369 * (username, password etc) to remote viewer during screen share. 370 */ decrementSensitiveComponentCountnull371 fun decrementSensitiveComponentCount() {} 372 373 /** On Android it is only available when the view is attached. */ 374 val outOfFrameExecutor: OutOfFrameExecutor? 375 get() = null 376 377 /** This can be used to Vote for a preferred frame rate. */ voteFrameRatenull378 fun voteFrameRate(frameRate: Float) {} 379 380 /** 381 * Dispatches a callback when something in this hierarchy scrolls. 382 * 383 * @param offset Delta scrolled. 384 */ dispatchOnScrollChangednull385 fun dispatchOnScrollChanged(delta: Offset) {} 386 387 companion object { 388 /** 389 * Enables additional (and expensive to do in production) assertions. Useful to be set to 390 * true during the tests covering our core logic. 391 */ 392 var enableExtraAssertions: Boolean = false 393 } 394 395 interface OnLayoutCompletedListener { onLayoutCompletenull396 fun onLayoutComplete() 397 } 398 } 399