blob: 6b530ef343a5545a006bf9f990b653fc2912073b [file] [log] [blame]
Mathias Agopian3866f0d2013-02-11 22:08:48 -08001/*
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
17package android.view;
18
19import dalvik.system.CloseGuard;
20import android.graphics.Bitmap;
21import android.graphics.Rect;
22import android.graphics.Region;
Mathias Agopian0449a402013-03-01 23:01:51 -080023import android.view.Surface;
Mathias Agopian3866f0d2013-02-11 22:08:48 -080024import android.os.IBinder;
25import android.os.SystemProperties;
26import android.util.Log;
27
28/**
29 * SurfaceControl
30 * @hide
31 */
32public class SurfaceControl {
33 private static final String TAG = "SurfaceControl";
Mathias Agopian29479eb2013-02-14 14:36:04 -080034
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);
Mathias Agopian0449a402013-03-01 23:01:51 -080043 private static native void nativeScreenshot(IBinder displayToken, Surface consumer,
44 int width, int height, int minLayer, int maxLayer, boolean allLayers);
Mathias Agopian29479eb2013-02-14 14:36:04 -080045
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
Mathias Agopian3866f0d2013-02-11 22:08:48 -080076 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 /**
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800162 * 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 /**
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800171 * 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
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800329 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 }
Jeff Brownfc0ebd72013-04-30 16:33:00 -0700499
500 if (surface != null) {
501 synchronized (surface.mLock) {
502 nativeSetDisplaySurface(displayToken, surface.mNativeObject);
503 }
504 } else {
505 nativeSetDisplaySurface(displayToken, 0);
506 }
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800507 }
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
Mathias Agopian0449a402013-03-01 23:01:51 -0800520
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
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800566 /**
567 * Copy the current screen contents into a bitmap and return it.
568 *
Mathias Agopian0449a402013-03-01 23:01:51 -0800569 * 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 *
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800574 * @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
Mathias Agopian49ff2c62013-03-17 01:05:21 -0700583 * if an error occurs. Make sure to call Bitmap.recycle() as soon as
584 * possible, once its content is not needed anymore.
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800585 */
586 public static Bitmap screenshot(int width, int height, int minLayer, int maxLayer) {
587 // TODO: should take the display as a parameter
Mathias Agopian0449a402013-03-01 23:01:51 -0800588 IBinder displayToken = SurfaceControl.getBuiltInDisplay(
589 SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN);
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800590 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.
Mathias Agopian49ff2c62013-03-17 01:05:21 -0700596 *
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.
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800604 */
605 public static Bitmap screenshot(int width, int height) {
606 // TODO: should take the display as a parameter
Mathias Agopian0449a402013-03-01 23:01:51 -0800607 IBinder displayToken = SurfaceControl.getBuiltInDisplay(
608 SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN);
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800609 return nativeScreenshot(displayToken, width, height, 0, 0, true);
610 }
611
Mathias Agopian0449a402013-03-01 23:01:51 -0800612 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
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800623 private static void checkHeadless() {
624 if (HEADLESS) {
625 throw new UnsupportedOperationException("Device is headless");
626 }
627 }
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800628}