转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/53966818

前言:一年半多以前,我们曾有个项目,要做一个截屏功能,当时负责调研的同事,答应了产品上这个功能,但开发一周后,发现,无法实现截取手机屏幕图像,须要root权限,才能做。因为最近研究MediaProjection,意外的发现,竟然无须root,可以轻松实现次功能。曾经被做不到的,如今做到了,很难相信此时的心情。看下今天的Agenda:

  • Android源码中使用组合键是如何实现屏幕截图功能的?
  • MediaProjection实现手机截屏效果
  • 简要思路

以我的魅族手机为例,是同时按电源键+音量下键来实现截屏,苹果手机则是电源键 + HOME键,小米手机是菜单键+音量下键,而HTC一般是按住电源键再按左下角的“主页”键。那么Android源码中使用组合键是如何实现屏幕截图功能呢?

Android源码中对按键的捕获位于文件PhoneWindowManager.java中





这个类处理所有的按键事件,其中函数interceptKeyBeforeQueueing()会对常用的按键做特殊处理。以我自己魅族手机为例,是同时按电源键和音量下键来截屏,那么在这个方法中可以看到这么如下代码:

interceptKeyBeforeQueueing







以上代码总结为:当按下音量下键时,且是down时,会进入到interceptPowerKeyDown方法中,而按下电源键时,且是down时,也会进入interceptPowerKeyDown方法中,接着进入这个方法中看下:

interceptPowerKeyDown







以上代码总结为:如果是interactive为true,且一些其他条件满足时,会记录电源键按下的时间,且进入interceptScreenshotChord方法中:







以上代码总结为:用两个布尔变量判断是否同时按了音量下键和电源键后,再计算两个按键响应Down事件之间的时间差不超过( // Time to volume and power must be pressed within this interval of each other.

private static final long SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS = 150;)150毫秒,也就认为是同时按了这两个键后,此种case时,才是真正的屏幕截屏的组合键。

获取到组合键后,会用一个mHandler 开始post一个runnable,进入这个runnable中:





以上代码,会执行方法takeScreenshot方法,接着进入:







以上代码总结为:使用AIDL绑定了service服务到”com.android.systemui.screenshot.TakeScreenshotService”,注意在service连接成功时,对message的msg.arg1和msg.arg2两个参数的赋值。其中在mScreenshotTimeout中对服务service做了超时处理。接着我们找到实现这个服务service的类TakeScreenshotService,该类在(frameworks/base/packages/SystemUI/src/com/android/systemui/screenshot包下):







对应代码如下:







以上代码总结为:引用了GlobalScreenshot类,调用了takeScreenshot方法,紧接着进入:







以上代码总结为:引用SurfaceControl类,调用了screenshot方法, 传入了屏幕的宽和高,这两个参数,接着进入SurfaceControl类中,位于frameworks/base/core/java/android/view目录下:







对应screenshot方法代码如下:







screenshot







最终到达native方法中nativeScreenshot







上面就是java层的部分,接着到jni层,在\frameworks\base\core\jni\android_view_SurfaceControl.cpp中:







以上代码总结为:到jni中,映射nativeScreenshot方法的是nativeScreenshotBitmap函数,这个函数代码如下:









以上代码总结为:实例化ScreenshotClient类,且调用update方法,最终通过构造一个新的bitmap,把screenshot得到的像素点,及相关信息达到bitmap,通过GraphicsJNI,重新创建一个bitmap返回给上层。

我们接着看下ScreenshotClient的声明,位于SurfaceComposerClient.h中。注意这个类是在frameworks\native\include\gui中,而前面android_view_SurfaceControl是在\frameworks\base\core\jni\下







最后辗转来到c++层,就是\frameworks\native\libs\gui下的SurfaceComposerClient.cpp中,实现ScreenshotClient声明的函数update,如下:







以上代码总结为:通过ISurfaceComposer接口,调用captureScreen函数,我们找到其对应的实现类\frameworks\native\libs\gui\ISurfaceComposer.cpp,找到captureScreen函数的实现如下:







以上代码总结为:把IGraphicBufferProducer,作为binder开始写到parcel中,最后一版看到transact,就知道当前是client端,而server端的onTransact()函数,会接收到传过来的参数。如这里的data。接着看下BnSurfaceComposer的onTransact方法,这个BnSurfaceComposer依然是在ISurfaceComposer.cpp中。







以上代码总结为:当进入到CAPTURE_SCREEN中,data会读取IGraphicBufferProducer生成出的图像buffe,接着调用 reply->writeInt32(res);返回给client.然后再回调到java层。以上就是系统截屏的原理。

那对于多媒体这块可以通过MediaProjection+VirturalDisplay+MediaProjectionManager来实现截屏,以下我的实例效果图:

效果图1:操作过程,点击浮动小剪刀,就可以实现截屏,拖动小剪刀,可到任意位置:

效果图2:截图后过程

主界面:

体验apk:

