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