android_view_SurfaceControl.cpp revision 6f7b58917104916ee6afd6f246c251c1d7a2102a
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#define LOG_TAG "SurfaceControl"
18
19#include <stdio.h>
20
21#include "jni.h"
22#include "JNIHelp.h"
23
24#include "android_os_Parcel.h"
25#include "android_util_Binder.h"
26#include "android/graphics/GraphicsJNI.h"
27#include "android/graphics/Region.h"
28
29#include <android_runtime/AndroidRuntime.h>
30#include <android_runtime/android_view_Surface.h>
31#include <android_runtime/android_view_SurfaceSession.h>
32
33#include <gui/Surface.h>
34#include <gui/SurfaceComposerClient.h>
35
36#include <ui/DisplayInfo.h>
37#include <ui/Rect.h>
38#include <ui/Region.h>
39
40#include <utils/Log.h>
41
42#include <ScopedUtfChars.h>
43
44// ----------------------------------------------------------------------------
45
46namespace android {
47
48static const char* const OutOfResourcesException =
49    "android/view/Surface$OutOfResourcesException";
50
51static struct {
52    jfieldID width;
53    jfieldID height;
54    jfieldID refreshRate;
55    jfieldID density;
56    jfieldID xDpi;
57    jfieldID yDpi;
58    jfieldID secure;
59} gPhysicalDisplayInfoClassInfo;
60
61
62class ScreenshotPixelRef : public SkPixelRef {
63public:
64    ScreenshotPixelRef(SkColorTable* ctable) {
65        fCTable = ctable;
66        SkSafeRef(ctable);
67        setImmutable();
68    }
69
70    virtual ~ScreenshotPixelRef() {
71        SkSafeUnref(fCTable);
72    }
73
74    status_t update(const sp<IBinder>& display, int width, int height,
75            int minLayer, int maxLayer, bool allLayers) {
76        status_t res = (width > 0 && height > 0)
77                ? (allLayers
78                        ? mScreenshot.update(display, width, height)
79                        : mScreenshot.update(display, width, height, minLayer, maxLayer))
80                : mScreenshot.update(display);
81        if (res != NO_ERROR) {
82            return res;
83        }
84
85        return NO_ERROR;
86    }
87
88    uint32_t getWidth() const {
89        return mScreenshot.getWidth();
90    }
91
92    uint32_t getHeight() const {
93        return mScreenshot.getHeight();
94    }
95
96    uint32_t getStride() const {
97        return mScreenshot.getStride();
98    }
99
100    uint32_t getFormat() const {
101        return mScreenshot.getFormat();
102    }
103
104protected:
105    // overrides from SkPixelRef
106    virtual void* onLockPixels(SkColorTable** ct) {
107        *ct = fCTable;
108        return (void*)mScreenshot.getPixels();
109    }
110
111    virtual void onUnlockPixels() {
112    }
113
114    SK_DECLARE_UNFLATTENABLE_OBJECT()
115private:
116    ScreenshotClient mScreenshot;
117    SkColorTable*    fCTable;
118
119    typedef SkPixelRef INHERITED;
120};
121
122
123// ----------------------------------------------------------------------------
124
125static jint nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
126        jstring nameStr, jint w, jint h, jint format, jint flags) {
127    ScopedUtfChars name(env, nameStr);
128    sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
129    sp<SurfaceControl> surface = client->createSurface(
130            String8(name.c_str()), w, h, format, flags);
131    if (surface == NULL) {
132        jniThrowException(env, OutOfResourcesException, NULL);
133        return 0;
134    }
135    surface->incStrong((void *)nativeCreate);
136    return int(surface.get());
137}
138
139static void nativeRelease(JNIEnv* env, jclass clazz, jint nativeObject) {
140    sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(nativeObject));
141    ctrl->decStrong((void *)nativeCreate);
142}
143
144static void nativeDestroy(JNIEnv* env, jclass clazz, jint nativeObject) {
145    sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(nativeObject));
146    ctrl->clear();
147    ctrl->decStrong((void *)nativeCreate);
148}
149
150static inline SkBitmap::Config convertPixelFormat(PixelFormat format) {
151    /* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then
152        we can map to SkBitmap::kARGB_8888_Config, and optionally call
153        bitmap.setIsOpaque(true) on the resulting SkBitmap (as an accelerator)
154    */
155    switch (format) {
156    case PIXEL_FORMAT_RGBX_8888:    return SkBitmap::kARGB_8888_Config;
157    case PIXEL_FORMAT_RGBA_8888:    return SkBitmap::kARGB_8888_Config;
158    case PIXEL_FORMAT_RGBA_4444:    return SkBitmap::kARGB_4444_Config;
159    case PIXEL_FORMAT_RGB_565:      return SkBitmap::kRGB_565_Config;
160    default:                        return SkBitmap::kNo_Config;
161    }
162}
163
164static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz, jobject displayTokenObj,
165        jint width, jint height, jint minLayer, jint maxLayer, bool allLayers) {
166    sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
167    if (displayToken == NULL) {
168        return NULL;
169    }
170
171    ScreenshotPixelRef* pixels = new ScreenshotPixelRef(NULL);
172    if (pixels->update(displayToken, width, height,
173            minLayer, maxLayer, allLayers) != NO_ERROR) {
174        delete pixels;
175        return NULL;
176    }
177
178    uint32_t w = pixels->getWidth();
179    uint32_t h = pixels->getHeight();
180    uint32_t s = pixels->getStride();
181    uint32_t f = pixels->getFormat();
182    ssize_t bpr = s * android::bytesPerPixel(f);
183
184    SkBitmap* bitmap = new SkBitmap();
185    bitmap->setConfig(convertPixelFormat(f), w, h, bpr);
186    if (f == PIXEL_FORMAT_RGBX_8888) {
187        bitmap->setIsOpaque(true);
188    }
189
190    if (w > 0 && h > 0) {
191        bitmap->setPixelRef(pixels)->unref();
192        bitmap->lockPixels();
193    } else {
194        // be safe with an empty bitmap.
195        delete pixels;
196        bitmap->setPixels(NULL);
197    }
198
199    return GraphicsJNI::createBitmap(env, bitmap, false, NULL);
200}
201
202static void nativeScreenshot(JNIEnv* env, jclass clazz,
203        jobject displayTokenObj, jobject surfaceObj,
204        jint width, jint height, jint minLayer, jint maxLayer, bool allLayers) {
205    sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
206    if (displayToken != NULL) {
207        sp<Surface> consumer = android_view_Surface_getSurface(env, surfaceObj);
208        if (consumer != NULL) {
209            if (allLayers) {
210                minLayer = 0;
211                maxLayer = -1;
212            }
213            ScreenshotClient::capture(
214                    displayToken, consumer->getIGraphicBufferProducer(),
215                    width, height, uint32_t(minLayer), uint32_t(maxLayer));
216        }
217    }
218}
219
220static void nativeOpenTransaction(JNIEnv* env, jclass clazz) {
221    SurfaceComposerClient::openGlobalTransaction();
222}
223
224static void nativeCloseTransaction(JNIEnv* env, jclass clazz) {
225    SurfaceComposerClient::closeGlobalTransaction();
226}
227
228static void nativeSetAnimationTransaction(JNIEnv* env, jclass clazz) {
229    SurfaceComposerClient::setAnimationTransaction();
230}
231
232static void nativeSetLayer(JNIEnv* env, jclass clazz, jint nativeObject, jint zorder) {
233    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
234    status_t err = ctrl->setLayer(zorder);
235    if (err < 0 && err != NO_INIT) {
236        doThrowIAE(env);
237    }
238}
239
240static void nativeSetPosition(JNIEnv* env, jclass clazz, jint nativeObject, jfloat x, jfloat y) {
241    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
242    status_t err = ctrl->setPosition(x, y);
243    if (err < 0 && err != NO_INIT) {
244        doThrowIAE(env);
245    }
246}
247
248static void nativeSetSize(JNIEnv* env, jclass clazz, jint nativeObject, jint w, jint h) {
249    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
250    status_t err = ctrl->setSize(w, h);
251    if (err < 0 && err != NO_INIT) {
252        doThrowIAE(env);
253    }
254}
255
256static void nativeSetFlags(JNIEnv* env, jclass clazz, jint nativeObject, jint flags, jint mask) {
257    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
258    status_t err = ctrl->setFlags(flags, mask);
259    if (err < 0 && err != NO_INIT) {
260        doThrowIAE(env);
261    }
262}
263
264static void nativeSetTransparentRegionHint(JNIEnv* env, jclass clazz, jint nativeObject, jobject regionObj) {
265    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
266    SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
267    if (!region) {
268        doThrowIAE(env);
269        return;
270    }
271
272    const SkIRect& b(region->getBounds());
273    Region reg(Rect(b.fLeft, b.fTop, b.fRight, b.fBottom));
274    if (region->isComplex()) {
275        SkRegion::Iterator it(*region);
276        while (!it.done()) {
277            const SkIRect& r(it.rect());
278            reg.addRectUnchecked(r.fLeft, r.fTop, r.fRight, r.fBottom);
279            it.next();
280        }
281    }
282
283    status_t err = ctrl->setTransparentRegionHint(reg);
284    if (err < 0 && err != NO_INIT) {
285        doThrowIAE(env);
286    }
287}
288
289static void nativeSetAlpha(JNIEnv* env, jclass clazz, jint nativeObject, jfloat alpha) {
290    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
291    status_t err = ctrl->setAlpha(alpha);
292    if (err < 0 && err != NO_INIT) {
293        doThrowIAE(env);
294    }
295}
296
297static void nativeSetMatrix(JNIEnv* env, jclass clazz, jint nativeObject,
298        jfloat dsdx, jfloat dtdx, jfloat dsdy, jfloat dtdy) {
299    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
300    status_t err = ctrl->setMatrix(dsdx, dtdx, dsdy, dtdy);
301    if (err < 0 && err != NO_INIT) {
302        doThrowIAE(env);
303    }
304}
305
306static void nativeSetWindowCrop(JNIEnv* env, jclass clazz, jint nativeObject,
307        jint l, jint t, jint r, jint b) {
308    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
309    Rect crop(l, t, r, b);
310    status_t err = ctrl->setCrop(crop);
311    if (err < 0 && err != NO_INIT) {
312        doThrowIAE(env);
313    }
314}
315
316static void nativeSetLayerStack(JNIEnv* env, jclass clazz, jint nativeObject, jint layerStack) {
317    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
318    status_t err = ctrl->setLayerStack(layerStack);
319    if (err < 0 && err != NO_INIT) {
320        doThrowIAE(env);
321    }
322}
323
324static jobject nativeGetBuiltInDisplay(JNIEnv* env, jclass clazz, jint id) {
325    sp<IBinder> token(SurfaceComposerClient::getBuiltInDisplay(id));
326    return javaObjectForIBinder(env, token);
327}
328
329static jobject nativeCreateDisplay(JNIEnv* env, jclass clazz, jstring nameObj,
330        jboolean secure) {
331    ScopedUtfChars name(env, nameObj);
332    sp<IBinder> token(SurfaceComposerClient::createDisplay(
333            String8(name.c_str()), bool(secure)));
334    return javaObjectForIBinder(env, token);
335}
336
337static void nativeSetDisplaySurface(JNIEnv* env, jclass clazz,
338        jobject tokenObj, jint nativeSurfaceObject) {
339    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
340    if (token == NULL) return;
341    sp<IGraphicBufferProducer> bufferProducer;
342    sp<Surface> sur(reinterpret_cast<Surface *>(nativeSurfaceObject));
343    if (sur != NULL) {
344        bufferProducer = sur->getIGraphicBufferProducer();
345    }
346    SurfaceComposerClient::setDisplaySurface(token, bufferProducer);
347}
348
349static void nativeSetDisplayLayerStack(JNIEnv* env, jclass clazz,
350        jobject tokenObj, jint layerStack) {
351    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
352    if (token == NULL) return;
353
354    SurfaceComposerClient::setDisplayLayerStack(token, layerStack);
355}
356
357static void nativeSetDisplayProjection(JNIEnv* env, jclass clazz,
358        jobject tokenObj, jint orientation,
359        jint layerStackRect_left, jint layerStackRect_top, jint layerStackRect_right, jint layerStackRect_bottom,
360        jint displayRect_left, jint displayRect_top, jint displayRect_right, jint displayRect_bottom) {
361    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
362    if (token == NULL) return;
363    Rect layerStackRect(layerStackRect_left, layerStackRect_top, layerStackRect_right, layerStackRect_bottom);
364    Rect displayRect(displayRect_left, displayRect_top, displayRect_right, displayRect_bottom);
365    SurfaceComposerClient::setDisplayProjection(token, orientation, layerStackRect, displayRect);
366}
367
368static jboolean nativeGetDisplayInfo(JNIEnv* env, jclass clazz,
369        jobject tokenObj, jobject infoObj) {
370    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
371    if (token == NULL) return JNI_FALSE;
372
373    DisplayInfo info;
374    if (SurfaceComposerClient::getDisplayInfo(token, &info)) {
375        return JNI_FALSE;
376    }
377
378    env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.width, info.w);
379    env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.height, info.h);
380    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.refreshRate, info.fps);
381    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.density, info.density);
382    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.xDpi, info.xdpi);
383    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.yDpi, info.ydpi);
384    env->SetBooleanField(infoObj, gPhysicalDisplayInfoClassInfo.secure, info.secure);
385    return JNI_TRUE;
386}
387
388static void nativeBlankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
389    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
390    if (token == NULL) return;
391
392    ALOGD_IF_SLOW(100, "Excessive delay in blankDisplay() while turning screen off");
393    SurfaceComposerClient::blankDisplay(token);
394}
395
396static void nativeUnblankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
397    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
398    if (token == NULL) return;
399
400    ALOGD_IF_SLOW(100, "Excessive delay in unblankDisplay() while turning screen on");
401    SurfaceComposerClient::unblankDisplay(token);
402}
403
404// ----------------------------------------------------------------------------
405
406static JNINativeMethod sSurfaceControlMethods[] = {
407    {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIII)I",
408            (void*)nativeCreate },
409    {"nativeRelease", "(I)V",
410            (void*)nativeRelease },
411    {"nativeDestroy", "(I)V",
412            (void*)nativeDestroy },
413    {"nativeScreenshot", "(Landroid/os/IBinder;IIIIZ)Landroid/graphics/Bitmap;",
414            (void*)nativeScreenshotBitmap },
415    {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/view/Surface;IIIIZ)V",
416            (void*)nativeScreenshot },
417    {"nativeOpenTransaction", "()V",
418            (void*)nativeOpenTransaction },
419    {"nativeCloseTransaction", "()V",
420            (void*)nativeCloseTransaction },
421    {"nativeSetAnimationTransaction", "()V",
422            (void*)nativeSetAnimationTransaction },
423    {"nativeSetLayer", "(II)V",
424            (void*)nativeSetLayer },
425    {"nativeSetPosition", "(IFF)V",
426            (void*)nativeSetPosition },
427    {"nativeSetSize", "(III)V",
428            (void*)nativeSetSize },
429    {"nativeSetTransparentRegionHint", "(ILandroid/graphics/Region;)V",
430            (void*)nativeSetTransparentRegionHint },
431    {"nativeSetAlpha", "(IF)V",
432            (void*)nativeSetAlpha },
433    {"nativeSetMatrix", "(IFFFF)V",
434            (void*)nativeSetMatrix },
435    {"nativeSetFlags", "(III)V",
436            (void*)nativeSetFlags },
437    {"nativeSetWindowCrop", "(IIIII)V",
438            (void*)nativeSetWindowCrop },
439    {"nativeSetLayerStack", "(II)V",
440            (void*)nativeSetLayerStack },
441    {"nativeGetBuiltInDisplay", "(I)Landroid/os/IBinder;",
442            (void*)nativeGetBuiltInDisplay },
443    {"nativeCreateDisplay", "(Ljava/lang/String;Z)Landroid/os/IBinder;",
444            (void*)nativeCreateDisplay },
445    {"nativeSetDisplaySurface", "(Landroid/os/IBinder;I)V",
446            (void*)nativeSetDisplaySurface },
447    {"nativeSetDisplayLayerStack", "(Landroid/os/IBinder;I)V",
448            (void*)nativeSetDisplayLayerStack },
449    {"nativeSetDisplayProjection", "(Landroid/os/IBinder;IIIIIIIII)V",
450            (void*)nativeSetDisplayProjection },
451    {"nativeGetDisplayInfo", "(Landroid/os/IBinder;Landroid/view/SurfaceControl$PhysicalDisplayInfo;)Z",
452            (void*)nativeGetDisplayInfo },
453    {"nativeBlankDisplay", "(Landroid/os/IBinder;)V",
454            (void*)nativeBlankDisplay },
455    {"nativeUnblankDisplay", "(Landroid/os/IBinder;)V",
456            (void*)nativeUnblankDisplay },
457};
458
459int register_android_view_SurfaceControl(JNIEnv* env)
460{
461    int err = AndroidRuntime::registerNativeMethods(env, "android/view/SurfaceControl",
462            sSurfaceControlMethods, NELEM(sSurfaceControlMethods));
463
464    jclass clazz = env->FindClass("android/view/SurfaceControl$PhysicalDisplayInfo");
465    gPhysicalDisplayInfoClassInfo.width = env->GetFieldID(clazz, "width", "I");
466    gPhysicalDisplayInfoClassInfo.height = env->GetFieldID(clazz, "height", "I");
467    gPhysicalDisplayInfoClassInfo.refreshRate = env->GetFieldID(clazz, "refreshRate", "F");
468    gPhysicalDisplayInfoClassInfo.density = env->GetFieldID(clazz, "density", "F");
469    gPhysicalDisplayInfoClassInfo.xDpi = env->GetFieldID(clazz, "xDpi", "F");
470    gPhysicalDisplayInfoClassInfo.yDpi = env->GetFieldID(clazz, "yDpi", "F");
471    gPhysicalDisplayInfoClassInfo.secure = env->GetFieldID(clazz, "secure", "Z");
472    return err;
473}
474
475};
476