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,
199            GraphicsJNI::kBitmapCreateFlag_Premultiplied, 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 nativeDestroyDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
338    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
339    if (token == NULL) return;
340    SurfaceComposerClient::destroyDisplay(token);
341}
342
343static void nativeSetDisplaySurface(JNIEnv* env, jclass clazz,
344        jobject tokenObj, jint nativeSurfaceObject) {
345    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
346    if (token == NULL) return;
347    sp<IGraphicBufferProducer> bufferProducer;
348    sp<Surface> sur(reinterpret_cast<Surface *>(nativeSurfaceObject));
349    if (sur != NULL) {
350        bufferProducer = sur->getIGraphicBufferProducer();
351    }
352    SurfaceComposerClient::setDisplaySurface(token, bufferProducer);
353}
354
355static void nativeSetDisplayLayerStack(JNIEnv* env, jclass clazz,
356        jobject tokenObj, jint layerStack) {
357    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
358    if (token == NULL) return;
359
360    SurfaceComposerClient::setDisplayLayerStack(token, layerStack);
361}
362
363static void nativeSetDisplayProjection(JNIEnv* env, jclass clazz,
364        jobject tokenObj, jint orientation,
365        jint layerStackRect_left, jint layerStackRect_top, jint layerStackRect_right, jint layerStackRect_bottom,
366        jint displayRect_left, jint displayRect_top, jint displayRect_right, jint displayRect_bottom) {
367    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
368    if (token == NULL) return;
369    Rect layerStackRect(layerStackRect_left, layerStackRect_top, layerStackRect_right, layerStackRect_bottom);
370    Rect displayRect(displayRect_left, displayRect_top, displayRect_right, displayRect_bottom);
371    SurfaceComposerClient::setDisplayProjection(token, orientation, layerStackRect, displayRect);
372}
373
374static jboolean nativeGetDisplayInfo(JNIEnv* env, jclass clazz,
375        jobject tokenObj, jobject infoObj) {
376    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
377    if (token == NULL) return JNI_FALSE;
378
379    DisplayInfo info;
380    if (SurfaceComposerClient::getDisplayInfo(token, &info)) {
381        return JNI_FALSE;
382    }
383
384    env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.width, info.w);
385    env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.height, info.h);
386    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.refreshRate, info.fps);
387    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.density, info.density);
388    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.xDpi, info.xdpi);
389    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.yDpi, info.ydpi);
390    env->SetBooleanField(infoObj, gPhysicalDisplayInfoClassInfo.secure, info.secure);
391    return JNI_TRUE;
392}
393
394static void nativeBlankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
395    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
396    if (token == NULL) return;
397
398    ALOGD_IF_SLOW(100, "Excessive delay in blankDisplay() while turning screen off");
399    SurfaceComposerClient::blankDisplay(token);
400}
401
402static void nativeUnblankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
403    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
404    if (token == NULL) return;
405
406    ALOGD_IF_SLOW(100, "Excessive delay in unblankDisplay() while turning screen on");
407    SurfaceComposerClient::unblankDisplay(token);
408}
409
410// ----------------------------------------------------------------------------
411
412static JNINativeMethod sSurfaceControlMethods[] = {
413    {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIII)I",
414            (void*)nativeCreate },
415    {"nativeRelease", "(I)V",
416            (void*)nativeRelease },
417    {"nativeDestroy", "(I)V",
418            (void*)nativeDestroy },
419    {"nativeScreenshot", "(Landroid/os/IBinder;IIIIZ)Landroid/graphics/Bitmap;",
420            (void*)nativeScreenshotBitmap },
421    {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/view/Surface;IIIIZ)V",
422            (void*)nativeScreenshot },
423    {"nativeOpenTransaction", "()V",
424            (void*)nativeOpenTransaction },
425    {"nativeCloseTransaction", "()V",
426            (void*)nativeCloseTransaction },
427    {"nativeSetAnimationTransaction", "()V",
428            (void*)nativeSetAnimationTransaction },
429    {"nativeSetLayer", "(II)V",
430            (void*)nativeSetLayer },
431    {"nativeSetPosition", "(IFF)V",
432            (void*)nativeSetPosition },
433    {"nativeSetSize", "(III)V",
434            (void*)nativeSetSize },
435    {"nativeSetTransparentRegionHint", "(ILandroid/graphics/Region;)V",
436            (void*)nativeSetTransparentRegionHint },
437    {"nativeSetAlpha", "(IF)V",
438            (void*)nativeSetAlpha },
439    {"nativeSetMatrix", "(IFFFF)V",
440            (void*)nativeSetMatrix },
441    {"nativeSetFlags", "(III)V",
442            (void*)nativeSetFlags },
443    {"nativeSetWindowCrop", "(IIIII)V",
444            (void*)nativeSetWindowCrop },
445    {"nativeSetLayerStack", "(II)V",
446            (void*)nativeSetLayerStack },
447    {"nativeGetBuiltInDisplay", "(I)Landroid/os/IBinder;",
448            (void*)nativeGetBuiltInDisplay },
449    {"nativeCreateDisplay", "(Ljava/lang/String;Z)Landroid/os/IBinder;",
450            (void*)nativeCreateDisplay },
451    {"nativeDestroyDisplay", "(Landroid/os/IBinder;)V",
452            (void*)nativeDestroyDisplay },
453    {"nativeSetDisplaySurface", "(Landroid/os/IBinder;I)V",
454            (void*)nativeSetDisplaySurface },
455    {"nativeSetDisplayLayerStack", "(Landroid/os/IBinder;I)V",
456            (void*)nativeSetDisplayLayerStack },
457    {"nativeSetDisplayProjection", "(Landroid/os/IBinder;IIIIIIIII)V",
458            (void*)nativeSetDisplayProjection },
459    {"nativeGetDisplayInfo", "(Landroid/os/IBinder;Landroid/view/SurfaceControl$PhysicalDisplayInfo;)Z",
460            (void*)nativeGetDisplayInfo },
461    {"nativeBlankDisplay", "(Landroid/os/IBinder;)V",
462            (void*)nativeBlankDisplay },
463    {"nativeUnblankDisplay", "(Landroid/os/IBinder;)V",
464            (void*)nativeUnblankDisplay },
465};
466
467int register_android_view_SurfaceControl(JNIEnv* env)
468{
469    int err = AndroidRuntime::registerNativeMethods(env, "android/view/SurfaceControl",
470            sSurfaceControlMethods, NELEM(sSurfaceControlMethods));
471
472    jclass clazz = env->FindClass("android/view/SurfaceControl$PhysicalDisplayInfo");
473    gPhysicalDisplayInfoClassInfo.width = env->GetFieldID(clazz, "width", "I");
474    gPhysicalDisplayInfoClassInfo.height = env->GetFieldID(clazz, "height", "I");
475    gPhysicalDisplayInfoClassInfo.refreshRate = env->GetFieldID(clazz, "refreshRate", "F");
476    gPhysicalDisplayInfoClassInfo.density = env->GetFieldID(clazz, "density", "F");
477    gPhysicalDisplayInfoClassInfo.xDpi = env->GetFieldID(clazz, "xDpi", "F");
478    gPhysicalDisplayInfoClassInfo.yDpi = env->GetFieldID(clazz, "yDpi", "F");
479    gPhysicalDisplayInfoClassInfo.secure = env->GetFieldID(clazz, "secure", "Z");
480    return err;
481}
482
483};
484