Removes the product flavor split.

This commit is contained in:
Vavassor 2017-05-18 18:10:46 -04:00
parent 6752d45d4b
commit 388ecfcf2e
13 changed files with 27 additions and 501 deletions

1
app/.gitignore vendored
View file

@ -1,3 +1,4 @@
/build /build
app-release.apk app-release.apk
app-google-release.apk app-google-release.apk
src/main/res/raw/keystore_tusky_api.bks

View file

@ -12,14 +12,6 @@ android {
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary true vectorDrawables.useSupportLibrary true
} }
productFlavors {
google {
buildConfigField "boolean", "USES_PUSH_NOTIFICATIONS", "true"
}
fdroid {
buildConfigField "boolean", "USES_PUSH_NOTIFICATIONS", "false"
}
}
buildTypes { buildTypes {
release { release {
minifyEnabled true minifyEnabled true
@ -59,14 +51,10 @@ dependencies {
compile 'com.github.arimorty:floatingsearchview:2.0.4' compile 'com.github.arimorty:floatingsearchview:2.0.4'
compile 'com.theartofdev.edmodo:android-image-cropper:2.4.3' compile 'com.theartofdev.edmodo:android-image-cropper:2.4.3'
compile 'com.jakewharton:butterknife:8.5.1' 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.client.mqttv3:1.1.0'
compile('org.eclipse.paho:org.eclipse.paho.android.service:1.1.1') { compile('org.eclipse.paho:org.eclipse.paho.android.service:1.1.1') {
exclude module: 'support-v4' exclude module: 'support-v4'
} }
testCompile 'junit:junit:4.12'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'
} }
apply plugin: 'com.google.gms.google-services'

View file

@ -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"
}

View file

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.keylesspalace.tusky">
<application>
<service
android:name=".MessagingService"
android:enabled="true"
android:exported="true" />
</application>
</manifest>

View file

@ -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 <http://www.gnu.org/licenses>. */
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<List<Notification>>() {
@Override
public void onResponse(Call<List<Notification>> call,
Response<List<Notification>> response) {
if (response.isSuccessful()) {
onNotificationsReceived(response.body());
}
}
@Override
public void onFailure(Call<List<Notification>> 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<Notification> notificationList) {
SharedPreferences notificationsPreferences = getSharedPreferences(
"Notifications", Context.MODE_PRIVATE);
Set<String> currentIds = notificationsPreferences.getStringSet(
"current_ids", new HashSet<String>());
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;
}
}

View file

@ -1,18 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.keylesspalace.tusky">
<application>
<meta-data android:name="firebase_analytics_collection_enabled" android:value="false" />
<service android:name=".MyFirebaseInstanceIdService" android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<service android:name=".MessagingService" android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
</application>
</manifest>

View file

@ -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 <http://www.gnu.org/licenses>.
*
* 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<Notification>() {
@Override
public void onResponse(Call<Notification> call, Response<Notification> response) {
if (response.isSuccessful()) {
NotificationMaker.make(MessagingService.this, NOTIFY_ID, response.body());
}
}
@Override
public void onFailure(Call<Notification> 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();
}
}

View file

@ -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 <http://www.gnu.org/licenses>.
*
* 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<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Log.d(TAG, response.message());
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d(TAG, t.getMessage());
}
});
tuskyAPI.register("https://" + domain, accessToken, refreshedToken).enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Log.d(TAG, response.message());
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d(TAG, t.getMessage());
}
});
}
}
}

View file

