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