UnifiedPushDistributor.java

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