Android清单文件、调用记录器中出错
当有人打电话时,我正在尝试录制语音通话。我从多个来源复制了代码。但清单文件中有错误。调试/AndroidManifest_xml中的所有问题。AAPT_uu错误_uu“设备描述”与属性描述(attr)引用不兼容。 android:description=“device\u description”和android:permission=“android.permission.BIND\u device\u ADMIN”。我有问题 代码:Android清单文件、调用记录器中出错,android,manifest,mediarecorder,Android,Manifest,Mediarecorder,当有人打电话时,我正在尝试录制语音通话。我从多个来源复制了代码。但清单文件中有错误。调试/AndroidManifest_xml中的所有问题。AAPT_uu错误_uu“设备描述”与属性描述(attr)引用不兼容。 android:description=“device\u description”和android:permission=“android.permission.BIND\u device\u ADMIN”。我有问题 代码: MainActivity.java: public
MainActivity.java:
public class MainActivity extends AppCompatActivity {
Context mContext;
private static final int REQUEST_CODE = 0;
private DevicePolicyManager mDPM;
private ComponentName mAdminName;
static final int REQUEST = 112;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
try {
// Initiate DevicePolicyManager.
mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
mAdminName = new ComponentName(this, DeviceAdminDemo.class);
if (!mDPM.isAdminActive(mAdminName)) {
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mAdminName);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, "Click on Activate button to secure your application.");
startActivityForResult(intent, REQUEST_CODE);
} else {
// mDPM.lockNow();
// Intent intent = new Intent(MainActivity.this,
// TrackDeviceService.class);
// startService(intent);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (REQUEST_CODE == requestCode) {
Intent intent = new Intent(MainActivity.this, TService.class);
startService(intent);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//do here
Toast.makeText(mContext, "The app was allowed to read your store.", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(mContext, "The app was not allowed to read your store.", Toast.LENGTH_LONG).show();
}
}
}
}
}
DeviceAdminDemo.java:
public class DeviceAdminDemo extends DeviceAdminReceiver {
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
}
public void onEnabled(Context context, Intent intent) {
};
public void onDisabled(Context context, Intent intent) {
};
}
TService.java:
public class TService extends Service {
private static final String ACTION_IN = "android.intent.action.PHONE_STATE";
private static final String ACTION_OUT = "android.intent.action.NEW_OUTGOING_CALL";
private CallBr br_call;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
Log.d("service", "destroy");
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
final IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_OUT);
filter.addAction(ACTION_IN);
this.br_call = new CallBr();
this.registerReceiver(this.br_call, filter);
return START_NOT_STICKY;
}
}
CallBr.java:
public class CallBr extends BroadcastReceiver {
private static final String ACTION_IN = "android.intent.action.PHONE_STATE";
private static final String ACTION_OUT = "android.intent.action.NEW_OUTGOING_CALL";
Bundle bundle;
String state;
String inCall, outCall;
public boolean wasRinging = false;
MediaRecorder recorder = null;
private static final String AUDIO_RECORDER_FILE_EXT_3GP = ".3gp";
private static final String AUDIO_RECORDER_FILE_EXT_MP4 = ".mp4";
private static final String AUDIO_RECORDER_FOLDER = "AudioRecorder";
private int currentFormat = 0;
private int output_formats[] = { MediaRecorder.OutputFormat.MPEG_4,
MediaRecorder.OutputFormat.THREE_GPP };
private String file_exts[] = { AUDIO_RECORDER_FILE_EXT_MP4,
AUDIO_RECORDER_FILE_EXT_3GP };
String RECORD_DIRECTORY = "Call Records";
static final int REQUEST = 112;
private boolean isRecordStarted = false;
@Override
public void onReceive(Context mContext, Intent intent) {
if (intent.getAction().equals(ACTION_IN)) {
if ((bundle = intent.getExtras()) != null) {
state = bundle.getString(TelephonyManager.EXTRA_STATE);
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
inCall = bundle.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
wasRinging = true;
Toast.makeText(mContext, "IN : " + inCall, Toast.LENGTH_LONG).show();
} else if (state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
if (wasRinging == true) {
Toast.makeText(mContext, "ANSWERED", Toast.LENGTH_LONG).show();
if (Build.VERSION.SDK_INT >= 23) {
String[] PERMISSIONS = {android.Manifest.permission.CALL_PHONE, android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_EXTERNAL_STORAGE, android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.MODIFY_AUDIO_SETTINGS, android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.PROCESS_OUTGOING_CALLS, Manifest.permission.MANAGE_EXTERNAL_STORAGE};
if (!hasPermissions(mContext, PERMISSIONS)) {
ActivityCompat.requestPermissions((Activity) mContext, PERMISSIONS, REQUEST );
startMediaRecorder();
} else {
//do here
startMediaRecorder();
}
} else {
//do here
startMediaRecorder();
}
}
} else if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
wasRinging = false;
Toast.makeText(mContext, "REJECT || DISCO", Toast.LENGTH_LONG).show();
if (isRecordStarted) {
recorder.stop();
isRecordStarted = false;
}
}
}
} else if (intent.getAction().equals(ACTION_OUT)) {
if ((bundle = intent.getExtras()) != null) {
outCall = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Toast.makeText(mContext, "OUT : " + outCall, Toast.LENGTH_LONG).show();
}
}
}
private boolean startMediaRecorder(){
recorder = new MediaRecorder();
try{
recorder.reset();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setAudioSamplingRate(8000);
recorder.setAudioEncodingBitRate(12200);
recorder.setOutputFormat(output_formats[currentFormat]);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
recorder.setOutputFile(getFilename());
MediaRecorder.OnErrorListener errorListener = new MediaRecorder.OnErrorListener() {
public void onError(MediaRecorder arg0, int arg1, int arg2) {
//Log.e(TAG, "OnErrorListener " + arg1 + "," + arg2);
terminateAndEraseFile();
}
};
recorder.setOnErrorListener(errorListener);
MediaRecorder.OnInfoListener infoListener = new MediaRecorder.OnInfoListener() {
public void onInfo(MediaRecorder arg0, int arg1, int arg2) {
//Log.e(TAG, "OnInfoListener " + arg1 + "," + arg2);
terminateAndEraseFile();
}
};
recorder.setOnInfoListener(infoListener);
recorder.prepare();
// Sometimes prepare takes some time to complete
Thread.sleep(2000);
recorder.start();
//recordstarted = true;
isRecordStarted = true;
return true;
}catch (Exception e){
e.getMessage();
terminateAndEraseFile();
return false;
}
}
private String getFilename() {
File MediaDirectory = new File( Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC), RECORD_DIRECTORY );
// have the object build the directory structure, if needed.
if (!MediaDirectory.exists()) {
Log.d("dirrrrrr", "" + MediaDirectory.mkdirs());
MediaDirectory.mkdirs();
}
String out = new SimpleDateFormat("dd-MM-yyyy hh-mm-ss").format(new Date());
return (MediaDirectory + "/" + out + "_" + System.currentTimeMillis() + file_exts[currentFormat]);
}
private void terminateAndEraseFile(){
try{
if (null != recorder) {
recorder.stop();
recorder.reset();
recorder.release();
recorder = null;
}
}catch(RuntimeException stopException){
}
}
private static boolean hasPermissions(Context context, String... permissions) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context != null && permissions != null) {
for (String permission : permissions) {
if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
}
return true;
}
}
Layout_my_admin.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">
<device-admin xmlns:android="http://schemas.android.com/apk/res/android" >
<uses-policies>
<force-lock />
</uses-policies>
main_AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.callrecorder">
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.STORAGE" />
<application
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/Theme.CallRecorder">
<receiver
android:name="com.example.callrecorder.DeviceAdminDemo"
android:description="device_description"
android:label="device_admin_label"
android:permission="android.permission.BIND_DEVICE_ADMIN" >
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/my_admin" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
<action android:name="android.app.action.DEVICE_ADMIN_DISABLED" />
<action android:name="android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED" />
</intent-filter>
</receiver>
<service android:name=".TService" >
</service>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
</device-admin>
</LinearLayout>
debug/AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.callrecorder"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="30" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.STORAGE" />
<application
android:allowBackup="true"
android:appComponentFactory="androidx.core.app.CoreComponentFactory"
android:debuggable="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:testOnly="true"
android:theme="@style/Theme.CallRecorder" >
<receiver
android:name="com.example.callrecorder.DeviceAdminDemo"
android:description="device_description"
android:label="device_admin_label"
android:permission="android.permission.BIND_DEVICE_ADMIN">
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/my_admin" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
<action android:name="android.app.action.DEVICE_ADMIN_DISABLED" />
<action android:name="android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED" />
</intent-filter>
</receiver>
<service android:name="com.example.callrecorder.TService" >
</service>
<activity android:name="com.example.callrecorder.MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
public类MainActivity扩展了AppCompatActivity{
语境;
私有静态最终整数请求_代码=0;
专用设备policymanager mDPM;
私有组件名mAdminName;
静态最终整数请求=112;
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext=这个;
试一试{
//启动DevicePolicyManager。
mDPM=(DevicePolicyManager)getSystemService(Context.DEVICE\u POLICY\u服务);
mAdminName=新组件名称(此为DeviceAdminDemo.class);
如果(!mDPM.isAdminActive(mAdminName)){
意向意向=新意向(DevicePolicyManager.ACTION\u ADD\u DEVICE\u ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,mAdminName);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_解释,“单击激活按钮以保护您的应用程序”);
startActivityForResult(意图、请求代码);
}否则{
//mDPM.lockNow();
//意向意向=新意向(MainActivity.this,
//TrackDeviceService.class);
//startService(意向);
}
}捕获(例外e){
e、 printStackTrace();
}
}
@凌驾
受保护的void onActivityResult(int请求代码、int结果代码、意图数据){
super.onActivityResult(请求代码、结果代码、数据);
if(请求\代码==请求代码){
意向意向=新意向(MainActivity.this、TService.class);
startService(意向);
}
}
@凌驾
public void onRequestPermissionsResult(int-requestCode,@NonNull-String[]permissions,@NonNull-int[]grantResults){
super.onRequestPermissionsResult(请求代码、权限、授权结果);
开关(请求代码){
案件请求:{
if(grantResults.length>0&&grantResults[0]==PackageManager.PERMISSION\u已授予){
//在这里做什么
Toast.makeText(mContext,“允许应用程序读取您的商店。”,Toast.LENGTH_LONG.show();
}否则{
Toast.makeText(mContext,“应用程序不允许读取您的应用商店。”,Toast.LENGTH_LONG.show();
}
}
}
}
}
DeviceAdminDemo.java:
公共类DeviceAdminDemo扩展DeviceAdminReceiver{
@凌驾
公共void onReceive(上下文、意图){
super.onReceive(上下文、意图);
}
公共void已启用(上下文、意图){
};
公共无效已禁用(上下文、意图){
};
}
TService.java:
公共类TService扩展了服务{
私有静态最终字符串ACTION_IN=“android.intent.ACTION.PHONE_STATE”;
私有静态最终字符串ACTION\u OUT=“android.intent.ACTION.NEW\u OUTGOING\u CALL”;
私人通话br bru通话;
@可空
@凌驾
公共IBinder onBind(意向){
返回null;
}
@凌驾
公共空间{
日志d(“服务”、“销毁”);
super.ondestory();
}
@凌驾
公共int onStartCommand(Intent Intent、int标志、int startId){
最终IntentFilter筛选器=新IntentFilter();
filter.addAction(ACTION_OUT);
filter.addAction(ACTION_IN);
this.br_call=new CallBr();
this.registerReceiver(this.br\u调用,过滤器);
返回开始时间不粘;
}
}
CallBr.java:
公共类CallBr扩展广播接收器{
私有静态最终字符串ACTION_IN=“android.intent.ACTION.PHONE_STATE”;
私有静态最终字符串ACTION\u OUT=“android.intent.ACTION.NEW\u OUTGOING\u CALL”;
束;
字符串状态;
字符串inCall,outCall;
公共布尔值=false;
MediaRecorder=null;
专用静态最终字符串音频\u记录器\u文件\u EXT\u 3GP=“.3GP”;
专用静态最终字符串音频\u记录器\u文件\u EXT\u MP4=“.MP4”;
专用静态最终字符串音频\u记录器\u文件夹=“音频记录器”;
私有int currentFormat=0;
私有int输出_格式[]={MediaRecorder.OutputFormat.MPEG_4,
MediaRecorder.OutputFormat.ThreeU GPP};
私有字符串文件\u exts[]={音频记录器\u文件\u EXT\u MP4,
音频\u记录器\u文件\u EXT\u 3GP};
String RECORD_DIRECTORY=“呼叫记录”;
静态最终整数请求=112;
私有布尔值isRecordStarted=false;
@凌驾
public void onReceive(上下文mContext、意图){
if(intent.getAction().equals(ACTION_IN)){
if((bundle=intent.getExtras())!=null){
state=bundle.getString(TelephonyManager.EXTRA_状态);
if(state.equals(TelephonyManager.EXTRA_state_RINGING)){
inCall=bundle.getString(Te