Oreo: Broadcast receiver Not working

10,795

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

Share:
10,795
user1955126
Author by

user1955126

Updated on June 04, 2022

Comments

  • user1955126
    user1955126 almost 2 years

    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.

  • Era Singla
    Era Singla almost 6 years
    Hi @Sandhya, Can you please have a look at my query? stackoverflow.com/questions/51221680/…
  • Krupa Kakkad
    Krupa Kakkad over 5 years
    Perfect Solution...Thanks :)
  • Feroz Siddiqui
    Feroz Siddiqui over 5 years
    it seems not working now. Its not woking in One plus 5 handset
  • sandhya sasane
    sandhya sasane over 5 years
    @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 )
  • mdroid
    mdroid almost 4 years
    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.