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