I am building an application in andr开发者_Go百科oid, which will perform an action when any phone call will come in my phone. I have tried this with broadcast receiver and phone state listener. But it is not working. If i use activity then phone state listener works well and good but it is not working with Broadcast receiver. What i am doing wrong? Please any body help....
Thanks & Regards
Here is an example from a Chinese BBS.
public class PhoneStatReceiver extends BroadcastReceiver{
private static final String TAG = "PhoneStatReceiver";
private static boolean incomingFlag = false;
private static String incoming_number = null;
@Override
public void onReceive(Context context, Intent intent) {
//如果是拨打电话
if(intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)){
incomingFlag = false;
String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Log.i(TAG, "call OUT:"+phoneNumber);
}else{
//如果是来电
TelephonyManager tm =
(TelephonyManager)context.getSystemService(Service.TELEPHONY_SERVICE);
switch (tm.getCallState()) {
case TelephonyManager.CALL_STATE_RINGING:
incomingFlag = true;//标识当前是来电
incoming_number = intent.getStringExtra("incoming_number");
Log.i(TAG, "RINGING :"+ incoming_number);
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
if(incomingFlag){
Log.i(TAG, "incoming ACCEPT :"+ incoming_number);
}
break;
case TelephonyManager.CALL_STATE_IDLE:
if(incomingFlag){
Log.i(TAG, "incoming IDLE");
}
break;
}
}
}
}
Register it in your AndroidManifest.xml
.
<receiver android:name=".filter.PhoneStatReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE"/>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"></uses-permission>
You can find some base code for that in this posts:
how do i retrieve the incoming phone call's number while ringing and store it in a variable in android?
How to block calls in android
<receiver android:name="ClassName">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE">/action>
</intent-filter>
</receiver>
Its working!!
I have read here https://gist.github.com/ftvs/e61ccb039f511eb288ee
It works fine for me. Android version 5.0.
My task had consisted next.
My application must observer all calls events. And distinguish incoming, outgoing calls. Any time when the incoming call has finished it must create the new outgoing call. Phone number specified in settings number. This phone number is the number of gate controller. (https://www.pal-es.com/3g-eng) It is cheating for opening automatic gates for users, not in the whitelist. This application works into a standalone smartphone and is used decided for this task only.
And some features you can find here too.
For example:
- how update textView value from Runnable thread
- I make outgoing call not from BroadcastReceiver class, because it impossible. It need make from MainActivity. Havy fun))) Try it.
MainActivity.java
package com.example.root.test02;
import android.content.Intent;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import java.text.SimpleDateFormat;
import java.util.Date;
/*
https://androidexample.com/Introduction_To_Broadcast_Receiver_Basics/index.php?view=article_discription&aid=60&aaid=85
https://androidexample.com/Incomming_Phone_Call_Broadcast_Receiver__-_Android_Example/index.php?view=article_discription&aid=61
https://stackoverflow.com/questions/5990590/how-to-detect-phone-call-broadcast-receiver-in-android
https://stackoverflow.com/questions/1083527/how-to-block-calls-in-android
https://stackoverflow.com/questions/5571249/how-do-i-retrieve-the-incoming-phone-calls-number-while-ringing-and-store-it-in
https://gist.github.com/ftvs/e61ccb039f511eb288ee
*/
public class MainActivity extends AppCompatActivity {
public TextView textView;
public String MetallurgTelNumber = "+79091112233"; // need redirect calls to this phone number
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
PhonecallReceiver rv = new PhonecallReceiver();
Thread myThread = new Thread(myRunnable);
myThread.start();
textView = (TextView) findViewById(R.id.incoming_calls_log);
textView.setText("Журнал входящих звонков:");
TextView version = (TextView) findViewById(R.id.tvVersion);
version.setText("v3.0");
}
public void CallToMetallurgGates()
{
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:" + MetallurgTelNumber));
startActivity(callIntent);
}
Runnable myRunnable = new Runnable() {
@Override
public void run()
{
while (true)
{
try
{
Thread.sleep(50); // Waits for 1 second (1000 milliseconds)
if (MyProperties.getInstance().NewIncomingCall)
{
CallToMetallurgGates();
MyProperties.getInstance().NewIncomingCall = false;
MyProperties.getInstance().CallId++;
String dbg_str = Integer.toString(MyProperties.getInstance().CallId) + " " + MyProperties.getInstance().PhoneNumber;
textView.post(new Runnable() {
public void run() {
SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss");
String currentDateandTime = sdf.format(new Date());
textView.append("\n" + currentDateandTime);
textView.append("\n(" + Integer.toString(MyProperties.getInstance().CallId) + "): " + MyProperties.getInstance().PhoneNumber);
textView.append("\nЗвоню на ворота: " + MetallurgTelNumber);
}
});
Thread.sleep(5000); // Waits for 1 second (1000 milliseconds)
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
}
PhonecallReceiver.java
package com.example.root.test02;
import java.util.Date;
import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import java.util.Date;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import com.example.root.test02.MainActivity;
public class PhonecallReceiver extends BroadcastReceiver {
// как только происходит входящий звонок
protected void onIncomingCallStarted(Context ctx, String number, Date start) {
Log.d("onIncomingCallStarted",number);
}
// как только снимается (hook off) трубка и делается исходящий
protected void onOutgoingCallStarted(Context ctx, String number, Date start) {
Log.d("onOutgoingCallStarted",number);
}
// когда нажимается кнопка Завершить на входящем звонке
protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end) {
Log.d("onIncomingCallEnded",number);
MyProperties.getInstance().NewIncomingCall = true;
MyProperties.getInstance().PhoneNumber = number + " завершенный";
}
// когда нажимается кнопка Завершить на исходящем звонке
protected void onOutgoingCallEnded(Context ctx, String number, Date start, Date end) {
Log.d("onOutgoingCallEnded",number);
}
// когда не сняли трубку при входящем звонке (пропуск звонка)
protected void onMissedCall(Context ctx, String number, Date start) {
MyProperties.getInstance().NewIncomingCall = true;
MyProperties.getInstance().PhoneNumber = number + " пропущенный";
}
//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;
onIncomingCallStarted(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);
}
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;
}
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
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);
}
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.root.test02">
**<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<uses-permission android:name="android.permission.CALL_PHONE" />**
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.Light">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
**<receiver android:name="com.example.root.test02.PhonecallReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>**
</application>
</manifest>
MyProperties.java
package com.example.root.test02;
public class MyProperties {
private static MyProperties mInstance= null;
public boolean NewIncomingCall = false;
public int CallId = 0;
public String PhoneNumber = "";
protected MyProperties(){}
public static synchronized MyProperties getInstance() {
if(null == mInstance){
mInstance = new MyProperties();
}
return mInstance;
}
}
Hopefully this will serve your purpose,
Please check this out.
<receiver android:name="ClassName">
<intent-filter>
<action android:name="android.intent.action.ANSWER">/action>
</intent-filter>
</receiver>
I experienced the same thing initially but then i add the following permission to my manifest.
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
of-course in my code i was just displaying a toast when i got a call. So, you'll probably have to add other permissions corresponding to your requirement.
精彩评论