1 /* 2 * Copyright (C) 2013 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.view; 18 19 import dalvik.system.CloseGuard; 20 import android.graphics.Bitmap; 21 import android.graphics.Rect; 22 import android.graphics.Region; 23 import android.view.Surface; 24 import android.os.IBinder; 25 import android.os.SystemProperties; 26 import android.util.Log; 27 28 /** 29 * SurfaceControl 30 * @hide 31 */ 32 public class SurfaceControl { 33 private static final String TAG = "SurfaceControl"; 34 35 private static native int nativeCreate(SurfaceSession session, String name, 36 int w, int h, int format, int flags) 37 throws OutOfResourcesException; 38 private static native void nativeRelease(int nativeObject); 39 private static native void nativeDestroy(int nativeObject); 40 41 private static native Bitmap nativeScreenshot(IBinder displayToken, 42 int width, int height, int minLayer, int maxLayer, boolean allLayers); 43 private static native void nativeScreenshot(IBinder displayToken, Surface consumer, 44 int width, int height, int minLayer, int maxLayer, boolean allLayers); 45 46 private static native void nativeOpenTransaction(); 47 private static native void nativeCloseTransaction(); 48 private static native void nativeSetAnimationTransaction(); 49 50 private static native void nativeSetLayer(int nativeObject, int zorder); 51 private static native void nativeSetPosition(int nativeObject, float x, float y); 52 private static native void nativeSetSize(int nativeObject, int w, int h); 53 private static native void nativeSetTransparentRegionHint(int nativeObject, Region region); 54 private static native void nativeSetAlpha(int nativeObject, float alpha); 55 private static native void nativeSetMatrix(int nativeObject, float dsdx, float dtdx, float dsdy, float dtdy); 56 private static native void nativeSetFlags(int nativeObject, int flags, int mask); 57 private static native void nativeSetWindowCrop(int nativeObject, int l, int t, int r, int b); 58 private static native void nativeSetLayerStack(int nativeObject, int layerStack); 59 60 private static native IBinder nativeGetBuiltInDisplay(int physicalDisplayId); 61 private static native IBinder nativeCreateDisplay(String name, boolean secure); 62 private static native void nativeSetDisplaySurface( 63 IBinder displayToken, int nativeSurfaceObject); 64 private static native void nativeSetDisplayLayerStack( 65 IBinder displayToken, int layerStack); 66 private static native void nativeSetDisplayProjection( 67 IBinder displayToken, int orientation, 68 int l, int t, int r, int b, 69 int L, int T, int R, int B); 70 private static native boolean nativeGetDisplayInfo( 71 IBinder displayToken, SurfaceControl.PhysicalDisplayInfo outInfo); 72 private static native void nativeBlankDisplay(IBinder displayToken); 73 private static native void nativeUnblankDisplay(IBinder displayToken); 74 75 76 private final CloseGuard mCloseGuard = CloseGuard.get(); 77 private String mName; 78 int mNativeObject; // package visibility only for Surface.java access 79 80 private static final boolean HEADLESS = "1".equals( 81 SystemProperties.get("ro.config.headless", "0")); 82 83 /** 84 * Exception thrown when a surface couldn't be created or resized. 85 */ 86 public static class OutOfResourcesException extends Exception { 87 public OutOfResourcesException() { 88 } 89 public OutOfResourcesException(String name) { 90 super(name); 91 } 92 } 93 94 /* flags used in constructor (keep in sync with ISurfaceComposerClient.h) */ 95 96 /** 97 * Surface creation flag: Surface is created hidden 98 */ 99 public static final int HIDDEN = 0x00000004; 100 101 /** 102 * Surface creation flag: The surface contains secure content, special 103 * measures will be taken to disallow the surface's content to be copied 104 * from another process. In particular, screenshots and VNC servers will 105 * be disabled, but other measures can take place, for instance the 106 * surface might not be hardware accelerated. 107 * 108 */ 109 public static final int SECURE = 0x00000080; 110 111 /** 112 * Surface creation flag: Creates a surface where color components are interpreted 113 * as "non pre-multiplied" by their alpha channel. Of course this flag is 114 * meaningless for surfaces without an alpha channel. By default 115 * surfaces are pre-multiplied, which means that each color component is 116 * already multiplied by its alpha value. In this case the blending 117 * equation used is: 118 * 119 * DEST = SRC + DEST * (1-SRC_ALPHA) 120 * 121 * By contrast, non pre-multiplied surfaces use the following equation: 122 * 123 * DEST = SRC * SRC_ALPHA * DEST * (1-SRC_ALPHA) 124 * 125 * pre-multiplied surfaces must always be used if transparent pixels are 126 * composited on top of each-other into the surface. A pre-multiplied 127 * surface can never lower the value of the alpha component of a given 128 * pixel. 129 * 130 * In some rare situations, a non pre-multiplied surface is preferable. 131 * 132 */ 133 public static final int NON_PREMULTIPLIED = 0x00000100; 134 135 /** 136 * Surface creation flag: Indicates that the surface must be considered opaque, 137 * even if its pixel format is set to translucent. This can be useful if an 138 * application needs full RGBA 8888 support for instance but will 139 * still draw every pixel opaque. 140 * 141 */ 142 public static final int OPAQUE = 0x00000400; 143 144 /** 145 * Surface creation flag: Application requires a hardware-protected path to an 146 * external display sink. If a hardware-protected path is not available, 147 * then this surface will not be displayed on the external sink. 148 * 149 */ 150 public static final int PROTECTED_APP = 0x00000800; 151 152 // 0x1000 is reserved for an independent DRM protected flag in framework 153 154 /** 155 * Surface creation flag: Creates a normal surface. 156 * This is the default. 157 * 158 */ 159 public static final int FX_SURFACE_NORMAL = 0x00000000; 160 161 /** 162 * Surface creation flag: Creates a Dim surface. 163 * Everything behind this surface is dimmed by the amount specified 164 * in {@link #setAlpha}. It is an error to lock a Dim surface, since it 165 * doesn't have a backing store. 166 * 167 */ 168 public static final int FX_SURFACE_DIM = 0x00020000; 169 170 /** 171 * Mask used for FX values above. 172 * 173 */ 174 public static final int FX_SURFACE_MASK = 0x000F0000; 175 176 /* flags used with setFlags() (keep in sync with ISurfaceComposer.h) */ 177 178 /** 179 * Surface flag: Hide the surface. 180 * Equivalent to calling hide(). 181 */ 182 public static final int SURFACE_HIDDEN = 0x01; 183 184 185 /* built-in physical display ids (keep in sync with ISurfaceComposer.h) 186 * these are different from the logical display ids used elsewhere in the framework */ 187 188 /** 189 * Built-in physical display id: Main display. 190 * Use only with {@link SurfaceControl#getBuiltInDisplay()}. 191 */ 192 public static final int BUILT_IN_DISPLAY_ID_MAIN = 0; 193 194 /** 195 * Built-in physical display id: Attached HDMI display. 196 * Use only with {@link SurfaceControl#getBuiltInDisplay()}. 197 */ 198 public static final int BUILT_IN_DISPLAY_ID_HDMI = 1; 199 200 201 202 /** 203 * Create a surface with a name. 204 * 205 * The surface creation flags specify what kind of surface to create and 206 * certain options such as whether the surface can be assumed to be opaque 207 * and whether it should be initially hidden. Surfaces should always be 208 * created with the {@link #HIDDEN} flag set to ensure that they are not 209 * made visible prematurely before all of the surface's properties have been 210 * configured. 211 * 212 * Good practice is to first create the surface with the {@link #HIDDEN} flag 213 * specified, open a transaction, set the surface layer, layer stack, alpha, 214 * and position, call {@link #show} if appropriate, and close the transaction. 215 * 216 * @param session The surface session, must not be null. 217 * @param name The surface name, must not be null. 218 * @param w The surface initial width. 219 * @param h The surface initial height. 220 * @param flags The surface creation flags. Should always include {@link #HIDDEN} 221 * in the creation flags. 222 */ 223 public SurfaceControl(SurfaceSession session, 224 String name, int w, int h, int format, int flags) 225 throws OutOfResourcesException { 226 if (session == null) { 227 throw new IllegalArgumentException("session must not be null"); 228 } 229 if (name == null) { 230 throw new IllegalArgumentException("name must not be null"); 231 } 232 233 if ((flags & SurfaceControl.HIDDEN) == 0) { 234 Log.w(TAG, "Surfaces should always be created with the HIDDEN flag set " 235 + "to ensure that they are not made visible prematurely before " 236 + "all of the surface's properties have been configured. " 237 + "Set the other properties and make the surface visible within " 238 + "a transaction. New surface name: " + name, 239 new Throwable()); 240 } 241 242 checkHeadless(); 243 244 mName = name; 245 mNativeObject = nativeCreate(session, name, w, h, format, flags); 246 if (mNativeObject == 0) { 247 throw new OutOfResourcesException( 248 "Couldn't allocate SurfaceControl native object"); 249 } 250 251 mCloseGuard.open("release"); 252 } 253 254 @Override 255 protected void finalize() throws Throwable { 256 try { 257 if (mCloseGuard != null) { 258 mCloseGuard.warnIfOpen(); 259 } 260 if (mNativeObject != 0) { 261 nativeRelease(mNativeObject); 262 } 263 } finally { 264 super.finalize(); 265 } 266 } 267 268 @Override 269 public String toString() { 270 return "Surface(name=" + mName + ")"; 271 } 272 273 /** 274 * Release the local reference to the server-side surface. 275 * Always call release() when you're done with a Surface. 276 * This will make the surface invalid. 277 */ 278 public void release() { 279 if (mNativeObject != 0) { 280 nativeRelease(mNativeObject); 281 mNativeObject = 0; 282 } 283 mCloseGuard.close(); 284 } 285 286 /** 287 * Free all server-side state associated with this surface and 288 * release this object's reference. This method can only be 289 * called from the process that created the service. 290 */ 291 public void destroy() { 292 if (mNativeObject != 0) { 293 nativeDestroy(mNativeObject); 294 mNativeObject = 0; 295 } 296 mCloseGuard.close(); 297 } 298 299 private void checkNotReleased() { 300 if (mNativeObject == 0) throw new NullPointerException( 301 "mNativeObject is null. Have you called release() already?"); 302 } 303 304 /* 305 * set surface parameters. 306 * needs to be inside open/closeTransaction block 307 */ 308 309 /** start a transaction */ 310 public static void openTransaction() { 311 nativeOpenTransaction(); 312 } 313 314 /** end a transaction */ 315 public static void closeTransaction() { 316 nativeCloseTransaction(); 317 } 318 319 /** flag the transaction as an animation */ 320 public static void setAnimationTransaction() { 321 nativeSetAnimationTransaction(); 322 } 323 324 public void setLayer(int zorder) { 325 checkNotReleased(); 326 nativeSetLayer(mNativeObject, zorder); 327 } 328 329 public void setPosition(float x, float y) { 330 checkNotReleased(); 331 nativeSetPosition(mNativeObject, x, y); 332 } 333 334 public void setSize(int w, int h) { 335 checkNotReleased(); 336 nativeSetSize(mNativeObject, w, h); 337 } 338 339 public void hide() { 340 checkNotReleased(); 341 nativeSetFlags(mNativeObject, SURFACE_HIDDEN, SURFACE_HIDDEN); 342 } 343 344 public void show() { 345 checkNotReleased(); 346 nativeSetFlags(mNativeObject, 0, SURFACE_HIDDEN); 347 } 348 349 public void setTransparentRegionHint(Region region) { 350 checkNotReleased(); 351 nativeSetTransparentRegionHint(mNativeObject, region); 352 } 353 354 public void setAlpha(float alpha) { 355 checkNotReleased(); 356 nativeSetAlpha(mNativeObject, alpha); 357 } 358 359 public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) { 360 checkNotReleased(); 361 nativeSetMatrix(mNativeObject, dsdx, dtdx, dsdy, dtdy); 362 } 363 364 public void setFlags(int flags, int mask) { 365 checkNotReleased(); 366 nativeSetFlags(mNativeObject, flags, mask); 367 } 368 369 public void setWindowCrop(Rect crop) { 370 checkNotReleased(); 371 if (crop != null) { 372 nativeSetWindowCrop(mNativeObject, 373 crop.left, crop.top, crop.right, crop.bottom); 374 } else { 375 nativeSetWindowCrop(mNativeObject, 0, 0, 0, 0); 376 } 377 } 378 379 public void setLayerStack(int layerStack) { 380 checkNotReleased(); 381 nativeSetLayerStack(mNativeObject, layerStack); 382 } 383 384 /* 385 * set display parameters. 386 * needs to be inside open/closeTransaction block 387 */ 388 389 /** 390 * Describes the properties of a physical display known to surface flinger. 391 */ 392 public static final class PhysicalDisplayInfo { 393 public int width; 394 public int height; 395 public float refreshRate; 396 public float density; 397 public float xDpi; 398 public float yDpi; 399 public boolean secure; 400 401 public PhysicalDisplayInfo() { 402 } 403 404 public PhysicalDisplayInfo(PhysicalDisplayInfo other) { 405 copyFrom(other); 406 } 407 408 @Override 409 public boolean equals(Object o) { 410 return o instanceof PhysicalDisplayInfo && equals((PhysicalDisplayInfo)o); 411 } 412 413 public boolean equals(PhysicalDisplayInfo other) { 414 return other != null 415 && width == other.width 416 && height == other.height 417 && refreshRate == other.refreshRate 418 && density == other.density 419 && xDpi == other.xDpi 420 && yDpi == other.yDpi 421 && secure == other.secure; 422 } 423 424 @Override 425 public int hashCode() { 426 return 0; // don't care 427 } 428 429 public void copyFrom(PhysicalDisplayInfo other) { 430 width = other.width; 431 height = other.height; 432 refreshRate = other.refreshRate; 433 density = other.density; 434 xDpi = other.xDpi; 435 yDpi = other.yDpi; 436 secure = other.secure; 437 } 438 439 // For debugging purposes 440 @Override 441 public String toString() { 442 return "PhysicalDisplayInfo{" + width + " x " + height + ", " + refreshRate + " fps, " 443 + "density " + density + ", " + xDpi + " x " + yDpi + " dpi, secure " + secure 444 + "}"; 445 } 446 } 447 448 public static void unblankDisplay(IBinder displayToken) { 449 if (displayToken == null) { 450 throw new IllegalArgumentException("displayToken must not be null"); 451 } 452 nativeUnblankDisplay(displayToken); 453 } 454 455 public static void blankDisplay(IBinder displayToken) { 456 if (displayToken == null) { 457 throw new IllegalArgumentException("displayToken must not be null"); 458 } 459 nativeBlankDisplay(displayToken); 460 } 461 462 public static boolean getDisplayInfo(IBinder displayToken, SurfaceControl.PhysicalDisplayInfo outInfo) { 463 if (displayToken == null) { 464 throw new IllegalArgumentException("displayToken must not be null"); 465 } 466 if (outInfo == null) { 467 throw new IllegalArgumentException("outInfo must not be null"); 468 } 469 return nativeGetDisplayInfo(displayToken, outInfo); 470 } 471 472 public static void setDisplayProjection(IBinder displayToken, 473 int orientation, Rect layerStackRect, Rect displayRect) { 474 if (displayToken == null) { 475 throw new IllegalArgumentException("displayToken must not be null"); 476 } 477 if (layerStackRect == null) { 478 throw new IllegalArgumentException("layerStackRect must not be null"); 479 } 480 if (displayRect == null) { 481 throw new IllegalArgumentException("displayRect must not be null"); 482 } 483 nativeSetDisplayProjection(displayToken, orientation, 484 layerStackRect.left, layerStackRect.top, layerStackRect.right, layerStackRect.bottom, 485 displayRect.left, displayRect.top, displayRect.right, displayRect.bottom); 486 } 487 488 public static void setDisplayLayerStack(IBinder displayToken, int layerStack) { 489 if (displayToken == null) { 490 throw new IllegalArgumentException("displayToken must not be null"); 491 } 492 nativeSetDisplayLayerStack(displayToken, layerStack); 493 } 494 495 public static void setDisplaySurface(IBinder displayToken, Surface surface) { 496 if (displayToken == null) { 497 throw new IllegalArgumentException("displayToken must not be null"); 498 } 499 500 if (surface != null) { 501 synchronized (surface.mLock) { 502 nativeSetDisplaySurface(displayToken, surface.mNativeSurface); 503 } 504 } else { 505 nativeSetDisplaySurface(displayToken, 0); 506 } 507 } 508 509 public static IBinder createDisplay(String name, boolean secure) { 510 if (name == null) { 511 throw new IllegalArgumentException("name must not be null"); 512 } 513 return nativeCreateDisplay(name, secure); 514 } 515 516 public static IBinder getBuiltInDisplay(int builtInDisplayId) { 517 return nativeGetBuiltInDisplay(builtInDisplayId); 518 } 519 520 521 /** 522 * Copy the current screen contents into the provided {@link Surface} 523 * 524 * @param display The display to take the screenshot of. 525 * @param consumer The {@link Surface} to take the screenshot into. 526 * @param width The desired width of the returned bitmap; the raw 527 * screen will be scaled down to this size. 528 * @param height The desired height of the returned bitmap; the raw 529 * screen will be scaled down to this size. 530 * @param minLayer The lowest (bottom-most Z order) surface layer to 531 * include in the screenshot. 532 * @param maxLayer The highest (top-most Z order) surface layer to 533 * include in the screenshot. 534 */ 535 public static void screenshot(IBinder display, Surface consumer, 536 int width, int height, int minLayer, int maxLayer) { 537 screenshot(display, consumer, width, height, minLayer, maxLayer, false); 538 } 539 540 /** 541 * Copy the current screen contents into the provided {@link Surface} 542 * 543 * @param display The display to take the screenshot of. 544 * @param consumer The {@link Surface} to take the screenshot into. 545 * @param width The desired width of the returned bitmap; the raw 546 * screen will be scaled down to this size. 547 * @param height The desired height of the returned bitmap; the raw 548 * screen will be scaled down to this size. 549 */ 550 public static void screenshot(IBinder display, Surface consumer, 551 int width, int height) { 552 screenshot(display, consumer, width, height, 0, 0, true); 553 } 554 555 /** 556 * Copy the current screen contents into the provided {@link Surface} 557 * 558 * @param display The display to take the screenshot of. 559 * @param consumer The {@link Surface} to take the screenshot into. 560 */ 561 public static void screenshot(IBinder display, Surface consumer) { 562 screenshot(display, consumer, 0, 0, 0, 0, true); 563 } 564 565 566 /** 567 * Copy the current screen contents into a bitmap and return it. 568 * 569 * CAVEAT: Versions of screenshot that return a {@link Bitmap} can 570 * be extremely slow; avoid use unless absolutely necessary; prefer 571 * the versions that use a {@link Surface} instead, such as 572 * {@link SurfaceControl#screenshot(IBinder, Surface)}. 573 * 574 * @param width The desired width of the returned bitmap; the raw 575 * screen will be scaled down to this size. 576 * @param height The desired height of the returned bitmap; the raw 577 * screen will be scaled down to this size. 578 * @param minLayer The lowest (bottom-most Z order) surface layer to 579 * include in the screenshot. 580 * @param maxLayer The highest (top-most Z order) surface layer to 581 * include in the screenshot. 582 * @return Returns a Bitmap containing the screen contents, or null 583 * if an error occurs. Make sure to call Bitmap.recycle() as soon as 584 * possible, once its content is not needed anymore. 585 */ 586 public static Bitmap screenshot(int width, int height, int minLayer, int maxLayer) { 587 // TODO: should take the display as a parameter 588 IBinder displayToken = SurfaceControl.getBuiltInDisplay( 589 SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN); 590 return nativeScreenshot(displayToken, width, height, minLayer, maxLayer, false); 591 } 592 593 /** 594 * Like {@link SurfaceControl#screenshot(int, int, int, int)} but includes all 595 * Surfaces in the screenshot. 596 * 597 * @param width The desired width of the returned bitmap; the raw 598 * screen will be scaled down to this size. 599 * @param height The desired height of the returned bitmap; the raw 600 * screen will be scaled down to this size. 601 * @return Returns a Bitmap containing the screen contents, or null 602 * if an error occurs. Make sure to call Bitmap.recycle() as soon as 603 * possible, once its content is not needed anymore. 604 */ 605 public static Bitmap screenshot(int width, int height) { 606 // TODO: should take the display as a parameter 607 IBinder displayToken = SurfaceControl.getBuiltInDisplay( 608 SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN); 609 return nativeScreenshot(displayToken, width, height, 0, 0, true); 610 } 611 612 private static void screenshot(IBinder display, Surface consumer, 613 int width, int height, int minLayer, int maxLayer, boolean allLayers) { 614 if (display == null) { 615 throw new IllegalArgumentException("displayToken must not be null"); 616 } 617 if (consumer == null) { 618 throw new IllegalArgumentException("consumer must not be null"); 619 } 620 nativeScreenshot(display, consumer, width, height, minLayer, maxLayer, allLayers); 621 } 622 623 private static void checkHeadless() { 624 if (HEADLESS) { 625 throw new UnsupportedOperationException("Device is headless"); 626 } 627 } 628 } 629