javaandroidandroid-serviceforeground-serviceandroid-service-binding

Notification with custom text and icon not showing when starting with a service


SO, I have a MainActivity that has a button which starts a service, MyService. I want the service to show the notification with a custom title,text,icon,etc. The service is a foreground service. not a bound service. everything works fine but the only thing is about my notification is keep showing "tap for more information" and clicking on it leads me to the settings page of my application. despite having the pendingIntent on my MainActivity.

What I want is to have a Notification with custom Title,Text,icon and an action to stop the service.

this is my MainActivity.java class

public class MainActivity extends AppCompatActivity {




    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.start_tracking).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                startCommand();

            }
        });


    }

    void startCommand() {


        startService(new Intent(this, MyService.class));


    }

}

Myservice.java file

public class MyService extends Service {


    boolean mServiceIsStarted = false;


    void moveToStartedState() {

        Intent myIntentbuilder = new IntentBuilder(this).setmCommandId(Command.START).build();

        Log.d(TAG, "moveToStartedState: Running on Android O - startForegroundService(intent)");
        ContextCompat.startForegroundService(this, myIntentbuilder);



    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand: ");

        boolean containsCommand = IntentBuilder.containsCommand(intent);


        routeIntentToCommand(intent);
        return START_NOT_STICKY;
    }

    void routeIntentToCommand(Intent intent) {

        if (intent != null) {

            if (IntentBuilder.containsCommand(intent)) {
                processCommand(IntentBuilder.getCommand(intent));
            } else
                commandStart();

        }


    }






    @Override
    public void onCreate() {
        super.onCreate();


        Log.d(TAG, "onCreate: ");


    }

    void showNotification() {
        Log.d(TAG, "showNotification: ");
        HandleNotification.O.createNotification(this);
    }


    private void processCommand(int command) {
        try {
            switch (command) {
                case Command.START:
                    commandStart();
                    break;
                case Command.STOP:
                    commandStop();
                    break;
            }
        } catch (Exception e) {
            e(TAG, "processCommand: exception", e);
        }
    }


    void commandStop() {
        stopSelf();
        stopForeground(true);

    }

    void commandStart() {
        if (!mServiceIsStarted) {
            mServiceIsStarted = true;
            moveToStartedState();
            return;
        }

//        
        HandleNotification.O.createNotification(this);


    }



    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


}

IntentBuilder.java class

@IntDef({Command.INVALID, Command.STOP, Command.START})
@Retention(RetentionPolicy.SOURCE)
@interface Command {

    int INVALID = -1;
    int STOP = 0;
    int START = 1;
}

public class IntentBuilder {

    private static final String KEY_MESSAGE = "msg";
    private static final String KEY_COMMAND = "cmd";
    private Context mContext;
    private String mMessage;
    private @Command
    int mCommandId = Command.INVALID;


    public static IntentBuilder getInstance(Context mContext) {
        return new IntentBuilder(mContext);
    }


    public IntentBuilder(Context mContext) {
        this.mContext = mContext;
    }

    public void setmContext(Context mContext) {
        this.mContext = mContext;
    }

    public IntentBuilder setmMessage(String mMessage) {
        this.mMessage = mMessage;
        return this;
    }

    public IntentBuilder setmCommandId(int mCommandId) {
        this.mCommandId = mCommandId;
        return this;
    }

    private static final String TAG = "IntentBuilder";

    public Intent build() {

        Log.e(TAG, "build: context cannot be null" + mContext);
        Intent intent = new Intent(mContext, MyService.class);
        if (mMessage != null)
            intent.putExtra(KEY_MESSAGE, mMessage);

        if (mCommandId != Command.INVALID)
            intent.putExtra(KEY_COMMAND, mCommandId);

        return intent;

    }

    public static boolean containsCommand(Intent intent) {
        return intent.getExtras() != null && intent.getExtras().containsKey(KEY_COMMAND);
    }

