diff --git a/app/.gitignore b/app/.gitignore index 61e52b44..d4026ab8 100644 --- a/app/.gitignore +++ b/app/.gitignore @@ -1,3 +1,4 @@ /build app-release.apk app-google-release.apk +src/main/res/raw/keystore_tusky_api.bks diff --git a/app/build.gradle b/app/build.gradle index 5ef9205d..cb33758a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,14 +12,6 @@ android { testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary true } - productFlavors { - google { - buildConfigField "boolean", "USES_PUSH_NOTIFICATIONS", "true" - } - fdroid { - buildConfigField "boolean", "USES_PUSH_NOTIFICATIONS", "false" - } - } buildTypes { release { minifyEnabled true @@ -59,14 +51,10 @@ dependencies { compile 'com.github.arimorty:floatingsearchview:2.0.4' compile 'com.theartofdev.edmodo:android-image-cropper:2.4.3' compile 'com.jakewharton:butterknife:8.5.1' - googleCompile 'com.google.firebase:firebase-messaging:10.2.4' - googleCompile 'com.google.firebase:firebase-crash:10.2.4' - testCompile 'junit:junit:4.12' - annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1' compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0' compile('org.eclipse.paho:org.eclipse.paho.android.service:1.1.1') { exclude module: 'support-v4' } + testCompile 'junit:junit:4.12' + annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1' } - -apply plugin: 'com.google.gms.google-services' diff --git a/app/google-services.json b/app/google-services.json deleted file mode 100644 index bfd19f88..00000000 --- a/app/google-services.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "project_info": { - "project_number": "268851337880", - "firebase_url": "https://tusky-62772.firebaseio.com", - "project_id": "tusky-62772", - "storage_bucket": "tusky-62772.appspot.com" - }, - "client": [ - { - "client_info": { - "mobilesdk_app_id": "1:268851337880:android:fc4111b1d145a00e", - "android_client_info": { - "package_name": "com.keylesspalace.tusky" - } - }, - "oauth_client": [ - { - "client_id": "268851337880-eie2ssto2d21bfihn9d1qupcrke8oebf.apps.googleusercontent.com", - "client_type": 1, - "android_info": { - "package_name": "com.keylesspalace.tusky", - "certificate_hash": "18d196307d6e928e99c2e0bb9818c01c38aff2f9" - } - }, - { - "client_id": "268851337880-n19d05m282nirs1fc9kdd5n4of6je4fk.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyCbJtSjuk4I3Jy8PdUaO3TaQOXubcOUElo" - } - ], - "services": { - "analytics_service": { - "status": 1 - }, - "appinvite_service": { - "status": 2, - "other_platform_oauth_client": [ - { - "client_id": "268851337880-n19d05m282nirs1fc9kdd5n4of6je4fk.apps.googleusercontent.com", - "client_type": 3 - } - ] - }, - "ads_service": { - "status": 2 - } - } - } - ], - "configuration_version": "1" -} \ No newline at end of file diff --git a/app/src/fdroid/AndroidManifest.xml b/app/src/fdroid/AndroidManifest.xml deleted file mode 100644 index b7060e6e..00000000 --- a/app/src/fdroid/AndroidManifest.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/fdroid/java/com/keylesspalace/tusky/MessagingService.java b/app/src/fdroid/java/com/keylesspalace/tusky/MessagingService.java deleted file mode 100644 index eaa1b1b5..00000000 --- a/app/src/fdroid/java/com/keylesspalace/tusky/MessagingService.java +++ /dev/null @@ -1,142 +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 . */ - -package com.keylesspalace.tusky; - -import android.app.IntentService; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; -import android.text.Spanned; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; - -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 com.keylesspalace.tusky.network.MastodonAPI; -import com.keylesspalace.tusky.util.NotificationMaker; -import com.keylesspalace.tusky.util.OkHttpUtils; - -import java.util.HashSet; -import java.util.List; - -import java.io.IOException; -import java.util.Set; - -import okhttp3.Interceptor; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; -import retrofit2.Retrofit; -import retrofit2.converter.gson.GsonConverterFactory; - -public class MessagingService extends IntentService { - public static final int NOTIFY_ID = 6; // This is an arbitrary number. - - private MastodonAPI mastodonAPI; - - public MessagingService() { - super("Tusky Pull Notification Service"); - } - - @Override - protected void onHandleIntent(Intent intent) { - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences( - getApplicationContext()); - boolean enabled = preferences.getBoolean("notificationsEnabled", true); - if (!enabled) { - return; - } - - createMastodonApi(); - - mastodonAPI.notifications(null, null, null).enqueue(new Callback>() { - @Override - public void onResponse(Call> call, - Response> response) { - if (response.isSuccessful()) { - onNotificationsReceived(response.body()); - } - } - - @Override - public void onFailure(Call> call, Throwable t) {} - }); - } - - private void createMastodonApi() { - SharedPreferences preferences = getSharedPreferences( - getString(R.string.preferences_file_key), Context.MODE_PRIVATE); - final String domain = preferences.getString("domain", null); - final String accessToken = preferences.getString("accessToken", null); - - OkHttpClient okHttpClient = OkHttpUtils.getCompatibleClientBuilder() - .addInterceptor(new Interceptor() { - @Override - public okhttp3.Response intercept(Chain chain) throws IOException { - Request originalRequest = chain.request(); - - Request.Builder builder = originalRequest.newBuilder() - .header("Authorization", String.format("Bearer %s", accessToken)); - - Request newRequest = builder.build(); - - return chain.proceed(newRequest); - } - }) - .build(); - - Gson gson = new GsonBuilder() - .registerTypeAdapter(Spanned.class, new SpannedTypeAdapter()) - .registerTypeAdapter(StringWithEmoji.class, new StringWithEmojiTypeAdapter()) - .create(); - - Retrofit retrofit = new Retrofit.Builder() - .baseUrl("https://" + domain) - .client(okHttpClient) - .addConverterFactory(GsonConverterFactory.create(gson)) - .build(); - - mastodonAPI = retrofit.create(MastodonAPI.class); - } - - private void onNotificationsReceived(List notificationList) { - SharedPreferences notificationsPreferences = getSharedPreferences( - "Notifications", Context.MODE_PRIVATE); - Set currentIds = notificationsPreferences.getStringSet( - "current_ids", new HashSet()); - for (Notification notification : notificationList) { - String id = notification.id; - if (!currentIds.contains(id)) { - currentIds.add(id); - NotificationMaker.make(this, NOTIFY_ID, notification); - } - } - notificationsPreferences.edit() - .putStringSet("current_ids", currentIds) - .apply(); - } - - public static String getInstanceToken() { - // This is only used for the "google" build flavor, so this version is just a stub method. - return null; - } -} diff --git a/app/src/google/AndroidManifest.xml b/app/src/google/AndroidManifest.xml deleted file mode 100644 index 20ecbe94..00000000 --- a/app/src/google/AndroidManifest.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/app/src/google/java/com/keylesspalace/tusky/MessagingService.java b/app/src/google/java/com/keylesspalace/tusky/MessagingService.java deleted file mode 100644 index 4a2a55da..00000000 --- a/app/src/google/java/com/keylesspalace/tusky/MessagingService.java +++ /dev/null @@ -1,133 +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 . - * - * If you modify this Program, or any covered work, by linking or combining it with Firebase Cloud - * Messaging and Firebase Crash Reporting (or a modified version of those libraries), containing - * parts covered by the Google APIs Terms of Service, the licensors of this Program grant you - * additional permission to convey the resulting work. */ - -package com.keylesspalace.tusky; - -import android.content.Context; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; -import android.text.Spanned; - -import com.google.firebase.iid.FirebaseInstanceId; -import com.google.firebase.messaging.FirebaseMessagingService; -import com.google.firebase.messaging.RemoteMessage; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; - -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 com.keylesspalace.tusky.network.MastodonAPI; -import com.keylesspalace.tusky.util.Log; -import com.keylesspalace.tusky.util.NotificationMaker; -import com.keylesspalace.tusky.util.OkHttpUtils; - -import java.io.IOException; - -import okhttp3.Interceptor; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; -import retrofit2.Retrofit; -import retrofit2.converter.gson.GsonConverterFactory; - -public class MessagingService extends FirebaseMessagingService { - private MastodonAPI mastodonAPI; - private static final String TAG = "MessagingService"; - public static final int NOTIFY_ID = 666; - - @Override - public void onMessageReceived(RemoteMessage remoteMessage) { - Log.d(TAG, remoteMessage.getFrom()); - Log.d(TAG, remoteMessage.toString()); - - String notificationId = remoteMessage.getData().get("notification_id"); - - if (notificationId == null) { - Log.e(TAG, "No notification ID in payload!!"); - return; - } - - Log.d(TAG, notificationId); - - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences( - getApplicationContext()); - boolean enabled = preferences.getBoolean("notificationsEnabled", true); - if (!enabled) { - return; - } - - createMastodonAPI(); - - mastodonAPI.notification(notificationId).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - NotificationMaker.make(MessagingService.this, NOTIFY_ID, response.body()); - } - } - - @Override - public void onFailure(Call call, Throwable t) {} - }); - } - - private void createMastodonAPI() { - SharedPreferences preferences = getSharedPreferences(getString(R.string.preferences_file_key), Context.MODE_PRIVATE); - final String domain = preferences.getString("domain", null); - final String accessToken = preferences.getString("accessToken", null); - - OkHttpClient okHttpClient = OkHttpUtils.getCompatibleClientBuilder() - .addInterceptor(new Interceptor() { - @Override - public okhttp3.Response intercept(Chain chain) throws IOException { - Request originalRequest = chain.request(); - - Request.Builder builder = originalRequest.newBuilder() - .header("Authorization", String.format("Bearer %s", accessToken)); - - Request newRequest = builder.build(); - - return chain.proceed(newRequest); - } - }) - .build(); - - Gson gson = new GsonBuilder() - .registerTypeAdapter(Spanned.class, new SpannedTypeAdapter()) - .registerTypeAdapter(StringWithEmoji.class, new StringWithEmojiTypeAdapter()) - .create(); - - Retrofit retrofit = new Retrofit.Builder() - .baseUrl("https://" + domain) - .client(okHttpClient) - .addConverterFactory(GsonConverterFactory.create(gson)) - .build(); - - mastodonAPI = retrofit.create(MastodonAPI.class); - } - - public static String getInstanceToken() { - return FirebaseInstanceId.getInstance().getToken(); - } -} diff --git a/app/src/google/java/com/keylesspalace/tusky/MyFirebaseInstanceIdService.java b/app/src/google/java/com/keylesspalace/tusky/MyFirebaseInstanceIdService.java deleted file mode 100644 index 14d640d5..00000000 --- a/app/src/google/java/com/keylesspalace/tusky/MyFirebaseInstanceIdService.java +++ /dev/null @@ -1,86 +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 . - * - * If you modify this Program, or any covered work, by linking or combining it with Firebase Cloud - * Messaging and Firebase Crash Reporting (or a modified version of those libraries), containing - * parts covered by the Google APIs Terms of Service, the licensors of this Program grant you - * additional permission to convey the resulting work. */ - -package com.keylesspalace.tusky; - -import android.content.Context; -import android.content.SharedPreferences; - -import com.google.firebase.iid.FirebaseInstanceId; -import com.google.firebase.iid.FirebaseInstanceIdService; -import com.keylesspalace.tusky.network.TuskyAPI; -import com.keylesspalace.tusky.util.Log; -import com.keylesspalace.tusky.util.OkHttpUtils; - -import okhttp3.ResponseBody; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; -import retrofit2.Retrofit; - -public class MyFirebaseInstanceIdService extends FirebaseInstanceIdService { - private static final String TAG = "com.keylesspalace.tusky.MyFirebaseInstanceIdService"; - - private TuskyAPI tuskyAPI; - - protected void createTuskyAPI() { - Retrofit retrofit = new Retrofit.Builder() - .baseUrl(getString(R.string.tusky_api_url)) - .client(OkHttpUtils.getCompatibleClient()) - .build(); - - tuskyAPI = retrofit.create(TuskyAPI.class); - } - - @Override - public void onTokenRefresh() { - createTuskyAPI(); - - String refreshedToken = FirebaseInstanceId.getInstance().getToken(); - SharedPreferences preferences = getSharedPreferences(getString(R.string.preferences_file_key), Context.MODE_PRIVATE); - String accessToken = preferences.getString("accessToken", null); - String domain = preferences.getString("domain", null); - - if (accessToken != null && domain != null) { - tuskyAPI.unregister("https://" + domain, accessToken).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - Log.d(TAG, response.message()); - } - - @Override - public void onFailure(Call call, Throwable t) { - Log.d(TAG, t.getMessage()); - } - }); - tuskyAPI.register("https://" + domain, accessToken, refreshedToken).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - Log.d(TAG, response.message()); - } - - @Override - public void onFailure(Call call, Throwable t) { - Log.d(TAG, t.getMessage()); - } - }); - } - } -} diff --git a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java index 4ba4c0b8..e88cd1cb 100644 --- a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java @@ -15,8 +15,6 @@ package com.keylesspalace.tusky; -import android.app.AlarmManager; -import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -24,7 +22,6 @@ import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.os.Bundle; -import android.os.SystemClock; import android.preference.PreferenceManager; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; @@ -55,7 +52,6 @@ public class BaseActivity extends AppCompatActivity { public MastodonAPI mastodonAPI; protected PushNotificationClient pushNotificationClient; protected Dispatcher mastodonApiDispatcher; - protected PendingIntent serviceAlarmIntent; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -156,10 +152,8 @@ public class BaseActivity extends AppCompatActivity { } protected void createTuskyAPI() { - if (BuildConfig.USES_PUSH_NOTIFICATIONS) { - // TODO: Remove this test broker address. - pushNotificationClient = new PushNotificationClient(this, "tcp://104.236.116.199:1883"); - } + pushNotificationClient = new PushNotificationClient(this, + getString(R.string.tusky_api_url)); } protected void redirectIfNotLoggedIn() { @@ -193,28 +187,10 @@ public class BaseActivity extends AppCompatActivity { } protected void enablePushNotifications() { - if (BuildConfig.USES_PUSH_NOTIFICATIONS) { - pushNotificationClient.subscribeToTopic(); - } else { - // Start up the MessagingService on a repeating interval for "pull" notifications. - long checkInterval = 60 * 1000 * 5; - AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); - Intent intent = new Intent(this, MessagingService.class); - final int SERVICE_REQUEST_CODE = 8574603; // This number is arbitrary. - serviceAlarmIntent = PendingIntent.getService(this, SERVICE_REQUEST_CODE, intent, - PendingIntent.FLAG_UPDATE_CURRENT); - alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, - SystemClock.elapsedRealtime(), checkInterval, serviceAlarmIntent); - } + pushNotificationClient.subscribeToTopic(); } protected void disablePushNotifications() { - if (BuildConfig.USES_PUSH_NOTIFICATIONS) { - pushNotificationClient.unsubscribeToTopic(); - } else if (serviceAlarmIntent != null) { - // Cancel the repeating call for "pull" notifications. - AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); - alarmManager.cancel(serviceAlarmIntent); - } + pushNotificationClient.unsubscribeToTopic(); } } diff --git a/app/src/main/java/com/keylesspalace/tusky/MainActivity.java b/app/src/main/java/com/keylesspalace/tusky/MainActivity.java index 3d39b81a..4c4c2db5 100644 --- a/app/src/main/java/com/keylesspalace/tusky/MainActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/MainActivity.java @@ -215,8 +215,7 @@ public class MainActivity extends BaseActivity implements SFragment.OnUserRemove .putString("current", "[]") .apply(); - ((NotificationManager) (getSystemService(NOTIFICATION_SERVICE))) - .cancel(MessagingService.NOTIFY_ID); + pushNotificationClient.clearNotifications(); /* After editing a profile, the profile header in the navigation drawer needs to be * refreshed */ 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 ba8f3450..6c944f75 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/PushNotificationClient.java +++ b/app/src/main/java/com/keylesspalace/tusky/util/PushNotificationClient.java @@ -26,6 +26,7 @@ import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttMessage; import java.io.IOException; +import java.io.InputStream; import java.util.ArrayDeque; import okhttp3.Interceptor; @@ -88,20 +89,24 @@ public class PushNotificationClient { options.setAutomaticReconnect(true); options.setCleanSession(false); try { - /* TLS connection stuffs - InputStream input = context.getResources().openRawResource(R.raw.keystore_tusky_api); + /* String password = context.getString(R.string.tusky_api_keystore_password); - options.setSocketFactory(mqttAndroidClient.getSSLSocketFactory(input, 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 options = new DisconnectedBufferOptions(); - options.setBufferEnabled(true); - options.setBufferSize(100); - options.setPersistBuffer(false); - options.setDeleteOldestMessages(false); - mqttAndroidClient.setBufferOpts(options); + DisconnectedBufferOptions bufferOptions = new DisconnectedBufferOptions(); + bufferOptions.setBufferEnabled(true); + bufferOptions.setBufferSize(100); + bufferOptions.setPersistBuffer(false); + bufferOptions.setDeleteOldestMessages(false); + mqttAndroidClient.setBufferOpts(bufferOptions); onConnectionSuccess(); connected = true; flushQueuedActions(); @@ -253,4 +258,8 @@ public class PushNotificationClient { mastodonApi = retrofit.create(MastodonAPI.class); } + + public void clearNotifications() { + // TODO: make it happen + } } diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml index 73a4b542..212d54db 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 - https://tuskynotifier.keylesspalace.com + tcp://tuskyapi.keylesspalace.com your_password_here oauth2redirect diff --git a/build.gradle b/build.gradle index 80e6fd50..bfed5920 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,6 @@ buildscript { // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files - classpath 'com.google.gms:google-services:3.0.0' } }