如何在Android设备中检测来电?
我正在尝试制作一个应用程序,例如,当电话打到电话上时,我想检测电话号码。 下面是我试过的,但是没有检测到来电。
我想在后台运行我的MainActivity
,我该怎么做?
我已经在manifest
文件中给予了许可。
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
还有什么我应该提供清单?
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.test_layout); } public class myPhoneStateChangeListener extends PhoneStateListener { @Override public void onCallStateChanged(int state, String incomingNumber) { super.onCallStateChanged(state, incomingNumber); if (state == TelephonyManager.CALL_STATE_RINGING) { String phoneNumber = incomingNumber; } } } }
这是我用来做到这一点:
表现:
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/> <!--This part is inside the application--> <receiver android:name=".CallReceiver" > <intent-filter> <action android:name="android.intent.action.PHONE_STATE" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.NEW_OUTGOING_CALL" /> </intent-filter> </receiver>
我的基地可重复使用呼叫检测器
package com.gabesechan.android.reusable.receivers; import java.util.Date; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.telephony.TelephonyManager; 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 static int lastState = TelephonyManager.CALL_STATE_IDLE; private static Date callStartTime; private static boolean isIncoming; private static String savedNumber; //because the passed incoming is only valid in ringing @Override public void onReceive(Context context, Intent intent) { //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(); onOutgoingCallStarted(context, savedNumber, callStartTime); } else { isIncoming = true; callStartTime = new Date(); 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){ onIncomingCallEnded(context, savedNumber, callStartTime, new Date()); } else{ onOutgoingCallEnded(context, savedNumber, callStartTime, new Date()); } break; } lastState = state; } }
然后使用它,只需从它派生一个类,并实现一些简单的函数,无论你关心哪种类型的函数:
public class CallReceiver extends PhonecallReceiver { @Override protected void onIncomingCallReceived(Context ctx, String number, Date start) { // } @Override protected void onIncomingCallAnswered(Context ctx, String number, Date start) { // } @Override protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end) { // } @Override protected void onOutgoingCallStarted(Context ctx, String number, Date start) { // } @Override protected void onOutgoingCallEnded(Context ctx, String number, Date start, Date end) { // } @Override protected void onMissedCall(Context ctx, String number, Date start) { // } }
另外,你可以看到我写的代码为什么代码就像我的博客 。 要点链接: https : //gist.github.com/ftvs/e61ccb039f511eb288ee
编辑:更新到更简单的代码,因为我已经改写了我自己使用的类
private MyPhoneStateListener phoneStateListener = new MyPhoneStateListener();
登记
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
并取消注册
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
这可能会帮助你,也添加要求permision
public class PhoneListener extends PhoneStateListener { private Context context; public static String getincomno; public PhoneListener(Context c) { Log.i("CallRecorder", "PhoneListener constructor"); context = c; } public void onCallStateChanged (int state, String incomingNumber) { if(!TextUtils.isEmpty(incomingNumber)){ // here for Outgoing number make null to get incoming number CallBroadcastReceiver.numberToCall = null; getincomno = incomingNumber; } switch (state) { case TelephonyManager.CALL_STATE_IDLE: break; case TelephonyManager.CALL_STATE_RINGING: Log.d("CallRecorder", "CALL_STATE_RINGING"); break; case TelephonyManager.CALL_STATE_OFFHOOK: break; } } }
@Gabe Sechan,感谢您的代码。 除了onOutgoingCallEnded()之外,它工作正常。 它永远不会被执行。 测试手机是三星S5和时尚。 我觉得有2个错误。
第一:一对括号丢失。
//.... 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{ // this one is missing if(isIncoming){ onIncomingCallEnded(context, savedNumber, callStartTime, new Date()); } else{ onOutgoingCallEnded(context, savedNumber, callStartTime, new Date()); } }// this one is missing break; //..
第二:如果在状态结束时,“lastState”没有被“状态”更新。 它应该被替换成这个函数的第一行
public void onCallStateChanged(Context context, int state, String number) { int lastStateTemp = lastState; lastState = state; // todo replace all the "lastState" by lastStateTemp from here. if(lastStateTemp == state){ //No change, debounce extras return; } //....
另外,我已经把“lastState”和“savedNumber”按照你的建议分成了共享首选项。
刚刚通过上述更改进行测试。 至少在我的手机上修复了问题。
这里是一个简单的方法,可以避免使用PhonestateListener和其他并发症。
所以在这里,我们正在接收来自Android的3个事件,如RINGING,OFFHOOK和IDLE。 为了获得所有可能的调用状态,我们需要定义自己的状态,如RINGING,OFFHOOK,IDLE,FIRST_CALL_RINGING,SECOND_CALL_RINGING。 它可以处理电话中的每个州。
请认为我们正在接收来自android的事件,我们将定义我们的通话状态。 看代码。
public class CallListening extends BroadcastReceiver { private static final String TAG ="broadcast_intent"; public static String incoming_number; private String current_state,previus_state,event; public static Boolean dialog= false; private Context context; private SharedPreferences sp,sp1; private SharedPreferences.Editor spEditor,spEditor1; public void onReceive(Context context, Intent intent) { //Log.d("intent_log", "Intent" + intent); dialog=true; this.context = context; event = intent.getStringExtra(TelephonyManager.EXTRA_STATE); incoming_number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER); Log.d(TAG, "The received event : "+event+", incoming_number : " + incoming_number); previus_state = getCallState(context); current_state = "IDLE"; if(incoming_number!=null){ updateIncomingNumber(incoming_number,context); }else { incoming_number=getIncomingNumber(context); } switch (event) { case "RINGING": Log.d(TAG, "State : Ringing, incoming_number : " + incoming_number); if((previus_state.equals("IDLE")) || (previus_state.equals("FIRST_CALL_RINGING"))){ current_state ="FIRST_CALL_RINGING"; } if((previus_state.equals("OFFHOOK"))||(previus_state.equals("SECOND_CALL_RINGING"))){ current_state = "SECOND_CALL_RINGING"; } break; case "OFFHOOK": Log.d(TAG, "State : offhook, incoming_number : " + incoming_number); if((previus_state.equals("IDLE")) ||(previus_state.equals("FIRST_CALL_RINGING")) || previus_state.equals("OFFHOOK")){ current_state = "OFFHOOK"; } if(previus_state.equals("SECOND_CALL_RINGING")){ current_state ="OFFHOOK"; startDialog(context); } break; case "IDLE": Log.d(TAG, "State : idle and incoming_number : " + incoming_number); if((previus_state.equals("OFFHOOK")) || (previus_state.equals("SECOND_CALL_RINGING")) || (previus_state.equals("IDLE"))){ current_state="IDLE"; } if(previus_state.equals("FIRST_CALL_RINGING")){ current_state = "IDLE"; startDialog(context); } updateIncomingNumber("no_number",context); Log.d(TAG,"stored incoming number flushed"); break; } if(!current_state.equals(previus_state)){ Log.d(TAG, "Updating state from "+previus_state +" to "+current_state); updateCallState(current_state,context); } } public void startDialog(Context context) { Log.d(TAG,"Starting Dialog box"); Intent intent1 = new Intent(context, NotifyHangup.class); intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent1); } public void updateCallState(String state,Context context){ sp = PreferenceManager.getDefaultSharedPreferences(context); spEditor = sp.edit(); spEditor.putString("call_state", state); spEditor.commit(); Log.d(TAG, "state updated"); } public void updateIncomingNumber(String inc_num,Context context){ sp = PreferenceManager.getDefaultSharedPreferences(context); spEditor = sp.edit(); spEditor.putString("inc_num", inc_num); spEditor.commit(); Log.d(TAG, "incoming number updated"); } public String getCallState(Context context){ sp1 = PreferenceManager.getDefaultSharedPreferences(context); String st =sp1.getString("call_state", "IDLE"); Log.d(TAG,"get previous state as :"+st); return st; } public String getIncomingNumber(Context context){ sp1 = PreferenceManager.getDefaultSharedPreferences(context); String st =sp1.getString("inc_num", "no_num"); Log.d(TAG,"get incoming number as :"+st); return st; } }