diff --git a/app/src/main/java/com/github/gotify/messages/MessagesActivity.java b/app/src/main/java/com/github/gotify/messages/MessagesActivity.java index 8a0651af..107f0dce 100644 --- a/app/src/main/java/com/github/gotify/messages/MessagesActivity.java +++ b/app/src/main/java/com/github/gotify/messages/MessagesActivity.java @@ -43,7 +43,6 @@ import com.github.gotify.Utils; import com.github.gotify.api.Api; import com.github.gotify.api.ApiException; -import com.github.gotify.api.CertUtils; import com.github.gotify.api.ClientFactory; import com.github.gotify.client.ApiClient; import com.github.gotify.client.api.ClientApi; @@ -60,22 +59,17 @@ import com.github.gotify.messages.provider.MessageFacade; import com.github.gotify.messages.provider.MessageState; import com.github.gotify.messages.provider.MessageWithImage; -import com.github.gotify.picasso.PicassoDataRequestHandler; +import com.github.gotify.picasso.PicassoHandler; import com.github.gotify.service.WebSocketService; import com.github.gotify.settings.SettingsActivity; import com.google.android.material.navigation.NavigationView; import com.google.android.material.snackbar.BaseTransientBottomBar; import com.google.android.material.snackbar.Snackbar; -import com.squareup.picasso.OkHttp3Downloader; -import com.squareup.picasso.Picasso; import com.squareup.picasso.Target; -import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import okhttp3.Cache; -import okhttp3.OkHttpClient; import static java.util.Collections.emptyList; @@ -123,9 +117,7 @@ public void onReceive(Context context, Intent intent) { private boolean isLoadMore = false; private Integer selectAppIdOnDrawerClose = null; - int PICASSO_CACHE_SIZE = 50 * 1024 * 1024; // 50 MB - private Cache picassoCache; - private Picasso picasso; + private PicassoHandler picassoHandler; // we need to keep the target references otherwise they get gc'ed before they can be called. @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") @@ -139,8 +131,7 @@ protected void onCreate(Bundle savedInstanceState) { Log.i("Entering " + getClass().getSimpleName()); settings = new Settings(this); - picassoCache = new Cache(new File(getCacheDir(), "picasso-cache"), PICASSO_CACHE_SIZE); - picasso = makePicasso(); + picassoHandler = new PicassoHandler(this, settings); client = ClientFactory.clientToken(settings.url(), settings.sslSettings(), settings.token()); @@ -157,7 +148,7 @@ protected void onCreate(Bundle savedInstanceState) { messagesView.getContext(), layoutManager.getOrientation()); ListMessageAdapter adapter = new ListMessageAdapter( - this, settings, picasso, emptyList(), this::scheduleDeletion); + this, settings, picassoHandler.get(), emptyList(), this::scheduleDeletion); messagesView.addItemDecoration(dividerItemDecoration); messagesView.setHasFixedSize(true); @@ -200,7 +191,7 @@ public void onDrawerClosed(View drawerView) { public void onRefreshAll(View view) { try { - picassoCache.evictAll(); + picassoHandler.evict(); } catch (IOException e) { Log.e("Problem evicting Picasso cache", e); } @@ -234,7 +225,9 @@ protected void onUpdateApps(List applications) { item.setCheckable(true); Target t = Utils.toDrawable(getResources(), item::setIcon); targetReferences.add(t); - picasso.load(Utils.resolveAbsoluteUrl(settings.url() + "/", app.getImage())) + picassoHandler + .get() + .load(Utils.resolveAbsoluteUrl(settings.url() + "/", app.getImage())) .error(R.drawable.ic_alarm) .placeholder(R.drawable.ic_placeholder) .resize(100, 100) @@ -242,20 +235,6 @@ protected void onUpdateApps(List applications) { } } - private Picasso makePicasso() { - OkHttpClient.Builder builder = new OkHttpClient.Builder(); - builder.cache(picassoCache); - - CertUtils.applySslSettings(builder, settings.sslSettings()); - - OkHttp3Downloader downloader = new OkHttp3Downloader(builder.build()); - - return new Picasso.Builder(this) - .addRequestHandler(new PicassoDataRequestHandler()) - .downloader(downloader) - .build(); - } - private void initDrawer() { setSupportActionBar(toolbar); navigationView.setItemIconTintList(null); @@ -370,7 +349,7 @@ protected void onPause() { @Override protected void onDestroy() { super.onDestroy(); - picasso.shutdown(); + picassoHandler.get().shutdown(); } private void scheduleDeletion(int position, Message message, boolean listAnimation) { diff --git a/app/src/main/java/com/github/gotify/messages/provider/MessageImageCombiner.java b/app/src/main/java/com/github/gotify/messages/provider/MessageImageCombiner.java index 4a145f66..95cb18c9 100644 --- a/app/src/main/java/com/github/gotify/messages/provider/MessageImageCombiner.java +++ b/app/src/main/java/com/github/gotify/messages/provider/MessageImageCombiner.java @@ -3,11 +3,11 @@ import com.github.gotify.client.model.Application; import com.github.gotify.client.model.Message; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; -class MessageImageCombiner { +public class MessageImageCombiner { List combine(List messages, List applications) { Map appIdToImage = appIdToImage(applications); @@ -26,8 +26,8 @@ List combine(List messages, List applica return result; } - private Map appIdToImage(List applications) { - Map map = new HashMap<>(); + public static Map appIdToImage(List applications) { + Map map = new ConcurrentHashMap<>(); for (Application app : applications) { map.put(app.getId(), app.getImage()); } diff --git a/app/src/main/java/com/github/gotify/picasso/PicassoHandler.java b/app/src/main/java/com/github/gotify/picasso/PicassoHandler.java new file mode 100644 index 00000000..c2f07174 --- /dev/null +++ b/app/src/main/java/com/github/gotify/picasso/PicassoHandler.java @@ -0,0 +1,94 @@ +package com.github.gotify.picasso; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import com.github.gotify.R; +import com.github.gotify.Settings; +import com.github.gotify.Utils; +import com.github.gotify.api.Callback; +import com.github.gotify.api.CertUtils; +import com.github.gotify.api.ClientFactory; +import com.github.gotify.client.api.ApplicationApi; +import com.github.gotify.log.Log; +import com.github.gotify.messages.provider.MessageImageCombiner; +import com.squareup.picasso.OkHttp3Downloader; +import com.squareup.picasso.Picasso; +import java.io.File; +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import okhttp3.Cache; +import okhttp3.OkHttpClient; + +public class PicassoHandler { + + private static final int PICASSO_CACHE_SIZE = 50 * 1024 * 1024; // 50 MB + private static final String PICASSO_CACHE_SUBFOLDER = "picasso-cache"; + + private Context context; + private Settings settings; + + private Cache picassoCache; + + private Picasso picasso; + private Map appIdToAppImage = new ConcurrentHashMap<>(); + + public PicassoHandler(Context context, Settings settings) { + this.context = context; + this.settings = settings; + + picassoCache = + new Cache( + new File(context.getCacheDir(), PICASSO_CACHE_SUBFOLDER), + PICASSO_CACHE_SIZE); + picasso = makePicasso(); + } + + private Picasso makePicasso() { + OkHttpClient.Builder builder = new OkHttpClient.Builder(); + builder.cache(picassoCache); + CertUtils.applySslSettings(builder, settings.sslSettings()); + OkHttp3Downloader downloader = new OkHttp3Downloader(builder.build()); + return new Picasso.Builder(context).downloader(downloader).build(); + } + + public Bitmap getIcon(Integer appId) { + if (appId == -1) { + return BitmapFactory.decodeResource(context.getResources(), R.drawable.gotify); + } + + try { + return picasso.load( + Utils.resolveAbsoluteUrl( + settings.url() + "/", appIdToAppImage.get(appId))) + .get(); + } catch (IOException e) { + Log.e("Could not load image for notification", e); + } + return BitmapFactory.decodeResource(context.getResources(), R.drawable.gotify); + } + + public void updateAppIds() { + ClientFactory.clientToken(settings.url(), settings.sslSettings(), settings.token()) + .createService(ApplicationApi.class) + .getApps() + .enqueue( + Callback.call( + (apps) -> { + appIdToAppImage.clear(); + appIdToAppImage.putAll(MessageImageCombiner.appIdToImage(apps)); + }, + (t) -> { + appIdToAppImage.clear(); + })); + } + + public Picasso get() { + return picasso; + } + + public void evict() throws IOException { + picassoCache.evictAll(); + } +} diff --git a/app/src/main/java/com/github/gotify/service/WebSocketService.java b/app/src/main/java/com/github/gotify/service/WebSocketService.java index 1130dd9b..53664cea 100644 --- a/app/src/main/java/com/github/gotify/service/WebSocketService.java +++ b/app/src/main/java/com/github/gotify/service/WebSocketService.java @@ -23,12 +23,14 @@ import com.github.gotify.Settings; import com.github.gotify.Utils; import com.github.gotify.api.ClientFactory; +import com.github.gotify.client.ApiClient; import com.github.gotify.client.api.MessageApi; import com.github.gotify.client.model.Message; import com.github.gotify.log.Log; import com.github.gotify.log.UncaughtExceptionHandler; import com.github.gotify.messages.Extras; import com.github.gotify.messages.MessagesActivity; +import com.github.gotify.picasso.PicassoHandler; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; @@ -46,16 +48,17 @@ public class WebSocketService extends Service { private AtomicInteger lastReceivedMessage = new AtomicInteger(NOT_LOADED); private MissedMessageUtil missingMessageUtil; + private PicassoHandler picassoHandler; + @Override public void onCreate() { super.onCreate(); settings = new Settings(this); - missingMessageUtil = - new MissedMessageUtil( - ClientFactory.clientToken( - settings.url(), settings.sslSettings(), settings.token()) - .createService(MessageApi.class)); + ApiClient client = + ClientFactory.clientToken(settings.url(), settings.sslSettings(), settings.token()); + missingMessageUtil = new MissedMessageUtil(client.createService(MessageApi.class)); Log.i("Create " + getClass().getSimpleName()); + picassoHandler = new PicassoHandler(this, settings); } @Override @@ -115,6 +118,8 @@ private void startPushService() { intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); ReconnectListener receiver = new ReconnectListener(this::doReconnect); registerReceiver(receiver, intentFilter); + + picassoHandler.updateAppIds(); } private void onDisconnect() { @@ -176,13 +181,15 @@ private void onMessage(Message message) { if (lastReceivedMessage.get() < message.getId()) { lastReceivedMessage.set(message.getId()); } + broadcast(message); showNotification( message.getId(), message.getTitle(), message.getMessage(), message.getPriority(), - message.getExtras()); + message.getExtras(), + message.getAppid()); } private void broadcast(Message message) { @@ -224,6 +231,16 @@ private void foreground(String message) { private void showNotification( int id, String title, String message, long priority, Map extras) { + showNotification(id, title, message, priority, extras, -1); + } + + private void showNotification( + int id, + String title, + String message, + long priority, + Map extras, + Integer appid) { Intent intent; @@ -263,6 +280,7 @@ private void showNotification( .setDefaults(Notification.DEFAULT_ALL) .setWhen(System.currentTimeMillis()) .setSmallIcon(R.drawable.ic_gotify) + .setLargeIcon(picassoHandler.getIcon(appid)) .setTicker(getString(R.string.app_name) + " - " + title) .setGroup(NotificationSupport.Group.MESSAGES) .setContentTitle(title)