一、前言:
gitHub地址:https://gitee.com/luoyanyong/PhotoDemo
1. 在开头,先说一下在imageVIew中如何显示文件中存储的视频的第一帧的图片。很简单,几行代码就搞定。
MediaMetadataRetriever media = new MediaMetadataRetriever();
media.setDataSource(user.getPath());
Bitmap bitmap = media.getFrameAtTime();
2. 下来,开始说拍照和存储视频,先在配置文件中声明一下provider,因为在安卓7.0以上想要存储必须要这个东西,没办法,写吧。
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="zj.it.bhne.gridengineeringsurvey.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
3. meta-data中的file_paths就是自己建的一个xml文件。"."的意思时所有格式。
<?xml version="1.0" encoding="utf-8"?>
<paths >
<external-path name="external_files" path="."/>
<files-path name="my_images" path="images/"/>
<root-path
name="root_path"
path="." />
</paths>
效果图:
二、开始使用:
1. 录屏:
/**
* 启动相机,创建文件,并要求返回uri
*/
private void startVideo() {
Intent intent = new Intent();
//指定动作,启动相机
intent.setAction(MediaStore.ACTION_VIDEO_CAPTURE);
intent.addCategory(Intent.CATEGORY_DEFAULT);
Log.d(TAG, "指定启动相机动作,完成。");
//创建文件
createVideoFile();
Log.d(TAG, "创建视频文件结束。");
//添加权限
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Log.d(TAG, "添加权限。");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//做一些处理
//获取uri
mVideoUri = FileProvider.getUriForFile(this, "zj.it.bhne.gridengineeringsurvey.fileprovider", mVideoFile);
} else {
//在版本低于此的时候,做一些处理
mVideoUri = Uri.fromFile(mVideoFile);
}
Log.d(TAG, "根据视频文件路径获取uri。");
//将uri加入到额外数据
intent.putExtra(MediaStore.EXTRA_OUTPUT, mVideoUri);
Log.d(TAG, "将uri加入启动相机的额外数据。");
Log.d(TAG, "启动相机...");
//启动相机并要求返回结果
startActivityForResult(intent, VIDEO_RESULT_CODE);
Log.d(TAG, "拍摄中...");
}
/**
* 创建视频文件
*/
private void createVideoFile() {
Log.d(TAG, "开始创建图片文件...");
//设置图片文件名(含后缀),以当前时间的毫秒值为名称
mVideoName = Calendar.getInstance().getTimeInMillis() + ".mp4";
Log.d(TAG, "设置图片文件的名称为:"+mVideoName);
//创建图片文件
mVideoFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/bhne/" + getPath() + "/", mVideoName);
//将图片的绝对路径设置给mImagePath,后面会用到
mVideoPath = mVideoFile.getAbsolutePath();
//按设置好的目录层级创建
mVideoFile.getParentFile().mkdirs();
Log.d(TAG, "按设置的目录层级创建图片文件,路径:"+mVideoPath);
//不加这句会报Read-only警告。且无法写入SD
mVideoFile.setWritable(true);
Log.d(TAG, "将图片文件设置可写。");
}
2. 拍照
/**
* 启动相机,创建文件,并要求返回uri
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void startCamera() {
Intent intent = new Intent();
//指定动作,启动相机
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
intent.addCategory(Intent.CATEGORY_DEFAULT);
Log.d(TAG, "指定启动相机动作,完成。");
//创建文件
createImageFile();
Log.d(TAG, "创建图片文件结束。");
//添加权限
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Log.d(TAG, "添加权限。");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//做一些处理
//获取uri
mImageUri = FileProvider.getUriForFile(this, "zj.it.bhne.gridengineeringsurvey.fileprovider", mImageFile);
} else {
//在版本低于此的时候,做一些处理
mImageUri = Uri.fromFile(mImageFile);
}
Log.d(TAG, "根据图片文件路径获取uri。");
//将uri加入到额外数据
intent.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri);
Log.d(TAG, "将uri加入启动相机的额外数据。");
Log.d(TAG, "启动相机...");
//启动相机并要求返回结果
startActivityForResult(intent, PHOTO_RESULT_CODE);
Log.d(TAG, "拍摄中...");
}
/**
* 创建图片文件
*/
private void createImageFile(){
Log.d(TAG, "开始创建图片文件...");
//设置图片文件名(含后缀),以当前时间的毫秒值为名称
mImageName = Calendar.getInstance().getTimeInMillis() + ".jpg";
Log.d(TAG, "设置图片文件的名称为:"+mImageName);
//创建图片文件
mImageFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/bhne/" + getPath() + "/", mImageName);
//将图片的绝对路径设置给mImagePath,后面会用到
mImagePath = mImageFile.getAbsolutePath();
//按设置好的目录层级创建
mImageFile.getParentFile().mkdirs();
Log.d(TAG, "按设置的目录层级创建图片文件,路径:"+mImagePath);
//不加这句会报Read-only警告。且无法写入SD
mImageFile.setWritable(true);
Log.d(TAG, "将图片文件设置可写。");
}
3. 录音:
/**
* 启动录音机,创建文件
*/
private void startRecord() {
Intent intent = new Intent();
intent.setAction(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
createVoiceFile();
Log.d(TAG, "创建录音文件");
//添加权限
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Log.d(TAG, "启动系统录音机,开始录音...");
startActivityForResult(intent, VOICE_RESULT_CODE);
}
/**
* 创建音频目录
*/
private void createVoiceFile() {
mVoiceName = getMyTime() + ".amr";
Log.d(TAG, "录音文件名称:" + mVoiceName);
mVoiceFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/" + SD_APP_DIR_NAME + "/" + VOICE_DIR_NAME + "/", mVoiceName);
mVoicePath = mVoiceFile.getAbsolutePath();
mVoiceFile.getParentFile().mkdirs();
Log.d(TAG, "按设置的目录层级创建音频文件,路径:" + mVoicePath);
mVoiceFile.setWritable(true);
}
/**
* 获取日期并格式化
* 如:2017_10_20 周三 上午 11:20:35
*
* @return 格式化好的日期字符串
*/
private String getMyTime() {
//存储格式化后的时间
String time;
//存储上午下午
String ampTime = "";
//判断上午下午,am上午,值为 0 ; pm下午,值为 1
int apm = Calendar.getInstance().get(Calendar.AM_PM);
if (apm == 0) {
ampTime = "上午";
} else {
ampTime = "下午";
}
//设置格式化格式
SimpleDateFormat format = new SimpleDateFormat("yyyy_MM_dd E " + ampTime + " kk:mm:ss");
time = format.format(new Date());
return time;
}
/**
* 保存音频到SD卡的指定位置
*
* @param path 录音文件的路径
*/
private void saveVoiceToSD(String path) {
//创建输入输出
InputStream isFrom = null;
OutputStream osTo = null;
try {
//设置输入输出流
isFrom = new FileInputStream(path);
osTo = new FileOutputStream(mVoicePath);
byte bt[] = new byte[1024];
int len;
while ((len = isFrom.read(bt)) != -1) {
Log.d(TAG, "len = " + len);
osTo.write(bt, 0, len);
}
Log.d(TAG, "保存录音完成。");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (osTo != null) {
try {
//不管是否出现异常,都要关闭流
osTo.close();
Log.d(TAG, "关闭输出流");
} catch (IOException e) {
e.printStackTrace();
}
}
if (isFrom != null) {
try {
isFrom.close();
Log.d(TAG, "关闭输入流");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 通过Uri,获取录音文件的路径(绝对路径)
*
* @param uri 录音文件的uri
* @return 录音文件的路径(String)
*/
private String getAudioFilePathFromUri(Uri uri) {
Cursor cursor = getContentResolver()
.query(uri, null, null, null, null);
cursor.moveToFirst();
int index = cursor.getColumnIndex(MediaStore.Audio.AudioColumns.DATA);
String temp = cursor.getString(index);
cursor.close();
return temp;
}
4. 返回处理:
/**
* 处理返回结果。
* 1、图片
* 2、音频
* 3、视频
*
* @param requestCode 请求码
* @param resultCode 结果码 成功 -1 失败 0
* @param data 返回的数据
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Log.d(TAG, "拍摄结束。");
Log.d(TAG, "录音结束。");
if (resultCode == Activity.RESULT_OK) {
Log.d(TAG, "返回成功。");
Log.d(TAG, "请求码:" + requestCode + " 结果码:" + resultCode + " data:" + data);
switch (requestCode) {
case PHOTO_RESULT_CODE: {
Bitmap bitmap = null;
try {
//根据uri设置bitmap
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), mImageUri);
Log.d(TAG, "根据uri设置bitmap。");
} catch (IOException e) {
e.printStackTrace();
}
//将图片保存到SD的指定位置
savePhotoToSD(bitmap);
//更新系统图库
updateSystemGallery();
Log.d(TAG, "结束。");
break;
}
case VOICE_RESULT_CODE: {
try {
Uri uri = data.getData();
String filePath = getAudioFilePathFromUri(uri);
Log.d(TAG, "根据uri获取文件路径:" + filePath);
Log.d(TAG, "开始保存录音文件");
saveVoiceToSD(filePath);
} catch (Exception e) {
throw new RuntimeException(e);
}
break;
}
case VIDEO_RESULT_CODE: {
// saveVideoTOSD();
break;
}
}
}
}
三、完整代码:
1. SystemVideoActivity类
package com.sumansoul.photodemo.twoActivity;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import androidx.core.content.FileProvider;
import com.sumansoul.photodemo.CommonUtils;
import com.sumansoul.photodemo.R;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import butterknife.BindView;
import butterknife.ButterKnife;
/**
* 支持拍照,拍视频
*/
public class SystemVideoActivity extends Activity {
@BindView(R.id.btn1)
Button btn1;
@BindView(R.id.btn2)
Button btn2;
@BindView(R.id.btn3)
Button btn3;
@BindView(R.id.btn4)
Button btn4;
private Uri mVideoUri;
private Uri mImageUri;
private String TAG = "LUO";
private File mVideoFile;
private String mVideoPath;
private String mVideoName;
private String mImageName;
private String mImagePath;
private File mImageFile;
/**
* 拍照
*/
private static int PHOTO_RESULT_CODE = 2;
/**
* 录视频
*/
private static int VIDEO_RESULT_CODE = 1;
private String mVoiceName;
private String mVoicePath;
/**
* 录音
*/
private static int VOICE_RESULT_CODE = 3;
/**
* 选择所有文件
*/
private static int ALBUM = 4;
private File mVoiceFile;
/**
* 系统选择的路径
*/
private String selectPath;
/**
* 内容提供者和XML配置一样
*/
String fileProvider = "com.sumansoul.photodemo.fileprovider";
@SuppressLint("WrongViewCast")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_system_video);
ButterKnife.bind(this);
/**
* 拍照
*/
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startCamera();
}
});
/**
* 录像
*/
btn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startVideo();
}
});
/**
* 录音
*/
btn3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startRecord();
}
});
/**
* 从系统相册选择
*/
btn4.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
setLocalPhoto();
}
});
}
/**
* 相册
*/
private void setLocalPhoto() {
Intent albumIntent = new Intent(Intent.ACTION_PICK, null);
// albumIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,"*/*");
// albumIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
albumIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "video/*");
startActivityForResult(albumIntent, ALBUM);
}
/**
* 启动相机,创建文件,并要求返回uri
*/
private void startVideo() {
Intent intent = new Intent();
//指定动作,启动相机
intent.setAction(MediaStore.ACTION_VIDEO_CAPTURE);
intent.addCategory(Intent.CATEGORY_DEFAULT);
Log.d(TAG, "指定启动相机动作,完成。");
//创建文件
createVideoFile();
Log.d(TAG, "创建视频文件结束。");
//添加权限
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Log.d(TAG, "添加权限。");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//做一些处理
//获取uri
mVideoUri = FileProvider.getUriForFile(this, fileProvider, mVideoFile);
} else {
//在版本低于此的时候,做一些处理
mVideoUri = Uri.fromFile(mVideoFile);
}
Log.d(TAG, "根据视频文件路径获取uri。");
//将uri加入到额外数据
intent.putExtra(MediaStore.EXTRA_OUTPUT, mVideoUri);
Log.d(TAG, "将uri加入启动相机的额外数据。");
Log.d(TAG, "启动相机...");
//启动相机并要求返回结果
startActivityForResult(intent, VIDEO_RESULT_CODE);
Log.d(TAG, "拍摄中...");
}
/**
* 创建视频文件
*/
private void createVideoFile() {
Log.d(TAG, "开始创建图片文件...");
//设置图片文件名(含后缀),以当前时间的毫秒值为名称
mVideoName = Calendar.getInstance().getTimeInMillis() + ".mp4";
Log.d(TAG, "设置图片文件的名称为:" + mVideoName);
//创建图片文件
mVideoFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/LUO/VIDEO/", mVideoName);
//将图片的绝对路径设置给mImagePath,后面会用到
mVideoPath = mVideoFile.getAbsolutePath();
//按设置好的目录层级创建
mVideoFile.getParentFile().mkdirs();
Log.d(TAG, "按设置的目录层级创建图片文件,路径:" + mVideoPath);
//不加这句会报Read-only警告。且无法写入SD
mVideoFile.setWritable(true);
Log.d(TAG, "将图片文件设置可写。");
}
/**
* 启动相机,创建文件,并要求返回uri
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void startCamera() {
Intent intent = new Intent();
//指定动作,启动相机
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
intent.addCategory(Intent.CATEGORY_DEFAULT);
Log.d(TAG, "指定启动相机动作,完成。");
//创建文件
createImageFile();
Log.d(TAG, "创建图片文件结束。");
//添加权限
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Log.d(TAG, "添加权限。");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//做一些处理
//获取uri
mImageUri = FileProvider.getUriForFile(this, fileProvider, mImageFile);
} else {
//在版本低于此的时候,做一些处理
mImageUri = Uri.fromFile(mImageFile);
}
Log.d(TAG, "根据图片文件路径获取uri。");
//将uri加入到额外数据
intent.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri);
Log.d(TAG, "将uri加入启动相机的额外数据。");
Log.d(TAG, "启动相机...");
//启动相机并要求返回结果
startActivityForResult(intent, PHOTO_RESULT_CODE);
Log.d(TAG, "拍摄中...");
}
/**
* 创建图片文件
*/
private void createImageFile() {
Log.d(TAG, "开始创建图片文件...");
//设置图片文件名(含后缀),以当前时间的毫秒值为名称
mImageName = Calendar.getInstance().getTimeInMillis() + ".jpg";
Log.d(TAG, "设置图片文件的名称为:" + mImageName);
//创建图片文件
mImageFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/LUO/IMAGE/", mImageName);
//将图片的绝对路径设置给mImagePath,后面会用到
mImagePath = mImageFile.getAbsolutePath();
//按设置好的目录层级创建
mImageFile.getParentFile().mkdirs();
Log.d(TAG, "按设置的目录层级创建图片文件,路径:" + mImagePath);
//不加这句会报Read-only警告。且无法写入SD
mImageFile.setWritable(true);
Log.d(TAG, "将图片文件设置可写。");
}
/**
* 启动录音机,创建文件
*/
private void startRecord() {
Intent intent = new Intent();
intent.setAction(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
createVoiceFile();
Log.d(TAG, "创建录音文件");
//添加权限
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Log.d(TAG, "启动系统录音机,开始录音...");
startActivityForResult(intent, VOICE_RESULT_CODE);
}
/**
* 创建音频目录
*/
private void createVoiceFile() {
mVoiceName = getMyTime() + ".amr";
Log.d(TAG, "录音文件名称:" + mVoiceName);
mVoiceFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/LUO/VOICE/", mVoiceName);
mVoicePath = mVoiceFile.getAbsolutePath();
mVoiceFile.getParentFile().mkdirs();
Log.d(TAG, "按设置的目录层级创建音频文件,路径:" + mVoicePath);
mVoiceFile.setWritable(true);
}
/**
* 获取日期并格式化
* 如:2017_10_20 周三 上午 11:20:35
*
* @return 格式化好的日期字符串
*/
private String getMyTime() {
//存储格式化后的时间
String time;
//存储上午下午
String ampTime = "";
//判断上午下午,am上午,值为 0 ; pm下午,值为 1
int apm = Calendar.getInstance().get(Calendar.AM_PM);
if (apm == 0) {
ampTime = "上午";
} else {
ampTime = "下午";
}
//设置格式化格式
SimpleDateFormat format = new SimpleDateFormat("yyyy_MM_dd E " + ampTime + " kk:mm:ss");
time = format.format(new Date());
return time;
}
/**
* 保存音频到SD卡的指定位置
*
* @param path 录音文件的路径
*/
private void saveVoiceToSD(String path) {
//创建输入输出
InputStream isFrom = null;
OutputStream osTo = null;
try {
//设置输入输出流
isFrom = new FileInputStream(path);
osTo = new FileOutputStream(mVoicePath);
byte bt[] = new byte[1024];
int len;
while ((len = isFrom.read(bt)) != -1) {
Log.d(TAG, "len = " + len);
osTo.write(bt, 0, len);
}
Log.d(TAG, "保存录音完成。");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (osTo != null) {
try {
//不管是否出现异常,都要关闭流
osTo.close();
Log.d(TAG, "关闭输出流");
} catch (IOException e) {
e.printStackTrace();
}
}
if (isFrom != null) {
try {
isFrom.close();
Log.d(TAG, "关闭输入流");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 通过Uri,获取录音文件的路径(绝对路径)
*
* @param uri 录音文件的uri
* @return 录音文件的路径(String)
*/
private String getAudioFilePathFromUri(Uri uri) {
Cursor cursor = getContentResolver()
.query(uri, null, null, null, null);
cursor.moveToFirst();
int index = cursor.getColumnIndex(MediaStore.Audio.AudioColumns.DATA);
String temp = cursor.getString(index);
cursor.close();
return temp;
}
/**
* 处理返回结果。
* 1、图片
* 2、音频
* 3、视频
*
* @param requestCode 请求码
* @param resultCode 结果码 成功 -1 失败 0
* @param data 返回的数据
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
Log.d(TAG, "返回成功。");
Log.d(TAG, "请求码:" + requestCode + " 结果码:" + resultCode + " data:" + data);
if (requestCode == PHOTO_RESULT_CODE) {
Bitmap bitmap = null;
try {
//根据uri设置bitmap
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), mImageUri);
Log.d(TAG, "根据uri设置bitmap。");
} catch (IOException e) {
e.printStackTrace();
}
Log.d(TAG, "结束。");
} else if (requestCode == VOICE_RESULT_CODE) {
try {
Uri uri = data.getData();
String filePath = getAudioFilePathFromUri(uri);
Log.d(TAG, "根据uri获取文件路径:" + filePath);
Log.d(TAG, "开始保存录音文件");
saveVoiceToSD(filePath);
} catch (Exception e) {
throw new RuntimeException(e);
}
} else if (requestCode == VIDEO_RESULT_CODE) {
Log.d(TAG, "拍摄结束。");
} else if (requestCode == ALBUM) {
//裁剪本地相册
if (data != null && data.getData() != null) {
Uri data1 = data.getData();
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
selectPath = data1.toString();
} else {
selectPath = data1.getPath();
}
// Uri --> Path
if (selectPath.contains("content://")) {
selectPath = CommonUtils.getFilePathFromContentUri(data1, this.getContentResolver());
}
Log.d(TAG, "相册返回=====" + selectPath);
}
}
}
}
}
2. activity_system_video.XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/btn1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginTop="10dp"
android:layout_marginRight="30dp"
android:text="拍照" />
<Button
android:id="@+id/btn2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginTop="10dp"
android:layout_marginRight="30dp"
android:text="录像" />
<Button
android:id="@+id/btn3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginTop="10dp"
android:layout_marginRight="30dp"
android:text="录音" />
<Button
android:id="@+id/btn4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginTop="10dp"
android:layout_marginRight="30dp"
android:text="选择系统相册" />
</LinearLayout>
3. manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.sumansoul.photodemo">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!--录音权限-->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<application
android:name=".BaseApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--拍照使用 -->
<provider
android:name=".provider.CustfileProvider"
android:authorities="com.sumansoul.photodemo.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<activity android:name=".twoActivity.VideoActivity" />
<activity android:name=".twoActivity.SystemVideoActivity" />
</application>
</manifest>
参考链接:https://blog.csdn.net/haojiagou/article/details/81235574