Reputation: 18376
Currently I'm developing a call blocker application like Truecaller.
What I needed
I want to detect the incoming calls even my app is removed from the recent apps list.
Manifest.xml code
<receiver android:name=".PhoneStateReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
My broadcast receiver code
@Override
public void onReceive(Context context, Intent intent) {
//my call blocking code
}
My problem
My BroadcastReceiver wont work in the background as if I removed from the recent apps list.
My full manifest code here
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ranjith.callblocker">
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.GET_TASKS" />
<application
android:allowBackup="true"
android:enabled="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<receiver
android:name=".PhoneStateReceiver"
android:enabled="true"
android:exported="true"
android:process=":anotherProcess">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Should I use service or anything else?
Update:
With Suraj answer I tried this tags in my receiver
android:enabled="true"
android:exported="true"
android:process=":anotherProcess"
it works on kitkat.. but not works on lollipop..
Updated question:
Incase If not possible to keep alive broadcast receiver How can I detect incoming calls even my app is closed?
anybody give detailed answer..
Upvotes: 24
Views: 9173
Reputation: 454
You need to create a Service
and and register it in manifest. After it you should register your BroadcastReceiver
inside the service instead of manifest.
A Service
is not stopped, when app is removed from recents, so your receiver will also continue to work. You will even also get a callback via Service#onTaskRemoved
when app is removed from recents.
Though you will also need to handle some other cases, when a Service
can be stopped.
One case is when android can stop your service when system is low on memory, you can fix it by returning START_STICKY
from your onStartCommand
method.
Other case is when device is rebooted, you will need to register a broadcast receiver for ACTION_BOOT_COMPLETED
in mnifest to fix this. You can restart your service in its onReceive
method.
Hope below example code helps-
private BroadcastReceiver mReceiver;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.v(LOG_TAG, "worked");
}
};
registerReceiver(mReceiver,
new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
return START_STICKY;
}
@Override
public void onDestroy() {
unregisterReceiver(mReceiver);
super.onDestroy()
}
Upvotes: 2
Reputation: 988
Here is code It work fine for me:
In Manifest you add permission:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
Next Steps create a Service
start when start App (maybe MainActivity
)
call this code in method onCreate
of Service
Code
((TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE)).listen(new PhoneStateListener(new PhoneStateListener.PhoneCallListener() {
@Override
public void PhoneCall() {
// Do something
}
@Override
public void PhoneOff() {
// Do something
}
@Override
public void MissCall() {
// Do something
}
}), PhoneStateListener.LISTEN_CALL_STATE);
PhoneStateListener.java
import android.telephony.TelephonyManager;
/**
* PhoneStateListener.
*
* @author DaoLQ
*/
public class PhoneStateListener extends android.telephony.PhoneStateListener {
public interface PhoneCallListener {
void PhoneCall();
void PhoneOff();
void MissCall();
}
private PhoneCallListener mPhoneCallListener;
private boolean ring = false;
private boolean callReceived = false;
public PhoneStateListener(PhoneCallListener listener) {
mPhoneCallListener = listener;
}
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
mPhoneCallListener.PhoneOff();
if (ring && !callReceived) {
mPhoneCallListener.MissCall();
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
// CALL_STATE_OFFHOOK;
callReceived = true;
mPhoneCallListener.PhoneCall();
break;
case TelephonyManager.CALL_STATE_RINGING:
ring = true;
mPhoneCallListener.PhoneCall();
break;
default:
break;
}
}
}
Upvotes: 0
Reputation:
You can try register Broadcast Receiver inside on onCreate() of activity.
Upvotes: 0
Reputation: 82
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.phonestatelistener">
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<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.android.receiver.PhoneStateListener" android:exported="true" >
<intent-filter >
<action android:name="android.intent.action.PHONE_STATE"/>
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
</application>
public class PhoneStateListener extends BroadcastReceiver {
public static String TAG="PhoneStateListener";
public static String ACTION_PHONE_STATE = "android.intent.action.PHONE_STATE";
public static String ACTION_OUTGOING_CALL = "android.intent.action.NEW_OUTGOING_CALL";
public static String ACTION_SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_PHONE_STATE)) {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
Toast.makeText(context, "Incoming call", Toast.LENGTH_SHORT).show();
Log.d(TAG, "Incoming call");
}
} else if (intent.getAction().equals(ACTION_OUTGOING_CALL)) {
Toast.makeText(context, "Outgoing call", Toast.LENGTH_SHORT).show();
Log.d(TAG, "Outgoing call");
} else if (intent.getAction().equals(ACTION_SMS_RECEIVED)) {
Toast.makeText(context, "Incoming message", Toast.LENGTH_SHORT).show();
Log.d(TAG, "Incoming message");
}
}
}
Try this . It will work until you force close the application
Upvotes: 0
Reputation: 767
Here we are notifying receiver from service.
So make a service class as
public class MyService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new CountDownTimer(100000,4000)
{
@Override
public void onTick(long millisUntilFinished) {
sendBroadcast(new Intent("fromservice"));
}
@Override
public void onFinish() {
}
}.start();
return START_STICKY;
}
}
Now make a receiver as
public class MyReceiver extends WakefulBroadcastReceiver {
@Override
public void onReceive(final Context context, Intent intent) {
Toast.makeText(context, "inside receiver", Toast.LENGTH_SHORT).show();
}
}
now start the service from main activity
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService(new Intent(this,MyService.class));
}
}
Declare receiver and service in manifest as follows
<receiver android:name=".MyReceiver"
android:process=":jk"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="fromservice"/>
</intent-filter>
</receiver>
<service android:name=".MyService"
android:process=":ff"
android:enabled="true"
android:exported="true" />
Add the following permission to your manifest. This is used for preventing cpu to sleep.
<uses-permission android:name="android.permission.WAKE_LOCK"/>
What is count down timer ?
Count down timer can be understood like a iteration which has to methods
onTick() and onFinish()
onTick() is called many times after an interval (time duration) as given in CountDownTimer constructor.
onFinish() is called at last(only once) when the longTimeInFuture has aarived.
Upvotes: 5
Reputation: 2899
Here is my recipe, it actually works from 4.4 to 6.0
Manifest:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<application>
<receiver android:name=".utils.PhoneReceiver">
<intent-filter android:priority="999">
<action android:name="android.intent.action.PHONE_STATE" />
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
</application>
Then in the PhoneReceiver.class
public class PhoneReceiver extends BroadcastReceiver
{
public void onReceive(Context thecontext, Intent intent)
{
if ("android.provider.Telephony.SMS_RECEIVED".equals(intent.getAction()))
{
// handle SMS received
}
else if ("android.intent.action.NEW_OUTGOING_CALL".equals(intent.getAction()))
{
// handle outgoing call
}
else if (intent.getAction().equals("android.intent.action.PHONE_STATE"))
{
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
/* from there do your stuff... */
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING))
String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
/* etc. etc. */
}
}
}
Upvotes: -1
Reputation: 40156
You must add permission from manifest,
<uses-permission android:name="android.permission.READ_PHONE_STATE" >
And receiver must have below attributes declared, also always try to use full package name when declaring name.
<receiver
android:name="ranjith.callblocker.PhoneStateReceiver"
android:enabled="true"
android:exported="true"
android:permission="android.permission.READ_PHONE_STATE">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
Then try to put a Log inside receiver block,
@Override
public void onReceive(Context context, Intent intent) {
Log.i("TAG", "Receiver is called but might not block call for other reason!");
}
Make sure that you are not unregistering the receiver by name from any of you onPause, onStop, onDestroy methods
Upvotes: -2