24

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..

Ranjithkumar
  • 16,071
  • 12
  • 120
  • 159
  • 2
    you need your broadcast receiver to be in your background service. – Janki Gadhiya Apr 25 '16 at 05:22
  • I have the same problem :-(. Did you find out the solution @jankigadhiya. Could you please share with me :-) – vNext Sep 27 '16 at 08:30
  • Hi! any solution for this? I have the same problem on Android 6.0, Everything works fine when app is running, but if I close it from recent apps list, the receiver is stopped too – vgarzom Oct 12 '16 at 16:33
  • 2
    Solved... In my case I was testing in a device Asus Zenfone 2, this one has a preinstalled app called "Asus Mobile Manager" which was blocking the automatic start of applications, so I allowed the automatic start of my application and everything works nice. – vgarzom Oct 12 '16 at 19:41
  • @vgarzom thanks for useful info.. – Ranjithkumar Oct 13 '16 at 04:13

7 Answers7

5

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.

Suraj
  • 737
  • 6
  • 21
  • 1
    If I change this settings my broadcast receiver always keep alive ahh(even my app removed from recent app list) ? – Ranjithkumar Apr 24 '16 at 01:27
  • yes, enabled attribute means that system can instantaniate your receivwr if its killed. See the edit answer. You can place receive in another process as well – Suraj Apr 24 '16 at 05:15
  • I tried your answer but not working in my phone.. my phone android version is 5.0.2(lollipop).. this code not working in lollipop ahh? – Ranjithkumar Apr 24 '16 at 18:32
  • modify your receiver to implement wakefulbroadcastreceiver and also add wakelock permission in manifest file – Suraj Apr 25 '16 at 07:58
  • I would suggest you to make a service with START_STICKY Intent and then sending a broadcast intent to receiver from service – Suraj Apr 25 '16 at 09:08
  • I offer bounty worth 250 for this question.. If you give detailed answer I am ready to give you.. because your solution works partially (kitkat works,lollipop not works) so please give detailed answer with example – Ranjithkumar Apr 26 '16 at 04:18
  • Hi, I can provide you detailed solution. How can I contact you? – Suraj Apr 26 '16 at 04:52
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/110203/discussion-between-suraj-kumar-agrahari-and-ranjith-kumar). – Suraj Apr 26 '16 at 05:33
  • hi, I checked on android 5.0.2 and my solution works fine on it – Suraj May 13 '16 at 07:44
  • how you testing? and which app? because when I press back -> and remove from recent tasks -> it not working.. r u test with my app. – Ranjithkumar May 13 '16 at 07:46
  • if you press back -> and remove from recent tasks -> it working ahh? surely this scenario not working – Ranjithkumar May 13 '16 at 08:25
  • ok. I check that. here my service death. when I press back & remove recent app list. – Ranjithkumar May 13 '16 at 08:33
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/111879/discussion-between-suraj-kumar-agrahari-and-ranjith-kumar). – Suraj May 13 '16 at 16:07
2

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()
}
Sachin Gupta
  • 444
  • 3
  • 10
  • yes.. you are correct.. I am also create a service like this link http://stackoverflow.com/a/35915926/3879847 .. But I don`t know how to connect the broadcast receiver to service? can you help me.. my service is in that link.. my broadcast receiver is in this question.. can you connect these two classes. – Ranjithkumar May 02 '16 at 10:08
  • 1
    As far as your link is concerned, i do not think there is nay need to send a broadcast and restart service from onTaskRemoved or from onDestroy. Both can be termed as bad code practices. Actually your service will not be stopped when task is removed from recents. – Sachin Gupta May 02 '16 at 10:19
  • as per your updated answer I need to declare my broadcast receiver inside the **onStartCommand()** and also set intent filter from code.. No need my broadcast receiver in manifest ahh? – Ranjithkumar May 02 '16 at 10:23
  • sorry bro.. not working when I remove from recent tasks.. service will dead..& also receiver not called.. tested in 5.0.1 & 4.4 with real phone calls – Ranjithkumar May 02 '16 at 12:27
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/110833/discussion-between-sachin-gupta-and-ranjith-kumar). – Sachin Gupta May 02 '16 at 12:38
  • Your code seems to have some other issue because a simple service can not be dead when app is removed from recents. Hope you have not used stopWithTask attribut. It is well document since API 14. Refer link http://developer.android.com/reference/android/app/Service.html#onTaskRemoved(android.content.Intent) – Sachin Gupta May 02 '16 at 12:45
0
<?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

anoopg87
  • 82
  • 6
  • thanks for your answer.. I already included **READ_PHONE_STATE** permission & also **android:exported="true"** added. But it not working in my lollipop 5.0.2 phone.. r u see my manifest file? what you extra added & how you say it`s working? – Ranjithkumar Apr 29 '16 at 06:44
  • I am using 5.1.1 device. its working for me . if you force close the application then you wont get the notification – anoopg87 Apr 29 '16 at 07:43
  • if you remove your apps from recent tasks list.. It worked ahh? this is my requirement.. please read my qtn once again & answer please..I described what is my problem in my qtn clearly. this answer surely not solve my problem – Ranjithkumar Apr 29 '16 at 07:57
0

You can try register Broadcast Receiver inside on onCreate() of activity.

  • If I register broadcast receiver inside the onCreate() it will worked ahh? can you explain more? My requirement -> If I remove from recent tasks also my broadcast receiver keep alive.. – Ranjithkumar Apr 30 '16 at 05:42
0

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;
        }
    }
}
DaoLQ
  • 988
  • 1
  • 6
  • 13
  • Bro what is the life time of this service? If I remove app from recent tasks this service running or not? – Ranjithkumar Apr 30 '16 at 06:32
  • - You can start service from method``oncreate`` in``class App extends Application`` this service still work when remove app from recent task. - note : need declare ``App`` in ``manifest`` – DaoLQ Apr 30 '16 at 06:43
  • I am use the same all above code.. it only works for app open.. If I remove app from recent tasks public void PhoneCall() { // Do something } not getting called – Ranjithkumar May 02 '16 at 12:26
-1

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. */
        }
    }
}
JBA
  • 2,889
  • 1
  • 21
  • 38
  • r u tested after app removed from recent tasks. because my question **broadcast receiver not working after app removed from recent tasks..** – Ranjithkumar Apr 26 '16 at 06:11
  • Sure I noticed the specificity of your question. This code is actually working even if the App is removed from recent - note that it works only if the App has been launched once after install (that is true for every receivers and services...) – JBA Apr 26 '16 at 06:21
  • 1
    What I would recommend to investigate further, is to register a broadcast receiver BOOT_COMPLETE in your application : if you see it fired once the phone reboots, it means obviously that your app can receive boradcasts even if it was not already running in bg... – JBA Apr 26 '16 at 08:27
  • thanks for recommendation.. but I use same like that code above.. only one action for incoming call.. but not working when app removed from recent tasks – Ranjithkumar Apr 26 '16 at 09:06
-2

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

Sazzad Hissain Khan
  • 37,929
  • 33
  • 189
  • 256