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