Merge branch 'master' into #136

This commit is contained in:
torrentcome 2017-05-29 12:14:09 +02:00 committed by torrentcome
commit 2b9f19805f
39 changed files with 525 additions and 648 deletions

View file

@ -9,6 +9,7 @@ import android.preference.PreferenceManager;
import android.support.customtabs.CustomTabsIntent;
import android.support.v4.content.ContextCompat;
import android.text.style.URLSpan;
import android.util.Log;
import android.view.View;
import com.keylesspalace.tusky.R;

View file

@ -23,6 +23,7 @@ import android.net.Uri;
import android.os.AsyncTask;
import android.support.annotation.Nullable;
import android.support.media.ExifInterface;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
@ -32,6 +33,7 @@ import java.util.ArrayList;
import java.util.List;
public class DownsizeImageTask extends AsyncTask<Uri, Void, Boolean> {
private static final String TAG = "DownsizeImageTask";
private int sizeLimit;
private ContentResolver contentResolver;
private Listener listener;
@ -100,6 +102,7 @@ public class DownsizeImageTask extends AsyncTask<Uri, Void, Boolean> {
try {
inputStream = contentResolver.openInputStream(uri);
} catch (FileNotFoundException e) {
Log.d(TAG, Log.getStackTraceString(e));
return ExifInterface.ORIENTATION_UNDEFINED;
}
if (inputStream == null) {
@ -109,6 +112,7 @@ public class DownsizeImageTask extends AsyncTask<Uri, Void, Boolean> {
try {
exifInterface = new ExifInterface(inputStream);
} catch (IOException e) {
Log.d(TAG, Log.getStackTraceString(e));
IOUtils.closeQuietly(inputStream);
return ExifInterface.ORIENTATION_UNDEFINED;
}

View file

@ -1,53 +0,0 @@
/* Copyright 2017 Andrew Dawson
*
* This file is a part of Tusky.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see <http://www.gnu.org/licenses>. */
package com.keylesspalace.tusky.util;
import com.keylesspalace.tusky.BuildConfig;
/**A wrapper for android.util.Log that allows for disabling logging, such as for release builds.*/
public class Log {
private static final boolean LOGGING_ENABLED = BuildConfig.DEBUG;
public static void i(String tag, String string) {
if (LOGGING_ENABLED) {
android.util.Log.i(tag, string);
}
}
public static void e(String tag, String string) {
if (LOGGING_ENABLED) {
android.util.Log.e(tag, string);
}
}
public static void d(String tag, String string) {
if (LOGGING_ENABLED) {
android.util.Log.d(tag, string);
}
}
public static void v(String tag, String string) {
if (LOGGING_ENABLED) {
android.util.Log.v(tag, string);
}
}
public static void w(String tag, String string) {
if (LOGGING_ENABLED) {
android.util.Log.w(tag, string);
}
}
}

View file

@ -28,6 +28,7 @@ import android.provider.Settings;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;
import android.util.Log;
import com.keylesspalace.tusky.MainActivity;
import com.keylesspalace.tusky.R;
@ -41,6 +42,9 @@ import org.json.JSONArray;
import org.json.JSONException;
public class NotificationMaker {
public static final String TAG = "NotificationMaker";
public static void make(final Context context, final int notifyId, Notification body) {
final SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(context);
@ -68,7 +72,7 @@ public class NotificationMaker {
alreadyContains = true;
}
} catch (JSONException e) {
e.printStackTrace();
Log.d(TAG, Log.getStackTraceString(e));
}
}
@ -129,7 +133,7 @@ public class NotificationMaker {
builder.setContentTitle(String.format(context.getString(R.string.notification_title_summary), currentNotifications.length()))
.setContentText(truncateWithEllipses(joinNames(context, currentNotifications), 40));
} catch (JSONException e) {
e.printStackTrace();
Log.d(TAG, Log.getStackTraceString(e));
}
}

View file

@ -17,6 +17,7 @@ package com.keylesspalace.tusky.util;
import android.os.Build;
import android.support.annotation.NonNull;
import android.util.Log;
import com.keylesspalace.tusky.BuildConfig;

View file

@ -5,6 +5,7 @@ import android.content.ClipboardManager;
import android.content.Context;
import android.os.AsyncTask;
import android.text.TextUtils;
import android.util.Log;
import android.webkit.URLUtil;
import org.jsoup.Connection;

View file

@ -0,0 +1,238 @@
package com.keylesspalace.tusky.util;
import android.app.NotificationManager;
import android.content.Context;
import android.support.annotation.NonNull;
import android.text.Spanned;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.entity.Notification;
import com.keylesspalace.tusky.json.SpannedTypeAdapter;
import com.keylesspalace.tusky.json.StringWithEmoji;
import com.keylesspalace.tusky.json.StringWithEmojiTypeAdapter;
import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.DisconnectedBufferOptions;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import java.io.InputStream;
import java.util.ArrayDeque;
import java.util.ArrayList;
import static android.content.Context.NOTIFICATION_SERVICE;
public class PushNotificationClient {
private static final String TAG = "PushNotificationClient";
private static final int NOTIFY_ID = 666;
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 ArrayDeque<QueuedAction> queuedActions;
private ArrayList<String> subscribedTopics;
public PushNotificationClient(final @NonNull Context applicationContext,
@NonNull String serverUri) {
queuedActions = new ArrayDeque<>();
subscribedTopics = new ArrayList<>();
// Create the MQTT client.
String clientId = MqttClient.generateClientId();
mqttAndroidClient = new MqttAndroidClient(applicationContext, serverUri, clientId);
mqttAndroidClient.setCallback(new MqttCallbackExtended() {
@Override
public void connectComplete(boolean reconnect, String serverURI) {
if (reconnect) {
flushQueuedActions();
for (String topic : subscribedTopics) {
subscribeToTopic(topic);
}
}
}
@Override
public void connectionLost(Throwable cause) {
onConnectionLost();
}
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
onMessageReceived(applicationContext, new String(message.getPayload()));
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
// This client is read-only, so this is unused.
}
});
}
private void flushQueuedActions() {
while (!queuedActions.isEmpty()) {
QueuedAction action = queuedActions.pop();
switch (action.type) {
case SUBSCRIBE: subscribeToTopic(action.topic); break;
case UNSUBSCRIBE: unsubscribeToTopic(action.topic); break;
case DISCONNECT: disconnect(); break;
}
}
}
/** Connect to the MQTT broker. */
public void connect(Context context) {
MqttConnectOptions options = new MqttConnectOptions();
options.setAutomaticReconnect(true);
options.setCleanSession(false);
try {
String password = context.getString(R.string.tusky_api_keystore_password);
InputStream keystore = context.getResources().openRawResource(R.raw.keystore_tusky_api);
try {
options.setSocketFactory(mqttAndroidClient.getSSLSocketFactory(keystore, password));
} finally {
IOUtils.closeQuietly(keystore);
}
mqttAndroidClient.connect(options).setActionCallback(new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken asyncActionToken) {
DisconnectedBufferOptions bufferOptions = new DisconnectedBufferOptions();
bufferOptions.setBufferEnabled(true);
bufferOptions.setBufferSize(100);
bufferOptions.setPersistBuffer(false);
bufferOptions.setDeleteOldestMessages(false);
mqttAndroidClient.setBufferOpts(bufferOptions);
onConnectionSuccess();
flushQueuedActions();
}
@Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.e(TAG, "An exception occurred while connecting. " + exception.getMessage()
+ " " + exception.getCause());
onConnectionFailure();
}
});
} catch (MqttException e) {
Log.e(TAG, "An exception occurred while connecpting. " + e.getMessage());
onConnectionFailure();
}
}
private void onConnectionSuccess() {
Log.v(TAG, "The connection succeeded.");
}
private void onConnectionFailure() {
Log.v(TAG, "The connection failed.");
}
private void onConnectionLost() {
Log.v(TAG, "The connection was lost.");
}
/** Disconnect from the MQTT broker. */
public void disconnect() {
if (!mqttAndroidClient.isConnected()) {
queuedActions.add(new QueuedAction(QueuedAction.Type.DISCONNECT));
return;
}
try {
mqttAndroidClient.disconnect();
} catch (MqttException ex) {
Log.e(TAG, "An exception occurred while disconnecting.");
onDisconnectFailed();
}
}
private void onDisconnectFailed() {
Log.v(TAG, "Failed while disconnecting from the broker.");
}
/** Subscribe to the push notification topic. */
public void subscribeToTopic(final String topic) {
if (!mqttAndroidClient.isConnected()) {
queuedActions.add(new QueuedAction(QueuedAction.Type.SUBSCRIBE, topic));
return;
}
try {
mqttAndroidClient.subscribe(topic, 0, null, new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken asyncActionToken) {
subscribedTopics.add(topic);
onConnectionSuccess();
}
@Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.e(TAG, "An exception occurred while subscribing." + exception.getMessage());
onConnectionFailure();
}
});
} catch (MqttException e) {
Log.e(TAG, "An exception occurred while subscribing." + e.getMessage());
onConnectionFailure();
}
}
/** Unsubscribe from the push notification topic. */
public void unsubscribeToTopic(String topic) {
if (!mqttAndroidClient.isConnected()) {
queuedActions.add(new QueuedAction(QueuedAction.Type.UNSUBSCRIBE, topic));
return;
}
try {
mqttAndroidClient.unsubscribe(topic);
subscribedTopics.remove(topic);
} catch (MqttException e) {
Log.e(TAG, "An exception occurred while unsubscribing." + e.getMessage());
onConnectionFailure();
}
}
private void onMessageReceived(final Context context, String message) {
Log.v(TAG, "Notification received: " + message);
Gson gson = new GsonBuilder()
.registerTypeAdapter(Spanned.class, new SpannedTypeAdapter())
.registerTypeAdapter(StringWithEmoji.class, new StringWithEmojiTypeAdapter())
.create();
Notification notification = gson.fromJson(message, Notification.class);
NotificationMaker.make(context, NOTIFY_ID, notification);
}
public void clearNotifications(Context context) {
((NotificationManager) (context.getSystemService(NOTIFICATION_SERVICE))).cancel(NOTIFY_ID);
}
public String getDeviceToken() {
return mqttAndroidClient.getClientId();
}
}