shantanu
shantanu

Reputation: 2418

NotificationCompat.Builder action is not working

I'm trying to add action in foreground service notification. But action click never fired pending intent. I tried two following approach.

1st Approach

Service

Intent stopActionIntent = new Intent(STOP_SERVICE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(MyService.this, 0, stopActionIntent,0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID);
builder.addAction(0,"stop",pendingIntent);

Manifest

<receiver android:name="com.myproject.receivers.ServiceActionReceiver">
    <intent-filter >
        <action android:name="com.myproject.services.myservice.STOP_SERVICE"/>
    </intent-filter>
</receiver>

Broadcast receiver

@Override
public void onReceive(Context context, Intent intent) {
    if(intent != null && intent.getAction().equals(MyService.STOP_SERVICE)){
        context.stopService(new Intent(context,MyService.class));
    }
}

But broadcast receiver never called.

2nd Approach

service

if(intent != null && STOP_SERVICE.equals(intent.getAction())){
    stopSelf();
    return  super.onStartCommand(intent,flags,startId);
}
else {
    Intent stopActionIntent = new Intent(this,MyService.class);
    stopActionIntent.setAction(STOP_SERVICE);
    PendingIntent pendingIntent = PendingIntent.getActivity(MyService.this, 0, stopActionIntent,0);
    NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID);
    builder.addAction(0,"stop",pendingIntent);
}

Neither approach is worked.

build.gradle

defaultConfig {
    applicationId "com.myproject.project"
    minSdkVersion 16
    targetSdkVersion 27
    versionCode 2
    versionName "1.0.0"
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    multiDexEnabled true
}

Note: Notification and action are visible.

Edit

Doesn't works on Android 8.0 or higher, other version works.

Upvotes: 0

Views: 2492

Answers (3)

sandhya sasane
sandhya sasane

Reputation: 1352

@Shantanu, You have multiple problems. I will suggest you should create another new and sample project for making your concept clear and once cleared use it in your existing project. You have multiple issues, Lets resolve one by one-

  1. Make Receiver to catch the particular event
  2. From Receiver Start a service ( foreground service )
  3. From service, create notification(s)

Look before starting, you must have new sample project with a mainactivity and a layout of mainactivity.

Manifest.xml : This files must have, the permissions we required in our app. I am posting a sample file below in which i am handling multiple permissions and on particular event i am calling the receiver. I want my receiver to be awake and get called on every outgoing and incoming or missed call.

<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.VIBRATE" />

<uses-permission android:name="android.permission.READ_CONTACTS" />

<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />

<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"
        android:screenOrientation="portrait">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

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

    <receiver
        android:name=".Receiver"
        android:enabled="true"
        android:exported="true">

        <intent-filter>
            <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.PHONE_STATE" />
        </intent-filter>
    </receiver>

    <activity android:name=".developer_activity" />
    <activity android:name=".WhiteListActivity" />
    <activity android:name=".Contacts"></activity>
</application>

Do not copy above file as it is, just look where and how permissions are placed. If you copy whole file, it wont work. Just place your permissions above application tag. Thats it.

Now create a service from-> your project explorer, in android studio / eclipse.. Right click on it-> Select new -> select service-> service it will open dialog for you and give appropriate name to your service.

It will create a service class for you and will also modify your manifest.xml for you. You dont need to edit your manifest.xml for that You have a look on my above manifest file service tag. It got created for me automatically when i created service like this.


Now how to create receiver for catching particular event whenever gets triggered in android system :

For that again goto project explorer -> Right Click -> new -> other -> broadcast receiver. It will also open a dialog for you and give name for your receiver. Again you do not require to modify manifest file by your hands. This will modify your manifest.xml automatically. You can again refer above manifest file. And have a look over service and receiver is created there for me..


Now how to call that receiver whenever above new call starts.. see how how i placed

<intent-filter>
    <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
<intent-filter>
    <action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>

within the receiver tags; This means my receiver will get called for this two events always.


Now Receiver.java :

In your onReceive function of receiver

Log.d("RECEIVER ","\SUCCESS : ");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
    context.startForegroundService(new Intent(context, WatchMan.class));
}
else
{
    context.startService(new Intent(context, WatchMan.class));
}

