static jboolean android_view_GraphicBuffer_lockCanvas(JNIEnv* env, jobject,
        jlong wrapperHandle, jobject canvas, jobject dirtyRect) {

    GraphicBufferWrapper* wrapper =
                reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
    if (!wrapper) {
        return JNI_FALSE;
    }

    sp<GraphicBuffer> buffer(wrapper->buffer);

    Rect rect;
    if (dirtyRect) {
        rect.left = GET_INT(dirtyRect, gRectClassInfo.left);
        rect.top = GET_INT(dirtyRect, gRectClassInfo.top);
        rect.right = GET_INT(dirtyRect, gRectClassInfo.right);
        rect.bottom = GET_INT(dirtyRect, gRectClassInfo.bottom);
    } else {
        rect.set(Rect(buffer->getWidth(), buffer->getHeight()));
    }

    void* bits = NULL;
    status_t status = buffer->lock(LOCK_CANVAS_USAGE, rect, &bits);

    if (status) return JNI_FALSE;
    if (!bits) {
        buffer->unlock();
        return JNI_FALSE;
    }

    ssize_t bytesCount = buffer->getStride() * bytesPerPixel(buffer->getPixelFormat());

    SkBitmap bitmap;
    bitmap.setInfo(SkImageInfo::Make(buffer->getWidth(), buffer->getHeight(),
                                     convertPixelFormat(buffer->getPixelFormat()),
                                     kPremul_SkAlphaType),
                   bytesCount);

    if (buffer->getWidth() > 0 && buffer->getHeight() > 0) {
        bitmap.setPixels(bits);
    } else {
        bitmap.setPixels(NULL);
    }

    SET_INT(canvas, gCanvasClassInfo.mSurfaceFormat, buffer->getPixelFormat());
    INVOKEV(canvas, gCanvasClassInfo.setNativeBitmap, reinterpret_cast<jlong>(&bitmap));

    SkRect clipRect;
    clipRect.set(rect.left, rect.top, rect.right, rect.bottom);
    SkCanvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas);
    nativeCanvas->clipRect(clipRect);

    if (dirtyRect) {
        INVOKEV(dirtyRect, gRectClassInfo.set,
                int(rect.left), int(rect.top), int(rect.right), int(rect.bottom));
    }

    return JNI_TRUE;
}
static void com_android_server_AssetAtlasService_releaseCanvas(JNIEnv* env, jobject,
        jobject canvas, jlong bitmapHandle) {

    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
    INVOKEV(canvas, gCanvasClassInfo.setNativeBitmap, (jlong)0);

    delete bitmap;
}
static jlong com_android_server_AssetAtlasService_acquireCanvas(JNIEnv* env, jobject,
        jobject canvas, jint width, jint height) {

    SkBitmap* bitmap = new SkBitmap;
    bitmap->allocN32Pixels(width, height);
    bitmap->eraseColor(0);
    INVOKEV(canvas, gCanvasClassInfo.setNativeBitmap, reinterpret_cast<jlong>(bitmap));

    return reinterpret_cast<jlong>(bitmap);
}
static jboolean android_view_TextureView_lockCanvas(JNIEnv* env, jobject,
        jlong nativeWindow, jobject canvas, jobject dirtyRect) {

    if (!nativeWindow) {
        return JNI_FALSE;
    }

    ANativeWindow_Buffer buffer;

    Rect rect;
    if (dirtyRect) {
        rect.left = GET_INT(dirtyRect, gRectClassInfo.left);
        rect.top = GET_INT(dirtyRect, gRectClassInfo.top);
        rect.right = GET_INT(dirtyRect, gRectClassInfo.right);
        rect.bottom = GET_INT(dirtyRect, gRectClassInfo.bottom);
    } else {
        rect.set(Rect(0x3FFF, 0x3FFF));
    }

    sp<ANativeWindow> window((ANativeWindow*) nativeWindow);
    int32_t status = native_window_lock(window.get(), &buffer, &rect);
    if (status) return JNI_FALSE;

    ssize_t bytesCount = buffer.stride * bytesPerPixel(buffer.format);

    SkBitmap bitmap;
    bitmap.setConfig(convertPixelFormat(buffer.format), buffer.width, buffer.height, bytesCount);

    if (buffer.format == WINDOW_FORMAT_RGBX_8888) {
        bitmap.setIsOpaque(true);
    }

    if (buffer.width > 0 && buffer.height > 0) {
        bitmap.setPixels(buffer.bits);
    } else {
        bitmap.setPixels(NULL);
    }

    SET_INT(canvas, gCanvasClassInfo.mSurfaceFormat, buffer.format);

    SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
    swapCanvasPtr(env, canvas, nativeCanvas);

    SkRect clipRect;
    clipRect.set(rect.left, rect.top, rect.right, rect.bottom);
    nativeCanvas->clipRect(clipRect);

    if (dirtyRect) {
        INVOKEV(dirtyRect, gRectClassInfo.set,
                int(rect.left), int(rect.top), int(rect.right), int(rect.bottom));
    }

    return JNI_TRUE;
}
static jboolean android_view_GraphicBuffer_unlockCanvasAndPost(JNIEnv* env, jobject,
        jlong wrapperHandle, jobject canvas) {

    GraphicBufferWrapper* wrapper =
                reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
    INVOKEV(canvas, gCanvasClassInfo.setNativeBitmap, (jlong)0);

    if (wrapper) {
        status_t status = wrapper->buffer->unlock();
        return status == 0 ? JNI_TRUE : JNI_FALSE;
    }

    return JNI_FALSE;
}
void    DoSplashSetScaleFactor(float scaleFactor) {
    INVOKEV(SplashSetScaleFactor)(scaleFactor);
}
void    DoSplashSetFileJarName(const char* fileName, const char* jarName) {
    INVOKEV(SplashSetFileJarName)(fileName, jarName);
}
void    DoSplashClose(void) {
    INVOKEV(SplashClose)();
}
void    DoSplashInit(void) {
    INVOKEV(SplashInit)();
}