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