web-dev-qa-db-ja.com

Androidで通話を録音する方法は?

着信と発信を記録し、ユーザーが電話をかけるか電話をかけると自動的に実行されるアプリを作りたいです。

55
Ankit Sharma

OK、まず最初に、Device Policy Managerを使用する必要があり、デバイスを管理デバイスにする必要があります。その後、1つのBroadCastレシーバーと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>

//マニフェストで次のことを宣言します:

マニフェストに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>
90
Pratik Dasa

以下のコードは私のために働いています電話の発信を記録する

//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" />
15
Mukesh Parmar

私はこれについてコメントしたいと思いますが、その厳しい投稿です。したがって、基本的に、この投稿からの回答と私が読んだ別の投稿からの回答の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コールサービスから。受信者から直接メディアを記録したい場合はエラーが発生するため、サービスから受信者を登録する必要があります。その後、記録開始と終了を呼び出すことができます。 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>

だから、これは私のサムスンギャラクシーs6エッジ+で完璧に動作し、ギャラクシーノート4とサムスンJ5でそれをテストしました、この投稿の著者と電話の受信に関する投稿に感謝します。

9
Vulovic Vukasin

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);

}
3
Sagar Chavada

受け入れられた答えは完璧です。ただし、発信コールを記録しません。発信コールの場合、コールが実際に応答されたことを検出することはできません(多くの投稿を精査することでわかる限り)(精査通知またはログ以外の方法を見つけられる場合はお知らせください)。最も簡単な解決策は、発信コールが発信されたらすぐに録音を開始し、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;
                            }
                        }
                    }


                }
            }
        }
    }
3

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 。お役に立てば幸いです。

1
Vergeltung