From 0d201fe3e2c6e938166eb4d2aed9429a1207b1f6 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Tue, 18 Jul 2023 15:47:28 -0400 Subject: [PATCH 01/32] rename and move notification cache to its own file --- .../CustomNotificationProvider.java | 58 +++++++------------ .../NotificationCache.java | 30 ++++++++++ 2 files changed, 50 insertions(+), 38 deletions(-) create mode 100644 android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java index d7dff0ffcf0f..76cc1e32b519 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java @@ -49,6 +49,8 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; +import com.expensify.chat.customairshipextender.NotificationCache.NotificationData; + public class CustomNotificationProvider extends ReactNotificationProvider { // Resize icons to 100 dp x 100 dp private static final int MAX_ICON_SIZE_DPS = 100; @@ -71,7 +73,7 @@ public class CustomNotificationProvider extends ReactNotificationProvider { private static final String ONYX_DATA_KEY = "onyxData"; private final ExecutorService executorService = Executors.newCachedThreadPool(); - public final HashMap cache = new HashMap<>(); + public final HashMap cache = new HashMap<>(); public CustomNotificationProvider(@NonNull Context context, @NonNull AirshipConfigOptions configOptions) { super(context, configOptions); @@ -168,8 +170,8 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil } // Retrieve and check for cached notifications - NotificationCache notificationCache = findOrCreateNotificationCache(reportID); - boolean hasExistingNotification = notificationCache.messages.size() >= 1; + NotificationData notificationData = findOrCreateNotificationData(reportID); + boolean hasExistingNotification = notificationData.messages.size() >= 1; try { JsonMap reportMap = payload.get(ONYX_DATA_KEY).getList().get(1).getMap().get("value").getMap(); @@ -183,8 +185,8 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil String conversationName = payload.get("roomName") == null ? "" : payload.get("roomName").getString(""); // Retrieve or create the Person object who sent the latest report comment - Person person = notificationCache.people.get(accountID); - Bitmap personIcon = notificationCache.bitmapIcons.get(accountID); + Person person = notificationData.people.get(accountID); + Bitmap personIcon = notificationData.bitmapIcons.get(accountID); if (personIcon == null) { personIcon = fetchIcon(context, avatar); @@ -200,13 +202,13 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil .setName(name) .build(); - notificationCache.people.put(accountID, person); - notificationCache.bitmapIcons.put(accountID, personIcon); + notificationData.people.put(accountID, person); + notificationData.bitmapIcons.put(accountID, personIcon); } // Despite not using conversation style for the initial notification from each chat, we need to cache it to enable conversation style for future notifications long createdTimeInMillis = getMessageTimeInMillis(messageData.get("created").getString("")); - notificationCache.messages.add(new NotificationCache.Message(person, message, createdTimeInMillis)); + notificationData.messages.add(new NotificationData.Message(person, message, createdTimeInMillis)); // Conversational styling should be applied to groups chats, rooms, and any 1:1 chats with more than one notification (ensuring the large profile image is always shown) @@ -217,7 +219,7 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil .setConversationTitle(conversationName); // Add all conversation messages to the notification, including the last one we just received. - for (NotificationCache.Message cachedMessage : notificationCache.messages) { + for (NotificationData.Message cachedMessage : notificationData.messages) { messagingStyle.addMessage(cachedMessage.text, cachedMessage.time, cachedMessage.person); } builder.setStyle(messagingStyle); @@ -225,8 +227,8 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil // Clear the previous notification associated to this conversation so it looks like we are // replacing them with this new one we just built. - if (notificationCache.prevNotificationID != -1) { - NotificationManagerCompat.from(context).cancel(notificationCache.prevNotificationID); + if (notificationData.prevNotificationID != -1) { + NotificationManagerCompat.from(context).cancel(notificationData.prevNotificationID); } } catch (Exception e) { @@ -235,7 +237,7 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil // Store the new notification ID so we can replace the notification if this conversation // receives more messages - notificationCache.prevNotificationID = notificationID; + notificationData.prevNotificationID = notificationID; } /** @@ -262,15 +264,15 @@ private long getMessageTimeInMillis(String createdTime) { * @param reportID Report ID. * @return Notification Cache. */ - private NotificationCache findOrCreateNotificationCache(long reportID) { - NotificationCache notificationCache = cache.get(reportID); + private NotificationData findOrCreateNotificationData(long reportID) { + NotificationData notificationData = cache.get(reportID); - if (notificationCache == null) { - notificationCache = new NotificationCache(); - cache.put(reportID, notificationCache); + if (notificationData == null) { + notificationData = new NotificationData(); + cache.put(reportID, notificationData); } - return notificationCache; + return notificationData; } /** @@ -328,24 +330,4 @@ private Bitmap fetchIcon(@NonNull Context context, String urlString) { return null; } - - private static class NotificationCache { - public Map people = new HashMap<>(); - public ArrayList messages = new ArrayList<>(); - - public Map bitmapIcons = new HashMap<>(); - public int prevNotificationID = -1; - - public static class Message { - public Person person; - public String text; - public long time; - - Message(Person person, String text, long time) { - this.person = person; - this.text = text; - this.time = time; - } - } - } } diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java new file mode 100644 index 000000000000..fbe6e802722d --- /dev/null +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -0,0 +1,30 @@ +package com.expensify.chat.customairshipextender; + +import android.graphics.Bitmap; +import androidx.core.app.Person; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +public class NotificationCache { + public static class NotificationData { + public Map people = new HashMap<>(); + public ArrayList messages = new ArrayList<>(); + + public Map bitmapIcons = new HashMap<>(); + public int prevNotificationID = -1; + + public static class Message { + public Person person; + public String text; + public long time; + + Message(Person person, String text, long time) { + this.person = person; + this.text = text; + this.time = time; + } + } + } +} From f0d18112a011fed353c8d30f342fd3706e07ed87 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Tue, 18 Jul 2023 16:46:03 -0400 Subject: [PATCH 02/32] move notification cache hashmap over --- .../CustomNotificationProvider.java | 24 ++---------------- .../NotificationCache.java | 25 +++++++++++++++++++ 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java index 76cc1e32b519..a1080c507823 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java @@ -73,7 +73,6 @@ public class CustomNotificationProvider extends ReactNotificationProvider { private static final String ONYX_DATA_KEY = "onyxData"; private final ExecutorService executorService = Executors.newCachedThreadPool(); - public final HashMap cache = new HashMap<>(); public CustomNotificationProvider(@NonNull Context context, @NonNull AirshipConfigOptions configOptions) { super(context, configOptions); @@ -170,7 +169,7 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil } // Retrieve and check for cached notifications - NotificationData notificationData = findOrCreateNotificationData(reportID); + NotificationData notificationData = NotificationCache.getNotificationData(reportID); boolean hasExistingNotification = notificationData.messages.size() >= 1; try { @@ -256,25 +255,6 @@ private long getMessageTimeInMillis(String createdTime) { return Calendar.getInstance().getTimeInMillis(); } - /** - * Check if we are showing a notification related to a reportID. - * If not, create a new NotificationCache so we can build a conversation notification - * as the messages come. - * - * @param reportID Report ID. - * @return Notification Cache. - */ - private NotificationData findOrCreateNotificationData(long reportID) { - NotificationData notificationData = cache.get(reportID); - - if (notificationData == null) { - notificationData = new NotificationData(); - cache.put(reportID, notificationData); - } - - return notificationData; - } - /** * Remove the notification data from the cache when the user dismisses the notification. * @@ -289,7 +269,7 @@ public void onDismissNotification(PushMessage message) { return; } - cache.remove(reportID); + NotificationCache.setNotificationData(reportID, null); } catch (Exception e) { Log.e(TAG, "Failed to delete conversation cache. SendID=" + message.getSendId(), e); } diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index fbe6e802722d..98edaa4d3a92 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -8,6 +8,31 @@ import java.util.Map; public class NotificationCache { + + public static final HashMap cache = new HashMap<>(); + + /* + * Get NotificationData for an existing notification or create a new instance + * if it doesn't exist + */ + public static NotificationData getNotificationData(long reportID) { + NotificationData notificationData = cache.get(reportID); + + if (notificationData == null) { + notificationData = new NotificationData(); + setNotificationData(reportID, notificationData); + } + + return notificationData; + } + + /* + * Set and persist NotificationData in the cache + */ + public static void setNotificationData(long reportID, NotificationData data) { + cache.put(reportID, data); + } + public static class NotificationData { public Map people = new HashMap<>(); public ArrayList messages = new ArrayList<>(); From 5891d85c734c25b4999820cfebfdd0c44321ea78 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Wed, 19 Jul 2023 16:48:49 -0400 Subject: [PATCH 03/32] implement Parcelable for Message --- .../NotificationCache.java | 54 ++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index 98edaa4d3a92..fb874acd23e9 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -1,7 +1,13 @@ package com.expensify.chat.customairshipextender; import android.graphics.Bitmap; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; + +import androidx.annotation.NonNull; import androidx.core.app.Person; +import androidx.core.graphics.drawable.IconCompat; import java.util.ArrayList; import java.util.HashMap; @@ -40,7 +46,7 @@ public static class NotificationData { public Map bitmapIcons = new HashMap<>(); public int prevNotificationID = -1; - public static class Message { + public static class Message implements Parcelable { public Person person; public String text; public long time; @@ -50,6 +56,52 @@ public static class Message { this.text = text; this.time = time; } + + Message(Parcel parcel) { + this.person = convertToPerson(parcel.readBundle()); + this.text = parcel.readString(); + this.time = parcel.readLong(); + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int i) { + parcel.writeBundle(convertToBundle(person)); + parcel.writeString(text); + parcel.writeLong(time); + } + + @Override + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() + { + public Message createFromParcel(Parcel in) { + return new Message(in); + } + + @Override + public Object[] newArray(int size) { + return new Person[size]; + } + }; } } + + private static Bundle convertToBundle(Person p) { + Bundle bundle = new Bundle(); + bundle.putParcelable("icon", (Parcelable) p.getIcon()); + bundle.putString("key", p.getKey()); + bundle.putString("name", p.getName().toString()); + return bundle; + } + + private static Person convertToPerson(Bundle b) { + return new Person.Builder() + .setIcon((IconCompat) b.getParcelable("icon")) + .setKey(b.getString("key")) + .setName(b.getString("name")) + .build(); + } } From 9e3452dc78b8b083491dee81d1f812dba1e9de73 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Wed, 19 Jul 2023 18:05:03 -0400 Subject: [PATCH 04/32] convert hashmaps to bundles --- .../CustomNotificationProvider.java | 8 +++---- .../NotificationCache.java | 21 ++++++++++++++++--- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java index a1080c507823..50108cf5a84c 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java @@ -184,8 +184,8 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil String conversationName = payload.get("roomName") == null ? "" : payload.get("roomName").getString(""); // Retrieve or create the Person object who sent the latest report comment - Person person = notificationData.people.get(accountID); - Bitmap personIcon = notificationData.bitmapIcons.get(accountID); + Person person = notificationData.getPerson(accountID); + Bitmap personIcon = notificationData.getIcon(accountID); if (personIcon == null) { personIcon = fetchIcon(context, avatar); @@ -201,8 +201,8 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil .setName(name) .build(); - notificationData.people.put(accountID, person); - notificationData.bitmapIcons.put(accountID, personIcon); + notificationData.putPerson(accountID, person); + notificationData.putIcon(accountID, personIcon); } // Despite not using conversation style for the initial notification from each chat, we need to cache it to enable conversation style for future notifications diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index fb874acd23e9..3b97ee364e14 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -11,7 +11,6 @@ import java.util.ArrayList; import java.util.HashMap; -import java.util.Map; public class NotificationCache { @@ -40,12 +39,28 @@ public static void setNotificationData(long reportID, NotificationData data) { } public static class NotificationData { - public Map people = new HashMap<>(); + private final Bundle people = new Bundle(); + private final Bundle icons = new Bundle(); public ArrayList messages = new ArrayList<>(); - public Map bitmapIcons = new HashMap<>(); public int prevNotificationID = -1; + public Person getPerson(String accountID) { + return convertToPerson(people.getParcelable(accountID)); + } + + public void putPerson(String accountID, Person person) { + people.putParcelable(accountID, convertToBundle(person)); + } + + public Bitmap getIcon(String accountID) { + return icons.getParcelable(accountID); + } + + public void putIcon(String accountID, Bitmap bitmap) { + icons.putParcelable(accountID, bitmap); + } + public static class Message implements Parcelable { public Person person; public String text; From 43893e28e799bda33abad8b354b25af19c7080fb Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Wed, 19 Jul 2023 18:06:28 -0400 Subject: [PATCH 05/32] fix bundling Person objects by converting icon to bundle --- .../chat/customairshipextender/NotificationCache.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index 3b97ee364e14..34b8fc1cfc5f 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -106,7 +106,7 @@ public Object[] newArray(int size) { private static Bundle convertToBundle(Person p) { Bundle bundle = new Bundle(); - bundle.putParcelable("icon", (Parcelable) p.getIcon()); + bundle.putBundle("icon", p.getIcon().toBundle()); bundle.putString("key", p.getKey()); bundle.putString("name", p.getName().toString()); return bundle; @@ -114,7 +114,7 @@ private static Bundle convertToBundle(Person p) { private static Person convertToPerson(Bundle b) { return new Person.Builder() - .setIcon((IconCompat) b.getParcelable("icon")) + .setIcon(IconCompat.createFromBundle(b.getBundle("icon"))) .setKey(b.getString("key")) .setName(b.getString("name")) .build(); From 05cb4765666e58296e6870e962f52375e72c1f7d Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Wed, 19 Jul 2023 18:06:49 -0400 Subject: [PATCH 06/32] safety check --- .../chat/customairshipextender/NotificationCache.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index 34b8fc1cfc5f..7955b6cb6365 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -113,6 +113,10 @@ private static Bundle convertToBundle(Person p) { } private static Person convertToPerson(Bundle b) { + if (b == null) { + return null; + } + return new Person.Builder() .setIcon(IconCompat.createFromBundle(b.getBundle("icon"))) .setKey(b.getString("key")) From 56a1dc1e32fd0e38643b41a567be4026b3a91b48 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Thu, 20 Jul 2023 15:44:36 -0400 Subject: [PATCH 07/32] rename and lift NotificationMessage out of NotificationData to fix static/non-static references --- .../CustomNotificationProvider.java | 5 +- .../NotificationCache.java | 72 +++++++++---------- 2 files changed, 39 insertions(+), 38 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java index 50108cf5a84c..ca267d78bc11 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java @@ -50,6 +50,7 @@ import java.util.concurrent.TimeUnit; import com.expensify.chat.customairshipextender.NotificationCache.NotificationData; +import com.expensify.chat.customairshipextender.NotificationCache.NotificationMessage; public class CustomNotificationProvider extends ReactNotificationProvider { // Resize icons to 100 dp x 100 dp @@ -207,7 +208,7 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil // Despite not using conversation style for the initial notification from each chat, we need to cache it to enable conversation style for future notifications long createdTimeInMillis = getMessageTimeInMillis(messageData.get("created").getString("")); - notificationData.messages.add(new NotificationData.Message(person, message, createdTimeInMillis)); + notificationData.messages.add(new NotificationMessage(person, message, createdTimeInMillis)); // Conversational styling should be applied to groups chats, rooms, and any 1:1 chats with more than one notification (ensuring the large profile image is always shown) @@ -218,7 +219,7 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil .setConversationTitle(conversationName); // Add all conversation messages to the notification, including the last one we just received. - for (NotificationData.Message cachedMessage : notificationData.messages) { + for (NotificationMessage cachedMessage : notificationData.messages) { messagingStyle.addMessage(cachedMessage.text, cachedMessage.time, cachedMessage.person); } builder.setStyle(messagingStyle); diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index 7955b6cb6365..a5a8f4132edf 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -14,7 +14,7 @@ public class NotificationCache { - public static final HashMap cache = new HashMap<>(); + private static final HashMap cache = new HashMap<>(); /* * Get NotificationData for an existing notification or create a new instance @@ -41,7 +41,7 @@ public static void setNotificationData(long reportID, NotificationData data) { public static class NotificationData { private final Bundle people = new Bundle(); private final Bundle icons = new Bundle(); - public ArrayList messages = new ArrayList<>(); + public ArrayList messages = new ArrayList<>(); public int prevNotificationID = -1; @@ -60,48 +60,48 @@ public Bitmap getIcon(String accountID) { public void putIcon(String accountID, Bitmap bitmap) { icons.putParcelable(accountID, bitmap); } + } - public static class Message implements Parcelable { - public Person person; - public String text; - public long time; + public static class NotificationMessage implements Parcelable { + public Person person; + public String text; + public long time; - Message(Person person, String text, long time) { - this.person = person; - this.text = text; - this.time = time; - } + NotificationMessage(Person person, String text, long time) { + this.person = person; + this.text = text; + this.time = time; + } - Message(Parcel parcel) { - this.person = convertToPerson(parcel.readBundle()); - this.text = parcel.readString(); - this.time = parcel.readLong(); - } + NotificationMessage(Parcel parcel) { + this.person = convertToPerson(parcel.readBundle()); + this.text = parcel.readString(); + this.time = parcel.readLong(); + } - @Override - public void writeToParcel(@NonNull Parcel parcel, int i) { - parcel.writeBundle(convertToBundle(person)); - parcel.writeString(text); - parcel.writeLong(time); + @Override + public void writeToParcel(@NonNull Parcel parcel, int i) { + parcel.writeBundle(convertToBundle(person)); + parcel.writeString(text); + parcel.writeLong(time); + } + + @Override + public int describeContents() { + return 0; + } + + public final Parcelable.Creator CREATOR = new Parcelable.Creator() + { + public NotificationMessage createFromParcel(Parcel in) { + return new NotificationMessage(in); } @Override - public int describeContents() { - return 0; + public Object[] newArray(int size) { + return new Person[size]; } - - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() - { - public Message createFromParcel(Parcel in) { - return new Message(in); - } - - @Override - public Object[] newArray(int size) { - return new Person[size]; - } - }; - } + }; } private static Bundle convertToBundle(Person p) { From 3bf3bf5b7a645e6c8a7fdf16c5a70a36f9dd4b32 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Thu, 20 Jul 2023 16:01:46 -0400 Subject: [PATCH 08/32] fix parcelable creator for NotificationMessage --- .../chat/customairshipextender/NotificationCache.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index a5a8f4132edf..aa780b6df7eb 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -91,15 +91,15 @@ public int describeContents() { return 0; } - public final Parcelable.Creator CREATOR = new Parcelable.Creator() + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public NotificationMessage createFromParcel(Parcel in) { return new NotificationMessage(in); } @Override - public Object[] newArray(int size) { - return new Person[size]; + public NotificationMessage[] newArray(int size) { + return new NotificationMessage[size]; } }; } From e643107a06096d8691304a2e06a34679d98cced8 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Thu, 20 Jul 2023 16:14:24 -0400 Subject: [PATCH 09/32] implement parcelable for NotificationData --- .../NotificationCache.java | 43 ++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index aa780b6df7eb..315df663ce72 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -38,13 +38,47 @@ public static void setNotificationData(long reportID, NotificationData data) { cache.put(reportID, data); } - public static class NotificationData { - private final Bundle people = new Bundle(); - private final Bundle icons = new Bundle(); + public static class NotificationData implements Parcelable { + private Bundle people = new Bundle(); + private Bundle icons = new Bundle(); public ArrayList messages = new ArrayList<>(); public int prevNotificationID = -1; + public NotificationData() { + } + + protected NotificationData(Parcel parcel) { + people = parcel.readBundle(); + icons = parcel.readBundle(); + messages = parcel.createTypedArrayList(NotificationMessage.CREATOR); + prevNotificationID = parcel.readInt(); + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int i) { + parcel.writeBundle(people); + parcel.writeBundle(icons); + parcel.writeList(messages); + } + + @Override + public int describeContents() { + return 0; + } + + public static final Creator CREATOR = new Creator() { + @Override + public NotificationData createFromParcel(Parcel in) { + return new NotificationData(in); + } + + @Override + public NotificationData[] newArray(int size) { + return new NotificationData[size]; + } + }; + public Person getPerson(String accountID) { return convertToPerson(people.getParcelable(accountID)); } @@ -91,8 +125,7 @@ public int describeContents() { return 0; } - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() - { + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public NotificationMessage createFromParcel(Parcel in) { return new NotificationMessage(in); } From 5ef1f639d467aa1b12dd7604fa5c0c77dd29f7bd Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Thu, 20 Jul 2023 16:38:18 -0400 Subject: [PATCH 10/32] convert cache to Bundle --- .../chat/customairshipextender/NotificationCache.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index 315df663ce72..98ecffa7cb6f 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -14,14 +14,14 @@ public class NotificationCache { - private static final HashMap cache = new HashMap<>(); + private static final Bundle cache = new Bundle(); /* * Get NotificationData for an existing notification or create a new instance * if it doesn't exist */ public static NotificationData getNotificationData(long reportID) { - NotificationData notificationData = cache.get(reportID); + NotificationData notificationData = cache.getParcelable(Long.toString(reportID)); if (notificationData == null) { notificationData = new NotificationData(); @@ -35,7 +35,7 @@ public static NotificationData getNotificationData(long reportID) { * Set and persist NotificationData in the cache */ public static void setNotificationData(long reportID, NotificationData data) { - cache.put(reportID, data); + cache.putParcelable(Long.toString(reportID), data); } public static class NotificationData implements Parcelable { From 43dfbc606338334f54ab8ac670f40a24ecbc5952 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Thu, 20 Jul 2023 17:33:39 -0400 Subject: [PATCH 11/32] add helper for writing cache to file --- .../NotificationCache.java | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index 98ecffa7cb6f..52f277aaded4 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -1,5 +1,6 @@ package com.expensify.chat.customairshipextender; +import android.content.Context; import android.graphics.Bitmap; import android.os.Bundle; import android.os.Parcel; @@ -9,8 +10,10 @@ import androidx.core.app.Person; import androidx.core.graphics.drawable.IconCompat; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; import java.util.ArrayList; -import java.util.HashMap; public class NotificationCache { @@ -38,6 +41,29 @@ public static void setNotificationData(long reportID, NotificationData data) { cache.putParcelable(Long.toString(reportID), data); } + private static void writeToInternalStorage(Context context) { + Parcel parcel = Parcel.obtain(); + parcel.writeBundle(cache); + + FileOutputStream output = null; + try { + File file = new File(context.getFilesDir(), "notification-cache"); + output = new FileOutputStream(file); + output.write(parcel.marshall()); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (output != null) { + output.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + parcel.recycle(); + } + } + public static class NotificationData implements Parcelable { private Bundle people = new Bundle(); private Bundle icons = new Bundle(); From 949fb1c2a1cc250fdba5bdc10346ab0022ffcc66 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Mon, 24 Jul 2023 17:09:10 -0400 Subject: [PATCH 12/32] encode bitmaps so we can marshal the final parcel to bytes --- .../NotificationCache.java | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index 52f277aaded4..ce6117c57f92 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -114,11 +114,31 @@ public void putPerson(String accountID, Person person) { } public Bitmap getIcon(String accountID) { - return icons.getParcelable(accountID); + return decodeToBitmap(icons.getString(accountID)); } public void putIcon(String accountID, Bitmap bitmap) { - icons.putParcelable(accountID, bitmap); + icons.putString(accountID, encodeTobase64(bitmap)); + } + + public static String encodeTobase64(Bitmap bitmap) { + if (bitmap == null) { + return ""; + } + + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream); + byte[] byteArray = byteArrayOutputStream.toByteArray(); + return Base64.encodeToString(byteArray, Base64.DEFAULT); + } + + public static Bitmap decodeToBitmap(String base64String) { + if (base64String == null) { + return null; + } + + byte[] decodedBytes = Base64.decode(base64String, Base64.DEFAULT); + return BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length); } } From 6fa2aacd95ef8e5e2b2ccaa203cbd8b01bf72699 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Fri, 28 Jul 2023 14:24:18 -0400 Subject: [PATCH 13/32] de-dupe person reference --- .../CustomNotificationProvider.java | 4 ++-- .../chat/customairshipextender/NotificationCache.java | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java index ca267d78bc11..b951ced71a23 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java @@ -208,7 +208,7 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil // Despite not using conversation style for the initial notification from each chat, we need to cache it to enable conversation style for future notifications long createdTimeInMillis = getMessageTimeInMillis(messageData.get("created").getString("")); - notificationData.messages.add(new NotificationMessage(person, message, createdTimeInMillis)); + notificationData.messages.add(new NotificationMessage(accountID, message, createdTimeInMillis)); // Conversational styling should be applied to groups chats, rooms, and any 1:1 chats with more than one notification (ensuring the large profile image is always shown) @@ -220,7 +220,7 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil // Add all conversation messages to the notification, including the last one we just received. for (NotificationMessage cachedMessage : notificationData.messages) { - messagingStyle.addMessage(cachedMessage.text, cachedMessage.time, cachedMessage.person); + messagingStyle.addMessage(cachedMessage.text, cachedMessage.time, notificationData.getPerson(cachedMessage.accountID)); } builder.setStyle(messagingStyle); } diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index ce6117c57f92..72c2b2868162 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -143,25 +143,25 @@ public static Bitmap decodeToBitmap(String base64String) { } public static class NotificationMessage implements Parcelable { - public Person person; + public String accountID; public String text; public long time; - NotificationMessage(Person person, String text, long time) { - this.person = person; + NotificationMessage(String accountID, String text, long time) { + this.accountID = accountID; this.text = text; this.time = time; } NotificationMessage(Parcel parcel) { - this.person = convertToPerson(parcel.readBundle()); + this.accountID = parcel.readString(); this.text = parcel.readString(); this.time = parcel.readLong(); } @Override public void writeToParcel(@NonNull Parcel parcel, int i) { - parcel.writeBundle(convertToBundle(person)); + parcel.writeString(accountID); parcel.writeString(text); parcel.writeLong(time); } From 907fb2e5d02b5f1b5174778b24ee78652f9a074f Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Fri, 28 Jul 2023 14:38:37 -0400 Subject: [PATCH 14/32] use Serializable instead --- .../NotificationCache.java | 31 +------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index 72c2b2868162..51b996053a16 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -142,7 +142,7 @@ public static Bitmap decodeToBitmap(String base64String) { } } - public static class NotificationMessage implements Parcelable { + public static class NotificationMessage implements Serializable { public String accountID; public String text; public long time; @@ -152,35 +152,6 @@ public static class NotificationMessage implements Parcelable { this.text = text; this.time = time; } - - NotificationMessage(Parcel parcel) { - this.accountID = parcel.readString(); - this.text = parcel.readString(); - this.time = parcel.readLong(); - } - - @Override - public void writeToParcel(@NonNull Parcel parcel, int i) { - parcel.writeString(accountID); - parcel.writeString(text); - parcel.writeLong(time); - } - - @Override - public int describeContents() { - return 0; - } - - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public NotificationMessage createFromParcel(Parcel in) { - return new NotificationMessage(in); - } - - @Override - public NotificationMessage[] newArray(int size) { - return new NotificationMessage[size]; - } - }; } private static Bundle convertToBundle(Person p) { From 5170132a66e9b09a9194bf43c6f430383886dcc1 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Fri, 28 Jul 2023 14:45:11 -0400 Subject: [PATCH 15/32] switch back to Serializable --- .../NotificationCache.java | 33 +------------------ 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index 51b996053a16..5f4a1645938a 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -64,7 +64,7 @@ private static void writeToInternalStorage(Context context) { } } - public static class NotificationData implements Parcelable { + public static class NotificationData implements Serializable { private Bundle people = new Bundle(); private Bundle icons = new Bundle(); public ArrayList messages = new ArrayList<>(); @@ -74,37 +74,6 @@ public static class NotificationData implements Parcelable { public NotificationData() { } - protected NotificationData(Parcel parcel) { - people = parcel.readBundle(); - icons = parcel.readBundle(); - messages = parcel.createTypedArrayList(NotificationMessage.CREATOR); - prevNotificationID = parcel.readInt(); - } - - @Override - public void writeToParcel(@NonNull Parcel parcel, int i) { - parcel.writeBundle(people); - parcel.writeBundle(icons); - parcel.writeList(messages); - } - - @Override - public int describeContents() { - return 0; - } - - public static final Creator CREATOR = new Creator() { - @Override - public NotificationData createFromParcel(Parcel in) { - return new NotificationData(in); - } - - @Override - public NotificationData[] newArray(int size) { - return new NotificationData[size]; - } - }; - public Person getPerson(String accountID) { return convertToPerson(people.getParcelable(accountID)); } From 17b882db1fa1c7c0c45373412c5ce8d212b1fcc2 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Fri, 28 Jul 2023 14:54:13 -0400 Subject: [PATCH 16/32] switch back to hashmaps in NotificationData --- .../CustomNotificationProvider.java | 10 ++++---- .../NotificationCache.java | 25 ++++++------------- 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java index b951ced71a23..356551b6db75 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java @@ -185,8 +185,8 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil String conversationName = payload.get("roomName") == null ? "" : payload.get("roomName").getString(""); // Retrieve or create the Person object who sent the latest report comment - Person person = notificationData.getPerson(accountID); - Bitmap personIcon = notificationData.getIcon(accountID); + Person person = notificationData.people.get(accountID); + Bitmap personIcon = notificationData.icons.get(accountID); if (personIcon == null) { personIcon = fetchIcon(context, avatar); @@ -202,8 +202,8 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil .setName(name) .build(); - notificationData.putPerson(accountID, person); - notificationData.putIcon(accountID, personIcon); + notificationData.people.put(accountID, person); + notificationData.icons.put(accountID, personIcon); } // Despite not using conversation style for the initial notification from each chat, we need to cache it to enable conversation style for future notifications @@ -220,7 +220,7 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil // Add all conversation messages to the notification, including the last one we just received. for (NotificationMessage cachedMessage : notificationData.messages) { - messagingStyle.addMessage(cachedMessage.text, cachedMessage.time, notificationData.getPerson(cachedMessage.accountID)); + messagingStyle.addMessage(cachedMessage.text, cachedMessage.time, notificationData.people.get(cachedMessage.accountID)); } builder.setStyle(messagingStyle); } diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index 5f4a1645938a..9aede6b97cca 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -2,18 +2,23 @@ import android.content.Context; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import android.util.Base64; import androidx.annotation.NonNull; import androidx.core.app.Person; import androidx.core.graphics.drawable.IconCompat; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.io.Serializable; import java.util.ArrayList; +import java.util.HashMap; public class NotificationCache { @@ -65,8 +70,8 @@ private static void writeToInternalStorage(Context context) { } public static class NotificationData implements Serializable { - private Bundle people = new Bundle(); - private Bundle icons = new Bundle(); + public HashMap people = new HashMap(); + public HashMap icons = new HashMap(); public ArrayList messages = new ArrayList<>(); public int prevNotificationID = -1; @@ -74,22 +79,6 @@ public static class NotificationData implements Serializable { public NotificationData() { } - public Person getPerson(String accountID) { - return convertToPerson(people.getParcelable(accountID)); - } - - public void putPerson(String accountID, Person person) { - people.putParcelable(accountID, convertToBundle(person)); - } - - public Bitmap getIcon(String accountID) { - return decodeToBitmap(icons.getString(accountID)); - } - - public void putIcon(String accountID, Bitmap bitmap) { - icons.putString(accountID, encodeTobase64(bitmap)); - } - public static String encodeTobase64(Bitmap bitmap) { if (bitmap == null) { return ""; From 46687de29668b47e4372c5409f4cc3a818ee9ac9 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Fri, 28 Jul 2023 15:04:39 -0400 Subject: [PATCH 17/32] switch cache back to HashMap --- .../NotificationCache.java | 35 +++---------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index 9aede6b97cca..2cd10402b06a 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -1,35 +1,28 @@ package com.expensify.chat.customairshipextender; -import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; -import android.os.Parcel; -import android.os.Parcelable; import android.util.Base64; -import androidx.annotation.NonNull; import androidx.core.app.Person; import androidx.core.graphics.drawable.IconCompat; import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; public class NotificationCache { - private static final Bundle cache = new Bundle(); + private static final HashMap cache = new HashMap(); /* * Get NotificationData for an existing notification or create a new instance * if it doesn't exist */ public static NotificationData getNotificationData(long reportID) { - NotificationData notificationData = cache.getParcelable(Long.toString(reportID)); + NotificationData notificationData = cache.get(Long.toString(reportID)); if (notificationData == null) { notificationData = new NotificationData(); @@ -43,30 +36,10 @@ public static NotificationData getNotificationData(long reportID) { * Set and persist NotificationData in the cache */ public static void setNotificationData(long reportID, NotificationData data) { - cache.putParcelable(Long.toString(reportID), data); + cache.put(Long.toString(reportID), data); } - private static void writeToInternalStorage(Context context) { - Parcel parcel = Parcel.obtain(); - parcel.writeBundle(cache); - - FileOutputStream output = null; - try { - File file = new File(context.getFilesDir(), "notification-cache"); - output = new FileOutputStream(file); - output.write(parcel.marshall()); - } catch (IOException e) { - e.printStackTrace(); - } finally { - try { - if (output != null) { - output.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } - parcel.recycle(); - } + private static void writeToInternalStorage() { } public static class NotificationData implements Serializable { From e03a51c8211c096110f009b245ac981e23d1e64c Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Fri, 28 Jul 2023 16:03:28 -0400 Subject: [PATCH 18/32] write the cache to internal storage --- .../CustomNotificationProvider.java | 2 ++ .../NotificationCache.java | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java index 356551b6db75..ec65ab0f1944 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java @@ -238,6 +238,8 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil // Store the new notification ID so we can replace the notification if this conversation // receives more messages notificationData.prevNotificationID = notificationID; + + NotificationCache.setNotificationData(reportID, notificationData); } /** diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index 2cd10402b06a..88ad31d3874c 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -1,5 +1,6 @@ package com.expensify.chat.customairshipextender; +import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; @@ -8,7 +9,13 @@ import androidx.core.app.Person; import androidx.core.graphics.drawable.IconCompat; +import com.expensify.chat.MainApplication; + import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; @@ -37,9 +44,23 @@ public static NotificationData getNotificationData(long reportID) { */ public static void setNotificationData(long reportID, NotificationData data) { cache.put(Long.toString(reportID), data); + writeToInternalStorage(); } private static void writeToInternalStorage() { + Context context = MainApplication.getContext(); + try { + File outputFile = new File(context.getFilesDir(), "notification-cache"); + FileOutputStream fos = new FileOutputStream(outputFile); + ObjectOutputStream oos = new ObjectOutputStream(fos); + + oos.writeObject(cache); + + oos.close(); + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } } public static class NotificationData implements Serializable { From dd8f47c40602b437b3a3aa36b76e2dbef70474e7 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Fri, 28 Jul 2023 16:04:03 -0400 Subject: [PATCH 19/32] encode bitmap to string so it's serializable --- .../CustomNotificationProvider.java | 4 +-- .../NotificationCache.java | 31 ++++++------------- 2 files changed, 11 insertions(+), 24 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java index ec65ab0f1944..09cad85abdfc 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java @@ -186,7 +186,7 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil // Retrieve or create the Person object who sent the latest report comment Person person = notificationData.people.get(accountID); - Bitmap personIcon = notificationData.icons.get(accountID); + Bitmap personIcon = notificationData.getIcon(accountID); if (personIcon == null) { personIcon = fetchIcon(context, avatar); @@ -203,7 +203,7 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil .build(); notificationData.people.put(accountID, person); - notificationData.icons.put(accountID, personIcon); + notificationData.putIcon(accountID, personIcon); } // Despite not using conversation style for the initial notification from each chat, we need to cache it to enable conversation style for future notifications diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index 88ad31d3874c..ce7ea0617697 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -65,12 +65,19 @@ private static void writeToInternalStorage() { public static class NotificationData implements Serializable { public HashMap people = new HashMap(); - public HashMap icons = new HashMap(); + private HashMap icons = new HashMap(); public ArrayList messages = new ArrayList<>(); public int prevNotificationID = -1; - public NotificationData() { + public NotificationData() {} + + public Bitmap getIcon(String accountID) { + return decodeToBitmap(icons.get(accountID)); + } + + public void putIcon(String accountID, Bitmap bitmap) { + icons.put(accountID, encodeTobase64(bitmap)); } public static String encodeTobase64(Bitmap bitmap) { @@ -105,24 +112,4 @@ public static class NotificationMessage implements Serializable { this.time = time; } } - - private static Bundle convertToBundle(Person p) { - Bundle bundle = new Bundle(); - bundle.putBundle("icon", p.getIcon().toBundle()); - bundle.putString("key", p.getKey()); - bundle.putString("name", p.getName().toString()); - return bundle; - } - - private static Person convertToPerson(Bundle b) { - if (b == null) { - return null; - } - - return new Person.Builder() - .setIcon(IconCompat.createFromBundle(b.getBundle("icon"))) - .setKey(b.getString("key")) - .setName(b.getString("name")) - .build(); - } } From 1e06cf04e1343df4e2f818ea9a90dd936972a22d Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Fri, 28 Jul 2023 16:23:58 -0400 Subject: [PATCH 20/32] persist just the person name to make it serializable --- .../CustomNotificationProvider.java | 7 ++-- .../NotificationCache.java | 32 ++++++++++++++++++- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java index 09cad85abdfc..0ba77f809b19 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java @@ -185,7 +185,7 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil String conversationName = payload.get("roomName") == null ? "" : payload.get("roomName").getString(""); // Retrieve or create the Person object who sent the latest report comment - Person person = notificationData.people.get(accountID); + Person person = notificationData.getPerson(accountID); Bitmap personIcon = notificationData.getIcon(accountID); if (personIcon == null) { @@ -202,8 +202,7 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil .setName(name) .build(); - notificationData.people.put(accountID, person); - notificationData.putIcon(accountID, personIcon); + notificationData.putPerson(accountID, name, personIcon); } // Despite not using conversation style for the initial notification from each chat, we need to cache it to enable conversation style for future notifications @@ -220,7 +219,7 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil // Add all conversation messages to the notification, including the last one we just received. for (NotificationMessage cachedMessage : notificationData.messages) { - messagingStyle.addMessage(cachedMessage.text, cachedMessage.time, notificationData.people.get(cachedMessage.accountID)); + messagingStyle.addMessage(cachedMessage.text, cachedMessage.time, notificationData.getPerson(cachedMessage.accountID)); } builder.setStyle(messagingStyle); } diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index ce7ea0617697..ca5123141657 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -64,7 +64,7 @@ private static void writeToInternalStorage() { } public static class NotificationData implements Serializable { - public HashMap people = new HashMap(); + private HashMap names = new HashMap(); private HashMap icons = new HashMap(); public ArrayList messages = new ArrayList<>(); @@ -80,6 +80,26 @@ public void putIcon(String accountID, Bitmap bitmap) { icons.put(accountID, encodeTobase64(bitmap)); } + public Person getPerson(String accountID) { + if (!names.containsKey(accountID) || !icons.containsKey(accountID)) { + return null; + } + + String name = names.get(accountID); + Bitmap icon = getIcon(accountID); + + return new Person.Builder() + .setIcon(IconCompat.createWithBitmap(icon)) + .setKey(accountID) + .setName(name) + .build(); + } + + public void putPerson(String accountID, String name, Bitmap icon) { + names.put(accountID, name); + icons.put(accountID, encodeTobase64(icon)); + } + public static String encodeTobase64(Bitmap bitmap) { if (bitmap == null) { return ""; @@ -112,4 +132,14 @@ public static class NotificationMessage implements Serializable { this.time = time; } } + + public static class NotificationPerson implements Serializable { + public String accountID; + public String name; + + public NotificationPerson(String accountID, String name) { + this.accountID = accountID; + this.name = name; + } + } } From 3704944f6e37249ecad91d193dbc66b55a15bd2a Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Fri, 28 Jul 2023 16:40:08 -0400 Subject: [PATCH 21/32] read cache from storage when it's null --- .../NotificationCache.java | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index ca5123141657..844af80d7835 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -3,7 +3,6 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.os.Bundle; import android.util.Base64; import androidx.core.app.Person; @@ -13,8 +12,10 @@ import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.ArrayList; @@ -22,13 +23,17 @@ public class NotificationCache { - private static final HashMap cache = new HashMap(); + private static HashMap cache = null; /* * Get NotificationData for an existing notification or create a new instance * if it doesn't exist */ public static NotificationData getNotificationData(long reportID) { + if (cache == null) { + cache = readFromInternalStorage(); + } + NotificationData notificationData = cache.get(Long.toString(reportID)); if (notificationData == null) { @@ -63,6 +68,26 @@ private static void writeToInternalStorage() { } } + private static HashMap readFromInternalStorage() { + HashMap result; + Context context = MainApplication.getContext(); + try { + File fileCache = new File(context.getFilesDir(), "notification-cache"); + FileInputStream fis = new FileInputStream(fileCache); + ObjectInputStream ois = new ObjectInputStream(fis); + + result = (HashMap) ois.readObject(); + + ois.close(); + fis.close(); + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); + result = new HashMap<>(); + } + + return result; + } + public static class NotificationData implements Serializable { private HashMap names = new HashMap(); private HashMap icons = new HashMap(); From 6189be7b09d62749b6802b61e1045a39ac1d68f4 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Fri, 28 Jul 2023 16:41:33 -0400 Subject: [PATCH 22/32] save a static reference for application context --- .../main/java/com/expensify/chat/MainApplication.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/android/app/src/main/java/com/expensify/chat/MainApplication.java b/android/app/src/main/java/com/expensify/chat/MainApplication.java index a4f2bc97416d..b53b966d60d4 100644 --- a/android/app/src/main/java/com/expensify/chat/MainApplication.java +++ b/android/app/src/main/java/com/expensify/chat/MainApplication.java @@ -18,10 +18,12 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.util.List; public class MainApplication extends MultiDexApplication implements ReactApplication { + + private static Context context = null; + private final ReactNativeHost mReactNativeHost = new DefaultReactNativeHost(this) { @Override @@ -67,6 +69,8 @@ public ReactNativeHost getReactNativeHost() { public void onCreate() { super.onCreate(); + context = getApplicationContext(); + // Use night (dark) mode so native UI defaults to dark theme. AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); @@ -99,4 +103,8 @@ public void onCreate() { e.printStackTrace(); } } + + public static Context getContext() { + return context; + } } \ No newline at end of file From 38f55c0d549832b4e82b874fa21cc0bccb9978ad Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Fri, 28 Jul 2023 16:45:55 -0400 Subject: [PATCH 23/32] restore the cache on set as well --- .../chat/customairshipextender/NotificationCache.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index 844af80d7835..f57e12d7ed97 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -48,6 +48,10 @@ public static NotificationData getNotificationData(long reportID) { * Set and persist NotificationData in the cache */ public static void setNotificationData(long reportID, NotificationData data) { + if (cache == null) { + cache = readFromInternalStorage(); + } + cache.put(Long.toString(reportID), data); writeToInternalStorage(); } From 93fa41e55104d1c4dfaf5de592db073f1c8b8361 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Fri, 28 Jul 2023 16:55:47 -0400 Subject: [PATCH 24/32] handle the notification getting dismissed on open --- .../customairshipextender/CustomNotificationListener.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationListener.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationListener.java index 514e5aca14a0..8149ca118d58 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationListener.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationListener.java @@ -26,6 +26,10 @@ public void onNotificationPosted(@NonNull @NotNull NotificationInfo notification @Override public boolean onNotificationOpened(@NonNull @NotNull NotificationInfo notificationInfo) { + // The notification is also dismissed when it's tapped so handle that as well + PushMessage message = notificationInfo.getMessage(); + provider.onDismissNotification(message); + return parent.onNotificationOpened(notificationInfo); } From 32f2027a52a3b0dc76d49e4ffeaa0edc4da595a1 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Fri, 28 Jul 2023 16:57:37 -0400 Subject: [PATCH 25/32] use constant for cache file name --- .../chat/customairshipextender/NotificationCache.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index f57e12d7ed97..2b6396642047 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -23,6 +23,7 @@ public class NotificationCache { + private static final String CACHE_FILE_NAME = "notification-cache"; private static HashMap cache = null; /* @@ -59,7 +60,7 @@ public static void setNotificationData(long reportID, NotificationData data) { private static void writeToInternalStorage() { Context context = MainApplication.getContext(); try { - File outputFile = new File(context.getFilesDir(), "notification-cache"); + File outputFile = new File(context.getFilesDir(), CACHE_FILE_NAME); FileOutputStream fos = new FileOutputStream(outputFile); ObjectOutputStream oos = new ObjectOutputStream(fos); @@ -76,7 +77,7 @@ private static HashMap readFromInternalStorage() { HashMap result; Context context = MainApplication.getContext(); try { - File fileCache = new File(context.getFilesDir(), "notification-cache"); + File fileCache = new File(context.getFilesDir(), CACHE_FILE_NAME); FileInputStream fis = new FileInputStream(fileCache); ObjectInputStream ois = new ObjectInputStream(fis); From 887b1bc6fbd040da46798c9c8e6eb2b63e259322 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Fri, 28 Jul 2023 17:03:30 -0400 Subject: [PATCH 26/32] add comment explaining encoded bitmaps --- .../chat/customairshipextender/NotificationCache.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index 2b6396642047..3295b74c1368 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -95,6 +95,9 @@ private static HashMap readFromInternalStorage() { public static class NotificationData implements Serializable { private HashMap names = new HashMap(); + + // A map of accountID => base64 encoded Bitmap + // In order to make Bitmaps serializable, we encode them as base64 strings private HashMap icons = new HashMap(); public ArrayList messages = new ArrayList<>(); From e7188b8cf6e493f065c3dad6f707bc4c30f97f75 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Fri, 28 Jul 2023 17:05:17 -0400 Subject: [PATCH 27/32] remove unused data class --- .../chat/customairshipextender/NotificationCache.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index 3295b74c1368..9219296a2f5f 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -165,14 +165,4 @@ public static class NotificationMessage implements Serializable { this.time = time; } } - - public static class NotificationPerson implements Serializable { - public String accountID; - public String name; - - public NotificationPerson(String accountID, String name) { - this.accountID = accountID; - this.name = name; - } - } } From 6df512d623b8bfc6f63b8b3fdb08abb4e9b04d80 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Fri, 28 Jul 2023 17:18:07 -0400 Subject: [PATCH 28/32] linter suggestions --- .../chat/customairshipextender/NotificationCache.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index 9219296a2f5f..e8b3fc40b19b 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -94,11 +94,11 @@ private static HashMap readFromInternalStorage() { } public static class NotificationData implements Serializable { - private HashMap names = new HashMap(); + private final HashMap names = new HashMap<>(); // A map of accountID => base64 encoded Bitmap // In order to make Bitmaps serializable, we encode them as base64 strings - private HashMap icons = new HashMap(); + private final HashMap icons = new HashMap<>(); public ArrayList messages = new ArrayList<>(); public int prevNotificationID = -1; @@ -110,7 +110,7 @@ public Bitmap getIcon(String accountID) { } public void putIcon(String accountID, Bitmap bitmap) { - icons.put(accountID, encodeTobase64(bitmap)); + icons.put(accountID, encodeToBase64(bitmap)); } public Person getPerson(String accountID) { @@ -130,10 +130,10 @@ public Person getPerson(String accountID) { public void putPerson(String accountID, String name, Bitmap icon) { names.put(accountID, name); - icons.put(accountID, encodeTobase64(icon)); + putIcon(accountID, icon); } - public static String encodeTobase64(Bitmap bitmap) { + public static String encodeToBase64(Bitmap bitmap) { if (bitmap == null) { return ""; } From f119998ab9088121eba1417ab4553f36ddb22390 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Tue, 1 Aug 2023 10:37:01 -0400 Subject: [PATCH 29/32] Revert "save a static reference for application context" This reverts commit 6189be7b09d62749b6802b61e1045a39ac1d68f4. --- .../main/java/com/expensify/chat/MainApplication.java | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/MainApplication.java b/android/app/src/main/java/com/expensify/chat/MainApplication.java index b53b966d60d4..a4f2bc97416d 100644 --- a/android/app/src/main/java/com/expensify/chat/MainApplication.java +++ b/android/app/src/main/java/com/expensify/chat/MainApplication.java @@ -18,12 +18,10 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.util.List; public class MainApplication extends MultiDexApplication implements ReactApplication { - - private static Context context = null; - private final ReactNativeHost mReactNativeHost = new DefaultReactNativeHost(this) { @Override @@ -69,8 +67,6 @@ public ReactNativeHost getReactNativeHost() { public void onCreate() { super.onCreate(); - context = getApplicationContext(); - // Use night (dark) mode so native UI defaults to dark theme. AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); @@ -103,8 +99,4 @@ public void onCreate() { e.printStackTrace(); } } - - public static Context getContext() { - return context; - } } \ No newline at end of file From d772757727b4c3f61d1d7625b2d3a179eab38806 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Tue, 1 Aug 2023 10:46:30 -0400 Subject: [PATCH 30/32] use UAirship helper for getting application context --- .../chat/customairshipextender/NotificationCache.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index e8b3fc40b19b..8207c9d9d425 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -9,6 +9,7 @@ import androidx.core.graphics.drawable.IconCompat; import com.expensify.chat.MainApplication; +import com.urbanairship.UAirship; import java.io.ByteArrayOutputStream; import java.io.File; @@ -58,7 +59,7 @@ public static void setNotificationData(long reportID, NotificationData data) { } private static void writeToInternalStorage() { - Context context = MainApplication.getContext(); + Context context = UAirship.getApplicationContext(); try { File outputFile = new File(context.getFilesDir(), CACHE_FILE_NAME); FileOutputStream fos = new FileOutputStream(outputFile); @@ -75,7 +76,7 @@ private static void writeToInternalStorage() { private static HashMap readFromInternalStorage() { HashMap result; - Context context = MainApplication.getContext(); + Context context = UAirship.getApplicationContext(); try { File fileCache = new File(context.getFilesDir(), CACHE_FILE_NAME); FileInputStream fis = new FileInputStream(fileCache); From b396b5ee91e75b4341c74fdfab759f3f40e7e32e Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Wed, 2 Aug 2023 14:24:52 -0400 Subject: [PATCH 31/32] add doc for NotificationData class --- .../chat/customairshipextender/NotificationCache.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index 8207c9d9d425..3184a845f6d7 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -94,6 +94,10 @@ private static HashMap readFromInternalStorage() { return result; } + /** + * A class for caching data for notifications. We use this to track active notifications so we + * can thread related notifications together + */ public static class NotificationData implements Serializable { private final HashMap names = new HashMap<>(); From 6b3ff25a7ca57f88a4f3098051f4a76ea40b0c0f Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Wed, 2 Aug 2023 14:51:39 -0400 Subject: [PATCH 32/32] safely close file streams --- .../NotificationCache.java | 44 ++++++++++++++----- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java index 3184a845f6d7..7ddc17d37b4d 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/NotificationCache.java @@ -60,35 +60,55 @@ public static void setNotificationData(long reportID, NotificationData data) { private static void writeToInternalStorage() { Context context = UAirship.getApplicationContext(); + + FileOutputStream fos = null; + ObjectOutputStream oos = null; try { File outputFile = new File(context.getFilesDir(), CACHE_FILE_NAME); - FileOutputStream fos = new FileOutputStream(outputFile); - ObjectOutputStream oos = new ObjectOutputStream(fos); - + fos = new FileOutputStream(outputFile); + oos = new ObjectOutputStream(fos); oos.writeObject(cache); - - oos.close(); - fos.close(); } catch (IOException e) { e.printStackTrace(); + } finally { + try { + if (oos != null) { + oos.close(); + } + if (fos != null) { + fos.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } } } private static HashMap readFromInternalStorage() { HashMap result; Context context = UAirship.getApplicationContext(); + + FileInputStream fis = null; + ObjectInputStream ois = null; try { File fileCache = new File(context.getFilesDir(), CACHE_FILE_NAME); - FileInputStream fis = new FileInputStream(fileCache); - ObjectInputStream ois = new ObjectInputStream(fis); - + fis = new FileInputStream(fileCache); + ois = new ObjectInputStream(fis); result = (HashMap) ois.readObject(); - - ois.close(); - fis.close(); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); result = new HashMap<>(); + } finally { + try { + if (ois != null) { + ois.close(); + } + if (fis != null) { + fis.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } } return result;