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