【问题标题】:How to record phone calls in android?如何在android中记录电话?
【发布时间】:2013-09-24 02:55:51
【问题描述】:

我想制作一个应用程序来记录来电和去电,并在用户接听或拨打任何电话时自动运行。

【问题讨论】:

    标签: android recording


    【解决方案1】:

    好的,首先您需要使用设备策略管理器,并且需要将您的设备设为管理员设备。之后,您必须创建一个广播接收器和一项服务。我在这里发布代码并且工作正常。

    主活动:

    public class MainActivity extends Activity {
        private static final int REQUEST_CODE = 0;
        private DevicePolicyManager mDPM;
        private ComponentName mAdminName;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            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);
            }
        }
    
    }
    

    //DeviceAdminDemo类

    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类

    public class TService extends Service {
        MediaRecorder recorder;
        File audiofile;
        String name, phonenumber;
        String audio_format;
        public String Audio_Type;
        int audioSource;
        Context context;
        private Handler handler;
        Timer timer;
        Boolean offHook = false, ringing = false;
        Toast toast;
        Boolean isOffHook = false;
        private boolean recordstarted = false;
    
        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;
    
    
    
    
        @Override
        public IBinder onBind(Intent arg0) {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public void onDestroy() {
            Log.d("service", "destroy");
    
            super.onDestroy();
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            // final String terminate =(String)
            // intent.getExtras().get("terminate");//
            // intent.getStringExtra("terminate");
            // Log.d("TAG", "service started");
            //
            // TelephonyManager telephony = (TelephonyManager)
            // getSystemService(Context.TELEPHONY_SERVICE); // TelephonyManager
            // // object
            // CustomPhoneStateListener customPhoneListener = new
            // CustomPhoneStateListener();
            // telephony.listen(customPhoneListener,
            // PhoneStateListener.LISTEN_CALL_STATE);
            // context = getApplicationContext();
    
            final IntentFilter filter = new IntentFilter();
            filter.addAction(ACTION_OUT);
            filter.addAction(ACTION_IN);
            this.br_call = new CallBr();
            this.registerReceiver(this.br_call, filter);
    
            // if(terminate != null) {
            // stopSelf();
            // }
            return START_NOT_STICKY;
        }
    
        public class CallBr extends BroadcastReceiver {
            Bundle bundle;
            String state;
            String inCall, outCall;
            public boolean wasRinging = false;
    
            @Override
            public void onReceive(Context context, 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(context, "IN : " + inCall, Toast.LENGTH_LONG).show();
                        } else if (state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
                            if (wasRinging == true) {
    
                                Toast.makeText(context, "ANSWERED", Toast.LENGTH_LONG).show();
    
                                String out = new SimpleDateFormat("dd-MM-yyyy hh-mm-ss").format(new Date());
                                File sampleDir = new File(Environment.getExternalStorageDirectory(), "/TestRecordingDasa1");
                                if (!sampleDir.exists()) {
                                    sampleDir.mkdirs();
                                }
                                String file_name = "Record";
                                try {
                                    audiofile = File.createTempFile(file_name, ".amr", sampleDir);
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                                String path = Environment.getExternalStorageDirectory().getAbsolutePath();
    
                                recorder = new MediaRecorder();
    //                          recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL);
    
                                recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION);
                                recorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);
                                recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
                                recorder.setOutputFile(audiofile.getAbsolutePath());
                                try {
                                    recorder.prepare();
                                } catch (IllegalStateException e) {
                                    e.printStackTrace();
                                } catch (IOException e) { 
                                    e.printStackTrace();
                                }
                                recorder.start();
                                recordstarted = true;
                            }
                        } else if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
                            wasRinging = false;
                            Toast.makeText(context, "REJECT || DISCO", Toast.LENGTH_LONG).show();
                            if (recordstarted) {
                                recorder.stop();
                                recordstarted = false;
                            }
                        }
                    }
                } else if (intent.getAction().equals(ACTION_OUT)) {
                    if ((bundle = intent.getExtras()) != null) {
                        outCall = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
                        Toast.makeText(context, "OUT : " + outCall, Toast.LENGTH_LONG).show();
                    }
                }
            }
        }
    
    }
    

    //清单文件中的权限

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.RECORD_AUDIO" />
        <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
        <uses-permission android:name="android.permission.READ_PHONE_STATE" />
        <uses-permission android:name="android.permission.STORAGE" />
    

    //my_admin.xml

    <device-admin xmlns:android="http://schemas.android.com/apk/res/android" >
        <uses-policies>
            <force-lock />
        </uses-policies>
    </device-admin>
    

    //在manifest中声明如下内容:

    将 DeviceAdminDemo 类声明为清单:

     <receiver
                android:name="com.example.voicerecorder1.DeviceAdminDemo"
                android:description="@string/device_description"
                android:label="@string/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>
    

    【讨论】:

    • 它会在后台记录通话......不是在前面,如果你想改变你可以根据你的要求来做,但是这个代码工作正常。如果您觉得有用,请接受并投票。因为其他人可以从中受益。
    • 是否有这个 Github 存储库示例?
    • 它工作得很好......但是在我重新启动手机后......录制停止......没有吐司,没有任何工作......它变得没用......如何将device_admin设置为boot_completed。
    • 通话后找不到我的记录
    • 这个DevicePolicyManager在这里有什么用?
    【解决方案2】:

    下面的代码可以让我记录拨出电话

    //Call Recording varibales
    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 MediaRecorder recorder = null;
    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 };
    
    AudioManager audioManager;
    

    //把这个方法放到oncreate()方法之外

    private String getFilename() {
        String filepath = Environment.getExternalStorageDirectory().getPath();
        File file = new File(filepath, AUDIO_RECORDER_FOLDER);
    
        if (!file.exists()) {
            file.mkdirs();
        }
    
        return (file.getAbsolutePath() + "/" + System.currentTimeMillis() + file_exts[currentFormat]);
    }
    
    private MediaRecorder.OnErrorListener errorListener = new MediaRecorder.OnErrorListener() {
        @Override
        public void onError(MediaRecorder mr, int what, int extra) {
            Toast.makeText(CallActivity.this,
                    "Error: " + what + ", " + extra, Toast.LENGTH_SHORT).show();
        }
    };
    
    private MediaRecorder.OnInfoListener infoListener = new MediaRecorder.OnInfoListener() {
        @Override
        public void onInfo(MediaRecorder mr, int what, int extra) {
            Toast.makeText(CallActivity.this,
                    "Warning: " + what + ", " + extra, Toast.LENGTH_SHORT)
                    .show();
        }
    };
    

    //下面的部分代码使您的设备在扬声器上

        audioManager = (AudioManager)getApplicationContext().getSystemService(Context.AUDIO_SERVICE); 
        audioManager.setMode(AudioManager.MODE_IN_CALL);
        audioManager.setSpeakerphoneOn(true);
    

    //下面部分代码开始录制

    recorder = new MediaRecorder();
        recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        recorder.setOutputFormat(output_formats[currentFormat]);
        //recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
        recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
        recorder.setOutputFile(getFilename());
        recorder.setOnErrorListener(errorListener);
        recorder.setOnInfoListener(infoListener);
    
        try {
            recorder.prepare();
            recorder.start();
        } catch (IllegalStateException e) {
             Log.e("REDORDING :: ",e.getMessage());
                e.printStackTrace();
        } catch (IOException e) {
            Log.e("REDORDING :: ",e.getMessage());
            e.printStackTrace();
        }
    

    //为了停止录音,请记住在通话结束或停止时关闭扬声器

    audioManager.setSpeakerphoneOn(false);
    
        try{
            if (null != recorder) {
                recorder.stop();
                recorder.reset();
                recorder.release();
    
                recorder = null;
            }
        }catch(RuntimeException stopException){
    
        }
    

    并授予清单文件的权限,

    <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" />
    

    【讨论】:

    • 如何检测拨出电话被接听或挂断
    • Hi Muhammad,希望它能够工作,因为它使用设备的系统调用功能,所以,你可以试试。
    • 这种方法适用于某些手机。完全取决于制造商。要尝试的更多参数:MediaRecorder.AudioSource.VOICE_CALL、VOICE_DOWNLINK、VOICE_UPLINK。如果您想要更好的控制(例如,更好的质量:输出 PCM 格式),请使用 AudioRecorder。
    • 能否请教一下来电的处理方法,也放到github上?
    • @AbhijitChakra : 没有在棉花糖上测试,因为已经实现了很久,但我认为它会起作用,只是你必须为棉花糖添加允许权限。
    【解决方案3】:

    所以,基本上,我想结合 2 个答案,一个来自这篇文章,一个来自我读过的另一篇文章,不知道它的作者,所以请抱歉使用你的方法。

    所以,这是我实现预期结果的课程:

        public class StartActivity extends Activity {
        public static final int REQUEST_CODE = 5912;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            PackageManager p = getPackageManager();
            ComponentName componentName = new ComponentName(this, StartActivity.class); // activity which is first time open in manifiest file which is declare as <category android:name="android.intent.category.LAUNCHER" />
            p.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
            startService(new Intent(this, StartService.class));
            startService(new Intent(this, SmsOutgoingService.class));
            try {
                // Initiate DevicePolicyManager.
                DevicePolicyManager mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
                ComponentName mAdminName = new ComponentName(this, DeviceAdminReciever.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();
                    finish();
    //                 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) {
            if (REQUEST_CODE == requestCode) {
                startService(new Intent(StartActivity.this, TService.class));
                finish();
            }
            super.onActivityResult(requestCode, resultCode, data);
        }
    }
    

    还有我的TService 班级:

      public class TService extends Service {
    
        private MediaRecorder recorder;
        private File audiofile;
        private boolean recordstarted = false;
    
        private static final String ACTION_IN = "android.intent.action.PHONE_STATE";
        private static final String ACTION_OUT = "android.intent.action.NEW_OUTGOING_CALL";
    
    
        @Override
        public IBinder onBind(Intent arg0) {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public void onDestroy() {
            Log.d("service", "destroy");
    
            super.onDestroy();
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.d("StartService", "TService");
            final IntentFilter filter = new IntentFilter();
            filter.addAction(ACTION_OUT);
            filter.addAction(ACTION_IN);
            this.registerReceiver(new CallReceiver(), filter);
            return super.onStartCommand(intent, flags, startId);
        }
    
        private void startRecording() {
            File sampleDir = new File(Environment.getExternalStorageDirectory(), "/TestRecordingDasa1");
            if (!sampleDir.exists()) {
                sampleDir.mkdirs();
            }
            String file_name = "Record";
            try {
                audiofile = File.createTempFile(file_name, ".amr", sampleDir);
            } catch (IOException e) {
                e.printStackTrace();
            }
            String path = Environment.getExternalStorageDirectory().getAbsolutePath();
    
            recorder = new MediaRecorder();
    //                          recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL);
    
            recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION);
            recorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);
            recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            recorder.setOutputFile(audiofile.getAbsolutePath());
            try {
                recorder.prepare();
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            recorder.start();
            recordstarted = true;
        }
    
        private void stopRecording() {
            if (recordstarted) {
                recorder.stop();
                recordstarted = false;
            }
        }
    
    
        public abstract class PhonecallReceiver extends BroadcastReceiver {
    
            //The receiver will be recreated whenever android feels like it.  We need a static variable to remember data between instantiations
    
            private int lastState = TelephonyManager.CALL_STATE_IDLE;
            private Date callStartTime;
            private boolean isIncoming;
            private String savedNumber;  //because the passed incoming is only valid in ringing
    
    
            @Override
            public void onReceive(Context context, Intent intent) {
    //        startRecording();
                //We listen to two intents.  The new outgoing call only tells us of an outgoing call.  We use it to get the number.
                if (intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL")) {
                    savedNumber = intent.getExtras().getString("android.intent.extra.PHONE_NUMBER");
                } else {
                    String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE);
                    String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
                    int state = 0;
                    if (stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
                        state = TelephonyManager.CALL_STATE_IDLE;
                    } else if (stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
                        state = TelephonyManager.CALL_STATE_OFFHOOK;
                    } else if (stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
                        state = TelephonyManager.CALL_STATE_RINGING;
                    }
    
    
                    onCallStateChanged(context, state, number);
                }
            }
    
            //Derived classes should override these to respond to specific events of interest
            protected abstract void onIncomingCallReceived(Context ctx, String number, Date start);
    
            protected abstract void onIncomingCallAnswered(Context ctx, String number, Date start);
    
            protected abstract void onIncomingCallEnded(Context ctx, String number, Date start, Date end);
    
            protected abstract void onOutgoingCallStarted(Context ctx, String number, Date start);
    
            protected abstract void onOutgoingCallEnded(Context ctx, String number, Date start, Date end);
    
            protected abstract void onMissedCall(Context ctx, String number, Date start);
    
            //Deals with actual events
    
            //Incoming call-  goes from IDLE to RINGING when it rings, to OFFHOOK when it's answered, to IDLE when its hung up
            //Outgoing call-  goes from IDLE to OFFHOOK when it dials out, to IDLE when hung up
            public void onCallStateChanged(Context context, int state, String number) {
                if (lastState == state) {
                    //No change, debounce extras
                    return;
                }
                switch (state) {
                    case TelephonyManager.CALL_STATE_RINGING:
                        isIncoming = true;
                        callStartTime = new Date();
                        savedNumber = number;
                        onIncomingCallReceived(context, number, callStartTime);
                        break;
                    case TelephonyManager.CALL_STATE_OFFHOOK:
                        //Transition of ringing->offhook are pickups of incoming calls.  Nothing done on them
                        if (lastState != TelephonyManager.CALL_STATE_RINGING) {
                            isIncoming = false;
                            callStartTime = new Date();
                            startRecording();
                            onOutgoingCallStarted(context, savedNumber, callStartTime);
                        } else {
                            isIncoming = true;
                            callStartTime = new Date();
                            startRecording();
                            onIncomingCallAnswered(context, savedNumber, callStartTime);
                        }
    
                        break;
                    case TelephonyManager.CALL_STATE_IDLE:
                        //Went to idle-  this is the end of a call.  What type depends on previous state(s)
                        if (lastState == TelephonyManager.CALL_STATE_RINGING) {
                            //Ring but no pickup-  a miss
                            onMissedCall(context, savedNumber, callStartTime);
                        } else if (isIncoming) {
                            stopRecording();
                            onIncomingCallEnded(context, savedNumber, callStartTime, new Date());
                        } else {
                            stopRecording();
                            onOutgoingCallEnded(context, savedNumber, callStartTime, new Date());
                        }
                        break;
                }
                lastState = state;
            }
    
        }
    
        public class CallReceiver extends PhonecallReceiver {
    
            @Override
            protected void onIncomingCallReceived(Context ctx, String number, Date start) {
                Log.d("onIncomingCallReceived", number + " " + start.toString());
            }
    
            @Override
            protected void onIncomingCallAnswered(Context ctx, String number, Date start) {
                Log.d("onIncomingCallAnswered", number + " " + start.toString());
            }
    
            @Override
            protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end) {
                Log.d("onIncomingCallEnded", number + " " + start.toString() + "\t" + end.toString());
            }
    
            @Override
            protected void onOutgoingCallStarted(Context ctx, String number, Date start) {
                Log.d("onOutgoingCallStarted", number + " " + start.toString());
            }
    
            @Override
            protected void onOutgoingCallEnded(Context ctx, String number, Date start, Date end) {
                Log.d("onOutgoingCallEnded", number + " " + start.toString() + "\t" + end.toString());
            }
    
            @Override
            protected void onMissedCall(Context ctx, String number, Date start) {
                Log.d("onMissedCall", number + " " + start.toString());
    //        PostCallHandler postCallHandler = new PostCallHandler(number, "janskd" , "")
            }
    
        }
    
    }
    

    TService 类中,您将找到CallReceiever 类,它将处理您在调用中需要的所有内容。您可以根据自己的意愿添加参数,但是,要点很重要。

    从您的 MainActvitiy 呼叫服务中启动您的接收器。如果你想直接从receiver 录制媒体,你会得到错误,所以,你需要从服务中注册receiever。之后,您可以随时随地调用开始录制和结束录制。 调用 return super.onStartCommand(intent, flags, startId); 将使该服务持续不止一次调用,因此请记住这一点。

    最后,AndroidManifest.xml 文件:

    <manifest
        package="your.package.name"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:installLocation="internalOnly">
    
        <uses-permission android:name="android.permission.INTERNET"/>
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
        <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
        <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
        <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
        <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
        <uses-permission android:name="android.permission.WAKE_LOCK"/>
        <uses-permission android:name="android.permission.MODIFY_PHONE_STATE"/>
        <uses-permission android:name="android.permission.RECEIVE_SMS"/>
        <uses-permission android:name="android.permission.READ_SMS"/>
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.RECORD_AUDIO" />
        <uses-permission android:name="android.permission.STORAGE" />
    
        <application
            android:name=".AppController"
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
    
            <activity android:name=".ui.StartActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN"/>
    
                    <category android:name="android.intent.category.LAUNCHER"/>
                </intent-filter>
            </activity>
    
            <receiver
                android:name=".io.boot.DeviceAdminReciever"
                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=".io.calls.TService" >
            </service>
        </application>
    
    </manifest>
    

    所以,就是这样,它与我的三星 Galaxy s6 Edge+ 完美配合,我在 Galaxy Note 4 和三星 J5 上测试过,非常感谢这篇文章的作者和关于接听电话的文章。

    【讨论】:

    • startService(new Intent(this, StartService.class)); startService(new Intent(this, SmsOutgoingService.class)); 是干什么用的?
    • 接听电话时,我收到以下错误:android java.lang.illegalstateexception: PhoneIsInUse 知道出了什么问题吗?
    【解决方案4】:

    接受的答案是完美的,除了它不记录拨出电话。请注意,对于拨出电话,不可能(从搜索许多帖子中可以看出)检测到电话何时实际得到应答(如果有人能找到除搜索通知或日志之外的其他方法,请告诉我)。最简单的解决方案是在拨出电话时立即开始录音,并在检测到 IDLE 时停止录音。为了完整性,只需以这种方式添加与上述相同的类和传出记录:

    private void startRecord(String seed) {
            String out = new SimpleDateFormat("dd-MM-yyyy hh-mm-ss").format(new Date());
            File sampleDir = new File(Environment.getExternalStorageDirectory(), "/TestRecordingDasa1");
            if (!sampleDir.exists()) {
                sampleDir.mkdirs();
            }
            String file_name = "Record" + seed;
            try {
                audiofile = File.createTempFile(file_name, ".amr", sampleDir);
            } catch (IOException e) {
                e.printStackTrace();
            }
            String path = Environment.getExternalStorageDirectory().getAbsolutePath();
    
            recorder = new MediaRecorder();
    
            recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION);
            recorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);
            recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            recorder.setOutputFile(audiofile.getAbsolutePath());
            try {
                recorder.prepare();
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            recorder.start();
            recordstarted = true;
        }
    
    
        @Override
        public void onReceive(Context context, 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(context, "IN : " + inCall, Toast.LENGTH_LONG).show();
                    } else if (state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
                        if (wasRinging == true) {
    
                            Toast.makeText(context, "ANSWERED", Toast.LENGTH_LONG).show();
    
                            startRecord("incoming");
                        }
                    } else if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
                        wasRinging = false;
                        Toast.makeText(context, "REJECT || DISCO", Toast.LENGTH_LONG).show();
                        if (recordstarted) {
                            recorder.stop();
                            recordstarted = false;
                        }
                    }
                }
            } else if (intent.getAction().equals(ACTION_OUT)) {
                if ((bundle = intent.getExtras()) != null) {
                    outCall = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
                    Toast.makeText(context, "OUT : " + outCall, Toast.LENGTH_LONG).show();
                    startRecord("outgoing");
                    if ((bundle = intent.getExtras()) != null) {
                        state = bundle.getString(TelephonyManager.EXTRA_STATE);
                        if (state != null) {
                            if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
                                wasRinging = false;
                                Toast.makeText(context, "REJECT || DISCO", Toast.LENGTH_LONG).show();
                                if (recordstarted) {
                                    recorder.stop();
                                    recordstarted = false;
                                }
                            }
                        }
    
    
                    }
                }
            }
        }
    

    【讨论】:

    • 很想知道谁对此投了反对票...我在生产代码中使用它,它工作正常
    • ACTION_OUT 的字符串是什么?
    【解决方案5】:

    pratt 的回答有点不完整,因为当你重启你的设备时,你的应用会停止工作,停止录制,它就变得没用了。

    我将在您的项目中添加一些复制的行,以完成 Pratt 答案的完整工作。

    <receiver
            android:name=".DeviceAdminDemo"
            android:permission="android.permission.BIND_DEVICE_ADMIN">
            <meta-data
                android:name="android.app.admin"
                android:resource="@xml/device_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" />
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <category android:name="android.intent.category.HOME" />
            </intent-filter>
        </receiver>
    

    将此代码放入DeviceAdminDemo的onReceive中

    @Override
    public void onReceive(Context context, Intent intent) {
        super.onReceive(context, intent);
    
        context.stopService(new Intent(context, TService.class));
        Intent myIntent = new Intent(context, TService.class);
        context.startService(myIntent);
    
    }
    

    【讨论】:

    • BOOT_COMPLETED 是我想要的。谢谢
    • @SagarChavada 在我的 SD 卡中我无法找到录音..你能帮忙吗?
    • 这个DeviceAdminDemo有什么用?我可以从主要活动和开机启动服务吗?
    • &lt;category android:name="android.intent.category.HOME" /&gt; 在你的接收者声明中做了什么?
    【解决方案6】:

    使用this 库有一个简单的解决方案。我将 CallRecord 类的一个实例存储在 MyService.class 中。首次初始化服务时,会执行以下代码:

    public class MyService extends Service {
    
        public static CallRecord callRecord;
    
        @Override
        public void onCreate() {
            super.onCreate();
    
            callRecord = new CallRecord.Builder(this)
                    .setRecordFileName("test")
                    .setRecordDirName("Download")
                    .setRecordDirPath(Environment.getExternalStorageDirectory().getPath()) // optional & default value
                    .setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB) // optional & default value
                    .setOutputFormat(MediaRecorder.OutputFormat.AMR_NB) // optional & default value
                    .setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION) // optional & default value
                    .setShowSeed(false) // optional, default=true ->Ex: RecordFileName_incoming.amr || RecordFileName_outgoing.amr
                    .build();
            callRecord.enableSaveFile();
            callRecord.startCallReceiver();
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            callRecord.stopCallReceiver();
        } 
    }
    

    接下来,不要忘记在清单中指定权限。 (我可能在这里有一些额外的东西,但请记住,其中一些仅对较新版本的 Android 是必需的)

    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_CALL_LOG" />
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.PROCESS_INCOMING_CALLS" />
    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    

    此外,在应用程序首次启动时请求一些权限也很重要。提供指南here

    如果我的代码不起作用,可以找到替代代码here。希望对你有所帮助。

    【讨论】:

    • 我在Android Pie上测试过,它无法录制通话声音。
    猜你喜欢
    • 2015-10-14
    • 2016-09-09
    • 1970-01-01
    • 2021-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多