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