1、权限申请
权限包括最基本的读写权限,使用相机的权限,还有有两个系统权限,一个是SD创建和删除文件的权限,另一个是悬浮窗的权限。具体如下:
android6.0以上需要动态申请,部分手机需要在系统设置中手动开启悬浮窗权限。
2、具体实现代码
2.1 创建服务,后台进行录屏操作
package comvoice.example.zhangbin.videorecorddemo;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.MediaRecorder;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.os.Environment;
import android.os.IBinder;
import android.support.annotation.Nullable;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Created by dzjin on 2018/1/9.
*/
public class ScreenRecordService extends Service {
private int resultCode;
private Intent resultData=null;
private MediaProjection mediaProjection=null;
private MediaRecorder mediaRecorder=null;
private VirtualDisplay virtualDisplay=null;
private int mScreenWidth;
private int mScreenHeight;
private int mScreenDensity;
private Context context=null;
@Override
public void onCreate() {
super.onCreate();
}
/**
* Called by the system every time a client explicitly starts the service by calling startService(Intent),
* providing the arguments it supplied and a unique integer token representing the start request.
* Do not call this method directly.
* @param intent
* @param flags
* @param startId
* @return
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
try{
resultCode=intent.getIntExtra("resultCode",-1);
resultData=intent.getParcelableExtra("resultData");
mScreenWidth=intent.getIntExtra("mScreenWidth",0);
mScreenHeight=intent.getIntExtra("mScreenHeight",0);
mScreenDensity=intent.getIntExtra("mScreenDensity",0);
mediaProjection=createMediaProjection();
mediaRecorder=createMediaRecorder();
virtualDisplay=createVirtualDisplay();
mediaRecorder.start();
}catch (Exception e) {
e.printStackTrace();
}
/**
* START_NOT_STICKY:
* Constant to return from onStartCommand(Intent, int, int): if this service's process is
* killed while it is started (after returning from onStartCommand(Intent, int, int)),
* and there are no new start intents to deliver to it, then take the service out of the
* started state and don't recreate until a future explicit call to Context.startService(Intent).
* The service will not receive a onStartCommand(Intent, int, int) call with a null Intent
* because it will not be re-started if there are no pending Intents to deliver.
*/
return Service.START_NOT_STICKY;
}
//createMediaProjection
public MediaProjection createMediaProjection(){
/**
* Use with getSystemService(Class) to retrieve a MediaProjectionManager instance for
* managing media projection sessions.
*/
return ((MediaProjectionManager)getSystemService(Context.MEDIA_PROJECTION_SERVICE))
.getMediaProjection(resultCode,resultData);
/**
* Retrieve the MediaProjection obtained from a succesful screen capture request.
* Will be null if the result from the startActivityForResult() is anything other than RESULT_OK.
*/
}
private MediaRecorder createMediaRecorder(){
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
String filePath=Environment.getExternalStorageDirectory()+"/ScreenVideo/";
if(!new File(filePath).exists()){
new File(filePath).mkdirs();
}
String filePathName= filePath+simpleDateFormat.format(new Date())+".mp4";
//Used to record audio and video. The recording control is based on a simple state machine.
MediaRecorder mediaRecorder=new MediaRecorder();
//Set the video source to be used for recording.
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
//Set the format of the output produced during recording.
//3GPP media file format
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
//Sets the video encoding bit rate for recording.
//param:the video encoding bit rate in bits per second.
mediaRecorder.setVideoEncodingBitRate(5*mScreenWidth*mScreenHeight);
//Sets the video encoder to be used for recording.
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
//Sets the width and height of the video to be captured.
mediaRecorder.setVideoSize(mScreenWidth,mScreenHeight);
//Sets the frame rate of the video to be captured.
mediaRecorder.setVideoFrameRate(60);
try{
//Pass in the file object to be written.
mediaRecorder.setOutputFile(filePathName);
//Prepares the recorder to begin capturing and encoding data.
mediaRecorder.prepare();
}catch (Exception e){
e.printStackTrace();
}
return mediaRecorder;
}
private VirtualDisplay createVirtualDisplay(){
/**
* name String: The name of the virtual display, must be non-empty.This value must never be null.
width int: The width of the virtual display in pixels. Must be greater than 0.
height int: The height of the virtual display in pixels. Must be greater than 0.
dpi int: The density of the virtual display in dpi. Must be greater than 0.
flags int: A combination of virtual display flags. See DisplayManager for the full list of flags.
surface Surface: The surface to which the content of the virtual display should be rendered, or null if there is none initially.
callback VirtualDisplay.Callback: Callback to call when the virtual display's state changes, or null if none.
handler Handler: The Handler on which the callback should be invoked, or null if the callback should be invoked on the calling thread's main Looper.
*/
/**
* DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR
* Virtual display flag: Allows content to be mirrored on private displays when no content is being shown.
*/
return mediaProjection.createVirtualDisplay("mediaProjection",mScreenWidth,mScreenHeight,mScreenDensity,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,mediaRecorder.getSurface(),null,null);
}
@Override
public void onDestroy() {
super.onDestroy();
if(virtualDisplay!=null){
virtualDisplay.release();
virtualDisplay=null;
}
if(mediaRecorder!=null){
mediaRecorder.stop();
mediaRecorder=null;
}
if(mediaProjection!=null){
mediaProjection.stop();
mediaProjection=null;
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
2.2 MainActivity中代码实现
创建悬浮窗
在onDestroy()中移除悬浮窗布局:
windowManager.removeView(floatWindowView);
悬浮窗的布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/bt_play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="录屏"
android:textSize="10dp"
android:background="@drawable/bg_shape"/>
</LinearLayout>
带返回结果的点击事件:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 1000){
if(resultCode == RESULT_OK){
//获得录屏权限,启动Service进行录制
Intent intent=new Intent(MainActivity.this,ScreenRecordService.class);
intent.putExtra("resultCode",resultCode);
intent.putExtra("resultData",data);
intent.putExtra("mScreenWidth",mScreenWidth);
intent.putExtra("mScreenHeight",mScreenHeight);
intent.putExtra("mScreenDensity",mScreenDensity);
startService(intent);
Toast.makeText(this,"录屏开始",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this,"录屏失败",Toast.LENGTH_SHORT).show();
}
}
}
开始录屏:
//start screen record
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void startScreenRecord(){
//Manages the retrieval of certain types of MediaProjection tokens.
MediaProjectionManager mediaProjectionManager=
(MediaProjectionManager)getSystemService(Context.MEDIA_PROJECTION_SERVICE);
//Returns an Intent that must passed to startActivityForResult() in order to start screen capture.
Intent permissionIntent=mediaProjectionManager.createScreenCaptureIntent();
startActivityForResult(permissionIntent,1000);
isRecord=true;
buttonRecord.setText(new String("停止录屏"));
}
停止录屏:
//stop screen record.
private void stopScreenRecord(){
Intent service = new Intent(this, ScreenRecordService.class);
stopService(service);
isRecord=false;
buttonRecord.setText(new String("开始录屏"));
Toast.makeText(this,"录屏成功",Toast.LENGTH_SHORT).show();
}
MainActivity的完整代码:
package comvoice.example.zhangbin.videorecorddemo;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.media.projection.MediaProjectionManager;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.Settings;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast;
import com.tbruyelle.rxpermissions.RxPermissions;
import rx.functions.Action1;
public class MainActivity extends AppCompatActivity {
private LinearLayout linearLayout=null;
private Button buttonRecord=null;
private Button buttonCapture=null;
private boolean isRecord=false;
private int mScreenWidth;
private int mScreenHeight;
private int mScreenDensity;
private WindowManager windowManager;
private View floatWindowView;
private RxPermissions rxPermissions;
private Button bt_play;
private float lastX;
private float lastY;
private float mTouchStartX;
private float mTouchStartY;
/**
* 浮动窗原始位置
*/
private float startPositionX = 0;
private float startPositionY = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rxPermissions=new RxPermissions(this);
getScreenBaseInfo();
initView();
initClick();
}
@Override
protected void onStart() {
super.onStart();
rxPermissions.request(Manifest.permission.CAMERA,Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS,Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.SYSTEM_ALERT_WINDOW)
.subscribe(new Action1<Boolean>() {
@Override
public void call(Boolean aBoolean) {
if(aBoolean){
}
}
});
}
private void initWindow() {
windowManager= (WindowManager) getSystemService(Context.WINDOW_SERVICE);
//设置悬浮窗布局属性
final WindowManager.LayoutParams layoutParams=new WindowManager.LayoutParams();
//设置类型
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
layoutParams.type=WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
}else {
layoutParams.type=WindowManager.LayoutParams.TYPE_PHONE;
}
//设置行为选项
layoutParams.flags=WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
//设置悬浮窗的显示位置
layoutParams.gravity= Gravity.LEFT;
//设置x周的偏移量
layoutParams.x=0;
//设置y轴的偏移量
layoutParams.y=0;
//如果悬浮窗图片为透明图片,需要设置该参数为PixelFormat.RGBA_8888
layoutParams.format= PixelFormat.RGBA_8888;
//设置悬浮窗的宽度
layoutParams.width=WindowManager.LayoutParams.WRAP_CONTENT;
//设置悬浮窗的高度
layoutParams.height=WindowManager.LayoutParams.WRAP_CONTENT;
//设置悬浮窗的布局
floatWindowView= LayoutInflater.from(this).inflate(R.layout.float_window,null);
//加载显示悬浮窗
windowManager.addView(floatWindowView,layoutParams);
bt_play=floatWindowView.findViewById(R.id.bt_play);
bt_play.setOnClickListener(new View.OnClickListener() {
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public void onClick(View view) {
if(isRecord){
bt_play.setText("开始录屏");
stopScreenRecord();
}else{
bt_play.setText("停止录屏");
startScreenRecord();
}
}
});
bt_play.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
windowManager.removeView(floatWindowView);
return false;
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
windowManager.removeView(floatWindowView);
}
private void initClick() {
buttonRecord.setOnClickListener(new View.OnClickListener() {
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public void onClick(View view) {
if(isRecord){
stopScreenRecord();
}else{
startScreenRecord();
}
}
});
buttonCapture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
initWindow();
}
});
}
private void initView() {
linearLayout=(LinearLayout)findViewById(R.id.linearLayout);
buttonRecord=(Button)findViewById(R.id.buttonRecord);
buttonCapture=findViewById(R.id.buttonCapture);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 1000){
if(resultCode == RESULT_OK){
//获得录屏权限,启动Service进行录制
Intent intent=new Intent(MainActivity.this,ScreenRecordService.class);
intent.putExtra("resultCode",resultCode);
intent.putExtra("resultData",data);
intent.putExtra("mScreenWidth",mScreenWidth);
intent.putExtra("mScreenHeight",mScreenHeight);
intent.putExtra("mScreenDensity",mScreenDensity);
startService(intent);
Toast.makeText(this,"录屏开始",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this,"录屏失败",Toast.LENGTH_SHORT).show();
}
}
}
//start screen record
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void startScreenRecord(){
//Manages the retrieval of certain types of MediaProjection tokens.
MediaProjectionManager mediaProjectionManager=
(MediaProjectionManager)getSystemService(Context.MEDIA_PROJECTION_SERVICE);
//Returns an Intent that must passed to startActivityForResult() in order to start screen capture.
Intent permissionIntent=mediaProjectionManager.createScreenCaptureIntent();
startActivityForResult(permissionIntent,1000);
isRecord=true;
buttonRecord.setText(new String("停止录屏"));
}
//stop screen record.
private void stopScreenRecord(){
Intent service = new Intent(this, ScreenRecordService.class);
stopService(service);
isRecord=false;
buttonRecord.setText(new String("开始录屏"));
Toast.makeText(this,"录屏成功",Toast.LENGTH_SHORT).show();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// 在这里将BACK键模拟了HOME键的返回桌面功能(并无必要)
if (keyCode == KeyEvent.KEYCODE_BACK) {
simulateHome();
return true;
}
return super.onKeyDown(keyCode, event);
}
/**
* 获取屏幕基本信息
*/
private void getScreenBaseInfo() {
//A structure describing general information about a display, such as its size, density, and font scaling.
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
mScreenWidth = metrics.widthPixels;
mScreenHeight = metrics.heightPixels;
mScreenDensity = metrics.densityDpi;
}
/**
* 模拟HOME键返回桌面的功能
*/
private void simulateHome() {
//Intent.ACTION_MAIN,Activity Action: Start as a main entry point, does not expect to receive data.
Intent intent = new Intent(Intent.ACTION_MAIN);
//If set, this activity will become the start of a new task on this history stack.
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//This is the home activity, that is the first activity that is displayed when the device boots.
intent.addCategory(Intent.CATEGORY_HOME);
this.startActivity(intent);
}
}
上面实现了简单的录屏功能:
完整代码链接:
https://download.csdn.net/download/u011897782/10677004