5

I was trying to get notification trigger on my application whenever the user makes a new call. I'm registering receiver in my activity and destroying it in onDestroy() method. Following is the code snippets for registering

registerReceiver(inComingCall = new IncomingCall(),new IntentFilter("android.intent.action.PHONE_STATE"));

The issue I'm facing is I'm not getting any trigger in override onReceive() method for the Broadcast receiver. Kindly let me know whether any new implementations or the separate way I should do for receiving the broadcast especially for Oreo.

Thanks in Advance.

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
user1955126
  • 79
  • 1
  • 2
  • 5
  • 1
    have you registered for READ_PHONE_STATE permission in your manifest and requested for the permission? – Sagar Mar 30 '18 at 11:18
  • 1
    From Android O, the permission behavior is changed. Please look in to this : https://developer.android.com/about/versions/oreo/android-8.0-changes.html – Chithra B Mar 30 '18 at 11:29
  • Yes. I have added the permission but still its not working .Following is the code – user1955126 Mar 31 '18 at 13:16
  • Oreo have some restriction in Broadcast Receiver. check this blog link https://medium.com/exploring-android/exploring-background-execution-limits-on-android-oreo-ab384762a66c – Ashok Apr 15 '18 at 04:20
  • this is best solution https://github.com/devggaurav/BroadcastReceiver-For-Naught-and-Oreo-devices – Danial clarc Oct 02 '19 at 11:03

4 Answers4

9

I faced this issue for a long time. And every one will provide you a link to google developers site, which describes nothing than how they are having limits on background services; with no proper documentation and no sample code showing developers, how to implement it on Oreo or Higher. Even on stack-Overflow you will find only links to the google developers site on limitations.


I hope you or some other developer will find this very helpful.


There are still some exclusions like NEW_OUTGOING_CALL OR BOOT_COMPLETED which you can still use in manifest. But its a good practise to implement runtime at application context. I wanted my PHONE_STATE ready always for getting incoming and outgoing calls; On every reboot too...


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.rushi.boottest">

<uses-sdk
    android:minSdkVersion="16"
    android:targetSdkVersion="26" />

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

<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/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=".MyReceiver"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>

    <service
        android:name=".CatchNumbers"
        android:enabled="true"
        android:exported="true" />
    <service
        android:name=".WatchMan"
        android:enabled="true"
        android:exported="true"></service>
</application>

</manifest>

In above manifest.xml i have not placed WRITE_EXTERNAL_STORAGE and READ_EXTERNAL_STORAGE. It has automatically inserted by android studio as i implemented it runtime.


Here is my OnBoot Receiver :

package com.example.rushi.boottest;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;
import android.widget.Toast;

public class MyReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
    Log.d("BootTest : ", "\nOnBootReceiver - Received a broadcast!");
    Toast.makeText(context, "OnBootReceiver Received a broadcast!!", Toast.LENGTH_LONG).show();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
    {
        context.startForegroundService(new Intent(context, WatchMan.class));
    }
    else
    {
        context.startService(new Intent(context, WatchMan.class));
    }
}
}

Here is WatchMan.java a foreground service that implements receivers runtime

public class WatchMan extends Service
{
NotificationManager mNotifyManager;
NotificationCompat.Builder mBuilder;
NotificationChannel notificationChannel;
String NOTIFICATION_CHANNEL_ID = "17";

private BroadcastReceiver mCallBroadcastReceiver = new BroadcastReceiver()
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
        String PhoneNumber = "UNKNOWN";
        Log.d("RECEIVER :  ","IS UP AGAIN....");

        try
        {
            String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
            if(state == null)
            {
                PhoneNumber = "UNKNOWN";
            }
            else if (state.equals(TelephonyManager.EXTRA_STATE_RINGING))
            {
                PhoneNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
                Log.d("RECEIVER : ","Incoming number : "+PhoneNumber);
            }
            if(intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL"))
            {
                PhoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
                Log.d("RECEIVER : ","Outgoing number : "+PhoneNumber);
            }
            if(!PhoneNumber.contentEquals("UNKNOWN"))
            {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
                {
                    context.startForegroundService(new Intent(context, CatchNumbers.class));
                }
                else
                {
                    context.startService(new Intent(context, CatchNumbers.class));
                }
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
            Log.e("RECEIVER : ", "Exception is : ", e);
        }
    }
};

public WatchMan() { }

@Override
public void onCreate()
{
    super.onCreate();
    Log.d("WatchMan : ", "\nOnCreate...");

    IntentFilter CallFilter = new IntentFilter();
    CallFilter.addAction("android.intent.action.NEW_OUTGOING_CALL");
    CallFilter.addAction("android.intent.action.PHONE_STATE");
    this.registerReceiver(mCallBroadcastReceiver, CallFilter);

    Log.d("WatchMan : ", "\nmCallBroadcastReceiver Created....");

    mNotifyManager = (NotificationManager) getApplicationContext().getSystemService(NOTIFICATION_SERVICE);
    mBuilder = new NotificationCompat.Builder(this, null);
    mBuilder.setContentTitle("Insta Promo")
            .setContentText("Checking New Numbers")
            .setTicker("Checking New Numbers")
            .setSmallIcon(R.drawable.ic_launcher_background)
            .setPriority(Notification.PRIORITY_LOW)
            .setDefaults(Notification.DEFAULT_ALL)
            .setVisibility(Notification.VISIBILITY_PUBLIC)
            .setOngoing(true)
            .setAutoCancel(false);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
    {
        notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "My Notifications", NotificationManager.IMPORTANCE_HIGH);

        // Configure the notification channel.
        notificationChannel.setDescription("Channel description");
        notificationChannel.enableLights(true);
        notificationChannel.setLightColor(Color.RED);
        notificationChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
        notificationChannel.enableVibration(true);
        notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
        mNotifyManager.createNotificationChannel(notificationChannel);

        mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
        startForeground(17, mBuilder.build());
    }
    else
    {
        mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
        //startForeground(17, mBuilder.build());
        mNotifyManager.notify(17, mBuilder.build());
    }
}

