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