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