Setup client-side for integration with the wryk/tusky-api prototype.
This commit is contained in:
parent
73a5144741
commit
e282f13fdc
|
@ -35,6 +35,8 @@ import com.keylesspalace.tusky.json.SpannedTypeAdapter;
|
||||||
import com.keylesspalace.tusky.json.StringWithEmoji;
|
import com.keylesspalace.tusky.json.StringWithEmoji;
|
||||||
import com.keylesspalace.tusky.json.StringWithEmojiTypeAdapter;
|
import com.keylesspalace.tusky.json.StringWithEmojiTypeAdapter;
|
||||||
import com.keylesspalace.tusky.network.MastodonAPI;
|
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.OkHttpUtils;
|
||||||
import com.keylesspalace.tusky.util.PushNotificationClient;
|
import com.keylesspalace.tusky.util.PushNotificationClient;
|
||||||
|
|
||||||
|
@ -45,11 +47,17 @@ import okhttp3.Interceptor;
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
|
import okhttp3.ResponseBody;
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
import retrofit2.Retrofit;
|
import retrofit2.Retrofit;
|
||||||
import retrofit2.converter.gson.GsonConverterFactory;
|
import retrofit2.converter.gson.GsonConverterFactory;
|
||||||
|
|
||||||
public class BaseActivity extends AppCompatActivity {
|
public class BaseActivity extends AppCompatActivity {
|
||||||
|
private static final String TAG = "BaseActivity"; // logging tag
|
||||||
|
|
||||||
public MastodonAPI mastodonAPI;
|
public MastodonAPI mastodonAPI;
|
||||||
|
public TuskyApi tuskyApi;
|
||||||
protected PushNotificationClient pushNotificationClient;
|
protected PushNotificationClient pushNotificationClient;
|
||||||
protected Dispatcher mastodonApiDispatcher;
|
protected Dispatcher mastodonApiDispatcher;
|
||||||
|
|
||||||
|
@ -59,7 +67,8 @@ public class BaseActivity extends AppCompatActivity {
|
||||||
|
|
||||||
redirectIfNotLoggedIn();
|
redirectIfNotLoggedIn();
|
||||||
createMastodonAPI();
|
createMastodonAPI();
|
||||||
createTuskyAPI();
|
createTuskyApi();
|
||||||
|
createPushNotificationClient();
|
||||||
|
|
||||||
/* There isn't presently a way to globally change the theme of a whole application at
|
/* 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
|
* 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);
|
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(),
|
pushNotificationClient = new PushNotificationClient(getApplicationContext(),
|
||||||
getString(R.string.tusky_api_url));
|
"tcp://" + getString(R.string.tusky_api_domain));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void redirectIfNotLoggedIn() {
|
protected void redirectIfNotLoggedIn() {
|
||||||
|
@ -187,10 +206,57 @@ public class BaseActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void enablePushNotifications() {
|
protected void enablePushNotifications() {
|
||||||
pushNotificationClient.subscribeToTopic();
|
Callback<ResponseBody> callback = new Callback<ResponseBody>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<ResponseBody> call,
|
||||||
|
retrofit2.Response<ResponseBody> response) {
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
pushNotificationClient.subscribeToTopic(getPushNotificationTopic());
|
||||||
|
} else {
|
||||||
|
onEnablePushNotificationsFailure();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<ResponseBody> 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() {
|
protected void disablePushNotifications() {
|
||||||
pushNotificationClient.unsubscribeToTopic();
|
Callback<ResponseBody> callback = new Callback<ResponseBody>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<ResponseBody> call,
|
||||||
|
retrofit2.Response<ResponseBody> response) {
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
pushNotificationClient.unsubscribeToTopic(getPushNotificationTopic());
|
||||||
|
} else {
|
||||||
|
onDisablePushNotificationsFailure();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<ResponseBody> 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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,15 +17,14 @@ package com.keylesspalace.tusky.network;
|
||||||
|
|
||||||
import okhttp3.ResponseBody;
|
import okhttp3.ResponseBody;
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.http.Field;
|
|
||||||
import retrofit2.http.FormUrlEncoded;
|
import retrofit2.http.FormUrlEncoded;
|
||||||
import retrofit2.http.POST;
|
import retrofit2.http.POST;
|
||||||
|
|
||||||
public interface TuskyAPI {
|
public interface TuskyApi {
|
||||||
@FormUrlEncoded
|
@FormUrlEncoded
|
||||||
@POST("/register")
|
@POST("/register")
|
||||||
Call<ResponseBody> register(@Field("instance_url") String instanceUrl, @Field("access_token") String accessToken, @Field("device_token") String deviceToken);
|
Call<ResponseBody> register(String instanceUrl, String accessToken, String deviceToken);
|
||||||
@FormUrlEncoded
|
@FormUrlEncoded
|
||||||
@POST("/unregister")
|
@POST("/unregister")
|
||||||
Call<ResponseBody> unregister(@Field("instance_url") String instanceUrl, @Field("access_token") String accessToken);
|
Call<ResponseBody> unregister(String instanceUrl, String accessToken, String deviceToken);
|
||||||
}
|
}
|
|
@ -29,6 +29,7 @@ import org.eclipse.paho.client.mqttv3.MqttMessage;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import okhttp3.Interceptor;
|
import okhttp3.Interceptor;
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
|
@ -43,23 +44,37 @@ import static android.content.Context.NOTIFICATION_SERVICE;
|
||||||
|
|
||||||
public class PushNotificationClient {
|
public class PushNotificationClient {
|
||||||
private static final String TAG = "PushNotificationClient";
|
private static final String TAG = "PushNotificationClient";
|
||||||
private static final String TOPIC = "tusky/notification";
|
|
||||||
private static final int NOTIFY_ID = 666;
|
private static final int NOTIFY_ID = 666;
|
||||||
|
|
||||||
private enum QueuedAction {
|
private static class QueuedAction {
|
||||||
|
enum Type {
|
||||||
SUBSCRIBE,
|
SUBSCRIBE,
|
||||||
UNSUBSCRIBE,
|
UNSUBSCRIBE,
|
||||||
DISCONNECT,
|
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 MqttAndroidClient mqttAndroidClient;
|
||||||
private MastodonAPI mastodonApi;
|
private MastodonAPI mastodonApi;
|
||||||
private ArrayDeque<QueuedAction> queuedActions;
|
private ArrayDeque<QueuedAction> queuedActions;
|
||||||
private boolean subscribed;
|
private ArrayList<String> subscribedTopics;
|
||||||
|
|
||||||
public PushNotificationClient(final @NonNull Context applicationContext,
|
public PushNotificationClient(final @NonNull Context applicationContext,
|
||||||
@NonNull String serverUri) {
|
@NonNull String serverUri) {
|
||||||
queuedActions = new ArrayDeque<>();
|
queuedActions = new ArrayDeque<>();
|
||||||
|
subscribedTopics = new ArrayList<>();
|
||||||
|
|
||||||
// Create the MQTT client.
|
// Create the MQTT client.
|
||||||
String clientId = MqttClient.generateClientId();
|
String clientId = MqttClient.generateClientId();
|
||||||
|
@ -69,8 +84,8 @@ public class PushNotificationClient {
|
||||||
public void connectComplete(boolean reconnect, String serverURI) {
|
public void connectComplete(boolean reconnect, String serverURI) {
|
||||||
if (reconnect) {
|
if (reconnect) {
|
||||||
flushQueuedActions();
|
flushQueuedActions();
|
||||||
if (subscribed) {
|
for (String topic : subscribedTopics) {
|
||||||
subscribeToTopic();
|
subscribeToTopic(topic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,9 +148,9 @@ public class PushNotificationClient {
|
||||||
private void flushQueuedActions() {
|
private void flushQueuedActions() {
|
||||||
while (!queuedActions.isEmpty()) {
|
while (!queuedActions.isEmpty()) {
|
||||||
QueuedAction action = queuedActions.pop();
|
QueuedAction action = queuedActions.pop();
|
||||||
switch (action) {
|
switch (action.type) {
|
||||||
case SUBSCRIBE: subscribeToTopic(); break;
|
case SUBSCRIBE: subscribeToTopic(action.topic); break;
|
||||||
case UNSUBSCRIBE: unsubscribeToTopic(); break;
|
case UNSUBSCRIBE: unsubscribeToTopic(action.topic); break;
|
||||||
case DISCONNECT: disconnect(); break;
|
case DISCONNECT: disconnect(); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,7 +159,7 @@ public class PushNotificationClient {
|
||||||
/** Disconnect from the MQTT broker. */
|
/** Disconnect from the MQTT broker. */
|
||||||
public void disconnect() {
|
public void disconnect() {
|
||||||
if (!mqttAndroidClient.isConnected()) {
|
if (!mqttAndroidClient.isConnected()) {
|
||||||
queuedActions.add(QueuedAction.DISCONNECT);
|
queuedActions.add(new QueuedAction(QueuedAction.Type.DISCONNECT));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
@ -160,16 +175,16 @@ public class PushNotificationClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Subscribe to the push notification topic. */
|
/** Subscribe to the push notification topic. */
|
||||||
public void subscribeToTopic() {
|
public void subscribeToTopic(final String topic) {
|
||||||
if (!mqttAndroidClient.isConnected()) {
|
if (!mqttAndroidClient.isConnected()) {
|
||||||
queuedActions.add(QueuedAction.SUBSCRIBE);
|
queuedActions.add(new QueuedAction(QueuedAction.Type.SUBSCRIBE, topic));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
mqttAndroidClient.subscribe(TOPIC, 0, null, new IMqttActionListener() {
|
mqttAndroidClient.subscribe(topic, 0, null, new IMqttActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(IMqttToken asyncActionToken) {
|
public void onSuccess(IMqttToken asyncActionToken) {
|
||||||
subscribed = true;
|
subscribedTopics.add(topic);
|
||||||
onConnectionSuccess();
|
onConnectionSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,14 +201,14 @@ public class PushNotificationClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Unsubscribe from the push notification topic. */
|
/** Unsubscribe from the push notification topic. */
|
||||||
public void unsubscribeToTopic() {
|
public void unsubscribeToTopic(String topic) {
|
||||||
if (!mqttAndroidClient.isConnected()) {
|
if (!mqttAndroidClient.isConnected()) {
|
||||||
queuedActions.add(QueuedAction.UNSUBSCRIBE);
|
queuedActions.add(new QueuedAction(QueuedAction.Type.UNSUBSCRIBE, topic));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
mqttAndroidClient.unsubscribe(TOPIC);
|
mqttAndroidClient.unsubscribe(topic);
|
||||||
subscribed = false;
|
subscribedTopics.remove(topic);
|
||||||
} catch (MqttException e) {
|
} catch (MqttException e) {
|
||||||
Log.e(TAG, "An exception occurred while unsubscribing." + e.getMessage());
|
Log.e(TAG, "An exception occurred while unsubscribing." + e.getMessage());
|
||||||
onConnectionFailure();
|
onConnectionFailure();
|
||||||
|
@ -271,4 +286,8 @@ public class PushNotificationClient {
|
||||||
public void clearNotifications(Context context) {
|
public void clearNotifications(Context context) {
|
||||||
((NotificationManager) (context.getSystemService(NOTIFICATION_SERVICE))).cancel(NOTIFY_ID);
|
((NotificationManager) (context.getSystemService(NOTIFICATION_SERVICE))).cancel(NOTIFY_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getDeviceToken() {
|
||||||
|
return mqttAndroidClient.getClientId();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name" translatable="false">Tusky</string>
|
<string name="app_name" translatable="false">Tusky</string>
|
||||||
<string name="app_website" translatable="false">https://tusky.keylesspalace.com</string>
|
<string name="app_website" translatable="false">https://tusky.keylesspalace.com</string>
|
||||||
<string name="tusky_api_url" translatable="false">tcp://tuskyapi.keylesspalace.com</string>
|
<string name="tusky_api_domain" translatable="false">tuskyapi.keylesspalace.com</string>
|
||||||
<string name="tusky_api_keystore_password" translatable="false">your_password_here</string>
|
<string name="tusky_api_keystore_password" translatable="false">your_password_here</string>
|
||||||
|
|
||||||
<string name="oauth_scheme" translatable="false">oauth2redirect</string>
|
<string name="oauth_scheme" translatable="false">oauth2redirect</string>
|
||||||
|
|
Loading…
Reference in New Issue