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