From fe9e431a2b752c9fd772546c11fe1957bc167201 Mon Sep 17 00:00:00 2001 From: Jannis Mattheis Date: Fri, 29 May 2020 19:32:47 +0200 Subject: [PATCH 01/17] Delete client on logout `api.deleteClient()` only create a call but doesn't execute it. --- .../main/java/com/github/gotify/messages/MessagesActivity.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/com/github/gotify/messages/MessagesActivity.java b/app/src/main/java/com/github/gotify/messages/MessagesActivity.java index 3522dd5..8a0651a 100644 --- a/app/src/main/java/com/github/gotify/messages/MessagesActivity.java +++ b/app/src/main/java/com/github/gotify/messages/MessagesActivity.java @@ -330,7 +330,6 @@ public class MessagesActivity extends AppCompatActivity public void doLogout(DialogInterface dialog, int which) { setContentView(R.layout.splash); new DeleteClientAndNavigateToLogin().execute(); - finish(); } private void startLoading() { @@ -683,7 +682,7 @@ public class MessagesActivity extends AppCompatActivity if (currentClient != null) { Log.i("Delete client with id " + currentClient.getId()); - api.deleteClient(currentClient.getId()); + Api.execute(api.deleteClient(currentClient.getId())); } else { Log.e("Could not delete client, client does not exist."); } From 91dfd881e103366db1d41f480775681e6f00a757 Mon Sep 17 00:00:00 2001 From: Jannis Mattheis Date: Sat, 30 May 2020 19:59:28 +0200 Subject: [PATCH 02/17] Fix not working scheduled reconnect Documentation for postDelayed: > Causes the Runnable r to be added to the message queue, to be run > after the specified amount of time elapses. > The runnable will be run on the thread to which this handler > is attached. > The time-base is {@link android.os.SystemClock#uptimeMillis}. > Time spent in deep sleep will add an additional delay to execution. TL;DR: if the CPU is in deep sleep, the postDelayed runnable won't be executed. --- .../gotify/service/WebSocketConnection.java | 39 +++++++++++++------ .../gotify/service/WebSocketService.java | 11 ++++-- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/github/gotify/service/WebSocketConnection.java b/app/src/main/java/com/github/gotify/service/WebSocketConnection.java index ebda4da..feea22a 100644 --- a/app/src/main/java/com/github/gotify/service/WebSocketConnection.java +++ b/app/src/main/java/com/github/gotify/service/WebSocketConnection.java @@ -1,7 +1,9 @@ package com.github.gotify.service; +import android.app.AlarmManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; +import android.os.Build; import android.os.Handler; import com.github.gotify.SSLSettings; import com.github.gotify.Utils; @@ -9,6 +11,7 @@ import com.github.gotify.api.Callback; import com.github.gotify.api.CertUtils; import com.github.gotify.client.model.Message; import com.github.gotify.log.Log; +import java.util.Calendar; import java.util.concurrent.TimeUnit; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; @@ -17,8 +20,9 @@ import okhttp3.Response; import okhttp3.WebSocket; import okhttp3.WebSocketListener; -public class WebSocketConnection { +class WebSocketConnection { private final ConnectivityManager connectivityManager; + private final AlarmManager alarmManager; private OkHttpClient client; private final Handler reconnectHandler = new Handler(); @@ -41,8 +45,10 @@ public class WebSocketConnection { String baseUrl, SSLSettings settings, String token, - ConnectivityManager connectivityManager) { + ConnectivityManager connectivityManager, + AlarmManager alarmManager) { this.connectivityManager = connectivityManager; + this.alarmManager = alarmManager; OkHttpClient.Builder builder = new OkHttpClient.Builder() .readTimeout(0, TimeUnit.MILLISECONDS) @@ -119,14 +125,25 @@ public class WebSocketConnection { } } - public synchronized void scheduleReconnect(long millis) { - reconnectHandler.removeCallbacks(reconnectCallback); - - Log.i( - "WebSocket: scheduling a restart in " - + TimeUnit.SECONDS.convert(millis, TimeUnit.MILLISECONDS) - + " second(s)"); - reconnectHandler.postDelayed(reconnectCallback, millis); + public synchronized void scheduleReconnect(long seconds) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + Log.i( + "WebSocket: scheduling a restart in " + + seconds + + " second(s) (via alarm manager)"); + final Calendar future = Calendar.getInstance(); + future.add(Calendar.SECOND, (int) seconds); + alarmManager.setExact( + AlarmManager.RTC_WAKEUP, + future.getTimeInMillis(), + "reconnect-tag", + this::start, + null); + } else { + Log.i("WebSocket: scheduling a restart in " + seconds + " second(s)"); + reconnectHandler.removeCallbacks(reconnectCallback); + reconnectHandler.postDelayed(reconnectCallback, TimeUnit.SECONDS.toMillis(seconds)); + } } private class Listener extends WebSocketListener { @@ -191,7 +208,7 @@ public class WebSocketConnection { int minutes = Math.min(errorCount * 2 - 1, 20); onNetworkFailure.execute(minutes); - scheduleReconnect(TimeUnit.MINUTES.toMillis(minutes)); + scheduleReconnect(TimeUnit.MINUTES.toSeconds(minutes)); } super.onFailure(webSocket, t, response); diff --git a/app/src/main/java/com/github/gotify/service/WebSocketService.java b/app/src/main/java/com/github/gotify/service/WebSocketService.java index 480fc01..1130dd9 100644 --- a/app/src/main/java/com/github/gotify/service/WebSocketService.java +++ b/app/src/main/java/com/github/gotify/service/WebSocketService.java @@ -1,5 +1,6 @@ package com.github.gotify.service; +import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -30,7 +31,6 @@ import com.github.gotify.messages.Extras; import com.github.gotify.messages.MessagesActivity; import java.util.List; import java.util.Map; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; public class WebSocketService extends Service { @@ -92,10 +92,15 @@ public class WebSocketService extends Service { ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); + AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); connection = new WebSocketConnection( - settings.url(), settings.sslSettings(), settings.token(), cm) + settings.url(), + settings.sslSettings(), + settings.token(), + cm, + alarmManager) .onOpen(this::onOpen) .onClose(() -> foreground(getString(R.string.websocket_closed))) .onBadRequest(this::onBadRequest) @@ -121,7 +126,7 @@ public class WebSocketService extends Service { return; } - connection.scheduleReconnect(TimeUnit.SECONDS.toMillis(5)); + connection.scheduleReconnect(5); } private void onBadRequest(String message) { From 85c255e462261dc001164571eb62526ce3e3bbeb Mon Sep 17 00:00:00 2001 From: fn Date: Thu, 18 Jun 2020 18:03:57 +0200 Subject: [PATCH 03/17] Show appicon in notifications --- .../gotify/messages/MessagesActivity.java | 39 ++------ .../provider/MessageImageCombiner.java | 8 +- .../github/gotify/picasso/PicassoHandler.java | 94 +++++++++++++++++++ .../gotify/service/WebSocketService.java | 30 ++++-- 4 files changed, 131 insertions(+), 40 deletions(-) create mode 100644 app/src/main/java/com/github/gotify/picasso/PicassoHandler.java diff --git a/app/src/main/java/com/github/gotify/messages/MessagesActivity.java b/app/src/main/java/com/github/gotify/messages/MessagesActivity.java index 8a0651a..107f0dc 100644 --- a/app/src/main/java/com/github/gotify/messages/MessagesActivity.java +++ b/app/src/main/java/com/github/gotify/messages/MessagesActivity.java @@ -43,7 +43,6 @@ import com.github.gotify.Settings; import com.github.gotify.Utils; import com.github.gotify.api.Api; import com.github.gotify.api.ApiException; -import com.github.gotify.api.CertUtils; import com.github.gotify.api.ClientFactory; import com.github.gotify.client.ApiClient; import com.github.gotify.client.api.ClientApi; @@ -60,22 +59,17 @@ import com.github.gotify.messages.provider.MessageDeletion; import com.github.gotify.messages.provider.MessageFacade; import com.github.gotify.messages.provider.MessageState; import com.github.gotify.messages.provider.MessageWithImage; -import com.github.gotify.picasso.PicassoDataRequestHandler; +import com.github.gotify.picasso.PicassoHandler; import com.github.gotify.service.WebSocketService; import com.github.gotify.settings.SettingsActivity; import com.google.android.material.navigation.NavigationView; import com.google.android.material.snackbar.BaseTransientBottomBar; import com.google.android.material.snackbar.Snackbar; -import com.squareup.picasso.OkHttp3Downloader; -import com.squareup.picasso.Picasso; import com.squareup.picasso.Target; -import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import okhttp3.Cache; -import okhttp3.OkHttpClient; import static java.util.Collections.emptyList; @@ -123,9 +117,7 @@ public class MessagesActivity extends AppCompatActivity private boolean isLoadMore = false; private Integer selectAppIdOnDrawerClose = null; - int PICASSO_CACHE_SIZE = 50 * 1024 * 1024; // 50 MB - private Cache picassoCache; - private Picasso picasso; + private PicassoHandler picassoHandler; // we need to keep the target references otherwise they get gc'ed before they can be called. @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") @@ -139,8 +131,7 @@ public class MessagesActivity extends AppCompatActivity Log.i("Entering " + getClass().getSimpleName()); settings = new Settings(this); - picassoCache = new Cache(new File(getCacheDir(), "picasso-cache"), PICASSO_CACHE_SIZE); - picasso = makePicasso(); + picassoHandler = new PicassoHandler(this, settings); client = ClientFactory.clientToken(settings.url(), settings.sslSettings(), settings.token()); @@ -157,7 +148,7 @@ public class MessagesActivity extends AppCompatActivity messagesView.getContext(), layoutManager.getOrientation()); ListMessageAdapter adapter = new ListMessageAdapter( - this, settings, picasso, emptyList(), this::scheduleDeletion); + this, settings, picassoHandler.get(), emptyList(), this::scheduleDeletion); messagesView.addItemDecoration(dividerItemDecoration); messagesView.setHasFixedSize(true); @@ -200,7 +191,7 @@ public class MessagesActivity extends AppCompatActivity public void onRefreshAll(View view) { try { - picassoCache.evictAll(); + picassoHandler.evict(); } catch (IOException e) { Log.e("Problem evicting Picasso cache", e); } @@ -234,7 +225,9 @@ public class MessagesActivity extends AppCompatActivity item.setCheckable(true); Target t = Utils.toDrawable(getResources(), item::setIcon); targetReferences.add(t); - picasso.load(Utils.resolveAbsoluteUrl(settings.url() + "/", app.getImage())) + picassoHandler + .get() + .load(Utils.resolveAbsoluteUrl(settings.url() + "/", app.getImage())) .error(R.drawable.ic_alarm) .placeholder(R.drawable.ic_placeholder) .resize(100, 100) @@ -242,20 +235,6 @@ public class MessagesActivity extends AppCompatActivity } } - private Picasso makePicasso() { - OkHttpClient.Builder builder = new OkHttpClient.Builder(); - builder.cache(picassoCache); - - CertUtils.applySslSettings(builder, settings.sslSettings()); - - OkHttp3Downloader downloader = new OkHttp3Downloader(builder.build()); - - return new Picasso.Builder(this) - .addRequestHandler(new PicassoDataRequestHandler()) - .downloader(downloader) - .build(); - } - private void initDrawer() { setSupportActionBar(toolbar); navigationView.setItemIconTintList(null); @@ -370,7 +349,7 @@ public class MessagesActivity extends AppCompatActivity @Override protected void onDestroy() { super.onDestroy(); - picasso.shutdown(); + picassoHandler.get().shutdown(); } private void scheduleDeletion(int position, Message message, boolean listAnimation) { diff --git a/app/src/main/java/com/github/gotify/messages/provider/MessageImageCombiner.java b/app/src/main/java/com/github/gotify/messages/provider/MessageImageCombiner.java index 4a145f6..95cb18c 100644 --- a/app/src/main/java/com/github/gotify/messages/provider/MessageImageCombiner.java +++ b/app/src/main/java/com/github/gotify/messages/provider/MessageImageCombiner.java @@ -3,11 +3,11 @@ package com.github.gotify.messages.provider; import com.github.gotify.client.model.Application; import com.github.gotify.client.model.Message; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; -class MessageImageCombiner { +public class MessageImageCombiner { List combine(List messages, List applications) { Map appIdToImage = appIdToImage(applications); @@ -26,8 +26,8 @@ class MessageImageCombiner { return result; } - private Map appIdToImage(List applications) { - Map map = new HashMap<>(); + public static Map appIdToImage(List applications) { + Map map = new ConcurrentHashMap<>(); for (Application app : applications) { map.put(app.getId(), app.getImage()); } diff --git a/app/src/main/java/com/github/gotify/picasso/PicassoHandler.java b/app/src/main/java/com/github/gotify/picasso/PicassoHandler.java new file mode 100644 index 0000000..c2f0717 --- /dev/null +++ b/app/src/main/java/com/github/gotify/picasso/PicassoHandler.java @@ -0,0 +1,94 @@ +package com.github.gotify.picasso; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import com.github.gotify.R; +import com.github.gotify.Settings; +import com.github.gotify.Utils; +import com.github.gotify.api.Callback; +import com.github.gotify.api.CertUtils; +import com.github.gotify.api.ClientFactory; +import com.github.gotify.client.api.ApplicationApi; +import com.github.gotify.log.Log; +import com.github.gotify.messages.provider.MessageImageCombiner; +import com.squareup.picasso.OkHttp3Downloader; +import com.squareup.picasso.Picasso; +import java.io.File; +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import okhttp3.Cache; +import okhttp3.OkHttpClient; + +public class PicassoHandler { + + private static final int PICASSO_CACHE_SIZE = 50 * 1024 * 1024; // 50 MB + private static final String PICASSO_CACHE_SUBFOLDER = "picasso-cache"; + + private Context context; + private Settings settings; + + private Cache picassoCache; + + private Picasso picasso; + private Map appIdToAppImage = new ConcurrentHashMap<>(); + + public PicassoHandler(Context context, Settings settings) { + this.context = context; + this.settings = settings; + + picassoCache = + new Cache( + new File(context.getCacheDir(), PICASSO_CACHE_SUBFOLDER), + PICASSO_CACHE_SIZE); + picasso = makePicasso(); + } + + private Picasso makePicasso() { + OkHttpClient.Builder builder = new OkHttpClient.Builder(); + builder.cache(picassoCache); + CertUtils.applySslSettings(builder, settings.sslSettings()); + OkHttp3Downloader downloader = new OkHttp3Downloader(builder.build()); + return new Picasso.Builder(context).downloader(downloader).build(); + } + + public Bitmap getIcon(Integer appId) { + if (appId == -1) { + return BitmapFactory.decodeResource(context.getResources(), R.drawable.gotify); + } + + try { + return picasso.load( + Utils.resolveAbsoluteUrl( + settings.url() + "/", appIdToAppImage.get(appId))) + .get(); + } catch (IOException e) { + Log.e("Could not load image for notification", e); + } + return BitmapFactory.decodeResource(context.getResources(), R.drawable.gotify); + } + + public void updateAppIds() { + ClientFactory.clientToken(settings.url(), settings.sslSettings(), settings.token()) + .createService(ApplicationApi.class) + .getApps() + .enqueue( + Callback.call( + (apps) -> { + appIdToAppImage.clear(); + appIdToAppImage.putAll(MessageImageCombiner.appIdToImage(apps)); + }, + (t) -> { + appIdToAppImage.clear(); + })); + } + + public Picasso get() { + return picasso; + } + + public void evict() throws IOException { + picassoCache.evictAll(); + } +} diff --git a/app/src/main/java/com/github/gotify/service/WebSocketService.java b/app/src/main/java/com/github/gotify/service/WebSocketService.java index 1130dd9..53664ce 100644 --- a/app/src/main/java/com/github/gotify/service/WebSocketService.java +++ b/app/src/main/java/com/github/gotify/service/WebSocketService.java @@ -23,12 +23,14 @@ import com.github.gotify.R; import com.github.gotify.Settings; import com.github.gotify.Utils; import com.github.gotify.api.ClientFactory; +import com.github.gotify.client.ApiClient; import com.github.gotify.client.api.MessageApi; import com.github.gotify.client.model.Message; import com.github.gotify.log.Log; import com.github.gotify.log.UncaughtExceptionHandler; import com.github.gotify.messages.Extras; import com.github.gotify.messages.MessagesActivity; +import com.github.gotify.picasso.PicassoHandler; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; @@ -46,16 +48,17 @@ public class WebSocketService extends Service { private AtomicInteger lastReceivedMessage = new AtomicInteger(NOT_LOADED); private MissedMessageUtil missingMessageUtil; + private PicassoHandler picassoHandler; + @Override public void onCreate() { super.onCreate(); settings = new Settings(this); - missingMessageUtil = - new MissedMessageUtil( - ClientFactory.clientToken( - settings.url(), settings.sslSettings(), settings.token()) - .createService(MessageApi.class)); + ApiClient client = + ClientFactory.clientToken(settings.url(), settings.sslSettings(), settings.token()); + missingMessageUtil = new MissedMessageUtil(client.createService(MessageApi.class)); Log.i("Create " + getClass().getSimpleName()); + picassoHandler = new PicassoHandler(this, settings); } @Override @@ -115,6 +118,8 @@ public class WebSocketService extends Service { intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); ReconnectListener receiver = new ReconnectListener(this::doReconnect); registerReceiver(receiver, intentFilter); + + picassoHandler.updateAppIds(); } private void onDisconnect() { @@ -176,13 +181,15 @@ public class WebSocketService extends Service { if (lastReceivedMessage.get() < message.getId()) { lastReceivedMessage.set(message.getId()); } + broadcast(message); showNotification( message.getId(), message.getTitle(), message.getMessage(), message.getPriority(), - message.getExtras()); + message.getExtras(), + message.getAppid()); } private void broadcast(Message message) { @@ -224,6 +231,16 @@ public class WebSocketService extends Service { private void showNotification( int id, String title, String message, long priority, Map extras) { + showNotification(id, title, message, priority, extras, -1); + } + + private void showNotification( + int id, + String title, + String message, + long priority, + Map extras, + Integer appid) { Intent intent; @@ -263,6 +280,7 @@ public class WebSocketService extends Service { .setDefaults(Notification.DEFAULT_ALL) .setWhen(System.currentTimeMillis()) .setSmallIcon(R.drawable.ic_gotify) + .setLargeIcon(picassoHandler.getIcon(appid)) .setTicker(getString(R.string.app_name) + " - " + title) .setGroup(NotificationSupport.Group.MESSAGES) .setContentTitle(title) From f85b5312e65e498d6bf59b01c4fff9584dda387c Mon Sep 17 00:00:00 2001 From: Robbie Page Date: Sat, 26 Jan 2019 00:11:59 -0500 Subject: [PATCH 04/17] Add share activity --- app/src/main/AndroidManifest.xml | 11 ++- .../main/java/com/github/gotify/Utils.java | 14 +++ .../gotify/messages/MessagesActivity.java | 9 +- .../github/gotify/sharing/ShareActivity.java | 94 +++++++++++++++++++ 4 files changed, 119 insertions(+), 9 deletions(-) create mode 100644 app/src/main/java/com/github/gotify/sharing/ShareActivity.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 314b2b1..395523f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -45,6 +45,15 @@ android:name=".settings.SettingsActivity" android:theme="@style/AppTheme.NoActionBar" android:label="@string/title_activity_settings" /> + + + + + + + @@ -55,4 +64,4 @@ - \ No newline at end of file + diff --git a/app/src/main/java/com/github/gotify/Utils.java b/app/src/main/java/com/github/gotify/Utils.java index 739c5a1..9ef319e 100644 --- a/app/src/main/java/com/github/gotify/Utils.java +++ b/app/src/main/java/com/github/gotify/Utils.java @@ -1,12 +1,14 @@ package com.github.gotify; import android.app.Activity; +import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.text.format.DateUtils; import android.view.View; +import android.widget.Toast; import androidx.annotation.NonNull; import com.github.gotify.client.JSON; import com.github.gotify.log.Log; @@ -96,4 +98,16 @@ public class Utils { if (str == null) return null; return new Buffer().writeUtf8(str).inputStream(); } + + public static T first(T[] data) { + if (data.length != 1) { + throw new IllegalArgumentException("must be one element"); + } + + return data[0]; + } + + public static void showLongToast(Context context, String message) { + Toast.makeText(context, message, Toast.LENGTH_LONG).show(); + } } diff --git a/app/src/main/java/com/github/gotify/messages/MessagesActivity.java b/app/src/main/java/com/github/gotify/messages/MessagesActivity.java index 107f0dc..16ceb16 100644 --- a/app/src/main/java/com/github/gotify/messages/MessagesActivity.java +++ b/app/src/main/java/com/github/gotify/messages/MessagesActivity.java @@ -71,6 +71,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import static com.github.gotify.Utils.first; import static java.util.Collections.emptyList; public class MessagesActivity extends AppCompatActivity @@ -695,12 +696,4 @@ public class MessagesActivity extends AppCompatActivity adapter.setItems(messageWithImages); adapter.notifyDataSetChanged(); } - - private T first(T[] data) { - if (data.length != 1) { - throw new IllegalArgumentException("must be one element"); - } - - return data[0]; - } } diff --git a/app/src/main/java/com/github/gotify/sharing/ShareActivity.java b/app/src/main/java/com/github/gotify/sharing/ShareActivity.java new file mode 100644 index 0000000..c6dbe4b --- /dev/null +++ b/app/src/main/java/com/github/gotify/sharing/ShareActivity.java @@ -0,0 +1,94 @@ +package com.github.gotify.sharing; + +import android.app.Activity; +import android.content.Intent; +import android.os.AsyncTask; +import android.os.Bundle; +import com.github.gotify.Settings; +import com.github.gotify.Utils; +import com.github.gotify.api.Api; +import com.github.gotify.api.ApiException; +import com.github.gotify.api.ClientFactory; +import com.github.gotify.client.ApiClient; +import com.github.gotify.client.api.ApplicationApi; +import com.github.gotify.client.api.MessageApi; +import com.github.gotify.client.model.Application; +import com.github.gotify.client.model.Message; +import com.github.gotify.log.Log; +import java.util.List; + +import static com.github.gotify.Utils.first; + +public class ShareActivity extends Activity { + private ApiClient client; + private Settings settings; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + settings = new Settings(this); + handleShareIntent(); + } + + private void handleShareIntent() { + Intent intent = getIntent(); + String action = intent.getAction(); + String type = intent.getType(); + + if (Intent.ACTION_SEND.equals(action) && type != null) { + if ("text/plain".equals(type)) { + String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); + if (sharedText != null) { + Message message = new Message(); + message.setMessage(sharedText); + message.setTitle("Shared content"); + message.setPriority((long) 5); + + client = + ClientFactory.clientToken( + settings.url(), settings.sslSettings(), settings.token()); + + new GetApps().execute(message); + } + } + } + } + + private class GetApps extends AsyncTask { + @Override + protected Void doInBackground(Message... messages) { + try { + ApplicationApi applicationApi = client.createService(ApplicationApi.class); + List apps = Api.execute(applicationApi.getApps()); + client = + ClientFactory.clientToken( + settings.url(), settings.sslSettings(), apps.get(0).getToken()); + new SendSharedContent().execute(first(messages)); + } catch (ApiException apiException) { + Log.e("Failed getting apps", apiException); + } + + return null; + } + } + + private class SendSharedContent extends AsyncTask { + @Override + protected String doInBackground(Message... messages) { + try { + MessageApi messageApi = client.createService(MessageApi.class); + Api.execute(messageApi.createMessage(first(messages))); + return "Pushed!"; + } catch (ApiException apiException) { + Log.e("Failed sending message", apiException); + return "Oops! Something went wrong..."; + } + } + + @Override + protected void onPostExecute(String message) { + Utils.showLongToast(ShareActivity.this, message); + ShareActivity.this.finish(); + } + } +} From dea1e42820af14c3dfb7426cc514fb1defaea190 Mon Sep 17 00:00:00 2001 From: tomasvanagas Date: Thu, 9 Jul 2020 22:41:47 +0300 Subject: [PATCH 05/17] Add inputs for the pushed message to share activity --- .project | 17 ++ app/src/main/AndroidManifest.xml | 3 +- .../main/java/com/github/gotify/Utils.java | 7 - .../gotify/messages/MessagesActivity.java | 4 + .../github/gotify/sharing/ShareActivity.java | 145 ++++++++++++------ app/src/main/res/drawable/ic_send.xml | 9 ++ app/src/main/res/drawable/ic_settings.xml | 4 +- app/src/main/res/layout/activity_share.xml | 92 +++++++++++ app/src/main/res/menu/messages_menu.xml | 6 + app/src/main/res/values/strings.xml | 8 +- build.gradle | 2 +- client/build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 +- 13 files changed, 246 insertions(+), 57 deletions(-) create mode 100644 .project create mode 100644 app/src/main/res/drawable/ic_send.xml create mode 100644 app/src/main/res/layout/activity_share.xml diff --git a/.project b/.project new file mode 100644 index 0000000..3964dd3 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + android + Project android created by Buildship. + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 395523f..4726443 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -47,7 +47,8 @@ android:label="@string/title_activity_settings" /> + android:theme="@style/AppTheme.NoActionBar" + android:label="Push message"> diff --git a/app/src/main/java/com/github/gotify/Utils.java b/app/src/main/java/com/github/gotify/Utils.java index 9ef319e..fb9df51 100644 --- a/app/src/main/java/com/github/gotify/Utils.java +++ b/app/src/main/java/com/github/gotify/Utils.java @@ -1,14 +1,12 @@ package com.github.gotify; import android.app.Activity; -import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.text.format.DateUtils; import android.view.View; -import android.widget.Toast; import androidx.annotation.NonNull; import com.github.gotify.client.JSON; import com.github.gotify.log.Log; @@ -103,11 +101,6 @@ public class Utils { if (data.length != 1) { throw new IllegalArgumentException("must be one element"); } - return data[0]; } - - public static void showLongToast(Context context, String message) { - Toast.makeText(context, message, Toast.LENGTH_LONG).show(); - } } diff --git a/app/src/main/java/com/github/gotify/messages/MessagesActivity.java b/app/src/main/java/com/github/gotify/messages/MessagesActivity.java index 16ceb16..3f9224b 100644 --- a/app/src/main/java/com/github/gotify/messages/MessagesActivity.java +++ b/app/src/main/java/com/github/gotify/messages/MessagesActivity.java @@ -62,6 +62,7 @@ import com.github.gotify.messages.provider.MessageWithImage; import com.github.gotify.picasso.PicassoHandler; import com.github.gotify.service.WebSocketService; import com.github.gotify.settings.SettingsActivity; +import com.github.gotify.sharing.ShareActivity; import com.google.android.material.navigation.NavigationView; import com.google.android.material.snackbar.BaseTransientBottomBar; import com.google.android.material.snackbar.Snackbar; @@ -301,6 +302,9 @@ public class MessagesActivity extends AppCompatActivity startActivity(new Intent(this, LogsActivity.class)); } else if (id == R.id.settings) { startActivity(new Intent(this, SettingsActivity.class)); + } else if (id == R.id.push_message) { + Intent intent = new Intent(MessagesActivity.this, ShareActivity.class); + startActivity(intent); } drawer.closeDrawer(GravityCompat.START); diff --git a/app/src/main/java/com/github/gotify/sharing/ShareActivity.java b/app/src/main/java/com/github/gotify/sharing/ShareActivity.java index c6dbe4b..065a096 100644 --- a/app/src/main/java/com/github/gotify/sharing/ShareActivity.java +++ b/app/src/main/java/com/github/gotify/sharing/ShareActivity.java @@ -1,82 +1,141 @@ package com.github.gotify.sharing; -import android.app.Activity; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; +import android.view.MenuItem; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.Spinner; +import android.widget.Toast; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import com.github.gotify.R; import com.github.gotify.Settings; -import com.github.gotify.Utils; import com.github.gotify.api.Api; import com.github.gotify.api.ApiException; import com.github.gotify.api.ClientFactory; import com.github.gotify.client.ApiClient; -import com.github.gotify.client.api.ApplicationApi; import com.github.gotify.client.api.MessageApi; import com.github.gotify.client.model.Application; import com.github.gotify.client.model.Message; import com.github.gotify.log.Log; +import com.github.gotify.messages.provider.ApplicationHolder; +import java.util.ArrayList; import java.util.List; import static com.github.gotify.Utils.first; -public class ShareActivity extends Activity { - private ApiClient client; +public class ShareActivity extends AppCompatActivity { private Settings settings; + private ApplicationHolder appsHolder; + + @BindView(R.id.title) + EditText edtTxtTitle; + + @BindView(R.id.content) + EditText edtTxtContent; + + @BindView(R.id.edtTxtPriority) + EditText edtTxtPriority; + + @BindView(R.id.appSpinner) + Spinner appSpinner; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + setContentView(R.layout.activity_share); + ButterKnife.bind(this); + + Log.i("Entering " + getClass().getSimpleName()); + setSupportActionBar(findViewById(R.id.toolbar)); + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setDisplayShowCustomEnabled(true); + } settings = new Settings(this); - handleShareIntent(); - } - private void handleShareIntent() { Intent intent = getIntent(); - String action = intent.getAction(); String type = intent.getType(); - - if (Intent.ACTION_SEND.equals(action) && type != null) { - if ("text/plain".equals(type)) { - String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); - if (sharedText != null) { - Message message = new Message(); - message.setMessage(sharedText); - message.setTitle("Shared content"); - message.setPriority((long) 5); - - client = - ClientFactory.clientToken( - settings.url(), settings.sslSettings(), settings.token()); - - new GetApps().execute(message); - } + if (Intent.ACTION_SEND.equals(intent.getAction()) && "text/plain".equals(type)) { + String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); + if (sharedText != null) { + edtTxtContent.setText(sharedText); } } + + ApiClient client = + ClientFactory.clientToken(settings.url(), settings.sslSettings(), settings.token()); + appsHolder = new ApplicationHolder(this, client); + appsHolder.onUpdate(() -> populateSpinner(appsHolder.get())); + appsHolder.request(); } - private class GetApps extends AsyncTask { - @Override - protected Void doInBackground(Message... messages) { - try { - ApplicationApi applicationApi = client.createService(ApplicationApi.class); - List apps = Api.execute(applicationApi.getApps()); - client = - ClientFactory.clientToken( - settings.url(), settings.sslSettings(), apps.get(0).getToken()); - new SendSharedContent().execute(first(messages)); - } catch (ApiException apiException) { - Log.e("Failed getting apps", apiException); - } - - return null; + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); } + return super.onOptionsItemSelected(item); } - private class SendSharedContent extends AsyncTask { + @OnClick(R.id.push_button) + public void pushMessage(View view) { + String titleText = edtTxtTitle.getText().toString(); + String contentText = edtTxtContent.getText().toString(); + String priority = edtTxtPriority.getText().toString(); + int appIndex = appSpinner.getSelectedItemPosition(); + + if (contentText.isEmpty()) { + Toast.makeText(this, "Content should not be empty.", Toast.LENGTH_LONG).show(); + return; + } else if (priority.isEmpty()) { + Toast.makeText(this, "Priority should be number.", Toast.LENGTH_LONG).show(); + return; + } + + Message message = new Message(); + if (!titleText.isEmpty()) { + message.setTitle(titleText); + } + message.setMessage(contentText); + message.setPriority(Long.parseLong(priority)); + new PushMessage(appsHolder.get().get(appIndex).getToken()).execute(message); + } + + private void populateSpinner(List apps) { + List appNameList = new ArrayList<>(); + for (Application app : apps) { + appNameList.add(app.getName()); + } + + ArrayAdapter adapter = + new ArrayAdapter<>( + this, android.R.layout.simple_spinner_dropdown_item, appNameList); + appSpinner.setAdapter(adapter); + } + + private class PushMessage extends AsyncTask { + private String token; + + public PushMessage(String token) { + this.token = token; + } + @Override protected String doInBackground(Message... messages) { + List apps = appsHolder.get(); + ApiClient pushClient = + ClientFactory.clientToken(settings.url(), settings.sslSettings(), token); + try { - MessageApi messageApi = client.createService(MessageApi.class); + MessageApi messageApi = pushClient.createService(MessageApi.class); Api.execute(messageApi.createMessage(first(messages))); return "Pushed!"; } catch (ApiException apiException) { @@ -87,7 +146,7 @@ public class ShareActivity extends Activity { @Override protected void onPostExecute(String message) { - Utils.showLongToast(ShareActivity.this, message); + Toast.makeText(ShareActivity.this, message, Toast.LENGTH_LONG).show(); ShareActivity.this.finish(); } } diff --git a/app/src/main/res/drawable/ic_send.xml b/app/src/main/res/drawable/ic_send.xml new file mode 100644 index 0000000..ac34cb9 --- /dev/null +++ b/app/src/main/res/drawable/ic_send.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_settings.xml b/app/src/main/res/drawable/ic_settings.xml index a087c86..af2a382 100644 --- a/app/src/main/res/drawable/ic_settings.xml +++ b/app/src/main/res/drawable/ic_settings.xml @@ -1,5 +1,7 @@ + android:viewportWidth="20" + android:width="24dp" + xmlns:android="http://schemas.android.com/apk/res/android"> diff --git a/app/src/main/res/layout/activity_share.xml b/app/src/main/res/layout/activity_share.xml new file mode 100644 index 0000000..1c20d6b --- /dev/null +++ b/app/src/main/res/layout/activity_share.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + +