blob: 531445f076b3fc40e2c7efb5713769e6543dd0bf [file] [log] [blame]
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "Surface"
#include <stdio.h>
#include "android_os_Parcel.h"
#include "android_util_Binder.h"
#include "android/graphics/GraphicsJNI.h"
#include "android/graphics/Region.h"
#include <binder/IMemory.h>
#include <gui/ISurfaceComposer.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/SurfaceTexture.h>
#include <ui/DisplayInfo.h>
#include <ui/Rect.h>
#include <ui/Region.h>
#include <EGL/egl.h>
#include <SkCanvas.h>
#include <SkBitmap.h>
#include <SkRegion.h>
#include <SkPixelRef.h>
#include "jni.h"
#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_Surface.h>
#include <android_runtime/android_view_SurfaceSession.h>
#include <android_runtime/android_graphics_SurfaceTexture.h>
#include <utils/misc.h>
#include <utils/Log.h>
#include <ScopedUtfChars.h>
// ----------------------------------------------------------------------------
namespace android {
static const char* const OutOfResourcesException =
"android/view/Surface$OutOfResourcesException";
static struct {
jclass clazz;
jfieldID mNativeSurface;
jfieldID mNativeSurfaceControl;
jfieldID mGenerationId;
jfieldID mCanvas;
jfieldID mCanvasSaveCount;
jmethodID ctor;
} gSurfaceClassInfo;
static struct {
jfieldID left;
jfieldID top;
jfieldID right;
jfieldID bottom;
} gRectClassInfo;
static struct {
jfieldID mNativeCanvas;
jfieldID mSurfaceFormat;
} gCanvasClassInfo;
static struct {
jfieldID width;
jfieldID height;
jfieldID refreshRate;
jfieldID density;
jfieldID xDpi;
jfieldID yDpi;
} gPhysicalDisplayInfoClassInfo;
class ScreenshotPixelRef : public SkPixelRef {
public:
ScreenshotPixelRef(SkColorTable* ctable) {
fCTable = ctable;
SkSafeRef(ctable);
setImmutable();
}
virtual ~ScreenshotPixelRef() {
SkSafeUnref(fCTable);
}
status_t update(const sp<IBinder>& display, int width, int height,
int minLayer, int maxLayer, bool allLayers) {
status_t res = (width > 0 && height > 0)
? (allLayers
? mScreenshot.update(display, width, height)
: mScreenshot.update(display, width, height, minLayer, maxLayer))
: mScreenshot.update(display);
if (res != NO_ERROR) {
return res;
}
return NO_ERROR;
}
uint32_t getWidth() const {
return mScreenshot.getWidth();
}
uint32_t getHeight() const {
return mScreenshot.getHeight();
}
uint32_t getStride() const {
return mScreenshot.getStride();
}
uint32_t getFormat() const {
return mScreenshot.getFormat();
}
protected:
// overrides from SkPixelRef
virtual void* onLockPixels(SkColorTable** ct) {
*ct = fCTable;
return (void*)mScreenshot.getPixels();
}
virtual void onUnlockPixels() {
}
private:
ScreenshotClient mScreenshot;
SkColorTable* fCTable;
typedef SkPixelRef INHERITED;
};
// ----------------------------------------------------------------------------
static sp<SurfaceControl> getSurfaceControl(JNIEnv* env, jobject surfaceObj) {
return reinterpret_cast<SurfaceControl*>(
env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurfaceControl));
}
static void setSurfaceControl(JNIEnv* env, jobject surfaceObj,
const sp<SurfaceControl>& surface) {
SurfaceControl* const p = reinterpret_cast<SurfaceControl*>(
env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurfaceControl));
if (surface.get()) {
surface->incStrong(surfaceObj);
}
if (p) {
p->decStrong(surfaceObj);
}
env->SetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurfaceControl,
reinterpret_cast<jint>(surface.get()));
}
static sp<Surface> getSurface(JNIEnv* env, jobject surfaceObj) {
sp<Surface> result(android_view_Surface_getSurface(env, surfaceObj));
if (result == NULL) {
/*
* if this method is called from the WindowManager's process, it means
* the client is is not remote, and therefore is allowed to have
* a Surface (data), so we create it here.
* If we don't have a SurfaceControl, it means we're in a different
* process.
*/
SurfaceControl* const control = reinterpret_cast<SurfaceControl*>(
env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurfaceControl));
if (control) {
result = control->getSurface();
if (result != NULL) {
result->incStrong(surfaceObj);
env->SetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurface,
reinterpret_cast<jint>(result.get()));
}
}
}
return result;
}
sp<ANativeWindow> android_view_Surface_getNativeWindow(JNIEnv* env, jobject surfaceObj) {
return getSurface(env, surfaceObj);
}
bool android_view_Surface_isInstanceOf(JNIEnv* env, jobject obj) {
return env->IsInstanceOf(obj, gSurfaceClassInfo.clazz);
}
sp<Surface> android_view_Surface_getSurface(JNIEnv* env, jobject surfaceObj) {
return reinterpret_cast<Surface*>(
env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurface));
}
static void setSurface(JNIEnv* env, jobject surfaceObj, const sp<Surface>& surface) {
Surface* const p = reinterpret_cast<Surface*>(
env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurface));
if (surface.get()) {
surface->incStrong(surfaceObj);
}
if (p) {
p->decStrong(surfaceObj);
}
env->SetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurface,
reinterpret_cast<jint>(surface.get()));
// This test is conservative and it would be better to compare the ISurfaces
if (p && p != surface.get()) {
jint generationId = env->GetIntField(surfaceObj,
gSurfaceClassInfo.mGenerationId);
generationId++;
env->SetIntField(surfaceObj,
gSurfaceClassInfo.mGenerationId, generationId);
}
}
static sp<ISurfaceTexture> getISurfaceTexture(JNIEnv* env, jobject surfaceObj) {
if (surfaceObj) {
sp<Surface> surface(getSurface(env, surfaceObj));
if (surface != NULL) {
return surface->getSurfaceTexture();
}
}
return NULL;
}
jobject android_view_Surface_createFromISurfaceTexture(JNIEnv* env,
const sp<ISurfaceTexture>& surfaceTexture) {
if (surfaceTexture == NULL) {
return NULL;
}
sp<Surface> surface(new Surface(surfaceTexture));
if (surface == NULL) {
return NULL;
}
jobject surfaceObj = env->NewObject(gSurfaceClassInfo.clazz, gSurfaceClassInfo.ctor);
if (surfaceObj == NULL) {
if (env->ExceptionCheck()) {
ALOGE("Could not create instance of Surface from ISurfaceTexture.");
LOGE_EX(env);
env->ExceptionClear();
}
return NULL;
}
setSurface(env, surfaceObj, surface);
return surfaceObj;
}
// ----------------------------------------------------------------------------
static void nativeCreate(JNIEnv* env, jobject surfaceObj, jobject sessionObj,
jstring nameStr, jint w, jint h, jint format, jint flags) {
ScopedUtfChars name(env, nameStr);
sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
sp<SurfaceControl> surface = client->createSurface(
String8(name.c_str()), w, h, format, flags);
if (surface == NULL) {
jniThrowException(env, OutOfResourcesException, NULL);
return;
}
setSurfaceControl(env, surfaceObj, surface);
}
static void nativeCreateFromSurfaceTexture(JNIEnv* env, jobject surfaceObj,
jobject surfaceTextureObj) {
sp<SurfaceTexture> st(SurfaceTexture_getSurfaceTexture(env, surfaceTextureObj));
if (st == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"SurfaceTexture has already been released");
return;
}
sp<ISurfaceTexture> bq = st->getBufferQueue();
sp<Surface> surface(new Surface(bq));
if (surface == NULL) {
jniThrowException(env, OutOfResourcesException, NULL);
return;
}
setSurface(env, surfaceObj, surface);
}
static void nativeRelease(JNIEnv* env, jobject surfaceObj) {
setSurfaceControl(env, surfaceObj, NULL);
setSurface(env, surfaceObj, NULL);
}
static void nativeDestroy(JNIEnv* env, jobject surfaceObj) {
sp<SurfaceControl> surfaceControl(getSurfaceControl(env, surfaceObj));
if (SurfaceControl::isValid(surfaceControl)) {
surfaceControl->clear();
}
setSurfaceControl(env, surfaceObj, NULL);
setSurface(env, surfaceObj, NULL);
}
static jboolean nativeIsValid(JNIEnv* env, jobject surfaceObj) {
sp<SurfaceControl> surfaceControl(getSurfaceControl(env, surfaceObj));
if (surfaceControl != NULL) {
return SurfaceControl::isValid(surfaceControl) ? JNI_TRUE : JNI_FALSE;
}
sp<Surface> surface(getSurface(env, surfaceObj));
return Surface::isValid(surface) ? JNI_TRUE : JNI_FALSE;
}
static jint nativeGetIdentity(JNIEnv* env, jobject surfaceObj) {
sp<SurfaceControl> control(getSurfaceControl(env, surfaceObj));
if (control != NULL) {
return jint(control->getIdentity());
}
sp<Surface> surface(getSurface(env, surfaceObj));
if (surface != NULL) {
return jint(surface->getIdentity());
}
return -1;
}
static jboolean nativeIsConsumerRunningBehind(JNIEnv* env, jobject surfaceObj) {
sp<Surface> surface(getSurface(env, surfaceObj));
if (!Surface::isValid(surface)) {
doThrowIAE(env);
return JNI_FALSE;
}
int value = 0;
ANativeWindow* anw = static_cast<ANativeWindow*>(surface.get());
anw->query(anw, NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &value);
return value;
}
static inline SkBitmap::Config convertPixelFormat(PixelFormat format) {
/* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then
we can map to SkBitmap::kARGB_8888_Config, and optionally call
bitmap.setIsOpaque(true) on the resulting SkBitmap (as an accelerator)
*/
switch (format) {
case PIXEL_FORMAT_RGBX_8888: return SkBitmap::kARGB_8888_Config;
case PIXEL_FORMAT_RGBA_8888: return SkBitmap::kARGB_8888_Config;
case PIXEL_FORMAT_RGBA_4444: return SkBitmap::kARGB_4444_Config;
case PIXEL_FORMAT_RGB_565: return SkBitmap::kRGB_565_Config;
case PIXEL_FORMAT_A_8: return SkBitmap::kA8_Config;
default: return SkBitmap::kNo_Config;
}
}
static jobject nativeLockCanvas(JNIEnv* env, jobject surfaceObj, jobject dirtyRectObj) {
sp<Surface> surface(getSurface(env, surfaceObj));
if (!Surface::isValid(surface)) {
doThrowIAE(env);
return NULL;
}
// get dirty region
Region dirtyRegion;
if (dirtyRectObj) {
Rect dirty;
dirty.left = env->GetIntField(dirtyRectObj, gRectClassInfo.left);
dirty.top = env->GetIntField(dirtyRectObj, gRectClassInfo.top);
dirty.right = env->GetIntField(dirtyRectObj, gRectClassInfo.right);
dirty.bottom = env->GetIntField(dirtyRectObj, gRectClassInfo.bottom);
if (!dirty.isEmpty()) {
dirtyRegion.set(dirty);
}
} else {
dirtyRegion.set(Rect(0x3FFF, 0x3FFF));
}
Surface::SurfaceInfo info;
status_t err = surface->lock(&info, &dirtyRegion);
if (err < 0) {
const char* const exception = (err == NO_MEMORY) ?
OutOfResourcesException :
"java/lang/IllegalArgumentException";
jniThrowException(env, exception, NULL);
return NULL;
}
// Associate a SkCanvas object to this surface
jobject canvasObj = env->GetObjectField(surfaceObj, gSurfaceClassInfo.mCanvas);
env->SetIntField(canvasObj, gCanvasClassInfo.mSurfaceFormat, info.format);
SkCanvas* nativeCanvas = reinterpret_cast<SkCanvas*>(
env->GetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas));
SkBitmap bitmap;
ssize_t bpr = info.s * bytesPerPixel(info.format);
bitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, bpr);
if (info.format == PIXEL_FORMAT_RGBX_8888) {
bitmap.setIsOpaque(true);
}
if (info.w > 0 && info.h > 0) {
bitmap.setPixels(info.bits);
} else {
// be safe with an empty bitmap.
bitmap.setPixels(NULL);
}
nativeCanvas->setBitmapDevice(bitmap);
SkRegion clipReg;
if (dirtyRegion.isRect()) { // very common case
const Rect b(dirtyRegion.getBounds());
clipReg.setRect(b.left, b.top, b.right, b.bottom);
} else {
size_t count;
Rect const* r = dirtyRegion.getArray(&count);
while (count) {
clipReg.op(r->left, r->top, r->right, r->bottom, SkRegion::kUnion_Op);
r++, count--;
}
}
nativeCanvas->clipRegion(clipReg);
int saveCount = nativeCanvas->save();
env->SetIntField(surfaceObj, gSurfaceClassInfo.mCanvasSaveCount, saveCount);
if (dirtyRectObj) {
const Rect& bounds(dirtyRegion.getBounds());
env->SetIntField(dirtyRectObj, gRectClassInfo.left, bounds.left);
env->SetIntField(dirtyRectObj, gRectClassInfo.top, bounds.top);
env->SetIntField(dirtyRectObj, gRectClassInfo.right, bounds.right);
env->SetIntField(dirtyRectObj, gRectClassInfo.bottom, bounds.bottom);
}
return canvasObj;
}
static void nativeUnlockCanvasAndPost(JNIEnv* env, jobject surfaceObj, jobject canvasObj) {
jobject ownCanvasObj = env->GetObjectField(surfaceObj, gSurfaceClassInfo.mCanvas);
if (!env->IsSameObject(ownCanvasObj, canvasObj)) {
doThrowIAE(env);
return;
}
sp<Surface> surface(getSurface(env, surfaceObj));
if (!Surface::isValid(surface)) {
return;
}
// detach the canvas from the surface
SkCanvas* nativeCanvas = reinterpret_cast<SkCanvas*>(
env->GetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas));
int saveCount = env->GetIntField(surfaceObj, gSurfaceClassInfo.mCanvasSaveCount);
nativeCanvas->restoreToCount(saveCount);
nativeCanvas->setBitmapDevice(SkBitmap());
env->SetIntField(surfaceObj, gSurfaceClassInfo.mCanvasSaveCount, 0);
// unlock surface
status_t err = surface->unlockAndPost();
if (err < 0) {
doThrowIAE(env);
}
}
static jobject nativeScreenshot(JNIEnv* env, jclass clazz, jobject displayTokenObj,
jint width, jint height, jint minLayer, jint maxLayer, bool allLayers) {
sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
if (displayToken == NULL) {
return NULL;
}
ScreenshotPixelRef* pixels = new ScreenshotPixelRef(NULL);
if (pixels->update(displayToken, width, height,
minLayer, maxLayer, allLayers) != NO_ERROR) {
delete pixels;
return NULL;
}
uint32_t w = pixels->getWidth();
uint32_t h = pixels->getHeight();
uint32_t s = pixels->getStride();
uint32_t f = pixels->getFormat();
ssize_t bpr = s * android::bytesPerPixel(f);
SkBitmap* bitmap = new SkBitmap();
bitmap->setConfig(convertPixelFormat(f), w, h, bpr);
if (f == PIXEL_FORMAT_RGBX_8888) {
bitmap->setIsOpaque(true);
}
if (w > 0 && h > 0) {
bitmap->setPixelRef(pixels)->unref();
bitmap->lockPixels();
} else {
// be safe with an empty bitmap.
delete pixels;
bitmap->setPixels(NULL);
}
return GraphicsJNI::createBitmap(env, bitmap, false, NULL);
}
static void nativeOpenTransaction(JNIEnv* env, jclass clazz) {
SurfaceComposerClient::openGlobalTransaction();
}
static void nativeCloseTransaction(JNIEnv* env, jclass clazz) {
SurfaceComposerClient::closeGlobalTransaction();
}
static void nativeSetAnimationTransaction(JNIEnv* env, jclass clazz) {
SurfaceComposerClient::setAnimationTransaction();
}
static void nativeSetLayer(JNIEnv* env, jobject surfaceObj, jint zorder) {
sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
if (surface == NULL) return;
status_t err = surface->setLayer(zorder);
if (err < 0 && err != NO_INIT) {
doThrowIAE(env);
}
}
static void nativeSetPosition(JNIEnv* env, jobject surfaceObj, jfloat x, jfloat y) {
sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
if (surface == NULL) return;
status_t err = surface->setPosition(x, y);
if (err < 0 && err != NO_INIT) {
doThrowIAE(env);
}
}
static void nativeSetSize(JNIEnv* env, jobject surfaceObj, jint w, jint h) {
sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
if (surface == NULL) return;
status_t err = surface->setSize(w, h);
if (err < 0 && err != NO_INIT) {
doThrowIAE(env);
}
}
static void nativeSetFlags(JNIEnv* env, jobject surfaceObj, jint flags, jint mask) {
sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
if (surface == NULL) return;
status_t err = surface->setFlags(flags, mask);
if (err < 0 && err != NO_INIT) {
doThrowIAE(env);
}
}
static void nativeSetTransparentRegionHint(JNIEnv* env, jobject surfaceObj, jobject regionObj) {
sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
if (surface == NULL) return;
SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
if (!region) {
doThrowIAE(env);
return;
}
const SkIRect& b(region->getBounds());
Region reg(Rect(b.fLeft, b.fTop, b.fRight, b.fBottom));
if (region->isComplex()) {
SkRegion::Iterator it(*region);
while (!it.done()) {
const SkIRect& r(it.rect());
reg.addRectUnchecked(r.fLeft, r.fTop, r.fRight, r.fBottom);
it.next();
}
}
status_t err = surface->setTransparentRegionHint(reg);
if (err < 0 && err != NO_INIT) {
doThrowIAE(env);
}
}
static void nativeSetAlpha(JNIEnv* env, jobject surfaceObj, jfloat alpha) {
sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
if (surface == NULL) return;
status_t err = surface->setAlpha(alpha);
if (err < 0 && err != NO_INIT) {
doThrowIAE(env);
}
}
static void nativeSetMatrix(JNIEnv* env, jobject surfaceObj,
jfloat dsdx, jfloat dtdx, jfloat dsdy, jfloat dtdy) {
sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
if (surface == NULL) return;
status_t err = surface->setMatrix(dsdx, dtdx, dsdy, dtdy);
if (err < 0 && err != NO_INIT) {
doThrowIAE(env);
}
}
static void nativeSetWindowCrop(JNIEnv* env, jobject surfaceObj, jobject cropObj) {
const sp<SurfaceControl>& surface(getSurfaceControl(env, surfaceObj));
if (surface == NULL) return;
Rect crop;
if (cropObj) {
crop.left = env->GetIntField(cropObj, gRectClassInfo.left);
crop.top = env->GetIntField(cropObj, gRectClassInfo.top);
crop.right = env->GetIntField(cropObj, gRectClassInfo.right);
crop.bottom = env->GetIntField(cropObj, gRectClassInfo.bottom);
} else {
crop.left = crop.top = crop.right = crop.bottom = 0;
}
status_t err = surface->setCrop(crop);
if (err < 0 && err != NO_INIT) {
doThrowIAE(env);
}
}
static void nativeSetLayerStack(JNIEnv* env, jobject surfaceObj, jint layerStack) {
sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
if (surface == NULL) return;
status_t err = surface->setLayerStack(layerStack);
if (err < 0 && err != NO_INIT) {
doThrowIAE(env);
}
}
static jobject nativeGetBuiltInDisplay(JNIEnv* env, jclass clazz, jint id) {
sp<IBinder> token(SurfaceComposerClient::getBuiltInDisplay(id));
return javaObjectForIBinder(env, token);
}
static jobject nativeCreateDisplay(JNIEnv* env, jclass clazz, jstring nameObj) {
ScopedUtfChars name(env, nameObj);
sp<IBinder> token(SurfaceComposerClient::createDisplay(String8(name.c_str())));
return javaObjectForIBinder(env, token);
}
static void nativeSetDisplaySurface(JNIEnv* env, jclass clazz,
jobject tokenObj, jobject surfaceObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return;
sp<ISurfaceTexture> surfaceTexture(getISurfaceTexture(env, surfaceObj));
SurfaceComposerClient::setDisplaySurface(token, surfaceTexture);
}
static void nativeSetDisplayLayerStack(JNIEnv* env, jclass clazz,
jobject tokenObj, jint layerStack) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return;
SurfaceComposerClient::setDisplayLayerStack(token, layerStack);
}
static void nativeSetDisplayProjection(JNIEnv* env, jclass clazz,
jobject tokenObj, jint orientation, jobject layerStackRectObj, jobject displayRectObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return;
Rect layerStackRect;
layerStackRect.left = env->GetIntField(layerStackRectObj, gRectClassInfo.left);
layerStackRect.top = env->GetIntField(layerStackRectObj, gRectClassInfo.top);
layerStackRect.right = env->GetIntField(layerStackRectObj, gRectClassInfo.right);
layerStackRect.bottom = env->GetIntField(layerStackRectObj, gRectClassInfo.bottom);
Rect displayRect;
displayRect.left = env->GetIntField(displayRectObj, gRectClassInfo.left);
displayRect.top = env->GetIntField(displayRectObj, gRectClassInfo.top);
displayRect.right = env->GetIntField(displayRectObj, gRectClassInfo.right);
displayRect.bottom = env->GetIntField(displayRectObj, gRectClassInfo.bottom);
SurfaceComposerClient::setDisplayProjection(token, orientation, layerStackRect, displayRect);
}
static jboolean nativeGetDisplayInfo(JNIEnv* env, jclass clazz,
jobject tokenObj, jobject infoObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return JNI_FALSE;
DisplayInfo info;
if (SurfaceComposerClient::getDisplayInfo(token, &info)) {
return JNI_FALSE;
}
env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.width, info.w);
env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.height, info.h);
env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.refreshRate, info.fps);
env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.density, info.density);
env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.xDpi, info.xdpi);
env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.yDpi, info.ydpi);
return JNI_TRUE;
}
static void nativeBlankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return;
ALOGD_IF_SLOW(100, "Excessive delay in blankDisplay() while turning screen off");
SurfaceComposerClient::blankDisplay(token);
}
static void nativeUnblankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return;
ALOGD_IF_SLOW(100, "Excessive delay in unblankDisplay() while turning screen on");
SurfaceComposerClient::unblankDisplay(token);
}
// ----------------------------------------------------------------------------
static void nativeCopyFrom(JNIEnv* env, jobject surfaceObj, jobject otherObj) {
/*
* This is used by the WindowManagerService just after constructing
* a Surface and is necessary for returning the Surface reference to
* the caller. At this point, we should only have a SurfaceControl.
*/
sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
sp<SurfaceControl> other(getSurfaceControl(env, otherObj));
if (!SurfaceControl::isSameSurface(surface, other)) {
// we reassign the surface only if it's a different one
// otherwise we would loose our client-side state.
setSurfaceControl(env, surfaceObj, other);
}
}
static void nativeTransferFrom(JNIEnv* env, jobject surfaceObj, jobject otherObj) {
sp<SurfaceControl> control(getSurfaceControl(env, otherObj));
sp<Surface> surface(android_view_Surface_getSurface(env, otherObj));
setSurfaceControl(env, surfaceObj, control);
setSurface(env, surfaceObj, surface);
setSurfaceControl(env, otherObj, NULL);
setSurface(env, otherObj, NULL);
}
static void nativeReadFromParcel(JNIEnv* env, jobject surfaceObj, jobject parcelObj) {
Parcel* parcel = parcelForJavaObject(env, parcelObj);
if (parcel == NULL) {
doThrowNPE(env);
return;
}
sp<Surface> surface(Surface::readFromParcel(*parcel));
setSurfaceControl(env, surfaceObj, NULL);
setSurface(env, surfaceObj, surface);
}
static void nativeWriteToParcel(JNIEnv* env, jobject surfaceObj, jobject parcelObj) {
Parcel* parcel = parcelForJavaObject(env, parcelObj);
if (parcel == NULL) {
doThrowNPE(env);
return;
}
// The Java instance may have a SurfaceControl (in the case of the
// WindowManager or a system app). In that case, we defer to the
// SurfaceControl to send its ISurface. Otherwise, if the Surface is
// available we let it parcel itself. Finally, if the Surface is also
// NULL we fall back to using the SurfaceControl path which sends an
// empty surface; this matches legacy behavior.
sp<SurfaceControl> control(getSurfaceControl(env, surfaceObj));
if (control != NULL) {
SurfaceControl::writeSurfaceToParcel(control, parcel);
} else {
sp<Surface> surface(android_view_Surface_getSurface(env, surfaceObj));
if (surface != NULL) {
Surface::writeToParcel(surface, parcel);
} else {
SurfaceControl::writeSurfaceToParcel(NULL, parcel);
}
}
}
// ----------------------------------------------------------------------------
static JNINativeMethod gSurfaceMethods[] = {
{"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIII)V",
(void*)nativeCreate },
{"nativeCreateFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)V",
(void*)nativeCreateFromSurfaceTexture },
{"nativeRelease", "()V",
(void*)nativeRelease },
{"nativeDestroy", "()V",
(void*)nativeDestroy },
{"nativeIsValid", "()Z",
(void*)nativeIsValid },
{"nativeGetIdentity", "()I",
(void*)nativeGetIdentity },
{"nativeIsConsumerRunningBehind", "()Z",
(void*)nativeIsConsumerRunningBehind },
{"nativeLockCanvas", "(Landroid/graphics/Rect;)Landroid/graphics/Canvas;",
(void*)nativeLockCanvas },
{"nativeUnlockCanvasAndPost", "(Landroid/graphics/Canvas;)V",
(void*)nativeUnlockCanvasAndPost },
{"nativeScreenshot", "(Landroid/os/IBinder;IIIIZ)Landroid/graphics/Bitmap;",
(void*)nativeScreenshot },
{"nativeOpenTransaction", "()V",
(void*)nativeOpenTransaction },
{"nativeCloseTransaction", "()V",
(void*)nativeCloseTransaction },
{"nativeSetAnimationTransaction", "()V",
(void*)nativeSetAnimationTransaction },
{"nativeSetLayer", "(I)V",
(void*)nativeSetLayer },
{"nativeSetPosition", "(FF)V",
(void*)nativeSetPosition },
{"nativeSetSize", "(II)V",
(void*)nativeSetSize },
{"nativeSetTransparentRegionHint", "(Landroid/graphics/Region;)V",
(void*)nativeSetTransparentRegionHint },
{"nativeSetAlpha", "(F)V",
(void*)nativeSetAlpha },
{"nativeSetMatrix", "(FFFF)V",
(void*)nativeSetMatrix },
{"nativeSetFlags", "(II)V",
(void*)nativeSetFlags },
{"nativeSetWindowCrop", "(Landroid/graphics/Rect;)V",
(void*)nativeSetWindowCrop },
{"nativeSetLayerStack", "(I)V",
(void*)nativeSetLayerStack },
{"nativeGetBuiltInDisplay", "(I)Landroid/os/IBinder;",
(void*)nativeGetBuiltInDisplay },
{"nativeCreateDisplay", "(Ljava/lang/String;)Landroid/os/IBinder;",
(void*)nativeCreateDisplay },
{"nativeSetDisplaySurface", "(Landroid/os/IBinder;Landroid/view/Surface;)V",
(void*)nativeSetDisplaySurface },
{"nativeSetDisplayLayerStack", "(Landroid/os/IBinder;I)V",
(void*)nativeSetDisplayLayerStack },
{"nativeSetDisplayProjection", "(Landroid/os/IBinder;ILandroid/graphics/Rect;Landroid/graphics/Rect;)V",
(void*)nativeSetDisplayProjection },
{"nativeGetDisplayInfo", "(Landroid/os/IBinder;Landroid/view/Surface$PhysicalDisplayInfo;)Z",
(void*)nativeGetDisplayInfo },
{"nativeBlankDisplay", "(Landroid/os/IBinder;)V",
(void*)nativeBlankDisplay },
{"nativeUnblankDisplay", "(Landroid/os/IBinder;)V",
(void*)nativeUnblankDisplay },
{"nativeCopyFrom", "(Landroid/view/Surface;)V",
(void*)nativeCopyFrom },
{"nativeTransferFrom", "(Landroid/view/Surface;)V",
(void*)nativeTransferFrom },
{"nativeReadFromParcel", "(Landroid/os/Parcel;)V",
(void*)nativeReadFromParcel },
{"nativeWriteToParcel", "(Landroid/os/Parcel;)V",
(void*)nativeWriteToParcel },
};
int register_android_view_Surface(JNIEnv* env)
{
int err = AndroidRuntime::registerNativeMethods(env, "android/view/Surface",
gSurfaceMethods, NELEM(gSurfaceMethods));
jclass clazz = env->FindClass("android/view/Surface");
gSurfaceClassInfo.clazz = jclass(env->NewGlobalRef(clazz));
gSurfaceClassInfo.mNativeSurface =
env->GetFieldID(gSurfaceClassInfo.clazz, ANDROID_VIEW_SURFACE_JNI_ID, "I");
gSurfaceClassInfo.mNativeSurfaceControl =
env->GetFieldID(gSurfaceClassInfo.clazz, "mNativeSurfaceControl", "I");
gSurfaceClassInfo.mGenerationId =
env->GetFieldID(gSurfaceClassInfo.clazz, "mGenerationId", "I");
gSurfaceClassInfo.mCanvas =
env->GetFieldID(gSurfaceClassInfo.clazz, "mCanvas", "Landroid/graphics/Canvas;");
gSurfaceClassInfo.mCanvasSaveCount =
env->GetFieldID(gSurfaceClassInfo.clazz, "mCanvasSaveCount", "I");
gSurfaceClassInfo.ctor = env->GetMethodID(gSurfaceClassInfo.clazz, "<init>", "()V");
clazz = env->FindClass("android/graphics/Canvas");
gCanvasClassInfo.mNativeCanvas = env->GetFieldID(clazz, "mNativeCanvas", "I");
gCanvasClassInfo.mSurfaceFormat = env->GetFieldID(clazz, "mSurfaceFormat", "I");
clazz = env->FindClass("android/graphics/Rect");
gRectClassInfo.left = env->GetFieldID(clazz, "left", "I");
gRectClassInfo.top = env->GetFieldID(clazz, "top", "I");
gRectClassInfo.right = env->GetFieldID(clazz, "right", "I");
gRectClassInfo.bottom = env->GetFieldID(clazz, "bottom", "I");
clazz = env->FindClass("android/view/Surface$PhysicalDisplayInfo");
gPhysicalDisplayInfoClassInfo.width = env->GetFieldID(clazz, "width", "I");
gPhysicalDisplayInfoClassInfo.height = env->GetFieldID(clazz, "height", "I");
gPhysicalDisplayInfoClassInfo.refreshRate = env->GetFieldID(clazz, "refreshRate", "F");
gPhysicalDisplayInfoClassInfo.density = env->GetFieldID(clazz, "density", "F");
gPhysicalDisplayInfoClassInfo.xDpi = env->GetFieldID(clazz, "xDpi", "F");
gPhysicalDisplayInfoClassInfo.yDpi = env->GetFieldID(clazz, "yDpi", "F");
return err;
}
};