Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3374421
D9069.id30795.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
8 KB
Referenced Files
None
Subscribers
None
D9069.id30795.diff
View Options
diff --git a/native/android/app/build.gradle b/native/android/app/build.gradle
--- a/native/android/app/build.gradle
+++ b/native/android/app/build.gradle
@@ -707,6 +707,15 @@
} else {
implementation jscFlavor
}
+ def work_version = "2.8.1"
+ // (Java only)
+ implementation "androidx.work:work-runtime:$work_version"
+ // Kotlin + coroutines
+ implementation "androidx.work:work-runtime-ktx:$work_version"
+ // Guava for listenable future to solve the bug:
+ // https://stackoverflow.com/questions/64290141/android-studio-class-file-for-com-google-common-util-concurrent-listenablefuture
+ // https://github.com/google/ExoPlayer/issues/7993
+ implementation "com.google.guava:guava:31.0.1-android"
}
if (isNewArchitectureEnabled()) {
diff --git a/native/android/app/src/main/java/app/comm/android/notifications/CommAndroidNotificationsBlobServiceClient.java b/native/android/app/src/main/java/app/comm/android/notifications/CommAndroidNotificationsBlobServiceClient.java
--- a/native/android/app/src/main/java/app/comm/android/notifications/CommAndroidNotificationsBlobServiceClient.java
+++ b/native/android/app/src/main/java/app/comm/android/notifications/CommAndroidNotificationsBlobServiceClient.java
@@ -1,6 +1,13 @@
package app.comm.android.notifications;
+import android.content.Context;
import android.util.Log;
+import androidx.work.Constraints;
+import androidx.work.Data;
+import androidx.work.NetworkType;
+import androidx.work.OneTimeWorkRequest;
+import androidx.work.WorkManager;
+import androidx.work.WorkRequest;
import com.google.firebase.messaging.RemoteMessage;
import java.io.IOException;
import java.lang.OutOfMemoryError;
@@ -17,8 +24,6 @@
import org.json.JSONObject;
public class CommAndroidNotificationsBlobServiceClient {
- private static final String BLOB_SERVICE_URL =
- "https://blob.commtechnologies.org";
// The FirebaseMessagingService docs state that message
// processing should complete within at most 20 seconds
// window. Therefore we limit http time call to 15 seconds
@@ -26,11 +31,17 @@
private static final int NOTIFICATION_PROCESSING_TIME_LIMIT = 15;
// OkHttp docs advise to share OkHttpClient instances
// https://square.github.io/okhttp/4.x/okhttp/okhttp3/-ok-http-client/#okhttpclients-should-be-shared
- private static final OkHttpClient httpClient =
+
+ public static final OkHttpClient httpClient =
new OkHttpClient.Builder()
.callTimeout(NOTIFICATION_PROCESSING_TIME_LIMIT, TimeUnit.SECONDS)
.build();
+ public static final String BLOB_SERVICE_URL =
+ "https://blob.commtechnologies.org";
+ public static final String BLOB_HASH_KEY = "blob_hash";
+ public static final String BLOB_HOLDER_KEY = "holder";
+
@FunctionalInterface
public interface BlobServiceMessageConsumer {
void accept(RemoteMessage message, byte[] blob);
@@ -71,7 +82,28 @@
});
}
- private String getAuthToken() {
+ public void scheduleDeferredBlobDeletion(
+ String blobHash,
+ String blobHolder,
+ Context context) {
+ Constraints constraints = new Constraints.Builder()
+ .setRequiredNetworkType(NetworkType.CONNECTED)
+ .build();
+ WorkRequest deleteBlobWorkRequest =
+ new OneTimeWorkRequest.Builder(DeleteBlobWork.class)
+ .setConstraints(constraints)
+ .setInitialDelay(
+ NOTIFICATION_PROCESSING_TIME_LIMIT, TimeUnit.SECONDS)
+ .setInputData(new Data.Builder()
+ .putString(BLOB_HASH_KEY, blobHash)
+ .putString(BLOB_HOLDER_KEY, blobHolder)
+ .build())
+ .build();
+
+ WorkManager.getInstance(context).enqueue(deleteBlobWorkRequest);
+ }
+
+ public static String getAuthToken() {
// Authentication data are retrieved on every request
// since they might change while CommNotificationsHandler
// thread is running so we should not rely on caching
diff --git a/native/android/app/src/main/java/app/comm/android/notifications/CommNotificationsHandler.java b/native/android/app/src/main/java/app/comm/android/notifications/CommNotificationsHandler.java
--- a/native/android/app/src/main/java/app/comm/android/notifications/CommNotificationsHandler.java
+++ b/native/android/app/src/main/java/app/comm/android/notifications/CommNotificationsHandler.java
@@ -44,6 +44,7 @@
private static final String ENCRYPTED_PAYLOAD_KEY = "encryptedPayload";
private static final String ENCRYPTION_FAILED_KEY = "encryptionFailed";
private static final String BLOB_HASH_KEY = "blobHash";
+ private static final String BLOB_HOLDER_KEY = "holder";
private static final String AES_ENCRYPTION_KEY_KEY = "encryptionKey";
private static final String CHANNEL_ID = "default";
@@ -108,7 +109,11 @@
}
String blobHash = message.getData().get(BLOB_HASH_KEY);
- if (blobHash != null) {
+ String blobHolder = message.getData().get(BLOB_HOLDER_KEY);
+
+ if (blobHash != null && blobHolder != null) {
+ blobServiceClient.scheduleDeferredBlobDeletion(
+ blobHash, blobHolder, this.getApplicationContext());
blobServiceClient.getAndConsumeAsync(
blobHash,
message,
diff --git a/native/android/app/src/main/java/app/comm/android/notifications/DeleteBlobWork.java b/native/android/app/src/main/java/app/comm/android/notifications/DeleteBlobWork.java
new file mode 100644
--- /dev/null
+++ b/native/android/app/src/main/java/app/comm/android/notifications/DeleteBlobWork.java
@@ -0,0 +1,95 @@
+package app.comm.android.notifications;
+
+import android.content.Context;
+import android.util.Log;
+import androidx.work.Data;
+import androidx.work.ListenableWorker.Result;
+import androidx.work.Worker;
+import androidx.work.WorkerParameters;
+import java.io.IOException;
+import java.util.function.Consumer;
+import okhttp3.MediaType;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+public class DeleteBlobWork extends Worker {
+
+ private static final int MAX_RETRY_ATTEMPTS = 10;
+
+ public DeleteBlobWork(Context context, WorkerParameters params) {
+ super(context, params);
+ }
+
+ @Override
+ public Result doWork() {
+ String blobHash = getInputData().getString(
+ CommAndroidNotificationsBlobServiceClient.BLOB_HASH_KEY);
+ String blobHolder = getInputData().getString(
+ CommAndroidNotificationsBlobServiceClient.BLOB_HOLDER_KEY);
+
+ String jsonBody;
+ try {
+ jsonBody =
+ new JSONObject()
+ .put(
+ CommAndroidNotificationsBlobServiceClient.BLOB_HASH_KEY,
+ blobHash)
+ .put(
+ CommAndroidNotificationsBlobServiceClient.BLOB_HOLDER_KEY,
+ blobHolder)
+ .toString();
+ } catch (JSONException e) {
+ // This should never happen since the code
+ // throwing is just simple JSON creation.
+ // If it happens there is no way to retry
+ // so we fail immediately.
+ Log.w(
+ "COMM",
+ "Failed to create JSON from blob hash and holder provided.",
+ e);
+ return Result.failure();
+ }
+
+ String authToken = CommAndroidNotificationsBlobServiceClient.getAuthToken();
+ RequestBody requestBody =
+ RequestBody.create(MediaType.parse("application/json"), jsonBody);
+ Request request =
+ new Request.Builder()
+ .delete(requestBody)
+ .url(
+ CommAndroidNotificationsBlobServiceClient.BLOB_SERVICE_URL +
+ "/blob")
+ .header("Authorization", authToken)
+ .build();
+
+ try {
+ Response response =
+ CommAndroidNotificationsBlobServiceClient.httpClient.newCall(request)
+ .execute();
+ if (response.isSuccessful()) {
+ return Result.success();
+ }
+ Log.w(
+ "COMM",
+ "Failed to execute blob deletion request. HTTP code:" +
+ response.code() + " status: " + response.message());
+ return retryOrFail();
+ } catch (IOException e) {
+ Log.w(
+ "COMM",
+ "IO exception occurred while issuing blob deletion request.",
+ e);
+ return retryOrFail();
+ }
+ }
+
+ private Result retryOrFail() {
+ if (getRunAttemptCount() > MAX_RETRY_ATTEMPTS) {
+ return Result.failure();
+ }
+ return Result.retry();
+ }
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Nov 27, 3:28 PM (19 h, 34 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2590821
Default Alt Text
D9069.id30795.diff (8 KB)
Attached To
Mode
D9069: Schedule blob deletion on Android when large notifications arrives
Attached
Detach File
Event Timeline
Log In to Comment