PushManagementService.java

  1package eu.siacs.conversations.services;
  2
  3import android.util.Log;
  4
  5import com.google.android.gms.common.ConnectionResult;
  6import com.google.android.gms.common.GoogleApiAvailability;
  7import com.google.firebase.iid.FirebaseInstanceId;
  8import com.google.firebase.iid.InstanceIdResult;
  9
 10import eu.siacs.conversations.Config;
 11import eu.siacs.conversations.R;
 12import eu.siacs.conversations.entities.Account;
 13import eu.siacs.conversations.utils.PhoneHelper;
 14import eu.siacs.conversations.xml.Element;
 15import eu.siacs.conversations.xml.Namespace;
 16import eu.siacs.conversations.xmpp.Jid;
 17import eu.siacs.conversations.xmpp.XmppConnection;
 18import eu.siacs.conversations.xmpp.forms.Data;
 19import eu.siacs.conversations.xmpp.stanzas.IqPacket;
 20
 21public class PushManagementService {
 22
 23    protected final XmppConnectionService mXmppConnectionService;
 24
 25    PushManagementService(XmppConnectionService service) {
 26        this.mXmppConnectionService = service;
 27    }
 28
 29    private static Data findResponseData(IqPacket response) {
 30        final Element command = response.findChild("command", Namespace.COMMANDS);
 31        final Element x = command == null ? null : command.findChild("x", Namespace.DATA);
 32        return x == null ? null : Data.parse(x);
 33    }
 34
 35    private Jid getAppServer() {
 36        return Jid.of(mXmppConnectionService.getString(R.string.app_server));
 37    }
 38
 39    void registerPushTokenOnServer(final Account account) {
 40        Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": has push support");
 41        retrieveFcmInstanceToken(token -> {
 42            final String androidId = PhoneHelper.getAndroidId(mXmppConnectionService);
 43            final IqPacket packet = mXmppConnectionService.getIqGenerator().pushTokenToAppServer(getAppServer(), token, androidId);
 44            mXmppConnectionService.sendIqPacket(account, packet, (a, response) -> {
 45                final Data data = findResponseData(response);
 46                if (response.getType() == IqPacket.TYPE.RESULT && data != null) {
 47                    try {
 48                        String node = data.getValue("node");
 49                        String secret = data.getValue("secret");
 50                        Jid jid = Jid.of(data.getValue("jid"));
 51                        if (node != null && secret != null) {
 52                            enablePushOnServer(a, jid, node, secret);
 53                        }
 54                    } catch (IllegalArgumentException e) {
 55                        e.printStackTrace();
 56                    }
 57                } else {
 58                    Log.d(Config.LOGTAG, a.getJid().asBareJid() + ": invalid response from app server");
 59                }
 60            });
 61        });
 62    }
 63
 64    private void enablePushOnServer(final Account account, final Jid appServer, final String node, final String secret) {
 65        final IqPacket enable = mXmppConnectionService.getIqGenerator().enablePush(appServer, node, secret);
 66        mXmppConnectionService.sendIqPacket(account, enable, (a, p) -> {
 67            if (p.getType() == IqPacket.TYPE.RESULT) {
 68                Log.d(Config.LOGTAG, a.getJid().asBareJid() + ": successfully enabled push on server");
 69            } else if (p.getType() == IqPacket.TYPE.ERROR) {
 70                Log.d(Config.LOGTAG, a.getJid().asBareJid() + ": enabling push on server failed");
 71            }
 72        });
 73    }
 74
 75    private void retrieveFcmInstanceToken(final OnGcmInstanceTokenRetrieved instanceTokenRetrieved) {
 76        final FirebaseInstanceId firebaseInstanceId;
 77        try {
 78            firebaseInstanceId = FirebaseInstanceId.getInstance();
 79        } catch (IllegalStateException e) {
 80            Log.d(Config.LOGTAG, "unable to get firebase instance token ",e);
 81            return;
 82        }
 83        firebaseInstanceId.getInstanceId().addOnCompleteListener(task -> {
 84            if (!task.isSuccessful()) {
 85                Log.d(Config.LOGTAG, "unable to get Firebase instance token", task.getException());
 86            }
 87            final InstanceIdResult result;
 88            try {
 89                result = task.getResult();
 90            } catch (Exception e) {
 91                Log.d(Config.LOGTAG, "unable to get Firebase instance token due to bug in library ", e);
 92                return;
 93            }
 94            if (result != null) {
 95                instanceTokenRetrieved.onGcmInstanceTokenRetrieved(result.getToken());
 96            }
 97        });
 98
 99    }
100
101
102    public boolean available(Account account) {
103        final XmppConnection connection = account.getXmppConnection();
104        return connection != null
105                && connection.getFeatures().sm()
106                && connection.getFeatures().push()
107                && playServicesAvailable();
108    }
109
110    private boolean playServicesAvailable() {
111        return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(mXmppConnectionService) == ConnectionResult.SUCCESS;
112    }
113
114    public boolean isStub() {
115        return false;
116    }
117
118    interface OnGcmInstanceTokenRetrieved {
119        void onGcmInstanceTokenRetrieved(String token);
120    }
121}