Reverts notifications from MQTT prototype to pull notifications.
This commit is contained in:
parent
14d02e72b7
commit
f68f6d7473
9 changed files with 295 additions and 148 deletions
|
@ -98,7 +98,7 @@
|
||||||
|
|
||||||
<receiver android:name=".receiver.NotificationClearBroadcastReceiver" />
|
<receiver android:name=".receiver.NotificationClearBroadcastReceiver" />
|
||||||
|
|
||||||
<service android:name="org.eclipse.paho.android.service.MqttService" />
|
<service android:name=".service.PullNotificationService" />
|
||||||
<service
|
<service
|
||||||
tools:targetApi="24"
|
tools:targetApi="24"
|
||||||
android:name="com.keylesspalace.tusky.service.TuskyTileService"
|
android:name="com.keylesspalace.tusky.service.TuskyTileService"
|
||||||
|
|
|
@ -15,6 +15,9 @@
|
||||||
|
|
||||||
package com.keylesspalace.tusky;
|
package com.keylesspalace.tusky;
|
||||||
|
|
||||||
|
import android.app.AlarmManager;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
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;
|
||||||
|
@ -22,24 +25,23 @@ 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;
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
import android.util.Log;
|
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.keylesspalace.tusky.entity.Session;
|
|
||||||
import com.keylesspalace.tusky.json.SpannedTypeAdapter;
|
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.network.TuskyApi;
|
||||||
|
import com.keylesspalace.tusky.service.PullNotificationService;
|
||||||
import com.keylesspalace.tusky.util.OkHttpUtils;
|
import com.keylesspalace.tusky.util.OkHttpUtils;
|
||||||
import com.keylesspalace.tusky.util.PushNotificationClient;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@ -48,18 +50,14 @@ 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
|
protected static final int SERVICE_REQUEST_CODE = 8574603; // This number is arbitrary.
|
||||||
|
|
||||||
public MastodonApi mastodonApi;
|
public MastodonApi mastodonApi;
|
||||||
public TuskyApi tuskyApi;
|
public TuskyApi tuskyApi;
|
||||||
protected PushNotificationClient pushNotificationClient;
|
|
||||||
protected Dispatcher mastodonApiDispatcher;
|
protected Dispatcher mastodonApiDispatcher;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -69,7 +67,6 @@ 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
|
||||||
|
@ -173,11 +170,6 @@ public class BaseActivity extends AppCompatActivity {
|
||||||
tuskyApi = retrofit.create(TuskyApi.class);
|
tuskyApi = retrofit.create(TuskyApi.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void createPushNotificationClient() {
|
|
||||||
pushNotificationClient = new PushNotificationClient(getApplicationContext(),
|
|
||||||
"ssl://" + getString(R.string.tusky_api_url) + ":8883");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void redirectIfNotLoggedIn() {
|
protected void redirectIfNotLoggedIn() {
|
||||||
SharedPreferences preferences = getPrivatePreferences();
|
SharedPreferences preferences = getPrivatePreferences();
|
||||||
String domain = preferences.getString("domain", null);
|
String domain = preferences.getString("domain", null);
|
||||||
|
@ -209,66 +201,47 @@ public class BaseActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void enablePushNotifications() {
|
protected void enablePushNotifications() {
|
||||||
Callback<ResponseBody> callback = new Callback<ResponseBody>() {
|
// Start up the PullNotificationService on a repeating interval.
|
||||||
@Override
|
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
public void onResponse(Call<ResponseBody> call,
|
String minutesString = preferences.getString("pullNotificationCheckInterval", "15");
|
||||||
retrofit2.Response<ResponseBody> response) {
|
long minutes = Long.valueOf(minutesString);
|
||||||
if (response.isSuccessful()) {
|
long checkInterval = 1000 * 60 * minutes;
|
||||||
pushNotificationClient.subscribeToTopic(getPushNotificationTopic());
|
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
|
||||||
pushNotificationClient.connect(BaseActivity.this);
|
Intent intent = new Intent(this, PullNotificationService.class);
|
||||||
} else {
|
PendingIntent serviceAlarmIntent = PendingIntent.getService(this, SERVICE_REQUEST_CODE,
|
||||||
onEnablePushNotificationsFailure(response.message());
|
intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
}
|
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
||||||
}
|
SystemClock.elapsedRealtime(), checkInterval, serviceAlarmIntent);
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Call<ResponseBody> call, Throwable t) {
|
|
||||||
onEnablePushNotificationsFailure(t.getMessage());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
String deviceToken = pushNotificationClient.getDeviceToken();
|
|
||||||
Session session = new Session(getDomain(), getAccessToken(), deviceToken);
|
|
||||||
tuskyApi.register(session)
|
|
||||||
.enqueue(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onEnablePushNotificationsFailure(String message) {
|
|
||||||
Log.e(TAG, "Enabling push notifications failed. " + message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void disablePushNotifications() {
|
protected void disablePushNotifications() {
|
||||||
Callback<ResponseBody> callback = new Callback<ResponseBody>() {
|
// Cancel the repeating call for "pull" notifications.
|
||||||
@Override
|
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
|
||||||
public void onResponse(Call<ResponseBody> call,
|
Intent intent = new Intent(this, PullNotificationService.class);
|
||||||
retrofit2.Response<ResponseBody> response) {
|
PendingIntent serviceAlarmIntent = PendingIntent.getService(this, SERVICE_REQUEST_CODE,
|
||||||
if (response.isSuccessful()) {
|
intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
pushNotificationClient.unsubscribeToTopic(getPushNotificationTopic());
|
alarmManager.cancel(serviceAlarmIntent);
|
||||||
} else {
|
|
||||||
onDisablePushNotificationsFailure();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Call<ResponseBody> call, Throwable t) {
|
|
||||||
onDisablePushNotificationsFailure();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
String deviceToken = pushNotificationClient.getDeviceToken();
|
|
||||||
Session session = new Session(getDomain(), getAccessToken(), deviceToken);
|
|
||||||
tuskyApi.unregister(session)
|
|
||||||
.enqueue(callback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onDisablePushNotificationsFailure() {
|
protected void clearNotifications() {
|
||||||
Log.e(TAG, "Disabling push notifications failed.");
|
SharedPreferences notificationPreferences = getApplicationContext()
|
||||||
|
.getSharedPreferences("Notifications", MODE_PRIVATE);
|
||||||
|
notificationPreferences.edit()
|
||||||
|
.putString("current", "[]")
|
||||||
|
.apply();
|
||||||
|
|
||||||
|
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||||
|
manager.cancel(PullNotificationService.NOTIFY_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getPushNotificationTopic() {
|
protected void setPullNotificationCheckInterval(long minutes) {
|
||||||
return String.format("%s/%s/#", getDomain(), getAccessToken());
|
long checkInterval = 1000 * 60 * minutes;
|
||||||
}
|
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
|
||||||
|
Intent intent = new Intent(this, PullNotificationService.class);
|
||||||
private String getDomain() {
|
PendingIntent serviceAlarmIntent = PendingIntent.getService(this, SERVICE_REQUEST_CODE,
|
||||||
return getPrivatePreferences()
|
intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
.getString("domain", null);
|
alarmManager.cancel(serviceAlarmIntent);
|
||||||
|
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
||||||
|
SystemClock.elapsedRealtime(), checkInterval, serviceAlarmIntent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -210,17 +210,19 @@ public class MainActivity extends BaseActivity {
|
||||||
composeButton = floatingBtn;
|
composeButton = floatingBtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
|
||||||
|
ArrayList<Integer> pageHistoryList = new ArrayList<>();
|
||||||
|
pageHistoryList.addAll(pageHistory);
|
||||||
|
outState.putIntegerArrayList("pageHistory", pageHistoryList);
|
||||||
|
super.onSaveInstanceState(outState, outPersistentState);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
SharedPreferences notificationPreferences = getApplicationContext()
|
clearNotifications();
|
||||||
.getSharedPreferences("Notifications", MODE_PRIVATE);
|
|
||||||
notificationPreferences.edit()
|
|
||||||
.putString("current", "[]")
|
|
||||||
.apply();
|
|
||||||
|
|
||||||
pushNotificationClient.clearNotifications(this);
|
|
||||||
|
|
||||||
/* 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 */
|
||||||
|
@ -234,11 +236,50 @@ public class MainActivity extends BaseActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
ArrayList<Integer> pageHistoryList = new ArrayList<>();
|
if (requestCode == COMPOSE_RESULT && resultCode == ComposeActivity.RESULT_OK) {
|
||||||
pageHistoryList.addAll(pageHistory);
|
Intent intent = new Intent(TimelineReceiver.Types.STATUS_COMPOSED);
|
||||||
outState.putIntegerArrayList("pageHistory", pageHistoryList);
|
LocalBroadcastManager.getInstance(getApplicationContext())
|
||||||
super.onSaveInstanceState(outState, outPersistentState);
|
.sendBroadcast(intent);
|
||||||
|
}
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackPressed() {
|
||||||
|
if (drawer != null && drawer.isDrawerOpen()) {
|
||||||
|
drawer.closeDrawer();
|
||||||
|
} else if (pageHistory.size() < 2) {
|
||||||
|
super.onBackPressed();
|
||||||
|
} else {
|
||||||
|
pageHistory.pop();
|
||||||
|
viewPager.setCurrentItem(pageHistory.peek());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||||
|
switch (keyCode) {
|
||||||
|
case KeyEvent.KEYCODE_MENU: {
|
||||||
|
if (drawer.isDrawerOpen()) {
|
||||||
|
drawer.closeDrawer();
|
||||||
|
} else {
|
||||||
|
drawer.openDrawer();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case KeyEvent.KEYCODE_SEARCH: {
|
||||||
|
startActivity(new Intent(this, SearchActivity.class));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.onKeyDown(keyCode, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix for GitHub issues #190, #259 (MainActivity won't restart on screen rotation.)
|
||||||
|
@Override
|
||||||
|
public void onConfigurationChanged(Configuration newConfig) {
|
||||||
|
super.onConfigurationChanged(newConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tintTab(TabLayout.Tab tab, boolean tinted) {
|
private void tintTab(TabLayout.Tab tab, boolean tinted) {
|
||||||
|
@ -465,51 +506,4 @@ public class MainActivity extends BaseActivity {
|
||||||
private void onFetchUserInfoFailure(Exception exception) {
|
private void onFetchUserInfoFailure(Exception exception) {
|
||||||
Log.e(TAG, "Failed to fetch user info. " + exception.getMessage());
|
Log.e(TAG, "Failed to fetch user info. " + exception.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
||||||
if (requestCode == COMPOSE_RESULT && resultCode == ComposeActivity.RESULT_OK) {
|
|
||||||
Intent intent = new Intent(TimelineReceiver.Types.STATUS_COMPOSED);
|
|
||||||
LocalBroadcastManager.getInstance(getApplicationContext())
|
|
||||||
.sendBroadcast(intent);
|
|
||||||
}
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBackPressed() {
|
|
||||||
if (drawer != null && drawer.isDrawerOpen()) {
|
|
||||||
drawer.closeDrawer();
|
|
||||||
} else if (pageHistory.size() < 2) {
|
|
||||||
super.onBackPressed();
|
|
||||||
} else {
|
|
||||||
pageHistory.pop();
|
|
||||||
viewPager.setCurrentItem(pageHistory.peek());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
|
||||||
switch (keyCode) {
|
|
||||||
case KeyEvent.KEYCODE_MENU: {
|
|
||||||
if (drawer.isDrawerOpen()) {
|
|
||||||
drawer.closeDrawer();
|
|
||||||
} else {
|
|
||||||
drawer.openDrawer();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case KeyEvent.KEYCODE_SEARCH: {
|
|
||||||
startActivity(new Intent(this, SearchActivity.class));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return super.onKeyDown(keyCode, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fix for GitHub issues #190, #259 (MainActivity won't restart on screen rotation.)
|
|
||||||
@Override
|
|
||||||
public void onConfigurationChanged(Configuration newConfig) {
|
|
||||||
super.onConfigurationChanged(newConfig);
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -59,24 +59,34 @@ public class PreferencesActivity extends BaseActivity
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||||
if (key.equals("lightTheme")) {
|
switch (key) {
|
||||||
themeSwitched = true;
|
case "lightTheme": {
|
||||||
// recreate() could be used instead, but it doesn't have an animation B).
|
themeSwitched = true;
|
||||||
Intent intent = getIntent();
|
// recreate() could be used instead, but it doesn't have an animation B).
|
||||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
|
Intent intent = getIntent();
|
||||||
Bundle savedInstanceState = new Bundle();
|
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
saveInstanceState(savedInstanceState);
|
Bundle savedInstanceState = new Bundle();
|
||||||
intent.putExtras(savedInstanceState);
|
saveInstanceState(savedInstanceState);
|
||||||
startActivity(intent);
|
intent.putExtras(savedInstanceState);
|
||||||
finish();
|
startActivity(intent);
|
||||||
overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
|
finish();
|
||||||
} else if (key.equals("notificationsEnabled")) {
|
overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
|
||||||
boolean notificationsEnabled = sharedPreferences.getBoolean("notificationsEnabled", true);
|
break;
|
||||||
|
}
|
||||||
if (notificationsEnabled) {
|
case "notificationsEnabled": {
|
||||||
enablePushNotifications();
|
boolean enabled = sharedPreferences.getBoolean("notificationsEnabled", true);
|
||||||
} else {
|
if (enabled) {
|
||||||
disablePushNotifications();
|
enablePushNotifications();
|
||||||
|
} else {
|
||||||
|
disablePushNotifications();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "pullNotificationCheckInterval": {
|
||||||
|
String s = sharedPreferences.getString("pullNotificationCheckInterval", "15");
|
||||||
|
long minutes = Long.valueOf(s);
|
||||||
|
setPullNotificationCheckInterval(minutes);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
/* 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.service;
|
||||||
|
|
||||||
|
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.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 com.keylesspalace.tusky.network.MastodonApi;
|
||||||
|
import com.keylesspalace.tusky.util.OkHttpUtils;
|
||||||
|
import com.keylesspalace.tusky.util.NotificationMaker;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
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 PullNotificationService extends IntentService {
|
||||||
|
public static final int NOTIFY_ID = 6; // This is an arbitrary number.
|
||||||
|
|
||||||
|
private MastodonApi mastodonApi;
|
||||||
|
|
||||||
|
public PullNotificationService() {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,7 +41,7 @@ import com.squareup.picasso.Target;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
|
|
||||||
class NotificationMaker {
|
public class NotificationMaker {
|
||||||
|
|
||||||
public static final String TAG = "NotificationMaker";
|
public static final String TAG = "NotificationMaker";
|
||||||
|
|
||||||
|
|
27
app/src/main/res/values/array.xml
Normal file
27
app/src/main/res/values/array.xml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string-array name="pull_notification_check_interval_names">
|
||||||
|
<item>5 minutes</item>
|
||||||
|
<item>10 minutes</item>
|
||||||
|
<item>15 minutes</item>
|
||||||
|
<item>20 minutes</item>
|
||||||
|
<item>25 minutes</item>
|
||||||
|
<item>30 minutes</item>
|
||||||
|
<item>45 minutes</item>
|
||||||
|
<item>1 hour</item>
|
||||||
|
<item>2 hours</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="pull_notification_check_intervals" inputType="integer">
|
||||||
|
<item>5</item>
|
||||||
|
<item>10</item>
|
||||||
|
<item>15</item>
|
||||||
|
<item>20</item>
|
||||||
|
<item>25</item>
|
||||||
|
<item>30</item>
|
||||||
|
<item>45</item>
|
||||||
|
<item>60</item>
|
||||||
|
<item>120</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
</resources>
|
|
@ -146,7 +146,8 @@
|
||||||
|
|
||||||
<string name="pref_title_notification_settings">Notifications</string>
|
<string name="pref_title_notification_settings">Notifications</string>
|
||||||
<string name="pref_title_edit_notification_settings">Edit Notifications</string>
|
<string name="pref_title_edit_notification_settings">Edit Notifications</string>
|
||||||
<string name="pref_title_notifications_enabled">Push notifications</string>
|
<string name="pref_title_notifications_enabled">Notifications</string>
|
||||||
|
<string name="pref_title_pull_notification_check_interval">Check Interval</string>
|
||||||
<string name="pref_title_notification_alerts">Alerts</string>
|
<string name="pref_title_notification_alerts">Alerts</string>
|
||||||
<string name="pref_title_notification_alert_sound">Notify with a sound</string>
|
<string name="pref_title_notification_alert_sound">Notify with a sound</string>
|
||||||
<string name="pref_title_notification_alert_vibrate">Notify with vibration</string>
|
<string name="pref_title_notification_alert_vibrate">Notify with vibration</string>
|
||||||
|
|
|
@ -54,6 +54,12 @@
|
||||||
android:title="@string/pref_title_notifications_enabled"
|
android:title="@string/pref_title_notifications_enabled"
|
||||||
android:defaultValue="true" />
|
android:defaultValue="true" />
|
||||||
|
|
||||||
|
<ListPreference android:key="pullNotificationCheckInterval"
|
||||||
|
android:title="@string/pref_title_pull_notification_check_interval"
|
||||||
|
android:entries="@array/pull_notification_check_interval_names"
|
||||||
|
android:entryValues="@array/pull_notification_check_intervals"
|
||||||
|
android:defaultValue="15" />
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:dependency="notificationsEnabled"
|
android:dependency="notificationsEnabled"
|
||||||
android:title="@string/pref_title_notification_filters">
|
android:title="@string/pref_title_notification_filters">
|
||||||
|
|
Loading…
Reference in a new issue