1/* 2 * Copyright (C) 2007 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 dalvik.system.CloseGuard; 20 21import android.content.res.CompatibilityInfo.Translator; 22import android.graphics.Bitmap; 23import android.graphics.Canvas; 24import android.graphics.Matrix; 25import android.graphics.Rect; 26import android.graphics.Region; 27import android.graphics.SurfaceTexture; 28import android.os.IBinder; 29import android.os.Parcelable; 30import android.os.Parcel; 31import android.os.SystemProperties; 32import android.util.Log; 33 34/** 35 * Handle onto a raw buffer that is being managed by the screen compositor. 36 */ 37public class Surface implements Parcelable { 38 private static final String TAG = "Surface"; 39 40 private static final boolean HEADLESS = "1".equals( 41 SystemProperties.get("ro.config.headless", "0")); 42 43 public static final Parcelable.Creator<Surface> CREATOR = 44 new Parcelable.Creator<Surface>() { 45 public Surface createFromParcel(Parcel source) { 46 try { 47 Surface s = new Surface(); 48 s.readFromParcel(source); 49 return s; 50 } catch (Exception e) { 51 Log.e(TAG, "Exception creating surface from parcel", e); 52 return null; 53 } 54 } 55 56 public Surface[] newArray(int size) { 57 return new Surface[size]; 58 } 59 }; 60 61 /** 62 * Rotation constant: 0 degree rotation (natural orientation) 63 */ 64 public static final int ROTATION_0 = 0; 65 66 /** 67 * Rotation constant: 90 degree rotation. 68 */ 69 public static final int ROTATION_90 = 1; 70 71 /** 72 * Rotation constant: 180 degree rotation. 73 */ 74 public static final int ROTATION_180 = 2; 75 76 /** 77 * Rotation constant: 270 degree rotation. 78 */ 79 public static final int ROTATION_270 = 3; 80 81 /* built-in physical display ids (keep in sync with ISurfaceComposer.h) 82 * these are different from the logical display ids used elsewhere in the framework */ 83 84 /** 85 * Built-in physical display id: Main display. 86 * Use only with {@link #getBuiltInDisplay()}. 87 * @hide 88 */ 89 public static final int BUILT_IN_DISPLAY_ID_MAIN = 0; 90 91 /** 92 * Built-in physical display id: Attached HDMI display. 93 * Use only with {@link #getBuiltInDisplay()}. 94 * @hide 95 */ 96 public static final int BUILT_IN_DISPLAY_ID_HDMI = 1; 97 98 /* flags used in constructor (keep in sync with ISurfaceComposerClient.h) */ 99 100 /** 101 * Surface creation flag: Surface is created hidden 102 * @hide */ 103 public static final int HIDDEN = 0x00000004; 104 105 /** 106 * Surface creation flag: The surface contains secure content, special 107 * measures will be taken to disallow the surface's content to be copied 108 * from another process. In particular, screenshots and VNC servers will 109 * be disabled, but other measures can take place, for instance the 110 * surface might not be hardware accelerated. 111 * @hide 112 */ 113 public static final int SECURE = 0x00000080; 114 115 /** 116 * Surface creation flag: Creates a surface where color components are interpreted 117 * as "non pre-multiplied" by their alpha channel. Of course this flag is 118 * meaningless for surfaces without an alpha channel. By default 119 * surfaces are pre-multiplied, which means that each color component is 120 * already multiplied by its alpha value. In this case the blending 121 * equation used is: 122 * 123 * DEST = SRC + DEST * (1-SRC_ALPHA) 124 * 125 * By contrast, non pre-multiplied surfaces use the following equation: 126 * 127 * DEST = SRC * SRC_ALPHA * DEST * (1-SRC_ALPHA) 128 * 129 * pre-multiplied surfaces must always be used if transparent pixels are 130 * composited on top of each-other into the surface. A pre-multiplied 131 * surface can never lower the value of the alpha component of a given 132 * pixel. 133 * 134 * In some rare situations, a non pre-multiplied surface is preferable. 135 * @hide 136 */ 137 public static final int NON_PREMULTIPLIED = 0x00000100; 138 139 /** 140 * Surface creation flag: Indicates that the surface must be considered opaque, 141 * even if its pixel format is set to translucent. This can be useful if an 142 * application needs full RGBA 8888 support for instance but will 143 * still draw every pixel opaque. 144 * @hide 145 */ 146 public static final int OPAQUE = 0x00000400; 147 148 /** 149 * Surface creation flag: Application requires a hardware-protected path to an 150 * external display sink. If a hardware-protected path is not available, 151 * then this surface will not be displayed on the external sink. 152 * @hide 153 */ 154 public static final int PROTECTED_APP = 0x00000800; 155 156 // 0x1000 is reserved for an independent DRM protected flag in framework 157 158 /** 159 * Surface creation flag: Creates a normal surface. 160 * This is the default. 161 * @hide 162 */ 163 public static final int FX_SURFACE_NORMAL = 0x00000000; 164 165 /** 166 * Surface creation flag: Creates a Blur surface. 167 * Everything behind this surface is blurred by some amount. 168 * The quality and refresh speed of the blur effect is not settable or guaranteed. 169 * It is an error to lock a Blur surface, since it doesn't have a backing store. 170 * @hide 171 * @deprecated 172 */ 173 @Deprecated 174 public static final int FX_SURFACE_BLUR = 0x00010000; 175 176 /** 177 * Surface creation flag: Creates a Dim surface. 178 * Everything behind this surface is dimmed by the amount specified 179 * in {@link #setAlpha}. It is an error to lock a Dim surface, since it 180 * doesn't have a backing store. 181 * @hide 182 */ 183 public static final int FX_SURFACE_DIM = 0x00020000; 184 185 /** 186 * @hide 187 */ 188 public static final int FX_SURFACE_SCREENSHOT = 0x00030000; 189 190 /** 191 * Mask used for FX values above. 192 * @hide 193 */ 194 public static final int FX_SURFACE_MASK = 0x000F0000; 195 196 /* flags used with setFlags() (keep in sync with ISurfaceComposer.h) */ 197 198 /** 199 * Surface flag: Hide the surface. 200 * Equivalent to calling hide(). 201 * @hide 202 */ 203 public static final int SURFACE_HIDDEN = 0x01; 204 205 206 private final CloseGuard mCloseGuard = CloseGuard.get(); 207 private String mName; 208 209 // Note: These fields are accessed by native code. 210 // The mSurfaceControl will only be present for Surfaces used by the window 211 // server or system processes. When this class is parceled we defer to the 212 // mSurfaceControl to do the parceling. Otherwise we parcel the 213 // mNativeSurface. 214 private int mNativeSurface; // Surface* 215 private int mNativeSurfaceControl; // SurfaceControl* 216 private int mGenerationId; // incremented each time mNativeSurface changes 217 private final Canvas mCanvas = new CompatibleCanvas(); 218 private int mCanvasSaveCount; // Canvas save count at time of lockCanvas() 219 220 // The Translator for density compatibility mode. This is used for scaling 221 // the canvas to perform the appropriate density transformation. 222 private Translator mCompatibilityTranslator; 223 224 // A matrix to scale the matrix set by application. This is set to null for 225 // non compatibility mode. 226 private Matrix mCompatibleMatrix; 227 228 private int mWidth; 229 private int mHeight; 230 231 private native void nativeCreate(SurfaceSession session, String name, 232 int w, int h, int format, int flags) 233 throws OutOfResourcesException; 234 private native void nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture) 235 throws OutOfResourcesException; 236 private native void nativeRelease(); 237 private native void nativeDestroy(); 238 239 private native boolean nativeIsValid(); 240 private native int nativeGetIdentity(); 241 private native boolean nativeIsConsumerRunningBehind(); 242 243 private native Canvas nativeLockCanvas(Rect dirty); 244 private native void nativeUnlockCanvasAndPost(Canvas canvas); 245 246 private static native Bitmap nativeScreenshot(IBinder displayToken, 247 int width, int height, int minLayer, int maxLayer, boolean allLayers); 248 249 private static native void nativeOpenTransaction(); 250 private static native void nativeCloseTransaction(); 251 private static native void nativeSetAnimationTransaction(); 252 253 private native void nativeSetLayer(int zorder); 254 private native void nativeSetPosition(float x, float y); 255 private native void nativeSetSize(int w, int h); 256 private native void nativeSetTransparentRegionHint(Region region); 257 private native void nativeSetAlpha(float alpha); 258 private native void nativeSetMatrix(float dsdx, float dtdx, float dsdy, float dtdy); 259 private native void nativeSetFlags(int flags, int mask); 260 private native void nativeSetWindowCrop(Rect crop); 261 private native void nativeSetLayerStack(int layerStack); 262 263 private static native IBinder nativeGetBuiltInDisplay(int physicalDisplayId); 264 private static native IBinder nativeCreateDisplay(String name, boolean secure); 265 private static native void nativeSetDisplaySurface( 266 IBinder displayToken, Surface surface); 267 private static native void nativeSetDisplayLayerStack( 268 IBinder displayToken, int layerStack); 269 private static native void nativeSetDisplayProjection( 270 IBinder displayToken, int orientation, Rect layerStackRect, Rect displayRect); 271 private static native boolean nativeGetDisplayInfo( 272 IBinder displayToken, PhysicalDisplayInfo outInfo); 273 private static native void nativeBlankDisplay(IBinder displayToken); 274 private static native void nativeUnblankDisplay(IBinder displayToken); 275 276 private native void nativeCopyFrom(Surface other); 277 private native void nativeTransferFrom(Surface other); 278 private native void nativeReadFromParcel(Parcel source); 279 private native void nativeWriteToParcel(Parcel dest); 280 281 282 /** 283 * Create an empty surface, which will later be filled in by readFromParcel(). 284 * @hide 285 */ 286 public Surface() { 287 checkHeadless(); 288 289 mCloseGuard.open("release"); 290 } 291 292 /** 293 * Create a surface with a name. 294 * 295 * The surface creation flags specify what kind of surface to create and 296 * certain options such as whether the surface can be assumed to be opaque 297 * and whether it should be initially hidden. Surfaces should always be 298 * created with the {@link #HIDDEN} flag set to ensure that they are not 299 * made visible prematurely before all of the surface's properties have been 300 * configured. 301 * 302 * Good practice is to first create the surface with the {@link #HIDDEN} flag 303 * specified, open a transaction, set the surface layer, layer stack, alpha, 304 * and position, call {@link #show} if appropriate, and close the transaction. 305 * 306 * @param session The surface session, must not be null. 307 * @param name The surface name, must not be null. 308 * @param w The surface initial width. 309 * @param h The surface initial height. 310 * @param flags The surface creation flags. Should always include {@link #HIDDEN} 311 * in the creation flags. 312 * @hide 313 */ 314 public Surface(SurfaceSession session, 315 String name, int w, int h, int format, int flags) 316 throws OutOfResourcesException { 317 if (session == null) { 318 throw new IllegalArgumentException("session must not be null"); 319 } 320 if (name == null) { 321 throw new IllegalArgumentException("name must not be null"); 322 } 323 324 if ((flags & HIDDEN) == 0) { 325 Log.w(TAG, "Surfaces should always be created with the HIDDEN flag set " 326 + "to ensure that they are not made visible prematurely before " 327 + "all of the surface's properties have been configured. " 328 + "Set the other properties and make the surface visible within " 329 + "a transaction. New surface name: " + name, 330 new Throwable()); 331 } 332 333 checkHeadless(); 334 335 mName = name; 336 mWidth = w; 337 mHeight = h; 338 nativeCreate(session, name, w, h, format, flags); 339 340 mCloseGuard.open("release"); 341 } 342 343 /** 344 * Create Surface from a {@link SurfaceTexture}. 345 * 346 * Images drawn to the Surface will be made available to the {@link 347 * SurfaceTexture}, which can attach them to an OpenGL ES texture via {@link 348 * SurfaceTexture#updateTexImage}. 349 * 350 * @param surfaceTexture The {@link SurfaceTexture} that is updated by this 351 * Surface. 352 */ 353 public Surface(SurfaceTexture surfaceTexture) { 354 if (surfaceTexture == null) { 355 throw new IllegalArgumentException("surfaceTexture must not be null"); 356 } 357 358 checkHeadless(); 359 360 mName = surfaceTexture.toString(); 361 try { 362 nativeCreateFromSurfaceTexture(surfaceTexture); 363 } catch (OutOfResourcesException ex) { 364 // We can't throw OutOfResourcesException because it would be an API change. 365 throw new RuntimeException(ex); 366 } 367 368 mCloseGuard.open("release"); 369 } 370 371 @Override 372 protected void finalize() throws Throwable { 373 try { 374 if (mCloseGuard != null) { 375 mCloseGuard.warnIfOpen(); 376 } 377 nativeRelease(); 378 } finally { 379 super.finalize(); 380 } 381 } 382 383 /** 384 * Release the local reference to the server-side surface. 385 * Always call release() when you're done with a Surface. 386 * This will make the surface invalid. 387 */ 388 public void release() { 389 nativeRelease(); 390 mCloseGuard.close(); 391 } 392 393 /** 394 * Free all server-side state associated with this surface and 395 * release this object's reference. This method can only be 396 * called from the process that created the service. 397 * @hide 398 */ 399 public void destroy() { 400 nativeDestroy(); 401 mCloseGuard.close(); 402 } 403 404 /** 405 * Returns true if this object holds a valid surface. 406 * 407 * @return True if it holds a physical surface, so lockCanvas() will succeed. 408 * Otherwise returns false. 409 */ 410 public boolean isValid() { 411 return nativeIsValid(); 412 } 413 414 /** 415 * Gets the generation number of this surface, incremented each time 416 * the native surface contained within this object changes. 417 * 418 * @return The current generation number. 419 * @hide 420 */ 421 public int getGenerationId() { 422 return mGenerationId; 423 } 424 425 /** 426 * Returns true if the consumer of this Surface is running behind the producer. 427 * 428 * @return True if the consumer is more than one buffer ahead of the producer. 429 * @hide 430 */ 431 public boolean isConsumerRunningBehind() { 432 return nativeIsConsumerRunningBehind(); 433 } 434 435 /** 436 * Gets a {@link Canvas} for drawing into this surface. 437 * 438 * After drawing into the provided {@link Canvas}, the caller should 439 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface. 440 * 441 * @param dirty A rectangle that represents the dirty region that the caller wants 442 * to redraw. This function may choose to expand the dirty rectangle if for example 443 * the surface has been resized or if the previous contents of the surface were 444 * not available. The caller should redraw the entire dirty region as represented 445 * by the contents of the dirty rect upon return from this function. 446 * The caller may also pass <code>null</code> instead, in the case where the 447 * entire surface should be redrawn. 448 * @return A canvas for drawing into the surface. 449 */ 450 public Canvas lockCanvas(Rect dirty) 451 throws OutOfResourcesException, IllegalArgumentException { 452 return nativeLockCanvas(dirty); 453 } 454 455 /** 456 * Posts the new contents of the {@link Canvas} to the surface and 457 * releases the {@link Canvas}. 458 * 459 * @param canvas The canvas previously obtained from {@link #lockCanvas}. 460 */ 461 public void unlockCanvasAndPost(Canvas canvas) { 462 nativeUnlockCanvasAndPost(canvas); 463 } 464 465 /** 466 * @deprecated This API has been removed and is not supported. Do not use. 467 */ 468 @Deprecated 469 public void unlockCanvas(Canvas canvas) { 470 throw new UnsupportedOperationException(); 471 } 472 473 /** 474 * Sets the translator used to scale canvas's width/height in compatibility 475 * mode. 476 */ 477 void setCompatibilityTranslator(Translator translator) { 478 if (translator != null) { 479 float appScale = translator.applicationScale; 480 mCompatibleMatrix = new Matrix(); 481 mCompatibleMatrix.setScale(appScale, appScale); 482 } 483 } 484 485 /** 486 * Like {@link #screenshot(int, int, int, int)} but includes all 487 * Surfaces in the screenshot. 488 * 489 * @hide 490 */ 491 public static Bitmap screenshot(int width, int height) { 492 // TODO: should take the display as a parameter 493 IBinder displayToken = getBuiltInDisplay(BUILT_IN_DISPLAY_ID_MAIN); 494 return nativeScreenshot(displayToken, width, height, 0, 0, true); 495 } 496 497 /** 498 * Copy the current screen contents into a bitmap and return it. 499 * 500 * @param width The desired width of the returned bitmap; the raw 501 * screen will be scaled down to this size. 502 * @param height The desired height of the returned bitmap; the raw 503 * screen will be scaled down to this size. 504 * @param minLayer The lowest (bottom-most Z order) surface layer to 505 * include in the screenshot. 506 * @param maxLayer The highest (top-most Z order) surface layer to 507 * include in the screenshot. 508 * @return Returns a Bitmap containing the screen contents, or null 509 * if an error occurs. 510 * 511 * @hide 512 */ 513 public static Bitmap screenshot(int width, int height, int minLayer, int maxLayer) { 514 // TODO: should take the display as a parameter 515 IBinder displayToken = getBuiltInDisplay(BUILT_IN_DISPLAY_ID_MAIN); 516 return nativeScreenshot(displayToken, width, height, minLayer, maxLayer, false); 517 } 518 519 /* 520 * set surface parameters. 521 * needs to be inside open/closeTransaction block 522 */ 523 524 /** start a transaction @hide */ 525 public static void openTransaction() { 526 nativeOpenTransaction(); 527 } 528 529 /** end a transaction @hide */ 530 public static void closeTransaction() { 531 nativeCloseTransaction(); 532 } 533 534 /** flag the transaction as an animation @hide */ 535 public static void setAnimationTransaction() { 536 nativeSetAnimationTransaction(); 537 } 538 539 /** @hide */ 540 public void setLayer(int zorder) { 541 nativeSetLayer(zorder); 542 } 543 544 /** @hide */ 545 public void setPosition(int x, int y) { 546 nativeSetPosition(x, y); 547 } 548 549 /** @hide */ 550 public void setPosition(float x, float y) { 551 nativeSetPosition(x, y); 552 } 553 554 /** @hide */ 555 public void setSize(int w, int h) { 556 mWidth = w; 557 mHeight = h; 558 nativeSetSize(w, h); 559 } 560 561 /** @hide */ 562 public int getWidth() { 563 return mWidth; 564 } 565 566 /** @hide */ 567 public int getHeight() { 568 return mHeight; 569 } 570 571 /** @hide */ 572 public void hide() { 573 nativeSetFlags(SURFACE_HIDDEN, SURFACE_HIDDEN); 574 } 575 576 /** @hide */ 577 public void show() { 578 nativeSetFlags(0, SURFACE_HIDDEN); 579 } 580 581 /** @hide */ 582 public void setTransparentRegionHint(Region region) { 583 nativeSetTransparentRegionHint(region); 584 } 585 586 /** @hide */ 587 public void setAlpha(float alpha) { 588 nativeSetAlpha(alpha); 589 } 590 591 /** @hide */ 592 public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) { 593 nativeSetMatrix(dsdx, dtdx, dsdy, dtdy); 594 } 595 596 /** @hide */ 597 public void setFlags(int flags, int mask) { 598 nativeSetFlags(flags, mask); 599 } 600 601 /** @hide */ 602 public void setWindowCrop(Rect crop) { 603 nativeSetWindowCrop(crop); 604 } 605 606 /** @hide */ 607 public void setLayerStack(int layerStack) { 608 nativeSetLayerStack(layerStack); 609 } 610 611 /** @hide */ 612 public static IBinder getBuiltInDisplay(int builtInDisplayId) { 613 return nativeGetBuiltInDisplay(builtInDisplayId); 614 } 615 616 /** @hide */ 617 public static IBinder createDisplay(String name, boolean secure) { 618 if (name == null) { 619 throw new IllegalArgumentException("name must not be null"); 620 } 621 return nativeCreateDisplay(name, secure); 622 } 623 624 /** @hide */ 625 public static void setDisplaySurface(IBinder displayToken, Surface surface) { 626 if (displayToken == null) { 627 throw new IllegalArgumentException("displayToken must not be null"); 628 } 629 nativeSetDisplaySurface(displayToken, surface); 630 } 631 632 /** @hide */ 633 public static void setDisplayLayerStack(IBinder displayToken, int layerStack) { 634 if (displayToken == null) { 635 throw new IllegalArgumentException("displayToken must not be null"); 636 } 637 nativeSetDisplayLayerStack(displayToken, layerStack); 638 } 639 640 /** @hide */ 641 public static void setDisplayProjection(IBinder displayToken, 642 int orientation, Rect layerStackRect, Rect displayRect) { 643 if (displayToken == null) { 644 throw new IllegalArgumentException("displayToken must not be null"); 645 } 646 if (layerStackRect == null) { 647 throw new IllegalArgumentException("layerStackRect must not be null"); 648 } 649 if (displayRect == null) { 650 throw new IllegalArgumentException("displayRect must not be null"); 651 } 652 nativeSetDisplayProjection(displayToken, orientation, layerStackRect, displayRect); 653 } 654 655 /** @hide */ 656 public static boolean getDisplayInfo(IBinder displayToken, PhysicalDisplayInfo outInfo) { 657 if (displayToken == null) { 658 throw new IllegalArgumentException("displayToken must not be null"); 659 } 660 if (outInfo == null) { 661 throw new IllegalArgumentException("outInfo must not be null"); 662 } 663 return nativeGetDisplayInfo(displayToken, outInfo); 664 } 665 666 /** @hide */ 667 public static void blankDisplay(IBinder displayToken) { 668 if (displayToken == null) { 669 throw new IllegalArgumentException("displayToken must not be null"); 670 } 671 nativeBlankDisplay(displayToken); 672 } 673 674 /** @hide */ 675 public static void unblankDisplay(IBinder displayToken) { 676 if (displayToken == null) { 677 throw new IllegalArgumentException("displayToken must not be null"); 678 } 679 nativeUnblankDisplay(displayToken); 680 } 681 682 /** 683 * Copy another surface to this one. This surface now holds a reference 684 * to the same data as the original surface, and is -not- the owner. 685 * This is for use by the window manager when returning a window surface 686 * back from a client, converting it from the representation being managed 687 * by the window manager to the representation the client uses to draw 688 * in to it. 689 * @hide 690 */ 691 public void copyFrom(Surface other) { 692 if (other == null) { 693 throw new IllegalArgumentException("other must not be null"); 694 } 695 if (other != this) { 696 nativeCopyFrom(other); 697 } 698 } 699 700 /** 701 * Transfer the native state from 'other' to this surface, releasing it 702 * from 'other'. This is for use in the client side for drawing into a 703 * surface; not guaranteed to work on the window manager side. 704 * This is for use by the client to move the underlying surface from 705 * one Surface object to another, in particular in SurfaceFlinger. 706 * @hide. 707 */ 708 public void transferFrom(Surface other) { 709 if (other == null) { 710 throw new IllegalArgumentException("other must not be null"); 711 } 712 if (other != this) { 713 nativeTransferFrom(other); 714 } 715 } 716 717 @Override 718 public int describeContents() { 719 return 0; 720 } 721 722 public void readFromParcel(Parcel source) { 723 if (source == null) { 724 throw new IllegalArgumentException("source must not be null"); 725 } 726 727 mName = source.readString(); 728 nativeReadFromParcel(source); 729 } 730 731 @Override 732 public void writeToParcel(Parcel dest, int flags) { 733 if (dest == null) { 734 throw new IllegalArgumentException("dest must not be null"); 735 } 736 737 dest.writeString(mName); 738 nativeWriteToParcel(dest); 739 if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) { 740 release(); 741 } 742 } 743 744 @Override 745 public String toString() { 746 return "Surface(name=" + mName + ", identity=" + nativeGetIdentity() + ")"; 747 } 748 749 private static void checkHeadless() { 750 if (HEADLESS) { 751 throw new UnsupportedOperationException("Device is headless"); 752 } 753 } 754 755 /** 756 * Exception thrown when a surface couldn't be created or resized. 757 */ 758 public static class OutOfResourcesException extends Exception { 759 public OutOfResourcesException() { 760 } 761 762 public OutOfResourcesException(String name) { 763 super(name); 764 } 765 } 766 767 /** 768 * Describes the properties of a physical display known to surface flinger. 769 * @hide 770 */ 771 public static final class PhysicalDisplayInfo { 772 public int width; 773 public int height; 774 public float refreshRate; 775 public float density; 776 public float xDpi; 777 public float yDpi; 778 public boolean secure; 779 780 public PhysicalDisplayInfo() { 781 } 782 783 public PhysicalDisplayInfo(PhysicalDisplayInfo other) { 784 copyFrom(other); 785 } 786 787 @Override 788 public boolean equals(Object o) { 789 return o instanceof PhysicalDisplayInfo && equals((PhysicalDisplayInfo)o); 790 } 791 792 public boolean equals(PhysicalDisplayInfo other) { 793 return other != null 794 && width == other.width 795 && height == other.height 796 && refreshRate == other.refreshRate 797 && density == other.density 798 && xDpi == other.xDpi 799 && yDpi == other.yDpi 800 && secure == other.secure; 801 } 802 803 @Override 804 public int hashCode() { 805 return 0; // don't care 806 } 807 808 public void copyFrom(PhysicalDisplayInfo other) { 809 width = other.width; 810 height = other.height; 811 refreshRate = other.refreshRate; 812 density = other.density; 813 xDpi = other.xDpi; 814 yDpi = other.yDpi; 815 secure = other.secure; 816 } 817 818 // For debugging purposes 819 @Override 820 public String toString() { 821 return "PhysicalDisplayInfo{" + width + " x " + height + ", " + refreshRate + " fps, " 822 + "density " + density + ", " + xDpi + " x " + yDpi + " dpi, secure " + secure 823 + "}"; 824 } 825 } 826 827 /** 828 * A Canvas class that can handle the compatibility mode. 829 * This does two things differently. 830 * <ul> 831 * <li>Returns the width and height of the target metrics, rather than 832 * native. For example, the canvas returns 320x480 even if an app is running 833 * in WVGA high density. 834 * <li>Scales the matrix in setMatrix by the application scale, except if 835 * the matrix looks like obtained from getMatrix. This is a hack to handle 836 * the case that an application uses getMatrix to keep the original matrix, 837 * set matrix of its own, then set the original matrix back. There is no 838 * perfect solution that works for all cases, and there are a lot of cases 839 * that this model does not work, but we hope this works for many apps. 840 * </ul> 841 */ 842 private final class CompatibleCanvas extends Canvas { 843 // A temp matrix to remember what an application obtained via {@link getMatrix} 844 private Matrix mOrigMatrix = null; 845 846 @Override 847 public int getWidth() { 848 int w = super.getWidth(); 849 if (mCompatibilityTranslator != null) { 850 w = (int)(w * mCompatibilityTranslator.applicationInvertedScale + .5f); 851 } 852 return w; 853 } 854 855 @Override 856 public int getHeight() { 857 int h = super.getHeight(); 858 if (mCompatibilityTranslator != null) { 859 h = (int)(h * mCompatibilityTranslator.applicationInvertedScale + .5f); 860 } 861 return h; 862 } 863 864 @Override 865 public void setMatrix(Matrix matrix) { 866 if (mCompatibleMatrix == null || mOrigMatrix == null || mOrigMatrix.equals(matrix)) { 867 // don't scale the matrix if it's not compatibility mode, or 868 // the matrix was obtained from getMatrix. 869 super.setMatrix(matrix); 870 } else { 871 Matrix m = new Matrix(mCompatibleMatrix); 872 m.preConcat(matrix); 873 super.setMatrix(m); 874 } 875 } 876 877 @Override 878 public void getMatrix(Matrix m) { 879 super.getMatrix(m); 880 if (mOrigMatrix == null) { 881 mOrigMatrix = new Matrix(); 882 } 883 mOrigMatrix.set(m); 884 } 885 } 886} 887