diff --git a/src/main/java/eu/siacs/conversations/persistance/UnifiedPushDatabase.java b/src/main/java/eu/siacs/conversations/persistance/UnifiedPushDatabase.java index f36506bd1..fd7b27db4 100644 --- a/src/main/java/eu/siacs/conversations/persistance/UnifiedPushDatabase.java +++ b/src/main/java/eu/siacs/conversations/persistance/UnifiedPushDatabase.java @@ -16,6 +16,7 @@ import com.google.common.collect.ImmutableList; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; import java.util.List; import eu.siacs.conversations.Config; @@ -129,6 +130,23 @@ public class UnifiedPushDatabase extends SQLiteOpenHelper { return null; } + public List deletePushTargets() { + final SQLiteDatabase sqLiteDatabase = getReadableDatabase(); + final ImmutableList.Builder builder = new ImmutableList.Builder<>(); + try (final Cursor cursor = sqLiteDatabase.query("push",new String[]{"application","instance"},null,null,null,null,null)) { + if (cursor != null && cursor.moveToFirst()) { + builder.add(new PushTarget( + cursor.getString(cursor.getColumnIndexOrThrow("application")), + cursor.getString(cursor.getColumnIndexOrThrow("instance")))); + } + } catch (final Exception e) { + Log.d(Config.LOGTAG,"unable to retrieve push targets",e); + return builder.build(); + } + sqLiteDatabase.delete("push",null,null); + return builder.build(); + } + public boolean hasEndpoints(final UnifiedPushBroker.Transport transport) { final SQLiteDatabase sqLiteDatabase = getReadableDatabase(); try (final Cursor cursor = diff --git a/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java b/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java index f7715fd6f..d152c5d07 100644 --- a/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java +++ b/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java @@ -10,10 +10,18 @@ import android.os.Messenger; import android.os.RemoteException; import android.preference.PreferenceManager; import android.util.Log; + +import androidx.annotation.NonNull; + import com.google.common.base.Optional; import com.google.common.base.Strings; import com.google.common.collect.Iterables; import com.google.common.io.BaseEncoding; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; + import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; @@ -239,6 +247,9 @@ public class UnifiedPushBroker { public boolean reconfigurePushDistributor() { final boolean enabled = getTransport().isPresent(); setUnifiedPushDistributorEnabled(enabled); + if (!enabled) { + unregisterCurrentPushTargets(); + } return enabled; } @@ -261,6 +272,43 @@ public class UnifiedPushBroker { } } + private void unregisterCurrentPushTargets() { + final var future = deletePushTargets(); + Futures.addCallback( + future, + new FutureCallback<>() { + @Override + public void onSuccess( + final List pushTargets) { + broadcastUnregistered(pushTargets); + } + + @Override + public void onFailure(@NonNull Throwable throwable) { + Log.d( + Config.LOGTAG, + "could not delete endpoints after UnifiedPushDistributor was disabled"); + } + }, + MoreExecutors.directExecutor()); + } + + private ListenableFuture> deletePushTargets() { + return Futures.submit(() -> UnifiedPushDatabase.getInstance(service).deletePushTargets(),SCHEDULER); + } + + private void broadcastUnregistered(final List pushTargets) { + for(final UnifiedPushDatabase.PushTarget pushTarget : pushTargets) { + Log.d(Config.LOGTAG,"sending unregistered to "+pushTarget); + broadcastUnregistered(pushTarget); + } + } + + private void broadcastUnregistered(final UnifiedPushDatabase.PushTarget pushTarget) { + final var intent = unregisteredIntent(pushTarget); + service.sendBroadcast(intent); + } + public boolean processPushMessage( final Account account, final Jid transport, final Element push) { final String instance = push.getAttribute("instance"); @@ -355,6 +403,7 @@ public class UnifiedPushBroker { updateIntent.putExtra("token", target.instance); updateIntent.putExtra("bytesMessage", payload); updateIntent.putExtra("message", new String(payload, StandardCharsets.UTF_8)); + // TODO add distributor verification? service.sendBroadcast(updateIntent); } @@ -379,6 +428,19 @@ public class UnifiedPushBroker { return intent; } + private Intent unregisteredIntent(final UnifiedPushDatabase.PushTarget pushTarget) { + final Intent intent = new Intent(UnifiedPushDistributor.ACTION_UNREGISTERED); + intent.setPackage(pushTarget.application); + intent.putExtra("token", pushTarget.instance); + 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; + } + public void rebroadcastEndpoint(final Messenger messenger, final String instance, final Transport transport) { final UnifiedPushDatabase unifiedPushDatabase = UnifiedPushDatabase.getInstance(service); final UnifiedPushDatabase.ApplicationEndpoint endpoint = diff --git a/src/main/java/eu/siacs/conversations/services/UnifiedPushDistributor.java b/src/main/java/eu/siacs/conversations/services/UnifiedPushDistributor.java index 4616cc622..b47a61a53 100644 --- a/src/main/java/eu/siacs/conversations/services/UnifiedPushDistributor.java +++ b/src/main/java/eu/siacs/conversations/services/UnifiedPushDistributor.java @@ -29,8 +29,15 @@ import eu.siacs.conversations.utils.Compatibility; public class UnifiedPushDistributor extends BroadcastReceiver { + // distributor actions (these are actios used for connector->distributor broadcasts) + // we, the distributor, have a broadcast receiver listening for those actions + public static final String ACTION_REGISTER = "org.unifiedpush.android.distributor.REGISTER"; public static final String ACTION_UNREGISTER = "org.unifiedpush.android.distributor.UNREGISTER"; + + + // connector actions (these are actions used for distributor->connector broadcasts) + public static final String ACTION_UNREGISTERED = "org.unifiedpush.android.connector.UNREGISTERED"; public static final String ACTION_BYTE_MESSAGE = "org.unifiedpush.android.distributor.feature.BYTES_MESSAGE"; public static final String ACTION_REGISTRATION_FAILED = @@ -172,6 +179,7 @@ public class UnifiedPushDistributor extends BroadcastReceiver { if (unifiedPushDatabase.deleteInstance(instance)) { quickLog(context, String.format("successfully unregistered token %s from UnifiedPushed (application requested unregister)", instance)); Log.d(Config.LOGTAG, "successfully removed " + instance + " from UnifiedPush"); + // TODO send UNREGISTERED broadcast back to app?! } }