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    void registerPushTokenOnServer(final Conversation conversation) {
 67        Log.d(Config.LOGTAG, conversation.getAccount().getJid().asBareJid() + ": room "+conversation.getJid().asBareJid()+" has push support");
 68        retrieveFcmInstanceToken(token -> {
 69            final Jid muc = conversation.getJid().asBareJid();
 70            final String androidId = PhoneHelper.getAndroidId(mXmppConnectionService);
 71            final IqPacket packet = mXmppConnectionService.getIqGenerator().pushTokenToAppServer(getAppServer(), token, androidId, muc);
 72            packet.setTo(muc);
 73            mXmppConnectionService.sendIqPacket(conversation.getAccount(), packet, (a, response) -> {
 74                final Data data = findResponseData(response);
 75                if (response.getType() == IqPacket.TYPE.RESULT && data != null) {
 76                    try {
 77                        final String node = data.getValue("node");
 78                        final String secret = data.getValue("secret");
 79                        final Jid jid = Jid.of(data.getValue("jid"));
 80                        if (node != null && secret != null) {
 81                            enablePushOnServer(conversation, jid, node, secret);
 82                        }
 83                    } catch (IllegalArgumentException e) {
 84                        e.printStackTrace();
 85                    }
 86                } else {
 87                    Log.d(Config.LOGTAG, a.getJid().asBareJid() + ": invalid response from app server");
 88                }
 89            });
 90        });
 91    }
 92
 93    private void enablePushOnServer(final Account account, final Jid appServer, final String node, final String secret) {
 94        final IqPacket enable = mXmppConnectionService.getIqGenerator().enablePush(appServer, node, secret);
 95        mXmppConnectionService.sendIqPacket(account, enable, (a, p) -> {
 96            if (p.getType() == IqPacket.TYPE.RESULT) {
 97                Log.d(Config.LOGTAG, a.getJid().asBareJid() + ": successfully enabled push on server");
 98            } else if (p.getType() == IqPacket.TYPE.ERROR) {
 99                Log.d(Config.LOGTAG, a.getJid().asBareJid() + ": enabling push on server failed");
100            }
101        });
102    }
103
104    private void enablePushOnServer(final Conversation conversation, final Jid appServer, final String node, final String secret) {
105        final Jid muc = conversation.getJid().asBareJid();
106        final IqPacket enable = mXmppConnectionService.getIqGenerator().enablePush(appServer, node, secret);
107        enable.setTo(muc);
108        mXmppConnectionService.sendIqPacket(conversation.getAccount(), enable, (a, p) -> {
109            if (p.getType() == IqPacket.TYPE.RESULT) {
110                Log.d(Config.LOGTAG, a.getJid().asBareJid() + ": successfully enabled push on " + muc);
111                if (conversation.setAttribute(Conversation.ATTRIBUTE_ALWAYS_NOTIFY, node)) {
112                    mXmppConnectionService.updateConversation(conversation);
113                }
114            } else if (p.getType() == IqPacket.TYPE.ERROR) {
115                Log.d(Config.LOGTAG, a.getJid().asBareJid() + ": enabling push on " + muc + " failed");
116            }
117        });
118    }
119
120    public void disablePushOnServer(final Conversation conversation) {
121        final Jid muc = conversation.getJid().asBareJid();
122        final String node = conversation.getAttribute(Conversation.ATTRIBUTE_PUSH_NODE);
123        if (node != null) {
124            final IqPacket disable = mXmppConnectionService.getIqGenerator().disablePush(getAppServer(), node);
125            disable.setTo(muc);
126            mXmppConnectionService.sendIqPacket(conversation.getAccount(), disable, (account, response) -> {
127                if (response.getType() == IqPacket.TYPE.ERROR) {
128                    Log.d(Config.LOGTAG,account.getJid().asBareJid()+": unable to disable push for room "+muc);
129                }
130            });
131        } else {
132            Log.d(Config.LOGTAG,conversation.getAccount().getJid().asBareJid()+": room "+muc+" has no stored node. unable to disable push");
133        }
134    }
135
136    private void retrieveFcmInstanceToken(final OnGcmInstanceTokenRetrieved instanceTokenRetrieved) {
137        FirebaseInstanceId.getInstance().getInstanceId().addOnCompleteListener(task -> {
138            if (!task.isSuccessful()) {
139                Log.d(Config.LOGTAG, "unable to get Firebase instance token", task.getException());
140            }
141            final InstanceIdResult result = task.getResult();
142            if (result != null) {
143                instanceTokenRetrieved.onGcmInstanceTokenRetrieved(result.getToken());
144            }
145        });
146
147    }
148
149
150    public boolean available(Account account) {
151        final XmppConnection connection = account.getXmppConnection();
152        return connection != null
153                && connection.getFeatures().sm()
154                && connection.getFeatures().push()
155                && playServicesAvailable();
156    }
157
158    private boolean playServicesAvailable() {
159        return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(mXmppConnectionService) == ConnectionResult.SUCCESS;
160    }
161
162    public boolean isStub() {
163        return false;
164    }
165
166    interface OnGcmInstanceTokenRetrieved {
167        void onGcmInstanceTokenRetrieved(String token);
168    }
169}