@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
    Log.d("WatchMan : ", "\nmCallBroadcastReceiver Listening....");

    //return super.onStartCommand(intent, flags, startId);

    return START_NOT_STICKY;
}

@Override
public void onDestroy()
{
    this.unregisterReceiver(mCallBroadcastReceiver);
    Log.d("WatchMan : ", "\nDestroyed....");
    Log.d("WatchMan : ", "\nWill be created again....");
}

@Override
public IBinder onBind(Intent intent)
{
    // TODO: Return the communication channel to the service.
    throw new UnsupportedOperationException("Not yet implemented");
}
}

Now in the receiver before calling insert phone numbers into sqlite database table; so that you can read it from CatchNumbers.java service and perform whatever actions you wants on incoming and outgoing numbers. Hope it helps you or someone else

sandhya sasane
  • 1,334
  • 12
  • 19
  • Hi @Sandhya, Can you please have a look at my query? https://stackoverflow.com/questions/51221680/broadcast-receiver-not-working-in-oreo/51221721#51221721 – Era Singla Jul 07 '18 at 10:26
  • Perfect Solution...Thanks :) – Krupa Kakkad Oct 26 '18 at 06:28
  • it seems not working now. Its not woking in One plus 5 handset – Feroz Siddiqui Nov 05 '18 at 10:46
  • @FerozSiddiqui, One plus X, is a one of NON STANDARD MOBILE PHONE MANUFACTURERS.., there are multiple like VIVO, MI, ......... Its OXYGEN OS AND NOT STOCK ANDROID OS. ( you need to be battery optimisation off to work on it. I have tested it on One Plus 3 and it works.. As post oreo you have to make battery optimisation exemption, ask users to exempt ) – sandhya sasane Nov 07 '18 at 19:34
0

The solution of Sandhya Sasane work for me on the android 9 emulator the BOOT_COMPLETED notification is received (either forcing it via "adb" or rebooting the emulator).

But on a real device Huawei P-Smart with EMUI 9.1.0.119 never happens :(

Ice72
  • 11
  • 1
  • 4
0

None of the above answers seem to work for me. Here is my solution but in kotlin. Paste the following parts of the code and change the necessary details as per your app.

After onCreate method in Mainactivity:

override fun onStart() {
    super.onStart()
    var intentfilter1: IntentFilter = IntentFilter("com.spotify.music.playbackstatechanged")

    intentfilter1.addCategory(Intent.CATEGORY_DEFAULT)
    registerReceiver(mreceiver, intentfilter1)


}

override fun onStop() {
    super.onStop()
    unregisterReceiver(mreceiver)
}

In onCreate method:

mreceiver = SpotifyBroadcastReceiver()

In MainAvtivity before onCreate method:

lateinit var mreceiver: SpotifyBroadcastReceiver

Mainfest.xml file

     <receiver android:name=".SpotifyBroadcastReceiver" //name of the broadcast receiver class
        android:permission="android.permission.RECEIVE_BOOT_COMPLETED"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="com.spotify.music.playbackstatechanged" /> //Things required by my broadcast receiver class
        </intent-filter>
    </receiver>

Let me know if i missed something or you need some other info related to the snippet.

P.S: Im new to kotlin too....im just sharing what worked for me. It might or might not work for you configuration so Happy coding!!

Santhosh
  • 81
  • 2
  • 11
-1

I also had this kind of issue, but I found a better solution:

@BroadcastReceiverActions({"android.intent.action.SCREEN_ON", "android.intent.action.SCREEN_OFF",
        "android.intent.action.DREAMING_STARTED", "android.intent.action.DREAMING_STOPPED",
        "android.intent.action.ACTION_POWER_DISCONNECTED", "android.intent.action.ACTION_POWER_CONNECTED",
        "android.net.conn.CONNECTIVITY_CHANGE"})
public class MyReceiver extends BroadcastReceiver {

    public MyReceiver() {
        super();
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        Session.getGlobalReceiverCallBack(context, intent);

        //Log.e("dfd", "" + intent.getAction());
    }
}

public class AppController extends Application {

    private BroadcastReceiver receiver;
    MyReceiver mR;

    @Override
    public void onCreate() {
        super.onCreate();
        mR = new MyReceiver();
        receiver = DynamicReceiver.with(mR)
                .register(this);

    }
}

public class MainActivity extends AppCompatActivity implements GlobalReceiverCallBack {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Session.setmGlobalReceiverCallback(this);

    }

    @Override
    public void onCallBackReceived(Context context, Intent intent) {

        Toast.makeText(context, "" + intent.getAction(), Toast.LENGTH_LONG).show();
    }
}

For complete reference you can see also https://github.com/devggaurav/BroadcastReceiver-For-Naught-and-Oreo-devices

Akshay Kumar
  • 71
  • 2
  • 2
  • Not working, when the app is not running. If the app is killed or removed from the recent screen then the app does not receive any broadcast. – mdroid May 27 '20 at 12:54