@ -15,8 +15,6 @@
package com.keylesspalace.tusky; package com.keylesspalace.tusky;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
@ -24,7 +22,6 @@ import android.graphics.Color;
import android.graphics.PorterDuff; import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Bundle; import android.os.Bundle;
import android.os.SystemClock;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
@ -55,7 +52,6 @@ public class BaseActivity extends AppCompatActivity {
public MastodonAPI mastodonAPI; public MastodonAPI mastodonAPI;
protected PushNotificationClient pushNotificationClient; protected PushNotificationClient pushNotificationClient;
protected Dispatcher mastodonApiDispatcher; protected Dispatcher mastodonApiDispatcher;
protected PendingIntent serviceAlarmIntent;
@Override @Override
protected void onCreate(@Nullable Bundle savedInstanceState) { protected void onCreate(@Nullable Bundle savedInstanceState) {
@ -156,10 +152,8 @@ public class BaseActivity extends AppCompatActivity {
} }
protected void createTuskyAPI() { protected void createTuskyAPI() {
if (BuildConfig.USES_PUSH_NOTIFICATIONS) { pushNotificationClient = new PushNotificationClient(this,
// TODO: Remove this test broker address. getString(R.string.tusky_api_url));
pushNotificationClient = new PushNotificationClient(this, "tcp://104.236.116.199:1883");
}
} }
protected void redirectIfNotLoggedIn() { protected void redirectIfNotLoggedIn() {
@ -193,28 +187,10 @@ public class BaseActivity extends AppCompatActivity {
} }
protected void enablePushNotifications() { protected void enablePushNotifications() {
if (BuildConfig.USES_PUSH_NOTIFICATIONS) { pushNotificationClient.subscribeToTopic();
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);
}
} }
protected void disablePushNotifications() { protected void disablePushNotifications() {
if (BuildConfig.USES_PUSH_NOTIFICATIONS) { pushNotificationClient.unsubscribeToTopic();
pushNotificationClient.unsubscribeToTopic();
} else if (serviceAlarmIntent != null) {
// Cancel the repeating call for "pull" notifications.
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(serviceAlarmIntent);
}
} }
} }

View file

@ -215,8 +215,7 @@ public class MainActivity extends BaseActivity implements SFragment.OnUserRemove
.putString("current", "[]") .putString("current", "[]")
.apply(); .apply();
((NotificationManager) (getSystemService(NOTIFICATION_SERVICE))) pushNotificationClient.clearNotifications();
.cancel(MessagingService.NOTIFY_ID);
/* After editing a profile, the profile header in the navigation drawer needs to be /* After editing a profile, the profile header in the navigation drawer needs to be
* refreshed */ * refreshed */

View file

@ -26,6 +26,7 @@ import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage; import org.eclipse.paho.client.mqttv3.MqttMessage;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import okhttp3.Interceptor; import okhttp3.Interceptor;
@ -88,20 +89,24 @@ public class PushNotificationClient {
options.setAutomaticReconnect(true); options.setAutomaticReconnect(true);
options.setCleanSession(false); options.setCleanSession(false);
try { try {
/* TLS connection stuffs /*
InputStream input = context.getResources().openRawResource(R.raw.keystore_tusky_api);
String password = context.getString(R.string.tusky_api_keystore_password); 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() { mqttAndroidClient.connect(options).setActionCallback(new IMqttActionListener() {
@Override @Override
public void onSuccess(IMqttToken asyncActionToken) { public void onSuccess(IMqttToken asyncActionToken) {
DisconnectedBufferOptions options = new DisconnectedBufferOptions(); DisconnectedBufferOptions bufferOptions = new DisconnectedBufferOptions();
options.setBufferEnabled(true); bufferOptions.setBufferEnabled(true);
options.setBufferSize(100); bufferOptions.setBufferSize(100);
options.setPersistBuffer(false); bufferOptions.setPersistBuffer(false);
options.setDeleteOldestMessages(false); bufferOptions.setDeleteOldestMessages(false);
mqttAndroidClient.setBufferOpts(options); mqttAndroidClient.setBufferOpts(bufferOptions);
onConnectionSuccess(); onConnectionSuccess();
connected = true; connected = true;
flushQueuedActions(); flushQueuedActions();
@ -253,4 +258,8 @@ public class PushNotificationClient {
mastodonApi = retrofit.create(MastodonAPI.class); mastodonApi = retrofit.create(MastodonAPI.class);
} }
public void clearNotifications() {
// TODO: make it happen
}
} }

View file

@ -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">https://tuskynotifier.keylesspalace.com</string> <string name="tusky_api_url" translatable="false">tcp://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>

View file

@ -9,7 +9,6 @@ buildscript {
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files
classpath 'com.google.gms:google-services:3.0.0'
} }
} }