I have a service that records phone calls when triggered by telephony broadcast events. When the phone is unlocked the service beautifully records the phone calls, however when the phone is locked the service stops recording calls. Are there any considerations I need to take into account when the phone is locked? I am testing and a Samsung device running KitKat.
public class CallRecorderService extends Service {
public static boolean RUNNING = false;
private final static String AUDIO_EXT = ".3gpp";
private MediaRecorder mMediaRecorder;
private boolean mRecording;
private Store mStore;
@Override
public void onCreate() {
super.onCreate();
mStore = new Store(this);
RUNNING = true;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
intentFilter.addAction(Intent.ACTION_NEW_OUTGOING_CALL);
CallBroadcastReceiver cbr = new CallBroadcastReceiver();
registerReceiver(cbr, intentFilter);
return START_STICKY;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
private class CallBroadcastReceiver extends AbstractCallReceiver {
private SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyyMMddHHmmss");
private String mOutputFileName;
private void persist(String fileName, String phoneNumber, Date startTime, Date endTime, Call.CallDirection callDirection) {
Call call = new Call();
call.setAudioFileName(mOutputFileName);
call.setPhoneNumber(phoneNumber);
call.setStartDateTime(startTime);
call.setEndDateTime(endTime);
call.setCallDirection(callDirection);
mStore.add(call);
mStore.save();
}
@Override
protected void onIncomingCallStarted(Context context, String phoneNumber, Date startTime) {
startRecording(startTime, phoneNumber);
Intent intent = new Intent(IntentUtil.ACTION_INCOMING_CALL_STARTED);
intent.putExtra(IntentUtil.EXTRA_FILE_NAME, mOutputFileName);
intent.putExtra(IntentUtil.EXTRA_PHONE_NUMBER, phoneNumber);
intent.putExtra(IntentUtil.EXTRA_START_TIME, startTime);
sendBroadcast(intent);
}
@Override
protected void onIncomingCallEnded(Context context, String phoneNumber, Date startTime, Date endTime) {
stopRecording();
persist(mOutputFileName, phoneNumber, startTime, endTime, Call.CallDirection.INCOMING);
Intent intent = new Intent(IntentUtil.ACTION_INCOMING_CALL_ENDED);
intent.putExtra(IntentUtil.EXTRA_FILE_NAME, mOutputFileName);
intent.putExtra(IntentUtil.EXTRA_PHONE_NUMBER, phoneNumber);
intent.putExtra(IntentUtil.EXTRA_START_TIME, startTime);
intent.putExtra(IntentUtil.EXTRA_END_TIME, endTime);
sendBroadcast(intent);
}
@Override
protected void onOutgoingCallStarted(Context context, String phoneNumber, Date startTime) {
startRecording(startTime, phoneNumber);
Intent intent = new Intent(IntentUtil.ACTION_OUTGOING_CALL_STARTED);
intent.putExtra(IntentUtil.EXTRA_FILE_NAME, mOutputFileName);
intent.putExtra(IntentUtil.EXTRA_PHONE_NUMBER, phoneNumber);
intent.putExtra(IntentUtil.EXTRA_START_TIME, startTime);
sendBroadcast(intent);
}
@Override
protected void onOutgoingCallEnded(Context context, String phoneNumber, Date startTime, Date endTime) {
stopRecording();
persist(mOutputFileName, phoneNumber, startTime, endTime, Call.CallDirection.OUTGOING);
Intent intent = new Intent(IntentUtil.ACTION_OUTGOING_CALL_ENDED);
intent.putExtra(IntentUtil.EXTRA_FILE_NAME, mOutputFileName);
intent.putExtra(IntentUtil.EXTRA_PHONE_NUMBER, phoneNumber);
intent.putExtra(IntentUtil.EXTRA_START_TIME, startTime);
intent.putExtra(IntentUtil.EXTRA_END_TIME, endTime);
sendBroadcast(intent);
}
public void startRecording(Date startTime, String phoneNumber) {
if (mRecording) {
return;
}
try {
mMediaRecorder = new MediaRecorder();
//TODO Research Sumsung specific audio source.
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mMediaRecorder.setOutputFile(getRecordingPath(startTime));
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mMediaRecorder.prepare();
mMediaRecorder.start();
mRecording = true;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void stopRecording() {
if (!mRecording) {
return;
}
mMediaRecorder.stop();
mMediaRecorder.reset();
mMediaRecorder.release();
mRecording = false;
}
public String getRecordingPath(Date startTime) {
mOutputFileName = dateFormatter.format(startTime) + AUDIO_EXT;
return new File(mStore.getAudioDir(), mOutputFileName).getAbsolutePath();
}
}
}
public class AbstractCallReceiver extends BroadcastReceiver {
private String mPhoneNumber;
private Context mContext;
private int mLastState = TelephonyManager.CALL_STATE_IDLE;
private boolean mIsIncoming;
private Date mCallStartTime;
private Date mCallEndTime;
private Store mStore;
@Override
public void onReceive(Context context, Intent intent) {
mContext = context;
/**
* Two broadcast events are sent because we are registered for both READ_PHONE_STATE and
* READ_CALL_LOG. We can ignore one of the events by testing if EXTRA_INCOMING_NUMBER
* is not set in the intent.
*/
if (intent.hasExtra(TelephonyManager.EXTRA_STATE) && !intent.hasExtra(TelephonyManager.EXTRA_INCOMING_NUMBER)) {
return;
}
String action = intent.getAction();
switch (action) {
case Intent.ACTION_NEW_OUTGOING_CALL:
mPhoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
break;
case TelephonyManager.ACTION_PHONE_STATE_CHANGED:
int state = 0;
String stateStr = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
mPhoneNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
if (stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
state = TelephonyManager.CALL_STATE_RINGING;
} else 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;
}
onCallStateChanged(state);
break;
}
}
private void onCallStateChanged(int state) {
if (state == mLastState) {
return;
}
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
mIsIncoming = true;
mCallStartTime = new Date();
onIncomingCallStarted(mContext, mPhoneNumber, mCallStartTime);
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
if (mLastState != TelephonyManager.CALL_STATE_RINGING) {
mIsIncoming = false;
mCallStartTime = new Date();
onOutgoingCallStarted(mContext, mPhoneNumber, mCallStartTime);
}
break;
case TelephonyManager.CALL_STATE_IDLE:
if (mLastState == TelephonyManager.CALL_STATE_RINGING) {
onMissedCall(mContext, mPhoneNumber, mCallStartTime);
} else if (mIsIncoming) {
mCallEndTime = new Date();
onIncomingCallEnded(mContext, mPhoneNumber, mCallStartTime, mCallEndTime);
} else {
mCallEndTime = new Date();
onOutgoingCallEnded(mContext, mPhoneNumber, mCallStartTime, mCallEndTime);
}
break;
}
mLastState = state;
}
protected void onIncomingCallStarted(Context context, String phoneNumber, Date startTime) {
}
protected void onOutgoingCallStarted(Context context, String phoneNumber, Date startTime) {
}
protected void onIncomingCallEnded(Context context, String phoneNumber, Date startTime, Date endTime) {
}
protected void onOutgoingCallEnded(Context context, String phoneNumber, Date startTime, Date endTime) {
}
protected void onMissedCall(Context context, String phoneNumber, Date startTime) {
}
}
from Service not receiving broadcast messages when the phone is locked
No comments:
Post a Comment