android - Android Manifest 文件中的错误,呼叫记录器
问题描述
当有人打电话时,我正在尝试录制语音通话。我已经从多个来源复制了代码。但是 Manifest 文件中有错误。debug/AndroidManifest_xml 中的所有问题。AAPT_error_'device_description' 与属性描述 (attr) 参考不兼容。android:description="device_description" 和 android:permission="android.permission.BIND_DEVICE_ADMIN"。有问题。
代码:
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>