链接:http://pan.baidu.com/s/1kVugxCV 密码:97z0

实现思路:

  • MediaProjection是一个token,用户可以授予应用程序捕获屏幕内容和录制系统音频。
  • 屏幕截取,可以通过MediaProjectionManager的createScreenCaptureIntent,创建一个intent,保证有足够能力截取屏幕上的内容,但是没有系统声音。
  • 调用setUpMediaProjection()方法获取共享数据并对其进行赋值;若已初始化,则直接调用virtualDisplay()方法利用之前定义的变量对截屏环境进行初始化。

第一时间获得博客更新提醒,以及更多android干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。



如果你觉得好,随手点赞,也是对笔者的肯定,也可以分享此公众号给你更多的人,原创不易

Android Multimedia框架总结(二十五)MediaProjection实现手机截屏(无须root)的更多相关文章

  1. Android Multimedia框架总结(十五)Camera框架之Camera2补充

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52751055 前言:监于5.0之 ...

  2. Android Multimedia框架总结(十二)CodeC部分之OMXCodec与OMX事件回调流程

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52629449 前言:上篇文中分析 ...

  3. Android Multimedia框架总结(十九)Camera2框架C/S模型之CameraService启动及与Client连接过程

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/53150322 Agenda: 一 ...

  4. Android Multimedia框架总结(十六)Camera2框架之openCamera及session过程

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52942533 前言:前一篇介绍了 ...

  5. Android Multimedia框架总结(十四)Camera框架初识及自定义相机案例

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52738492 前言:国庆节告一段 ...

  6. Android Multimedia框架总结(十)Stagefright框架之音视频输出过程

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52560012 前言:上篇文中最后 ...

  7. Android项目实战(二十五):Android studio 混淆+打包+验证是否成功

    前言: 单挑Android项目,最近即时通讯用到环信,集成sdk的时候 官方有一句 在 ProGuard 文件中加入以下 keep. -keep class com.hyphenate.** {*;} ...

  8. Android Studio 使用教程(二十五)之运行Android Studio工程

    一.Android虚拟设备入口 上期我们使用了Android Studio创建了HeloWorld工程,要想运行该工程,首先需要一个Android虚拟设备来模拟Android程序的运行. 重新打开An ...

  9. Android核心分析之二十五Android GDI之共享缓冲区机制

    Androird GDI之共享缓冲区机制 1  native_handle_t对private_handle_t 的包裹     private_handle_t是gralloc.so使用的本地缓冲区 ...

随机推荐

  1. html标记语言 --格式标记

    html标记语言 --格式标记 一.格式标记 1.<br>单标记,强制换行标记,让后面的文字.图片.表格等显示在下一行 2.<p>换段落标记 3.<center>居 ...

  2. 用js来实现那些数据结构05(栈02-栈的应用)

    上一篇文章我们一起实现了栈,那么这一篇文章我们一起来用栈解决问题.看看如何用栈来解决进制转换,平衡圆括号以及汉诺塔问题,使我们对栈有更为深入的理解. 1.进制转换 我们先来看看十进制如何转换成二进制, ...

  3. STL源码剖析 — 空间配置器(allocator)

    前言 以STL的实现角度而言,第一个需要介绍的就是空间配置器,因为整个STL的操作对象都存放在容器之中. 你完全可以实现一个直接向硬件存取空间的allocator. 下面介绍的是SGI STL提供的配 ...

  4. glut 深度测试无不起作用问题解决

    OpenGL中使用glEnable(GL_DEPTH_TEST)后深度测试没有起作用,发现深度缓冲没有创建.glut库在兼容模式(GL_COMPATIBILITY_PROFILE)下displaymo ...

  5. C#扩展方法(转)

    扩展方法使您能够向现有类型"添加"方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型." 这是msdn上说的,也就是你可以对String,Int,DataRo ...

  6. No mapping found for HTTP request with URI [/user/login.do] in DispatcherServlet with name 'dispatcher'错误

    1.警告的相关信息 七月 24, 2017 3:53:04 下午 org.springframework.web.servlet.DispatcherServlet noHandlerFound警告: ...

  7. [LeetCode] Coin Change 2 硬币找零之二

    You are given coins of different denominations and a total amount of money. Write a function to comp ...

  8. [LeetCode] Longest Palindromic Subsequence 最长回文子序列

    Given a string s, find the longest palindromic subsequence's length in s. You may assume that the ma ...

  9. vim 批量注释和批量取消注释

    批量注释 按ctrl+v进入可视块模式, 上下移动选中需要注释的行, 按I, 输入注释符号#, 按两下Esc, 保存   批量取消注释 按ctrl+v进入可视块模式, 上下移动选中需要取消注释的行, ...

  10. Redis常用命令--Sets

    Set是不重复且无序的字符串元素的集合. 还可以对set集取交集,并集,差等等. 在Redis中大概有15个操作Set的命令. SADD key member [member ...]:添加一个或者多 ...