From e282f13fdcb62ed17967ae2ea0cce20d7a04ade8 Mon Sep 17 00:00:00 2001 From: Vavassor Date: Fri, 19 May 2017 21:28:12 -0400 Subject: [PATCH] Setup client-side for integration with the wryk/tusky-api prototype. --- .../com/keylesspalace/tusky/BaseActivity.java | 76 +++++++++++++++++-- .../network/{TuskyAPI.java => TuskyApi.java} | 7 +- .../tusky/util/PushNotificationClient.java | 61 ++++++++++----- app/src/main/res/values/donottranslate.xml | 2 +- 4 files changed, 115 insertions(+), 31 deletions(-) rename app/src/main/java/com/keylesspalace/tusky/network/{TuskyAPI.java => TuskyApi.java} (73%) diff --git a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java index 0bb76039f..d01eb28f0 100644 --- a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java @@ -35,6 +35,8 @@ import com.keylesspalace.tusky.json.SpannedTypeAdapter; import com.keylesspalace.tusky.json.StringWithEmoji; import com.keylesspalace.tusky.json.StringWithEmojiTypeAdapter; import com.keylesspalace.tusky.network.MastodonAPI; +import com.keylesspalace.tusky.network.TuskyApi; +import com.keylesspalace.tusky.util.Log; import com.keylesspalace.tusky.util.OkHttpUtils; import com.keylesspalace.tusky.util.PushNotificationClient; @@ -45,11 +47,17 @@ import okhttp3.Interceptor; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; +import okhttp3.ResponseBody; +import retrofit2.Call; +import retrofit2.Callback; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; public class BaseActivity extends AppCompatActivity { + private static final String TAG = "BaseActivity"; // logging tag + public MastodonAPI mastodonAPI; + public TuskyApi tuskyApi; protected PushNotificationClient pushNotificationClient; protected Dispatcher mastodonApiDispatcher; @@ -59,7 +67,8 @@ public class BaseActivity extends AppCompatActivity { redirectIfNotLoggedIn(); createMastodonAPI(); - createTuskyAPI(); + createTuskyApi(); + createPushNotificationClient(); /* There isn't presently a way to globally change the theme of a whole application at * runtime, just individual activities. So, each activity has to set its theme before any @@ -151,9 +160,19 @@ public class BaseActivity extends AppCompatActivity { mastodonAPI = retrofit.create(MastodonAPI.class); } - protected void createTuskyAPI() { + protected void createTuskyApi() { + Retrofit retrofit = new Retrofit.Builder() + .baseUrl("https://" + getString(R.string.tusky_api_domain)) + .client(OkHttpUtils.getCompatibleClient()) + .build(); + + tuskyApi = retrofit.create(TuskyApi.class); + } + + protected void createPushNotificationClient() { + // TODO: Switch to ssl:// when TLS support is added. pushNotificationClient = new PushNotificationClient(getApplicationContext(), - getString(R.string.tusky_api_url)); + "tcp://" + getString(R.string.tusky_api_domain)); } protected void redirectIfNotLoggedIn() { @@ -187,10 +206,57 @@ public class BaseActivity extends AppCompatActivity { } protected void enablePushNotifications() { - pushNotificationClient.subscribeToTopic(); + Callback callback = new Callback() { + @Override + public void onResponse(Call call, + retrofit2.Response response) { + if (response.isSuccessful()) { + pushNotificationClient.subscribeToTopic(getPushNotificationTopic()); + } else { + onEnablePushNotificationsFailure(); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + onEnablePushNotificationsFailure(); + } + }; + tuskyApi.register(getBaseUrl(), getAccessToken(), pushNotificationClient.getDeviceToken()) + .enqueue(callback); + } + + private void onEnablePushNotificationsFailure() { + Log.e(TAG, "Enabling push notifications failed."); } protected void disablePushNotifications() { - pushNotificationClient.unsubscribeToTopic(); + Callback callback = new Callback() { + @Override + public void onResponse(Call call, + retrofit2.Response response) { + if (response.isSuccessful()) { + pushNotificationClient.unsubscribeToTopic(getPushNotificationTopic()); + } else { + onDisablePushNotificationsFailure(); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + onDisablePushNotificationsFailure(); + } + }; + tuskyApi.unregister(getBaseUrl(), getAccessToken(), pushNotificationClient.getDeviceToken()) + .enqueue(callback); + } + + private void onDisablePushNotificationsFailure() { + Log.e(TAG, "Disabling push notifications failed."); + } + + private String getPushNotificationTopic() { + return String.format("%s/%s/%s", getBaseUrl(), getAccessToken(), + pushNotificationClient.getDeviceToken()); } } diff --git a/app/src/main/java/com/keylesspalace/tusky/network/TuskyAPI.java b/app/src/main/java/com/keylesspalace/tusky/network/TuskyApi.java similarity index 73% rename from app/src/main/java/com/keylesspalace/tusky/network/TuskyAPI.java rename to app/src/main/java/com/keylesspalace/tusky/network/TuskyApi.java index 700de83c8..393decb90 100644 --- a/app/src/main/java/com/keylesspalace/tusky/network/TuskyAPI.java +++ b/app/src/main/java/com/keylesspalace/tusky/network/TuskyApi.java @@ -17,15 +17,14 @@ package com.keylesspalace.tusky.network; import okhttp3.ResponseBody; import retrofit2.Call; -import retrofit2.http.Field; import retrofit2.http.FormUrlEncoded; import retrofit2.http.POST; -public interface TuskyAPI { +public interface TuskyApi { @FormUrlEncoded @POST("/register") - Call register(@Field("instance_url") String instanceUrl, @Field("access_token") String accessToken, @Field("device_token") String deviceToken); + Call register(String instanceUrl, String accessToken, String deviceToken); @FormUrlEncoded @POST("/unregister") - Call unregister(@Field("instance_url") String instanceUrl, @Field("access_token") String accessToken); + Call unregister(String instanceUrl, String accessToken, String deviceToken); } diff --git a/app/src/main/java/com/keylesspalace/tusky/util/PushNotificationClient.java b/app/src/main/java/com/keylesspalace/tusky/util/PushNotificationClient.java index f75e318e3..40150bb2b 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/PushNotificationClient.java +++ b/app/src/main/java/com/keylesspalace/tusky/util/PushNotificationClient.java @@ -29,6 +29,7 @@ import org.eclipse.paho.client.mqttv3.MqttMessage; import java.io.IOException; import java.io.InputStream; import java.util.ArrayDeque; +import java.util.ArrayList; import okhttp3.Interceptor; import okhttp3.OkHttpClient; @@ -43,23 +44,37 @@ import static android.content.Context.NOTIFICATION_SERVICE; public class PushNotificationClient { private static final String TAG = "PushNotificationClient"; - private static final String TOPIC = "tusky/notification"; private static final int NOTIFY_ID = 666; - private enum QueuedAction { - SUBSCRIBE, - UNSUBSCRIBE, - DISCONNECT, + private static class QueuedAction { + enum Type { + SUBSCRIBE, + UNSUBSCRIBE, + DISCONNECT, + } + + Type type; + String topic; + + QueuedAction(Type type) { + this.type = type; + } + + QueuedAction(Type type, String topic) { + this.type = type; + this.topic = topic; + } } private MqttAndroidClient mqttAndroidClient; private MastodonAPI mastodonApi; private ArrayDeque queuedActions; - private boolean subscribed; + private ArrayList subscribedTopics; public PushNotificationClient(final @NonNull Context applicationContext, @NonNull String serverUri) { queuedActions = new ArrayDeque<>(); + subscribedTopics = new ArrayList<>(); // Create the MQTT client. String clientId = MqttClient.generateClientId(); @@ -69,8 +84,8 @@ public class PushNotificationClient { public void connectComplete(boolean reconnect, String serverURI) { if (reconnect) { flushQueuedActions(); - if (subscribed) { - subscribeToTopic(); + for (String topic : subscribedTopics) { + subscribeToTopic(topic); } } } @@ -133,10 +148,10 @@ public class PushNotificationClient { private void flushQueuedActions() { while (!queuedActions.isEmpty()) { QueuedAction action = queuedActions.pop(); - switch (action) { - case SUBSCRIBE: subscribeToTopic(); break; - case UNSUBSCRIBE: unsubscribeToTopic(); break; - case DISCONNECT: disconnect(); break; + switch (action.type) { + case SUBSCRIBE: subscribeToTopic(action.topic); break; + case UNSUBSCRIBE: unsubscribeToTopic(action.topic); break; + case DISCONNECT: disconnect(); break; } } } @@ -144,7 +159,7 @@ public class PushNotificationClient { /** Disconnect from the MQTT broker. */ public void disconnect() { if (!mqttAndroidClient.isConnected()) { - queuedActions.add(QueuedAction.DISCONNECT); + queuedActions.add(new QueuedAction(QueuedAction.Type.DISCONNECT)); return; } try { @@ -160,16 +175,16 @@ public class PushNotificationClient { } /** Subscribe to the push notification topic. */ - public void subscribeToTopic() { + public void subscribeToTopic(final String topic) { if (!mqttAndroidClient.isConnected()) { - queuedActions.add(QueuedAction.SUBSCRIBE); + queuedActions.add(new QueuedAction(QueuedAction.Type.SUBSCRIBE, topic)); return; } try { - mqttAndroidClient.subscribe(TOPIC, 0, null, new IMqttActionListener() { + mqttAndroidClient.subscribe(topic, 0, null, new IMqttActionListener() { @Override public void onSuccess(IMqttToken asyncActionToken) { - subscribed = true; + subscribedTopics.add(topic); onConnectionSuccess(); } @@ -186,14 +201,14 @@ public class PushNotificationClient { } /** Unsubscribe from the push notification topic. */ - public void unsubscribeToTopic() { + public void unsubscribeToTopic(String topic) { if (!mqttAndroidClient.isConnected()) { - queuedActions.add(QueuedAction.UNSUBSCRIBE); + queuedActions.add(new QueuedAction(QueuedAction.Type.UNSUBSCRIBE, topic)); return; } try { - mqttAndroidClient.unsubscribe(TOPIC); - subscribed = false; + mqttAndroidClient.unsubscribe(topic); + subscribedTopics.remove(topic); } catch (MqttException e) { Log.e(TAG, "An exception occurred while unsubscribing." + e.getMessage()); onConnectionFailure(); @@ -271,4 +286,8 @@ public class PushNotificationClient { public void clearNotifications(Context context) { ((NotificationManager) (context.getSystemService(NOTIFICATION_SERVICE))).cancel(NOTIFY_ID); } + + public String getDeviceToken() { + return mqttAndroidClient.getClientId(); + } } diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml index 212d54db0..e69825343 100644 --- a/app/src/main/res/values/donottranslate.xml +++ b/app/src/main/res/values/donottranslate.xml @@ -2,7 +2,7 @@ Tusky https://tusky.keylesspalace.com - tcp://tuskyapi.keylesspalace.com + tuskyapi.keylesspalace.com your_password_here oauth2redirect