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