UnifiedPushDistributor.java

  1package eu.siacs.conversations.services;
  2
  3import android.content.BroadcastReceiver;
  4import android.content.Context;
  5import android.content.Intent;
  6import android.content.pm.ResolveInfo;
  7import android.net.Uri;
  8import android.util.Log;
  9
 10import com.google.common.base.Charsets;
 11import com.google.common.base.Joiner;
 12import com.google.common.base.Strings;
 13import com.google.common.collect.Lists;
 14import com.google.common.hash.Hashing;
 15import com.google.common.io.BaseEncoding;
 16
 17import java.util.Arrays;
 18import java.util.Collection;
 19import java.util.List;
 20
 21import eu.siacs.conversations.Config;
 22import eu.siacs.conversations.persistance.UnifiedPushDatabase;
 23import eu.siacs.conversations.utils.Compatibility;
 24
 25public class UnifiedPushDistributor extends BroadcastReceiver {
 26
 27    public static final String ACTION_REGISTER = "org.unifiedpush.android.distributor.REGISTER";
 28    public static final String ACTION_UNREGISTER = "org.unifiedpush.android.distributor.UNREGISTER";
 29    public static final String ACTION_BYTE_MESSAGE =
 30            "org.unifiedpush.android.distributor.feature.BYTES_MESSAGE";
 31    public static final String ACTION_REGISTRATION_FAILED =
 32            "org.unifiedpush.android.connector.REGISTRATION_FAILED";
 33    public static final String ACTION_MESSAGE = "org.unifiedpush.android.connector.MESSAGE";
 34    public static final String ACTION_NEW_ENDPOINT =
 35            "org.unifiedpush.android.connector.NEW_ENDPOINT";
 36
 37    public static final String PREFERENCE_ACCOUNT = "up_push_account";
 38    public static final String PREFERENCE_PUSH_SERVER = "up_push_server";
 39
 40    public static final List<String> PREFERENCES =
 41            Arrays.asList(PREFERENCE_ACCOUNT, PREFERENCE_PUSH_SERVER);
 42
 43    @Override
 44    public void onReceive(final Context context, final Intent intent) {
 45        if (intent == null) {
 46            return;
 47        }
 48        final String action = intent.getAction();
 49        final String application = intent.getStringExtra("application");
 50        final String instance = intent.getStringExtra("token");
 51        final List<String> features = intent.getStringArrayListExtra("features");
 52        switch (Strings.nullToEmpty(action)) {
 53            case ACTION_REGISTER:
 54                register(context, application, instance, features);
 55                break;
 56            case ACTION_UNREGISTER:
 57                unregister(context, instance);
 58                break;
 59            case Intent.ACTION_PACKAGE_FULLY_REMOVED:
 60                unregisterApplication(context, intent.getData());
 61                break;
 62            default:
 63                Log.d(Config.LOGTAG, "UnifiedPushDistributor received unknown action " + action);
 64                break;
 65        }
 66    }
 67
 68    private void register(
 69            final Context context,
 70            final String application,
 71            final String instance,
 72            final Collection<String> features) {
 73        if (Strings.isNullOrEmpty(application) || Strings.isNullOrEmpty(instance)) {
 74            Log.w(Config.LOGTAG, "ignoring invalid UnifiedPush registration");
 75            return;
 76        }
 77        final List<String> receivers = getBroadcastReceivers(context, application);
 78        if (receivers.contains(application)) {
 79            final boolean byteMessage = features != null && features.contains(ACTION_BYTE_MESSAGE);
 80            Log.d(
 81                    Config.LOGTAG,
 82                    "received up registration from "
 83                            + application
 84                            + "/"
 85                            + instance
 86                            + " features: "
 87                            + features);
 88            if (UnifiedPushDatabase.getInstance(context).register(application, instance)) {
 89                Log.d(
 90                        Config.LOGTAG,
 91                        "successfully created UnifiedPush entry. waking up XmppConnectionService");
 92                final Intent serviceIntent = new Intent(context, XmppConnectionService.class);
 93                serviceIntent.setAction(XmppConnectionService.ACTION_RENEW_UNIFIED_PUSH_ENDPOINTS);
 94                serviceIntent.putExtra("instance", instance);
 95                Compatibility.startService(context, serviceIntent);
 96            } else {
 97                Log.d(Config.LOGTAG, "not successful. sending error message back to application");
 98                final Intent registrationFailed = new Intent(ACTION_REGISTRATION_FAILED);
 99                registrationFailed.setPackage(application);
100                registrationFailed.putExtra("token", instance);
101                context.sendBroadcast(registrationFailed);
102            }
103        } else {
104            Log.d(
105                    Config.LOGTAG,
106                    "ignoring invalid UnifiedPush registration. Unknown application "
107                            + application);
108        }
109    }
110
111    private List<String> getBroadcastReceivers(final Context context, final String application) {
112        final Intent messageIntent = new Intent(ACTION_MESSAGE);
113        messageIntent.setPackage(application);
114        final List<ResolveInfo> resolveInfo =
115                context.getPackageManager().queryBroadcastReceivers(messageIntent, 0);
116        return Lists.transform(
117                resolveInfo, ri -> ri.activityInfo == null ? null : ri.activityInfo.packageName);
118    }
119
120    private void unregister(final Context context, final String instance) {
121        if (Strings.isNullOrEmpty(instance)) {
122            Log.w(Config.LOGTAG, "ignoring invalid UnifiedPush un-registration");
123            return;
124        }
125        final UnifiedPushDatabase unifiedPushDatabase = UnifiedPushDatabase.getInstance(context);
126        if (unifiedPushDatabase.deleteInstance(instance)) {
127            Log.d(Config.LOGTAG, "successfully removed " + instance + " from UnifiedPush");
128        }
129    }
130
131    private void unregisterApplication(final Context context, final Uri uri) {
132        if (uri != null && "package".equalsIgnoreCase(uri.getScheme())) {
133            final String application = uri.getSchemeSpecificPart();
134            if (Strings.isNullOrEmpty(application)) {
135                return;
136            }
137            Log.d(Config.LOGTAG, "app " + application + " has been removed from the system");
138            final UnifiedPushDatabase database = UnifiedPushDatabase.getInstance(context);
139            if (database.deleteApplication(application)) {
140                Log.d(Config.LOGTAG, "successfully removed " + application + " from UnifiedPush");
141            }
142        }
143    }
144
145    public static String hash(String... components) {
146        return BaseEncoding.base64()
147                .encode(
148                        Hashing.sha256()
149                                .hashString(Joiner.on('\0').join(components), Charsets.UTF_8)
150                                .asBytes());
151    }
152}