之前有个需求,获取launcher的截屏,那么自然无法通过View来转换成bitmap。那么只能通过系统源码来获取,网上找到的基本都是以下方法(注意需要系统权限):
surfacaController.screenshot(int,int);
但是这个方法有两个问题:
1、悬浮控件会排列到屏幕的左上角,导致截屏效果不理想。
2、旋转屏幕后截屏,图片会存在旋转问题。
于是翻看源码发现这个方法有很多重载,然后很幸运的是真给我找到了一个重载:
/**
1994 * @see SurfaceControl#screenshot(Rect, int, int, boolean, int)}
1995 * @hide
1996 */
1997 @UnsupportedAppUsage
1998 public static Bitmap screenshot(Rect sourceCrop, int width, int height, int rotation) {
1999 return screenshot(sourceCrop, width, height, false, rotation);
2000 }
2002 /**
2003 * Copy the current screen contents into a hardware bitmap and return it.
2004 * Note: If you want to modify the Bitmap in software, you will need to copy the Bitmap into
2005 * a software Bitmap using {@link Bitmap#copy(Bitmap.Config, boolean)}
2006 *
2007 * CAVEAT: Versions of screenshot that return a {@link Bitmap} can be extremely slow; avoid use
2008 * unless absolutely necessary; prefer the versions that use a {@link Surface} such as
2009 * {@link SurfaceControl#screenshot(IBinder, Surface)} or {@link GraphicBuffer} such as
2010 * {@link SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)}.
2011 *
2012 * @see SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)}
2013 * @hide
2014 */
2015 @UnsupportedAppUsage
2016 public static Bitmap screenshot(Rect sourceCrop, int width, int height,
2017 boolean useIdentityTransform, int rotation) {
2018 // TODO: should take the display as a parameter
2019 final IBinder displayToken = SurfaceControl.getInternalDisplayToken();
2020 if (displayToken == null) {
2021 Log.w(TAG, "Failed to take screenshot because internal display is disconnected");
2022 return null;
2023 }
2024
2025 if (rotation == ROTATION_90 || rotation == ROTATION_270) {
2026 rotation = (rotation == ROTATION_90) ? ROTATION_270 : ROTATION_90;
2027 }
2028
2029 SurfaceControl.rotateCropForSF(sourceCrop, rotation);
2030 final ScreenshotGraphicBuffer buffer = screenshotToBuffer(displayToken, sourceCrop, width,
2031 height, useIdentityTransform, rotation);
2032
2033 if (buffer == null) {
2034 Log.w(TAG, "Failed to take screenshot");
2035 return null;
2036 }
2037 return Bitmap.wrapHardwareBuffer(buffer.getGraphicBuffer(), buffer.getColorSpace());
2038 }
2094 private static void rotateCropForSF(Rect crop, int rot) {
2095 if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
2096 int tmp = crop.top;
2097 crop.top = crop.left;
2098 crop.left = tmp;
2099 tmp = crop.right;
2100 crop.right = crop.bottom;
2101 crop.bottom = tmp;
2102 }
2103 }
可以发现,最后一个int类型参数代表的是拍摄的角度,如果向左旋转截屏就是270度,向右旋转截屏就是90度。
//解释:
ROTATION_0 //int值为0
ROTATION_90 //int值为1
ROTATION_180 //int值为2
ROTATION_270 //int值为3
现在就解决了屏幕旋转截屏的问题,但是惊喜的发现悬浮控件出现在左上角的问题也顺带解决了,这个我还没搞懂是什么原因,懂的大神请评论区指教。
最后贴上调用代码:
//系统截屏
private Bitmap screenshotSystem() {
Class<?> demo;
Bitmap bitmap = null;
try {
demo = Class.forName("android.view.SurfaceControl");
Method method = demo.getMethod("screenshot", Rect.class, int.class, int.class, int.class);
Object obj = obj = method.invoke(null, new Rect(), getWidth(), getHeight(), int);; //最后一个参数是屏幕旋转角度0,1,2,3对应0,90,180,270
bitmap = (Bitmap) obj;
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}