錄音權限與攝像頭權限


(一)、Android錄音權限被禁解決方案

大家在做Android錄音的時候會碰到權限被禁止的情況出現,當用戶禁止了錄音權限的時候我們為了界面友好會提示用戶,但是安卓機型很多,有些機型在錄音start的時候如果被禁會報異常,當然這種情況很好解決,但是有些機型會正常執行,在此我們分析一下我所遇到的情況。

被禁情況分析

1,第一種,就是start的時候會報異常,這種我們把它包在try catch中即可捕獲到異常。在此不多累述。 
2,第二種,就是不報異常,正常執行,這種情況我們沒辦法去判斷系統是否禁止了我們的app的錄音權限。

所以我在此分析的是部分機型在被禁止后不報異常,我們可以去檢測音頻振幅大小,部分機型的音頻振幅值在用MediaRecorder時是0,在用AudioRecord時值小於0,所以這種情況我們可以通過其振幅值判斷:


(1)AudioRecord判斷方法:

int readSize = 0;

/*--實時錄音寫數據--*/ readSize = audioRecord.read(buffer,0,minBufferSize); if (readSize < 0) { //錄音出現異常 } 

該方法能檢測到大部分機型錄音被禁止,或其他異常狀況。 

  檢測錄音程序是否被禁用了,可以使用下面的代碼判斷

int read = audioRecord.read(data, 0, recBufSize);

if(AudioRecord.ERROR_INVALID_OPERATION != read){
      // 做正常的錄音處理
} else {
     //錄音可能被禁用了,做出適當的提示
}

 

 

(2)MediaRecorder判斷方法: 

MediaRecorder就不怎么好檢測了,因為MediaRecorder在用方法getMaxAmplitude()時取得振幅值是0-32767,也就是即使不禁止錄音權限,振幅值依然會有0值出現,所以不能簡單地判斷振幅值是否為0,我在此的檢測方法是根據前1s的錄音,取10次振幅值進行判斷: 


先聲明三個變量:

    private int vocAuthority[] = new int[10];

    private int vocNum = 0;

 private boolean check = true;

然后寫個方法:

int vocLevel = mRecorder.getMaxAmplitude(); if (check) { if (vocNum >= 10) { Set<Integer> set = new HashSet<Integer>(); for (int i = 0; i < vocNum; i++) { set.add(vocAuthority[i]); } if (set.size() == 1) { if (handler != null) handler.sendEmptyMessage(MSG_ERROR_AUDIO_RECORD); }else{ check = false; } } else { vocAuthority[vocNum] = vocLevel; vocNum++; } }

該方法每100ms執行一次,1s十次后判斷vocAuthority中的值是否全部一樣,也就是說是否全部為零,如果全部一樣那么錄音肯定有問題。(我試了如果在非常安靜的情況下前十次的取值也不是都為零,大家可以試試) 


3,第三種,還有部分機型不僅不報異常,而且在錄音時會制造音頻振幅的假數據,也就是雖然錄音被禁止,系統依然會把音頻振幅反饋給你,像華為p7就是這樣,這種情況肯定不能再去檢測音頻振幅了,只能另辟蹊徑,通過我的觀察發現在用MediaRecorder錄音時,如果被禁止那么本地不會出現錄音文件,所以我們可以以此為突破口,檢測本地是否有生成的錄音文件來判斷系統是否禁止了我們的錄音權限。AudioRecord我沒試,大家可以試試。

 

(二)、Android攝像頭權限被禁解決方案

待總結

 

 

直接上代碼吧!!!

package com.wytiger.mytest.utils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import android.annotation.TargetApi;
import android.app.AppOpsManager;
import android.content.Context;
import android.hardware.Camera;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Binder;
import android.os.Build;
import android.util.Log;

@SuppressWarnings("deprecation")
public class PermissionUtil {
public static final String TAG = "TAG_PERMISSION";

public static final int STATE_NO_PERMISSION = -1;
public static final int STATE_RECORDING = 0;
public static final int STATE_SUCCESS = 1;

/**
* 判斷是否有錄音權限
*
* @return
*/
public static boolean hasRecordPermission() {
boolean hasPermission = false;
if (getRecordState() == STATE_SUCCESS) {
hasPermission = true;
} else {
hasPermission = false;
}

return hasPermission;
}

/**
* 判斷是否有錄音權限
*
* @return
*/
// public static boolean hasRecordPermission2() {
// boolean hasPermission = false;
//
//
//
// return hasPermission;
// }

/**
* 獲取錄音狀態
*
* @return
*/
public static int getRecordState() {
int minBuffer = AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
short[] point = new short[minBuffer];
int readSize = 0;

AudioRecord audioRecord = null;
try {
audioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, 44100, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,
(minBuffer * 100));
// 開始錄音
audioRecord.startRecording();// 檢測是否可以進入初始化狀態

} catch (Exception e) {
Log.e(TAG, "catch, 捕捉到異常, 無錄音權限, e = " + e.getMessage());

if (audioRecord != null) {
audioRecord.release();
audioRecord = null;
Log.i(TAG, "catch, 返回對象非空,釋放資源");
} else {
Log.i(TAG, "catch, 返回對象非空");
}

return STATE_NO_PERMISSION;
}

// 檢測是否在錄音中
if (audioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) {
// 6.0以下機型都會返回此狀態,故使用時需要判斷bulid版本
if (audioRecord != null) {
audioRecord.stop();
audioRecord.release();
audioRecord = null;
Log.e(TAG, "無法啟動錄音, 無法錄音");
}
return STATE_RECORDING;

} else {// 正在錄音
readSize = audioRecord.read(point, 0, point.length);

// 檢測是否可以獲取錄音結果
if (readSize <= 0) {
if (audioRecord != null) {
audioRecord.stop();
audioRecord.release();
audioRecord = null;
}
Log.e(TAG, "沒有獲取到錄音數據,無錄音權限");
return STATE_NO_PERMISSION;

} else {
if (audioRecord != null) {
audioRecord.stop();
audioRecord.release();
audioRecord = null;
}
Log.i(TAG, "獲取到錄音數據, 有錄音權限");
return STATE_SUCCESS;
}
}
}

/**
* 是否有攝像頭權限
*
* @return
*/
@SuppressWarnings("deprecation")
public static boolean hasCameraPermission() {
// 無權限可能出現的情況(部分):
// 1, 直接拋異常
// 2, 不拋異常,返回對象為空
// 3, 獲取到的數據為空

boolean canUse = true;
Camera mCamera = null;
try {
mCamera = Camera.open();
mCamera.setParameters(mCamera.getParameters());
} catch (Exception e) {
Log.e(TAG, "catch, 捕捉到異常, 無攝像頭權限");
// 1, 直接拋異常
canUse = false;

if (mCamera != null) {// 返回對象非空(魅族)
mCamera.release();
mCamera = null;
Log.i(TAG, "catch, 對象非空,釋放資源");

} else if (mCamera == null) {// 2, 返回對象為空
Log.e(TAG, "catch, 對象為空");
}

} finally {
if (mCamera != null) {
canUse = true;
mCamera.release();
mCamera = null;
Log.i(TAG, "finally, 對象非空,釋放資源");

} else if (mCamera == null) {// 2, 返回對象為空
canUse = false;
Log.e(TAG, "finally, 對象為空");
}
}

Log.i(TAG, "返回");
return canUse;
}

// op flag
public static final int opCameraFlag = 26;
public static final int opRecordAudioFlag = 27;

@TargetApi(Build.VERSION_CODES.KITKAT)
/**
* 是否有指定權限,在api19以上有效
* @param mContext:上下文
* @param opFlag: 指定操作碼,see AppOpsManager define
* @return
*/
public boolean hasPermission(Context mContext, int opFlag) {
boolean hasPermission = false;

if (Build.VERSION.SDK_INT >= 19) {
if (checkOp(mContext, opFlag) == 0) {
hasPermission = true;

} else if (checkOp(mContext, opFlag) == 1) {
hasPermission = false;

} else {
hasPermission = false;
Log.e(TAG, "內部出錯");
}

return hasPermission;

} else {
Log.e(TAG, "API below 19 cannot invoke!");
}
return true;
}


@TargetApi(Build.VERSION_CODES.KITKAT)
@SuppressWarnings({ "unchecked", "rawtypes" })
/**
* Api19以上有效
* 返回 0 代表有權限,1代表沒有權限,-1函數出錯啦
*
* @param context
* @param op
* @return
*/
private static int checkOp(Context context, int op) {
if (Build.VERSION.SDK_INT >= 19) {
try {
AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
Class clazz = AppOpsManager.class;
Class[] cArg = new Class[3];
cArg[0] = int.class;
cArg[1] = int.class;
cArg[2] = String.class;
Method checkOpMethod = clazz.getDeclaredMethod("checkOp", cArg);
return (Integer) checkOpMethod.invoke(manager, op, Binder.getCallingUid(), context.getPackageName());
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
return -1;
}

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM