摄像头拍照
文章目录
- 摄像头拍照
- 1、Camera1使用
- 2、 Camera2拍照流程图:
- 2.1 CameraManager
- 2.2 CameraCharacteristics
- 2.3 CameraDevice
- 2.4 CameraDevice.StateCallback
- 2.5 CameraRequest和CameraRequest.Builder
- 2.6 CaptureRequest.Builder(内部类)
- 2.7 CaptureRequest.Key(内部类)
- 2.8 CameraCaptureSession
- 2.9 CameraCaptureSession.CaptureCallback
- 2.10 CameraCaptureSession.StateCallback
- 2.11 CaptureResult
- 2.12 ImageReader
- 2.13 TextureView 和SurfaceView
- 3 、Camera框架实现录像
- 4 、屏幕捕捉
从 Android 5.0 开始,Google 引入了一套全新的相机框架 Camera2(android.hardware.camera2)并且废弃了旧的相机框架 Camera1(android.hardware.Camera)
1、Camera1使用
1.1 使用步骤:
- 调用Camera.open(),打开相机,默认为后置,可以根据摄像头ID来指定打开前置还是后置
- 调用Camera.getParameters ()得到一个Camera.Parameters对象
- 使用步骤2得到的Camera.Parameters对象,对拍照参数进行设置
- 调用Camera.setPreviewDispaly(SurfaceHolder holder),指定使用哪个SurfaceView来显示预览图片
- 调用Camera.startPreview()方法开始预览取景
- 调用Camera.takePicture()方法进行拍照
- 拍照结束后,调用Camera.stopPreview()结束取景预览,之后再replease()方法释放资
1.2 为什么要使用Camera2
通过 Camera2 提供的高级特性可以构建出更加高质量的相机应用程序。
1.在开启相机之前检查相机信息
2.在不开启预览的情况下拍照
3.一次拍摄多张不同格式和尺寸的图片
4.控制曝光时间
5.连拍
1.3 Camera2的 5点新特性:
(1)支持30帧的高清连拍功能。
(2)支持每帧之间的手动设置。
(3)支持RAW原始图像的拍摄。
(4)支持快门零延迟以及电影速拍。
(5)支持相机其它方面的手动控制,包括噪音消除。
1.4 Camera2架构概述
Camera2引用了管道的概念,将Camera Device相机设备和Android Device安卓设备连接起来,android Device通过管道发送CaputerRequest拍照请求给Camera Device,Camera Device通过管道返回CameraMetaData数据给Android Device,这一切建立在一个叫做CameraCaptureSession。
1.5 Camera2中比较重要的类及方法
其中CameraManager是所有相机设备(CameraDevice)的管理者,而每个CameraDevice自己会负责建立CameraCaptureSession以及建立CaptureRequest。
CameraCharacteristics是CameraDevice的属性描述类,在CameraCharacteristics中可以进行相机设备功能的详细设定(当然了,首先你得确定你的相机设备支持这些功能才行)。
类图中有着三个重要的callback,其中CameraCaptureSession.CaptureCallback将处理预览和拍照图片的工作,需要重点对待
2、 Camera2拍照流程图:
-
调用 CameraManager的openCamera(String cameraId, CameraDevice.StateCallback callback, Handler handler) 方法打开指定摄像头。该方法的第一个参数cameraId代表要打开的摄像头ID(摄像头ID(通常0代表后置摄像头,1代表前置摄像头);第二个参数用于监听摄像头的状态;第三个参数代表执行callback的Handler,如果程序希望直接在当前线程中执行callback,则可将handler参数设为null。
-
获取CameraDevice对象
当摄像头被打开之后,程序即可获取CameraDevice—即根据摄像头ID获取了指定摄像头设备,然后调用CameraDevice的createCaptureSession(List outputs, CameraCaptureSession. StateCallback callback,Handler handler)方法来创建CameraCaptureSession。该方法的第一个参数是一个List集合,封装了所有需要从该摄像头获取图片的Surface,第二个参数用于监听CameraCaptureSession的创建过程;第三个参数代表执行callback的Handler,如果程序希望直接在当前线程中执行callback,则可将handler参数设为null。 -
设置设置摄像头模式
不管预览还是拍照,程序都调用CameraDevice的createCaptureRequest(int templateType)
方法创建CaptureRequest.Builder
,该方法支持TEMPLATE_PREVIEW(预览)、TEMPLATE_RECORD(拍摄视频)、TEMPLATE_STILL_CAPTURE(拍照)等参数。
通过第3步所调用方法返回的CaptureRequest.Builder设置拍照的各种参数,比如对焦模式、曝光模式等。
调用CaptureRequest.Builder的build()方法即可得到CaptureRequest对象,接下来程序可通过CameraCaptureSession的setRepeatingRequest()方法开始预览,或调用capture()方法拍照。
2.1 CameraManager
管理所有的摄像头(CameraDevice)设备的管理者,用于打开和关闭系统摄像头。
获取该实例的方法:
CameraManager manager =(CameraManager)Context.getSystemService(Context.CAMERA_SERVICE);
或者
CameraManager manager =(CameraManager)Context.getSystemService(CameraManager.class);
-
getCameraIdList() :返回当前设备中可用的相机列表, 这个 id 通常都是从 0 开始并依次递增的
-
public CameraCharacteristics getCameraCharacteristics (String cameraId) :根据摄像头id返回该摄像头的相关信息;cameraId,0为后置摄像头、1为前置摄像头
-
public void openCamera(String cameraId,final CameraDevice.StateCallback callback, Handler handler)
-
public void openCamera(String cameraId,Executor executor,final CameraDevice.StateCallback callback)都是打开指定cameraId的相机,只是一个传入Handler,一个传入Executor,是想用线程池来执行Camera中耗时操作
😄 cameraId 是一个标识,标识当前要打开的camera
😆 callback 是一个状态回调,当前camera被打开的时候,这个状态回调会被触发的。
😃 handler 指定回调执行的线程。传 null 时默认使用当前线程的 Looper,我们通常创建一个后台线程来处理。
😚 executor操作线程池
2.2 CameraCharacteristics
描述摄像头的各种特性,其中的属性都是固定的,类似于Camera1中的CamerInfo。通过CameraManager的getCameraCharacteristics(String cameraId)
方法来获取
包含一个CameraCharacteristics.Key<T>
的内部类,用做相机特性的字段查询使用。常搭配 CameraCharacteristics.get(CameraCharacteristics.Key<T> key)
方法使用。
get(Key<T> key)
:通过制定的key获取相应的相机参数。
常用的key值有:
😉 CameraCharacteristics.LENS_FACING :获取摄像头方向。前置摄像头(LENS_FACING_FRONT)或 后置摄像头(LENS_FACING_BACK)
😃 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL:获取当前设备支持的相机特性
😃 CameraCharacteristics.SENSOR_ORIENTATION:获取摄像头方向
😃 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP:获取StreamConfigurationMap,它是管理摄像头支持的所有输出格式和尺寸
😃 CameraCharacteristics.FLASH_INFO_AVAILABLE:是否支持闪光灯
😃 CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT:同时检测到人脸的数量
😃 CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES:相机支持的人脸检测模式
2.3 CameraDevice
CameraDevice 代表当前连接的相机设备,可以把它看作为相机设备在 java 代码中的表现,它的职责有以下四个:
-
根据指定的参数创建 CameraCaptureSession。
-
根据指定的模板创建 CaptureRequest。
-
关闭相机设备。
-
监听相机设备的状态,例如断开连接、开启成功和开启失败等。
熟悉 Camera1 的人可能会说 CameraDevice 就是 Camera1 的 Camera 类,实则不是,Camera 类几乎负责了所有相机的操作,而 CameraDevice 的功能则十分的单一,就是只负责建立相机连接的事务,而更加细化的相机操作则交给了稍后会介绍的CameraCaptureSession。
创建方法:通过 CameraManager 的 openCamera() 方法打开相机,在 CameraDevice.StateCallback 的 onOpened(CameraDevice camera) 方法中可获得 CameraDevice 的实例。
createCaptureRequest(int templateType)
:创建一个新的拍照请求。参数templateType代表了请求类型,请求类型一共分为六种,分别为:
😁 TEMPLATE_PREVIEW : 创建预览的请求,相机会优先保证高帧率而不是高画质
😁 TEMPLATE_STILL_CAPTURE: 创建一个拍照请求。相机会优先保证高画质而不是高帧率
😁 TEMPLATE_RECORD : 创建一个录像请求。相机会使用标准帧率,并设置录像级别的画质
😁 TEMPLATE_VIDEO_SNAPSHOT : 创建一个录像时拍照的请求。相机会尽可能的保证照片质量的同时不破坏正在录制的视频质量; 高于 LEGACY
😁 TEMPLATE_ZERO_SHUTTER_LAG : 创建一个适用于零快门延迟的请求。在不影响预览帧率的情况下最大化图像质量
😁 TEMPLATE_MANUAL : 创建一个基本捕获请求,这种请求中所有的自动控制都是禁用的(自动曝光,自动白平衡、自动焦点)
硬件支持等级
在 Camera2 中,相机设备支持的硬件等级有LEGACY < LIMITED < FULL < LEVEL_3
-
LEVEL_LEGACY: 向后兼容模式, 如果是此等级, 基本没有额外功能
-
LEVEL_LIMITED: 有最基本的功能, 还支持一些额外的高级功能, 这些高级功能是LEVEL_FULL的子集
-
LEVEL_FULL: 支持对每一帧数据进行控制,还支持高速率的图片拍摄
-
LEVEL_3: 支持YUV后处理和Raw格式图片拍摄, 还支持额外的输出流配置
-
LEVEL_EXTERNAL: API28中加入的, 应该是外接的摄像头, 功能和LIMITED类似
createCaptureSession(List<Surface>outputs,CameraCaptureSession.StateCallback callback,Handler handler)
:创建CaptureSession会话,一个 CameraDevice 一次只能开启一个 CameraCaptureSession,绝大部分的相机操作都是通过向 CameraCaptureSession 提交一个 Capture 请求实现的,例如拍照、连拍、设置闪光灯模式、触摸对焦、显示预览画面等等。第一个参数 outputs 是一个 List 数组,相机会把捕捉到的图片数据传递给该参数中的 Surface 。第二个参数 StateCallback 是创建会话的状态回调。第三个参数描述了 StateCallback 被调用时所在的线程
2.4 CameraDevice.StateCallback
CameraDevice的内部类StateCallback,一个回调对象,用于接收关于相机的更新状态。这些状态更新包括关于设备完成启动的通知(允许CameraDevice的createCaptureSession(List, CameraCaptureSession.StateCallback, Handler)被调用),关于设备断开或闭包,以及意外的设备错误。关于特定的CaptureRequests进程事件是由 CameraCaptureSession.CaptureCallback 提供的
回调方法:
回调方法 | 解释 |
---|---|
onClosed(CameraDevice camera) | 当一个相机设备CameraDevice的close()方法时,这个方法就被调用 |
onDisconnected(CameraDevice camera) | 当相机设备不再可用时,这个方法就被调用 |
onError(CameraDevice camera, int error) | 当相机设备遇到严重错误时,这种方法就被调用了,错误见上表的常量 |
onOpened(CameraDevice camera) | 当相机完成打开操作后,这个方法就被调用 |
onError 回调方法中相应的错误码
常量 | 解释 |
---|---|
ERROR_CAMERA_DEVICE | 由CameraDevice.StateCallback的onError(CameraDevice, int)报告的错误代码,表明相机设备遇到了一个致命错误 |
ERROR_CAMERA_DISABLED | 由CameraDevice.StateCallback的onError(CameraDevice, int)报告的错误代码,这表明由于设备的政策,相机设备无法打开。 |
ERROR_CAMERA_IN_USE | 由onError(CameraDevice, int)报告的错误代码,表明摄像机设备已经在使用中了 |
ERROR_CAMERA_SERVICE | 由onError(CameraDevice, int)报告的错误代码,表明摄像机服务遇到了一个致命错误。 |
ERROR_MAX_CAMERAS_IN_USE | 由onError(CameraDevice, int)报告的错误代码,表明相机设备无法打开,因为有太多其他的开放相机设备。 |
2.5 CameraRequest和CameraRequest.Builder
当程序调用setRepeatingRequest()方法进行预览时,或调用capture()方法进行拍照时,都需要传入CameraRequest参数。CameraRequest代表了一次捕获请求,用于描述捕获图片的各种参数设置,比如对焦模式、曝光模式……总之,程序需要对照片所做的各种控制,都通过CameraRequest参数进行设置
使用CaptureRequest.Builder实例创建CaptureRequests对象,通过调用CameraDevice的createCaptureRequest(int templateType) 获取CaptureRequest.Builder对象。
2.6 CaptureRequest.Builder(内部类)
典型的建造者模式,是 CaptureRequest 的构建者。
addTarget(Surface outputTarget):
给此次请求添加一个Surface对象作为图像的输出目标,CameraDevice返回的数据送到这个target surface中。target surface可以是Surface View,Surface Texture,将返回的数据传递到预览界面中;还可以是MediaRecorder或mageReader,将返回的数据传给这两个类,进行进一步处理,形成视频文件或者图片。
2.7 CaptureRequest.Key(内部类)
用作 CaptureRequest.Builder 的属性字段设置和查询使用
set(Key key, T value):设置指定的参数值。
// 自动对焦
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
// 闪光灯
captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH)
// 根据摄像头方向对保存的照片进行旋转,使其为"自然方向"
captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, mCameraSensorOrientation)
// 人脸检测模式
captureRequestBuilder.set(CaptureRequest.STATISTICS_FACE_DETECT_MODE, CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_
SIMPLE)
2.8 CameraCaptureSession
当需要拍照、预览等功能时,需要先创建该类的实例,然后通过该实例里的方法进行控制(例如:拍照 capture())
setRepeatingRequest(CaptureRequest request,CaptureCallback listener, Handler handler):
根据传入的 CaptureRequest 对象开始一个无限循环的捕捉图像的请求, 一般用于捕获画面输出至预览界面或者录制视频。第二个参数 listener 为捕捉图像的回调,在回调中可以拿到捕捉到的图像信息,通常作为请求的进度监听器
capture( CaptureRequest request,CaptureCallback listener, Handler handler):
捕获一次,一般用于拍照;第二个参数为拍照的结果回调
Capture()比setRepeatingRequest ()优先级高,当在setRepeatingRequest 时进行Capture,会先处理Capture,然后继续setRepeatingRequest 。(PS:可以根据平时使用相机时,首先我们看到的预览界面是setRepeatingRequest 显示出来的,当点击拍照时执行Capture,然后又出现预览界面继续实行setRepeatingRequest )。
2.9 CameraCaptureSession.CaptureCallback
CameraCaptureSession的内部类CaptureCallback,一个回调对象,用于跟踪向相机提交CaptureRequest对象的进程。
这个回调是在一个请求触发一个捕获开始时调用的,当捕获完成时调用。可以使用这个类来跟踪各进度。如果出现错误捕获图像则会触发错误方法,而不是完成方法。
重写的七个方法:
方法 | 解释 |
---|---|
onCaptureBufferLost(CameraCaptureSession session, CaptureRequest request, Surface target, long frameNumber) | 如果捕获的单个缓冲区不能发送到它的目标表面,就会调用该方法。 |
onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) | 当一个图像捕捉已经完全完成并且所有的结果元数据都可用时,这个方法就会被调用。 |
onCaptureFailed(CameraCaptureSession session, CaptureRequest request, CaptureFailure failure) | 当相机不能向 CaptureResult 对象提供请求,就会调用 |
onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, CaptureResult partialResult) | 当图像捕捉取得部分进展时,就会调用该方法;有些(但不是全部)从图像捕获中得到的结果是可用的。 |
onCaptureSequenceAborted(CameraCaptureSession session, int sequenceId) | 这个方法独立于CaptureCallback中的其他方法,当捕获序列在任何CaptureResult或capture失败之前通过这个侦听器返回时。 |
onCaptureSequenceCompleted(CameraCaptureSession session, int sequenceId, long frameNumber) | 这个方法独立于CaptureCallback中的其他方法,当捕获序列完成后,通过这个侦听器返回所有的CaptureResult或capture失败。 |
onCaptureStarted(CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber) | 当摄像机设备开始捕捉请求的输出图像,在图像曝光开始时,或者当摄像机设备开始处理一个重新处理请求的输入图像时,这个方法就被调用了。 |
2.10 CameraCaptureSession.StateCallback
CameraCaptureSession的内部类StateCallback,一个回调对象,用于接收关于相机捕捉会话状态的更新。 其中只有 onConfigured 和 onConfigureFailed 两个方法是抽象的(必须重写),其余均有空实现。
重写的七个方法:
方法 | 解释 |
---|---|
onActive(CameraCaptureSession session) | 当会话开始主动处理捕获请求时,将调用此方法。 |
onCaptureQueueEmpty(CameraCaptureSession session) | 当摄像机设备的输入捕捉队列变为空时,该方法将被调用,并准备接受下一个请求。 |
onClosed(CameraCaptureSession session) | 会话关闭触发 |
onConfigureFailed(CameraCaptureSession session) | 如果会话不能按照请求配置,则调用此方法。 |
onConfigured(CameraCaptureSession session) | 当摄像机设备完成配置时,这个方法就会被调用,会话可以开始处理捕获请求。 |
onReady(CameraCaptureSession session) | 每当会话不再需要处理请求时,就会调用此方法。 |
onSurfacePrepared(CameraCaptureSession session, Surface surface) | 当输出表的缓冲区预分配完成时,就会调用 |
2.11 CaptureResult
-
描述拍照完成后的结果(从图像传感器捕获单个图像的结果子集),包含捕获硬件的配置(传感器sensor,、透镜 lens、闪光灯flash),处理管道pipeline,控制算法和输出缓冲区。处理完 CaptureRequest之后,CaptureResults由CameraDevice类产生
-
CaptureResult的所有字段和CaptureRequest相同
-
CaptureResult 对象也是不可变的。常使用的子类是 TotalCaptureResult。
-
在CameraCaptureSession.CaptureCallback 类的回调方法 onCaptureProgressed() 和 onCaptureCompleted() 中都可以拿到 CaptureResult 的对象。
2.12 ImageReader
得到一个ImageReader对象的方法为newInstance(int width, int height, int format, int maxImages)。前两个参数是保存图片的宽高,第三个参数为保存图片的格式,也就是reader生产的Image的格式,必须是ImageFormat或PixelFormat中的常量,并不是所有的formats都会被支持,第四个参数代表用户可以同时访问到的最大图片数量
image的data被存储在Image类里面,新的images通过ImageReader的surface发送给ImageReader,类似一个队列,需要通过acquireLatestImage()或者acquireNextImage()方法取出Image。
2.13 TextureView 和SurfaceView
SurfaceView 在自己独立的线程中绘制,不会影响到主线程,内部使用双缓冲机制,画面更流畅。相比于 TextureView,它内存占用低,绘制更及时,耗时也更低,但不支持动画和截图。
由于 SurfaceView 是拥有一个独立的 Surface,不在 View hierachy 体系中,因此不支持动画和截图,而 TextureView 则没有该限制。TextureView 是 Android 4.0 之后引入的,它将内容流直接投影到 View 中,数据流可以来自 App 进程或远端进程。缺点是必须在硬件加速的窗口中使用,且内存和耗电比 SurfaceView 更高,绘制也可能存在 1~3 帧的延迟。
使用TextureView的步骤:
(1)MainActvity要实现TextureView.SurfaceTextureListener接口
(2)创建TextureView,并将MainActvity设置为SurfaceTextureListener,供系统回调MainActvity实现的onSurfaceTextureXXX接口方法
(3)在onSurfaceTextureAvailable回调中拿到SurfaceTexture,并把它设置给camera,作为承载、预览数据流的载体
(4)在onSurfaceTextureDestroyed中关闭预览,释放camera资源,返回true
3 、Camera框架实现录像
-
预览是将数据展示在SurfaceView或者TextureView上,mMediaRecorder.getSurface();
-
按照MediaRecorder的相关步骤进行设置
4 、屏幕捕捉
在Android5.0之后开放了新的接口android.media.projection,使用该接口,第三方应用程序无需获取系统root权限也可以直接进行屏幕截图操作了。
由于使用了媒体的映射技术手段,故截取的屏幕并不是真正的设备屏幕,而是截取的通过映射出来的“虚拟屏幕”。
MediaProjection是一个准许APP拥有截取屏幕或者是记录系统音频的能力,可以用来捕捉屏幕,具体来说可以截取当前屏幕和录制屏幕视频。MediaProjection由MediaProjectionManager来管理和获取。
4.1 MediaProjectionManager
- MediaProjectionManager 是一个系统级的服务,可以通过 getSystemService 来获取实例
Context.getSystemService(Class)方法,参数用MediaProjectionManager.class
Context.getSystemService(String)方法,参数用Context.MEDIA_PROJECTION_SERVICE
例如:
MediaProjectionManager mMediaProjectionManager =
(MediaProjectionManager)getSystemService(Context.MEDIA_PROJECTION_SERVICE);
公有方法
-
Intent createScreenCaptureIntent()
创建了一个隐式的intent,用来调用系统的录屏程序。通过startActivityForResult来传递这个intent,这个Activity会提示用户是否允许捕捉屏幕。所以可以通过onActivityResult来获取用户操作结果,通过getMediaProjection来取出intent中的数据
-
MediaProjection getMediaProjection (int resultCode, Intent resultData)
成功获得用户允许后获取MediaProjection对象。如果授权失败,则得到空对象。
4.2 MediaProjection
通过createScreenCaptureIntent()捕获屏幕会话。
VirtualDisplay类代表一个虚拟显示器,需要调用DisplayManager 类的 createVirtualDisplay()方法,将虚拟显示器的内容渲染在一个Surface控件上,当进程终止时虚拟显示器会被自动的释放,并且所有的Window都会被强制移除。当不再使用他时,你应该调用release() 方法来释放资源。
公有方法:
- VirtualDisplay createVirtualDisplay (String name, int width, int height, int dpi, int flags, Surface surface, VirtualDisplay.Callback callback, Handler handler)
创建一个VirtualDisplay用来捕获屏幕内容。
name: VirtualDisplay的名字,永不为空
width: 宽度,单位为像素,必须大于0
height: 高度,单位为像素,必须大于0
dpi: 像素密度,单位为dp,必须大于0
flags:int DisplayManager定义的flag组合,虚拟显示标志,取值是:
💗 VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR允许在没有显示内容的情况下在虚显上显示内容
💗 VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY只显示本镜像的内容
💗 VIRTUAL_DISPLAY_FLAG_PRESENTATION
💗 VIRTUAL_DISPLAY_FLAG_PUBLIC
💗 VIRTUAL_DISPLAY_FLAG_SECURE
surface:Surface virtual display
的内容应该被渲染的surface,没有的话为空
⭐️ 显示使用SurfaceView组件
⭐️ 截屏使用ImageReader类,这个类的getSurface()方法获取到surface直接传入MediaProjection.createVirtualDisplay()方法中,此时就可以执行截取。通过ImageReader.acquireLatestImage()方法即可获取当前屏幕的Image,经过简单处理之后即可保存为Bitmap。
⭐️ 录屏需要用到MediaCodec,这个类将原始的屏幕数据编码,在通过MediaMuxer封装成MP4格式保存。MediaCodec.createInputSurface()获取一个surface对象传入MediaProjection.createVirtualDisplay()即可获取屏幕原始多媒体数据,之后读取MediaCodec编码输出数据经过MediaMuxer封装处理MP4即可播放,实现录屏。
callback:VirtualDisplay.Callback virtual display
状态变化的回调
handler:Handler callback
调用的Handler。如果回调在calling thread的主looper被调用,则为空
void registerCallback (MediaProjection.Callback callback, Handler handler)
注册一个listener接收MediaProjection变化状态的通知。
-
void stop ()停止projection
-
void unregisterCallback (MediaProjection.Callback callback) 取消注册MediaProjection的listener
4.3 步骤如下:
1、获取MediaProjectionManager
该对象是一个系统服务,可通getSystemService(Context.MEDIA_PROJECTION_SERVICE)获取
2、通过MediaProjectionManager.createScreenCaptureIntent()获取Intent
弹出dialog询问用户是否授权应用捕捉屏幕,同时覆写onActivityResult()获取授权结果。
3、通过startActivityForResult传入Intent, 如果授权成功,在onActivityResult中通过MediaProjectionManager.getMediaProjection(resultCode,data)获取MediaProjection
4、创建ImageReader,构建VirtualDisplay
5、最后就是通过ImageReader截图,就可以从ImageReader里获得Image对象。
6、将Image对象转换成bitmap
MediaProjection漏洞
Android MediaProjection服务被滥用,攻击者可以录音、获取屏幕内容。影响Android5.0之后8.0以前的所有版本,google回应已在8.0版本对漏洞进行了修复。
漏洞描述
Google在Android 5.0中引入了MediaProjection 服务, MediaProjection服务可以让应用开发者获取屏幕内容和记录系统音频。在Android 5.0之前,应用开发者需要应用在 root权限下运行或者用设备的release key对应用进行签名,只有这样才可以使用系统保护的权限来获取屏幕内容。而且,使用 MediaProjection服务时,不需要在 AndroidManifest.xml中声明请求的权限。
安卓应用开发者抵御此类攻击的方式是通过应用的WindowManager开启FLAG_SECURE布局参数。这可以确保应用窗口的内容是安全的,可以防止被截屏或通过其他不安全的方式查看。 FLAG_SECURE参数的设置如下:
public class ApplicationActivity extends AppCompatActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(LayoutParams.FLAG_SECURE,LayoutParams.FLAG_SECURE);
}
}