This differential enables CommNotificationsHandler /keyserver to fetch/upload and AES-decrypt/AES-encrypt notification payload if it's size exceeds FCM limits.
Details
Change NEXT_CODE_VERSION to 0 in lib/shared/version-utils.js. Build Android app (can be emulator).
Background the app. Send big notification (type 8000 * 'x' in python shell and copy the string). Ensure that the banner is displayed in Android client. Kill the keyserver and open the app. Keyserver is killed but the message is visible since we fetched it from blob service.
Diff Detail
- Repository
- rCOMM Comm
- Lint
Lint Not Applicable - Unit
Tests Not Applicable
Event Timeline
native/android/app/src/main/java/app/comm/android/notifications/CommAndroidNotificationsBlobServiceClient.java | ||
---|---|---|
37 ↗ | (On Diff #28842) | My idea to handle blob service query failure is that the notification containing blob_hash and encryption key will contain some very short text (to ensure it is deliverable via FCM) that will be displayed instead if we can't fetch the actual blob at the moment. An alternative to handle network/blob service downtime would be to turn this query into a WorkRequest with exponential backoff retry policy: https://developer.android.com/guide/background/persistent/getting-started/define-work#retries_backoff |
native/android/app/src/main/java/app/comm/android/notifications/CommNotificationsHandler.java | ||
---|---|---|
110 ↗ | (On Diff #28842) | Why to make this call asynchronous? On one hand FCM docs state that onMessageReceived is executed on separate thread - different than main thread: https://firebase.google.com/docs/reference/android/com/google/firebase/messaging/FirebaseMessagingService. On the other thread, I had done some search through FCM code and found out it is always the same thread - subsequent onMessageReceived calls are executed sequentially on dedicated background thread. Therefore I concluded that we shouldn't block displaying small notifications immediately on some large notification being downloaded. To avoid background execution abuse I set time limit on each blob request to the value mentioned in the docs: https://firebase.google.com/docs/cloud-messaging/android/receive#backgrounded |
native/android/app/src/main/java/app/comm/android/notifications/CommAndroidNotificationsBlobServiceClient.java | ||
---|---|---|
37 ↗ | (On Diff #28842) | But I think using WorkManager and exponential backoff policy for this case a bit of over-engineering. |
native/android/app/src/main/java/app/comm/android/notifications/CommAndroidNotificationsBlobServiceClient.java | ||
---|---|---|
23–26 ↗ | (On Diff #28842) |
|
37 ↗ | (On Diff #28842) |
This idea makes sense - I think we want notification to be displayed even if it's short instead of delaying its delivery until request succeeds (which may never happen). As a user, I'd be more frustrated when received notif too late (or totally miss it) than if it was brief/vague but delivered quickly. |
native/android/app/src/main/java/app/comm/android/notifications/CommNotificationsHandler.java | ||
110 ↗ | (On Diff #28842) | Makes sense to me |
364 ↗ | (On Diff #28842) | Do we have to create this object each time this function is called? |
All the comments are minor except the one about badgeOnly handling which seems confusing.
keyserver/src/push/send.js | ||
---|---|---|
1210–1216 ↗ | (On Diff #38175) | We're not supporting that code version anymore, so the condition from the original if becomes !badgeOnly || true which s equal to true. Why then we're still checking !badgeOnly? And why we're handling only badgeOnly: '0' case? |
native/android/app/src/main/java/app/comm/android/commservices/CommAndroidBlobClient.java | ||
25 ↗ | (On Diff #38175) | It is a good idea to describe the unit in the variable name. |
34 ↗ | (On Diff #38175) | We don't have to specify all the exceptions when we're specifying their supertype (e.g. OutOfMemoryError is a subtype of Exception which means that it is enough to specify throws Exception). But do we really need to specify Exception? |
57–63 ↗ | (On Diff #38175) | It would be more convenient if CommSecureStore.get was returning Optional<String>. Then we could simply call String userID = CommSecureStore.get("userID").orElse("") |
native/android/app/src/main/java/app/comm/android/notifications/CommNotificationsHandler.java | ||
291–301 ↗ | (On Diff #38175) | I guess that by logging out e we're giving the info about which type of exception was thrown, so we probably don't need to have a catch clause for each type of exception Log.w("COMM", "Failure when handling large notification.", e);. |
keyserver/src/push/send.js | ||
---|---|---|
1210–1216 ↗ | (On Diff #38175) | You are right @tomek . This if statement should be removed and badgeOnly always set to '0'. Real badge only notifs are handled in updateBadgeCount function in this file. |
native/android/app/src/main/java/app/comm/android/commservices/CommAndroidBlobClient.java | ||
34 ↗ | (On Diff #38175) | OkHttp library methods are throwing checked exception so throws clause is necessary. |
57–63 ↗ | (On Diff #38175) | This is probably out of the scope of this differential. |
native/android/app/src/main/java/app/comm/android/commservices/CommAndroidBlobClient.java | ||
---|---|---|
34 ↗ | (On Diff #38175) | Are they declaring to throw Exception or a subtype? If only some subtypes, we can make this method declare throwing only the subtypes and not the Exception. |
native/android/app/src/main/java/app/comm/android/commservices/CommAndroidBlobClient.java | ||
---|---|---|
34 ↗ | (On Diff #38175) | OkHttp methods that we use here [[ https://square.github.io/okhttp/#post-to-a-server | could throw IOException ]]. Out getAuthToken method could throw JSONException. Theoretically we can experience OutOfMemory error since we are downloading potentially large blob into memory. That said if we want to be more specific we would have to bring back the original code and remove the Exception. |
keyserver/src/push/send.js | ||
---|---|---|
1210–1216 ↗ | (On Diff #38175) | We actually introduced a bug here. From my latest understanding updateBadgeCount handles user-initiated badge updates (marking thread manually as unread/read). The code above was supposed to handle the case of visual notification sent to the thread that user might have potentially muted. The badgeOnly here was based on thread subcription. |
keyserver/src/push/send.js | ||
---|---|---|
1210–1216 ↗ | (On Diff #38175) | Will be fixed when we land: https://phab.comm.dev/D12539 |
keyserver/src/push/send.js | ||
---|---|---|
1210–1216 ↗ | (On Diff #38175) | Can you clarify what product impact this bug has? How does it affect users? |
keyserver/src/push/send.js | ||
---|---|---|
1210–1216 ↗ | (On Diff #38175) | I spoke to @marcin about this in our 1:1 today. The bug is that when the keyserver should send a badge-only notif to an Android device, it accidentally sets badgeOnly to 0 and includes fields not relevant for badgeOnly notifs (the text of the notif). This results in a visual notif for the user Since this is a user-facing issue, I've created an urgent task to track: ENG-8620 |