SurfaceControl.screenshot() usage | Solution to return null after using SurfaceControl.screenshot()

Preface

SurfaceControl.screenshot()It is the system's screenshot method. It belongs to the system API and is not open to users. Therefore, if you want to use it, you need the system's signature ( platform.keystorefile) to call it.
On higher versions of Android (for example android 11), if there is no system signature, even if reflection is used, a method cannot be found exception will be reported. However, if there is a system signature, just call it directly.



Old way to use

Many tutorials on the Internet show old calling methods, which are no longer applicable in higher versions, as follows:

  1. Screenshot using reflection call
//获取屏幕尺寸
DisplayMetrics mDisplayMetrics = new DisplayMetrics();
float[] dims = {
    
    mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels};
//调用screenshot()
try {
    
    
    Class<?> demo = Class.forName("android.view.SurfaceControl");
    Method method = demo.getDeclaredMethod("screenshot", int.class,int.class);
    mScreenBitmap = (Bitmap) method.invoke(null,(int) dims[0],(int) dims[1]);
} catch (Exception e) {
    
    
    e.printStackTrace();
}
//显示bitmap
ImageView image = findViewById(R.id.image);
image.setImageBitmap(mScreenBitmap);
  1. Directly call the screenshot method to take a screenshot
//获取屏幕尺寸
DisplayMetrics mDisplayMetrics = new DisplayMetrics();
float[] dims = {
    
    mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels};
//调用screenshot()
Bitmap mScreenBitmap = SurfaceControl.screenshot((int) dims[0],(int) dims[1]);
//显示bitmap
ImageView image = findViewById(R.id.image);
image.setImageBitmap(mScreenBitmap);


New ways to use

In later versions of Android, screenshot(width, height)the method has been cancelled, so the method of only passing in two int values ​​does not work .

Among the remaining screenshot() construction parameters, screenshot(Rect sourceCrop, int width, int height, int rotation)this method is the most convenient to use.
The parameter description is as follows:

parameter effect
sourceCrop The portion of the screen to be captured in a bitmap; the caller can pass in this if no cropping is required new Rect().
width Returns the desired width of the bitmap; the original screen will be scaled down to this size; the caller can pass in this if scaling is not required 0.
height Returns the desired height of the bitmap; the original screen will be scaled down to this size; the caller can pass in this if scaling is not required 0.
rotation Apply a custom clockwise rotation to the screenshot, ie Surface.ROTION_0,90,180,270. By default SurfaceFlinger will always take screenshots in its original portrait orientation, so this is useful for returning screenshots that are independent of device orientation

Therefore, on the new android system, we can write like this:

//调用screenshot()
//参数传入默认的,表示直接截全屏并且不缩放,不裁剪,不旋转
Bitmap mScreenBitmap = SurfaceControl.screenshot(new Rect(), 0, 0, Surface.ROTATION_0);
//显示bitmap
ImageView image = findViewById(R.id.image);
image.setImageBitmap(mScreenBitmap);

Since this method does not depend on Activity, it can be used to achieve the effect of background screenshots . However, it should be noted that calling this method requires the system's signature ( platform.keystore), or addingandroid:sharedUserId="android.uid.system"



Solution to screenshot() always returning null

If no error is reported after you call it, but the returned value bitmapis always null, it may be a permissions issue. The solution is as follows:

  1. increasing AndroidManifest.xml_android:sharedUserId="android.uid.system"
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.xxx"
    android:sharedUserId="android.uid.system">
	...
  1. If you don’t want to turn the app into a system app, you can AndroidManifest.xmladd separate permissions in
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.xxx">

	<!-- 增加此权限 -->
    <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
	...

Just use one of the above two methods .

Guess you like

Origin blog.csdn.net/Guan_li_peng/article/details/128345431