ensure will tell 'messenger' when UP registration fails or is delayed

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java      | 29 
src/main/java/eu/siacs/conversations/services/UnifiedPushDistributor.java | 60 
2 files changed, 71 insertions(+), 18 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java 🔗

@@ -1,5 +1,6 @@
 package eu.siacs.conversations.services;
 
+import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.SharedPreferences;
@@ -87,14 +88,32 @@ public class UnifiedPushBroker {
             if (transport.account.isEnabled()) {
                 renewUnifiedEndpoint(transportOptional.get(), pushTargetMessenger);
             } else {
+                if (pushTargetMessenger.messenger != null) {
+                    sendRegistrationDelayed(pushTargetMessenger.messenger,"account is disabled");
+                }
                 Log.d(Config.LOGTAG, "skipping UnifiedPush endpoint renewal. Account is disabled");
             }
         } else {
+            if (pushTargetMessenger.messenger != null) {
+                sendRegistrationDelayed(pushTargetMessenger.messenger,"no transport selected");
+            }
             Log.d(Config.LOGTAG, "skipping UnifiedPush endpoint renewal. No transport selected");
         }
         return transportOptional;
     }
 
+    private void sendRegistrationDelayed(final Messenger messenger, final String error) {
+        final Intent intent = new Intent(UnifiedPushDistributor.ACTION_REGISTRATION_DELAYED);
+        intent.putExtra(UnifiedPushDistributor.EXTRA_MESSAGE, error);
+        final var message = new Message();
+        message.obj = intent;
+        try {
+            messenger.send(message);
+        } catch (final RemoteException e) {
+            Log.d(Config.LOGTAG,"unable to tell messenger of delayed registration",e);
+        }
+    }
+
     private void renewUnifiedEndpoint(final Transport transport, final PushTargetMessenger pushTargetMessenger) {
         final Account account = transport.account;
         final UnifiedPushDatabase unifiedPushDatabase = UnifiedPushDatabase.getInstance(service);
@@ -346,11 +365,17 @@ public class UnifiedPushBroker {
         service.sendBroadcast(updateIntent);
     }
 
-    private static Intent endpointIntent(final String instance, final UnifiedPushDatabase.ApplicationEndpoint endpoint) {
+    private Intent endpointIntent(final String instance, final UnifiedPushDatabase.ApplicationEndpoint endpoint) {
         final Intent intent = new Intent(UnifiedPushDistributor.ACTION_NEW_ENDPOINT);
         intent.setPackage(endpoint.application);
         intent.putExtra("token", instance);
         intent.putExtra("endpoint", endpoint.endpoint);
+        final var distributorVerificationIntent = new Intent();
+        distributorVerificationIntent.setPackage(service.getPackageName());
+        final var pendingIntent =
+                PendingIntent.getBroadcast(
+                        service, 0, distributorVerificationIntent, PendingIntent.FLAG_IMMUTABLE);
+        intent.putExtra("distributor", pendingIntent);
         return intent;
     }
 
@@ -378,7 +403,7 @@ public class UnifiedPushBroker {
 
     public static class PushTargetMessenger {
         private final UnifiedPushDatabase.PushTarget pushTarget;
-        private final Messenger messenger;
+        public final Messenger messenger;
 
         public PushTargetMessenger(UnifiedPushDatabase.PushTarget pushTarget, Messenger messenger) {
             this.pushTarget = pushTarget;

src/main/java/eu/siacs/conversations/services/UnifiedPushDistributor.java 🔗

@@ -6,8 +6,10 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ResolveInfo;
 import android.net.Uri;
+import android.os.Message;
 import android.os.Messenger;
 import android.os.Parcelable;
+import android.os.RemoteException;
 import android.util.Log;
 
 import com.google.common.base.Charsets;
@@ -33,10 +35,17 @@ public class UnifiedPushDistributor extends BroadcastReceiver {
             "org.unifiedpush.android.distributor.feature.BYTES_MESSAGE";
     public static final String ACTION_REGISTRATION_FAILED =
             "org.unifiedpush.android.connector.REGISTRATION_FAILED";
+
+    // this action is only used in 'messenger' communication to tell the app that a registration is
+    // probably fine but can not be processed right now; for example due to spotty internet
+    public static final String ACTION_REGISTRATION_DELAYED =
+            "org.unifiedpush.android.connector.REGISTRATION_DELAYED";
     public static final String ACTION_MESSAGE = "org.unifiedpush.android.connector.MESSAGE";
     public static final String ACTION_NEW_ENDPOINT =
             "org.unifiedpush.android.connector.NEW_ENDPOINT";
 
+    public static final String EXTRA_MESSAGE = "message";
+
     public static final String PREFERENCE_ACCOUNT = "up_push_account";
     public static final String PREFERENCE_PUSH_SERVER = "up_push_server";
 
@@ -50,9 +59,8 @@ public class UnifiedPushDistributor extends BroadcastReceiver {
         }
         final String action = intent.getAction();
         final String application;
-        final Parcelable appByPendingIntent = intent.getParcelableExtra("app");
-        if (appByPendingIntent instanceof PendingIntent) {
-            final PendingIntent pendingIntent = (PendingIntent) appByPendingIntent;
+        final Parcelable appVerification = intent.getParcelableExtra("app");
+        if (appVerification instanceof PendingIntent pendingIntent) {
             application = pendingIntent.getIntentSender().getCreatorPackage();
             Log.d(Config.LOGTAG,"received application name via pending intent "+ application);
         } else {
@@ -62,18 +70,12 @@ public class UnifiedPushDistributor extends BroadcastReceiver {
         final String instance = intent.getStringExtra("token");
         final List<String> features = intent.getStringArrayListExtra("features");
         switch (Strings.nullToEmpty(action)) {
-            case ACTION_REGISTER:
-                register(context, application, instance, features, messenger);
-                break;
-            case ACTION_UNREGISTER:
-                unregister(context, instance);
-                break;
-            case Intent.ACTION_PACKAGE_FULLY_REMOVED:
-                unregisterApplication(context, intent.getData());
-                break;
-            default:
-                Log.d(Config.LOGTAG, "UnifiedPushDistributor received unknown action " + action);
-                break;
+            case ACTION_REGISTER -> register(context, application, instance, features, messenger);
+            case ACTION_UNREGISTER -> unregister(context, instance);
+            case Intent.ACTION_PACKAGE_FULLY_REMOVED ->
+                    unregisterApplication(context, intent.getData());
+            default ->
+                    Log.d(Config.LOGTAG, "UnifiedPushDistributor received unknown action " + action);
         }
     }
 
@@ -114,11 +116,25 @@ public class UnifiedPushDistributor extends BroadcastReceiver {
             } else {
                 Log.d(Config.LOGTAG, "not successful. sending error message back to application");
                 final Intent registrationFailed = new Intent(ACTION_REGISTRATION_FAILED);
+                registrationFailed.putExtra(EXTRA_MESSAGE, "instance already exits");
                 registrationFailed.setPackage(application);
                 registrationFailed.putExtra("token", instance);
-                context.sendBroadcast(registrationFailed);
+                if (messenger instanceof Messenger m) {
+                    final var message = new Message();
+                    message.obj = registrationFailed;
+                    try {
+                        m.send(message);
+                    } catch (final RemoteException e) {
+                        context.sendBroadcast(registrationFailed);
+                    }
+                } else {
+                    context.sendBroadcast(registrationFailed);
+                }
             }
         } else {
+            if (messenger instanceof Messenger m) {
+                sendRegistrationFailed(m,"Your application is not registered to receive messages");
+            }
             Log.d(
                     Config.LOGTAG,
                     "ignoring invalid UnifiedPush registration. Unknown application "
@@ -126,6 +142,18 @@ public class UnifiedPushDistributor extends BroadcastReceiver {
         }
     }
 
+    private void sendRegistrationFailed(final Messenger messenger, final String error) {
+        final Intent intent = new Intent(ACTION_REGISTRATION_FAILED);
+        intent.putExtra(EXTRA_MESSAGE, error);
+        final var message = new Message();
+        message.obj = intent;
+        try {
+            messenger.send(message);
+        } catch (final RemoteException e) {
+            Log.d(Config.LOGTAG,"unable to tell messenger of failed registration",e);
+        }
+    }
+
     private List<String> getBroadcastReceivers(final Context context, final String application) {
         final Intent messageIntent = new Intent(ACTION_MESSAGE);
         messageIntent.setPackage(application);