我需要一些帮助,我曾经多次搜索过这个问题,但我找不到解决办法, 我的问题是关于记录接听电话;让我随机强制关闭(不是所有时间)
这里是完整的我的服务
public class BiftorCallRecorderService extends Service
{
MediaRecorder recorder=new MediaRecorder();
boolean recording=false;
String CallNumber;
Boolean DEBUG=false;
Context mContext;
int AudioRecordSource;
int AudioOutFormat;
String OutFormat;
public static String OutFile;
String OutFileTime = new SimpleDateFormat("yyyy_MM_dd_HHmmss").format(Calendar.getInstance().getTime());
Boolean ShowNotification;
Boolean EnableCallRecording ,RecordMyNumbersOnly;
//All About DropBox
final static private String ACCOUNT_PREFS_NAME = "prefs";
final static private String ACCESS_KEY_NAME = "ACCESS_KEY";
final static private String ACCESS_SECRET_NAME = "ACCESS_SECRET";
final static private String APP_KEY = "wyhim4z3oa3gbb8";
final static private String APP_SECRET = "cnfg4zr2ifrq200";
static DropboxAPI<AndroidAuthSession> mApi;
/**
* calling BiftorSettings for set settings
* detect phone state
* if record my number only was enable go to find method and check the number if contain
* that number start recording if not dont start
* if the phone state is idle stop recording meaning if call end
*/
BroadcastReceiver CallRecorder=new BroadcastReceiver()
{
@Override
public void onReceive(Context arg0, Intent intent)
{
BiftorSettings();
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if(TelephonyManager.EXTRA_STATE_OFFHOOK.equals(state))
{
File Numbers_File = new File("data/data/com.Biftor.BiftorRecorderUtilities/files/Record_Number.txt");
String number=CallNumber.replaceAll("\\s+","");
if(find(Numbers_File, number) && RecordMyNumbersOnly&&recorder!=null)
BiftorStartRecording();
else if(!RecordMyNumbersOnly&&recorder!=null)
BiftorStartRecording();
}
if(TelephonyManager.EXTRA_STATE_IDLE.equals(state))
{
BiftorStopRecording();
}
if(TelephonyManager.EXTRA_STATE_RINGING.equals(state))
{
CallNumber=intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
}
}
};
/**
* getting Receive Phone number and save in
* CallNumber string
*/
BroadcastReceiver OutGoingNumDetector=new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
BiftorSettings();
CallNumber=intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
}
};
/**
* creat service and register recivers
* call the BiftorSettings
*/
@Override
public void onCreate()
{
super.onCreate();
IntentFilter RecFilter = new IntentFilter();
RecFilter.addAction("android.intent.action.PHONE_STATE");
registerReceiver(CallRecorder, RecFilter);
IntentFilter OutGoingNumFilter=new IntentFilter();
OutGoingNumFilter.addAction("android.intent.action.NEW_OUTGOING_CALL");
registerReceiver(OutGoingNumDetector, OutGoingNumFilter);
BiftorSettings();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent arg0)
{
return null;
}
/**
* destory Receivers
*/
@Override
public void onDestroy()
{
super.onDestroy();
unregisterReceiver(CallRecorder);
unregisterReceiver(OutGoingNumDetector);
}
/**
* starting recording
* if EnableCallRecording not true get out from this method
* settings recorder.setAudioSource(AudioRecordSource) from BiftorSettings
* settings output format from BiftorSettings
* make out dir from BiftorSettings
* recorder.prepare() and set the recording state true
* if recorder cant start put recorder = null the user should select other recording Audio source
* if recorder.start working fine set Isrecording=true else if recorder.start not wrok have problems
* set the Isrecording=false recording=false and set the recorder null
* if Isrecording=true send notification and show toast start recording else recording failed
*/
public void BiftorStartRecording()
{
if(!EnableCallRecording)return;
if(recording==false)
{
Boolean Isrecording;
try {
recorder.setAudioSource(AudioRecordSource);
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
OutFile= prefs.getString("Biftor_Recorder_Utilities_Dir_Picker", Environment.getExternalStorageDirectory().toString() + "/BiftorRecorder")+"/BiftorCallRecorder";
File dir= new File(OutFile);
if(!dir.exists())
dir.mkdirs();
switch (AudioOutFormat) {
case 1:
OutFormat = ".3gp";
break;
case 2:
OutFormat = ".mpg";
break;
case 3:
OutFormat = ".amr";
break;
case 4:
OutFormat = ".wav";
break;
case 5:
OutFormat = ".mp3";
break;
}
OutFile+="/"+CallNumber+ "_" + OutFileTime+ OutFormat;
recorder.setOutputFile(OutFile);
try {
recorder.prepare();
recording=true;
} catch (java.io.IOException e) {
recorder = null;
return;
}
recorder.start();
Isrecording=true;
} catch (java.lang.Exception e) {
recording=false;
Isrecording=false;
recorder = null;
}
if(Isrecording){
if(ShowNotification)
SendNotification(true);
else
SendNotification(false);
Toast.makeText(getApplicationContext(), getString(R.string.BiftorCallRecorder_Sarted) +CallNumber, Toast.LENGTH_LONG).show();
}else
Toast.makeText(getApplicationContext(), getString(R.string.Recording) +getString(R.string.failed), Toast.LENGTH_LONG).show();
}
}
/**
* Stop Recording and check out file method
* and remove Notification
* and send the BroadcastIntent
* if recording have problem recording is false and put the recorder empty
* relase,rest and stop the recorder at last put to null if recording is true
* if EnableCallRecording is not true get out from this method
*/
public void BiftorStopRecording()
{
if(!EnableCallRecording)return;
if(recording==true)
{
if(recorder!=null){ //add this check
recorder.stop();
recorder.reset();
recorder.release();
recorder=null;
} //add this closing bracket too
recording=false;
SendBroadcastIntent();
SendNotification(false);
CheckOutPutFile(OutFile);
} else {
recorder=null;
recording=false;
SendNotification(false);
CheckOutPutFile(OutFile);
}
//prepare a new recorder for next call
recorder =new MediaRecorder();
}
/**
* Restart this service after end
*/
public void SendBroadcastIntent()
{
Intent intent = new Intent();
intent.setAction("com.Biftor.BiftorCallRecorder.CALRECORDER_INTENT");
sendBroadcast(intent);
}
/**
* check output file if not having zero size save that
*/
public void CheckOutPutFile(String outfile)
{
File outputfile=new File(outfile);
if (outputfile.exists()){
if(outputfile.length()<=0){
outputfile.delete();
Toast.makeText(getApplicationContext(), getString(R.string.BiftorCallRecorder_Status)+" :"+
getString(R.string.Recording)+" "+
getString(R.string.is_empty), Toast.LENGTH_LONG).show();
}else{
Toast.makeText(getApplicationContext(), getString(R.string.Record_Saved)+ OutFile, Toast.LENGTH_LONG).show();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
if(prefs.getBoolean("Biftor_DropBox_Upload_CallRecords", false)&isNetworkAvailable())
BiftorUploadToDropBox(OutFile);
}
}else
return;
}
/**
* check number is in blacklist
*/
public boolean find(File f, String searchString) {
boolean result = false;
Scanner in = null;
if(f.exists())
{
try {
in = new Scanner(new FileReader(f));
while(in.hasNextLine() && !result) {
result = in.nextLine().indexOf(searchString) >= 0;
}
}
catch(IOException e) {
e.printStackTrace();
}
finally {
try { in.close() ; } catch(Exception e) { /* ignore */ }
}
}
return result;
}
/**
* Recording Settings
*/
public void BiftorSettings() {
mContext = getApplicationContext();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
AudioRecordSource = Integer.parseInt(prefs.getString("Biftor_Audio_Record_Source", "1"));
AudioOutFormat = Integer.parseInt(prefs.getString("Biftor_Audio_Out_Format", "1"));
ShowNotification = prefs.getBoolean("Biftor_Show_Notification", true);
EnableCallRecording = prefs.getBoolean("Biftor_Enable_Call_Recording", true);
RecordMyNumbersOnly = prefs.getBoolean("Biftor_Enable_Record_My_Numbers_Only", false);
}
/**
* send ther recording state notification
*/
@SuppressWarnings("deprecation")
public void SendNotification(Boolean status)
{
Context c = getApplicationContext();
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
if (status) {
int icon = R.drawable.ic_launcher;
Notification notification = new Notification(icon, getString(R.string.Recording)+CallNumber+getString(R.string.call), System.currentTimeMillis());
CharSequence contentTitle = getString(R.string.BiftorCallRecorder_Status);
CharSequence contentText = getString(R.string.Recording) +CallNumber+getString(R.string.call);
Intent notificationIntent = new Intent(this, BiftorCallRecorderSettings.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(c, contentTitle, contentText, contentIntent);
mNotificationManager.notify(1, notification);
} else {
mNotificationManager.cancel(1);
}
}
/**
* Upload Recorders to user dropbox after end
*/
public void BiftorUploadToDropBox(String outFile) {
AndroidAuthSession session = buildSession();
mApi = new DropboxAPI<AndroidAuthSession>(session);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
File file=new File(outFile);
if(file.exists()){
String Dropboxfolder ="/"+prefs.getString("DropBox_User_CallRecorder_Folder", "")+"/";
BiftorAutoUploadCallsToDropbox upload = new BiftorAutoUploadCallsToDropbox(getApplicationContext(), mApi, Dropboxfolder, file);
upload.execute();
}
else
return;
}
/**
* Shows keeping the access keys returned from Trusted Authenticator in a local
* store, rather than storing user name & password, and re-authenticating each
* time (which is not to be done, ever).
*/
public void loadAuth(AndroidAuthSession session) {
SharedPreferences prefs = getApplicationContext().getSharedPreferences(ACCOUNT_PREFS_NAME, 0);
String key = prefs.getString(ACCESS_KEY_NAME, null);
String secret = prefs.getString(ACCESS_SECRET_NAME, null);
if (key == null || secret == null || key.length() == 0 || secret.length() == 0) return;
if (key.equals("oauth2:")) {
// If the key is set to "oauth2:", then we can assume the token is for OAuth 2.
session.setOAuth2AccessToken(secret);
} else {
// Still support using old OAuth 1 tokens.
session.setAccessTokenPair(new AccessTokenPair(key, secret));
}
}
/**
* Upload Recorders to user dropbox after end
*/
public AndroidAuthSession buildSession() {
AppKeyPair appKeyPair = new AppKeyPair(APP_KEY, APP_SECRET);
AndroidAuthSession session = new AndroidAuthSession(appKeyPair);
loadAuth(session);
return session;
}
/**
* check the network
*/
public boolean isNetworkAvailable() {
ConnectivityManager connectivityManager
= (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
}
这里是接收器
public class BiftorCallRecorderReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context arg0, Intent arg1)
{
// TODO Auto-generated method stub
arg0.stopService(new Intent(arg0,BiftorCallRecorderService.class));
Intent intent=new Intent(arg0, BiftorCallRecorderService.class);
arg0.startService(intent);
// Toast.makeText(arg0, "Service BroadcastReceiver", Toast.LENGTH_SHORT).show();
}
}
这里是清单
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<service
android:name="com.Biftor.BiftorRecorderUtilities.BiftorCallRecorder.BiftorCallRecorderService"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="com.Biftor.BiftorCallRecorder.CALRECORDER_INTENT" />
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</service>
<receiver
android:name="com.Biftor.BiftorRecorderUtilities.BiftorCallRecorder.BiftorCallRecorderReceiver"
android:enabled="true"
android:exported="false" >
<intent-filter>
<action android:name="com.Biftor.BiftorCallRecorder.CALRECORDER_INTENT" />
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
最后这是我的logcat
W/BroadcastQueue(18654): Permission Denial: broadcasting Intent { act=android.intent.action.PHONE_STATE flg=0x10 (has extras) } from android (pid=19243, uid=1001) is not exported from uid 10057 due to receiver com.Biftor.BiftorRecorderUtilities/.BiftorCallRecorder.BiftorCallRecorderReceiver
E/AndroidRuntime(20713): FATAL EXCEPTION: main
E/AndroidRuntime(20713): Process: com.Biftor.BiftorRecorderUtilities, PID: 20713
E/AndroidRuntime(20713): java.lang.RuntimeException: Error receiving broadcast Intent { act=android.intent.action.PHONE_STATE flg=0x10 (has extras) } in com.Biftor.BiftorRecorderUtilities.BiftorCallRecorder.BiftorCallRecorderService$1@41db6990
E/AndroidRuntime(20713): at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:769)
E/AndroidRuntime(20713): at android.os.Handler.handleCallback(Handler.java:733)
E/AndroidRuntime(20713): at android.os.Handler.dispatchMessage(Handler.java:95)
E/AndroidRuntime(20713): at android.os.Looper.loop(Looper.java:136)
E/AndroidRuntime(20713): at android.app.ActivityThread.main(ActivityThread.java:5043)
E/AndroidRuntime(20713): at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(20713): at java.lang.reflect.Method.invoke(Method.java:515)
E/AndroidRuntime(20713): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795)
E/AndroidRuntime(20713): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:611)
E/AndroidRuntime(20713): at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime(20713): Caused by: java.lang.NullPointerException
E/AndroidRuntime(20713): at com.Biftor.BiftorRecorderUtilities.BiftorCallRecorder.BiftorCallRecorderService.BiftorStopRecording(BiftorCallRecorderService.java:282)
E/AndroidRuntime(20713): at com.Biftor.BiftorRecorderUtilities.BiftorCallRecorder.BiftorCallRecorderService$1.onReceive(BiftorCallRecorderService.java:90)
E/AndroidRuntime(20713): at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:759)
E/AndroidRuntime(20713): ... 9 more
I/ActivityManager(18654): Process com.Biftor.BiftorRecorderUtilities (pid 20713) has died.
W/ActivityManager(18654): Scheduling restart of crashed service com.Biftor.BiftorRecorderUtilities/.BiftorCallRecorder.BiftorCallRecorderService in 1000ms
I/ActivityManager(18654): Start proc com.Biftor.BiftorRecorderUtilities for service com.Biftor.BiftorRecorderUtilities/.BiftorCallRecorder.BiftorCallRecorderService: pid=21531 uid=10057 gids={50057, 1028, 1015, 1023, 3003}
请不要得到这个问题的负面率我添加了所有需要的东西:-) 抱歉英语不好。
修改
代码清理并为每种方法添加评论希望这次更好
编辑2但又错误
public class BiftorCallRecorderService extends Service
{
MediaRecorder recorder=new MediaRecorder();
boolean recording=false;
String CallNumber;
Context mContext;
String OutFormat;
public static String OutFile;
String OutFileTime = new SimpleDateFormat("yyyy_MM_dd_HHmmss").format(Calendar.getInstance().getTime());
/**
* detect phone state
* if the phone state is idle stop recording meaning if call end
*/
BroadcastReceiver CallRecorder=new BroadcastReceiver()
{
@Override
public void onReceive(Context arg0, Intent intent)
{
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if(TelephonyManager.EXTRA_STATE_OFFHOOK.equals(state)&&recorder!=null)
{
BiftorStartRecording();
}
if(TelephonyManager.EXTRA_STATE_IDLE.equals(state))
{
BiftorStopRecording();
}
if(TelephonyManager.EXTRA_STATE_RINGING.equals(state))
{
CallNumber=intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
}
}
};
/**
* getting Receive Phone number and save in
* CallNumber string
*/
BroadcastReceiver OutGoingNumDetector=new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
CallNumber=intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
}
};
/**
* creat service and register recivers
*/
@Override
public void onCreate()
{
super.onCreate();
IntentFilter RecFilter = new IntentFilter();
RecFilter.addAction("android.intent.action.PHONE_STATE");
registerReceiver(CallRecorder, RecFilter);
IntentFilter OutGoingNumFilter=new IntentFilter();
OutGoingNumFilter.addAction("android.intent.action.NEW_OUTGOING_CALL");
registerReceiver(OutGoingNumDetector, OutGoingNumFilter);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent arg0)
{
return null;
}
/**
* destory Receivers
*/
@Override
public void onDestroy()
{
super.onDestroy();
unregisterReceiver(CallRecorder);
unregisterReceiver(OutGoingNumDetector);
}
/**
* starting recording
* if EnableCallRecording not true get out from this method
* settings recorder.setAudioSource(AudioRecordSource) from BiftorSettings
* settings output format from BiftorSettings
* make out dir from BiftorSettings
* recorder.prepare() and set the recording state true
* if recorder cant start put recorder = null the user should select other recording Audio source
* if recorder.start working fine set Isrecording=true else if recorder.start not wrok have problems
* set the Isrecording=false recording=false and set the recorder null
* if Isrecording=true send notification and show toast start recording else recording failed
*/
public void BiftorStartRecording()
{
if(recording==false)
{
Boolean Isrecording;
try {
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
OutFile= Environment.getExternalStorageDirectory().toString() + "/BiftorRecorder"+"/BiftorCallRecorder";
File dir= new File(OutFile);
if(!dir.exists())
dir.mkdirs();
OutFormat = ".3gp";
OutFile+="/"+CallNumber+ "_" + OutFileTime+ OutFormat;
recorder.setOutputFile(OutFile);
try {
recorder.prepare();
recording=true;
} catch (java.io.IOException e) {
recorder = null;
return;
}
recorder.start();
Isrecording=true;
} catch (java.lang.Exception e) {
recording=false;
Isrecording=false;
recorder = null;
}
if(Isrecording){
Toast.makeText(getApplicationContext(), getString(R.string.BiftorCallRecorder_Sarted) +CallNumber, Toast.LENGTH_LONG).show();
}else
Toast.makeText(getApplicationContext(), getString(R.string.Recording) +getString(R.string.failed), Toast.LENGTH_LONG).show();
}
}
/**
* Stop Recording and check out file method
* and send the BroadcastIntent
* if recording have problem recording is false and put the recorder empty
* relase,rest and stop the recorder at last put to null if recording is true
*/
public void BiftorStopRecording()
{
if(recording==true)
{
if(recorder!=null){
recorder.stop();
recorder.reset();
recorder.release();
recorder=null;
recording=false;
SendBroadcastIntent();
CheckOutPutFile(OutFile);
}
}
else{
recorder=null;
recording=false;
CheckOutPutFile(OutFile);
}
recorder =new MediaRecorder();
}
/**
* Restart this service after end
*/
public void SendBroadcastIntent()
{
Intent intent = new Intent();
intent.setAction("com.Biftor.BiftorCallRecorder.CALRECORDER_INTENT");
sendBroadcast(intent);
}
/**
* check output file if not having zero size save that
*/
public void CheckOutPutFile(String outfile)
{
File outputfile=new File(outfile);
if (outputfile.exists()){
if(outputfile.length()<=0){
outputfile.delete();
Toast.makeText(getApplicationContext(), getString(R.string.BiftorCallRecorder_Status)+" :"+
getString(R.string.Recording)+" "+
getString(R.string.is_empty), Toast.LENGTH_LONG).show();
}else{
Toast.makeText(getApplicationContext(), getString(R.string.Record_Saved)+ OutFile, Toast.LENGTH_LONG).show();
}
}
}
}
编辑3 可能需要增加全服务类,我也从安卓市场获得了关于修正斜杠的新错误
java.lang.RuntimeException: Error receiving broadcast Intent { act=android.intent.action.PHONE_STATE flg=0x10 (has extras) } in com.Biftor.BiftorRecorderUtilities.BiftorCallRecorder.t@4169cf60
Caused by: java.lang.NullPointerException
at java.io.File.fixSlashes(File.java:185)
at java.io.File.<init>(File.java:134)
at com.Biftor.BiftorRecorderUtilities.BiftorCallRecorder.BiftorCallRecorderService.a(Unknown Source)
at com.Biftor.BiftorRecorderUtilities.BiftorCallRecorder.BiftorCallRecorderService.b(Unknown Source)
at com.Biftor.BiftorRecorderUtilities.BiftorCallRecorder.t.onReceive(Unknown Source)
at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:788)
... 9 more
感谢。
答案 0 :(得分:0)
您错过了在清单文件中添加权限:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<强> [编辑] 强>
使用MediaRecorder
的{{1}}方法移动onReceive
创建代码:
BiftorCallRecorderService
<强> [编辑++] 强>
在@Override
public void onReceive(Context arg0, Intent intent) {
recorder = new MediaRecorder();
BiftorSettings();
//Other stuffs here
}
方法中stop
之前添加延迟:
BiftorStopRecording
答案 1 :(得分:0)
您的代码不易阅读,而且有很多......所以我不确定,但似乎问题如下:
在BiftorStartRecording
中,如果由于某种原因发生异常:您设置recorder = null;
(查看BiftorStartRecording
方法的catch块)。
然后,onReceive
被调用(即您的广播收到消息):在某些条件下BiftorStopRecording
从onReceive
调用。
BiftorStopRecording
尝试在录像机上调用某些内容,但由于先前的异常,录像机现在为空。
如何解决?
希望它有所帮助。
试试这个:
public void BiftorStopRecording()
{
if(!EnableCallRecording)return;
if(recording==true)
{
if(recorder!=null){ //add this check
recorder.stop();
recorder.reset();
recorder.release();
recorder=null;
} //add this closing bracket too
recording=false;
SendBroadcastIntent();
SendNotification(false);
CheckOutPutFile(OutFile);
} else {
recorder=null;
recording=false;
SendNotification(false);
CheckOutPutFile(OutFile);
}
//prepare a new recorder for next call
recorder = =new MediaRecorder();
}