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 native void nativeCreate(SurfaceSession session, String name, 229 int w, int h, int format, int flags) 230 throws OutOfResourcesException; 231 private native void nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture) 232 throws OutOfResourcesException; 233 private native void nativeRelease(); 234 private native void nativeDestroy(); 235 236 private native boolean nativeIsValid(); 237 private native int nativeGetIdentity(); 238 private native boolean nativeIsConsumerRunningBehind(); 239 240 private native Canvas nativeLockCanvas(Rect dirty); 241 private native void nativeUnlockCanvasAndPost(Canvas canvas); 242 243 private static native Bitmap nativeScreenshot(IBinder displayToken, 244 int width, int height, int minLayer, int maxLayer, boolean allLayers); 245 246 private static native void nativeOpenTransaction(); 247 private static native void nativeCloseTransaction(); 248 private static native void nativeSetAnimationTransaction(); 249 250 private native void nativeSetLayer(int zorder); 251 private native void nativeSetPosition(float x, float y); 252 private native void nativeSetSize(int w, int h); 253 private native void nativeSetTransparentRegionHint(Region region); 254 private native void nativeSetAlpha(float alpha); 255 private native void nativeSetMatrix(float dsdx, float dtdx, float dsdy, float dtdy); 256 private native void nativeSetFlags(int flags, int mask); 257 private native void nativeSetWindowCrop(Rect crop); 258 private native void nativeSetLayerStack(int layerStack); 259 260 private static native IBinder nativeGetBuiltInDisplay(int physicalDisplayId); 261 private static native IBinder nativeCreateDisplay(String name, boolean secure); 262 private static native void nativeSetDisplaySurface( 263 IBinder displayToken, Surface surface); 264 private static native void nativeSetDisplayLayerStack( 265 IBinder displayToken, int layerStack); 266 private static native void nativeSetDisplayProjection( 267 IBinder displayToken, int orientation, Rect layerStackRect, Rect displayRect); 268 private static native boolean nativeGetDisplayInfo( 269 IBinder displayToken, PhysicalDisplayInfo outInfo); 270 private static native void nativeBlankDisplay(IBinder displayToken); 271 private static native void nativeUnblankDisplay(IBinder displayToken); 272 273 private native void nativeCopyFrom(Surface other); 274 private native void nativeTransferFrom(Surface other); 275 private native void nativeReadFromParcel(Parcel source); 276 private native void nativeWriteToParcel(Parcel dest); 277 278 279 /** 280 * Create an empty surface, which will later be filled in by readFromParcel(). 281 * @hide 282 */ 283 public Surface() { 284 checkHeadless(); 285 286 mCloseGuard.open("release"); 287 } 288 289 /** 290 * Create a surface with a name. 291 * 292 * The surface creation flags specify what kind of surface to create and 293 * certain options such as whether the surface can be assumed to be opaque 294 * and whether it should be initially hidden. Surfaces should always be 295 * created with the {@link #HIDDEN} flag set to ensure that they are not 296 * made visible prematurely before all of the surface's properties have been 297 * configured. 298 * 299 * Good practice is to first create the surface with the {@link #HIDDEN} flag 300 * specified, open a transaction, set the surface layer, layer stack, alpha, 301 * and position, call {@link #show} if appropriate, and close the transaction. 302 * 303 * @param session The surface session, must not be null. 304 * @param name The surface name, must not be null. 305 * @param w The surface initial width. 306 * @param h The surface initial height. 307 * @param flags The surface creation flags. Should always include {@link #HIDDEN} 308 * in the creation flags. 309 * @hide 310 */ 311 public Surface(SurfaceSession session, 312 String name, int w, int h, int format, int flags) 313 throws OutOfResourcesException { 314 if (session == null) { 315 throw new IllegalArgumentException("session must not be null"); 316 } 317 if (name == null) { 318 throw new IllegalArgumentException("name must not be null"); 319 } 320 321 if ((flags & HIDDEN) == 0) { 322 Log.w(TAG, "Surfaces should always be created with the HIDDEN flag set " 323 + "to ensure that they are not made visible prematurely before " 324 + "all of the surface's properties have been configured. " 325 + "Set the other properties and make the surface visible within " 326 + "a transaction. New surface name: " + name, 327 new Throwable()); 328 } 329 330 checkHeadless(); 331 332 mName = name; 333 nativeCreate(session, name, w, h, format, flags); 334 335 mCloseGuard.open("release"); 336 } 337 338 /** 339 * Create Surface from a {@link SurfaceTexture}. 340 * 341 * Images drawn to the Surface will be made available to the {@link 342 * SurfaceTexture}, which can attach them to an OpenGL ES texture via {@link 343 * SurfaceTexture#updateTexImage}. 344 * 345 * @param surfaceTexture The {@link SurfaceTexture} that is updated by this 346 * Surface. 347 */ 348 public Surface(SurfaceTexture surfaceTexture) { 349 if (surfaceTexture == null) { 350 throw new IllegalArgumentException("surfaceTexture must not be null"); 351 } 352 353 checkHeadless(); 354 355 mName = surfaceTexture.toString(); 356 try { 357 nativeCreateFromSurfaceTexture(surfaceTexture); 358 } catch (OutOfResourcesException ex) { 359 // We can't throw OutOfResourcesException because it would be an API change. 360 throw new RuntimeException(ex); 361 } 362 363 mCloseGuard.open("release"); 364 } 365 366 @Override 367 protected void finalize() throws Throwable { 368 try { 369 if (mCloseGuard != null) { 370 mCloseGuard.warnIfOpen(); 371 } 372 nativeRelease(); 373 } finally { 374 super.finalize(); 375 } 376 } 377 378 /** 379 * Release the local reference to the server-side surface. 380 * Always call release() when you're done with a Surface. 381 * This will make the surface invalid. 382 */ 383 public void release() { 384 nativeRelease(); 385 mCloseGuard.close(); 386 } 387 388 /** 389 * Free all server-side state associated with this surface and 390 * release this object's reference. This method can only be 391 * called from the process that created the service. 392 * @hide 393 */ 394 public void destroy() { 395 nativeDestroy(); 396 mCloseGuard.close(); 397 } 398 399 /** 400 * Returns true if this object holds a valid surface. 401 * 402 * @return True if it holds a physical surface, so lockCanvas() will succeed. 403 * Otherwise returns false. 404 */ 405 public boolean isValid() { 406 return nativeIsValid(); 407 } 408 409 /** 410 * Gets the generation number of this surface, incremented each time 411 * the native surface contained within this object changes. 412 * 413 * @return The current generation number. 414 * @hide 415 */ 416 public int getGenerationId() { 417 return mGenerationId; 418 } 419 420 /** 421 * Returns true if the consumer of this Surface is running behind the producer. 422 * 423 * @return True if the consumer is more than one buffer ahead of the producer. 424 * @hide 425 */ 426 public boolean isConsumerRunningBehind() { 427 return nativeIsConsumerRunningBehind(); 428 } 429 430 /** 431 * Gets a {@link Canvas} for drawing into this surface. 432 * 433 * After drawing into the provided {@link Canvas}, the caller should 434 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface. 435 * 436 * @param dirty A rectangle that represents the dirty region that the caller wants 437 * to redraw. This function may choose to expand the dirty rectangle if for example 438 * the surface has been resized or if the previous contents of the surface were 439 * not available. The caller should redraw the entire dirty region as represented 440 * by the contents of the dirty rect upon return from this function. 441 * The caller may also pass <code>null</code> instead, in the case where the 442 * entire surface should be redrawn. 443 * @return A canvas for drawing into the surface. 444 */ 445 public Canvas lockCanvas(Rect dirty) 446 throws OutOfResourcesException, IllegalArgumentException { 447 return nativeLockCanvas(dirty); 448 } 449 450 /** 451 * Posts the new contents of the {@link Canvas} to the surface and 452 * releases the {@link Canvas}. 453 * 454 * @param canvas The canvas previously obtained from {@link #lockCanvas}. 455 */ 456 public void unlockCanvasAndPost(Canvas canvas) { 457 nativeUnlockCanvasAndPost(canvas); 458 } 459 460 /** 461 * @deprecated This API has been removed and is not supported. Do not use. 462 */ 463 @Deprecated 464 public void unlockCanvas(Canvas canvas) { 465 throw new UnsupportedOperationException(); 466 } 467 468 /** 469 * Sets the translator used to scale canvas's width/height in compatibility 470 * mode. 471 */ 472 void setCompatibilityTranslator(Translator translator) { 473 if (translator != null) { 474 float appScale = translator.applicationScale; 475 mCompatibleMatrix = new Matrix(); 476 mCompatibleMatrix.setScale(appScale, appScale); 477 } 478 } 479 480 /** 481 * Like {@link #screenshot(int, int, int, int)} but includes all 482 * Surfaces in the screenshot. 483 * 484 * @hide 485 */ 486 public static Bitmap screenshot(int width, int height) { 487 // TODO: should take the display as a parameter 488 IBinder displayToken = getBuiltInDisplay(BUILT_IN_DISPLAY_ID_MAIN); 489 return nativeScreenshot(displayToken, width, height, 0, 0, true); 490 } 491 492 /** 493 * Copy the current screen contents into a bitmap and return it. 494 * 495 * @param width The desired width of the returned bitmap; the raw 496 * screen will be scaled down to this size. 497 * @param height The desired height of the returned bitmap; the raw 498 * screen will be scaled down to this size. 499 * @param minLayer The lowest (bottom-most Z order) surface layer to 500 * include in the screenshot. 501 * @param maxLayer The highest (top-most Z order) surface layer to 502 * include in the screenshot. 503 * @return Returns a Bitmap containing the screen contents, or null 504 * if an error occurs. 505 * 506 * @hide 507 */ 508 public static Bitmap screenshot(int width, int height, int minLayer, int maxLayer) { 509 // TODO: should take the display as a parameter 510 IBinder displayToken = getBuiltInDisplay(BUILT_IN_DISPLAY_ID_MAIN); 511 return nativeScreenshot(displayToken, width, height, minLayer, maxLayer, false); 512 } 513 514 /* 515 * set surface parameters. 516 * needs to be inside open/closeTransaction block 517 */ 518 519 /** start a transaction @hide */ 520 public static void openTransaction() { 521 nativeOpenTransaction(); 522 } 523 524 /** end a transaction @hide */ 525 public static void closeTransaction() { 526 nativeCloseTransaction(); 527 } 528 529 /** flag the transaction as an animation @hide */ 530 public static void setAnimationTransaction() { 531 nativeSetAnimationTransaction(); 532 } 533 534 /** @hide */ 535 public void setLayer(int zorder) { 536 nativeSetLayer(zorder); 537 } 538 539 /** @hide */ 540 public void setPosition(int x, int y) { 541 nativeSetPosition((float)x, (float)y); 542 } 543 544 /** @hide */ 545 public void setPosition(float x, float y) { 546 nativeSetPosition(x, y); 547 } 548 549 /** @hide */ 550 public void setSize(int w, int h) { 551 nativeSetSize(w, h); 552 } 553 554 /** @hide */ 555 public void hide() { 556 nativeSetFlags(SURFACE_HIDDEN, SURFACE_HIDDEN); 557 } 558 559 /** @hide */ 560 public void show() { 561 nativeSetFlags(0, SURFACE_HIDDEN); 562 } 563 564 /** @hide */ 565 public void setTransparentRegionHint(Region region) { 566 nativeSetTransparentRegionHint(region); 567 } 568 569 /** @hide */ 570 public void setAlpha(float alpha) { 571 nativeSetAlpha(alpha); 572 } 573 574 /** @hide */ 575 public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) { 576 nativeSetMatrix(dsdx, dtdx, dsdy, dtdy); 577 } 578 579 /** @hide */ 580 public void setFlags(int flags, int mask) { 581 nativeSetFlags(flags, mask); 582 } 583 584 /** @hide */ 585 public void setWindowCrop(Rect crop) { 586 nativeSetWindowCrop(crop); 587 } 588 589 /** @hide */ 590 public void setLayerStack(int layerStack) { 591 nativeSetLayerStack(layerStack); 592 } 593 594 /** @hide */ 595 public static IBinder getBuiltInDisplay(int builtInDisplayId) { 596 return nativeGetBuiltInDisplay(builtInDisplayId); 597 } 598 599 /** @hide */ 600 public static IBinder createDisplay(String name, boolean secure) { 601 if (name == null) { 602 throw new IllegalArgumentException("name must not be null"); 603 } 604 return nativeCreateDisplay(name, secure); 605 } 606 607 /** @hide */ 608 public static void setDisplaySurface(IBinder displayToken, Surface surface) { 609 if (displayToken == null) { 610 throw new IllegalArgumentException("displayToken must not be null"); 611 } 612 nativeSetDisplaySurface(displayToken, surface); 613 } 614 615 /** @hide */ 616 public static void setDisplayLayerStack(IBinder displayToken, int layerStack) { 617 if (displayToken == null) { 618 throw new IllegalArgumentException("displayToken must not be null"); 619 } 620 nativeSetDisplayLayerStack(displayToken, layerStack); 621 } 622 623 /** @hide */ 624 public static void setDisplayProjection(IBinder displayToken, 625 int orientation, Rect layerStackRect, Rect displayRect) { 626 if (displayToken == null) { 627 throw new IllegalArgumentException("displayToken must not be null"); 628 } 629 if (layerStackRect == null) { 630 throw new IllegalArgumentException("layerStackRect must not be null"); 631 } 632 if (displayRect == null) { 633 throw new IllegalArgumentException("displayRect must not be null"); 634 } 635 nativeSetDisplayProjection(displayToken, orientation, layerStackRect, displayRect); 636 } 637 638 /** @hide */ 639 public static boolean getDisplayInfo(IBinder displayToken, PhysicalDisplayInfo outInfo) { 640 if (displayToken == null) { 641 throw new IllegalArgumentException("displayToken must not be null"); 642 } 643 if (outInfo == null) { 644 throw new IllegalArgumentException("outInfo must not be null"); 645 } 646 return nativeGetDisplayInfo(displayToken, outInfo); 647 } 648 649 /** @hide */ 650 public static void blankDisplay(IBinder displayToken) { 651 if (displayToken == null) { 652 throw new IllegalArgumentException("displayToken must not be null"); 653 } 654 nativeBlankDisplay(displayToken); 655 } 656 657 /** @hide */ 658 public static void unblankDisplay(IBinder displayToken) { 659 if (displayToken == null) { 660 throw new IllegalArgumentException("displayToken must not be null"); 661 } 662 nativeUnblankDisplay(displayToken); 663 } 664 665 /** 666 * Copy another surface to this one. This surface now holds a reference 667 * to the same data as the original surface, and is -not- the owner. 668 * This is for use by the window manager when returning a window surface 669 * back from a client, converting it from the representation being managed 670 * by the window manager to the representation the client uses to draw 671 * in to it. 672 * @hide 673 */ 674 public void copyFrom(Surface other) { 675 if (other == null) { 676 throw new IllegalArgumentException("other must not be null"); 677 } 678 if (other != this) { 679 nativeCopyFrom(other); 680 } 681 } 682 683 /** 684 * Transfer the native state from 'other' to this surface, releasing it 685 * from 'other'. This is for use in the client side for drawing into a 686 * surface; not guaranteed to work on the window manager side. 687 * This is for use by the client to move the underlying surface from 688 * one Surface object to another, in particular in SurfaceFlinger. 689 * @hide. 690 */ 691 public void transferFrom(Surface other) { 692 if (other == null) { 693 throw new IllegalArgumentException("other must not be null"); 694 } 695 if (other != this) { 696 nativeTransferFrom(other); 697 } 698 } 699 700 @Override 701 public int describeContents() { 702 return 0; 703 } 704 705 public void readFromParcel(Parcel source) { 706 if (source == null) { 707 throw new IllegalArgumentException("source must not be null"); 708 } 709 710 mName = source.readString(); 711 nativeReadFromParcel(source); 712 } 713 714 @Override 715 public void writeToParcel(Parcel dest, int flags) { 716 if (dest == null) { 717 throw new IllegalArgumentException("dest must not be null"); 718 } 719 720 dest.writeString(mName); 721 nativeWriteToParcel(dest); 722 if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) { 723 release(); 724 } 725 } 726 727 @Override 728 public String toString() { 729 return "Surface(name=" + mName + ", identity=" + nativeGetIdentity() + ")"; 730 } 731 732 private static void checkHeadless() { 733 if (HEADLESS) { 734 throw new UnsupportedOperationException("Device is headless"); 735 } 736 } 737 738 /** 739 * Exception thrown when a surface couldn't be created or resized. 740 */ 741 public static class OutOfResourcesException extends Exception { 742 public OutOfResourcesException() { 743 } 744 745 public OutOfResourcesException(String name) { 746 super(name); 747 } 748 } 749 750 /** 751 * Describes the properties of a physical display known to surface flinger. 752 * @hide 753 */ 754 public static final class PhysicalDisplayInfo { 755 public int width; 756 public int height; 757 public float refreshRate; 758 public float density; 759 public float xDpi; 760 public float yDpi; 761 public boolean secure; 762 763 public PhysicalDisplayInfo() { 764 } 765 766 public PhysicalDisplayInfo(PhysicalDisplayInfo other) { 767 copyFrom(other); 768 } 769 770 @Override 771 public boolean equals(Object o) { 772 return o instanceof PhysicalDisplayInfo && equals((PhysicalDisplayInfo)o); 773 } 774 775 public boolean equals(PhysicalDisplayInfo other) { 776 return other != null 777 && width == other.width 778 && height == other.height 779 && refreshRate == other.refreshRate 780 && density == other.density 781 && xDpi == other.xDpi 782 && yDpi == other.yDpi 783 && secure == other.secure; 784 } 785 786 @Override 787 public int hashCode() { 788 return 0; // don't care 789 } 790 791 public void copyFrom(PhysicalDisplayInfo other) { 792 width = other.width; 793 height = other.height; 794 refreshRate = other.refreshRate; 795 density = other.density; 796 xDpi = other.xDpi; 797 yDpi = other.yDpi; 798 secure = other.secure; 799 } 800 801 // For debugging purposes 802 @Override 803 public String toString() { 804 return "PhysicalDisplayInfo{" + width + " x " + height + ", " + refreshRate + " fps, " 805 + "density " + density + ", " + xDpi + " x " + yDpi + " dpi, secure " + secure 806 + "}"; 807 } 808 } 809 810 /** 811 * A Canvas class that can handle the compatibility mode. 812 * This does two things differently. 813 * <ul> 814 * <li>Returns the width and height of the target metrics, rather than 815 * native. For example, the canvas returns 320x480 even if an app is running 816 * in WVGA high density. 817 * <li>Scales the matrix in setMatrix by the application scale, except if 818 * the matrix looks like obtained from getMatrix. This is a hack to handle 819 * the case that an application uses getMatrix to keep the original matrix, 820 * set matrix of its own, then set the original matrix back. There is no 821 * perfect solution that works for all cases, and there are a lot of cases 822 * that this model does not work, but we hope this works for many apps. 823 * </ul> 824 */ 825 private final class CompatibleCanvas extends Canvas { 826 // A temp matrix to remember what an application obtained via {@link getMatrix} 827 private Matrix mOrigMatrix = null; 828 829 @Override 830 public int getWidth() { 831 int w = super.getWidth(); 832 if (mCompatibilityTranslator != null) { 833 w = (int)(w * mCompatibilityTranslator.applicationInvertedScale + .5f); 834 } 835 return w; 836 } 837 838 @Override 839 public int getHeight() { 840 int h = super.getHeight(); 841 if (mCompatibilityTranslator != null) { 842 h = (int)(h * mCompatibilityTranslator.applicationInvertedScale + .5f); 843 } 844 return h; 845 } 846 847 @Override 848 public void setMatrix(Matrix matrix) { 849 if (mCompatibleMatrix == null || mOrigMatrix == null || mOrigMatrix.equals(matrix)) { 850 // don't scale the matrix if it's not compatibility mode, or 851 // the matrix was obtained from getMatrix. 852 super.setMatrix(matrix); 853 } else { 854 Matrix m = new Matrix(mCompatibleMatrix); 855 m.preConcat(matrix); 856 super.setMatrix(m); 857 } 858 } 859 860 @Override 861 public void getMatrix(Matrix m) { 862 super.getMatrix(m); 863 if (mOrigMatrix == null) { 864 mOrigMatrix = new Matrix(); 865 } 866 mOrigMatrix.set(m); 867 } 868 } 869} 870