[Android] SurfaceControl 을 이용해서 화면 Screenshot

안드로이드에서 SurfaceControl 의 screenshot 메서드를 이용해서 아래와 같이 호출 뒤 리턴값으로 Bitmap 정보를 받을 수 있다.

SurfaceControl 은 hide 클래스이기 때문에 일반적으로 런타임시에 리플렉션으로 호출한다.

SurfaceControl 메서드를 따라가다보면 결국 Surface Flinger 쪽의 메서드를 호출 하게 되는데 결국 android.permission.READ_FRAME_BUFFER 퍼미션이 필요하다.

위 퍼미션은 일반 third-party 앱은 가질 수 없다.

// Take the screenshot
mScreenBitmap = SurfaceControl.screenshot((int) dims[0], (int) dims[1]);
  if (mScreenBitmap == null) {
      notifyScreenshotError(mContext, mNotificationManager);
      finisher.run();
      return;
}
...

 /**
     * Like {@link SurfaceControl#screenshot(int, int, int, int, boolean)} but
     * includes all Surfaces in the screenshot.
     *
     * @param width The desired width of the returned bitmap; the raw
     * screen will be scaled down to this size.
     * @param height The desired height of the returned bitmap; the raw
     * screen will be scaled down to this size.
     * @return Returns a Bitmap containing the screen contents, or null
     * if an error occurs. Make sure to call Bitmap.recycle() as soon as
     * possible, once its content is not needed anymore.
     */
    public static Bitmap screenshot(int width, int height) {
        // TODO: should take the display as a parameter
        IBinder displayToken = SurfaceControl.getBuiltInDisplay(
                SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN);
        return nativeScreenshot(displayToken, new Rect(), width, height, 0, 0, true,
                false, Surface.ROTATION_0);
    }

SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN은 화면을 뜻한다.

nativeScreenshot 메서드는 인자로 범위를 비롯해서 레이어 범위 등을 받는데 레이어를 분리해서 캡쳐할 수도 있다.