mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-12-28 11:35:48 +01:00
Add support for picture attachments in notifications
Also adds a local cache for pictures which is handled by the NotificationListener itself. If the picture is hosted in a third party content provider it gets queried. If the Bitmap is embedded in the notification, the local cache is used. In any case the NotificationSpec just holds a String to the absolute file path
This commit is contained in:
parent
7aa7de6463
commit
4aa145560a
@ -25,9 +25,11 @@ package nodomain.freeyourgadget.gadgetbridge.externalevents;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
@ -38,6 +40,7 @@ import android.os.Handler;
|
||||
import android.os.PowerManager;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.MediaStore;
|
||||
import android.service.notification.NotificationListenerService;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
|
||||
@ -51,6 +54,10 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@ -123,6 +130,17 @@ public class NotificationListener extends NotificationListenerService {
|
||||
public static final ArrayList<String> notificationStack = new ArrayList<>();
|
||||
private static final ArrayList<Integer> notificationsActive = new ArrayList<>();
|
||||
|
||||
private static final Set<String> supportedPictureMimeTypes = new HashSet<String>() {{
|
||||
add("image/"); //for im.vector.app
|
||||
add("image/jpeg");
|
||||
add("image/png");
|
||||
add("image/gif");
|
||||
add("image/bmp");
|
||||
add("image/webp");
|
||||
}};
|
||||
|
||||
private File notificationPictureCacheDirectory;
|
||||
|
||||
private long activeCallPostTime;
|
||||
private int mLastCallCommand = CallSpec.CALL_UNDEFINED;
|
||||
|
||||
@ -244,6 +262,8 @@ public class NotificationListener extends NotificationListenerService {
|
||||
filterLocal.addAction(ACTION_MUTE);
|
||||
filterLocal.addAction(ACTION_REPLY);
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filterLocal);
|
||||
createNotificationPictureCacheDirectory();
|
||||
cleanUpNotificationPictureProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -251,6 +271,7 @@ public class NotificationListener extends NotificationListenerService {
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
|
||||
notificationStack.clear();
|
||||
notificationsActive.clear();
|
||||
cleanUpNotificationPictureProvider();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@ -674,6 +695,41 @@ public class NotificationListener extends NotificationListenerService {
|
||||
notificationSpec.body = sanitizeUnicode(contentCS.toString());
|
||||
}
|
||||
|
||||
NotificationCompat.MessagingStyle messagingStyle = NotificationCompat.MessagingStyle.extractMessagingStyleFromNotification(notification);
|
||||
if (messagingStyle != null) {
|
||||
List<NotificationCompat.MessagingStyle.Message> messages = messagingStyle.getMessages();
|
||||
if (!messages.isEmpty()) {
|
||||
// Get the last message (assumed to be the most recent)
|
||||
NotificationCompat.MessagingStyle.Message lastMessage = messages.get(messages.size() - 1);
|
||||
|
||||
if (supportedPictureMimeTypes.contains(lastMessage.getDataMimeType())) {
|
||||
ContentResolver contentResolver = getContentResolver();
|
||||
try (Cursor cursor = contentResolver.query(lastMessage.getDataUri(), null, null, null, null)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
int dataIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
|
||||
notificationSpec.picturePath = cursor.getString(dataIndex);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (extras.containsKey(NotificationCompat.EXTRA_PICTURE)) {
|
||||
final Bitmap bmp = (Bitmap) extras.get(NotificationCompat.EXTRA_PICTURE);
|
||||
File pictureFile = new File(this.notificationPictureCacheDirectory, String.valueOf(notificationSpec.getId()));
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(pictureFile)) {
|
||||
bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
|
||||
notificationSpec.picturePath = pictureFile.getAbsolutePath();
|
||||
} catch (IOException e) {
|
||||
LOG.error("Failed to save picture to notification cache: {}", e.getMessage());
|
||||
} finally {
|
||||
bmp.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
if (notificationSpec.type == NotificationType.COL_REMINDER
|
||||
&& notificationSpec.body == null
|
||||
&& notificationSpec.title != null) {
|
||||
@ -792,6 +848,7 @@ public class NotificationListener extends NotificationListenerService {
|
||||
for (int notificationId : notificationsActive) {
|
||||
if (!activeNotificationsIds.contains(notificationId)) {
|
||||
notificationsToRemove.add(notificationId);
|
||||
deleteNotificationPicture(notificationId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -815,6 +872,27 @@ public class NotificationListener extends NotificationListenerService {
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteNotificationPicture(int notificationId) {
|
||||
File pictureFile = new File(this.notificationPictureCacheDirectory, String.valueOf(notificationId));
|
||||
if (pictureFile.exists())
|
||||
pictureFile.delete();
|
||||
}
|
||||
|
||||
private void cleanUpNotificationPictureProvider() {
|
||||
File[] pictureFiles = this.notificationPictureCacheDirectory.listFiles();
|
||||
if (pictureFiles == null)
|
||||
return;
|
||||
|
||||
for (File pictureFile : pictureFiles) {
|
||||
pictureFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
private void createNotificationPictureCacheDirectory() {
|
||||
final File cacheDir = getApplicationContext().getExternalCacheDir();
|
||||
this.notificationPictureCacheDirectory = new File(cacheDir, "notification-pictures");
|
||||
this.notificationPictureCacheDirectory.mkdir();
|
||||
}
|
||||
private void logNotification(StatusBarNotification sbn, boolean posted) {
|
||||
LOG.debug(
|
||||
"Notification {} {}: packageName={}, when={}, priority={}, category={}",
|
||||
|
@ -179,6 +179,7 @@ public class GBDeviceService implements DeviceService {
|
||||
.putExtra(EXTRA_NOTIFICATION_PEBBLE_COLOR, notificationSpec.pebbleColor)
|
||||
.putExtra(EXTRA_NOTIFICATION_SOURCEAPPID, notificationSpec.sourceAppId)
|
||||
.putExtra(EXTRA_NOTIFICATION_ICONID, notificationSpec.iconId)
|
||||
.putExtra(NOTIFICATION_PICTURE_PATH, notificationSpec.picturePath)
|
||||
.putExtra(EXTRA_NOTIFICATION_DNDSUPPRESSED, notificationSpec.dndSuppressed);
|
||||
invokeService(intent);
|
||||
}
|
||||
|
@ -99,6 +99,7 @@ public interface DeviceService extends EventHandler {
|
||||
String EXTRA_NOTIFICATION_ACTIONS = "notification_actions";
|
||||
String EXTRA_NOTIFICATION_PEBBLE_COLOR = "notification_pebble_color";
|
||||
String EXTRA_NOTIFICATION_ICONID = "notification_iconid";
|
||||
String NOTIFICATION_PICTURE_PATH = "notification_picture_path";
|
||||
String EXTRA_NOTIFICATION_DNDSUPPRESSED = "notification_dndsuppressed";
|
||||
String EXTRA_FIND_START = "find_start";
|
||||
String EXTRA_VIBRATION_INTENSITY = "vibration_intensity";
|
||||
|
@ -48,6 +48,7 @@ public class NotificationSpec {
|
||||
*/
|
||||
public int iconId;
|
||||
|
||||
public String picturePath;
|
||||
/**
|
||||
* The color that should be assigned to this notification when displayed on a Pebble
|
||||
*/
|
||||
|
@ -862,6 +862,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
|
||||
notificationSpec.flags = intentCopy.getIntExtra(EXTRA_NOTIFICATION_FLAGS, 0);
|
||||
notificationSpec.sourceAppId = intentCopy.getStringExtra(EXTRA_NOTIFICATION_SOURCEAPPID);
|
||||
notificationSpec.iconId = intentCopy.getIntExtra(EXTRA_NOTIFICATION_ICONID, 0);
|
||||
notificationSpec.picturePath = intent.getStringExtra(NOTIFICATION_PICTURE_PATH);
|
||||
notificationSpec.dndSuppressed = intentCopy.getIntExtra(EXTRA_NOTIFICATION_DNDSUPPRESSED, 0);
|
||||
|
||||
if (notificationSpec.type == NotificationType.GENERIC_SMS && notificationSpec.phoneNumber != null) {
|
||||
|
Loading…
Reference in New Issue
Block a user