Reputation: 3678
I'm looking for an easy way to use Picasso to load a noticiation icon (which is a URL on a remote webpage). In a previous version of the app I'm working on this code seemed to work:
Bitmap speakerPic = null;
try {
speakerPic = new AsyncTask<Void, Void, Bitmap>() {
@Override
protected Bitmap doInBackground(Void... params) {
try {
return Picasso.with(c).load(session.getSpeaker().getPhotoUrl()).get();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}.execute().get(1500, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
if (speakerPic != null) {
builder.setLargeIcon(speakerPic);
} else {
builder.setLargeIcon(BitmapFactory.decodeResource(c.getResources(), R.drawable.ic_launcher));
}
But now I get an TimeOutException every time (and I fallback to a default icon in my res folder). I have to use this AsyncTask because Picasso (/network) may not happen on the UI thread. (although I'm blocking the UI thread for 1.5sec here..).
I know Picasso can handle remoteviews, but I don't want to use a custom view for my notificiation. Also I couldn't find a way to get the RemoteView for the NoticifationIcon.
Is there a way to set the icon of my notification simply using Picasso?
Upvotes: 10
Views: 13426
Reputation: 430
Image loading code using Picaso 2.5.2 starts in middle of this method,besides that all stuff is simple notification code, just copy and paste ,replace "image_url" with actual image url.
private Notification notification;
public void genrateNewsNotification(String title, final int id) {
try {
final Context context=GcmService.this;
final NotificationCompat.Builder mBuilder;
final NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(id);
Intent notificationIntent = new Intent(context, YourActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addParentStack(MainActivity.class);
stackBuilder.addNextIntent(notificationIntent);
final PendingIntent contentIntent =
stackBuilder.getPendingIntent(
id,
PendingIntent.FLAG_UPDATE_CURRENT
);
mBuilder = new NotificationCompat.Builder(context);
mBuilder.setContentTitle("Custom Notification");
mBuilder.setAutoCancel(true);
mBuilder.setPriority(Notification.PRIORITY_MAX);
int currentapiVersion = android.os.Build.VERSION.SDK_INT;
if (currentapiVersion >= Build.VERSION_CODES.LOLLIPOP) {
mBuilder.setSmallIcon(R.drawable.launch_lolipop);
} else {
mBuilder.setSmallIcon(R.drawable.launcher_icon);
}
mBuilder.setContentText(title);
mBuilder.setContentIntent(contentIntent);
notification= mBuilder.build();
// image code starts from here
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
try{
Picasso.with(context).load("image_url")
.into(target);
notificationManager.notify(id, notification);
}
catch (Exception e){
// notification without image in case of Exception
notificationManager.notify(id, notification);
}
}else{
notificationManager.notify(id, notification);
}
} catch (Exception e) {
e.printStackTrace();
}
}
**// main stuff goes here ,it is an inner class**
private Target target = new Target() {
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
if (bitmap != null) {
RemoteViews views;
views = new RemoteViews(getPackageName(), R.layout.custom_notification);
views.setTextViewText(R.id.title, "Daily Notification");
views.setTextColor(R.id.title,getResources().getColor(R.color.black));
views.setImageViewBitmap(R.id.big_picture, bitmap);
views.setImageViewBitmap(R.id.big_icon, BitmapFactory.decodeResource(getResources(), R.drawable.launcher_icon));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
notification.bigContentView = views;
}
}
}
@Override
public void onBitmapFailed(Drawable errorDrawable) {
Log.i("errorDrawable","errorDrawable");
}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
Upvotes: 0
Reputation: 1120
I suggest a simplest way to integrate a remote picture inside your notification as large icon with Picasso.
// your notification builder
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(getString(R.string.app_name))
.setContentText(message)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
String picture = "https://i.sstatic.net/CE5lz.png";
Bitmap bmp = Picasso.with(getApplicationContext()).load(picture).get();
notificationBuilder.setLargeIcon(bmp);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notificationBuilder.build());
Upvotes: 10
Reputation: 3678
I'll answer the question myself because I've found a decent way, using Picasso and RemoteViews. Tested and working with Picasso 2.5.2 :
// Default stuff; making and showing notification
final Context context = getApplicationContext();
final NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
final Notification notification = new NotificationCompat.Builder(context)
.setSmallIcon(R.mipmap.ic_launcher) // Needed for the notification to work/show!!
.setContentTitle("Title of notification")
.setContentText("This is the description of the notification")
// Uncomment if you want to load a big picture
//.setStyle(new NotificationCompat.BigPictureStyle())
.build();
final int notifId = 1337;
notificationManager.notify(notifId, notification);
// Get RemoteView and id's needed
final RemoteViews contentView = notification.contentView;
final int iconId = android.R.id.icon;
// Uncomment for BigPictureStyle, Requires API 16!
//final RemoteViews bigContentView = notification.bigContentView;
//final int bigIconId = getResources().getIdentifier("android:id/big_picture", null, null);
// Use Picasso with RemoteViews to load image into a notification
Picasso.with(getApplicationContext()).load("https://i.sstatic.net/CE5lz.png").into(contentView, iconId, notifId, notification);
// Uncomment for BigPictureStyle
//Picasso.with(getApplicationContext()).load("https://i.sstatic.net/CE5lz.png").into(bigContentView, iconId, notifId, notification);
//Picasso.with(getApplicationContext()).load("https://i.sstatic.net/CE5lz.png").into(bigContentView, bigIconId, notifId, notification);
Upvotes: 20
Reputation: 551
If you don't want to wait until Picasso fetches the image before sending the notification, one solution is to send the notification twice with the same id, so that the NotificationManager
will update the existing notification the second time it's being sent.
In practice, the first time, use a placeholder for setLargeIcon()
, and the second time, use the Bitmap
you got from a Picasso Target
.
For instance, from your Activity
:
final Notification.Builder builder = new Notification.Builder(this);
final int id = 0; // change this w/ your notification id
Bitmap placeholder = BitmapFactory.decodeResource(getResources(), R.drawable.your_placeholder_icon);
builder.setContentTitle(title)
.yourFavoriteBuilderMethods(...)
.setLargeIcon(placeholder)
.setDefaults(0); // so that it doesn't ring twice
// mTarget should an instance variable of your class so it doesn't get GC'ed
mTarget = new Target() {
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
builder.setLargeIcon(bitmap)
.setDefaults(Notification.DEFAULT_ALL);
// send the notification again to update it w/ the right image
((NotificationManager) (getSystemService(NOTIFICATION_SERVICE)))
.notify(id, builder.build());
}
@Override
public void onBitmapFailed(Drawable errorDrawable) {}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {}
};
Picasso.with(this).load(your_image_url_here).into(mTarget);
// send notification for the first time here, w/ placeholder:
((NotificationManager) (getSystemService(NOTIFICATION_SERVICE)))
.notify(id, builder.build());
Since Picasso will need to access the internet, don't forget to set the right permission in your manifest for this to work:
<uses-permission android:name="android.permission.INTERNET" />
Upvotes: 4
Reputation: 1670
Not sure why your code is not working but its compiling fine for me, tested on API level 21 and Android Studio.
I made a few changes to fit my needs, e.g. removed the time delay.
The only noticeable differences is the below output in my logcat:
Setting airplane_mode_on has moved from android.provider.Settings.System to android.provider.Settings.Global, returning read-only value.
which is normal based on the links: this and this
And my updated code is:
Bitmap contactPic = null;
final String getOnlinePic = GET_AVATAR;
try {
contactPic = new AsyncTask<Void, Void, Bitmap>() {
@Override
protected Bitmap doInBackground(Void... params) {
try {
return Picasso.with(ctx).load(getOnlinePic)
.resize(200, 200)
.placeholder(R.drawable.ic_action_user_purple_light)
.error(R.drawable.ic_action_user_purple_light)
.get();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}.execute().get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
if (contactPic != null) {
builder.setLargeIcon(contactPic);
} else {
builder.setLargeIcon(BitmapFactory.decodeResource(ctx.getResources(), R.drawable.ic_action_user_purple_light));
}
Upvotes: 6