62

In my android application, i want to set Notification icons dynamically which will be loaded from URL. For that, i have used setLargeIcon property of NotificationBuilder in receiver.I reffered many link and tried various solutions but couldn't get desired output. Though i downloaded that image from url and setting that bitmap in notification, it is not being displayed. Instead it displays the setSmallIcon image as large icon. I don't know where i am going wrong. Here i am posting my code. Please help me to solve this issue. Thank you.

Code:

@SuppressLint("NewApi")
public class C2DMMessageReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if ("com.google.android.c2dm.intent.RECEIVE".equals(action)) {
            Log.e("C2DM", "received message");
            final String fullName = intent.getStringExtra("message");
            final String payload1 = intent.getStringExtra("message1");
            final String payload2 = intent.getStringExtra("message2");
            final String userImage = intent.getStringExtra("userImage");

            Log.e("userImage Url :", userImage); //it shows correct url

            new sendNotification(context)
                    .execute(fullName, payload1, userImage);
        }
    }

private class sendNotification extends AsyncTask<String, Void, Bitmap> {

        Context ctx;
        String message;

        public sendNotification(Context context) {
            super();
            this.ctx = context;
        }

        @Override
        protected Bitmap doInBackground(String... params) {

            InputStream in;
            message = params[0] + params[1];
            try {

                in = new URL(params[2]).openStream();
                Bitmap bmp = BitmapFactory.decodeStream(in);
                return bmp;

            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Bitmap result) {

            super.onPostExecute(result);
            try {
                NotificationManager notificationManager = (NotificationManager) ctx
                        .getSystemService(Context.NOTIFICATION_SERVICE);

                Intent intent = new Intent(ctx, NotificationsActivity.class);
                intent.putExtra("isFromBadge", false);


                Notification notification = new Notification.Builder(ctx)
                        .setContentTitle(
                                ctx.getResources().getString(R.string.app_name))
                        .setContentText(message)
                        .setSmallIcon(R.drawable.ic_launcher)
                        .setLargeIcon(result).build();

                // hide the notification after its selected
                notification.flags |= Notification.FLAG_AUTO_CANCEL;

                notificationManager.notify(1, notification);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
Zankhna
  • 4,360
  • 8
  • 59
  • 100
  • Can you post a screenshot? – johng Jul 19 '14 at 12:27
  • 1
    Its not possible for me to attach screenshot but i can tell you that how it looks. Actually it should display smallIcon value(R.drawable.ic_launcher) in notificationbar and when i enlarge my notification bar by swiping downside, it should dispaly bitmap(bm) which is set as large icon but in both notifictaionbar and enlarged notifictaion area shows small icon (R.drawable.ic_launcher). – Zankhna Jul 19 '14 at 13:15
  • possible duplicate of [Android - use external profile image in notification bar like Facebook](http://stackoverflow.com/questions/16007401/android-use-external-profile-image-in-notification-bar-like-facebook) – Sonia John Kavery May 04 '15 at 06:32

9 Answers9

44

Changed my code as below and its working now :

private class sendNotification extends AsyncTask<String, Void, Bitmap> {

        Context ctx;
        String message;

        public sendNotification(Context context) {
            super();
            this.ctx = context;
        }

        @Override
        protected Bitmap doInBackground(String... params) {

            InputStream in;
            message = params[0] + params[1];
            try {

                  URL url = new URL(params[2]);
                  HttpURLConnection connection = (HttpURLConnection)url.openConnection();
                  connection.setDoInput(true);
                  connection.connect();
                  in = connection.getInputStream();
                  Bitmap myBitmap = BitmapFactory.decodeStream(in);
                  return myBitmap;
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Bitmap result) {

            super.onPostExecute(result);
            try {
                NotificationManager notificationManager = (NotificationManager) ctx
                        .getSystemService(Context.NOTIFICATION_SERVICE);

                Intent intent = new Intent(ctx, NotificationsActivity.class);
                intent.putExtra("isFromBadge", false);


                Notification notification = new Notification.Builder(ctx)
                        .setContentTitle(
                                ctx.getResources().getString(R.string.app_name))
                        .setContentText(message)
                        .setSmallIcon(R.drawable.ic_launcher)
                        .setLargeIcon(result).build();

                // hide the notification after its selected
                notification.flags |= Notification.FLAG_AUTO_CANCEL;

                notificationManager.notify(1, notification);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
Zankhna
  • 4,360
  • 8
  • 59
  • 100
35

How to implement BigPicture style Notification:

Miracle has been done by .setStyle(new Notification.BigPictureStyle().bigPicture(result)) :

I have done this way with:

enter image description here

Generate notification by AsyncTask:

new generatePictureStyleNotification(this,"Title", "Message", 
                 "http://api.androidhive.info/images/sample.jpg").execute();

AsyncTask:

public class generatePictureStyleNotification extends AsyncTask<String, Void, Bitmap> {

        private Context mContext;
        private String title, message, imageUrl;

        public generatePictureStyleNotification(Context context, String title, String message, String imageUrl) {
            super();
            this.mContext = context;
            this.title = title;
            this.message = message;
            this.imageUrl = imageUrl;
        }

        @Override
        protected Bitmap doInBackground(String... params) {

            InputStream in;
            try {
                URL url = new URL(this.imageUrl);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setDoInput(true);
                connection.connect();
                in = connection.getInputStream();
                Bitmap myBitmap = BitmapFactory.decodeStream(in);
                return myBitmap;
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }

        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
        @Override
        protected void onPostExecute(Bitmap result) {
            super.onPostExecute(result);

            Intent intent = new Intent(mContext, MyOpenableActivity.class);
            intent.putExtra("key", "value");
            PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 100, intent, PendingIntent.FLAG_ONE_SHOT);

            NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
            Notification notif = new Notification.Builder(mContext)
                    .setContentIntent(pendingIntent)
                    .setContentTitle(title)
                    .setContentText(message)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setLargeIcon(result)
                    .setStyle(new Notification.BigPictureStyle().bigPicture(result))
                    .build();
            notif.flags |= Notification.FLAG_AUTO_CANCEL;
            notificationManager.notify(1, notif);
        }
    }
Vishal Yadav
  • 3,351
  • 3
  • 20
  • 40
Hiren Patel
  • 48,538
  • 20
  • 161
  • 144
  • 3
    Put some details along with code! It would help someone to understand the APIs, functionality and the implantation exactly! – Paresh Mayani Dec 07 '15 at 07:21
  • i am not able to call this method in FirebaseMessagingService How can i implement it. – Arpit Patel Oct 28 '16 at 12:28
  • @ArpitPatel May be the service is ending prior to retrieving image asynchronously. Did you try getting the image synchronously? Like here: http://androidbash.com/firebase-push-notification-android/ – rpattabi Nov 25 '16 at 03:54
  • ya i already solve using this tutorial. It is well explained. thanks by the for guidance @rpattabi – Arpit Patel Nov 25 '16 at 05:31
  • 1
    @rpattabi androidbash.com/firebase-push-notification-android I try this tutorial, but there is some restrictions **_Like_** Notification with image an fetched from the url is displayed to the user (with BigImage). But if the app is background or killed state, then onMessageReceived () method will not be called. Hence a simple notification containing just a message will be displayed in the notification bar on your Android device. – Prashant Gosai Jan 19 '17 at 05:49
  • Its working, but it takes a few seconds to display the notification, it doesn't display immediately. Is there some way that, notification generate immediately. Is there any way to display notification immediately, and load image from url meanwhile? – Narendra Singh May 08 '17 at 12:54
  • @PrashantGosai is there any way to show image in background state also ? – Tejas Pandya Jun 14 '18 at 12:04
  • Why did you have the notification code in Async Task? – LekeOpe Sep 18 '18 at 05:44
  • @Micklo_Nerd, We are loading image in background thread that's why we've used Async Task. You probably can use Rx java instead to eliminate the code. – Hiren Patel Sep 18 '18 at 06:40
  • Okay, i get it now. Thanks – LekeOpe Sep 18 '18 at 16:56
32

you can do this using Glide like this:

val notificationBuilder = NotificationCompat.Builder(this, channelId)
        .setSmallIcon(R.drawable.ic_message)
        .setContentTitle("title")
        .setContentText("text")

val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

val futureTarget = Glide.with(this)
        .asBitmap()
        .load(photoUrl)
        .submit()

val bitmap = futureTarget.get()
notificationBuilder.setLargeIcon(bitmap)

Glide.with(this).clear(futureTarget)

notificationManager.notify(0, notificationBuilder.build())

preview

Dan Alboteanu
  • 6,336
  • 1
  • 37
  • 33
13

Top answer in Kotlin and with Coroutines. This method applies the bitmap to the builder instead of a direct assignment, and of course if bitmap available. It's nice because if the url is wrong it will be caught in the try/catch.

fun applyImageUrl(
    builder: NotificationCompat.Builder, 
    imageUrl: String
) = runBlocking {
    val url = URL(imageUrl)

    withContext(Dispatchers.IO) {
        try {
            val input = url.openStream()
            BitmapFactory.decodeStream(input)
        } catch (e: IOException) {
            null
        }
    }?.let { bitmap ->
        builder.setLargeIcon(bitmap)
    }
}

with Kotlin & RxJava

fun applyImageUrl(
    builder: NotificationCompat.Builder,
    imageUrl: String
) {
    val url = URL(imageUrl)

    Single.create<Bitmap> { emitter ->
        try {
            val input = url.openStream()
            val bitmap = BitmapFactory.decodeStream(input)
            emitter.onSuccess(bitmap)
        } catch (e: Exception) {
            emitter.onError(e)
        }
    }.subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(
            {
                builder.setLargeIcon(it)
            }, {
                Timber.e("error generating bitmap for notification")
            }
        )
}
Juan Mendez
  • 2,242
  • 1
  • 22
  • 20
8

Since image is loaded from internet, it should be done async in a background thread. Either use async task or Glide (for efficient image loading).

To load image notification, you need to use "NotificationCompat.BigPictureStyle()". This requires a bitmap (which has to be extracted from image url)

Most of the API's and methods of Glide are now deprecated. Below is working with Glide 4.9 and upto Android 10.

 // Load bitmap from image url on background thread and display image notification
        private void getBitmapAsyncAndDoWork(String imageUrl) {

            final Bitmap[] bitmap = {null};

            Glide.with(getApplicationContext())
                    .asBitmap()
                    .load(imageUrl)
                    .into(new CustomTarget<Bitmap>() {
                        @Override
                        public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {

                            bitmap[0] = resource;
                            // TODO Do some work: pass this bitmap
                            displayImageNotification(bitmap[0]);
                        }

                        @Override
                        public void onLoadCleared(@Nullable Drawable placeholder) {
                        }
                    });
        }

Display the image notification once, the bitmap is ready.

private void displayImageNotification(Bitmap bitmap) {

      NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(), getChannelId());
            builder
                    .setContentTitle(title)
                    .setContentText(subtext)
                    .setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE)
                    .setSmallIcon(SMALL_ICON)
                    .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                    .setColor(getApplicationContext().getColor(color))
                    .setAutoCancel(true)
                    .setOngoing(false)
                    .setOnlyAlertOnce(true)
                    .setContentIntent(pendingIntent)
                     .setStyle(
                     new NotificationCompat.BigPictureStyle().bigPicture(bitmap))
                    .setPriority(Notification.PRIORITY_HIGH);

        getManager().notify(tag, id, builder.build());
}
Mayuri Khinvasara
  • 1,139
  • 1
  • 11
  • 11
4

I know a good answer has been given so let's see if we can make it easier to understand and implement.
---------------------Theory------------------------
The problem can be abstracted in two step solution namely
1) Get image from a URL
2) Decode image and pass to notification builder

1) Get image from a URL
InputStream in = new URL("Img URL goes here eg. http://gg.com/profile.jpg").openStream();

2) Decode and pass to notification
Bitmap bmp = null; #create a null bmp container that will be used to hold decoded img
bmp = BitmapFactory.decodeStream(in); # save the image into container

Voila! once you build the image and save it in the variable bmp, you can call it on notification builder .setLargeIcon(bmp)

--------Implementation---------------
Android studio will encourage you to wrap your code with try catch so the end product will look like this.

Bitmap bmp = null;
try {
    InputStream in = new URL("url goes here").openStream();
    bmp = BitmapFactory.decodeStream(in);
} catch (IOException e) {
    e.printStackTrace();
}

Once you have the bmp you can call it in notification builder as

NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_launcher)
            .setContentText("title")
            .setContentText("text goes here")
            .setLargeIcon(bmp)
            .setAutoCancel(true);
0

Using Picasso Library.

               Target target = new Target() {
                    @Override
                    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                        largeIcon=bitmap;
                    }

                    @Override
                    public void onBitmapFailed(Drawable errorDrawable) {
                    }

                    @Override
                    public void onPrepareLoad(Drawable placeHolderDrawable) {
                    }
                };

