android_view_SurfaceControl.cpp revision b251f3d0c619c37cc4e4b8d9f8b95eb377423190
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_RGB_565:      return SkBitmap::kRGB_565_Config;
159    default:                        return SkBitmap::kNo_Config;
160    }
161}
162
163static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz, jobject displayTokenObj,
164        jint width, jint height, jint minLayer, jint maxLayer, bool allLayers) {
165    sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
166    if (displayToken == NULL) {
167        return NULL;
168    }
169
170    ScreenshotPixelRef* pixels = new ScreenshotPixelRef(NULL);
171    if (pixels->update(displayToken, width, height,
172            minLayer, maxLayer, allLayers) != NO_ERROR) {
173        delete pixels;
174        return NULL;
175    }
176
177    uint32_t w = pixels->getWidth();
178    uint32_t h = pixels->getHeight();
179    uint32_t s = pixels->getStride();
180    uint32_t f = pixels->getFormat();
181    ssize_t bpr = s * android::bytesPerPixel(f);
182
183    SkBitmap* bitmap = new SkBitmap();
184    bitmap->setConfig(convertPixelFormat(f), w, h, bpr);
185    if (f == PIXEL_FORMAT_RGBX_8888) {
186        bitmap->setIsOpaque(true);
187    }
188
189    if (w > 0 && h > 0) {
190        bitmap->setPixelRef(pixels)->unref();
191        bitmap->lockPixels();
192    } else {
193        // be safe with an empty bitmap.
194        delete pixels;
195        bitmap->setPixels(NULL);
196    }
197
198    return GraphicsJNI::createBitmap(env, bitmap, false, NULL);
199}
200
201static void nativeScreenshot(JNIEnv* env, jclass clazz,
202        jobject displayTokenObj, jobject surfaceObj,
203        jint width, jint height, jint minLayer, jint maxLayer, bool allLayers) {
204    sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
205    if (displayToken != NULL) {
206        sp<Surface> consumer = android_view_Surface_getSurface(env, surfaceObj);
207        if (consumer != NULL) {
208            if (allLayers) {
209                minLayer = 0;
210                maxLayer = -1;
211            }
212            ScreenshotClient::capture(
213                    displayToken, consumer->getIGraphicBufferProducer(),
214                    width, height, uint32_t(minLayer), uint32_t(maxLayer));
215        }
216    }
217}
218
219static void nativeOpenTransaction(JNIEnv* env, jclass clazz) {
220    SurfaceComposerClient::openGlobalTransaction();
221}
222
223static void nativeCloseTransaction(JNIEnv* env, jclass clazz) {
224    SurfaceComposerClient::closeGlobalTransaction();
225}
226
227static void nativeSetAnimationTransaction(JNIEnv* env, jclass clazz) {
228    SurfaceComposerClient::setAnimationTransaction();
229}
230
231static void nativeSetLayer(JNIEnv* env, jclass clazz, jint nativeObject, jint zorder) {
232    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
233    status_t err = ctrl->setLayer(zorder);
234    if (err < 0 && err != NO_INIT) {
235        doThrowIAE(env);
236    }
237}
238
239static void nativeSetPosition(JNIEnv* env, jclass clazz, jint nativeObject, jfloat x, jfloat y) {
240    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
241    status_t err = ctrl->setPosition(x, y);
242    if (err < 0 && err != NO_INIT) {
243        doThrowIAE(env);
244    }
245}
246
247static void nativeSetSize(JNIEnv* env, jclass clazz, jint nativeObject, jint w, jint h) {
248    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
249    status_t err = ctrl->setSize(w, h);
250    if (err < 0 && err != NO_INIT) {
251        doThrowIAE(env);
252    }
253}
254
255static void nativeSetFlags(JNIEnv* env, jclass clazz, jint nativeObject, jint flags, jint mask) {
256    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
257    status_t err = ctrl->setFlags(flags, mask);
258    if (err < 0 && err != NO_INIT) {
259        doThrowIAE(env);
260    }
261}
262
263static void nativeSetTransparentRegionHint(JNIEnv* env, jclass clazz, jint nativeObject, jobject regionObj) {
264    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
265    SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
266    if (!region) {
267        doThrowIAE(env);
268        return;
269    }
270
271    const SkIRect& b(region->getBounds());
272    Region reg(Rect(b.fLeft, b.fTop, b.fRight, b.fBottom));
273    if (region->isComplex()) {
274        SkRegion::Iterator it(*region);
275        while (!it.done()) {
276            const SkIRect& r(it.rect());
277            reg.addRectUnchecked(r.fLeft, r.fTop, r.fRight, r.fBottom);
278            it.next();
279        }
280    }
281
282    status_t err = ctrl->setTransparentRegionHint(reg);
283    if (err < 0 && err != NO_INIT) {
284        doThrowIAE(env);
285    }
286}
287
288static void nativeSetAlpha(JNIEnv* env, jclass clazz, jint nativeObject, jfloat alpha) {
289    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
290    status_t err = ctrl->setAlpha(alpha);
291    if (err < 0 && err != NO_INIT) {
292        doThrowIAE(env);
293    }
294}
295
296static void nativeSetMatrix(JNIEnv* env, jclass clazz, jint nativeObject,
297        jfloat dsdx, jfloat dtdx, jfloat dsdy, jfloat dtdy) {
298    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
299    status_t err = ctrl->setMatrix(dsdx, dtdx, dsdy, dtdy);
300    if (err < 0 && err != NO_INIT) {
301        doThrowIAE(env);
302    }
303}
304
305static void nativeSetWindowCrop(JNIEnv* env, jclass clazz, jint nativeObject,
306        jint l, jint t, jint r, jint b) {
307    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
308    Rect crop(l, t, r, b);
309    status_t err = ctrl->setCrop(crop);
310    if (err < 0 && err != NO_INIT) {
311        doThrowIAE(env);
312    }
313}
314
315static void nativeSetLayerStack(JNIEnv* env, jclass clazz, jint nativeObject, jint layerStack) {
316    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
317    status_t err = ctrl->setLayerStack(layerStack);
318    if (err < 0 && err != NO_INIT) {
319        doThrowIAE(env);
320    }
321}
322
323static jobject nativeGetBuiltInDisplay(JNIEnv* env, jclass clazz, jint id) {
324    sp<IBinder> token(SurfaceComposerClient::getBuiltInDisplay(id));
325    return javaObjectForIBinder(env, token);
326}
327
328static jobject nativeCreateDisplay(JNIEnv* env, jclass clazz, jstring nameObj,
329        jboolean secure) {
330    ScopedUtfChars name(env, nameObj);
331    sp<IBinder> token(SurfaceComposerClient::createDisplay(
332            String8(name.c_str()), bool(secure)));
333    return javaObjectForIBinder(env, token);
334}
335
336static void nativeSetDisplaySurface(JNIEnv* env, jclass clazz,
337        jobject tokenObj, jint nativeSurfaceObject) {
338    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
339    if (token == NULL) return;
340    sp<IGraphicBufferProducer> bufferProducer;
341    sp<Surface> sur(reinterpret_cast<Surface *>(nativeSurfaceObject));
342    if (sur != NULL) {
343        bufferProducer = sur->getIGraphicBufferProducer();
344    }
345    SurfaceComposerClient::setDisplaySurface(token, bufferProducer);
346}
347
348static void nativeSetDisplayLayerStack(JNIEnv* env, jclass clazz,
349        jobject tokenObj, jint layerStack) {
350    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
351    if (token == NULL) return;
352
353    SurfaceComposerClient::setDisplayLayerStack(token, layerStack);
354}
355
356static void nativeSetDisplayProjection(JNIEnv* env, jclass clazz,
357        jobject tokenObj, jint orientation,
358        jint layerStackRect_left, jint layerStackRect_top, jint layerStackRect_right, jint layerStackRect_bottom,
359        jint displayRect_left, jint displayRect_top, jint displayRect_right, jint displayRect_bottom) {
360    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
361    if (token == NULL) return;
362    Rect layerStackRect(layerStackRect_left, layerStackRect_top, layerStackRect_right, layerStackRect_bottom);
363    Rect displayRect(displayRect_left, displayRect_top, displayRect_right, displayRect_bottom);
364    SurfaceComposerClient::setDisplayProjection(token, orientation, layerStackRect, displayRect);
365}
366
367static jboolean nativeGetDisplayInfo(JNIEnv* env, jclass clazz,
368        jobject tokenObj, jobject infoObj) {
369    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
370    if (token == NULL) return JNI_FALSE;
371
372    DisplayInfo info;
373    if (SurfaceComposerClient::getDisplayInfo(token, &info)) {
374        return JNI_FALSE;
375    }
376
377    env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.width, info.w);
378    env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.height, info.h);
379    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.refreshRate, info.fps);
380    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.density, info.density);
381    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.xDpi, info.xdpi);
382    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.yDpi, info.ydpi);
383    env->SetBooleanField(infoObj, gPhysicalDisplayInfoClassInfo.secure, info.secure);
384    return JNI_TRUE;
385}
386
387static void nativeBlankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
388    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
389    if (token == NULL) return;
390
391    ALOGD_IF_SLOW(100, "Excessive delay in blankDisplay() while turning screen off");
392    SurfaceComposerClient::blankDisplay(token);
393}
394
395static void nativeUnblankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
396    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
397    if (token == NULL) return;
398
399    ALOGD_IF_SLOW(100, "Excessive delay in unblankDisplay() while turning screen on");
400    SurfaceComposerClient::unblankDisplay(token);
401}
402
403// ----------------------------------------------------------------------------
404
405static JNINativeMethod sSurfaceControlMethods[] = {
406    {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIII)I",
407            (void*)nativeCreate },
408    {"nativeRelease", "(I)V",
409            (void*)nativeRelease },
410    {"nativeDestroy", "(I)V",
411            (void*)nativeDestroy },
412    {"nativeScreenshot", "(Landroid/os/IBinder;IIIIZ)Landroid/graphics/Bitmap;",
413            (void*)nativeScreenshotBitmap },
414    {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/view/Surface;IIIIZ)V",
415            (void*)nativeScreenshot },
416    {"nativeOpenTransaction", "()V",
417            (void*)nativeOpenTransaction },
418    {"nativeCloseTransaction", "()V",
419            (void*)nativeCloseTransaction },
420    {"nativeSetAnimationTransaction", "()V",
421            (void*)nativeSetAnimationTransaction },
422    {"nativeSetLayer", "(II)V",
423            (void*)nativeSetLayer },
424    {"nativeSetPosition", "(IFF)V",
425            (void*)nativeSetPosition },
426    {"nativeSetSize", "(III)V",
427            (void*)nativeSetSize },
428    {"nativeSetTransparentRegionHint", "(ILandroid/graphics/Region;)V",
429            (void*)nativeSetTransparentRegionHint },
430    {"nativeSetAlpha", "(IF)V",
431            (void*)nativeSetAlpha },
432    {"nativeSetMatrix", "(IFFFF)V",
433            (void*)nativeSetMatrix },
434    {"nativeSetFlags", "(III)V",
435            (void*)nativeSetFlags },
436    {"nativeSetWindowCrop", "(IIIII)V",
437            (void*)nativeSetWindowCrop },
438    {"nativeSetLayerStack", "(II)V",
439            (void*)nativeSetLayerStack },
440    {"nativeGetBuiltInDisplay", "(I)Landroid/os/IBinder;",
441            (void*)nativeGetBuiltInDisplay },
442    {"nativeCreateDisplay", "(Ljava/lang/String;Z)Landroid/os/IBinder;",
443            (void*)nativeCreateDisplay },
444    {"nativeSetDisplaySurface", "(Landroid/os/IBinder;I)V",
445            (void*)nativeSetDisplaySurface },
446    {"nativeSetDisplayLayerStack", "(Landroid/os/IBinder;I)V",
447            (void*)nativeSetDisplayLayerStack },
448    {"nativeSetDisplayProjection", "(Landroid/os/IBinder;IIIIIIIII)V",
449            (void*)nativeSetDisplayProjection },
450    {"nativeGetDisplayInfo", "(Landroid/os/IBinder;Landroid/view/SurfaceControl$PhysicalDisplayInfo;)Z",
451            (void*)nativeGetDisplayInfo },
452    {"nativeBlankDisplay", "(Landroid/os/IBinder;)V",
453            (void*)nativeBlankDisplay },
454    {"nativeUnblankDisplay", "(Landroid/os/IBinder;)V",
455            (void*)nativeUnblankDisplay },
456};
457
458int register_android_view_SurfaceControl(JNIEnv* env)
459{
460    int err = AndroidRuntime::registerNativeMethods(env, "android/view/SurfaceControl",
461            sSurfaceControlMethods, NELEM(sSurfaceControlMethods));
462
463    jclass clazz = env->FindClass("android/view/SurfaceControl$PhysicalDisplayInfo");
464    gPhysicalDisplayInfoClassInfo.width = env->GetFieldID(clazz, "width", "I");
465    gPhysicalDisplayInfoClassInfo.height = env->GetFieldID(clazz, "height", "I");
466    gPhysicalDisplayInfoClassInfo.refreshRate = env->GetFieldID(clazz, "refreshRate", "F");
467    gPhysicalDisplayInfoClassInfo.density = env->GetFieldID(clazz, "density", "F");
468    gPhysicalDisplayInfoClassInfo.xDpi = env->GetFieldID(clazz, "xDpi", "F");
469    gPhysicalDisplayInfoClassInfo.yDpi = env->GetFieldID(clazz, "yDpi", "F");
470    gPhysicalDisplayInfoClassInfo.secure = env->GetFieldID(clazz, "secure", "Z");
471    return err;
472}
473
474};
475