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.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 ;
79 } catch (IllegalStateException e) {
80 Log.d(Config.LOGTAG, "unable to get firebase instance token ", e);
81 return;
82 }
83 firebaseMessaging.getToken().addOnCompleteListener(task -> {
84 if (!task.isSuccessful()) {
85 Log.d(Config.LOGTAG, "unable to get Firebase instance token", task.getException());
86 }
87 final String 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);
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}