                Picasso.with(this).load("url").into(target); 





               NotificationCompat.Builder notificationBuilder =
                    new NotificationCompat.Builder(this, channelId)
                            .setSmallIcon(R.drawable.icon)
                            .setContentTitle(msg.getString("title"))
                            .setContentText(msg.getString("msg"))
                            .setAutoCancel(true)
                            .setSound(defaultSoundUri)
                            .setLargeIcon(largeIcon)
                            .setContentIntent(pendingIntent);
Sunil Soni
  • 433
  • 3
  • 18
0

Since I couldn't find any working solution for Picasso I'm posting my complete and working(July 2020) example using Picasso below.

It is sending the notification immediately and then updates it when the image for setLargeIcon() has been loaded. Normally this is very quick and the user should only see the updated version of the notification in most cases.

private void sendNotification(String message, String title, final String photoUrl) {
    Intent intent = new Intent(this, MainActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,
            PendingIntent.FLAG_ONE_SHOT);

    final NotificationCompat.Builder notificationBuilder =
            new NotificationCompat.Builder(this, CHANNEL_ID)
                    .setSmallIcon(R.drawable.wbib_transp_512)
                    .setContentTitle(title)
                    .setContentText(message)
                    .setAutoCancel(true)
                    .setPriority(NotificationCompat.PRIORITY_HIGH)
                    .setCategory(NotificationCompat.CATEGORY_MESSAGE)
                    .setContentIntent(pendingIntent);

    final NotificationManager notificationManager =
            (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

    notificationManager.notify(0, notificationBuilder.build());

    final Handler uiHandler = new Handler(Looper.getMainLooper());
    uiHandler.post(new Runnable() {
        @Override
        public void run() {
            Picasso.get()
                    .load(photoUrl)
                    .resize(200, 200)
                    .into(new Target() {
                        @Override
                        public void onBitmapLoaded(final Bitmap bitmap, final Picasso.LoadedFrom from) {
                            notificationBuilder.setLargeIcon(bitmap);
                            notificationManager.notify(0, notificationBuilder.build());
                        }

                        @Override
                        public void onBitmapFailed(Exception e, final Drawable errorDrawable) {
                            // Do nothing?
                        }

                        @Override
                        public void onPrepareLoad(final Drawable placeHolderDrawable) {
                            // Do nothing?
                        }
                    });
        }
    });


}
John T
  • 455
  • 6
  • 16
0

RxJava and Picasso way

private fun bigImageNotification(ctx: Context, title: String, msg: String, imgUrl: String): Disposable? {
    return Observable.fromCallable {
        Picasso.get().load(imgUrl).get()
    }
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe({
                createNotification(ctx, title, msg, it)
            }, {it.printStackTrace()})
}

private fun createNotification(ctx: Context, title: String, msg: String, img: Bitmap?) {
    val b = Notification.Builder(ctx)
    b.setAutoCancel(true)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle(title)
            .setContentText(msg)
            .setStyle(Notification.BigPictureStyle().bigPicture(img))
    val notificationManager = ctx.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    notificationManager.notify(1000, b.build())
}

Usage

bigImageNotification(context, "title", "msg", "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png")
Radesh
  • 10,690
  • 3
  • 42
  • 60