Again here .. you do not need to hand code the functions here. You can create sample overridden functions by right clicking on extended class BroadcastReceiver -> generate - override methods and select onReceive. It will create onReceive sample method for you. Within which you must insert above code how to call your service ( foreground service )


Now service :

Goto service class. Right click on extended class service -> generate -> override methods and whichever methods you are required. There must be empty service method, oncreate , onStartCommand, onDestroy, onBind. Again you can create sample standard methods ready for you using same above method of creation.


Now notifications :

service class declarations :

NotificationManager mNotifyManager;
NotificationCompat.Builder mBuilder;
NotificationChannel notificationChannel;
String NOTIFICATION_CHANNEL_ID = "2";

within OnCreate method :

try
    {

        Intent intent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);

        mNotifyManager = (NotificationManager) getApplicationContext().getSystemService(NOTIFICATION_SERVICE);
        mBuilder = new NotificationCompat.Builder(this, null);
        mBuilder.setContentTitle("App name")
                .setContentText("Notification text..")
                .setTicker("Notification text..")
                .setSmallIcon(R.drawable.ic_service_success)
                .setPriority(Notification.PRIORITY_HIGH)
                .setDefaults(Notification.DEFAULT_ALL)
                .setVisibility(Notification.VISIBILITY_PUBLIC)
                .setContentIntent(pendingIntent);

        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(2, mBuilder.build());


    }
    catch(Exception e)
    {
        Log.d("xx", "EXCEPTION IN SHOWING NOTIFICATION...\n");
        Log.e("xx", "Exception is : ", e);
    }

Now because of call to start foreground it will start running your Onstartcommand method


Within onstartcommand your logic and code goes there... It is upto you to implement runnable thread or not . It is optional.


You can show again other notifications like :

mBuilder.setContentText("Some success or failure...");
mBuilder.setTicker("Some success or failure...");
mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
startForeground(2, mBuilder.build());

Thats it. It should do all what you wants.. permissions, events, receiver, service ( foreground ) and notifications over 4.0 to 8.0 androids devices nearly 99.8 % devices.

Upvotes: 0

user2980181
user2980181

Reputation:

In Android O it's a must to use a channel with your Notification Builder.

sample code :

// Sets an ID for the notification, so it can be updated
int notifyID = 1; 
String CHANNEL_`enter code here`ID = "my_channel_01";// The id of the channel. 
CharSequence name = getString(R.string.channel_name);// The user-visible name of the channel.
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, name, importance);
// Create a notifi`enter code here`cation and set the notification channel.
Notification notification = new Notification.Builder(MainActivity.this)
        .setContentTitle("New Message")
        .setContentText("You've received new messages.")
        .setSmallIcon(R.drawable.ic_notify_status)
        .setChannelId(CHANNEL_ID)
        .build();

Upvotes: 0

Rohan Lodhi
Rohan Lodhi

Reputation: 1395

Try Below Code For Notification:

public void heads_up_notification() {
    Notification.Builder mBuilder = new Notification.Builder(this);
    NotificationManager nNotificationManager = (NotificationManager) getSystemService("notification");
    PendingIntent piDismiss = PendingIntent.getActivity(this, 0, new Intent(this, DirectReplyActivity.class), 0);
    Intent snoozeIntent = new Intent(this, MainActivity.class);
    snoozeIntent.setAction(NotificationCompat.CATEGORY_ALARM);
    PendingIntent piSnooze = PendingIntent.getService(this, 0, snoozeIntent, 0);
    mBuilder.setSmallIcon(C0220R.drawable.ic_launcher_background);
    mBuilder.setContentTitle("Heads up Notification");
    mBuilder.setContentText("heads up activated");
    mBuilder.setDefaults(-1);
    mBuilder.setPriority(1);
    mBuilder.addAction(C0220R.mipmap.ic_dismiss, "Dismiss", piDismiss);
    mBuilder.addAction(C0220R.mipmap.ic_stop, "Stop", piSnooze);
    nNotificationManager.notify(2, mBuilder.build());
}

Upvotes: 0

Related Questions