android_view_Surface.cpp revision 64a55af0ac700baecb0877235eb42caac59a3560
1/*
2 * Copyright (C) 2007 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 "Surface"
18
19#include <stdio.h>
20
21#include "android_os_Parcel.h"
22#include "android_util_Binder.h"
23#include "android/graphics/GraphicsJNI.h"
24#include "android/graphics/Region.h"
25
26#include <binder/IMemory.h>
27
28#include <gui/ISurfaceComposer.h>
29#include <gui/Surface.h>
30#include <gui/SurfaceComposerClient.h>
31#include <gui/SurfaceTexture.h>
32
33#include <ui/DisplayInfo.h>
34#include <ui/Rect.h>
35#include <ui/Region.h>
36
37#include <EGL/egl.h>
38
39#include <SkCanvas.h>
40#include <SkBitmap.h>
41#include <SkRegion.h>
42#include <SkPixelRef.h>
43
44#include "jni.h"
45#include "JNIHelp.h"
46#include <android_runtime/AndroidRuntime.h>
47#include <android_runtime/android_view_Surface.h>
48#include <android_runtime/android_view_SurfaceSession.h>
49#include <android_runtime/android_graphics_SurfaceTexture.h>
50#include <utils/misc.h>
51
52#include <ScopedUtfChars.h>
53
54
55// ----------------------------------------------------------------------------
56
57namespace android {
58
59static const char* const OutOfResourcesException =
60    "android/view/Surface$OutOfResourcesException";
61
62static struct {
63    jclass clazz;
64    jfieldID mNativeSurface;
65    jfieldID mNativeSurfaceControl;
66    jfieldID mGenerationId;
67    jfieldID mCanvas;
68    jfieldID mCanvasSaveCount;
69} gSurfaceClassInfo;
70
71static struct {
72    jfieldID left;
73    jfieldID top;
74    jfieldID right;
75    jfieldID bottom;
76} gRectClassInfo;
77
78static struct {
79    jfieldID mNativeCanvas;
80    jfieldID mSurfaceFormat;
81} gCanvasClassInfo;
82
83static struct {
84    jfieldID width;
85    jfieldID height;
86    jfieldID refreshRate;
87    jfieldID density;
88    jfieldID xDpi;
89    jfieldID yDpi;
90} gPhysicalDisplayInfoClassInfo;
91
92
93class ScreenshotPixelRef : public SkPixelRef {
94public:
95    ScreenshotPixelRef(SkColorTable* ctable) {
96        fCTable = ctable;
97        SkSafeRef(ctable);
98        setImmutable();
99    }
100
101    virtual ~ScreenshotPixelRef() {
102        SkSafeUnref(fCTable);
103    }
104
105    status_t update(const sp<IBinder>& display, int width, int height,
106            int minLayer, int maxLayer, bool allLayers) {
107        status_t res = (width > 0 && height > 0)
108                ? (allLayers
109                        ? mScreenshot.update(display, width, height)
110                        : mScreenshot.update(display, width, height, minLayer, maxLayer))
111                : mScreenshot.update(display);
112        if (res != NO_ERROR) {
113            return res;
114        }
115
116        return NO_ERROR;
117    }
118
119    uint32_t getWidth() const {
120        return mScreenshot.getWidth();
121    }
122
123    uint32_t getHeight() const {
124        return mScreenshot.getHeight();
125    }
126
127    uint32_t getStride() const {
128        return mScreenshot.getStride();
129    }
130
131    uint32_t getFormat() const {
132        return mScreenshot.getFormat();
133    }
134
135protected:
136    // overrides from SkPixelRef
137    virtual void* onLockPixels(SkColorTable** ct) {
138        *ct = fCTable;
139        return (void*)mScreenshot.getPixels();
140    }
141
142    virtual void onUnlockPixels() {
143    }
144
145private:
146    ScreenshotClient mScreenshot;
147    SkColorTable*    fCTable;
148
149    typedef SkPixelRef INHERITED;
150};
151
152
153// ----------------------------------------------------------------------------
154
155static sp<SurfaceControl> getSurfaceControl(JNIEnv* env, jobject surfaceObj) {
156    return reinterpret_cast<SurfaceControl*>(
157            env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurfaceControl));
158}
159
160static void setSurfaceControl(JNIEnv* env, jobject surfaceObj,
161        const sp<SurfaceControl>& surface) {
162    SurfaceControl* const p = reinterpret_cast<SurfaceControl*>(
163            env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurfaceControl));
164    if (surface.get()) {
165        surface->incStrong(surfaceObj);
166    }
167    if (p) {
168        p->decStrong(surfaceObj);
169    }
170    env->SetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurfaceControl,
171            reinterpret_cast<jint>(surface.get()));
172}
173
174static sp<Surface> getSurface(JNIEnv* env, jobject surfaceObj) {
175    sp<Surface> result(android_view_Surface_getSurface(env, surfaceObj));
176    if (result == NULL) {
177        /*
178         * if this method is called from the WindowManager's process, it means
179         * the client is is not remote, and therefore is allowed to have
180         * a Surface (data), so we create it here.
181         * If we don't have a SurfaceControl, it means we're in a different
182         * process.
183         */
184
185        SurfaceControl* const control = reinterpret_cast<SurfaceControl*>(
186                env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurfaceControl));
187        if (control) {
188            result = control->getSurface();
189            if (result != NULL) {
190                result->incStrong(surfaceObj);
191                env->SetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurface,
192                        reinterpret_cast<jint>(result.get()));
193            }
194        }
195    }
196    return result;
197}
198
199sp<ANativeWindow> android_view_Surface_getNativeWindow(JNIEnv* env, jobject surfaceObj) {
200    return getSurface(env, surfaceObj);
201}
202
203bool android_view_Surface_isInstanceOf(JNIEnv* env, jobject obj) {
204    return env->IsInstanceOf(obj, gSurfaceClassInfo.clazz);
205}
206
207sp<Surface> android_view_Surface_getSurface(JNIEnv* env, jobject surfaceObj) {
208    return reinterpret_cast<Surface*>(
209            env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurface));
210}
211
212static void setSurface(JNIEnv* env, jobject surfaceObj, const sp<Surface>& surface) {
213    Surface* const p = reinterpret_cast<Surface*>(
214            env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurface));
215    if (surface.get()) {
216        surface->incStrong(surfaceObj);
217    }
218    if (p) {
219        p->decStrong(surfaceObj);
220    }
221    env->SetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurface,
222            reinterpret_cast<jint>(surface.get()));
223
224    // This test is conservative and it would be better to compare the ISurfaces
225    if (p && p != surface.get()) {
226        jint generationId = env->GetIntField(surfaceObj,
227                gSurfaceClassInfo.mGenerationId);
228        generationId++;
229        env->SetIntField(surfaceObj,
230                gSurfaceClassInfo.mGenerationId, generationId);
231    }
232}
233
234// ----------------------------------------------------------------------------
235
236static void nativeCreate(JNIEnv* env, jobject surfaceObj, jobject sessionObj,
237        jstring nameStr, jint w, jint h, jint format, jint flags) {
238    ScopedUtfChars name(env, nameStr);
239    sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
240
241    sp<SurfaceControl> surface = client->createSurface(
242            String8(name.c_str()), w, h, format, flags);
243    if (surface == NULL) {
244        jniThrowException(env, OutOfResourcesException, NULL);
245        return;
246    }
247
248    setSurfaceControl(env, surfaceObj, surface);
249}
250
251static void nativeCreateFromSurfaceTexture(JNIEnv* env, jobject surfaceObj,
252        jobject surfaceTextureObj) {
253    sp<SurfaceTexture> st(SurfaceTexture_getSurfaceTexture(env, surfaceTextureObj));
254    if (st == NULL) {
255        jniThrowException(env, "java/lang/IllegalArgumentException",
256                "SurfaceTexture has already been released");
257        return;
258    }
259
260    sp<ISurfaceTexture> bq = st->getBufferQueue();
261
262    sp<Surface> surface(new Surface(bq));
263    if (surface == NULL) {
264        jniThrowException(env, OutOfResourcesException, NULL);
265        return;
266    }
267
268    setSurface(env, surfaceObj, surface);
269}
270
271static void nativeRelease(JNIEnv* env, jobject surfaceObj) {
272    setSurfaceControl(env, surfaceObj, NULL);
273    setSurface(env, surfaceObj, NULL);
274}
275
276static void nativeDestroy(JNIEnv* env, jobject surfaceObj) {
277    sp<SurfaceControl> surfaceControl(getSurfaceControl(env, surfaceObj));
278    if (SurfaceControl::isValid(surfaceControl)) {
279        surfaceControl->clear();
280    }
281    setSurfaceControl(env, surfaceObj, NULL);
282    setSurface(env, surfaceObj, NULL);
283}
284
285static jboolean nativeIsValid(JNIEnv* env, jobject surfaceObj) {
286    sp<SurfaceControl> surfaceControl(getSurfaceControl(env, surfaceObj));
287    if (surfaceControl != NULL) {
288        return SurfaceControl::isValid(surfaceControl) ? JNI_TRUE : JNI_FALSE;
289    }
290
291    sp<Surface> surface(getSurface(env, surfaceObj));
292    return Surface::isValid(surface) ? JNI_TRUE : JNI_FALSE;
293}
294
295static jint nativeGetIdentity(JNIEnv* env, jobject surfaceObj) {
296    sp<SurfaceControl> control(getSurfaceControl(env, surfaceObj));
297    if (control != NULL) {
298        return jint(control->getIdentity());
299    }
300
301    sp<Surface> surface(getSurface(env, surfaceObj));
302    if (surface != NULL) {
303        return jint(surface->getIdentity());
304    }
305
306    return -1;
307}
308
309static jboolean nativeIsConsumerRunningBehind(JNIEnv* env, jobject surfaceObj) {
310    sp<Surface> surface(getSurface(env, surfaceObj));
311    if (!Surface::isValid(surface)) {
312        doThrowIAE(env);
313        return JNI_FALSE;
314    }
315
316    int value = 0;
317    ANativeWindow* anw = static_cast<ANativeWindow*>(surface.get());
318    anw->query(anw, NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &value);
319    return value;
320}
321
322static inline SkBitmap::Config convertPixelFormat(PixelFormat format) {
323    /* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then
324        we can map to SkBitmap::kARGB_8888_Config, and optionally call
325        bitmap.setIsOpaque(true) on the resulting SkBitmap (as an accelerator)
326    */
327    switch (format) {
328    case PIXEL_FORMAT_RGBX_8888:    return SkBitmap::kARGB_8888_Config;
329    case PIXEL_FORMAT_RGBA_8888:    return SkBitmap::kARGB_8888_Config;
330    case PIXEL_FORMAT_RGBA_4444:    return SkBitmap::kARGB_4444_Config;
331    case PIXEL_FORMAT_RGB_565:      return SkBitmap::kRGB_565_Config;
332    case PIXEL_FORMAT_A_8:          return SkBitmap::kA8_Config;
333    default:                        return SkBitmap::kNo_Config;
334    }
335}
336
337static jobject nativeLockCanvas(JNIEnv* env, jobject surfaceObj, jobject dirtyRectObj) {
338    sp<Surface> surface(getSurface(env, surfaceObj));
339    if (!Surface::isValid(surface)) {
340        doThrowIAE(env);
341        return NULL;
342    }
343
344    // get dirty region
345    Region dirtyRegion;
346    if (dirtyRectObj) {
347        Rect dirty;
348        dirty.left = env->GetIntField(dirtyRectObj, gRectClassInfo.left);
349        dirty.top = env->GetIntField(dirtyRectObj, gRectClassInfo.top);
350        dirty.right = env->GetIntField(dirtyRectObj, gRectClassInfo.right);
351        dirty.bottom = env->GetIntField(dirtyRectObj, gRectClassInfo.bottom);
352        if (!dirty.isEmpty()) {
353            dirtyRegion.set(dirty);
354        }
355    } else {
356        dirtyRegion.set(Rect(0x3FFF, 0x3FFF));
357    }
358
359    Surface::SurfaceInfo info;
360    status_t err = surface->lock(&info, &dirtyRegion);
361    if (err < 0) {
362        const char* const exception = (err == NO_MEMORY) ?
363                OutOfResourcesException :
364                "java/lang/IllegalArgumentException";
365        jniThrowException(env, exception, NULL);
366        return NULL;
367    }
368
369    // Associate a SkCanvas object to this surface
370    jobject canvasObj = env->GetObjectField(surfaceObj, gSurfaceClassInfo.mCanvas);
371    env->SetIntField(canvasObj, gCanvasClassInfo.mSurfaceFormat, info.format);
372
373    SkCanvas* nativeCanvas = reinterpret_cast<SkCanvas*>(
374            env->GetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas));
375    SkBitmap bitmap;
376    ssize_t bpr = info.s * bytesPerPixel(info.format);
377    bitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, bpr);
378    if (info.format == PIXEL_FORMAT_RGBX_8888) {
379        bitmap.setIsOpaque(true);
380    }
381    if (info.w > 0 && info.h > 0) {
382        bitmap.setPixels(info.bits);
383    } else {
384        // be safe with an empty bitmap.
385        bitmap.setPixels(NULL);
386    }
387    nativeCanvas->setBitmapDevice(bitmap);
388
389    SkRegion clipReg;
390    if (dirtyRegion.isRect()) { // very common case
391        const Rect b(dirtyRegion.getBounds());
392        clipReg.setRect(b.left, b.top, b.right, b.bottom);
393    } else {
394        size_t count;
395        Rect const* r = dirtyRegion.getArray(&count);
396        while (count) {
397            clipReg.op(r->left, r->top, r->right, r->bottom, SkRegion::kUnion_Op);
398            r++, count--;
399        }
400    }
401
402    nativeCanvas->clipRegion(clipReg);
403
404    int saveCount = nativeCanvas->save();
405    env->SetIntField(surfaceObj, gSurfaceClassInfo.mCanvasSaveCount, saveCount);
406
407    if (dirtyRectObj) {
408        const Rect& bounds(dirtyRegion.getBounds());
409        env->SetIntField(dirtyRectObj, gRectClassInfo.left, bounds.left);
410        env->SetIntField(dirtyRectObj, gRectClassInfo.top, bounds.top);
411        env->SetIntField(dirtyRectObj, gRectClassInfo.right, bounds.right);
412        env->SetIntField(dirtyRectObj, gRectClassInfo.bottom, bounds.bottom);
413    }
414
415    return canvasObj;
416}
417
418static void nativeUnlockCanvasAndPost(JNIEnv* env, jobject surfaceObj, jobject canvasObj) {
419    jobject ownCanvasObj = env->GetObjectField(surfaceObj, gSurfaceClassInfo.mCanvas);
420    if (!env->IsSameObject(ownCanvasObj, canvasObj)) {
421        doThrowIAE(env);
422        return;
423    }
424
425    sp<Surface> surface(getSurface(env, surfaceObj));
426    if (!Surface::isValid(surface)) {
427        return;
428    }
429
430    // detach the canvas from the surface
431    SkCanvas* nativeCanvas = reinterpret_cast<SkCanvas*>(
432            env->GetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas));
433    int saveCount = env->GetIntField(surfaceObj, gSurfaceClassInfo.mCanvasSaveCount);
434    nativeCanvas->restoreToCount(saveCount);
435    nativeCanvas->setBitmapDevice(SkBitmap());
436    env->SetIntField(surfaceObj, gSurfaceClassInfo.mCanvasSaveCount, 0);
437
438    // unlock surface
439    status_t err = surface->unlockAndPost();
440    if (err < 0) {
441        doThrowIAE(env);
442    }
443}
444
445static jobject nativeScreenshot(JNIEnv* env, jclass clazz, jobject displayTokenObj,
446        jint width, jint height, jint minLayer, jint maxLayer, bool allLayers) {
447    sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
448    if (displayToken == NULL) {
449        return NULL;
450    }
451
452    ScreenshotPixelRef* pixels = new ScreenshotPixelRef(NULL);
453    if (pixels->update(displayToken, width, height,
454            minLayer, maxLayer, allLayers) != NO_ERROR) {
455        delete pixels;
456        return NULL;
457    }
458
459    uint32_t w = pixels->getWidth();
460    uint32_t h = pixels->getHeight();
461    uint32_t s = pixels->getStride();
462    uint32_t f = pixels->getFormat();
463    ssize_t bpr = s * android::bytesPerPixel(f);
464
465    SkBitmap* bitmap = new SkBitmap();
466    bitmap->setConfig(convertPixelFormat(f), w, h, bpr);
467    if (f == PIXEL_FORMAT_RGBX_8888) {
468        bitmap->setIsOpaque(true);
469    }
470
471    if (w > 0 && h > 0) {
472        bitmap->setPixelRef(pixels)->unref();
473        bitmap->lockPixels();
474    } else {
475        // be safe with an empty bitmap.
476        delete pixels;
477        bitmap->setPixels(NULL);
478    }
479
480    return GraphicsJNI::createBitmap(env, bitmap, false, NULL);
481}
482
483static void nativeOpenTransaction(JNIEnv* env, jclass clazz) {
484    SurfaceComposerClient::openGlobalTransaction();
485}
486
487static void nativeCloseTransaction(JNIEnv* env, jclass clazz) {
488    SurfaceComposerClient::closeGlobalTransaction();
489}
490
491static void nativeSetLayer(JNIEnv* env, jobject surfaceObj, jint zorder) {
492    sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
493    if (surface == NULL) return;
494
495    status_t err = surface->setLayer(zorder);
496    if (err < 0 && err != NO_INIT) {
497        doThrowIAE(env);
498    }
499}
500
501static void nativeSetPosition(JNIEnv* env, jobject surfaceObj, jfloat x, jfloat y) {
502    sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
503    if (surface == NULL) return;
504
505    status_t err = surface->setPosition(x, y);
506    if (err < 0 && err != NO_INIT) {
507        doThrowIAE(env);
508    }
509}
510
511static void nativeSetSize(JNIEnv* env, jobject surfaceObj, jint w, jint h) {
512    sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
513    if (surface == NULL) return;
514
515    status_t err = surface->setSize(w, h);
516    if (err < 0 && err != NO_INIT) {
517        doThrowIAE(env);
518    }
519}
520
521static void nativeSetFlags(JNIEnv* env, jobject surfaceObj, jint flags, jint mask) {
522    sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
523    if (surface == NULL) return;
524
525    status_t err = surface->setFlags(flags, mask);
526    if (err < 0 && err != NO_INIT) {
527        doThrowIAE(env);
528    }
529}
530
531static void nativeSetTransparentRegionHint(JNIEnv* env, jobject surfaceObj, jobject regionObj) {
532    sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
533    if (surface == NULL) return;
534
535    SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
536    if (!region) {
537        doThrowIAE(env);
538        return;
539    }
540
541    const SkIRect& b(region->getBounds());
542    Region reg(Rect(b.fLeft, b.fTop, b.fRight, b.fBottom));
543    if (region->isComplex()) {
544        SkRegion::Iterator it(*region);
545        while (!it.done()) {
546            const SkIRect& r(it.rect());
547            reg.addRectUnchecked(r.fLeft, r.fTop, r.fRight, r.fBottom);
548            it.next();
549        }
550    }
551
552    status_t err = surface->setTransparentRegionHint(reg);
553    if (err < 0 && err != NO_INIT) {
554        doThrowIAE(env);
555    }
556}
557
558static void nativeSetAlpha(JNIEnv* env, jobject surfaceObj, jfloat alpha) {
559    sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
560    if (surface == NULL) return;
561
562    status_t err = surface->setAlpha(alpha);
563    if (err < 0 && err != NO_INIT) {
564        doThrowIAE(env);
565    }
566}
567
568static void nativeSetMatrix(JNIEnv* env, jobject surfaceObj,
569        jfloat dsdx, jfloat dtdx, jfloat dsdy, jfloat dtdy) {
570    sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
571    if (surface == NULL) return;
572
573    status_t err = surface->setMatrix(dsdx, dtdx, dsdy, dtdy);
574    if (err < 0 && err != NO_INIT) {
575        doThrowIAE(env);
576    }
577}
578
579static void nativeSetWindowCrop(JNIEnv* env, jobject surfaceObj, jobject cropObj) {
580    const sp<SurfaceControl>& surface(getSurfaceControl(env, surfaceObj));
581    if (surface == NULL) return;
582
583    Rect crop;
584    if (cropObj) {
585        crop.left = env->GetIntField(cropObj, gRectClassInfo.left);
586        crop.top = env->GetIntField(cropObj, gRectClassInfo.top);
587        crop.right = env->GetIntField(cropObj, gRectClassInfo.right);
588        crop.bottom = env->GetIntField(cropObj, gRectClassInfo.bottom);
589    } else {
590        crop.left = crop.top = crop.right = crop.bottom = 0;
591    }
592
593    status_t err = surface->setCrop(crop);
594    if (err < 0 && err != NO_INIT) {
595        doThrowIAE(env);
596    }
597}
598
599static void nativeSetLayerStack(JNIEnv* env, jobject surfaceObj, jint layerStack) {
600    sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
601    if (surface == NULL) return;
602
603    status_t err = surface->setLayerStack(layerStack);
604    if (err < 0 && err != NO_INIT) {
605        doThrowIAE(env);
606    }
607}
608
609static jobject nativeGetBuiltInDisplay(JNIEnv* env, jclass clazz, jint id) {
610    sp<IBinder> token(SurfaceComposerClient::getBuiltInDisplay(id));
611    return javaObjectForIBinder(env, token);
612}
613
614static jobject nativeCreateDisplay(JNIEnv* env, jclass clazz, jstring nameObj) {
615    ScopedUtfChars name(env, nameObj);
616    // TODO: pass the name to SF.
617    sp<IBinder> token(SurfaceComposerClient::createDisplay());
618    return javaObjectForIBinder(env, token);
619}
620
621static void nativeSetDisplaySurface(JNIEnv* env, jclass clazz,
622        jobject tokenObj, jobject surfaceTextureObj) {
623    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
624    if (token == NULL) return;
625
626    if (!surfaceTextureObj) {
627        SurfaceComposerClient::setDisplaySurface(token, NULL);
628        return;
629    }
630
631    sp<SurfaceTexture> st(SurfaceTexture_getSurfaceTexture(env, surfaceTextureObj));
632    if (st == NULL) {
633        jniThrowException(env, "java/lang/IllegalArgumentException",
634                "SurfaceTexture has already been released");
635        return;
636    }
637
638    sp<ISurfaceTexture> bq = st->getBufferQueue();
639    SurfaceComposerClient::setDisplaySurface(token, bq);
640}
641
642static void nativeSetDisplayLayerStack(JNIEnv* env, jclass clazz,
643        jobject tokenObj, jint layerStack) {
644    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
645    if (token == NULL) return;
646
647    SurfaceComposerClient::setDisplayLayerStack(token, layerStack);
648}
649
650static void nativeSetDisplayOrientation(JNIEnv* env, jclass clazz,
651        jobject tokenObj, jint orientation) {
652    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
653    if (token == NULL) return;
654
655    SurfaceComposerClient::setDisplayOrientation(token, orientation);
656}
657
658static void nativeSetDisplayViewport(JNIEnv* env, jclass clazz,
659        jobject tokenObj, jobject rectObj) {
660    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
661    if (token == NULL) return;
662
663    Rect rect;
664    rect.left = env->GetIntField(rectObj, gRectClassInfo.left);
665    rect.top = env->GetIntField(rectObj, gRectClassInfo.top);
666    rect.right = env->GetIntField(rectObj, gRectClassInfo.right);
667    rect.bottom = env->GetIntField(rectObj, gRectClassInfo.bottom);
668    SurfaceComposerClient::setDisplayViewport(token, rect);
669}
670
671static void nativeSetDisplayFrame(JNIEnv* env, jclass clazz,
672        jobject tokenObj, jobject rectObj) {
673    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
674    if (token == NULL) return;
675
676    Rect rect;
677    rect.left = env->GetIntField(rectObj, gRectClassInfo.left);
678    rect.top = env->GetIntField(rectObj, gRectClassInfo.top);
679    rect.right = env->GetIntField(rectObj, gRectClassInfo.right);
680    rect.bottom = env->GetIntField(rectObj, gRectClassInfo.bottom);
681    SurfaceComposerClient::setDisplayFrame(token, rect);
682}
683
684static jboolean nativeGetDisplayInfo(JNIEnv* env, jclass clazz,
685        jobject tokenObj, jobject infoObj) {
686    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
687    if (token == NULL) return JNI_FALSE;
688
689    DisplayInfo info;
690    if (SurfaceComposerClient::getDisplayInfo(token, &info)) {
691        return JNI_FALSE;
692    }
693
694    env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.width, info.w);
695    env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.height, info.h);
696    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.refreshRate, info.fps);
697    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.density, info.density);
698    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.xDpi, info.xdpi);
699    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.yDpi, info.ydpi);
700    return JNI_TRUE;
701}
702
703// ----------------------------------------------------------------------------
704
705static void nativeCopyFrom(JNIEnv* env, jobject surfaceObj, jobject otherObj) {
706    /*
707     * This is used by the WindowManagerService just after constructing
708     * a Surface and is necessary for returning the Surface reference to
709     * the caller. At this point, we should only have a SurfaceControl.
710     */
711
712    sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
713    sp<SurfaceControl> other(getSurfaceControl(env, otherObj));
714    if (!SurfaceControl::isSameSurface(surface, other)) {
715        // we reassign the surface only if it's a different one
716        // otherwise we would loose our client-side state.
717        setSurfaceControl(env, surfaceObj, other);
718    }
719}
720
721static void nativeTransferFrom(JNIEnv* env, jobject surfaceObj, jobject otherObj) {
722    sp<SurfaceControl> control(getSurfaceControl(env, otherObj));
723    sp<Surface> surface(android_view_Surface_getSurface(env, otherObj));
724    setSurfaceControl(env, surfaceObj, control);
725    setSurface(env, surfaceObj, surface);
726    setSurfaceControl(env, otherObj, NULL);
727    setSurface(env, otherObj, NULL);
728}
729
730static void nativeReadFromParcel(JNIEnv* env, jobject surfaceObj, jobject parcelObj) {
731    Parcel* parcel = parcelForJavaObject(env, parcelObj);
732    if (parcel == NULL) {
733        doThrowNPE(env);
734        return;
735    }
736
737    sp<Surface> surface(Surface::readFromParcel(*parcel));
738    setSurfaceControl(env, surfaceObj, NULL);
739    setSurface(env, surfaceObj, surface);
740}
741
742static void nativeWriteToParcel(JNIEnv* env, jobject surfaceObj, jobject parcelObj) {
743    Parcel* parcel = parcelForJavaObject(env, parcelObj);
744    if (parcel == NULL) {
745        doThrowNPE(env);
746        return;
747    }
748
749    // The Java instance may have a SurfaceControl (in the case of the
750    // WindowManager or a system app). In that case, we defer to the
751    // SurfaceControl to send its ISurface. Otherwise, if the Surface is
752    // available we let it parcel itself. Finally, if the Surface is also
753    // NULL we fall back to using the SurfaceControl path which sends an
754    // empty surface; this matches legacy behavior.
755    sp<SurfaceControl> control(getSurfaceControl(env, surfaceObj));
756    if (control != NULL) {
757        SurfaceControl::writeSurfaceToParcel(control, parcel);
758    } else {
759        sp<Surface> surface(android_view_Surface_getSurface(env, surfaceObj));
760        if (surface != NULL) {
761            Surface::writeToParcel(surface, parcel);
762        } else {
763            SurfaceControl::writeSurfaceToParcel(NULL, parcel);
764        }
765    }
766}
767
768// ----------------------------------------------------------------------------
769
770static JNINativeMethod gSurfaceMethods[] = {
771    {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIII)V",
772            (void*)nativeCreate },
773    {"nativeCreateFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)V",
774            (void*)nativeCreateFromSurfaceTexture },
775    {"nativeRelease", "()V",
776            (void*)nativeRelease },
777    {"nativeDestroy", "()V",
778            (void*)nativeDestroy },
779    {"nativeIsValid", "()Z",
780            (void*)nativeIsValid },
781    {"nativeGetIdentity", "()I",
782            (void*)nativeGetIdentity },
783    {"nativeIsConsumerRunningBehind", "()Z",
784            (void*)nativeIsConsumerRunningBehind },
785    {"nativeLockCanvas", "(Landroid/graphics/Rect;)Landroid/graphics/Canvas;",
786            (void*)nativeLockCanvas },
787    {"nativeUnlockCanvasAndPost", "(Landroid/graphics/Canvas;)V",
788            (void*)nativeUnlockCanvasAndPost },
789    {"nativeScreenshot", "(Landroid/os/IBinder;IIIIZ)Landroid/graphics/Bitmap;",
790            (void*)nativeScreenshot },
791    {"nativeOpenTransaction", "()V",
792            (void*)nativeOpenTransaction },
793    {"nativeCloseTransaction", "()V",
794            (void*)nativeCloseTransaction },
795    {"nativeSetLayer", "(I)V",
796            (void*)nativeSetLayer },
797    {"nativeSetPosition", "(FF)V",
798            (void*)nativeSetPosition },
799    {"nativeSetSize", "(II)V",
800            (void*)nativeSetSize },
801    {"nativeSetTransparentRegionHint", "(Landroid/graphics/Region;)V",
802            (void*)nativeSetTransparentRegionHint },
803    {"nativeSetAlpha", "(F)V",
804            (void*)nativeSetAlpha },
805    {"nativeSetMatrix", "(FFFF)V",
806            (void*)nativeSetMatrix },
807    {"nativeSetFlags", "(II)V",
808            (void*)nativeSetFlags },
809    {"nativeSetWindowCrop", "(Landroid/graphics/Rect;)V",
810            (void*)nativeSetWindowCrop },
811    {"nativeSetLayerStack", "(I)V",
812            (void*)nativeSetLayerStack },
813    {"nativeGetBuiltInDisplay", "(I)Landroid/os/IBinder;",
814            (void*)nativeGetBuiltInDisplay },
815    {"nativeCreateDisplay", "(Ljava/lang/String;)Landroid/os/IBinder;",
816            (void*)nativeCreateDisplay },
817    {"nativeSetDisplaySurface", "(Landroid/os/IBinder;Landroid/graphics/SurfaceTexture;)V",
818            (void*)nativeSetDisplaySurface },
819    {"nativeSetDisplayLayerStack", "(Landroid/os/IBinder;I)V",
820            (void*)nativeSetDisplayLayerStack },
821    {"nativeSetDisplayOrientation", "(Landroid/os/IBinder;I)V",
822            (void*)nativeSetDisplayOrientation },
823    {"nativeSetDisplayViewport", "(Landroid/os/IBinder;Landroid/graphics/Rect;)V",
824            (void*)nativeSetDisplayViewport },
825    {"nativeSetDisplayFrame", "(Landroid/os/IBinder;Landroid/graphics/Rect;)V",
826            (void*)nativeSetDisplayFrame },
827    {"nativeGetDisplayInfo", "(Landroid/os/IBinder;Landroid/view/Surface$PhysicalDisplayInfo;)Z",
828            (void*)nativeGetDisplayInfo },
829    {"nativeCopyFrom", "(Landroid/view/Surface;)V",
830            (void*)nativeCopyFrom },
831    {"nativeTransferFrom", "(Landroid/view/Surface;)V",
832            (void*)nativeTransferFrom },
833    {"nativeReadFromParcel", "(Landroid/os/Parcel;)V",
834            (void*)nativeReadFromParcel },
835    {"nativeWriteToParcel", "(Landroid/os/Parcel;)V",
836            (void*)nativeWriteToParcel },
837};
838
839int register_android_view_Surface(JNIEnv* env)
840{
841    int err = AndroidRuntime::registerNativeMethods(env, "android/view/Surface",
842            gSurfaceMethods, NELEM(gSurfaceMethods));
843
844    jclass clazz = env->FindClass("android/view/Surface");
845    gSurfaceClassInfo.clazz = jclass(env->NewGlobalRef(clazz));
846    gSurfaceClassInfo.mNativeSurface =
847            env->GetFieldID(gSurfaceClassInfo.clazz, ANDROID_VIEW_SURFACE_JNI_ID, "I");
848    gSurfaceClassInfo.mNativeSurfaceControl =
849            env->GetFieldID(gSurfaceClassInfo.clazz, "mNativeSurfaceControl", "I");
850    gSurfaceClassInfo.mGenerationId =
851            env->GetFieldID(gSurfaceClassInfo.clazz, "mGenerationId", "I");
852    gSurfaceClassInfo.mCanvas =
853            env->GetFieldID(gSurfaceClassInfo.clazz, "mCanvas", "Landroid/graphics/Canvas;");
854    gSurfaceClassInfo.mCanvasSaveCount =
855            env->GetFieldID(gSurfaceClassInfo.clazz, "mCanvasSaveCount", "I");
856
857    clazz = env->FindClass("android/graphics/Canvas");
858    gCanvasClassInfo.mNativeCanvas = env->GetFieldID(clazz, "mNativeCanvas", "I");
859    gCanvasClassInfo.mSurfaceFormat = env->GetFieldID(clazz, "mSurfaceFormat", "I");
860
861    clazz = env->FindClass("android/graphics/Rect");
862    gRectClassInfo.left = env->GetFieldID(clazz, "left", "I");
863    gRectClassInfo.top = env->GetFieldID(clazz, "top", "I");
864    gRectClassInfo.right = env->GetFieldID(clazz, "right", "I");
865    gRectClassInfo.bottom = env->GetFieldID(clazz, "bottom", "I");
866
867    clazz = env->FindClass("android/view/Surface$PhysicalDisplayInfo");
868    gPhysicalDisplayInfoClassInfo.width = env->GetFieldID(clazz, "width", "I");
869    gPhysicalDisplayInfoClassInfo.height = env->GetFieldID(clazz, "height", "I");
870    gPhysicalDisplayInfoClassInfo.refreshRate = env->GetFieldID(clazz, "refreshRate", "F");
871    gPhysicalDisplayInfoClassInfo.density = env->GetFieldID(clazz, "density", "F");
872    gPhysicalDisplayInfoClassInfo.xDpi = env->GetFieldID(clazz, "xDpi", "F");
873    gPhysicalDisplayInfoClassInfo.yDpi = env->GetFieldID(clazz, "yDpi", "F");
874    return err;
875}
876
877};
878