    public static boolean containsMessage(Intent intent) {
        return intent.getExtras() != null && intent.getExtras().containsKey(KEY_MESSAGE);
    }

    public static @Command
    int getCommand(Intent intent) {
        final @Command int commandId = intent.getExtras().getInt(KEY_COMMAND);
        return commandId;
    }

    public static String getMessage(Intent intent) {
        return intent.getExtras().getString(KEY_MESSAGE);
    }
}

HandleNotification.java file

public class HandleNotification {


    public static class O {


        public static int getRandomNumber() {
            return new Random().nextInt(100000);
        }

        static PendingIntent getLaunchActivityPI(Service context) {

            Intent intent = new Intent(context, MainActivity.class);
            return PendingIntent.getActivity(context, getRandomNumber(), intent, 0);
        }

        static PendingIntent getStopServicePI(Service context) {
            PendingIntent pendingIntent;
            {
                Intent intent = new IntentBuilder(context).setmCommandId(Command.STOP).build();
                pendingIntent = PendingIntent.getService(context, getRandomNumber(), intent, 0);
            }
            return pendingIntent;
        }

        public static final Integer ONGOING_NOTIFICATION_ID = getRandomNumber();
        public static final String CHANNEL_ID = String.valueOf(getRandomNumber());

        private static final String TAG = "O";

        public static void createNotification(Service context) {
            Log.d(TAG, "createNotification: ");
            String channelId = createChannel(context);
            Notification notification = buildNotification(channelId, context);

            context.startForeground(ONGOING_NOTIFICATION_ID, notification);

        }


        static Notification buildNotification(String channelId, Service context) {

            PendingIntent piMainActivity = getLaunchActivityPI(context);
            PendingIntent piStopService = getStopServicePI(context);
            Icon poweroff = Icon.createWithResource(context, android.R.drawable.star_big_on);
            Notification.Action stopAction = new Notification.Action
                    .Builder(poweroff, "STOP", piStopService).build();

            return new Notification.Builder(context, channelId)
                    .addAction(stopAction)
                    .setContentTitle("Tracking...")

                    .setContentText("I'm tracking your location now... ")
                    .setContentIntent(piMainActivity)
                    .build();

        }


        @NonNull
        private static String createChannel(Context service) {

            NotificationManager notificationManager = (NotificationManager) service.getSystemService(Context.NOTIFICATION_SERVICE);
            CharSequence channelName = "Start Location Updates";
            int importance = NotificationManager.IMPORTANCE_DEFAULT;
            NotificationChannel notificationChannel = new NotificationChannel(CHANNEL_ID, channelName, importance);
            notificationManager.createNotificationChannel(notificationChannel);
            return CHANNEL_ID;

        }

    }


}

Solution

  • Use NotificationCompat.Builder. You can follow how to create one here

    NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle(textTitle)
        .setContentText(textContent)
        .setPriority(NotificationCompat.PRIORITY_DEFAULT);
    

    You can add your custom small or big icon, title, content, and other properties.

    An example from a project that I did long ago

    private void LockNotification() {
        NotificationCompat.Builder builder = new 
        NotificationCompat.Builder(getApplicationContext());
    
        Intent intent = new Intent(this, MainActivity.class);
        intent.putExtra("key","launch_about");
        PendingIntent pendingIntent = 
        PendingIntent.getActivity(getApplicationContext(), 0, intent, 
        PendingIntent.FLAG_UPDATE_CURRENT);
    
        // Set the title, text, and icon
        builder.setContentTitle(getString(R.string.app_name))
                .setContentText("App Lock Enabled")
                .setSmallIcon(R.drawable.ic_applock)
                .setContentIntent(pendingIntent)
                .setOngoing(true);
    
        // Get an instance of the Notification Manager
        NotificationManager notifyManager = (NotificationManager)
                getSystemService(Context.NOTIFICATION_SERVICE);
    
        // Build the notification and post it
        notifyManager.notify(0, builder.build());
    }