MainActivity :
package com.itheima74.test
;
import android.content.Intent
;
import android.os.Bundle
;
import android.os.Environment
;
import android.support.v7.app.AppCompatActivity
;
import android.widget.Toast
;
import com.itheima74.test.service.PhoneService
;
import java.io.File
;
/**
* 挂羊头卖狗肉,实为电话监听器(来电去电自动录音),改名为省电大师,图标亦改变
*/
public class MainActivity
extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
;
setContentView(R.layout.
activity_main)
;
// 在sdcard目录下创建一个名为Recoder的文件夹,用来存放录音文件
File folder =
new File(Environment.
getExternalStorageDirectory() + File.
separator +
"Recoder")
;
if (folder.exists()) {
System.
out.println(
"Recoder的文件夹已存在")
;
}
else {
// 如果文件夹不存在,则创建
boolean mkdir = folder.mkdir()
;
if (mkdir) {
System.
out.println(
"Recoder的文件夹创建成功")
;
}
else {
System.
out.println(
"Recoder的文件夹创建失败")
;
}
}
startService(
new Intent(
this, PhoneService.
class))
;
finish()
;
Toast.
makeText(
this, "服务已开启", Toast.
LENGTH_SHORT).show()
;
}
}
PhoneService :
package com.itheima74.test.service
;
import android.app.Service
;
import android.content.Context
;
import android.content.Intent
;
import android.media.MediaRecorder
;
import android.os.IBinder
;
import android.support.annotation.Nullable;
import android.telephony.PhoneStateListener
;
import android.telephony.TelephonyManager
;
import android.widget.Toast
;
import java.io.IOException
;
import java.text.SimpleDateFormat
;
import java.util.Date
;
/**
* 来电去电监听服务
* 实现的功能:
* 1.来电 去电自动录音,保存到sd卡
* 2.来电:以来电号码及当前系统时间为文件名保存,功能OK
* 3.开机自启功能OK
* 4.来电在响铃状态自动录音,解决来电未接听软件崩溃问题
* 5.去电在接听状态自动录,未能获取去电号码,去电不经过响铃状态,对象需重新创建
* 6.去电录音改为在广播接收者中进行
* 7.在4.1及真机4.4测试,功能Ok
* 8.模拟器7.1.1崩溃,权限控制已手动开启,不知真机测试如何
* 9.存在问题:录音质量不佳,录音文件过大,来电未接听开始录
* Created by My on 2017/2/18.
*/
public class PhoneService
extends Service {
private TelephonyManager
mTm;
private MyPhoneStateListener
mPhoneStateListener;
private MediaRecorder
mRecorder;
@Nullable
@Override
public IBinder
onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate()
;
System.
out.println(
"PhoneService onCreate")
;
mTm = (TelephonyManager) getSystemService(Context.
TELEPHONY_SERVICE)
;
mPhoneStateListener =
new MyPhoneStateListener()
;
mTm.listen(
mPhoneStateListener, PhoneStateListener.
LISTEN_CALL_STATE)
;
}
private class MyPhoneStateListener
extends PhoneStateListener {
@Override
public void onCallStateChanged(
int state
, String incomingNumber) {
super.onCallStateChanged(state
, incomingNumber)
;
if (state == TelephonyManager.
CALL_STATE_IDLE) {
System.
out.println(
"空闲状态")
;
if (
mRecorder !=
null) {
mRecorder.stop()
;
mRecorder.reset()
; // You can reuse the object by going back to setAudioSource() step
mRecorder.release()
; // Now the object cannot be reused
}
}
else if (state == TelephonyManager.
CALL_STATE_RINGING) {
System.
out.println(
"响铃状态")
;
// 创建一个MediaRecorder对象
mRecorder =
new MediaRecorder()
;
mRecorder.setAudioSource(MediaRecorder.AudioSource.
MIC)
;
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.
THREE_GPP)
;
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.
AMR_NB)
;
// 将来电号码及系统当前时间作为文件名保存起来,文件名不能用中文字符,只能下划线或者小横杠
long currentTimeMillis = System.
currentTimeMillis()
;
SimpleDateFormat simpleDateFormat =
new SimpleDateFormat(
"yyyy-MM-dd_HH-mm-ss")
;
String currentTime = simpleDateFormat.format(
new Date(currentTimeMillis))
;
// mnt/sdcard/Recoder/*.3gp
String path =
"mnt/sdcard/Recoder/in" + incomingNumber +
";" + currentTime +
".3gp";
mRecorder.setOutputFile(path)
;
// 准备监听
try {
mRecorder.prepare()
;
}
catch (IOException e) {
e.printStackTrace()
;
}
// 1.来电录音,为什么要在响铃状态开始录呢?因为如果来电未接听,则软件会崩溃
mRecorder.start()
;
}
else if (state == TelephonyManager.
CALL_STATE_OFFHOOK) {
System.
out.println(
"接听状态")
;
// 2.去电录音,放在NewOutGoingCall这个类中执行,方便获知去电号码
}
}
}
@Override
public void onDestroy() {
super.onDestroy()
;
System.
out.println(
"服务已关闭")
;
Toast.
makeText(
this, "服务已关闭", Toast.
LENGTH_SHORT).show()
;
// 取消监听
mTm.listen(
mPhoneStateListener, PhoneStateListener.
LISTEN_NONE)
;
mRecorder =
null;
}
}
BootReceiver :
package com.itheima74.test.receiver
;
import android.content.BroadcastReceiver
;
import android.content.Context
;
import android.content.Intent
;
import android.widget.Toast
;
import com.itheima74.test.service.PhoneService
;
/**
* 开机广播接收者,开机自启
* Created by My on 2017/2/18.
*/
public class BootReceiver
extends BroadcastReceiver {
@Override
public void onReceive(Context context
, Intent intent) {
System.
out.println(
"PhoneListener:手机开机了...")
;
Intent intent1 =
new Intent(context
, PhoneService.
class)
;
context.startService(intent1)
;
Toast.
makeText(context
, "PhoneService服务已开启", Toast.
LENGTH_LONG).show()
;
}
}
NewOutGoingCallReceiver :
package com.itheima74.test.receiver
;
import android.content.BroadcastReceiver
;
import android.content.Context
;
import android.content.Intent
;
import android.media.MediaRecorder
;
import android.telephony.PhoneStateListener
;
import android.telephony.TelephonyManager
;
import java.io.IOException
;
import java.text.SimpleDateFormat
;
import java.util.Date
;
/**
* 外拨电话到来广播接收者
* 将去电监听录音放到此处更加合适,因去电号码可知
* 无需启动一个新的服务,尽管可以在PhoneService电话空闲状态下stop它,但仍然画蛇添足
* Created by My on 2017/2/22.
*/
public class NewOutGoingCallReceiver
extends BroadcastReceiver {
private String
mNumber;
@Override
public void onReceive(Context context
, Intent intent) {
// 获取去电电话号码
mNumber = getResultData()
;
TelephonyManager mTm = (TelephonyManager) context.getSystemService(Context.
TELEPHONY_SERVICE)
;
MyPhoneStateListener mPhoneStateListener =
new MyPhoneStateListener()
;
mTm.listen(mPhoneStateListener
, PhoneStateListener.
LISTEN_CALL_STATE)
;
}
private class MyPhoneStateListener
extends PhoneStateListener {
private MediaRecorder
mRecorder;
@Override
public void onCallStateChanged(
int state
, String incomingNumber) {
super.onCallStateChanged(state
, incomingNumber)
;
if (state == TelephonyManager.
CALL_STATE_IDLE) {
if (
mRecorder !=
null) {
mRecorder.stop()
;
mRecorder.reset()
; // You can reuse the object by going back to setAudioSource() step
mRecorder.release()
; // Now the object cannot be reused
}
}
else if (state == TelephonyManager.
CALL_STATE_RINGING) {
}
else if (state == TelephonyManager.
CALL_STATE_OFFHOOK) {
mRecorder =
new MediaRecorder()
;
mRecorder.setAudioSource(MediaRecorder.AudioSource.
MIC)
;
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.
THREE_GPP)
;
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.
AMR_NB)
;
// 将来电号码及系统当前时间作为文件名保存起来,文件名不能用中文字符,只能下划线或者小横杠
long currentTimeMillis = System.
currentTimeMillis()
;
SimpleDateFormat simpleDateFormat =
new SimpleDateFormat(
"yyyy-MM-dd_HH-mm-ss")
;
String currentTime = simpleDateFormat.format(
new Date(currentTimeMillis))
;
// mnt/sdcard/ReCoder/outGoingCall/*.3gp
String path =
"mnt/sdcard/Recoder/out" +
mNumber +
";" + currentTime +
".3gp";
mRecorder.setOutputFile(path)
;
try {
mRecorder.prepare()
;
}
catch (IOException e) {
e.printStackTrace()
;
}
mRecorder.start()
; // Recording is now started
}
}
}
}
清单文件:
xml version="1.0" encoding="utf-8"?>
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.itheima74.test">
android:name="android.permission.READ_PHONE_STATE" />
android:name="android.permission.RECORD_AUDIO" />
android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
android:name="android.permission.PROCESS_OUTGOING_CALLS" />
android:allowBackup="true"
android:icon="@drawable/shendian"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:name=".MainActivity">
android:name="android.intent.action.MAIN" />
android:name="android.intent.category.LAUNCHER" />
android:name=".service.PhoneService" />
android:name=".receiver.BootReceiver">
android:name="android.intent.action.BOOT_COMPLETED" />
android:name=".receiver.NewOutGoingCallReceiver">
android:name="android.intent.action.NEW_OUTGOING_CALL" />