1 /*
2  * Copyright (C) 2010 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 android.graphics;
18 
19 import android.annotation.BytesLong;
20 import android.annotation.ColorInt;
21 import android.annotation.FloatRange;
22 import android.annotation.IntDef;
23 import android.annotation.NonNull;
24 import android.annotation.Nullable;
25 import android.graphics.animation.RenderNodeAnimator;
26 import android.view.NativeVectorDrawableAnimator;
27 import android.view.Surface;
28 import android.view.View;
29 
30 import com.android.internal.util.ArrayUtils;
31 
32 import dalvik.annotation.optimization.CriticalNative;
33 import dalvik.annotation.optimization.FastNative;
34 
35 import libcore.util.NativeAllocationRegistry;
36 
37 import java.lang.annotation.Retention;
38 import java.lang.annotation.RetentionPolicy;
39 
40 /**
41  * <p>RenderNode is used to build hardware accelerated rendering hierarchies. Each RenderNode
42  * contains both a display list as well as a set of properties that affect the rendering of the
43  * display list. RenderNodes are used internally for all Views by default and are not typically
44  * used directly.</p>
45  *
46  * <p>RenderNodes are used to divide up the rendering content of a complex scene into smaller
47  * pieces that can then be updated individually more cheaply. Updating part of the scene only needs
48  * to update the display list or properties of a small number of RenderNode instead of redrawing
49  * everything from scratch. A RenderNode only needs its display list re-recorded when its content
50  * alone should be changed. RenderNodes can also be transformed without re-recording the display
51  * list through the transform properties.</p>
52  *
53  * <p>A text editor might for instance store each paragraph into its own RenderNode.
54  * Thus when the user inserts or removes characters, only the display list of the
55  * affected paragraph needs to be recorded again.</p>
56  *
57  * <h3>Hardware acceleration</h3>
58  * <p>RenderNodes can be drawn using a {@link RecordingCanvas}. They are not
59  * supported in software. Always make sure that the {@link android.graphics.Canvas}
60  * you are using to render a display list is hardware accelerated using
61  * {@link android.graphics.Canvas#isHardwareAccelerated()}.</p>
62  *
63  * <h3>Creating a RenderNode</h3>
64  * <pre class="prettyprint">
65  *     RenderNode renderNode = new RenderNode("myRenderNode");
66  *     renderNode.setPosition(0, 0, 50, 50); // Set the size to 50x50
67  *     RecordingCanvas canvas = renderNode.beginRecording();
68  *     try {
69  *         // Draw with the canvas
70  *         canvas.drawRect(...);
71  *     } finally {
72  *         renderNode.endRecording();
73  *     }</pre>
74  *
75  * <h3>Drawing a RenderNode in a View</h3>
76  * <pre class="prettyprint">
77  *     protected void onDraw(Canvas canvas) {
78  *         if (canvas.isHardwareAccelerated()) {
79  *             // Check that the RenderNode has a display list, re-recording it if it does not.
80  *             if (!myRenderNode.hasDisplayList()) {
81  *                 updateDisplayList(myRenderNode);
82  *             }
83  *             // Draw the RenderNode into this canvas.
84  *             canvas.drawRenderNode(myRenderNode);
85  *         }
86  *     }</pre>
87  *
88  * <h3>Releasing resources</h3>
89  * <p>This step is not mandatory but recommended if you want to release resources
90  * held by a display list as soon as possible. Most significantly any bitmaps it may contain.</p>
91  * <pre class="prettyprint">
92  *     // Discards the display list content allowing for any held resources to be released.
93  *     // After calling this
94  *     renderNode.discardDisplayList();</pre>
95  *
96  *
97  * <h3>Properties</h3>
98  * <p>In addition, a RenderNode offers several properties, such as
99  * {@link #setScaleX(float)} or {@link #setTranslationX(float)}, that can be used to affect all
100  * the drawing commands recorded within. For instance, these properties can be used
101  * to move around a large number of images without re-issuing all the individual
102  * <code>canvas.drawBitmap()</code> calls.</p>
103  *
104  * <pre class="prettyprint">
105  *     private void createDisplayList() {
106  *         mRenderNode = new RenderNode("MyRenderNode");
107  *         mRenderNode.setPosition(0, 0, width, height);
108  *         RecordingCanvas canvas = mRenderNode.beginRecording();
109  *         try {
110  *             for (Bitmap b : mBitmaps) {
111  *                 canvas.drawBitmap(b, 0.0f, 0.0f, null);
112  *                 canvas.translate(0.0f, b.getHeight());
113  *             }
114  *         } finally {
115  *             mRenderNode.endRecording();
116  *         }
117  *     }
118  *
119  *     protected void onDraw(Canvas canvas) {
120  *         if (canvas.isHardwareAccelerated())
121  *             canvas.drawRenderNode(mRenderNode);
122  *         }
123  *     }
124  *
125  *     private void moveContentBy(int x) {
126  *          // This will move all the bitmaps recorded inside the display list
127  *          // by x pixels to the right and redraw this view. All the commands
128  *          // recorded in createDisplayList() won't be re-issued, only onDraw()
129  *          // will be invoked and will execute very quickly
130  *          mRenderNode.offsetLeftAndRight(x);
131  *          invalidate();
132  *     }</pre>
133  *
134  * <p>A few of the properties may at first appear redundant, such as {@link #setElevation(float)}
135  * and {@link #setTranslationZ(float)}. The reason for these duplicates are to allow for a
136  * separation between static & transient usages. For example consider a button that raises from 2dp
137  * to 8dp when pressed. To achieve that an application may decide to setElevation(2dip), and then
138  * on press to animate setTranslationZ to 6dip. Combined this achieves the final desired 8dip
139  * value, but the animation need only concern itself with animating the lift from press without
140  * needing to know the initial starting value. {@link #setTranslationX(float)} and
141  * {@link #setTranslationY(float)} are similarly provided for animation uses despite the functional
142  * overlap with {@link #setPosition(Rect)}.
143  *
144  * <p>The RenderNode's transform matrix is computed at render time as follows:
145  * <pre class="prettyprint">
146  *     Matrix transform = new Matrix();
147  *     transform.setTranslate(renderNode.getTranslationX(), renderNode.getTranslationY());
148  *     transform.preRotate(renderNode.getRotationZ(),
149  *             renderNode.getPivotX(), renderNode.getPivotY());
150  *     transform.preScale(renderNode.getScaleX(), renderNode.getScaleY(),
151  *             renderNode.getPivotX(), renderNode.getPivotY());</pre>
152  * The current canvas transform matrix, which is translated to the RenderNode's position,
153  * is then multiplied by the RenderNode's transform matrix. Therefore the ordering of calling
154  * property setters does not affect the result. That is to say that:
155  *
156  * <pre class="prettyprint">
157  *     renderNode.setTranslationX(100);
158  *     renderNode.setScaleX(100);</pre>
159  *
160  * is equivalent to:
161  *
162  * <pre class="prettyprint">
163  *     renderNode.setScaleX(100);
164  *     renderNode.setTranslationX(100);</pre>
165  *
166  * <h3>Threading</h3>
167  * <p>RenderNode may be created and used on any thread but they are not thread-safe. Only
168  * a single thread may interact with a RenderNode at any given time. It is critical
169  * that the RenderNode is only used on the same thread it is drawn with. For example when using
170  * RenderNode with a custom View, then that RenderNode must only be used from the UI thread.</p>
171  *
172  * <h3>When to re-render</h3>
173  * <p>Many of the RenderNode mutation methods, such as {@link #setTranslationX(float)}, return
174  * a boolean indicating if the value actually changed or not. This is useful in detecting
175  * if a new frame should be rendered or not. A typical usage would look like:
176  * <pre class="prettyprint">
177  *     public void translateTo(int x, int y) {
178  *         boolean needsUpdate = myRenderNode.setTranslationX(x);
179  *         needsUpdate |= myRenderNode.setTranslationY(y);
180  *         if (needsUpdate) {
181  *             myOwningView.invalidate();
182  *         }
183  *     }</pre>
184  * This is marginally faster than doing a more explicit up-front check if the value changed by
185  * comparing the desired value against {@link #getTranslationX()} as it minimizes JNI transitions.
186  * The actual mechanism of requesting a new frame to be rendered will depend on how this
187  * RenderNode is being drawn. If it's drawn to a containing View, as in the above snippet,
188  * then simply invalidating that View works. If instead the RenderNode is being drawn to a Canvas
189  * directly such as with {@link Surface#lockHardwareCanvas()} then a new frame needs to be drawn
190  * by calling {@link Surface#lockHardwareCanvas()}, re-drawing the root RenderNode or whatever
191  * top-level content is desired, and finally calling {@link Surface#unlockCanvasAndPost(Canvas)}.
192  * </p>
193  */
194 public final class RenderNode {
195 
196     // Use a Holder to allow static initialization in the boot image.
197     private static class NoImagePreloadHolder {
198         public static final NativeAllocationRegistry sRegistry =
199                 NativeAllocationRegistry.createMalloced(
200                 RenderNode.class.getClassLoader(), nGetNativeFinalizer());
201     }
202 
203     /**
204      * Not for general use; use only if you are ThreadedRenderer or RecordingCanvas.
205      *
206      * @hide
207      */
208     public final long mNativeRenderNode;
209     private final AnimationHost mAnimationHost;
210     private RecordingCanvas mCurrentRecordingCanvas;
211 
212     // Will be null if not currently registered
213     @Nullable
214     private CompositePositionUpdateListener mCompositePositionUpdateListener;
215 
216     /**
217      * Creates a new RenderNode that can be used to record batches of
218      * drawing operations, and store / apply render properties when drawn.
219      *
220      * @param name The name of the RenderNode, used for debugging purpose. May be null.
221      */
RenderNode(@ullable String name)222     public RenderNode(@Nullable String name) {
223         this(name, null);
224     }
225 
RenderNode(String name, AnimationHost animationHost)226     private RenderNode(String name, AnimationHost animationHost) {
227         mNativeRenderNode = nCreate(name);
228         NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeRenderNode);
229         mAnimationHost = animationHost;
230     }
231 
232     /**
233      * @see RenderNode#adopt(long)
234      */
RenderNode(long nativePtr)235     private RenderNode(long nativePtr) {
236         mNativeRenderNode = nativePtr;
237         NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeRenderNode);
238         mAnimationHost = null;
239     }
240 
241     /** @hide */
create(String name, @Nullable AnimationHost animationHost)242     public static RenderNode create(String name, @Nullable AnimationHost animationHost) {
243         return new RenderNode(name, animationHost);
244     }
245 
246     /**
247      * Adopts an existing native render node.
248      *
249      * Note: This will *NOT* incRef() on the native object, however it will
250      * decRef() when it is destroyed. The caller should have already incRef'd it
251      *
252      * @hide
253      */
adopt(long nativePtr)254     public static RenderNode adopt(long nativePtr) {
255         return new RenderNode(nativePtr);
256     }
257 
258     /**
259      * Listens for RenderNode position updates for synchronous window movement.
260      *
261      * This is not suitable for generic position listening, it is only designed & intended
262      * for use by things which require external position events like SurfaceView, PopupWindow, etc..
263      *
264      * @hide
265      */
266     public interface PositionUpdateListener {
267 
268         /**
269          * Called by native by a Rendering Worker thread to update window position
270          *
271          * @hide
272          */
positionChanged(long frameNumber, int left, int top, int right, int bottom)273         void positionChanged(long frameNumber, int left, int top, int right, int bottom);
274 
275         /**
276          * Called by native on RenderThread to notify that the view is no longer in the
277          * draw tree. UI thread is blocked at this point.
278          *
279          * @hide
280          */
positionLost(long frameNumber)281         void positionLost(long frameNumber);
282 
283     }
284 
285     private static final class CompositePositionUpdateListener implements PositionUpdateListener {
286         private final PositionUpdateListener[] mListeners;
287         private static final PositionUpdateListener[] sEmpty = new PositionUpdateListener[0];
288 
CompositePositionUpdateListener(PositionUpdateListener... listeners)289         CompositePositionUpdateListener(PositionUpdateListener... listeners) {
290             mListeners = listeners != null ? listeners : sEmpty;
291         }
292 
with(PositionUpdateListener listener)293         public CompositePositionUpdateListener with(PositionUpdateListener listener) {
294             return new CompositePositionUpdateListener(
295                     ArrayUtils.appendElement(PositionUpdateListener.class, mListeners, listener));
296         }
297 
without(PositionUpdateListener listener)298         public CompositePositionUpdateListener without(PositionUpdateListener listener) {
299             return new CompositePositionUpdateListener(
300                     ArrayUtils.removeElement(PositionUpdateListener.class, mListeners, listener));
301         }
302 
303         @Override
positionChanged(long frameNumber, int left, int top, int right, int bottom)304         public void positionChanged(long frameNumber, int left, int top, int right, int bottom) {
305             for (PositionUpdateListener pul : mListeners) {
306                 pul.positionChanged(frameNumber, left, top, right, bottom);
307             }
308         }
309 
310         @Override
positionLost(long frameNumber)311         public void positionLost(long frameNumber) {
312             for (PositionUpdateListener pul : mListeners) {
313                 pul.positionLost(frameNumber);
314             }
315         }
316     }
317 
318     /**
319      * Enable callbacks for position changes. Call only from the UI thread or with
320      * external synchronization.
321      *
322      * @hide
323      */
addPositionUpdateListener(@onNull PositionUpdateListener listener)324     public void addPositionUpdateListener(@NonNull PositionUpdateListener listener) {
325         CompositePositionUpdateListener comp = mCompositePositionUpdateListener;
326         if (comp == null) {
327             comp = new CompositePositionUpdateListener(listener);
328         } else {
329             comp = comp.with(listener);
330         }
331         mCompositePositionUpdateListener = comp;
332         nRequestPositionUpdates(mNativeRenderNode, comp);
333     }
334 
335     /**
336      * Disable a callback for position changes. Call only from the UI thread or with
337      * external synchronization.
338      *
339      * @param listener Callback to remove
340      * @hide
341      */
removePositionUpdateListener(@onNull PositionUpdateListener listener)342     public void removePositionUpdateListener(@NonNull PositionUpdateListener listener) {
343         CompositePositionUpdateListener comp = mCompositePositionUpdateListener;
344         if (comp != null) {
345             comp = comp.without(listener);
346             mCompositePositionUpdateListener = comp;
347             nRequestPositionUpdates(mNativeRenderNode, comp);
348         }
349     }
350 
351     /**
352      * Starts recording a display list for the render node. All
353      * operations performed on the returned canvas are recorded and
354      * stored in this display list.
355      *
356      * {@link #endRecording()} must be called when the recording is finished in order to apply
357      * the updated display list. Failing to call {@link #endRecording()} will result in an
358      * {@link IllegalStateException} if {@link #beginRecording(int, int)} is called again.
359      *
360      * @param width  The width of the recording viewport. This will not alter the width of the
361      *               RenderNode itself, that must be set with {@link #setPosition(Rect)}.
362      * @param height The height of the recording viewport. This will not alter the height of the
363      *               RenderNode itself, that must be set with {@link #setPosition(Rect)}.
364      * @return A canvas to record drawing operations.
365      * @throws IllegalStateException If a recording is already in progress. That is, the previous
366      * call to {@link #beginRecording(int, int)} did not call {@link #endRecording()}.
367      * @see #endRecording()
368      * @see #hasDisplayList()
369      */
beginRecording(int width, int height)370     public @NonNull RecordingCanvas beginRecording(int width, int height) {
371         if (mCurrentRecordingCanvas != null) {
372             throw new IllegalStateException(
373                     "Recording currently in progress - missing #endRecording() call?");
374         }
375         mCurrentRecordingCanvas = RecordingCanvas.obtain(this, width, height);
376         return mCurrentRecordingCanvas;
377     }
378 
379     /**
380      * Same as {@link #beginRecording(int, int)} with the width & height set
381      * to the RenderNode's own width & height. The RenderNode's width & height may be set
382      * with {@link #setPosition(int, int, int, int)}.
383      *
384      * @return A canvas to record drawing operations.
385      * @throws IllegalStateException If a recording is already in progress. That is, the previous
386      * call to {@link #beginRecording(int, int)} did not call {@link #endRecording()}.
387      * @see #endRecording()
388      * @see #hasDisplayList()
389      */
beginRecording()390     public @NonNull RecordingCanvas beginRecording() {
391         return beginRecording(nGetWidth(mNativeRenderNode), nGetHeight(mNativeRenderNode));
392     }
393 
394     /**
395      * `
396      * Ends the recording for this display list. Calling this method marks
397      * the display list valid and {@link #hasDisplayList()} will return true.
398      *
399      * @see #beginRecording(int, int)
400      * @see #hasDisplayList()
401      */
endRecording()402     public void endRecording() {
403         if (mCurrentRecordingCanvas == null) {
404             throw new IllegalStateException(
405                     "No recording in progress, forgot to call #beginRecording()?");
406         }
407         RecordingCanvas canvas = mCurrentRecordingCanvas;
408         mCurrentRecordingCanvas = null;
409         long displayList = canvas.finishRecording();
410         nSetDisplayList(mNativeRenderNode, displayList);
411         canvas.recycle();
412     }
413 
414     /**
415      * @hide
416      * @deprecated use {@link #beginRecording(int, int)} instead
417      */
418     @Deprecated
start(int width, int height)419     public RecordingCanvas start(int width, int height) {
420         return beginRecording(width, height);
421     }
422 
423     /**
424      * @hide
425      * @deprecated use {@link #endRecording()} instead
426      */
427     @Deprecated
end(RecordingCanvas canvas)428     public void end(RecordingCanvas canvas) {
429         if (canvas != mCurrentRecordingCanvas) {
430             throw new IllegalArgumentException("Wrong canvas");
431         }
432         endRecording();
433     }
434 
435     /**
436      * Reset native resources. This is called when cleaning up the state of display lists
437      * during destruction of hardware resources, to ensure that we do not hold onto
438      * obsolete resources after related resources are gone.
439      */
discardDisplayList()440     public void discardDisplayList() {
441         nSetDisplayList(mNativeRenderNode, 0);
442     }
443 
444     /**
445      * Returns whether the RenderNode has a display list. If this returns false, the RenderNode
446      * should be re-recorded with {@link #beginRecording()} and {@link #endRecording()}.
447      *
448      * A RenderNode without a display list may still be drawn, however it will have no impact
449      * on the rendering content until its display list is updated.
450      *
451      * When a RenderNode is no longer drawn by anything the system may automatically
452      * invoke {@link #discardDisplayList()}. It is therefore important to ensure that
453      * {@link #hasDisplayList()} is true on a RenderNode prior to drawing it.
454      *
455      * See {@link #discardDisplayList()}
456      *
457      * @return boolean true if this RenderNode has a display list, false otherwise.
458      */
hasDisplayList()459     public boolean hasDisplayList() {
460         return nIsValid(mNativeRenderNode);
461     }
462 
463     ///////////////////////////////////////////////////////////////////////////
464     // Matrix manipulation
465     ///////////////////////////////////////////////////////////////////////////
466 
467     /**
468      * Whether or not the RenderNode has an identity transform. This is a faster
469      * way to do the otherwise equivalent {@link #getMatrix(Matrix)} {@link Matrix#isIdentity()}
470      * as it doesn't require copying the Matrix first, thus minimizing overhead.
471      *
472      * @return true if the RenderNode has an identity transform, false otherwise
473      */
hasIdentityMatrix()474     public boolean hasIdentityMatrix() {
475         return nHasIdentityMatrix(mNativeRenderNode);
476     }
477 
478     /**
479      * Gets the current transform matrix
480      *
481      * @param outMatrix The matrix to store the transform of the RenderNode
482      */
getMatrix(@onNull Matrix outMatrix)483     public void getMatrix(@NonNull Matrix outMatrix) {
484         nGetTransformMatrix(mNativeRenderNode, outMatrix.native_instance);
485     }
486 
487     /**
488      * Gets the current transform inverted. This is a faster way to do the otherwise
489      * equivalent {@link #getMatrix(Matrix)} followed by {@link Matrix#invert(Matrix)}
490      *
491      * @param outMatrix The matrix to store the inverse transform of the RenderNode
492      */
getInverseMatrix(@onNull Matrix outMatrix)493     public void getInverseMatrix(@NonNull Matrix outMatrix) {
494         nGetInverseTransformMatrix(mNativeRenderNode, outMatrix.native_instance);
495     }
496 
497     ///////////////////////////////////////////////////////////////////////////
498     // RenderProperty Setters
499     ///////////////////////////////////////////////////////////////////////////
500 
501     /**
502      * @hide
503      * @deprecated use {@link #setUseCompositingLayer(boolean, Paint)} instead
504      */
505     @Deprecated
setLayerType(int layerType)506     public boolean setLayerType(int layerType) {
507         return nSetLayerType(mNativeRenderNode, layerType);
508     }
509 
510     /**
511      * @hide
512      * @deprecated use {@link #setUseCompositingLayer(boolean, Paint)} instead
513      */
514     @Deprecated
setLayerPaint(@ullable Paint paint)515     public boolean setLayerPaint(@Nullable Paint paint) {
516         return nSetLayerPaint(mNativeRenderNode, paint != null ? paint.getNativeInstance() : 0);
517     }
518 
519     /**
520      * Controls whether or not to force this RenderNode to render to an intermediate buffer.
521      * Internally RenderNode will already promote itself to a composition layer if it's useful
522      * for performance or required for the current combination of {@link #setAlpha(float)} and
523      * {@link #setHasOverlappingRendering(boolean)}.
524      *
525      * <p>The usage of this is instead to allow for either overriding of the internal behavior
526      * if it's measured to be necessary for the particular rendering content in question or, more
527      * usefully, to add a composition effect to the RenderNode via the optional paint parameter.
528      *
529      * <p>Note: When a RenderNode is using a compositing layer it will also result in
530      * clipToBounds=true behavior.
531      *
532      * @param forceToLayer if true this forces the RenderNode to use an intermediate buffer.
533      *                     Default & generally recommended value is false.
534      * @param paint        The blend mode, alpha, and ColorFilter to apply to the compositing layer.
535      *                     Only applies if forceToLayer is true. The paint's alpha is multiplied
536      *                     with {@link #getAlpha()} to resolve the final alpha of the RenderNode.
537      *                     If null then no additional composition effects are applied on top of the
538      *                     composition layer.
539      * @return True if the value changed, false if the new value was the same as the previous value.
540      */
setUseCompositingLayer(boolean forceToLayer, @Nullable Paint paint)541     public boolean setUseCompositingLayer(boolean forceToLayer, @Nullable Paint paint) {
542         boolean didChange = nSetLayerType(mNativeRenderNode, forceToLayer ? 2 : 0);
543         didChange |= nSetLayerPaint(mNativeRenderNode,
544                 paint != null ? paint.getNativeInstance() : 0);
545         return didChange;
546     }
547 
548     /**
549      * Gets whether or not a compositing layer is forced to be used. The default & recommended
550      * is false, as it is typically faster to avoid using compositing layers.
551      * See {@link #setUseCompositingLayer(boolean, Paint)}.
552      *
553      * @return true if a compositing layer is forced, false otherwise
554      */
getUseCompositingLayer()555     public boolean getUseCompositingLayer() {
556         return nGetLayerType(mNativeRenderNode) != 0;
557     }
558 
559     /**
560      * Sets an additional clip on the RenderNode. If null, the extra clip is removed from the
561      * RenderNode. If non-null, the RenderNode will be clipped to this rect. In addition  if
562      * {@link #setClipToBounds(boolean)} is true, then the RenderNode will be clipped to the
563      * intersection of this rectangle and the bounds of the render node, which is set with
564      * {@link #setPosition(Rect)}.
565      *
566      * <p>This is equivalent to do a {@link Canvas#clipRect(Rect)} at the start of this
567      * RenderNode's display list. However, as this is a property of the RenderNode instead
568      * of part of the display list it can be more easily animated for transient additional
569      * clipping. An example usage of this would be the {@link android.transition.ChangeBounds}
570      * transition animation with the resizeClip=true option.
571      *
572      * @param rect the bounds to clip to. If null, the additional clip is removed.
573      * @return True if the value changed, false if the new value was the same as the previous value.
574      */
setClipRect(@ullable Rect rect)575     public boolean setClipRect(@Nullable Rect rect) {
576         if (rect == null) {
577             return nSetClipBoundsEmpty(mNativeRenderNode);
578         } else {
579             return nSetClipBounds(mNativeRenderNode, rect.left, rect.top, rect.right, rect.bottom);
580         }
581     }
582 
583     /**
584      * Set whether the Render node should clip itself to its bounds. This defaults to true,
585      * and is useful to the renderer in enable quick-rejection of chunks of the tree as well as
586      * better partial invalidation support. Clipping can be further restricted or controlled
587      * through the combination of this property as well as {@link #setClipRect(Rect)}, which
588      * allows for a different clipping rectangle to be used in addition to or instead of the
589      * {@link #setPosition(int, int, int, int)} or the RenderNode.
590      *
591      * @param clipToBounds true if the display list should clip to its bounds, false otherwise.
592      * @return True if the value changed, false if the new value was the same as the previous value.
593      */
setClipToBounds(boolean clipToBounds)594     public boolean setClipToBounds(boolean clipToBounds) {
595         return nSetClipToBounds(mNativeRenderNode, clipToBounds);
596     }
597 
598     /**
599      * Returns whether or not the RenderNode is clipping to its bounds. See
600      * {@link #setClipToBounds(boolean)} and {@link #setPosition(int, int, int, int)}
601      *
602      * @return true if the render node clips to its bounds, false otherwise.
603      */
getClipToBounds()604     public boolean getClipToBounds() {
605         return nGetClipToBounds(mNativeRenderNode);
606     }
607 
608     /**
609      * <p>Sets whether the RenderNode should be drawn immediately after the
610      * closest ancestor RenderNode containing a projection receiver.
611      *
612      * <p>The default is false, and the rendering of this node happens in the typical draw order.
613      *
614      * <p>If true, then at rendering time this rendernode will not be drawn in order with the
615      * {@link Canvas#drawRenderNode(RenderNode)} command that drew this RenderNode, but instead
616      * it will be re-positioned in the RenderNode tree to be drawn on the closet ancestor with a
617      * child rendernode that has {@link #setProjectionReceiver(boolean)} as true.
618      *
619      * <p>The typical usage of this is to allow a child RenderNode to draw on a parent's background,
620      * such as the platform's usage with {@link android.graphics.drawable.RippleDrawable}. Consider
621      * the following structure, built out of which RenderNode called drawRenderNode on a different
622      * RenderNode:
623      *
624      * <pre>
625      *        +-------------+
626      *        |RenderNode: P|
627      *        +-+----------++
628      *          |          |
629      *          v          v
630      *  +-------+-----+  +-+--------------+
631      *  |RenderNode: C|  |RenderNode: P'BG|
632      *  +-------+-----+  +----------------+
633      *          |
634      *          |
635      * +--------+-------+
636      * |RenderNode: C'BG|
637      * +----------------+
638      * </pre>
639      *
640      * If P'BG is a projection receiver, and C'BG is set to project backwards then C'BG will
641      * behave as if it was drawn directly by P'BG instead of by C. This includes inheriting P'BG's
642      * clip instead of C's clip.
643      *
644      * @param shouldProject true if the display list should be projected onto a
645      *                      containing volume. Default is false.
646      * @return True if the value changed, false if the new value was the same as the previous value.
647      */
setProjectBackwards(boolean shouldProject)648     public boolean setProjectBackwards(boolean shouldProject) {
649         return nSetProjectBackwards(mNativeRenderNode, shouldProject);
650     }
651 
652     /**
653      * Sets whether the RenderNode is a projection receiver. If true then this RenderNode's parent
654      * should draw any descendant RenderNodes with ProjectBackwards=true directly on top of it.
655      * Default value is false. See
656      * {@link #setProjectBackwards(boolean)} for a description of what this entails.
657      *
658      * @param shouldRecieve True if this RenderNode is a projection receiver, false otherwise.
659      *                      Default is false.
660      * @return True if the value changed, false if the new value was the same as the previous value.
661      */
setProjectionReceiver(boolean shouldRecieve)662     public boolean setProjectionReceiver(boolean shouldRecieve) {
663         return nSetProjectionReceiver(mNativeRenderNode, shouldRecieve);
664     }
665 
666     /**
667      * Sets the outline, defining the shape that casts a shadow, and the path to
668      * be clipped if setClipToOutline is set.
669      *
670      * This will make a copy of the provided {@link Outline}, so any future modifications
671      * to the outline will need to call {@link #setOutline(Outline)} with the modified
672      * outline for those changes to be applied.
673      *
674      * @param outline The outline to use for this RenderNode.
675      * @return True if the value changed, false if the new value was the same as the previous value.
676      */
setOutline(@ullable Outline outline)677     public boolean setOutline(@Nullable Outline outline) {
678         if (outline == null) {
679             return nSetOutlineNone(mNativeRenderNode);
680         }
681 
682         switch (outline.mMode) {
683             case Outline.MODE_EMPTY:
684                 return nSetOutlineEmpty(mNativeRenderNode);
685             case Outline.MODE_ROUND_RECT:
686                 return nSetOutlineRoundRect(mNativeRenderNode,
687                         outline.mRect.left, outline.mRect.top,
688                         outline.mRect.right, outline.mRect.bottom,
689                         outline.mRadius, outline.mAlpha);
690             case Outline.MODE_PATH:
691                 return nSetOutlinePath(mNativeRenderNode, outline.mPath.mNativePath,
692                         outline.mAlpha);
693         }
694 
695         throw new IllegalArgumentException("Unrecognized outline?");
696     }
697 
698     /**
699      * Checks if the RenderNode has a shadow. That is, if the combination of {@link #getElevation()}
700      * and {@link #getTranslationZ()} is greater than zero, there is an {@link Outline} set with
701      * a valid shadow caster path, and the provided outline has a non-zero
702      * {@link Outline#getAlpha()}.
703      *
704      * @return True if this RenderNode has a shadow, false otherwise
705      */
hasShadow()706     public boolean hasShadow() {
707         return nHasShadow(mNativeRenderNode);
708     }
709 
710     /**
711      * Sets the color of the spot shadow that is drawn when the RenderNode has a positive Z or
712      * elevation value and is drawn inside of a {@link Canvas#enableZ()} section.
713      * <p>
714      * By default the shadow color is black. Generally, this color will be opaque so the intensity
715      * of the shadow is consistent between different RenderNodes with different colors.
716      * <p>
717      * The opacity of the final spot shadow is a function of the shadow caster height, the
718      * alpha channel of the outlineSpotShadowColor (typically opaque), and the
719      * {@link android.R.attr#spotShadowAlpha} theme attribute
720      *
721      * @param color The color this RenderNode will cast for its elevation spot shadow.
722      * @return True if the value changed, false if the new value was the same as the previous value.
723      */
setSpotShadowColor(@olorInt int color)724     public boolean setSpotShadowColor(@ColorInt int color) {
725         return nSetSpotShadowColor(mNativeRenderNode, color);
726     }
727 
728     /**
729      * @return The shadow color set by {@link #setSpotShadowColor(int)}, or black if nothing
730      * was set
731      */
getSpotShadowColor()732     public @ColorInt int getSpotShadowColor() {
733         return nGetSpotShadowColor(mNativeRenderNode);
734     }
735 
736     /**
737      * Sets the color of the ambient shadow that is drawn when the RenderNode has a positive Z or
738      * elevation value and is drawn inside of a {@link Canvas#enableZ()} section.
739      * <p>
740      * By default the shadow color is black. Generally, this color will be opaque so the intensity
741      * of the shadow is consistent between different RenderNodes with different colors.
742      * <p>
743      * The opacity of the final ambient shadow is a function of the shadow caster height, the
744      * alpha channel of the outlineAmbientShadowColor (typically opaque), and the
745      * {@link android.R.attr#ambientShadowAlpha} theme attribute.
746      *
747      * @param color The color this RenderNode will cast for its elevation shadow.
748      * @return True if the value changed, false if the new value was the same as the previous value.
749      */
setAmbientShadowColor(@olorInt int color)750     public boolean setAmbientShadowColor(@ColorInt int color) {
751         return nSetAmbientShadowColor(mNativeRenderNode, color);
752     }
753 
754     /**
755      * @return The shadow color set by {@link #setAmbientShadowColor(int)}, or black if
756      * nothing was set
757      */
getAmbientShadowColor()758     public @ColorInt int getAmbientShadowColor() {
759         return nGetAmbientShadowColor(mNativeRenderNode);
760     }
761 
762     /**
763      * Enables or disables clipping to the outline.
764      *
765      * @param clipToOutline true if clipping to the outline.
766      * @return True if the clipToOutline value changed, false if previous value matched the new
767      *         value.
768      */
setClipToOutline(boolean clipToOutline)769     public boolean setClipToOutline(boolean clipToOutline) {
770         return nSetClipToOutline(mNativeRenderNode, clipToOutline);
771     }
772 
773     /**
774      * See {@link #setClipToOutline(boolean)}
775      *
776      * @return True if this RenderNode clips to its outline, false otherwise
777      */
getClipToOutline()778     public boolean getClipToOutline() {
779         return nGetClipToOutline(mNativeRenderNode);
780     }
781 
782     /**
783      * Controls the RenderNode's circular reveal clip.
784      *
785      * @hide
786      */
setRevealClip(boolean shouldClip, float x, float y, float radius)787     public boolean setRevealClip(boolean shouldClip,
788             float x, float y, float radius) {
789         return nSetRevealClip(mNativeRenderNode, shouldClip, x, y, radius);
790     }
791 
792     /**
793      * Set the static matrix on the display list. The specified matrix is combined with other
794      * transforms (such as {@link #setScaleX(float)}, {@link #setRotationZ(float)}, etc.)
795      *
796      * @param matrix A transform matrix to apply to this display list
797      * @hide TODO Do we want this?
798      */
setStaticMatrix(Matrix matrix)799     public boolean setStaticMatrix(Matrix matrix) {
800         return nSetStaticMatrix(mNativeRenderNode, matrix.native_instance);
801     }
802 
803     /**
804      * Set the Animation matrix on the display list. This matrix exists if an Animation is
805      * currently playing on a View, and is set on the display list during at draw() time. When
806      * the Animation finishes, the matrix should be cleared by sending <code>null</code>
807      * for the matrix parameter.
808      *
809      * @param matrix The matrix, null indicates that the matrix should be cleared.
810      * @see #getAnimationMatrix()
811      *
812      * @hide TODO Do we want this?
813      */
setAnimationMatrix(@ullable Matrix matrix)814     public boolean setAnimationMatrix(@Nullable Matrix matrix) {
815         return nSetAnimationMatrix(mNativeRenderNode,
816                 (matrix != null) ? matrix.native_instance : 0);
817     }
818 
819     /**
820      * Returns the previously set Animation matrix. This matrix exists if an Animation is
821      * currently playing on a View, and is set on the display list during at draw() time.
822      * Returns <code>null</code> when there is no transformation provided by
823      * {@link #setAnimationMatrix(Matrix)}.
824      *
825      * @return the current Animation matrix.
826      * @see #setAnimationMatrix(Matrix)
827      *
828      * @hide
829      */
830     @Nullable
getAnimationMatrix()831     public Matrix getAnimationMatrix() {
832         Matrix output = new Matrix();
833         if (nGetAnimationMatrix(mNativeRenderNode, output.native_instance)) {
834             return output;
835         } else {
836             return null;
837         }
838     }
839 
840     /**
841      * Sets the translucency level for the display list.
842      *
843      * @param alpha The translucency of the display list, must be a value between 0.0f and 1.0f
844      * @see View#setAlpha(float)
845      * @see #getAlpha()
846      * @return True if the value changed, false if the new value was the same as the previous value.
847      */
setAlpha(float alpha)848     public boolean setAlpha(float alpha) {
849         return nSetAlpha(mNativeRenderNode, alpha);
850     }
851 
852     /**
853      * Returns the translucency level of this display list.
854      *
855      * @return A value between 0.0f and 1.0f
856      * @see #setAlpha(float)
857      */
getAlpha()858     public float getAlpha() {
859         return nGetAlpha(mNativeRenderNode);
860     }
861 
862     /**
863      * Sets whether the display list renders content which overlaps. Non-overlapping rendering
864      * can use a fast path for alpha that avoids rendering to an offscreen buffer. By default
865      * display lists consider they do not have overlapping content.
866      *
867      * @param hasOverlappingRendering False if the content is guaranteed to be non-overlapping,
868      *                                true otherwise.
869      * @see android.view.View#hasOverlappingRendering()
870      * @see #hasOverlappingRendering()
871      */
setHasOverlappingRendering(boolean hasOverlappingRendering)872     public boolean setHasOverlappingRendering(boolean hasOverlappingRendering) {
873         return nSetHasOverlappingRendering(mNativeRenderNode, hasOverlappingRendering);
874     }
875 
876     /** @hide */
877     @IntDef({USAGE_BACKGROUND})
878     @Retention(RetentionPolicy.SOURCE)
879     public @interface UsageHint {
880     }
881 
882     /**
883      * The default usage hint
884      *
885      * @hide
886      */
887     public static final int USAGE_UNKNOWN = 0;
888 
889     /**
890      * Usage is background content
891      *
892      * @hide
893      */
894     public static final int USAGE_BACKGROUND = 1;
895 
896     /**
897      * Provides a hint on what this RenderNode's display list content contains. This hint is used
898      * for automatic content transforms to improve accessibility or similar.
899      *
900      * @hide
901      */
setUsageHint(@sageHint int usageHint)902     public void setUsageHint(@UsageHint int usageHint) {
903         nSetUsageHint(mNativeRenderNode, usageHint);
904     }
905 
906     /**
907      * Indicates whether the content of this display list overlaps.
908      *
909      * @return True if this display list renders content which overlaps, false otherwise.
910      * @see #setHasOverlappingRendering(boolean)
911      */
hasOverlappingRendering()912     public boolean hasOverlappingRendering() {
913         return nHasOverlappingRendering(mNativeRenderNode);
914     }
915 
916     /**
917      * Sets the base elevation of this RenderNode in pixels
918      *
919      * @param lift the elevation in pixels
920      * @return True if the value changed, false if the new value was the same as the previous value.
921      */
setElevation(float lift)922     public boolean setElevation(float lift) {
923         return nSetElevation(mNativeRenderNode, lift);
924     }
925 
926     /**
927      * See {@link #setElevation(float)}
928      *
929      * @return The RenderNode's current elevation
930      */
getElevation()931     public float getElevation() {
932         return nGetElevation(mNativeRenderNode);
933     }
934 
935     /**
936      * Sets the translation value for the display list on the X axis.
937      *
938      * @param translationX The X axis translation value of the display list, in pixels
939      * @see View#setTranslationX(float)
940      * @see #getTranslationX()
941      * @return True if the value changed, false if the new value was the same as the previous value.
942      */
setTranslationX(float translationX)943     public boolean setTranslationX(float translationX) {
944         return nSetTranslationX(mNativeRenderNode, translationX);
945     }
946 
947     /**
948      * Returns the translation value for this display list on the X axis, in pixels.
949      *
950      * @see #setTranslationX(float)
951      */
getTranslationX()952     public float getTranslationX() {
953         return nGetTranslationX(mNativeRenderNode);
954     }
955 
956     /**
957      * Sets the translation value for the display list on the Y axis.
958      *
959      * @param translationY The Y axis translation value of the display list, in pixels
960      * @see View#setTranslationY(float)
961      * @see #getTranslationY()
962      * @return True if the value changed, false if the new value was the same as the previous value.
963      */
setTranslationY(float translationY)964     public boolean setTranslationY(float translationY) {
965         return nSetTranslationY(mNativeRenderNode, translationY);
966     }
967 
968     /**
969      * Returns the translation value for this display list on the Y axis, in pixels.
970      *
971      * @see #setTranslationY(float)
972      */
getTranslationY()973     public float getTranslationY() {
974         return nGetTranslationY(mNativeRenderNode);
975     }
976 
977     /**
978      * Sets the translation value for the display list on the Z axis.
979      *
980      * @see View#setTranslationZ(float)
981      * @see #getTranslationZ()
982      * @return True if the value changed, false if the new value was the same as the previous value.
983      */
setTranslationZ(float translationZ)984     public boolean setTranslationZ(float translationZ) {
985         return nSetTranslationZ(mNativeRenderNode, translationZ);
986     }
987 
988     /**
989      * Returns the translation value for this display list on the Z axis.
990      *
991      * @see #setTranslationZ(float)
992      */
getTranslationZ()993     public float getTranslationZ() {
994         return nGetTranslationZ(mNativeRenderNode);
995     }
996 
997     /**
998      * Sets the rotation value for the display list around the Z axis.
999      *
1000      * @param rotation The rotation value of the display list, in degrees
1001      * @see View#setRotation(float)
1002      * @see #getRotationZ()
1003      * @return True if the value changed, false if the new value was the same as the previous value.
1004      */
setRotationZ(float rotation)1005     public boolean setRotationZ(float rotation) {
1006         return nSetRotation(mNativeRenderNode, rotation);
1007     }
1008 
1009     /**
1010      * Returns the rotation value for this display list around the Z axis, in degrees.
1011      *
1012      * @see #setRotationZ(float)
1013      */
getRotationZ()1014     public float getRotationZ() {
1015         return nGetRotation(mNativeRenderNode);
1016     }
1017 
1018     /**
1019      * Sets the rotation value for the display list around the X axis.
1020      *
1021      * @param rotationX The rotation value of the display list, in degrees
1022      * @see View#setRotationX(float)
1023      * @see #getRotationX()
1024      * @return True if the value changed, false if the new value was the same as the previous value.
1025      */
setRotationX(float rotationX)1026     public boolean setRotationX(float rotationX) {
1027         return nSetRotationX(mNativeRenderNode, rotationX);
1028     }
1029 
1030     /**
1031      * Returns the rotation value for this display list around the X axis, in degrees.
1032      *
1033      * @see #setRotationX(float)
1034      */
getRotationX()1035     public float getRotationX() {
1036         return nGetRotationX(mNativeRenderNode);
1037     }
1038 
1039     /**
1040      * Sets the rotation value for the display list around the Y axis.
1041      *
1042      * @param rotationY The rotation value of the display list, in degrees
1043      * @see View#setRotationY(float)
1044      * @see #getRotationY()
1045      * @return True if the value changed, false if the new value was the same as the previous value.
1046      */
setRotationY(float rotationY)1047     public boolean setRotationY(float rotationY) {
1048         return nSetRotationY(mNativeRenderNode, rotationY);
1049     }
1050 
1051     /**
1052      * Returns the rotation value for this display list around the Y axis, in degrees.
1053      *
1054      * @see #setRotationY(float)
1055      */
getRotationY()1056     public float getRotationY() {
1057         return nGetRotationY(mNativeRenderNode);
1058     }
1059 
1060     /**
1061      * Sets the scale value for the display list on the X axis.
1062      *
1063      * @param scaleX The scale value of the display list
1064      * @see View#setScaleX(float)
1065      * @see #getScaleX()
1066      * @return True if the value changed, false if the new value was the same as the previous value.
1067      */
setScaleX(float scaleX)1068     public boolean setScaleX(float scaleX) {
1069         return nSetScaleX(mNativeRenderNode, scaleX);
1070     }
1071 
1072     /**
1073      * Returns the scale value for this display list on the X axis.
1074      *
1075      * @see #setScaleX(float)
1076      */
getScaleX()1077     public float getScaleX() {
1078         return nGetScaleX(mNativeRenderNode);
1079     }
1080 
1081     /**
1082      * Sets the scale value for the display list on the Y axis.
1083      *
1084      * @param scaleY The scale value of the display list
1085      * @see View#setScaleY(float)
1086      * @see #getScaleY()
1087      * @return True if the value changed, false if the new value was the same as the previous value.
1088      */
setScaleY(float scaleY)1089     public boolean setScaleY(float scaleY) {
1090         return nSetScaleY(mNativeRenderNode, scaleY);
1091     }
1092 
1093     /**
1094      * Returns the scale value for this display list on the Y axis.
1095      *
1096      * @see #setScaleY(float)
1097      */
getScaleY()1098     public float getScaleY() {
1099         return nGetScaleY(mNativeRenderNode);
1100     }
1101 
1102     /**
1103      * Sets the pivot value for the display list on the X axis
1104      *
1105      * @param pivotX The pivot value of the display list on the X axis, in pixels
1106      * @see View#setPivotX(float)
1107      * @see #getPivotX()
1108      * @return True if the value changed, false if the new value was the same as the previous value.
1109      */
setPivotX(float pivotX)1110     public boolean setPivotX(float pivotX) {
1111         return nSetPivotX(mNativeRenderNode, pivotX);
1112     }
1113 
1114     /**
1115      * Returns the pivot value for this display list on the X axis, in pixels.
1116      *
1117      * @see #setPivotX(float)
1118      */
getPivotX()1119     public float getPivotX() {
1120         return nGetPivotX(mNativeRenderNode);
1121     }
1122 
1123     /**
1124      * Sets the pivot value for the display list on the Y axis
1125      *
1126      * @param pivotY The pivot value of the display list on the Y axis, in pixels
1127      * @see View#setPivotY(float)
1128      * @see #getPivotY()
1129      * @return True if the value changed, false if the new value was the same as the previous value.
1130      */
setPivotY(float pivotY)1131     public boolean setPivotY(float pivotY) {
1132         return nSetPivotY(mNativeRenderNode, pivotY);
1133     }
1134 
1135     /**
1136      * Returns the pivot value for this display list on the Y axis, in pixels.
1137      *
1138      * @see #setPivotY(float)
1139      */
getPivotY()1140     public float getPivotY() {
1141         return nGetPivotY(mNativeRenderNode);
1142     }
1143 
1144     /**
1145      * @return Whether or not a pivot was explicitly set with {@link #setPivotX(float)} or
1146      * {@link #setPivotY(float)}. If no pivot has been set then the pivot will be the center
1147      * of the RenderNode.
1148      */
isPivotExplicitlySet()1149     public boolean isPivotExplicitlySet() {
1150         return nIsPivotExplicitlySet(mNativeRenderNode);
1151     }
1152 
1153     /**
1154      * Clears any pivot previously set by a call to  {@link #setPivotX(float)} or
1155      * {@link #setPivotY(float)}. After calling this {@link #isPivotExplicitlySet()} will be false
1156      * and the pivot used for rotation will return to default of being centered on the view.
1157      *
1158      * @return True if the value changed, false if the new value was the same as the previous value.
1159      */
resetPivot()1160     public boolean resetPivot() {
1161         return nResetPivot(mNativeRenderNode);
1162     }
1163 
1164     /**
1165      * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which
1166      * RenderNodes are drawn) from the camera to this RenderNode. The camera's distance
1167      * affects 3D transformations, for instance rotations around the X and Y
1168      * axis. If the rotationX or rotationY properties are changed and this view is
1169      * large (more than half the size of the screen), it is recommended to always
1170      * use a camera distance that's greater than the height (X axis rotation) or
1171      * the width (Y axis rotation) of this view.</p>
1172      *
1173      * <p>The distance of the camera from the drawing plane can have an affect on the
1174      * perspective distortion of the RenderNode when it is rotated around the x or y axis.
1175      * For example, a large distance will result in a large viewing angle, and there
1176      * will not be much perspective distortion of the view as it rotates. A short
1177      * distance may cause much more perspective distortion upon rotation, and can
1178      * also result in some drawing artifacts if the rotated view ends up partially
1179      * behind the camera (which is why the recommendation is to use a distance at
1180      * least as far as the size of the view, if the view is to be rotated.)</p>
1181      *
1182      * <p>The distance is expressed in pixels and must always be positive</p>
1183      *
1184      * @param distance The distance in pixels, must always be positive
1185      * @see #setRotationX(float)
1186      * @see #setRotationY(float)
1187      * @return True if the value changed, false if the new value was the same as the previous value.
1188      */
setCameraDistance( @loatRangefrom = 0.0f, to = Float.MAX_VALUE) float distance)1189     public boolean setCameraDistance(
1190             @FloatRange(from = 0.0f, to = Float.MAX_VALUE) float distance) {
1191         if (!Float.isFinite(distance) || distance < 0.0f) {
1192             throw new IllegalArgumentException("distance must be finite & positive, given="
1193                     + distance);
1194         }
1195         // Native actually wants this to be negative not positive, so we flip it.
1196         return nSetCameraDistance(mNativeRenderNode, -distance);
1197     }
1198 
1199     /**
1200      * Returns the distance in Z of the camera for this RenderNode
1201      *
1202      * @return the distance along the Z axis in pixels.
1203      * @see #setCameraDistance(float)
1204      */
getCameraDistance()1205     public @FloatRange(from = 0.0f, to = Float.MAX_VALUE) float getCameraDistance() {
1206         return -nGetCameraDistance(mNativeRenderNode);
1207     }
1208 
1209     /**
1210      * Sets the left position for the RenderNode.
1211      *
1212      * @param left The left position, in pixels, of the RenderNode
1213      * @return true if the value changed, false otherwise
1214      * @hide
1215      */
setLeft(int left)1216     public boolean setLeft(int left) {
1217         return nSetLeft(mNativeRenderNode, left);
1218     }
1219 
1220     /**
1221      * Sets the top position for the RenderNode.
1222      *
1223      * @param top The top position, in pixels, of the RenderNode
1224      * @return true if the value changed, false otherwise.
1225      * @hide
1226      */
setTop(int top)1227     public boolean setTop(int top) {
1228         return nSetTop(mNativeRenderNode, top);
1229     }
1230 
1231     /**
1232      * Sets the right position for the RenderNode.
1233      *
1234      * @param right The right position, in pixels, of the RenderNode
1235      * @return true if the value changed, false otherwise.
1236      * @hide
1237      */
setRight(int right)1238     public boolean setRight(int right) {
1239         return nSetRight(mNativeRenderNode, right);
1240     }
1241 
1242     /**
1243      * Sets the bottom position for the RenderNode.
1244      *
1245      * @param bottom The bottom position, in pixels, of the RenderNode
1246      * @return true if the value changed, false otherwise.
1247      * @hide
1248      */
setBottom(int bottom)1249     public boolean setBottom(int bottom) {
1250         return nSetBottom(mNativeRenderNode, bottom);
1251     }
1252 
1253     /**
1254      * Gets the left position for the RenderNode.
1255      *
1256      * @return the left position in pixels
1257      */
getLeft()1258     public int getLeft() {
1259         return nGetLeft(mNativeRenderNode);
1260     }
1261 
1262     /**
1263      * Gets the top position for the RenderNode.
1264      *
1265      * @return the top position in pixels
1266      */
getTop()1267     public int getTop() {
1268         return nGetTop(mNativeRenderNode);
1269     }
1270 
1271     /**
1272      * Gets the right position for the RenderNode.
1273      *
1274      * @return the right position in pixels
1275      */
getRight()1276     public int getRight() {
1277         return nGetRight(mNativeRenderNode);
1278     }
1279 
1280     /**
1281      * Gets the bottom position for the RenderNode.
1282      *
1283      * @return the bottom position in pixels
1284      */
getBottom()1285     public int getBottom() {
1286         return nGetBottom(mNativeRenderNode);
1287     }
1288 
1289     /**
1290      * Gets the width of the RenderNode, which is the right - left.
1291      *
1292      * @return the width of the RenderNode
1293      */
getWidth()1294     public int getWidth() {
1295         return nGetWidth(mNativeRenderNode);
1296     }
1297 
1298     /**
1299      * Gets the height of the RenderNode, which is the bottom - top.
1300      *
1301      * @return the height of the RenderNode
1302      */
getHeight()1303     public int getHeight() {
1304         return nGetHeight(mNativeRenderNode);
1305     }
1306 
1307     /**
1308      * Sets the left, top, right, and bottom of the RenderNode.
1309      *
1310      * @param left   The left position of the RenderNode, in pixels
1311      * @param top    The top position of the RenderNode, in pixels
1312      * @param right  The right position of the RenderNode, in pixels
1313      * @param bottom The bottom position of the RenderNode, in pixels
1314      * @return true if any values changed, false otherwise.
1315      * @hide
1316      */
setLeftTopRightBottom(int left, int top, int right, int bottom)1317     public boolean setLeftTopRightBottom(int left, int top, int right, int bottom) {
1318         return nSetLeftTopRightBottom(mNativeRenderNode, left, top, right, bottom);
1319     }
1320 
1321     /**
1322      * Sets the position of the RenderNode.
1323      *
1324      * @param left   The left position of the RenderNode, in pixels
1325      * @param top    The top position of the RenderNode, in pixels
1326      * @param right  The right position of the RenderNode, in pixels
1327      * @param bottom The bottom position of the RenderNode, in pixels
1328      * @return True if the value changed, false if the new value was the same as the previous value.
1329      */
setPosition(int left, int top, int right, int bottom)1330     public boolean setPosition(int left, int top, int right, int bottom) {
1331         return nSetLeftTopRightBottom(mNativeRenderNode, left, top, right, bottom);
1332     }
1333 
1334     /**
1335      * Sets the position of the RenderNode.
1336      *
1337      * @param position The position rectangle in pixels
1338      * @return True if the value changed, false if the new value was the same as the previous value.
1339      */
setPosition(@onNull Rect position)1340     public boolean setPosition(@NonNull Rect position) {
1341         return nSetLeftTopRightBottom(mNativeRenderNode,
1342                 position.left, position.top, position.right, position.bottom);
1343     }
1344 
1345     /**
1346      * Offsets the left and right positions for the RenderNode
1347      *
1348      * @param offset The amount that the left and right positions are offset in pixels
1349      * @return True if the value changed, false if the new value was the same as the previous value.
1350      */
offsetLeftAndRight(int offset)1351     public boolean offsetLeftAndRight(int offset) {
1352         return nOffsetLeftAndRight(mNativeRenderNode, offset);
1353     }
1354 
1355     /**
1356      * Offsets the top and bottom values for the RenderNode
1357      *
1358      * @param offset The amount that the left and right positions are offset in pixels
1359      * @return True if the value changed, false if the new value was the same as the previous value.
1360      */
offsetTopAndBottom(int offset)1361     public boolean offsetTopAndBottom(int offset) {
1362         return nOffsetTopAndBottom(mNativeRenderNode, offset);
1363     }
1364 
1365     /**
1366      * Outputs the RenderNode to the log. This method exists for use by
1367      * tools to output display lists for selected nodes to the log.
1368      *
1369      * @hide TODO: Expose? Should the shape of this be different than forced dump to logcat?
1370      */
output()1371     public void output() {
1372         nOutput(mNativeRenderNode);
1373     }
1374 
1375     /**
1376      * Gets the approximate memory usage of the RenderNode for debug purposes. Does not include
1377      * the memory usage of any child RenderNodes nor any bitmaps, only the memory usage of
1378      * this RenderNode and any data it owns.
1379      *
1380      * @return Approximate memory usage in bytes.
1381      */
computeApproximateMemoryUsage()1382     public @BytesLong long computeApproximateMemoryUsage() {
1383         return nGetUsageSize(mNativeRenderNode);
1384     }
1385 
1386     /**
1387      * Gets the approximate amount of memory allocated for the RenderNode for debug purposes.
1388      * Does not include the memory allocated by any child RenderNodes nor any bitmaps, only the
1389      * memory allocated for this RenderNode and any data it owns.
1390      *
1391      * The difference between this and {@link #computeApproximateMemoryUsage()} is this includes
1392      * memory allocated but not used. In particular structures such as DisplayLists are similar
1393      * to things like ArrayLists - they need to resize as commands are added to them. As such,
1394      * memory used can be less than memory allocated.
1395      *
1396      * @hide */
computeApproximateMemoryAllocated()1397     public @BytesLong long computeApproximateMemoryAllocated() {
1398         return nGetAllocatedSize(mNativeRenderNode);
1399     }
1400 
1401     /**
1402      * Sets whether or not to allow force dark to apply to this RenderNode.
1403      *
1404      * Setting this to false will disable the auto-dark feature on everything this RenderNode
1405      * draws, including any descendants.
1406      *
1407      * Setting this to true will allow this RenderNode to be automatically made dark, however
1408      * a value of 'true' will not override any 'false' value in its parent chain nor will
1409      * it prevent any 'false' in any of its children.
1410      *
1411      * @param allow Whether or not to allow force dark.
1412      * @return True if the value changed, false if the new value was the same as the previous value.
1413      */
setForceDarkAllowed(boolean allow)1414     public boolean setForceDarkAllowed(boolean allow) {
1415         return nSetAllowForceDark(mNativeRenderNode, allow);
1416     }
1417 
1418     /**
1419      * See {@link #setForceDarkAllowed(boolean)}
1420      *
1421      * @return true if force dark is allowed (default), false if it is disabled
1422      */
isForceDarkAllowed()1423     public boolean isForceDarkAllowed() {
1424         return nGetAllowForceDark(mNativeRenderNode);
1425     }
1426 
1427     /**
1428      * Returns the unique ID that identifies this RenderNode. This ID is unique for the
1429      * lifetime of the process. IDs are reset on process death, and are unique only within
1430      * the process.
1431      *
1432      * This ID is intended to be used with debugging tools to associate a particular
1433      * RenderNode across different debug dumping & inspection tools. For example
1434      * a View layout inspector should include the unique ID for any RenderNodes that it owns
1435      * to associate the drawing content with the layout content.
1436      *
1437      * @return the unique ID for this RenderNode
1438      */
getUniqueId()1439     public long getUniqueId() {
1440         return nGetUniqueId(mNativeRenderNode);
1441     }
1442 
1443     ///////////////////////////////////////////////////////////////////////////
1444     // Animations
1445     ///////////////////////////////////////////////////////////////////////////
1446 
1447     /**
1448      * TODO: Figure out if this can be eliminated/refactored away
1449      *
1450      * For now this interface exists to de-couple RenderNode from anything View-specific in a
1451      * bit of a kludge.
1452      *
1453      * @hide
1454      */
1455     public interface AnimationHost {
1456         /** @hide */
registerAnimatingRenderNode(RenderNode animator)1457         void registerAnimatingRenderNode(RenderNode animator);
1458 
1459         /** @hide */
registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator)1460         void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator);
1461 
1462         /** @hide */
isAttached()1463         boolean isAttached();
1464     }
1465 
1466     /** @hide */
addAnimator(RenderNodeAnimator animator)1467     public void addAnimator(RenderNodeAnimator animator) {
1468         if (!isAttached()) {
1469             throw new IllegalStateException("Cannot start this animator on a detached view!");
1470         }
1471         nAddAnimator(mNativeRenderNode, animator.getNativeAnimator());
1472         mAnimationHost.registerAnimatingRenderNode(this);
1473     }
1474 
1475     /** @hide */
isAttached()1476     public boolean isAttached() {
1477         return mAnimationHost != null && mAnimationHost.isAttached();
1478     }
1479 
1480     /** @hide */
registerVectorDrawableAnimator(NativeVectorDrawableAnimator animatorSet)1481     public void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animatorSet) {
1482         if (!isAttached()) {
1483             throw new IllegalStateException("Cannot start this animator on a detached view!");
1484         }
1485         mAnimationHost.registerVectorDrawableAnimator(animatorSet);
1486     }
1487 
1488     /** @hide */
endAllAnimators()1489     public void endAllAnimators() {
1490         nEndAllAnimators(mNativeRenderNode);
1491     }
1492 
1493     ///////////////////////////////////////////////////////////////////////////
1494     // Regular JNI methods
1495     ///////////////////////////////////////////////////////////////////////////
1496 
nCreate(String name)1497     private static native long nCreate(String name);
1498 
nGetNativeFinalizer()1499     private static native long nGetNativeFinalizer();
1500 
nOutput(long renderNode)1501     private static native void nOutput(long renderNode);
1502 
nGetUsageSize(long renderNode)1503     private static native int nGetUsageSize(long renderNode);
nGetAllocatedSize(long renderNode)1504     private static native int nGetAllocatedSize(long renderNode);
1505 
nRequestPositionUpdates(long renderNode, PositionUpdateListener callback)1506     private static native void nRequestPositionUpdates(long renderNode,
1507             PositionUpdateListener callback);
1508 
1509     // Animations
1510 
nAddAnimator(long renderNode, long animatorPtr)1511     private static native void nAddAnimator(long renderNode, long animatorPtr);
1512 
nEndAllAnimators(long renderNode)1513     private static native void nEndAllAnimators(long renderNode);
1514 
1515 
1516     ///////////////////////////////////////////////////////////////////////////
1517     // @FastNative methods
1518     ///////////////////////////////////////////////////////////////////////////
1519 
1520     @FastNative
nSetDisplayList(long renderNode, long newData)1521     private static native void nSetDisplayList(long renderNode, long newData);
1522 
1523 
1524     ///////////////////////////////////////////////////////////////////////////
1525     // @CriticalNative methods
1526     ///////////////////////////////////////////////////////////////////////////
1527 
1528     @CriticalNative
nIsValid(long renderNode)1529     private static native boolean nIsValid(long renderNode);
1530 
1531     // Matrix
1532 
1533     @CriticalNative
nGetTransformMatrix(long renderNode, long nativeMatrix)1534     private static native void nGetTransformMatrix(long renderNode, long nativeMatrix);
1535 
1536     @CriticalNative
nGetInverseTransformMatrix(long renderNode, long nativeMatrix)1537     private static native void nGetInverseTransformMatrix(long renderNode, long nativeMatrix);
1538 
1539     @CriticalNative
nHasIdentityMatrix(long renderNode)1540     private static native boolean nHasIdentityMatrix(long renderNode);
1541 
1542     // Properties
1543 
1544     @CriticalNative
nOffsetTopAndBottom(long renderNode, int offset)1545     private static native boolean nOffsetTopAndBottom(long renderNode, int offset);
1546 
1547     @CriticalNative
nOffsetLeftAndRight(long renderNode, int offset)1548     private static native boolean nOffsetLeftAndRight(long renderNode, int offset);
1549 
1550     @CriticalNative
nSetLeftTopRightBottom(long renderNode, int left, int top, int right, int bottom)1551     private static native boolean nSetLeftTopRightBottom(long renderNode, int left, int top,
1552             int right, int bottom);
1553 
1554     @CriticalNative
nSetLeft(long renderNode, int left)1555     private static native boolean nSetLeft(long renderNode, int left);
1556 
1557     @CriticalNative
nSetTop(long renderNode, int top)1558     private static native boolean nSetTop(long renderNode, int top);
1559 
1560     @CriticalNative
nSetRight(long renderNode, int right)1561     private static native boolean nSetRight(long renderNode, int right);
1562 
1563     @CriticalNative
nSetBottom(long renderNode, int bottom)1564     private static native boolean nSetBottom(long renderNode, int bottom);
1565 
1566     @CriticalNative
nGetLeft(long renderNode)1567     private static native int nGetLeft(long renderNode);
1568 
1569     @CriticalNative
nGetTop(long renderNode)1570     private static native int nGetTop(long renderNode);
1571 
1572     @CriticalNative
nGetRight(long renderNode)1573     private static native int nGetRight(long renderNode);
1574 
1575     @CriticalNative
nGetBottom(long renderNode)1576     private static native int nGetBottom(long renderNode);
1577 
1578     @CriticalNative
nSetCameraDistance(long renderNode, float distance)1579     private static native boolean nSetCameraDistance(long renderNode, float distance);
1580 
1581     @CriticalNative
nSetPivotY(long renderNode, float pivotY)1582     private static native boolean nSetPivotY(long renderNode, float pivotY);
1583 
1584     @CriticalNative
nSetPivotX(long renderNode, float pivotX)1585     private static native boolean nSetPivotX(long renderNode, float pivotX);
1586 
1587     @CriticalNative
nResetPivot(long renderNode)1588     private static native boolean nResetPivot(long renderNode);
1589 
1590     @CriticalNative
nSetLayerType(long renderNode, int layerType)1591     private static native boolean nSetLayerType(long renderNode, int layerType);
1592 
1593     @CriticalNative
nGetLayerType(long renderNode)1594     private static native int nGetLayerType(long renderNode);
1595 
1596     @CriticalNative
nSetLayerPaint(long renderNode, long paint)1597     private static native boolean nSetLayerPaint(long renderNode, long paint);
1598 
1599     @CriticalNative
nSetClipToBounds(long renderNode, boolean clipToBounds)1600     private static native boolean nSetClipToBounds(long renderNode, boolean clipToBounds);
1601 
1602     @CriticalNative
nGetClipToBounds(long renderNode)1603     private static native boolean nGetClipToBounds(long renderNode);
1604 
1605     @CriticalNative
nSetClipBounds(long renderNode, int left, int top, int right, int bottom)1606     private static native boolean nSetClipBounds(long renderNode, int left, int top,
1607             int right, int bottom);
1608 
1609     @CriticalNative
nSetClipBoundsEmpty(long renderNode)1610     private static native boolean nSetClipBoundsEmpty(long renderNode);
1611 
1612     @CriticalNative
nSetProjectBackwards(long renderNode, boolean shouldProject)1613     private static native boolean nSetProjectBackwards(long renderNode, boolean shouldProject);
1614 
1615     @CriticalNative
nSetProjectionReceiver(long renderNode, boolean shouldRecieve)1616     private static native boolean nSetProjectionReceiver(long renderNode, boolean shouldRecieve);
1617 
1618     @CriticalNative
nSetOutlineRoundRect(long renderNode, int left, int top, int right, int bottom, float radius, float alpha)1619     private static native boolean nSetOutlineRoundRect(long renderNode, int left, int top,
1620             int right, int bottom, float radius, float alpha);
1621 
1622     @CriticalNative
nSetOutlinePath(long renderNode, long nativePath, float alpha)1623     private static native boolean nSetOutlinePath(long renderNode, long nativePath,
1624             float alpha);
1625 
1626     @CriticalNative
nSetOutlineEmpty(long renderNode)1627     private static native boolean nSetOutlineEmpty(long renderNode);
1628 
1629     @CriticalNative
nSetOutlineNone(long renderNode)1630     private static native boolean nSetOutlineNone(long renderNode);
1631 
1632     @CriticalNative
nHasShadow(long renderNode)1633     private static native boolean nHasShadow(long renderNode);
1634 
1635     @CriticalNative
nSetSpotShadowColor(long renderNode, int color)1636     private static native boolean nSetSpotShadowColor(long renderNode, int color);
1637 
1638     @CriticalNative
nSetAmbientShadowColor(long renderNode, int color)1639     private static native boolean nSetAmbientShadowColor(long renderNode, int color);
1640 
1641     @CriticalNative
nGetSpotShadowColor(long renderNode)1642     private static native int nGetSpotShadowColor(long renderNode);
1643 
1644     @CriticalNative
nGetAmbientShadowColor(long renderNode)1645     private static native int nGetAmbientShadowColor(long renderNode);
1646 
1647     @CriticalNative
nSetClipToOutline(long renderNode, boolean clipToOutline)1648     private static native boolean nSetClipToOutline(long renderNode, boolean clipToOutline);
1649 
1650     @CriticalNative
nSetRevealClip(long renderNode, boolean shouldClip, float x, float y, float radius)1651     private static native boolean nSetRevealClip(long renderNode,
1652             boolean shouldClip, float x, float y, float radius);
1653 
1654     @CriticalNative
nSetAlpha(long renderNode, float alpha)1655     private static native boolean nSetAlpha(long renderNode, float alpha);
1656 
1657     @CriticalNative
nSetHasOverlappingRendering(long renderNode, boolean hasOverlappingRendering)1658     private static native boolean nSetHasOverlappingRendering(long renderNode,
1659             boolean hasOverlappingRendering);
1660 
1661     @CriticalNative
nSetUsageHint(long renderNode, int usageHint)1662     private static native void nSetUsageHint(long renderNode, int usageHint);
1663 
1664     @CriticalNative
nSetElevation(long renderNode, float lift)1665     private static native boolean nSetElevation(long renderNode, float lift);
1666 
1667     @CriticalNative
nSetTranslationX(long renderNode, float translationX)1668     private static native boolean nSetTranslationX(long renderNode, float translationX);
1669 
1670     @CriticalNative
nSetTranslationY(long renderNode, float translationY)1671     private static native boolean nSetTranslationY(long renderNode, float translationY);
1672 
1673     @CriticalNative
nSetTranslationZ(long renderNode, float translationZ)1674     private static native boolean nSetTranslationZ(long renderNode, float translationZ);
1675 
1676     @CriticalNative
nSetRotation(long renderNode, float rotation)1677     private static native boolean nSetRotation(long renderNode, float rotation);
1678 
1679     @CriticalNative
nSetRotationX(long renderNode, float rotationX)1680     private static native boolean nSetRotationX(long renderNode, float rotationX);
1681 
1682     @CriticalNative
nSetRotationY(long renderNode, float rotationY)1683     private static native boolean nSetRotationY(long renderNode, float rotationY);
1684 
1685     @CriticalNative
nSetScaleX(long renderNode, float scaleX)1686     private static native boolean nSetScaleX(long renderNode, float scaleX);
1687 
1688     @CriticalNative
nSetScaleY(long renderNode, float scaleY)1689     private static native boolean nSetScaleY(long renderNode, float scaleY);
1690 
1691     @CriticalNative
nSetStaticMatrix(long renderNode, long nativeMatrix)1692     private static native boolean nSetStaticMatrix(long renderNode, long nativeMatrix);
1693 
1694     @CriticalNative
nSetAnimationMatrix(long renderNode, long animationMatrix)1695     private static native boolean nSetAnimationMatrix(long renderNode, long animationMatrix);
1696 
1697     @CriticalNative
nHasOverlappingRendering(long renderNode)1698     private static native boolean nHasOverlappingRendering(long renderNode);
1699 
1700     @CriticalNative
nGetAnimationMatrix(long renderNode, long animationMatrix)1701     private static native boolean nGetAnimationMatrix(long renderNode, long animationMatrix);
1702 
1703     @CriticalNative
nGetClipToOutline(long renderNode)1704     private static native boolean nGetClipToOutline(long renderNode);
1705 
1706     @CriticalNative
nGetAlpha(long renderNode)1707     private static native float nGetAlpha(long renderNode);
1708 
1709     @CriticalNative
nGetCameraDistance(long renderNode)1710     private static native float nGetCameraDistance(long renderNode);
1711 
1712     @CriticalNative
nGetScaleX(long renderNode)1713     private static native float nGetScaleX(long renderNode);
1714 
1715     @CriticalNative
nGetScaleY(long renderNode)1716     private static native float nGetScaleY(long renderNode);
1717 
1718     @CriticalNative
nGetElevation(long renderNode)1719     private static native float nGetElevation(long renderNode);
1720 
1721     @CriticalNative
nGetTranslationX(long renderNode)1722     private static native float nGetTranslationX(long renderNode);
1723 
1724     @CriticalNative
nGetTranslationY(long renderNode)1725     private static native float nGetTranslationY(long renderNode);
1726 
1727     @CriticalNative
nGetTranslationZ(long renderNode)1728     private static native float nGetTranslationZ(long renderNode);
1729 
1730     @CriticalNative
nGetRotation(long renderNode)1731     private static native float nGetRotation(long renderNode);
1732 
1733     @CriticalNative
nGetRotationX(long renderNode)1734     private static native float nGetRotationX(long renderNode);
1735 
1736     @CriticalNative
nGetRotationY(long renderNode)1737     private static native float nGetRotationY(long renderNode);
1738 
1739     @CriticalNative
nIsPivotExplicitlySet(long renderNode)1740     private static native boolean nIsPivotExplicitlySet(long renderNode);
1741 
1742     @CriticalNative
nGetPivotX(long renderNode)1743     private static native float nGetPivotX(long renderNode);
1744 
1745     @CriticalNative
nGetPivotY(long renderNode)1746     private static native float nGetPivotY(long renderNode);
1747 
1748     @CriticalNative
nGetWidth(long renderNode)1749     private static native int nGetWidth(long renderNode);
1750 
1751     @CriticalNative
nGetHeight(long renderNode)1752     private static native int nGetHeight(long renderNode);
1753 
1754     @CriticalNative
nSetAllowForceDark(long renderNode, boolean allowForceDark)1755     private static native boolean nSetAllowForceDark(long renderNode, boolean allowForceDark);
1756 
1757     @CriticalNative
nGetAllowForceDark(long renderNode)1758     private static native boolean nGetAllowForceDark(long renderNode);
1759 
1760     @CriticalNative
nGetUniqueId(long renderNode)1761     private static native long nGetUniqueId(long renderNode);
1762 }
1763