android自动截图实现,Android 5.0及以上实现屏幕截图

在Android 5.0,API 21 之前想要截图系统屏幕必须Root才能完成,5.0之后开放了接口,下面看我们是怎么实现的。

--

1. 涉及到的相关类

1. MediaProjectionManager

官方原话: Manages the retrieval of certain types of {@link MediaProjection} tokens.

这个类通过 Context#getSystemService 中MEDIA_PROJECTION_SERVICE 获取,他的功能就是获取MediaProjection

2. MediaProjection

官方原话:A token granting applications the ability to capture screen contents and/or record system audio. The exact capabilities granted depend on the type of MediaProjection.在这个类中我们能获取到屏幕的内容

3. ImageReader

官方原话:The ImageReader class allows direct application access to image data

rendered into a {@link android.view.Surface}

通过这个类我们可以把Surface转换成图片

2. 上面三个类就可以完成我们截取屏幕图片的操作,那么下面我们将解释他们是怎么合作完成的

1. 首先获取用户授权,截图屏幕需要用户手动授权后才能操作

@TargetApi(Build.VERSION_CODES.LOLLIPOP)

public void requestCapturePermission() {

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {

//5.0 之后才允许使用屏幕截图

return;

}

MediaProjectionManager mediaProjectionManager = (MediaProjectionManager)

getSystemService(Context.MEDIA_PROJECTION_SERVICE);

startActivityForResult(

mediaProjectionManager.createScreenCaptureIntent(),

REQUEST_MEDIA_PROJECTION);

}

这里必须使用startActivityForResult 因为在createScreenCaptureIntent() 方法中会返回用户授权截取屏幕的结果,用户根据下面弹窗允许或者拒绝

3c90016e594e8d493f57588d565639e7.png

授权

用户选择后在Activity 的onActivityResult 中操作返回的结果data

@Override

protected void onActivityResult(int requestCode, int resultCode, Intent data) {

super.onActivityResult(requestCode, resultCode, data);

switch (requestCode) {

case REQUEST_MEDIA_PROJECTION:

if (resultCode == RESULT_OK && data != null) {

FloatWindowsService.setResultData(data);

startService(new Intent(getApplicationContext(), FloatWindowsService.class));

}

break;

}

}

这里我是用FloatWindowsService在桌面上显示一个悬浮按钮,点击截屏,下面我们看在FloatWindowsService 是如何实现截图

2. 截取屏幕内容生成Bitmap

首先创建ImageReader实例

private void createImageReader() {

mImageReader = ImageReader.newInstance(mScreenWidth, mScreenHeight, PixelFormat.RGBA_8888, 2);

}

然后点击事件中触发startScreenShot()

private void startScreenShot() {

mFloatView.setVisibility(View.GONE);

Handler handler = new Handler();

handler.postDelayed(new Runnable() {

public void run() {

//获取当前屏幕内容

startVirtual();

}

}, 5);

handler.postDelayed(new Runnable() {

public void run() {

//生成图片保存到本地

startCapture();

}

}, 30);

}

在startVirtual() 方法中我们做一件事,就是获取当前屏幕内容

public void startVirtual() {

if (mMediaProjection != null) {

virtualDisplay();

} else {

setUpMediaProjection();

virtualDisplay();

}

}

与此同时需要获取MediaProjection 实例,而mResultData 是授权后返回的结果

public void setUpMediaProjection() {

if (mResultData == null) {

Intent intent = new Intent(Intent.ACTION_MAIN);

intent.addCategory(Intent.CATEGORY_LAUNCHER);

startActivity(intent);

} else {

//mResultData是在Activity中用户授权后返回的结果

mMediaProjection = getMediaProjectionManager().getMediaProjection(Activity.RESULT_OK, mResultData);

}

}

最终得到当前屏幕的内容,注意这里mImageReader.getSurface()被传入,屏幕的数据也将会在ImageReader中的Surface中

private void virtualDisplay() {

mVirtualDisplay = mMediaProjection.createVirtualDisplay("screen-mirror",

mScreenWidth, mScreenHeight, mScreenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,

mImageReader.getSurface(), null, null);

}

最后把mImageReader得到的屏幕内容数据转换成图片,在AsyncTask中处理,

Image.Plane中的 buffer 数据并不是完全是Bitmap所需要的,需要注意下面3点

1. Image 设置的图片格式与Bitmap设置的必须一致

2. 缓冲数据存在行间距,所以我们必须去除这些间距

3. Image 使用后必须调用image.close();关闭,否则再次使用会报错

@Override

protected Bitmap doInBackground(Image... params) {

if (params == null || params.length < 1 || params[0] == null) {

return null;

}

Image image = params[0];

int width = image.getWidth();

int height = image.getHeight();

final Image.Plane[] planes = image.getPlanes();

final ByteBuffer buffer = planes[0].getBuffer();

//每个像素的间距

int pixelStride = planes[0].getPixelStride();

//总的间距

int rowStride = planes[0].getRowStride();

int rowPadding = rowStride - pixelStride * width;

Bitmap bitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888);

bitmap.copyPixelsFromBuffer(buffer);

bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height);

image.close();

最后把生成的bitmap保存起来,就ok了

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值