背景:
由于有些手机(如小米、魅族、华为)添加了权限管理,所以项目中需要在正式录音/录像之前,检查是否有权限。
测试中发现,
判断是否有录音权限的代码:
PackageManager pm = activity.getPackageManager();
String permission_name = "android.permission.RECORD_AUDIO";
boolean permission = (PackageManager.PERMISSION_GRANTED == pm.checkPermission(permission_name, activity.getPackageName()));
if(!permission){
quitWithFailure(IDY_ERROR.AA_PERMISSION_DENIED);
return;
}
但是测试下来,发现上述手机对于权限的判断,并不能返回正确的值。
第一次安装的时候,可以正确判断,但是允许之后,再改成拒绝,那么这个判断就不准了。 一直是返回的true。这样一来,依然不能保证正确录音。
想来想去,最终决定使用一个笨方法,即正式录音之前,先开始一个测试录音,录个几秒钟,然后每隔2s钟检查一次,录音文件是否存在,且大小是否增大,检查3次之后,符合正常情况的,则认为录音功能正常。否则,提示用户检查权限。
//2015-4-13 增加检查录音权限
private void checkMediaPermission(final int answer_type){
//如果不需要录音,不需要检查。 如果需要录音,则检查。
final RecordModel recordModel = FlysurveyApplication.recordDao.getRecordModel(project_id);
if (recordModel != null && !recordModel.getAudio_type().equals("")) {// 需要录音
//如果已经检查通过了,则不需要再检查
if (sp.getBooleanValue(project_id, false)) {
MyLog.getInstance().writeMessage(TAG, "答题前检查权限:已经检查通过,直接通过");
Intent intent = new Intent(ProjectActivity.this, AnswerPageActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable("projectmodel", projectModel);
intent.putExtras(bundle);
intent.putExtra("uuid", "");
intent.putExtra("answer_type", answer_type);
startActivity(intent);
return;
}
PackageManager pm = getPackageManager();
String permission_name = "android.permission.RECORD_AUDIO";
boolean permission = (PackageManager.PERMISSION_GRANTED == pm.checkPermission(permission_name, getPackageName()));
if(!permission){
//检查不通过,提示检查权限
MyLog.getInstance().writeMessage(TAG, "答题前检查权限:没有权限");
Toast.makeText(getApplication(), R.string.answer_failed_need_audio_permission, Toast.LENGTH_LONG).show();
return;
}
progressDialog = ProgressDialog.show(context, "", "正在检测答卷环境,请稍后。。。");
Thread testRecordThread = new Thread(new Runnable() {
@Override
public void run() {
//1.开启一个录音
final AudioRecorderUtil audioRecorder = new AudioRecorderUtil(recordModel,
projectModel.getProject_identifier(), project_id);
final File tmp_file = audioRecorder.testRecord();
//2.每隔2s钟检查一次,判断文件是否存在,若存在,则判断文件大小是否变化
if (tmp_file != null) {
final Timer timer = new Timer();
timer.schedule(new TimerTask() {
private boolean pass_test = false; //检查结果 true通过,false未通过
private long last_length = 0; //上一次的文件大小
private int check_count = 0; //检查次数
@Override
public void run() {
Log.d(TAG, "check");
long current_length = tmp_file.length();
pass_test = tmp_file.exists() && current_length > last_length;
last_length = current_length;
if (check_count > 1) {
//3.3次检查之后,若通过,则可以答题。 否则,不能答题。
if (pass_test) {
sp.putBooleanValue(project_id, true);
MyLog.getInstance().writeMessage(TAG, "答题前检查权限:三次验证通过");
Intent intent = new Intent(ProjectActivity.this, AnswerPageActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable("projectmodel", projectModel);
intent.putExtras(bundle);
intent.putExtra("uuid", "");
intent.putExtra("answer_type", answer_type);
startActivity(intent);
phandler.sendEmptyMessage(3);
}else{
//检查不通过,提示检查权限
sp.putBooleanValue(project_id, false);
MyLog.getInstance().writeMessage(TAG, "答题前检查权限:三次验证失败");
phandler.sendEmptyMessage(1);
}
//只检查3次,3次之后停止检查,删除测试录音文件
timer.cancel();
audioRecorder.closeTestRecord();
tmp_file.delete();
}
check_count ++;
}
}, 0, 2000);
}else{
//测试录音开启失败
sp.putBooleanValue(project_id, false);
MyLog.getInstance().writeMessage(TAG, "答题前检查权限:开启测试录音失败");
phandler.sendEmptyMessage(2);
}
}
});
testRecordThread.start();
}else{
Intent intent = new Intent(ProjectActivity.this, AnswerPageActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable("projectmodel", projectModel);
intent.putExtras(bundle);
intent.putExtra("uuid", "");
intent.putExtra("answer_type", answer_type);
startActivity(intent);
}
// if (!recordModel.getVideo_type().equals("")) {// 录像
//
// }
}
测试下来,ok。
然后,类似的,录像是否也需要检查呢?于是,想当然的,按照录音的方式,把录像也搞了下。。。并且使用了两个线程,美其名曰,一起检查,省时间啊!
然后写了一个又臭又长的方法:
//2015-4-13 增加检查录音权限
private void checkMediaPermission(final int answer_type){
//如果不需要录音,不需要检查。 如果需要录音,则检查。
final RecordModel recordModel = FlysurveyApplication.recordDao.getRecordModel(project_id);
final boolean needAudio = !recordModel.getAudio_type().equals("");
final boolean needVideo = !recordModel.getVideo_type().equals("");
if (needAudio) {
MyLog.getInstance().writeMessage(TAG, "【录音】需要录音权限");
}
if (needVideo) {
MyLog.getInstance().writeMessage(TAG, "【录像】需要录像权限");
}
boolean pass_audio = needAudio ? false : true; //不需要录音的时候,当作通过验证
boolean pass_video = needVideo ? false : true;
if (recordModel != null && (needAudio || needVideo)) {// 需要录音或录像
// ======第一步检查: 如果已经检查通过了,则不需要再检查 ==========
if (needAudio && sp.getBooleanValue(project_id + "_audio", false)) {
MyLog.getInstance().writeMessage(TAG, "【录音】第一步检查通过,以前允许过");
pass_audio = true;
}else{
MyLog.getInstance().writeMessage(TAG, "【录音】不需要录音,或,第一步检查失败,以前未通过");
}
if(needVideo && sp.getBooleanValue(project_id + "_video", false)){
MyLog.getInstance().writeMessage(TAG, "【录像】:第一步检查通过,以前允许过");
pass_video = true;
}else{
MyLog.getInstance().writeMessage(TAG, "【录像】不需要录像,或,第一步检查失败,以前未通过");
}
if (pass_audio && pass_video) {
Intent intent = new Intent(ProjectActivity.this, AnswerPageActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable("projectmodel", projectModel);
intent.putExtras(bundle);
intent.putExtra("uuid", "");
intent.putExtra("answer_type", answer_type);
startActivity(intent);
return;
}
// ===== 第二步检查: 检查权限 =========
PackageManager pm = getPackageManager();
if (needAudio) {
String permission_name = "android.permission.RECORD_AUDIO";
pass_audio = (PackageManager.PERMISSION_GRANTED == pm.checkPermission(permission_name, getPackageName()));
if(!pass_audio){
//检查不通过,提示检查权限
MyLog.getInstance().writeMessage(TAG, "【录音】第二步检查不通过,没有权限");
Toast.makeText(getApplication(), R.string.answer_failed_need_audio_permission, Toast.LENGTH_LONG).show();
return;
}else{
MyLog.getInstance().writeMessage(TAG, "【录音】第二步检查通过,有权限");
}
}
if (needVideo) {
String permission_name = "android.permission.CAMERA";
pass_video = (PackageManager.PERMISSION_GRANTED == pm.checkPermission(permission_name, getPackageName()));
if(!pass_video){
//检查不通过,提示检查权限
MyLog.getInstance().writeMessage(TAG, "【录像】第二步检查不通过,没有权限");
Toast.makeText(getApplication(), R.string.answer_failed_need_video_permission, Toast.LENGTH_LONG).show();
return;
}else{
MyLog.getInstance().writeMessage(TAG, "【录像】第二步检查通过,有权限");
}
}
if (!pass_video && !pass_audio) {
//两个都不通过
Toast.makeText(getApplication(), R.string.answer_failed_need_audio_video_permission, Toast.LENGTH_LONG).show();
return;
}else if(!pass_video){
//录像不通过
Toast.makeText(getApplication(), R.string.answer_failed_need_video_permission, Toast.LENGTH_LONG).show();
return;
}else if(!pass_audio){
//录音不通过
Toast.makeText(getApplication(), R.string.answer_failed_need_audio_permission, Toast.LENGTH_LONG).show();
return;
}
// ===== 第三步检查: 生成测试文件,判断大小 =====
progressDialog = ProgressDialog.show(context, "", "正在检测答卷环境,请稍后。。。");
if (needAudio) {
final Thread testRecordThread = new Thread(new Runnable() {
@Override
public void run() {
MyLog.getInstance().writeMessage(TAG, "【录音】准备第三步检查,开启测试录音");
//1.开启一个录音
audioRecorder = new AudioRecorderUtil(recordModel,
projectModel.getProject_identifier(), project_id);
audioRecorder.activity = ProjectActivity.this;
tmp_audio_file = audioRecorder.testRecord();
}
});
testRecordThread.start();
}
if (needVideo) {
final Thread testVideoThread = new Thread(new Runnable() {
@Override
public void run() {
MyLog.getInstance().writeMessage(TAG, "【录像】准备第三步检查,开启测试录像");
//1.开启一个录像
videoRecorder = new VideoRecorderUtil(_surfaceView, recordModel,
projectModel.getProject_identifier(), project_id);
videoRecorder.activity = ProjectActivity.this;
tmp_video_file = videoRecorder.testRecord();
}
});
testVideoThread.start();
}
final Timer timer = new Timer();
timer.schedule(new TimerTask() {
private boolean pass_test_audio = needAudio ? false : true; //检查结果 true通过,false未通过
private boolean pass_test_video = needVideo ? false : true; //检查结果 true通过,false未通过
private long last_audio_length = 0; //上一次的文件大小
private long last_video_length = 0; //上一次的文件大小
private int check_count = 0; //检查次数
@Override
public void run() {
Log.d(TAG, "check");
if (needAudio) {
if (tmp_audio_file != null) {
long current_length = tmp_audio_file.length();
pass_test_audio = tmp_audio_file.exists() && current_length > last_audio_length;
last_audio_length = current_length;
}
MyLog.getInstance().writeMessage(TAG, "【Timer_" + check_count +"】是否通过录音测试:" + pass_test_audio + ", 上一次大小:" + last_audio_length);
}
if (needVideo) {
if (tmp_video_file != null) {
long current_length = tmp_video_file.length();
pass_test_video = tmp_video_file.exists() && current_length > last_video_length;
last_video_length = current_length;
}
MyLog.getInstance().writeMessage(TAG, "【Timer_" + check_count +"】是否通过录像测试:" + pass_test_video + ", 上一次大小" + last_video_length);
}
if (check_count > 1) {
//3.3次检查之后,若通过,则可以答题。 否则,不能答题。
if (!pass_test_video && !pass_test_audio) {
//检查都不通过,提示检查权限
sp.putBooleanValue(project_id + "_audio", false);
sp.putBooleanValue(project_id + "_video", false);
MyLog.getInstance().writeMessage(TAG, "答题前检查录音/录像权限:三次验证都失败");
phandler.sendEmptyMessage(AUDIO_VIDEO_FORBID);
}else if(!pass_test_audio){
//检查录音不通过,提示检查权限
sp.putBooleanValue(project_id + "_audio", false);
MyLog.getInstance().writeMessage(TAG, "答题前检查录音权限:三次验证失败");
phandler.sendEmptyMessage(AUDIO_FORBID);
}else if(!pass_test_video){
//检查录音不通过,提示检查权限
sp.putBooleanValue(project_id + "_video", false);
MyLog.getInstance().writeMessage(TAG, "答题前检查录像权限:三次验证失败");
phandler.sendEmptyMessage(VIDEO_FORBID);
}else{
sp.putBooleanValue(project_id + "_video", true);
sp.putBooleanValue(project_id + "_audio", true);
MyLog.getInstance().writeMessage(TAG, "答题前检查录音/录像权限:三次验证都通过");
Intent intent = new Intent(ProjectActivity.this, AnswerPageActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable("projectmodel", projectModel);
intent.putExtras(bundle);
intent.putExtra("uuid", "");
intent.putExtra("answer_type", answer_type);
startActivity(intent);
phandler.sendEmptyMessage(ALLPASS);
}
//只检查3次,3次之后停止检查,删除测试录音文件
timer.cancel();
if (needAudio) {
audioRecorder.closeTestRecord();
if (tmp_audio_file != null && tmp_audio_file.exists()) {
tmp_audio_file.delete();
}
}
if (needVideo) {
videoRecorder.closeTestRecord();
if (tmp_video_file != null && tmp_video_file.exists()) {
tmp_video_file.delete();
}
}
}
check_count ++;
}
}, 2000, 2000);
}else{
Intent intent = new Intent(ProjectActivity.this, AnswerPageActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable("projectmodel", projectModel);
intent.putExtras(bundle);
intent.putExtra("uuid", "");
intent.putExtra("answer_type", answer_type);
startActivity(intent);
}
}
各种查原因,找到资料, http://stackoverflow.com/questions/23971817/mediarecorder-start-failed-38,看起来是开始录像的时候,已经开启录音了,抢麦克风了。
好吧,难怪正式答题的时候,录音、录像不能同时使用。自己写过的代码,自己也不记得。纠结下就当加深印象了。
最终,把录音和录像分开来,先检测录音,通过了再检测录像。
检测录音的代码:
/**
* 2015-4-13 增加检查录音权限
* 先检测录音,录音通过再检测录像
* @param answer_type
*/
private void checkMediaPermission(final int answer_type) {
// 如果不需要录音,不需要检查。 如果需要录音,则检查。
final RecordModel recordModel = FlysurveyApplication.recordDao
.getRecordModel(project_id);
if (recordModel == null) {
goToAnswerPage(answer_type);
return;
}
final boolean needAudio = !recordModel.getAudio_type().equals("");
// 需要录音,则先判断录音,后判断录像。不需要录音,直接判断录像
if (needAudio) {
MyLog.getInstance().writeMessage(TAG, "【录音】需要录音权限");
boolean pass_audio = false;
// ======第一步检查: 如果已经检查通过了,则不需要再检查 ==========
if (sp.getBooleanValue(project_id + "_audio", false)) {
MyLog.getInstance().writeMessage(TAG, "【录音】第一步检查通过,以前允许过");
pass_audio = true;
checkVideoPermission(recordModel, answer_type);
return;
} else {
MyLog.getInstance().writeMessage(TAG, "【录音】第一步检查失败,以前未通过");
}
// ===== 第二步检查: 检查权限 =========
PackageManager pm = getPackageManager();
String permission_name = "android.permission.RECORD_AUDIO";
pass_audio = (PackageManager.PERMISSION_GRANTED == pm
.checkPermission(permission_name, getPackageName()));
if (!pass_audio) {
// 检查不通过,提示检查权限
MyLog.getInstance().writeMessage(TAG, "【录音】第二步检查不通过,没有权限");
Toast.makeText(getApplication(),
R.string.answer_failed_need_audio_permission,
Toast.LENGTH_LONG).show();
return;
} else {
MyLog.getInstance().writeMessage(TAG, "【录音】第二步检查通过,有权限");
}
// ===== 第三步检查: 生成测试文件,判断大小 =====
progressDialog = ProgressDialog
.show(context, "", "正在检测答卷环境,请稍后。。。");
final Thread testRecordThread = new Thread(new Runnable() {
@Override
public void run() {
MyLog.getInstance().writeMessage(TAG, "【录音】准备第三步检查,开启测试录音");
// 1.开启一个录音
audioRecorder = new AudioRecorderUtil(recordModel,
projectModel.getProject_identifier(), project_id);
audioRecorder.activity = ProjectActivity.this;
tmp_audio_file = audioRecorder.testRecord();
}
});
testRecordThread.start();
final Timer timer = new Timer();
timer.schedule(new TimerTask() {
private boolean pass_test_audio = false; // 检查结果 true通过,false未通过
private long last_audio_length = 0; // 上一次的文件大小
private int check_count = 0; // 检查次数
@Override
public void run() {
if (tmp_audio_file != null) {
long current_length = tmp_audio_file.length();
pass_test_audio = tmp_audio_file.exists()
&& current_length > last_audio_length;
last_audio_length = current_length;
}
MyLog.getInstance().writeMessage(
TAG,
"【AudioTimer_" + check_count + "】是否通过录音测试:"
+ pass_test_audio + ", 上一次大小:"
+ last_audio_length);
if (check_count > 2) {
//3. 3次检查之后,关闭测试文件。(必须先关闭,否则影响后面测试录像)
// 只检查3次,3次之后停止检查,删除测试录音文件
timer.cancel();
audioRecorder.closeTestRecord();
if (tmp_audio_file != null && tmp_audio_file.exists()) {
tmp_audio_file.delete();
}
//若通过,则可以答题。 否则,不能答题。
if (!pass_test_audio) {
// 检查录音不通过,提示检查权限
sp.putBooleanValue(project_id + "_audio", false);
MyLog.getInstance().writeMessage(TAG,
"答题前检查录音权限:三次验证失败");
phandler.sendEmptyMessage(AUDIO_FORBID);
} else {
sp.putBooleanValue(project_id + "_audio", true);
MyLog.getInstance().writeMessage(TAG,
"答题前检查录音权限:三次验证都通过");
checkVideoPermission(recordModel, answer_type);
}
}
check_count++;
}
}, 2000, 2000);
}else{
checkVideoPermission(recordModel, answer_type);
}
}
/**
* 检测录像
* @param recordModel
* @param answer_type
*/
private void checkVideoPermission(final RecordModel recordModel, final int answer_type){
final boolean needVideo = !recordModel.getVideo_type().equals("");
if (needVideo) {
// 录音检查通过,开始检查录像
MyLog.getInstance().writeMessage(TAG, "【录像】需要录像权限");
boolean pass_video = false;
// ======第一步检查: 如果已经检查通过了,则不需要再检查 ==========
if (sp.getBooleanValue(project_id + "_video", false)) {
MyLog.getInstance().writeMessage(TAG,
"【录像】:第一步检查通过,以前允许过");
pass_video = true;
sp.putBooleanValue(project_id + "_video",
true);
goToAnswerPage(answer_type);
phandler.sendEmptyMessage(ALLPASS);
return;
} else {
MyLog.getInstance().writeMessage(TAG,
"【录像】第一步检查失败,以前未通过");
}
// ===== 第二步检查: 检查权限 =========
PackageManager pm = getPackageManager();
String permission_name = "android.permission.CAMERA";
pass_video = (PackageManager.PERMISSION_GRANTED == pm
.checkPermission(permission_name, getPackageName()));
if (!pass_video) {
// 检查不通过,提示检查权限
MyLog.getInstance().writeMessage(TAG,
"【录像】第二步检查不通过,没有权限");
sp.putBooleanValue(project_id + "_video",
false);
phandler.sendEmptyMessage(VIDEO_FORBID);
return;
} else {
MyLog.getInstance()
.writeMessage(TAG, "【录像】第二步检查通过,有权限");
}
// ===== 第三步检查: 生成测试文件,判断大小 =====
if (progressDialog == null) {
progressDialog = ProgressDialog.show(context, "",
"正在检测答卷环境,请稍后。。。");
}
final Thread testVideoThread = new Thread(new Runnable() {
@Override
public void run() {
MyLog.getInstance().writeMessage(TAG,
"【录像】准备第三步检查,开启测试录像");
// 1.开启一个录像
videoRecorder = new VideoRecorderUtil(_surfaceView,
recordModel,
projectModel.getProject_identifier(),
project_id);
videoRecorder.activity = ProjectActivity.this;
tmp_video_file = videoRecorder.testRecord();
}
});
testVideoThread.start();
final Timer timer = new Timer();
timer.schedule(new TimerTask() {
private boolean pass_test_video = false;
private long last_video_length = 0; // 上一次的文件大小
private int check_count = 0; // 检查次数
@Override
public void run() {
if (tmp_video_file != null) {
long current_length = tmp_video_file.length();
pass_test_video = tmp_video_file.exists()
&& current_length > last_video_length;
last_video_length = current_length;
}
MyLog.getInstance().writeMessage(
TAG,
"【VideoTimer_" + check_count + "】是否通过录像测试:"
+ pass_test_video + ", 上一次大小"
+ last_video_length);
if (check_count > 2) {
// 只检查3次,3次之后停止检查,删除测试录音文件
timer.cancel();
videoRecorder.closeTestRecord();
if (tmp_video_file != null
&& tmp_video_file.exists()) {
tmp_video_file.delete();
}
// 3.3次检查之后,若通过,则可以答题。 否则,不能答题。
if (!pass_test_video) {
// 检查录像不通过,提示检查权限
sp.putBooleanValue(project_id + "_video",
false);
MyLog.getInstance().writeMessage(TAG,
"答题前检查录像权限:三次验证失败");
phandler.sendEmptyMessage(VIDEO_FORBID);
} else {
sp.putBooleanValue(project_id + "_video",
true);
MyLog.getInstance().writeMessage(TAG,
"答题前检查录像权限:三次验证都通过");
goToAnswerPage(answer_type);
phandler.sendEmptyMessage(ALLPASS);
}
}
check_count++;
}
}, 2000, 2000);
} else {
sp.putBooleanValue(project_id + "_video",
true);
goToAnswerPage(answer_type);
phandler.sendEmptyMessage(ALLPASS);
}
}