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
17package android.view;
18
19import android.annotation.NonNull;
20import android.annotation.Nullable;
21import android.graphics.Matrix;
22import android.graphics.Outline;
23import android.graphics.Paint;
24import android.graphics.Rect;
25import android.graphics.drawable.AnimatedVectorDrawable;
26
27/**
28 * <p>A display list records a series of graphics related operations and can replay
29 * them later. Display lists are usually built by recording operations on a
30 * {@link DisplayListCanvas}. Replaying the operations from a display list avoids
31 * executing application code on every frame, and is thus much more efficient.</p>
32 *
33 * <p>Display lists are used internally for all views by default, and are not
34 * typically used directly. One reason to consider using a display is a custom
35 * {@link View} implementation that needs to issue a large number of drawing commands.
36 * When the view invalidates, all the drawing commands must be reissued, even if
37 * large portions of the drawing command stream stay the same frame to frame, which
38 * can become a performance bottleneck. To solve this issue, a custom View might split
39 * its content into several display lists. A display list is updated only when its
40 * content, and only its content, needs to be updated.</p>
41 *
42 * <p>A text editor might for instance store each paragraph into its own display list.
43 * Thus when the user inserts or removes characters, only the display list of the
44 * affected paragraph needs to be recorded again.</p>
45 *
46 * <h3>Hardware acceleration</h3>
47 * <p>Display lists can only be replayed using a {@link DisplayListCanvas}. They are not
48 * supported in software. Always make sure that the {@link android.graphics.Canvas}
49 * you are using to render a display list is hardware accelerated using
50 * {@link android.graphics.Canvas#isHardwareAccelerated()}.</p>
51 *
52 * <h3>Creating a display list</h3>
53 * <pre class="prettyprint">
54 *     HardwareRenderer renderer = myView.getHardwareRenderer();
55 *     if (renderer != null) {
56 *         DisplayList displayList = renderer.createDisplayList();
57 *         DisplayListCanvas canvas = displayList.start(width, height);
58 *         try {
59 *             // Draw onto the canvas
60 *             // For instance: canvas.drawBitmap(...);
61 *         } finally {
62 *             displayList.end();
63 *         }
64 *     }
65 * </pre>
66 *
67 * <h3>Rendering a display list on a View</h3>
68 * <pre class="prettyprint">
69 *     protected void onDraw(Canvas canvas) {
70 *         if (canvas.isHardwareAccelerated()) {
71 *             DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
72 *             displayListCanvas.drawDisplayList(mDisplayList);
73 *         }
74 *     }
75 * </pre>
76 *
77 * <h3>Releasing resources</h3>
78 * <p>This step is not mandatory but recommended if you want to release resources
79 * held by a display list as soon as possible.</p>
80 * <pre class="prettyprint">
81 *     // Mark this display list invalid, it cannot be used for drawing anymore,
82 *     // and release resources held by this display list
83 *     displayList.clear();
84 * </pre>
85 *
86 * <h3>Properties</h3>
87 * <p>In addition, a display list offers several properties, such as
88 * {@link #setScaleX(float)} or {@link #setLeft(int)}, that can be used to affect all
89 * the drawing commands recorded within. For instance, these properties can be used
90 * to move around a large number of images without re-issuing all the individual
91 * <code>drawBitmap()</code> calls.</p>
92 *
93 * <pre class="prettyprint">
94 *     private void createDisplayList() {
95 *         mDisplayList = DisplayList.create("MyDisplayList");
96 *         DisplayListCanvas canvas = mDisplayList.start(width, height);
97 *         try {
98 *             for (Bitmap b : mBitmaps) {
99 *                 canvas.drawBitmap(b, 0.0f, 0.0f, null);
100 *                 canvas.translate(0.0f, b.getHeight());
101 *             }
102 *         } finally {
103 *             displayList.end();
104 *         }
105 *     }
106 *
107 *     protected void onDraw(Canvas canvas) {
108 *         if (canvas.isHardwareAccelerated()) {
109 *             DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
110 *             displayListCanvas.drawDisplayList(mDisplayList);
111 *         }
112 *     }
113 *
114 *     private void moveContentBy(int x) {
115 *          // This will move all the bitmaps recorded inside the display list
116 *          // by x pixels to the right and redraw this view. All the commands
117 *          // recorded in createDisplayList() won't be re-issued, only onDraw()
118 *          // will be invoked and will execute very quickly
119 *          mDisplayList.offsetLeftAndRight(x);
120 *          invalidate();
121 *     }
122 * </pre>
123 *
124 * <h3>Threading</h3>
125 * <p>Display lists must be created on and manipulated from the UI thread only.</p>
126 *
127 * @hide
128 */
129public class RenderNode {
130
131    private boolean mValid;
132    // Do not access directly unless you are ThreadedRenderer
133    final long mNativeRenderNode;
134    private final View mOwningView;
135
136    private RenderNode(String name, View owningView) {
137        mNativeRenderNode = nCreate(name);
138        mOwningView = owningView;
139        if (mOwningView instanceof SurfaceView) {
140            nRequestPositionUpdates(mNativeRenderNode, (SurfaceView) mOwningView);
141        }
142    }
143
144    /**
145     * @see RenderNode#adopt(long)
146     */
147    private RenderNode(long nativePtr) {
148        mNativeRenderNode = nativePtr;
149        mOwningView = null;
150    }
151
152    /**
153     * Creates a new RenderNode that can be used to record batches of
154     * drawing operations, and store / apply render properties when drawn.
155     *
156     * @param name The name of the RenderNode, used for debugging purpose. May be null.
157     *
158     * @return A new RenderNode.
159     */
160    public static RenderNode create(String name, @Nullable View owningView) {
161        return new RenderNode(name, owningView);
162    }
163
164    /**
165     * Adopts an existing native render node.
166     *
167     * Note: This will *NOT* incRef() on the native object, however it will
168     * decRef() when it is destroyed. The caller should have already incRef'd it
169     */
170    public static RenderNode adopt(long nativePtr) {
171        return new RenderNode(nativePtr);
172    }
173
174
175    /**
176     * Starts recording a display list for the render node. All
177     * operations performed on the returned canvas are recorded and
178     * stored in this display list.
179     *
180     * Calling this method will mark the render node invalid until
181     * {@link #end(DisplayListCanvas)} is called.
182     * Only valid render nodes can be replayed.
183     *
184     * @param width The width of the recording viewport
185     * @param height The height of the recording viewport
186     *
187     * @return A canvas to record drawing operations.
188     *
189     * @see #end(DisplayListCanvas)
190     * @see #isValid()
191     */
192    public DisplayListCanvas start(int width, int height) {
193        return DisplayListCanvas.obtain(this, width, height);
194    }
195
196    /**
197     * Ends the recording for this display list. A display list cannot be
198     * replayed if recording is not finished. Calling this method marks
199     * the display list valid and {@link #isValid()} will return true.
200     *
201     * @see #start(int, int)
202     * @see #isValid()
203     */
204    public void end(DisplayListCanvas canvas) {
205        long displayList = canvas.finishRecording();
206        nSetDisplayList(mNativeRenderNode, displayList);
207        canvas.recycle();
208        mValid = true;
209    }
210
211    /**
212     * Reset native resources. This is called when cleaning up the state of display lists
213     * during destruction of hardware resources, to ensure that we do not hold onto
214     * obsolete resources after related resources are gone.
215     */
216    public void discardDisplayList() {
217        if (!mValid) return;
218
219        nSetDisplayList(mNativeRenderNode, 0);
220        mValid = false;
221    }
222
223    /**
224     * Returns whether the RenderNode's display list content is currently usable.
225     * If this returns false, the display list should be re-recorded prior to replaying it.
226     *
227     * @return boolean true if the display list is able to be replayed, false otherwise.
228     */
229    public boolean isValid() { return mValid; }
230
231    long getNativeDisplayList() {
232        if (!mValid) {
233            throw new IllegalStateException("The display list is not valid.");
234        }
235        return mNativeRenderNode;
236    }
237
238    ///////////////////////////////////////////////////////////////////////////
239    // Matrix manipulation
240    ///////////////////////////////////////////////////////////////////////////
241
242    public boolean hasIdentityMatrix() {
243        return nHasIdentityMatrix(mNativeRenderNode);
244    }
245
246    public void getMatrix(@NonNull Matrix outMatrix) {
247        nGetTransformMatrix(mNativeRenderNode, outMatrix.native_instance);
248    }
249
250    public void getInverseMatrix(@NonNull Matrix outMatrix) {
251        nGetInverseTransformMatrix(mNativeRenderNode, outMatrix.native_instance);
252    }
253
254    ///////////////////////////////////////////////////////////////////////////
255    // RenderProperty Setters
256    ///////////////////////////////////////////////////////////////////////////
257
258    public boolean setLayerType(int layerType) {
259        return nSetLayerType(mNativeRenderNode, layerType);
260    }
261
262    public boolean setLayerPaint(@Nullable Paint paint) {
263        return nSetLayerPaint(mNativeRenderNode, paint != null ? paint.getNativeInstance() : 0);
264    }
265
266    public boolean setClipBounds(@Nullable Rect rect) {
267        if (rect == null) {
268            return nSetClipBoundsEmpty(mNativeRenderNode);
269        } else {
270            return nSetClipBounds(mNativeRenderNode, rect.left, rect.top, rect.right, rect.bottom);
271        }
272    }
273
274    /**
275     * Set whether the Render node should clip itself to its bounds. This property is controlled by
276     * the view's parent.
277     *
278     * @param clipToBounds true if the display list should clip to its bounds
279     */
280    public boolean setClipToBounds(boolean clipToBounds) {
281        return nSetClipToBounds(mNativeRenderNode, clipToBounds);
282    }
283
284    /**
285     * Sets whether the display list should be drawn immediately after the
286     * closest ancestor display list containing a projection receiver.
287     *
288     * @param shouldProject true if the display list should be projected onto a
289     *            containing volume.
290     */
291    public boolean setProjectBackwards(boolean shouldProject) {
292        return nSetProjectBackwards(mNativeRenderNode, shouldProject);
293    }
294
295    /**
296     * Sets whether the display list is a projection receiver - that its parent
297     * DisplayList should draw any descendent DisplayLists with
298     * ProjectBackwards=true directly on top of it. Default value is false.
299     */
300    public boolean setProjectionReceiver(boolean shouldRecieve) {
301        return nSetProjectionReceiver(mNativeRenderNode, shouldRecieve);
302    }
303
304    /**
305     * Sets the outline, defining the shape that casts a shadow, and the path to
306     * be clipped if setClipToOutline is set.
307     *
308     * Deep copies the data into native to simplify reference ownership.
309     */
310    public boolean setOutline(@Nullable Outline outline) {
311        if (outline == null) {
312            return nSetOutlineNone(mNativeRenderNode);
313        }
314
315        switch(outline.mMode) {
316            case Outline.MODE_EMPTY:
317                return nSetOutlineEmpty(mNativeRenderNode);
318            case Outline.MODE_ROUND_RECT:
319                return nSetOutlineRoundRect(mNativeRenderNode, outline.mRect.left, outline.mRect.top,
320                        outline.mRect.right, outline.mRect.bottom, outline.mRadius, outline.mAlpha);
321            case Outline.MODE_CONVEX_PATH:
322                return nSetOutlineConvexPath(mNativeRenderNode, outline.mPath.mNativePath,
323                        outline.mAlpha);
324        }
325
326        throw new IllegalArgumentException("Unrecognized outline?");
327    }
328
329    public boolean hasShadow() {
330        return nHasShadow(mNativeRenderNode);
331    }
332
333    /**
334     * Enables or disables clipping to the outline.
335     *
336     * @param clipToOutline true if clipping to the outline.
337     */
338    public boolean setClipToOutline(boolean clipToOutline) {
339        return nSetClipToOutline(mNativeRenderNode, clipToOutline);
340    }
341
342    public boolean getClipToOutline() {
343        return nGetClipToOutline(mNativeRenderNode);
344    }
345
346    /**
347     * Controls the RenderNode's circular reveal clip.
348     */
349    public boolean setRevealClip(boolean shouldClip,
350            float x, float y, float radius) {
351        return nSetRevealClip(mNativeRenderNode, shouldClip, x, y, radius);
352    }
353
354    /**
355     * Set the static matrix on the display list. The specified matrix is combined with other
356     * transforms (such as {@link #setScaleX(float)}, {@link #setRotation(float)}, etc.)
357     *
358     * @param matrix A transform matrix to apply to this display list
359     */
360    public boolean setStaticMatrix(Matrix matrix) {
361        return nSetStaticMatrix(mNativeRenderNode, matrix.native_instance);
362    }
363
364    /**
365     * Set the Animation matrix on the display list. This matrix exists if an Animation is
366     * currently playing on a View, and is set on the display list during at draw() time. When
367     * the Animation finishes, the matrix should be cleared by sending <code>null</code>
368     * for the matrix parameter.
369     *
370     * @param matrix The matrix, null indicates that the matrix should be cleared.
371     */
372    public boolean setAnimationMatrix(Matrix matrix) {
373        return nSetAnimationMatrix(mNativeRenderNode,
374                (matrix != null) ? matrix.native_instance : 0);
375    }
376
377    /**
378     * Sets the translucency level for the display list.
379     *
380     * @param alpha The translucency of the display list, must be a value between 0.0f and 1.0f
381     *
382     * @see View#setAlpha(float)
383     * @see #getAlpha()
384     */
385    public boolean setAlpha(float alpha) {
386        return nSetAlpha(mNativeRenderNode, alpha);
387    }
388
389    /**
390     * Returns the translucency level of this display list.
391     *
392     * @return A value between 0.0f and 1.0f
393     *
394     * @see #setAlpha(float)
395     */
396    public float getAlpha() {
397        return nGetAlpha(mNativeRenderNode);
398    }
399
400    /**
401     * Sets whether the display list renders content which overlaps. Non-overlapping rendering
402     * can use a fast path for alpha that avoids rendering to an offscreen buffer. By default
403     * display lists consider they do not have overlapping content.
404     *
405     * @param hasOverlappingRendering False if the content is guaranteed to be non-overlapping,
406     *                                true otherwise.
407     *
408     * @see android.view.View#hasOverlappingRendering()
409     * @see #hasOverlappingRendering()
410     */
411    public boolean setHasOverlappingRendering(boolean hasOverlappingRendering) {
412        return nSetHasOverlappingRendering(mNativeRenderNode, hasOverlappingRendering);
413    }
414
415    /**
416     * Indicates whether the content of this display list overlaps.
417     *
418     * @return True if this display list renders content which overlaps, false otherwise.
419     *
420     * @see #setHasOverlappingRendering(boolean)
421     */
422    public boolean hasOverlappingRendering() {
423        //noinspection SimplifiableIfStatement
424        return nHasOverlappingRendering(mNativeRenderNode);
425    }
426
427    public boolean setElevation(float lift) {
428        return nSetElevation(mNativeRenderNode, lift);
429    }
430
431    public float getElevation() {
432        return nGetElevation(mNativeRenderNode);
433    }
434
435    /**
436     * Sets the translation value for the display list on the X axis.
437     *
438     * @param translationX The X axis translation value of the display list, in pixels
439     *
440     * @see View#setTranslationX(float)
441     * @see #getTranslationX()
442     */
443    public boolean setTranslationX(float translationX) {
444        return nSetTranslationX(mNativeRenderNode, translationX);
445    }
446
447    /**
448     * Returns the translation value for this display list on the X axis, in pixels.
449     *
450     * @see #setTranslationX(float)
451     */
452    public float getTranslationX() {
453        return nGetTranslationX(mNativeRenderNode);
454    }
455
456    /**
457     * Sets the translation value for the display list on the Y axis.
458     *
459     * @param translationY The Y axis translation value of the display list, in pixels
460     *
461     * @see View#setTranslationY(float)
462     * @see #getTranslationY()
463     */
464    public boolean setTranslationY(float translationY) {
465        return nSetTranslationY(mNativeRenderNode, translationY);
466    }
467
468    /**
469     * Returns the translation value for this display list on the Y axis, in pixels.
470     *
471     * @see #setTranslationY(float)
472     */
473    public float getTranslationY() {
474        return nGetTranslationY(mNativeRenderNode);
475    }
476
477    /**
478     * Sets the translation value for the display list on the Z axis.
479     *
480     * @see View#setTranslationZ(float)
481     * @see #getTranslationZ()
482     */
483    public boolean setTranslationZ(float translationZ) {
484        return nSetTranslationZ(mNativeRenderNode, translationZ);
485    }
486
487    /**
488     * Returns the translation value for this display list on the Z axis.
489     *
490     * @see #setTranslationZ(float)
491     */
492    public float getTranslationZ() {
493        return nGetTranslationZ(mNativeRenderNode);
494    }
495
496    /**
497     * Sets the rotation value for the display list around the Z axis.
498     *
499     * @param rotation The rotation value of the display list, in degrees
500     *
501     * @see View#setRotation(float)
502     * @see #getRotation()
503     */
504    public boolean setRotation(float rotation) {
505        return nSetRotation(mNativeRenderNode, rotation);
506    }
507
508    /**
509     * Returns the rotation value for this display list around the Z axis, in degrees.
510     *
511     * @see #setRotation(float)
512     */
513    public float getRotation() {
514        return nGetRotation(mNativeRenderNode);
515    }
516
517    /**
518     * Sets the rotation value for the display list around the X axis.
519     *
520     * @param rotationX The rotation value of the display list, in degrees
521     *
522     * @see View#setRotationX(float)
523     * @see #getRotationX()
524     */
525    public boolean setRotationX(float rotationX) {
526        return nSetRotationX(mNativeRenderNode, rotationX);
527    }
528
529    /**
530     * Returns the rotation value for this display list around the X axis, in degrees.
531     *
532     * @see #setRotationX(float)
533     */
534    public float getRotationX() {
535        return nGetRotationX(mNativeRenderNode);
536    }
537
538    /**
539     * Sets the rotation value for the display list around the Y axis.
540     *
541     * @param rotationY The rotation value of the display list, in degrees
542     *
543     * @see View#setRotationY(float)
544     * @see #getRotationY()
545     */
546    public boolean setRotationY(float rotationY) {
547        return nSetRotationY(mNativeRenderNode, rotationY);
548    }
549
550    /**
551     * Returns the rotation value for this display list around the Y axis, in degrees.
552     *
553     * @see #setRotationY(float)
554     */
555    public float getRotationY() {
556        return nGetRotationY(mNativeRenderNode);
557    }
558
559    /**
560     * Sets the scale value for the display list on the X axis.
561     *
562     * @param scaleX The scale value of the display list
563     *
564     * @see View#setScaleX(float)
565     * @see #getScaleX()
566     */
567    public boolean setScaleX(float scaleX) {
568        return nSetScaleX(mNativeRenderNode, scaleX);
569    }
570
571    /**
572     * Returns the scale value for this display list on the X axis.
573     *
574     * @see #setScaleX(float)
575     */
576    public float getScaleX() {
577        return nGetScaleX(mNativeRenderNode);
578    }
579
580    /**
581     * Sets the scale value for the display list on the Y axis.
582     *
583     * @param scaleY The scale value of the display list
584     *
585     * @see View#setScaleY(float)
586     * @see #getScaleY()
587     */
588    public boolean setScaleY(float scaleY) {
589        return nSetScaleY(mNativeRenderNode, scaleY);
590    }
591
592    /**
593     * Returns the scale value for this display list on the Y axis.
594     *
595     * @see #setScaleY(float)
596     */
597    public float getScaleY() {
598        return nGetScaleY(mNativeRenderNode);
599    }
600
601    /**
602     * Sets the pivot value for the display list on the X axis
603     *
604     * @param pivotX The pivot value of the display list on the X axis, in pixels
605     *
606     * @see View#setPivotX(float)
607     * @see #getPivotX()
608     */
609    public boolean setPivotX(float pivotX) {
610        return nSetPivotX(mNativeRenderNode, pivotX);
611    }
612
613    /**
614     * Returns the pivot value for this display list on the X axis, in pixels.
615     *
616     * @see #setPivotX(float)
617     */
618    public float getPivotX() {
619        return nGetPivotX(mNativeRenderNode);
620    }
621
622    /**
623     * Sets the pivot value for the display list on the Y axis
624     *
625     * @param pivotY The pivot value of the display list on the Y axis, in pixels
626     *
627     * @see View#setPivotY(float)
628     * @see #getPivotY()
629     */
630    public boolean setPivotY(float pivotY) {
631        return nSetPivotY(mNativeRenderNode, pivotY);
632    }
633
634    /**
635     * Returns the pivot value for this display list on the Y axis, in pixels.
636     *
637     * @see #setPivotY(float)
638     */
639    public float getPivotY() {
640        return nGetPivotY(mNativeRenderNode);
641    }
642
643    public boolean isPivotExplicitlySet() {
644        return nIsPivotExplicitlySet(mNativeRenderNode);
645    }
646
647    /**
648     * Sets the camera distance for the display list. Refer to
649     * {@link View#setCameraDistance(float)} for more information on how to
650     * use this property.
651     *
652     * @param distance The distance in Z of the camera of the display list
653     *
654     * @see View#setCameraDistance(float)
655     * @see #getCameraDistance()
656     */
657    public boolean setCameraDistance(float distance) {
658        return nSetCameraDistance(mNativeRenderNode, distance);
659    }
660
661    /**
662     * Returns the distance in Z of the camera of the display list.
663     *
664     * @see #setCameraDistance(float)
665     */
666    public float getCameraDistance() {
667        return nGetCameraDistance(mNativeRenderNode);
668    }
669
670    /**
671     * Sets the left position for the display list.
672     *
673     * @param left The left position, in pixels, of the display list
674     *
675     * @see View#setLeft(int)
676     */
677    public boolean setLeft(int left) {
678        return nSetLeft(mNativeRenderNode, left);
679    }
680
681    /**
682     * Sets the top position for the display list.
683     *
684     * @param top The top position, in pixels, of the display list
685     *
686     * @see View#setTop(int)
687     */
688    public boolean setTop(int top) {
689        return nSetTop(mNativeRenderNode, top);
690    }
691
692    /**
693     * Sets the right position for the display list.
694     *
695     * @param right The right position, in pixels, of the display list
696     *
697     * @see View#setRight(int)
698     */
699    public boolean setRight(int right) {
700        return nSetRight(mNativeRenderNode, right);
701    }
702
703    /**
704     * Sets the bottom position for the display list.
705     *
706     * @param bottom The bottom position, in pixels, of the display list
707     *
708     * @see View#setBottom(int)
709     */
710    public boolean setBottom(int bottom) {
711        return nSetBottom(mNativeRenderNode, bottom);
712    }
713
714    /**
715     * Sets the left and top positions for the display list
716     *
717     * @param left The left position of the display list, in pixels
718     * @param top The top position of the display list, in pixels
719     * @param right The right position of the display list, in pixels
720     * @param bottom The bottom position of the display list, in pixels
721     *
722     * @see View#setLeft(int)
723     * @see View#setTop(int)
724     * @see View#setRight(int)
725     * @see View#setBottom(int)
726     */
727    public boolean setLeftTopRightBottom(int left, int top, int right, int bottom) {
728        return nSetLeftTopRightBottom(mNativeRenderNode, left, top, right, bottom);
729    }
730
731    /**
732     * Offsets the left and right positions for the display list
733     *
734     * @param offset The amount that the left and right positions of the display
735     *               list are offset, in pixels
736     *
737     * @see View#offsetLeftAndRight(int)
738     */
739    public boolean offsetLeftAndRight(int offset) {
740        return nOffsetLeftAndRight(mNativeRenderNode, offset);
741    }
742
743    /**
744     * Offsets the top and bottom values for the display list
745     *
746     * @param offset The amount that the top and bottom positions of the display
747     *               list are offset, in pixels
748     *
749     * @see View#offsetTopAndBottom(int)
750     */
751    public boolean offsetTopAndBottom(int offset) {
752        return nOffsetTopAndBottom(mNativeRenderNode, offset);
753    }
754
755    /**
756     * Outputs the display list to the log. This method exists for use by
757     * tools to output display lists for selected nodes to the log.
758     */
759    public void output() {
760        nOutput(mNativeRenderNode);
761    }
762
763    /**
764     * Gets the size of the DisplayList for debug purposes.
765     */
766    public int getDebugSize() {
767        return nGetDebugSize(mNativeRenderNode);
768    }
769
770    /**
771     * Called by native when the passed displaylist is removed from the draw tree
772     */
773    void onRenderNodeDetached() {
774        discardDisplayList();
775        if (mOwningView != null) {
776            mOwningView.onRenderNodeDetached(this);
777        }
778    }
779
780    ///////////////////////////////////////////////////////////////////////////
781    // Animations
782    ///////////////////////////////////////////////////////////////////////////
783
784    public void addAnimator(RenderNodeAnimator animator) {
785        if (mOwningView == null || mOwningView.mAttachInfo == null) {
786            throw new IllegalStateException("Cannot start this animator on a detached view!");
787        }
788        nAddAnimator(mNativeRenderNode, animator.getNativeAnimator());
789        mOwningView.mAttachInfo.mViewRootImpl.registerAnimatingRenderNode(this);
790    }
791
792    public boolean isAttached() {
793        return mOwningView != null && mOwningView.mAttachInfo != null;
794    }
795
796    public void addAnimator(AnimatedVectorDrawable.VectorDrawableAnimatorRT animatorSet) {
797        if (mOwningView == null || mOwningView.mAttachInfo == null) {
798            throw new IllegalStateException("Cannot start this animator on a detached view!");
799        }
800        nAddAnimator(mNativeRenderNode, animatorSet.getAnimatorNativePtr());
801        mOwningView.mAttachInfo.mViewRootImpl.registerAnimatingRenderNode(this);
802    }
803
804    public void endAllAnimators() {
805        nEndAllAnimators(mNativeRenderNode);
806    }
807
808    ///////////////////////////////////////////////////////////////////////////
809    // Native methods
810    ///////////////////////////////////////////////////////////////////////////
811
812    // Intentionally not static because it acquires a reference to 'this'
813    private native long nCreate(String name);
814
815    private static native void nDestroyRenderNode(long renderNode);
816    private static native void nSetDisplayList(long renderNode, long newData);
817
818    // Matrix
819
820    private static native void nGetTransformMatrix(long renderNode, long nativeMatrix);
821    private static native void nGetInverseTransformMatrix(long renderNode, long nativeMatrix);
822    private static native boolean nHasIdentityMatrix(long renderNode);
823
824    // Properties
825
826    private static native boolean nOffsetTopAndBottom(long renderNode, int offset);
827    private static native boolean nOffsetLeftAndRight(long renderNode, int offset);
828    private static native boolean nSetLeftTopRightBottom(long renderNode, int left, int top,
829            int right, int bottom);
830    private static native boolean nSetBottom(long renderNode, int bottom);
831    private static native boolean nSetRight(long renderNode, int right);
832    private static native boolean nSetTop(long renderNode, int top);
833    private static native boolean nSetLeft(long renderNode, int left);
834    private static native boolean nSetCameraDistance(long renderNode, float distance);
835    private static native boolean nSetPivotY(long renderNode, float pivotY);
836    private static native boolean nSetPivotX(long renderNode, float pivotX);
837    private static native boolean nSetLayerType(long renderNode, int layerType);
838    private static native boolean nSetLayerPaint(long renderNode, long paint);
839    private static native boolean nSetClipToBounds(long renderNode, boolean clipToBounds);
840    private static native boolean nSetClipBounds(long renderNode, int left, int top,
841            int right, int bottom);
842    private static native boolean nSetClipBoundsEmpty(long renderNode);
843    private static native boolean nSetProjectBackwards(long renderNode, boolean shouldProject);
844    private static native boolean nSetProjectionReceiver(long renderNode, boolean shouldRecieve);
845    private static native boolean nSetOutlineRoundRect(long renderNode, int left, int top,
846            int right, int bottom, float radius, float alpha);
847    private static native boolean nSetOutlineConvexPath(long renderNode, long nativePath,
848            float alpha);
849    private static native boolean nSetOutlineEmpty(long renderNode);
850    private static native boolean nSetOutlineNone(long renderNode);
851    private static native boolean nHasShadow(long renderNode);
852    private static native boolean nSetClipToOutline(long renderNode, boolean clipToOutline);
853    private static native boolean nSetRevealClip(long renderNode,
854            boolean shouldClip, float x, float y, float radius);
855    private static native boolean nSetAlpha(long renderNode, float alpha);
856    private static native boolean nSetHasOverlappingRendering(long renderNode,
857            boolean hasOverlappingRendering);
858    private static native boolean nSetElevation(long renderNode, float lift);
859    private static native boolean nSetTranslationX(long renderNode, float translationX);
860    private static native boolean nSetTranslationY(long renderNode, float translationY);
861    private static native boolean nSetTranslationZ(long renderNode, float translationZ);
862    private static native boolean nSetRotation(long renderNode, float rotation);
863    private static native boolean nSetRotationX(long renderNode, float rotationX);
864    private static native boolean nSetRotationY(long renderNode, float rotationY);
865    private static native boolean nSetScaleX(long renderNode, float scaleX);
866    private static native boolean nSetScaleY(long renderNode, float scaleY);
867    private static native boolean nSetStaticMatrix(long renderNode, long nativeMatrix);
868    private static native boolean nSetAnimationMatrix(long renderNode, long animationMatrix);
869
870    private static native boolean nHasOverlappingRendering(long renderNode);
871    private static native boolean nGetClipToOutline(long renderNode);
872    private static native float nGetAlpha(long renderNode);
873    private static native float nGetCameraDistance(long renderNode);
874    private static native float nGetScaleX(long renderNode);
875    private static native float nGetScaleY(long renderNode);
876    private static native float nGetElevation(long renderNode);
877    private static native float nGetTranslationX(long renderNode);
878    private static native float nGetTranslationY(long renderNode);
879    private static native float nGetTranslationZ(long renderNode);
880    private static native float nGetRotation(long renderNode);
881    private static native float nGetRotationX(long renderNode);
882    private static native float nGetRotationY(long renderNode);
883    private static native boolean nIsPivotExplicitlySet(long renderNode);
884    private static native float nGetPivotX(long renderNode);
885    private static native float nGetPivotY(long renderNode);
886    private static native void nOutput(long renderNode);
887    private static native int nGetDebugSize(long renderNode);
888
889    private static native void nRequestPositionUpdates(long renderNode, SurfaceView callback);
890
891    ///////////////////////////////////////////////////////////////////////////
892    // Animations
893    ///////////////////////////////////////////////////////////////////////////
894
895    private static native void nAddAnimator(long renderNode, long animatorPtr);
896    private static native void nEndAllAnimators(long renderNode);
897
898    ///////////////////////////////////////////////////////////////////////////
899    // Finalization
900    ///////////////////////////////////////////////////////////////////////////
901
902    @Override
903    protected void finalize() throws Throwable {
904        try {
905            nDestroyRenderNode(mNativeRenderNode);
906        } finally {
907            super.finalize();
908        }
909    }
910}
911