From ee00513783251a12e307e941c57da486416c7e9e Mon Sep 17 00:00:00 2001 From: stephanlindauer Date: Sun, 28 May 2023 10:55:06 +0200 Subject: [PATCH 01/10] upgrade gradle --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d5e637e5..08addb44 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:7.4.1' + classpath 'com.android.tools.build:gradle:7.4.2' classpath 'com.github.bjoernq:unmockplugin:0.7.9' classpath 'net.ltgt.gradle:gradle-errorprone-plugin:2.0.2' } From 233c7e53dcee0ce9c8945fa815119f16e87478cb Mon Sep 17 00:00:00 2001 From: stephanlindauer Date: Sun, 28 May 2023 18:25:59 +0200 Subject: [PATCH 02/10] Extract pushing of location data from previous push/pull --- ...rverHandler.java => HeartbeatHandler.java} | 54 ++++++++----------- .../service/ServerSyncService.java | 8 +-- .../criticalmaps/vo/Endpoints.java | 5 +- 3 files changed, 30 insertions(+), 37 deletions(-) rename app/src/main/java/de/stephanlindauer/criticalmaps/handler/{PullServerHandler.java => HeartbeatHandler.java} (65%) diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/PullServerHandler.java b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/HeartbeatHandler.java similarity index 65% rename from app/src/main/java/de/stephanlindauer/criticalmaps/handler/PullServerHandler.java rename to app/src/main/java/de/stephanlindauer/criticalmaps/handler/HeartbeatHandler.java index 9618a6cc..283ce537 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/PullServerHandler.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/HeartbeatHandler.java @@ -3,7 +3,6 @@ import android.content.SharedPreferences; import android.os.AsyncTask; -import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -25,7 +24,7 @@ import okhttp3.Response; import timber.log.Timber; -public class PullServerHandler extends AsyncTask { +public class HeartbeatHandler extends AsyncTask { //dependencies private final ChatModel chatModel; @@ -37,7 +36,7 @@ public class PullServerHandler extends AsyncTask { private final LocationUpdateManager locationUpdateManager; @Inject - public PullServerHandler(ChatModel chatModel, + public HeartbeatHandler(ChatModel chatModel, OwnLocationModel ownLocationModel, UserModel userModel, ServerResponseProcessor serverResponseProcessor, @@ -54,54 +53,45 @@ public PullServerHandler(ChatModel chatModel, } @Override - protected String doInBackground(Void... params) { + protected Void doInBackground(Void... params) { + final boolean isObserverModeActive = new BooleanPreference( + sharedPreferences, SharedPrefsKeys.OBSERVER_MODE_ACTIVE).get(); + + if (!isObserverModeActive && ownLocationModel.hasPreciseLocation() + && locationUpdateManager.isUpdating()) { + Timber.d("Heartbeat preconditions are fulfilled."); + } else { + Timber.d("Heartbeat preconditions are not fulfilled."); + return null; + } + String jsonPostString = getJsonObject().toString(); final RequestBody body = RequestBody.create(MediaType.parse("application/json"), jsonPostString); - final Request request = new Request.Builder().url(Endpoints.MAIN_POST).post(body).build(); + final Request request = new Request.Builder().url(Endpoints.LOCATION_PUT).put(body).build(); try { final Response response = okHttpClient.newCall(request).execute(); - if (response.isSuccessful()) { - //noinspection ConstantConditions "Returns a non-null value if this response was [...] returned from Call.execute()." - return response.body().string(); + if (!response.isSuccessful()) { + //TODO Display error to user } } catch (IOException e) { Timber.e(e); } - return ""; + return null; } - @Override - protected void onPostExecute(String result) { - if (!result.isEmpty()) { - serverResponseProcessor.process(result); - } - } private JSONObject getJsonObject() { - JSONObject jsonObject = new JSONObject(); + JSONObject jsonObject; + jsonObject = ownLocationModel.getLocationJson(); - try { + try{ jsonObject.put("device", userModel.getChangingDeviceToken()); - - final boolean isObserverModeActive = new BooleanPreference( - sharedPreferences, SharedPrefsKeys.OBSERVER_MODE_ACTIVE).get(); - - Timber.d("observer mode enabled: %s", isObserverModeActive); - - if (!isObserverModeActive && ownLocationModel.hasPreciseLocation() - && locationUpdateManager.isUpdating()) { - jsonObject.put("location", ownLocationModel.getLocationJson()); - } - - if (chatModel.hasOutgoingMessages()) { - JSONArray messages = chatModel.getOutgoingMessagesAsJson(); - jsonObject.put("messages", messages); - } } catch (JSONException e) { Timber.e(e); } + return jsonObject; } } diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/service/ServerSyncService.java b/app/src/main/java/de/stephanlindauer/criticalmaps/service/ServerSyncService.java index dfd28e1f..305c87d4 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/service/ServerSyncService.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/service/ServerSyncService.java @@ -17,7 +17,7 @@ import de.stephanlindauer.criticalmaps.App; import de.stephanlindauer.criticalmaps.events.NetworkConnectivityChangedEvent; import de.stephanlindauer.criticalmaps.handler.NetworkConnectivityChangeHandler; -import de.stephanlindauer.criticalmaps.handler.PullServerHandler; +import de.stephanlindauer.criticalmaps.handler.HeartbeatHandler; import de.stephanlindauer.criticalmaps.managers.LocationUpdateManager; import de.stephanlindauer.criticalmaps.provider.EventBus; import de.stephanlindauer.criticalmaps.utils.TrackingInfoNotificationBuilder; @@ -25,7 +25,7 @@ public class ServerSyncService extends Service { @SuppressWarnings("FieldCanBeLocal") - private final int SERVER_SYNC_INTERVAL = 12 * 1000; // 12 sec -> 5 times a minute + private final int SERVER_SYNC_INTERVAL = 30 * 1000; // 30 sec private Timer timerPullServer; @@ -36,7 +36,7 @@ public class ServerSyncService extends Service { NetworkConnectivityChangeHandler networkConnectivityChangeHandler; @Inject - Provider pullServerHandler; + Provider heartbeatHandler; @Inject EventBus eventBus; @@ -66,7 +66,7 @@ private void startPullServerTimer() { TimerTask timerTaskPullServer = new TimerTask() { @Override public void run() { - pullServerHandler.get().execute(); + heartbeatHandler.get().execute(); } }; timerPullServer.scheduleAtFixedRate(timerTaskPullServer, 0, SERVER_SYNC_INTERVAL); diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/vo/Endpoints.java b/app/src/main/java/de/stephanlindauer/criticalmaps/vo/Endpoints.java index 18fc2844..2a58b906 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/vo/Endpoints.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/vo/Endpoints.java @@ -1,6 +1,9 @@ package de.stephanlindauer.criticalmaps.vo; public class Endpoints { - public static final String MAIN_POST = "https://api.criticalmaps.net/"; +// IMAGE_POST doesn't currently work. Once fixed CDN or API_GATEWAY should be used to prefix the URI. public static final String IMAGE_POST = "https://api.criticalmaps.net/gallery/"; + + public static final String LOCATION_GET = "https://api-cdn.criticalmaps.net/location"; + public static final String LOCATION_PUT = "https://api.criticalmaps.net/location"; } From 9cc919fec10c69b11020cc2afbd71f69ec77a009 Mon Sep 17 00:00:00 2001 From: stephanlindauer Date: Tue, 30 May 2023 16:21:17 +0200 Subject: [PATCH 03/10] Sending own location works at this point --- .../adapter/ChatMessageAdapter.java | 9 +- .../criticalmaps/fragments/ChatFragment.java | 15 ++-- .../handler/HeartbeatHandler.java | 4 +- .../handler/ServerResponseProcessor.java | 11 +-- .../criticalmaps/interfaces/IChatMessage.java | 8 -- .../criticalmaps/model/ChatModel.java | 86 ++++++++----------- .../model/OtherUsersLocationModel.java | 19 ++-- .../model/chat/OutgoingChatMessage.java | 4 +- .../model/chat/ReceivedChatMessage.java | 4 +- .../criticalmaps/vo/Endpoints.java | 4 +- 10 files changed, 65 insertions(+), 99 deletions(-) delete mode 100644 app/src/main/java/de/stephanlindauer/criticalmaps/interfaces/IChatMessage.java diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/adapter/ChatMessageAdapter.java b/app/src/main/java/de/stephanlindauer/criticalmaps/adapter/ChatMessageAdapter.java index 25759279..e753fa44 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/adapter/ChatMessageAdapter.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/adapter/ChatMessageAdapter.java @@ -15,13 +15,12 @@ import de.stephanlindauer.criticalmaps.R; import de.stephanlindauer.criticalmaps.databinding.ViewChatmessageBinding; -import de.stephanlindauer.criticalmaps.interfaces.IChatMessage; import de.stephanlindauer.criticalmaps.model.chat.ReceivedChatMessage; import de.stephanlindauer.criticalmaps.utils.TimeToWordStringConverter; public class ChatMessageAdapter extends RecyclerView.Adapter { - private List chatMessages; + private List chatMessages; static class ChatMessageViewHolder extends RecyclerView.ViewHolder { private final ViewChatmessageBinding binding; @@ -34,7 +33,7 @@ static class ChatMessageViewHolder extends RecyclerView.ViewHolder { this.binding = binding; } - void bind(IChatMessage message) { + void bind(ReceivedChatMessage message) { binding.chatmessageMessageText.setText(message.getMessage()); if (message instanceof ReceivedChatMessage) { dateFormatter.setTimeZone(TimeZone.getDefault()); @@ -58,7 +57,7 @@ void clearAnimation() { } } - public ChatMessageAdapter(List chatMessages) { + public ChatMessageAdapter(List chatMessages) { this.chatMessages = chatMessages; } @@ -87,7 +86,7 @@ public int getItemCount() { return chatMessages.size(); } - public void updateData(List savedAndOutgoingMessages) { + public void updateData(List savedAndOutgoingMessages) { this.chatMessages = savedAndOutgoingMessages; notifyDataSetChanged(); } diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/ChatFragment.java b/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/ChatFragment.java index 588a33bf..b098aee9 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/ChatFragment.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/ChatFragment.java @@ -33,9 +33,9 @@ import de.stephanlindauer.criticalmaps.databinding.FragmentChatBinding; import de.stephanlindauer.criticalmaps.events.NetworkConnectivityChangedEvent; import de.stephanlindauer.criticalmaps.events.NewServerResponseEvent; -import de.stephanlindauer.criticalmaps.interfaces.IChatMessage; import de.stephanlindauer.criticalmaps.model.ChatModel; import de.stephanlindauer.criticalmaps.model.chat.OutgoingChatMessage; +import de.stephanlindauer.criticalmaps.model.chat.ReceivedChatMessage; import de.stephanlindauer.criticalmaps.provider.EventBus; import de.stephanlindauer.criticalmaps.utils.AxtUtils.SimpleTextWatcher; @@ -46,6 +46,7 @@ public class ChatFragment extends Fragment { @Inject EventBus eventBus; + private boolean isTextInputEnabled = true; private ChatMessageAdapter chatMessageAdapter; private FragmentChatBinding binding; @@ -70,9 +71,9 @@ public void onActivityCreated(final Bundle savedState) { binding.chatMessagesRecyclerview.setAdapter(chatMessageAdapter); displayNewData(); - binding.chatMessageTextinputlayout.setCounterMaxLength(IChatMessage.MAX_LENGTH); + binding.chatMessageTextinputlayout.setCounterMaxLength(ChatModel.MESSAGE_MAX_LENGTH); binding.chatMessageEdittext.setFilters( - new InputFilter[]{new InputFilter.LengthFilter(IChatMessage.MAX_LENGTH)}); + new InputFilter[]{new InputFilter.LengthFilter(ChatModel.MESSAGE_MAX_LENGTH)}); binding.chatMessageEdittext.setOnEditorActionListener( (v, actionId, event) -> handleEditorAction(actionId)); @@ -130,18 +131,18 @@ private void handleSendClicked() { return; } - chatModel.setNewOutgoingMessage(new OutgoingChatMessage(message)); + chatModel.sendNewOutgoingMessage(new OutgoingChatMessage(message)); binding.chatMessageEdittext.setText(""); displayNewData(); } private void displayNewData() { - final List savedAndOutgoingMessages = chatModel.getSavedAndOutgoingMessages(); - chatMessageAdapter.updateData(savedAndOutgoingMessages); + final List receivedChatMessages = chatModel.getReceivedChatMessages(); + chatMessageAdapter.updateData(receivedChatMessages); if (binding.chatMessagesRecyclerview.getScrollState() == RecyclerView.SCROLL_STATE_IDLE) { - binding.chatMessagesRecyclerview.scrollToPosition(savedAndOutgoingMessages.size() - 1); + binding.chatMessagesRecyclerview.scrollToPosition(receivedChatMessages.size() - 1); } } diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/HeartbeatHandler.java b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/HeartbeatHandler.java index 283ce537..65db725d 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/HeartbeatHandler.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/HeartbeatHandler.java @@ -65,9 +65,9 @@ protected Void doInBackground(Void... params) { return null; } - String jsonPostString = getJsonObject().toString(); + String jsonPutBody = getJsonObject().toString(); - final RequestBody body = RequestBody.create(MediaType.parse("application/json"), jsonPostString); + final RequestBody body = RequestBody.create(MediaType.parse("application/json"), jsonPutBody); final Request request = new Request.Builder().url(Endpoints.LOCATION_PUT).put(body).build(); try { diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ServerResponseProcessor.java b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ServerResponseProcessor.java index 3b9c77e2..198221c1 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ServerResponseProcessor.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ServerResponseProcessor.java @@ -1,5 +1,6 @@ package de.stephanlindauer.criticalmaps.handler; +import org.json.JSONArray; import org.json.JSONObject; import javax.inject.Inject; @@ -27,13 +28,9 @@ public ServerResponseProcessor(OtherUsersLocationModel otherUsersLocationModel, public void process(final String jsonString) { try { - final JSONObject jsonObject = new JSONObject(jsonString); - if (jsonObject.has("locations")) { - otherUsersLocationModel.setFromJson(jsonObject.getJSONObject("locations")); - } - if (jsonObject.has("locations")) { - chatModel.setFromJson(jsonObject.getJSONObject("chatMessages")); - } + final JSONArray jsonArray = new JSONArray(jsonString); + otherUsersLocationModel.setFromJson(jsonArray); + eventBus.post(Events.NEW_SERVER_RESPONSE_EVENT); } catch (Exception e) { Timber.d(e); diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/interfaces/IChatMessage.java b/app/src/main/java/de/stephanlindauer/criticalmaps/interfaces/IChatMessage.java deleted file mode 100644 index bdc7b7b7..00000000 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/interfaces/IChatMessage.java +++ /dev/null @@ -1,8 +0,0 @@ -package de.stephanlindauer.criticalmaps.interfaces; - -public interface IChatMessage { - - int MAX_LENGTH = 255; - - String getMessage(); -} diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/model/ChatModel.java b/app/src/main/java/de/stephanlindauer/criticalmaps/model/ChatModel.java index bd16c2a5..450c7fa4 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/model/ChatModel.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/model/ChatModel.java @@ -1,5 +1,7 @@ package de.stephanlindauer.criticalmaps.model; +import androidx.annotation.NonNull; + import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -16,7 +18,6 @@ import javax.inject.Inject; import javax.inject.Singleton; -import de.stephanlindauer.criticalmaps.interfaces.IChatMessage; import de.stephanlindauer.criticalmaps.model.chat.OutgoingChatMessage; import de.stephanlindauer.criticalmaps.model.chat.ReceivedChatMessage; import okhttp3.internal.Util; @@ -24,36 +25,38 @@ @Singleton public class ChatModel { + public static int MESSAGE_MAX_LENGTH = 255; + + private final UserModel userModel; - private final List outgoingMessages = new ArrayList<>(); - private List chatMessages = new ArrayList<>(); + private List receivedChatMessages = new ArrayList<>(); @Inject - public ChatModel() { + public ChatModel(UserModel userModel) { + this.userModel = userModel; + } + + @NonNull + public List getReceivedChatMessages() { + return this.receivedChatMessages; } - public void setFromJson(JSONObject jsonObject) throws JSONException, + public void setFromJson(JSONArray jsonArray) throws JSONException, UnsupportedEncodingException { - chatMessages = new ArrayList<>(jsonObject.length()); - - Iterator identifiers = jsonObject.keys(); - while (identifiers.hasNext()) { - String identifier = identifiers.next(); - JSONObject value = jsonObject.getJSONObject(identifier); - String message = URLDecoder.decode(value.getString("message"), Util.UTF_8.name()); - Date timestamp = new Date(Long.parseLong(value.getString("timestamp")) * 1000); - - Iterator outgoingChatMessageIterator = outgoingMessages.iterator(); - while (outgoingChatMessageIterator.hasNext()) { - if (outgoingChatMessageIterator.next().getIdentifier().equals(identifier)) { - outgoingChatMessageIterator.remove(); - } - } + receivedChatMessages = new ArrayList<>(jsonArray.length()); + + for (int i = 0; i < jsonArray.length(); i++) { + JSONObject jsonObject = jsonArray.getJSONObject(i); + + String device = URLDecoder.decode(jsonObject.getString("device"), Util.UTF_8.name()); + String identifier = URLDecoder.decode(jsonObject.getString("identifier"), Util.UTF_8.name()); + String message = URLDecoder.decode(jsonObject.getString("message"), Util.UTF_8.name()); + Date timestamp = new Date(Long.parseLong(jsonObject.getString("timestamp")) * 1000); - chatMessages.add(new ReceivedChatMessage(message, timestamp)); + receivedChatMessages.add(new ReceivedChatMessage(message, timestamp)); } - Collections.sort(chatMessages, new Comparator() { + Collections.sort(receivedChatMessages, new Comparator() { @Override public int compare(ReceivedChatMessage oneChatMessages, ReceivedChatMessage otherChatMessage) { @@ -62,36 +65,15 @@ public int compare(ReceivedChatMessage oneChatMessages, }); } - public void setNewOutgoingMessage(OutgoingChatMessage newOutgoingMessage) { - outgoingMessages.add(newOutgoingMessage); - } - - public JSONArray getOutgoingMessagesAsJson() { - JSONArray jsonArray = new JSONArray(); - - for (OutgoingChatMessage outgoingChatMessage : outgoingMessages) { - try { - JSONObject messageObject = new JSONObject(); - messageObject.put("text", outgoingChatMessage.getUrlEncodedMessage()); - messageObject.put("timestamp", outgoingChatMessage.getTimestamp().getTime()); - messageObject.put("identifier", outgoingChatMessage.getIdentifier()); - jsonArray.put(messageObject); - } catch (JSONException e) { - Timber.d(e); - } + public void sendNewOutgoingMessage(OutgoingChatMessage newOutgoingMessage) { + JSONObject messageObject = new JSONObject(); + try { + messageObject.put("text", newOutgoingMessage.getUrlEncodedMessage()); + messageObject.put("timestamp", newOutgoingMessage.getTimestamp().getTime()); + messageObject.put("identifier", newOutgoingMessage.getIdentifier()); + messageObject.put("device", userModel.getChangingDeviceToken()); + } catch (JSONException e) { + Timber.d(e); } - return jsonArray; - } - - public ArrayList getSavedAndOutgoingMessages() { - int mergedListsSize = chatMessages.size() + outgoingMessages.size(); - ArrayList mergeArrayList = new ArrayList<>(mergedListsSize); - mergeArrayList.addAll(chatMessages); - mergeArrayList.addAll(outgoingMessages); - return mergeArrayList; - } - - public boolean hasOutgoingMessages() { - return !outgoingMessages.isEmpty(); } } diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/model/OtherUsersLocationModel.java b/app/src/main/java/de/stephanlindauer/criticalmaps/model/OtherUsersLocationModel.java index c5b28e7d..bbb4538d 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/model/OtherUsersLocationModel.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/model/OtherUsersLocationModel.java @@ -1,5 +1,6 @@ package de.stephanlindauer.criticalmaps.model; +import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.osmdroid.util.GeoPoint; @@ -19,18 +20,16 @@ public class OtherUsersLocationModel { public OtherUsersLocationModel() { } - public void setFromJson(JSONObject jsonObject) throws JSONException { - otherUsersLocations = new ArrayList<>(jsonObject.length()); + public void setFromJson(JSONArray jsonArray) throws JSONException { + otherUsersLocations = new ArrayList<>(jsonArray.length()); + for (int i=0; i < jsonArray.length(); i++) { + JSONObject locationObject = jsonArray.getJSONObject(i); - Iterator keys = jsonObject.keys(); - while (keys.hasNext()) { - String key = keys.next(); - JSONObject value = jsonObject.getJSONObject(key); - int latitudeE6 = Integer.parseInt(value.getString("latitude")); - int longitudeE6 = Integer.parseInt(value.getString("longitude")); + int latitudeE6 = Integer.parseInt(locationObject.getString("latitude")); + int longitudeE6 = Integer.parseInt(locationObject.getString("longitude")); - otherUsersLocations.add( - new GeoPoint(latitudeE6 / 1000000.0D, longitudeE6 / 1000000.0D)); + otherUsersLocations.add( + new GeoPoint(latitudeE6 / 1000000.0D, longitudeE6 / 1000000.0D)); } } diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/model/chat/OutgoingChatMessage.java b/app/src/main/java/de/stephanlindauer/criticalmaps/model/chat/OutgoingChatMessage.java index 7d6e5b2d..7c7f6033 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/model/chat/OutgoingChatMessage.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/model/chat/OutgoingChatMessage.java @@ -4,11 +4,10 @@ import java.net.URLEncoder; import java.util.Date; -import de.stephanlindauer.criticalmaps.interfaces.IChatMessage; import de.stephanlindauer.criticalmaps.utils.AeSimpleSHA1; import okhttp3.internal.Util; -public class OutgoingChatMessage implements IChatMessage { +public class OutgoingChatMessage { private final Date timestamp; private final String urlEncodedMessage; @@ -30,7 +29,6 @@ public String getUrlEncodedMessage() { return urlEncodedMessage; } - @Override public String getMessage() { return message; } diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/model/chat/ReceivedChatMessage.java b/app/src/main/java/de/stephanlindauer/criticalmaps/model/chat/ReceivedChatMessage.java index a4e42233..7f039934 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/model/chat/ReceivedChatMessage.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/model/chat/ReceivedChatMessage.java @@ -2,9 +2,8 @@ import java.util.Date; -import de.stephanlindauer.criticalmaps.interfaces.IChatMessage; -public class ReceivedChatMessage implements IChatMessage { +public class ReceivedChatMessage { private final Date timestamp; private final String message; @@ -18,7 +17,6 @@ public Date getTimestamp() { return timestamp; } - @Override public String getMessage() { return message; } diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/vo/Endpoints.java b/app/src/main/java/de/stephanlindauer/criticalmaps/vo/Endpoints.java index 2a58b906..8da323cc 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/vo/Endpoints.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/vo/Endpoints.java @@ -4,6 +4,6 @@ public class Endpoints { // IMAGE_POST doesn't currently work. Once fixed CDN or API_GATEWAY should be used to prefix the URI. public static final String IMAGE_POST = "https://api.criticalmaps.net/gallery/"; - public static final String LOCATION_GET = "https://api-cdn.criticalmaps.net/location"; - public static final String LOCATION_PUT = "https://api.criticalmaps.net/location"; + public static final String LOCATION_GET = "https://api-cdn.criticalmaps.net/locations"; + public static final String LOCATION_PUT = "https://api-gw.criticalmaps.net/locations"; } From f2eab6d683d989f626404a997790fd69bd3104fe Mon Sep 17 00:00:00 2001 From: stephanlindauer Date: Tue, 30 May 2023 16:55:51 +0200 Subject: [PATCH 04/10] Saving other users locations into OtherUsersLocationModel --- .../handler/HeartbeatHandler.java | 2 -- .../handler/ServerResponseProcessor.java | 2 +- .../model/OtherUsersLocationModel.java | 25 ++++++++++++------- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/HeartbeatHandler.java b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/HeartbeatHandler.java index 65db725d..a912eaed 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/HeartbeatHandler.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/HeartbeatHandler.java @@ -30,7 +30,6 @@ public class HeartbeatHandler extends AsyncTask { private final ChatModel chatModel; private final OwnLocationModel ownLocationModel; private final UserModel userModel; - private final ServerResponseProcessor serverResponseProcessor; private final OkHttpClient okHttpClient; private final SharedPreferences sharedPreferences; private final LocationUpdateManager locationUpdateManager; @@ -46,7 +45,6 @@ public HeartbeatHandler(ChatModel chatModel, this.chatModel = chatModel; this.ownLocationModel = ownLocationModel; this.userModel = userModel; - this.serverResponseProcessor = serverResponseProcessor; this.okHttpClient = okHttpClient; this.sharedPreferences = sharedPreferences; this.locationUpdateManager = locationUpdateManager; diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ServerResponseProcessor.java b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ServerResponseProcessor.java index 198221c1..cfe77eb5 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ServerResponseProcessor.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ServerResponseProcessor.java @@ -29,7 +29,7 @@ public ServerResponseProcessor(OtherUsersLocationModel otherUsersLocationModel, public void process(final String jsonString) { try { final JSONArray jsonArray = new JSONArray(jsonString); - otherUsersLocationModel.setFromJson(jsonArray); + otherUsersLocationModel.setFromJson(jsonArray); eventBus.post(Events.NEW_SERVER_RESPONSE_EVENT); } catch (Exception e) { diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/model/OtherUsersLocationModel.java b/app/src/main/java/de/stephanlindauer/criticalmaps/model/OtherUsersLocationModel.java index bbb4538d..31cd96c8 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/model/OtherUsersLocationModel.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/model/OtherUsersLocationModel.java @@ -9,6 +9,7 @@ import java.util.Iterator; import javax.inject.Inject; +import javax.inject.Provider; import javax.inject.Singleton; @Singleton @@ -16,20 +17,26 @@ public class OtherUsersLocationModel { private ArrayList otherUsersLocations = new ArrayList<>(); + private final UserModel userModel; + @Inject - public OtherUsersLocationModel() { + public OtherUsersLocationModel(UserModel userModel) { + this.userModel = userModel; } + public void setFromJson(JSONArray jsonArray) throws JSONException { otherUsersLocations = new ArrayList<>(jsonArray.length()); - for (int i=0; i < jsonArray.length(); i++) { - JSONObject locationObject = jsonArray.getJSONObject(i); - - int latitudeE6 = Integer.parseInt(locationObject.getString("latitude")); - int longitudeE6 = Integer.parseInt(locationObject.getString("longitude")); - - otherUsersLocations.add( - new GeoPoint(latitudeE6 / 1000000.0D, longitudeE6 / 1000000.0D)); + for (int i = 0; i < jsonArray.length(); i++) { + JSONObject locationObject = jsonArray.getJSONObject(i); + if (locationObject.getString("device").equals(userModel.getChangingDeviceToken())) { + continue; // Ignore own location + } + int latitudeE6 = Integer.parseInt(locationObject.getString("latitude")); + int longitudeE6 = Integer.parseInt(locationObject.getString("longitude")); + + otherUsersLocations.add( + new GeoPoint(latitudeE6 / 1000000.0D, longitudeE6 / 1000000.0D)); } } From 50382bee7070a9203051ca0ca5de04d96c8b2e12 Mon Sep 17 00:00:00 2001 From: stephanlindauer Date: Sun, 4 Jun 2023 10:14:05 +0200 Subject: [PATCH 05/10] send app version in HTTP header --- .../criticalmaps/handler/HeartbeatHandler.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/HeartbeatHandler.java b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/HeartbeatHandler.java index a912eaed..363d1f3b 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/HeartbeatHandler.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/HeartbeatHandler.java @@ -10,6 +10,7 @@ import javax.inject.Inject; +import de.stephanlindauer.criticalmaps.BuildConfig; import de.stephanlindauer.criticalmaps.managers.LocationUpdateManager; import de.stephanlindauer.criticalmaps.model.ChatModel; import de.stephanlindauer.criticalmaps.model.OwnLocationModel; @@ -17,6 +18,7 @@ import de.stephanlindauer.criticalmaps.prefs.SharedPrefsKeys; import de.stephanlindauer.criticalmaps.vo.Endpoints; import info.metadude.android.typedpreferences.BooleanPreference; +import okhttp3.Headers; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; @@ -66,7 +68,10 @@ protected Void doInBackground(Void... params) { String jsonPutBody = getJsonObject().toString(); final RequestBody body = RequestBody.create(MediaType.parse("application/json"), jsonPutBody); - final Request request = new Request.Builder().url(Endpoints.LOCATION_PUT).put(body).build(); + final Headers headers = Headers.of("app-version", BuildConfig.VERSION_NAME); + + final Request request = new Request.Builder().url(Endpoints.LOCATION_PUT).put(body).headers(headers).build(); + try { final Response response = okHttpClient.newCall(request).execute(); From a58f522ab2832d885e08fd4ec92a64a712448295 Mon Sep 17 00:00:00 2001 From: stephanlindauer Date: Sun, 4 Jun 2023 13:50:58 +0200 Subject: [PATCH 06/10] get and put works --- .../criticalmaps/fragments/MapFragment.java | 44 ++++++++++ .../handler/GetLocationHandler.java | 81 +++++++++++++++++++ ...atHandler.java => PutLocationHandler.java} | 17 ++-- .../service/ServerSyncService.java | 6 +- 4 files changed, 136 insertions(+), 12 deletions(-) create mode 100644 app/src/main/java/de/stephanlindauer/criticalmaps/handler/GetLocationHandler.java rename app/src/main/java/de/stephanlindauer/criticalmaps/handler/{HeartbeatHandler.java => PutLocationHandler.java} (85%) diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/MapFragment.java b/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/MapFragment.java index 389b5967..388ead35 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/MapFragment.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/MapFragment.java @@ -34,7 +34,11 @@ import org.osmdroid.views.overlay.gestures.RotationGestureOverlay; import org.osmdroid.views.overlay.infowindow.InfoWindow; +import java.util.Timer; +import java.util.TimerTask; + import javax.inject.Inject; +import javax.inject.Provider; import de.stephanlindauer.criticalmaps.App; import de.stephanlindauer.criticalmaps.R; @@ -43,6 +47,8 @@ import de.stephanlindauer.criticalmaps.events.NetworkConnectivityChangedEvent; import de.stephanlindauer.criticalmaps.events.NewLocationEvent; import de.stephanlindauer.criticalmaps.events.NewServerResponseEvent; +import de.stephanlindauer.criticalmaps.handler.GetLocationHandler; +import de.stephanlindauer.criticalmaps.handler.PutLocationHandler; import de.stephanlindauer.criticalmaps.handler.ShowGpxHandler; import de.stephanlindauer.criticalmaps.managers.LocationUpdateManager; import de.stephanlindauer.criticalmaps.model.OtherUsersLocationModel; @@ -53,6 +59,7 @@ import de.stephanlindauer.criticalmaps.utils.AlertBuilder; import de.stephanlindauer.criticalmaps.utils.MapViewUtils; import info.metadude.android.typedpreferences.BooleanPreference; +import timber.log.Timber; public class MapFragment extends Fragment { private final static String KEY_MAP_ZOOMLEVEL = "map_zoomlevel"; @@ -63,6 +70,16 @@ public class MapFragment extends Fragment { private final static double DEFAULT_ZOOM_LEVEL = 12; private final static double NO_GPS_PERMISSION_ZOOM_LEVEL = 3; + private final int SERVER_SYNC_INTERVAL = 30 * 1000; // 30 sec + + private Timer timerGetLocation; + + + + @Inject + Provider getLocationHandler; + + @Inject OwnLocationModel ownLocationModel; @@ -305,6 +322,9 @@ private void refreshView() { public void onResume() { super.onResume(); eventBus.register(this); + startGetLocationTimer(); + + Timber.d("onResume"); sharedPreferences.registerOnSharedPreferenceChangeListener( observerModeOnSharedPreferenceChangeListener); @@ -336,6 +356,9 @@ public void onSaveInstanceState(@NonNull Bundle outState) { public void onPause() { super.onPause(); eventBus.unregister(this); + stopGetLocationTimer(); + + Timber.d("onPause"); sharedPreferences.unregisterOnSharedPreferenceChangeListener( observerModeOnSharedPreferenceChangeListener); @@ -472,4 +495,25 @@ private void animateToLocation(final GeoPoint location) { private void setToLocation(final GeoPoint location) { mapView.getController().setCenter(location); } + private void startGetLocationTimer() { + stopGetLocationTimer(); + + timerGetLocation = new Timer(); + + TimerTask timerTaskPullServer = new TimerTask() { + @Override + public void run() { + getLocationHandler.get().execute(); + } + }; + timerGetLocation.scheduleAtFixedRate(timerTaskPullServer, 0, SERVER_SYNC_INTERVAL); + } + + private void stopGetLocationTimer() { + if (timerGetLocation != null) { + timerGetLocation.cancel(); + timerGetLocation = null; + } + } + } diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/GetLocationHandler.java b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/GetLocationHandler.java new file mode 100644 index 00000000..e229c828 --- /dev/null +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/GetLocationHandler.java @@ -0,0 +1,81 @@ +package de.stephanlindauer.criticalmaps.handler; + +import android.content.SharedPreferences; +import android.os.AsyncTask; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; + +import javax.inject.Inject; + +import de.stephanlindauer.criticalmaps.BuildConfig; +import de.stephanlindauer.criticalmaps.managers.LocationUpdateManager; +import de.stephanlindauer.criticalmaps.model.ChatModel; +import de.stephanlindauer.criticalmaps.model.OwnLocationModel; +import de.stephanlindauer.criticalmaps.model.UserModel; +import de.stephanlindauer.criticalmaps.prefs.SharedPrefsKeys; +import de.stephanlindauer.criticalmaps.vo.Endpoints; +import info.metadude.android.typedpreferences.BooleanPreference; +import okhttp3.Headers; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import timber.log.Timber; + +public class GetLocationHandler extends AsyncTask { + + //dependencies + private final ChatModel chatModel; + private final OwnLocationModel ownLocationModel; + private final UserModel userModel; + private final OkHttpClient okHttpClient; + private final SharedPreferences sharedPreferences; + private final LocationUpdateManager locationUpdateManager; + private final ServerResponseProcessor serverResponseProcessor; + + @Inject + public GetLocationHandler(ChatModel chatModel, + OwnLocationModel ownLocationModel, + UserModel userModel, + ServerResponseProcessor serverResponseProcessor, + OkHttpClient okHttpClient, + SharedPreferences sharedPreferences, + LocationUpdateManager locationUpdateManager) { + this.chatModel = chatModel; + this.ownLocationModel = ownLocationModel; + this.userModel = userModel; + this.okHttpClient = okHttpClient; + this.sharedPreferences = sharedPreferences; + this.locationUpdateManager = locationUpdateManager; + this.serverResponseProcessor = serverResponseProcessor; + } + + @Override + protected String doInBackground(Void... params) { + final Headers headers = Headers.of("app-version", BuildConfig.VERSION_NAME); + + final Request request = new Request.Builder().url(Endpoints.LOCATION_GET).get().headers(headers).build(); + + try { + final Response response = okHttpClient.newCall(request).execute(); + if (!response.isSuccessful()) { + Timber.d("Get locations unsuccessful."); + } + return response.body().string(); + } catch (IOException e) { + Timber.e(e); + } + return ""; + } + + @Override + protected void onPostExecute(String result) { + if (!result.isEmpty()) { + serverResponseProcessor.process(result); + } + } +} diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/HeartbeatHandler.java b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/PutLocationHandler.java similarity index 85% rename from app/src/main/java/de/stephanlindauer/criticalmaps/handler/HeartbeatHandler.java rename to app/src/main/java/de/stephanlindauer/criticalmaps/handler/PutLocationHandler.java index 363d1f3b..13b667c1 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/HeartbeatHandler.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/PutLocationHandler.java @@ -26,7 +26,7 @@ import okhttp3.Response; import timber.log.Timber; -public class HeartbeatHandler extends AsyncTask { +public class PutLocationHandler extends AsyncTask { //dependencies private final ChatModel chatModel; @@ -37,13 +37,13 @@ public class HeartbeatHandler extends AsyncTask { private final LocationUpdateManager locationUpdateManager; @Inject - public HeartbeatHandler(ChatModel chatModel, - OwnLocationModel ownLocationModel, - UserModel userModel, - ServerResponseProcessor serverResponseProcessor, - OkHttpClient okHttpClient, - SharedPreferences sharedPreferences, - LocationUpdateManager locationUpdateManager) { + public PutLocationHandler(ChatModel chatModel, + OwnLocationModel ownLocationModel, + UserModel userModel, + ServerResponseProcessor serverResponseProcessor, + OkHttpClient okHttpClient, + SharedPreferences sharedPreferences, + LocationUpdateManager locationUpdateManager) { this.chatModel = chatModel; this.ownLocationModel = ownLocationModel; this.userModel = userModel; @@ -72,7 +72,6 @@ protected Void doInBackground(Void... params) { final Request request = new Request.Builder().url(Endpoints.LOCATION_PUT).put(body).headers(headers).build(); - try { final Response response = okHttpClient.newCall(request).execute(); if (!response.isSuccessful()) { diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/service/ServerSyncService.java b/app/src/main/java/de/stephanlindauer/criticalmaps/service/ServerSyncService.java index 305c87d4..aab35951 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/service/ServerSyncService.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/service/ServerSyncService.java @@ -17,7 +17,7 @@ import de.stephanlindauer.criticalmaps.App; import de.stephanlindauer.criticalmaps.events.NetworkConnectivityChangedEvent; import de.stephanlindauer.criticalmaps.handler.NetworkConnectivityChangeHandler; -import de.stephanlindauer.criticalmaps.handler.HeartbeatHandler; +import de.stephanlindauer.criticalmaps.handler.PutLocationHandler; import de.stephanlindauer.criticalmaps.managers.LocationUpdateManager; import de.stephanlindauer.criticalmaps.provider.EventBus; import de.stephanlindauer.criticalmaps.utils.TrackingInfoNotificationBuilder; @@ -36,7 +36,7 @@ public class ServerSyncService extends Service { NetworkConnectivityChangeHandler networkConnectivityChangeHandler; @Inject - Provider heartbeatHandler; + Provider putLocationHandler; @Inject EventBus eventBus; @@ -66,7 +66,7 @@ private void startPullServerTimer() { TimerTask timerTaskPullServer = new TimerTask() { @Override public void run() { - heartbeatHandler.get().execute(); + putLocationHandler.get().execute(); } }; timerPullServer.scheduleAtFixedRate(timerTaskPullServer, 0, SERVER_SYNC_INTERVAL); From 97cd88630d6a2307b426c8b158d2e327383d388a Mon Sep 17 00:00:00 2001 From: Christian Balster Date: Sun, 4 Jun 2023 15:04:28 +0200 Subject: [PATCH 07/10] Cleanup unused imports etc. --- .../criticalmaps/fragments/MapFragment.java | 22 +++------ .../handler/GetLocationHandler.java | 46 +++++-------------- .../handler/PutLocationHandler.java | 30 ++++++------ 3 files changed, 32 insertions(+), 66 deletions(-) diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/MapFragment.java b/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/MapFragment.java index 388ead35..0548e154 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/MapFragment.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/MapFragment.java @@ -48,7 +48,6 @@ import de.stephanlindauer.criticalmaps.events.NewLocationEvent; import de.stephanlindauer.criticalmaps.events.NewServerResponseEvent; import de.stephanlindauer.criticalmaps.handler.GetLocationHandler; -import de.stephanlindauer.criticalmaps.handler.PutLocationHandler; import de.stephanlindauer.criticalmaps.handler.ShowGpxHandler; import de.stephanlindauer.criticalmaps.managers.LocationUpdateManager; import de.stephanlindauer.criticalmaps.model.OtherUsersLocationModel; @@ -59,7 +58,7 @@ import de.stephanlindauer.criticalmaps.utils.AlertBuilder; import de.stephanlindauer.criticalmaps.utils.MapViewUtils; import info.metadude.android.typedpreferences.BooleanPreference; -import timber.log.Timber; + public class MapFragment extends Fragment { private final static String KEY_MAP_ZOOMLEVEL = "map_zoomlevel"; @@ -69,17 +68,13 @@ public class MapFragment extends Fragment { private final static double DEFAULT_ZOOM_LEVEL = 12; private final static double NO_GPS_PERMISSION_ZOOM_LEVEL = 3; - private final int SERVER_SYNC_INTERVAL = 30 * 1000; // 30 sec private Timer timerGetLocation; - - @Inject Provider getLocationHandler; - @Inject OwnLocationModel ownLocationModel; @@ -321,11 +316,8 @@ private void refreshView() { @Override public void onResume() { super.onResume(); - eventBus.register(this); - startGetLocationTimer(); - - Timber.d("onResume"); + eventBus.register(this); sharedPreferences.registerOnSharedPreferenceChangeListener( observerModeOnSharedPreferenceChangeListener); @@ -334,6 +326,8 @@ public void onResume() { } else { zoomToLocation(defaultGeoPoint, NO_GPS_PERMISSION_ZOOM_LEVEL); } + + startGetLocationTimer(); } private void handleFirstLocationUpdate() { @@ -355,11 +349,9 @@ public void onSaveInstanceState(@NonNull Bundle outState) { @Override public void onPause() { super.onPause(); - eventBus.unregister(this); - stopGetLocationTimer(); - - Timber.d("onPause"); + stopGetLocationTimer(); + eventBus.unregister(this); sharedPreferences.unregisterOnSharedPreferenceChangeListener( observerModeOnSharedPreferenceChangeListener); } @@ -495,6 +487,7 @@ private void animateToLocation(final GeoPoint location) { private void setToLocation(final GeoPoint location) { mapView.getController().setCenter(location); } + private void startGetLocationTimer() { stopGetLocationTimer(); @@ -515,5 +508,4 @@ private void stopGetLocationTimer() { timerGetLocation = null; } } - } diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/GetLocationHandler.java b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/GetLocationHandler.java index e229c828..cbd71657 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/GetLocationHandler.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/GetLocationHandler.java @@ -1,75 +1,53 @@ package de.stephanlindauer.criticalmaps.handler; -import android.content.SharedPreferences; import android.os.AsyncTask; -import org.json.JSONException; -import org.json.JSONObject; - import java.io.IOException; import javax.inject.Inject; import de.stephanlindauer.criticalmaps.BuildConfig; -import de.stephanlindauer.criticalmaps.managers.LocationUpdateManager; -import de.stephanlindauer.criticalmaps.model.ChatModel; -import de.stephanlindauer.criticalmaps.model.OwnLocationModel; -import de.stephanlindauer.criticalmaps.model.UserModel; -import de.stephanlindauer.criticalmaps.prefs.SharedPrefsKeys; import de.stephanlindauer.criticalmaps.vo.Endpoints; -import info.metadude.android.typedpreferences.BooleanPreference; + import okhttp3.Headers; -import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; -import okhttp3.RequestBody; import okhttp3.Response; import timber.log.Timber; + public class GetLocationHandler extends AsyncTask { - //dependencies - private final ChatModel chatModel; - private final OwnLocationModel ownLocationModel; - private final UserModel userModel; private final OkHttpClient okHttpClient; - private final SharedPreferences sharedPreferences; - private final LocationUpdateManager locationUpdateManager; private final ServerResponseProcessor serverResponseProcessor; @Inject - public GetLocationHandler(ChatModel chatModel, - OwnLocationModel ownLocationModel, - UserModel userModel, - ServerResponseProcessor serverResponseProcessor, - OkHttpClient okHttpClient, - SharedPreferences sharedPreferences, - LocationUpdateManager locationUpdateManager) { - this.chatModel = chatModel; - this.ownLocationModel = ownLocationModel; - this.userModel = userModel; + public GetLocationHandler(ServerResponseProcessor serverResponseProcessor, + OkHttpClient okHttpClient + ) { this.okHttpClient = okHttpClient; - this.sharedPreferences = sharedPreferences; - this.locationUpdateManager = locationUpdateManager; this.serverResponseProcessor = serverResponseProcessor; } @Override protected String doInBackground(Void... params) { final Headers headers = Headers.of("app-version", BuildConfig.VERSION_NAME); - final Request request = new Request.Builder().url(Endpoints.LOCATION_GET).get().headers(headers).build(); + String responseString = ""; try { final Response response = okHttpClient.newCall(request).execute(); if (!response.isSuccessful()) { - Timber.d("Get locations unsuccessful."); + Timber.d("Get locations unsuccessful with code %d", response.code()); } - return response.body().string(); + //noinspection ConstantConditions "Returns a non-null value if this response was [...] returned from Call.execute()." + responseString = response.body().string(); + response.body().close(); } catch (IOException e) { Timber.e(e); } - return ""; + + return responseString; } @Override diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/PutLocationHandler.java b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/PutLocationHandler.java index 13b667c1..3cec59ca 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/PutLocationHandler.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/PutLocationHandler.java @@ -12,7 +12,6 @@ import de.stephanlindauer.criticalmaps.BuildConfig; import de.stephanlindauer.criticalmaps.managers.LocationUpdateManager; -import de.stephanlindauer.criticalmaps.model.ChatModel; import de.stephanlindauer.criticalmaps.model.OwnLocationModel; import de.stephanlindauer.criticalmaps.model.UserModel; import de.stephanlindauer.criticalmaps.prefs.SharedPrefsKeys; @@ -26,10 +25,9 @@ import okhttp3.Response; import timber.log.Timber; + public class PutLocationHandler extends AsyncTask { - //dependencies - private final ChatModel chatModel; private final OwnLocationModel ownLocationModel; private final UserModel userModel; private final OkHttpClient okHttpClient; @@ -37,14 +35,12 @@ public class PutLocationHandler extends AsyncTask { private final LocationUpdateManager locationUpdateManager; @Inject - public PutLocationHandler(ChatModel chatModel, - OwnLocationModel ownLocationModel, - UserModel userModel, - ServerResponseProcessor serverResponseProcessor, - OkHttpClient okHttpClient, - SharedPreferences sharedPreferences, - LocationUpdateManager locationUpdateManager) { - this.chatModel = chatModel; + public PutLocationHandler( + OwnLocationModel ownLocationModel, + UserModel userModel, + OkHttpClient okHttpClient, + SharedPreferences sharedPreferences, + LocationUpdateManager locationUpdateManager) { this.ownLocationModel = ownLocationModel; this.userModel = userModel; this.okHttpClient = okHttpClient; @@ -69,31 +65,31 @@ protected Void doInBackground(Void... params) { final RequestBody body = RequestBody.create(MediaType.parse("application/json"), jsonPutBody); final Headers headers = Headers.of("app-version", BuildConfig.VERSION_NAME); - final Request request = new Request.Builder().url(Endpoints.LOCATION_PUT).put(body).headers(headers).build(); try { final Response response = okHttpClient.newCall(request).execute(); if (!response.isSuccessful()) { //TODO Display error to user + Timber.d("Put location unsuccessful with code %d", response.code()); } + response.close(); } catch (IOException e) { Timber.e(e); } + return null; } - private JSONObject getJsonObject() { - JSONObject jsonObject; - jsonObject = ownLocationModel.getLocationJson(); + JSONObject jsonObject = ownLocationModel.getLocationJson(); - try{ + try { jsonObject.put("device", userModel.getChangingDeviceToken()); } catch (JSONException e) { Timber.e(e); } - + return jsonObject; } } From 78c56e49f6e6f9c7e1a9a8bed4e0124eff5a559c Mon Sep 17 00:00:00 2001 From: Christian Balster Date: Sun, 4 Jun 2023 16:43:35 +0200 Subject: [PATCH 08/10] Stop/start location requests on connectivity changed --- .../criticalmaps/fragments/MapFragment.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/MapFragment.java b/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/MapFragment.java index 0548e154..6913ceda 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/MapFragment.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/MapFragment.java @@ -70,8 +70,6 @@ public class MapFragment extends Fragment { private final static double NO_GPS_PERMISSION_ZOOM_LEVEL = 3; private final int SERVER_SYNC_INTERVAL = 30 * 1000; // 30 sec - private Timer timerGetLocation; - @Inject Provider getLocationHandler; @@ -107,6 +105,8 @@ public class MapFragment extends Fragment { private FragmentMapBinding binding; + private Timer timerGetLocation; + private final View.OnClickListener centerLocationOnClickListener = new View.OnClickListener() { @Override public void onClick(View v) { @@ -391,6 +391,12 @@ public void handleNetworkConnectivityChanged(NetworkConnectivityChangedEvent e) } else { binding.mapNoDataConnectivityFab.show(); } + + if (e.isConnected && timerGetLocation == null) { + startGetLocationTimer(); + } else { + stopGetLocationTimer(); + } } @Subscribe From 1db724e08aa56739ba92c8c4ec6017a31d65c737 Mon Sep 17 00:00:00 2001 From: Christian Balster Date: Sun, 4 Jun 2023 17:02:56 +0200 Subject: [PATCH 09/10] Migrate getting new chatmessages to new api --- .../criticalmaps/fragments/ChatFragment.java | 41 ++++++++++++- .../handler/GetChatmessagesHandler.java | 58 +++++++++++++++++++ .../handler/GetLocationHandler.java | 2 +- .../handler/ServerResponseProcessor.java | 12 +++- .../criticalmaps/model/ChatModel.java | 6 +- .../criticalmaps/vo/Endpoints.java | 5 +- .../handler/ServerResponseProcessorTest.java | 6 +- 7 files changed, 119 insertions(+), 11 deletions(-) create mode 100644 app/src/main/java/de/stephanlindauer/criticalmaps/handler/GetChatmessagesHandler.java diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/ChatFragment.java b/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/ChatFragment.java index b098aee9..521bf27a 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/ChatFragment.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/ChatFragment.java @@ -24,8 +24,11 @@ import java.util.ArrayList; import java.util.List; +import java.util.Timer; +import java.util.TimerTask; import javax.inject.Inject; +import javax.inject.Provider; import de.stephanlindauer.criticalmaps.App; import de.stephanlindauer.criticalmaps.R; @@ -33,23 +36,30 @@ import de.stephanlindauer.criticalmaps.databinding.FragmentChatBinding; import de.stephanlindauer.criticalmaps.events.NetworkConnectivityChangedEvent; import de.stephanlindauer.criticalmaps.events.NewServerResponseEvent; +import de.stephanlindauer.criticalmaps.handler.GetChatmessagesHandler; import de.stephanlindauer.criticalmaps.model.ChatModel; import de.stephanlindauer.criticalmaps.model.chat.OutgoingChatMessage; import de.stephanlindauer.criticalmaps.model.chat.ReceivedChatMessage; import de.stephanlindauer.criticalmaps.provider.EventBus; import de.stephanlindauer.criticalmaps.utils.AxtUtils.SimpleTextWatcher; + public class ChatFragment extends Fragment { + @Inject + Provider getChatmessagesHandler; + @Inject ChatModel chatModel; @Inject EventBus eventBus; - private boolean isTextInputEnabled = true; private ChatMessageAdapter chatMessageAdapter; private FragmentChatBinding binding; + private Timer timerGetChatmessages; + + private final int SERVER_SYNC_INTERVAL = 30 * 1000; // 30 sec @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, @@ -151,11 +161,13 @@ public void onResume() { super.onResume(); displayNewData(); eventBus.register(this); + startGetChatmessagesTimer(); } @Override public void onPause() { super.onPause(); + stopGetChatmessagesTimer(); eventBus.unregister(this); hideKeyBoard(binding.chatMessageEdittext); } @@ -176,6 +188,12 @@ public void handleNewServerData(NewServerResponseEvent e) { @Subscribe public void handleNetworkConnectivityChanged(NetworkConnectivityChangedEvent e) { setTextInputState(e.isConnected); + + if (e.isConnected && timerGetChatmessages == null) { + startGetChatmessagesTimer(); + } else { + stopGetChatmessagesTimer(); + } } private void setTextInputState(final boolean dataEnabled) { @@ -196,4 +214,25 @@ private void updateSendButtonEnabledState() { final String message = binding.chatMessageEdittext.getText().toString(); setSendButtonEnabledWithAnimation(!message.trim().isEmpty()); } + + private void startGetChatmessagesTimer() { + stopGetChatmessagesTimer(); + + timerGetChatmessages = new Timer(); + + TimerTask timerTaskPullServer = new TimerTask() { + @Override + public void run() { + getChatmessagesHandler.get().execute(); + } + }; + timerGetChatmessages.scheduleAtFixedRate(timerTaskPullServer, 0, SERVER_SYNC_INTERVAL); + } + + private void stopGetChatmessagesTimer() { + if (timerGetChatmessages != null) { + timerGetChatmessages.cancel(); + timerGetChatmessages = null; + } + } } diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/GetChatmessagesHandler.java b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/GetChatmessagesHandler.java new file mode 100644 index 00000000..6cee0499 --- /dev/null +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/GetChatmessagesHandler.java @@ -0,0 +1,58 @@ +package de.stephanlindauer.criticalmaps.handler; + +import android.os.AsyncTask; + +import java.io.IOException; + +import javax.inject.Inject; + +import de.stephanlindauer.criticalmaps.BuildConfig; +import de.stephanlindauer.criticalmaps.vo.Endpoints; +import okhttp3.Headers; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import timber.log.Timber; + + +public class GetChatmessagesHandler extends AsyncTask { + + private final OkHttpClient okHttpClient; + private final ServerResponseProcessor serverResponseProcessor; + + @Inject + public GetChatmessagesHandler(ServerResponseProcessor serverResponseProcessor, + OkHttpClient okHttpClient + ) { + this.okHttpClient = okHttpClient; + this.serverResponseProcessor = serverResponseProcessor; + } + + @Override + protected String doInBackground(Void... params) { + final Headers headers = Headers.of("app-version", BuildConfig.VERSION_NAME); + final Request request = new Request.Builder().url(Endpoints.CHAT_GET).get().headers(headers).build(); + + String responseString = ""; + try { + final Response response = okHttpClient.newCall(request).execute(); + if (!response.isSuccessful()) { + Timber.d("Get chatmessages unsuccessful with code %d", response.code()); + } + //noinspection ConstantConditions "Returns a non-null value if this response was [...] returned from Call.execute()." + responseString = response.body().string(); + response.body().close(); + } catch (IOException e) { + Timber.e(e); + } + + return responseString; + } + + @Override + protected void onPostExecute(String result) { + if (!result.isEmpty()) { + serverResponseProcessor.processChatmessages(result); + } + } +} diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/GetLocationHandler.java b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/GetLocationHandler.java index cbd71657..70c84def 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/GetLocationHandler.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/GetLocationHandler.java @@ -53,7 +53,7 @@ protected String doInBackground(Void... params) { @Override protected void onPostExecute(String result) { if (!result.isEmpty()) { - serverResponseProcessor.process(result); + serverResponseProcessor.processLocations(result); } } } diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ServerResponseProcessor.java b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ServerResponseProcessor.java index cfe77eb5..f82f545f 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ServerResponseProcessor.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/ServerResponseProcessor.java @@ -1,7 +1,6 @@ package de.stephanlindauer.criticalmaps.handler; import org.json.JSONArray; -import org.json.JSONObject; import javax.inject.Inject; @@ -26,11 +25,20 @@ public ServerResponseProcessor(OtherUsersLocationModel otherUsersLocationModel, this.chatModel = chatModel; } - public void process(final String jsonString) { + public void processLocations(final String jsonString) { try { final JSONArray jsonArray = new JSONArray(jsonString); otherUsersLocationModel.setFromJson(jsonArray); + eventBus.post(Events.NEW_SERVER_RESPONSE_EVENT); + } catch (Exception e) { + Timber.d(e); + } + } + public void processChatmessages(final String jsonString) { + try { + final JSONArray jsonArray = new JSONArray(jsonString); + chatModel.setFromJson(jsonArray); eventBus.post(Events.NEW_SERVER_RESPONSE_EVENT); } catch (Exception e) { Timber.d(e); diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/model/ChatModel.java b/app/src/main/java/de/stephanlindauer/criticalmaps/model/ChatModel.java index 450c7fa4..aa9550e2 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/model/ChatModel.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/model/ChatModel.java @@ -12,7 +12,6 @@ import java.util.Collections; import java.util.Comparator; import java.util.Date; -import java.util.Iterator; import java.util.List; import javax.inject.Inject; @@ -23,14 +22,15 @@ import okhttp3.internal.Util; import timber.log.Timber; + @Singleton public class ChatModel { - public static int MESSAGE_MAX_LENGTH = 255; private final UserModel userModel; - private List receivedChatMessages = new ArrayList<>(); + public static int MESSAGE_MAX_LENGTH = 255; + @Inject public ChatModel(UserModel userModel) { this.userModel = userModel; diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/vo/Endpoints.java b/app/src/main/java/de/stephanlindauer/criticalmaps/vo/Endpoints.java index 8da323cc..c77c2172 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/vo/Endpoints.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/vo/Endpoints.java @@ -1,9 +1,12 @@ package de.stephanlindauer.criticalmaps.vo; public class Endpoints { -// IMAGE_POST doesn't currently work. Once fixed CDN or API_GATEWAY should be used to prefix the URI. + // IMAGE_POST doesn't currently work. Once fixed CDN or API_GATEWAY should be used to prefix the URI. public static final String IMAGE_POST = "https://api.criticalmaps.net/gallery/"; public static final String LOCATION_GET = "https://api-cdn.criticalmaps.net/locations"; public static final String LOCATION_PUT = "https://api-gw.criticalmaps.net/locations"; + + public static final String CHAT_GET = "https://api-gw.criticalmaps.net/messages"; + public static final String CHAT_POST = "https://api-gw.criticalmaps.net/messages"; } diff --git a/app/src/test/java/de/stephanlindauer/criticalmaps/handler/ServerResponseProcessorTest.java b/app/src/test/java/de/stephanlindauer/criticalmaps/handler/ServerResponseProcessorTest.java index e276510f..244de88f 100644 --- a/app/src/test/java/de/stephanlindauer/criticalmaps/handler/ServerResponseProcessorTest.java +++ b/app/src/test/java/de/stephanlindauer/criticalmaps/handler/ServerResponseProcessorTest.java @@ -33,7 +33,7 @@ public void process_chatmessagesAreSetOnModel() throws IOException, URISyntaxExc final ServerResponseProcessor tested = new ServerResponseProcessor( mock(OtherUsersLocationModel.class), mock(EventBus.class), chatModel); - tested.process(json); + tested.processLocations(json); verify(chatModel).setFromJson(any(JSONObject.class)); } @@ -46,7 +46,7 @@ public void process_eventIsFiredForValidJSON() throws IOException, URISyntaxExce final ServerResponseProcessor tested = new ServerResponseProcessor( mock(OtherUsersLocationModel.class), eventMock, mock(ChatModel.class)); - tested.process(json); + tested.processLocations(json); verify(eventMock, times(1)).post(Events.NEW_SERVER_RESPONSE_EVENT); } @@ -57,7 +57,7 @@ public void process_noEventIsFiredForInvalidJSON() { final ServerResponseProcessor tested = new ServerResponseProcessor( mock(OtherUsersLocationModel.class), eventMock, mock(ChatModel.class)); - tested.process("borken"); + tested.processLocations("borken"); verify(eventMock, never()).post(Events.NEW_SERVER_RESPONSE_EVENT); } From 5ec10dc30874440f7f252365a49ae2999d606111 Mon Sep 17 00:00:00 2001 From: Christian Balster Date: Sun, 4 Jun 2023 19:17:50 +0200 Subject: [PATCH 10/10] Migrate sending chat messages to new API --- .../adapter/ChatMessageAdapter.java | 28 +------- .../criticalmaps/fragments/ChatFragment.java | 51 +++++++++++++- .../handler/PostChatmessagesHandler.java | 66 +++++++++++++++++++ .../criticalmaps/model/ChatModel.java | 20 ++++-- .../model/chat/OutgoingChatMessage.java | 47 ------------- .../criticalmaps/model/ChatModelTest.java | 1 - 6 files changed, 132 insertions(+), 81 deletions(-) create mode 100644 app/src/main/java/de/stephanlindauer/criticalmaps/handler/PostChatmessagesHandler.java delete mode 100644 app/src/main/java/de/stephanlindauer/criticalmaps/model/chat/OutgoingChatMessage.java diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/adapter/ChatMessageAdapter.java b/app/src/main/java/de/stephanlindauer/criticalmaps/adapter/ChatMessageAdapter.java index e753fa44..7f609666 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/adapter/ChatMessageAdapter.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/adapter/ChatMessageAdapter.java @@ -26,7 +26,6 @@ static class ChatMessageViewHolder extends RecyclerView.ViewHolder { private final ViewChatmessageBinding binding; private final DateFormat dateFormatter = DateFormat.getDateTimeInstance( DateFormat.DEFAULT, DateFormat.SHORT, Locale.getDefault()); - private ObjectAnimator sendingAnimator; ChatMessageViewHolder(ViewChatmessageBinding binding) { super(binding.getRoot()); @@ -35,25 +34,9 @@ static class ChatMessageViewHolder extends RecyclerView.ViewHolder { void bind(ReceivedChatMessage message) { binding.chatmessageMessageText.setText(message.getMessage()); - if (message instanceof ReceivedChatMessage) { - dateFormatter.setTimeZone(TimeZone.getDefault()); - binding.chatmessageLabelText.setText(TimeToWordStringConverter.getTimeAgo( - ((ReceivedChatMessage) message).getTimestamp(), itemView.getContext())); - } else { - binding.chatmessageLabelText.setText(R.string.chat_sending); - - sendingAnimator = (ObjectAnimator) AnimatorInflater.loadAnimator( - itemView.getContext(), R.animator.map_gps_fab_searching_animation); - sendingAnimator.setTarget(binding.chatmessageLabelText); - sendingAnimator.start(); - } - } - - void clearAnimation() { - if (sendingAnimator != null) { - sendingAnimator.cancel(); - binding.chatmessageLabelText.setAlpha(1f); - } + dateFormatter.setTimeZone(TimeZone.getDefault()); + binding.chatmessageLabelText.setText(TimeToWordStringConverter.getTimeAgo( + message.getTimestamp(), itemView.getContext())); } } @@ -76,11 +59,6 @@ public void onBindViewHolder(@NonNull ChatMessageViewHolder holder, int position holder.bind(chatMessages.get(position)); } - @Override - public void onViewDetachedFromWindow(@NonNull ChatMessageViewHolder holder) { - holder.clearAnimation(); - } - @Override public int getItemCount() { return chatMessages.size(); diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/ChatFragment.java b/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/ChatFragment.java index 521bf27a..8aed1951 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/ChatFragment.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/fragments/ChatFragment.java @@ -13,6 +13,7 @@ import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; +import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -22,6 +23,8 @@ import com.squareup.otto.Subscribe; +import org.json.JSONObject; + import java.util.ArrayList; import java.util.List; import java.util.Timer; @@ -37,8 +40,8 @@ import de.stephanlindauer.criticalmaps.events.NetworkConnectivityChangedEvent; import de.stephanlindauer.criticalmaps.events.NewServerResponseEvent; import de.stephanlindauer.criticalmaps.handler.GetChatmessagesHandler; +import de.stephanlindauer.criticalmaps.handler.PostChatmessagesHandler; import de.stephanlindauer.criticalmaps.model.ChatModel; -import de.stephanlindauer.criticalmaps.model.chat.OutgoingChatMessage; import de.stephanlindauer.criticalmaps.model.chat.ReceivedChatMessage; import de.stephanlindauer.criticalmaps.provider.EventBus; import de.stephanlindauer.criticalmaps.utils.AxtUtils.SimpleTextWatcher; @@ -57,9 +60,10 @@ public class ChatFragment extends Fragment { private boolean isTextInputEnabled = true; private ChatMessageAdapter chatMessageAdapter; private FragmentChatBinding binding; + // private ObjectAnimator sendingAnimator; private Timer timerGetChatmessages; - private final int SERVER_SYNC_INTERVAL = 30 * 1000; // 30 sec + private final int SERVER_SYNC_INTERVAL = 20 * 1000; // 20 sec @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, @@ -141,12 +145,51 @@ private void handleSendClicked() { return; } - chatModel.sendNewOutgoingMessage(new OutgoingChatMessage(message)); + // TODO handle UI state while sending, even though it shouldn't be noticeable + + JSONObject messageObject = chatModel.createNewOutgoingMessage(message); + new PostChatmessagesHandler(messageObject, new Runnable() { + @Override + public void run() { + // TODO check if still alive; else bail! + // TODO reset UI state + // clearAnimation(); + + // Restart timer task so sent message shows up in list immediately + stopGetChatmessagesTimer(); + startGetChatmessagesTimer(); + } + }, new Runnable() { + @Override + public void run() { + // TODO check if still alive; else bail! + // TODO reset UI state + Toast.makeText(getContext(), R.string.something_went_wrong, Toast.LENGTH_LONG).show(); + } + }).execute(); binding.chatMessageEdittext.setText(""); displayNewData(); } + /* + private void setSendingAnimation() { + binding.chatmessageLabelText.setText(R.string.chat_sending); + + sendingAnimator = (ObjectAnimator) AnimatorInflater.loadAnimator( + itemView.getContext(), R.animator.map_gps_fab_searching_animation); + sendingAnimator.setTarget(binding.chatmessageLabelText); + sendingAnimator.start(); + } + + private void clearAnimation() { + if (sendingAnimator != null) { + sendingAnimator.cancel(); + binding.chatmessageLabelText.setAlpha(1f); + } + } + */ + private void displayNewData() { final List receivedChatMessages = chatModel.getReceivedChatMessages(); chatMessageAdapter.updateData(receivedChatMessages); @@ -175,6 +218,8 @@ public void onPause() { @Override public void onDestroyView() { super.onDestroyView(); + // TODO + // clearAnimation(); binding = null; } diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/handler/PostChatmessagesHandler.java b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/PostChatmessagesHandler.java new file mode 100644 index 00000000..834befea --- /dev/null +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/handler/PostChatmessagesHandler.java @@ -0,0 +1,66 @@ +package de.stephanlindauer.criticalmaps.handler; + +import android.os.AsyncTask; + +import org.json.JSONObject; + +import java.io.IOException; + +import de.stephanlindauer.criticalmaps.App; +import de.stephanlindauer.criticalmaps.BuildConfig; +import de.stephanlindauer.criticalmaps.vo.Endpoints; +import okhttp3.Headers; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import timber.log.Timber; + + +public class PostChatmessagesHandler extends AsyncTask { + + private final OkHttpClient okHttpClient = App.components().okHttpClient(); + + private final JSONObject message; + private final Runnable onSuccessCallback; + private final Runnable onErrorCallback; + + public PostChatmessagesHandler(JSONObject message, Runnable onSuccessCallback, Runnable onErrorCallback) { + this.message = message; + this.onSuccessCallback = onSuccessCallback; + this.onErrorCallback = onErrorCallback; + } + + @Override + protected Boolean doInBackground(Void... params) { + + String jsonBody = message.toString(); + final RequestBody body = RequestBody.create(MediaType.parse("application/json"), jsonBody); + final Headers headers = Headers.of("app-version", BuildConfig.VERSION_NAME); + final Request request = new Request.Builder().url(Endpoints.CHAT_POST).post(body).headers(headers).build(); + + boolean wasSuccessful = false; + try { + final Response response = okHttpClient.newCall(request).execute(); + if (!response.isSuccessful()) { + Timber.d("Post chatmessages unsuccessful with code %d", response.code()); + } + wasSuccessful = response.isSuccessful(); + response.close(); + } catch (IOException e) { + Timber.e(e); + } + + return wasSuccessful; + } + + @Override + protected void onPostExecute(Boolean success) { + if (success) { + onSuccessCallback.run(); + } else { + onErrorCallback.run(); + } + } +} diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/model/ChatModel.java b/app/src/main/java/de/stephanlindauer/criticalmaps/model/ChatModel.java index aa9550e2..783e9b61 100644 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/model/ChatModel.java +++ b/app/src/main/java/de/stephanlindauer/criticalmaps/model/ChatModel.java @@ -8,6 +8,7 @@ import java.io.UnsupportedEncodingException; import java.net.URLDecoder; +import java.net.URLEncoder; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -17,8 +18,9 @@ import javax.inject.Inject; import javax.inject.Singleton; -import de.stephanlindauer.criticalmaps.model.chat.OutgoingChatMessage; +import de.stephanlindauer.criticalmaps.handler.PostChatmessagesHandler; import de.stephanlindauer.criticalmaps.model.chat.ReceivedChatMessage; +import de.stephanlindauer.criticalmaps.utils.AeSimpleSHA1; import okhttp3.internal.Util; import timber.log.Timber; @@ -65,15 +67,23 @@ public int compare(ReceivedChatMessage oneChatMessages, }); } - public void sendNewOutgoingMessage(OutgoingChatMessage newOutgoingMessage) { + public JSONObject createNewOutgoingMessage(String message) { JSONObject messageObject = new JSONObject(); try { - messageObject.put("text", newOutgoingMessage.getUrlEncodedMessage()); - messageObject.put("timestamp", newOutgoingMessage.getTimestamp().getTime()); - messageObject.put("identifier", newOutgoingMessage.getIdentifier()); + messageObject.put("text", urlEncodeMessage(message)); + messageObject.put("identifier", AeSimpleSHA1.SHA1(message + Math.random())); messageObject.put("device", userModel.getChangingDeviceToken()); } catch (JSONException e) { Timber.d(e); } + return messageObject; + } + + private String urlEncodeMessage(String messageToEncode) { + try { + return URLEncoder.encode(messageToEncode, Util.UTF_8.name()); + } catch (UnsupportedEncodingException e) { + return ""; + } } } diff --git a/app/src/main/java/de/stephanlindauer/criticalmaps/model/chat/OutgoingChatMessage.java b/app/src/main/java/de/stephanlindauer/criticalmaps/model/chat/OutgoingChatMessage.java deleted file mode 100644 index 7c7f6033..00000000 --- a/app/src/main/java/de/stephanlindauer/criticalmaps/model/chat/OutgoingChatMessage.java +++ /dev/null @@ -1,47 +0,0 @@ -package de.stephanlindauer.criticalmaps.model.chat; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.Date; - -import de.stephanlindauer.criticalmaps.utils.AeSimpleSHA1; -import okhttp3.internal.Util; - -public class OutgoingChatMessage { - - private final Date timestamp; - private final String urlEncodedMessage; - private final String identifier; - private final String message; - - public OutgoingChatMessage(String message) { - this.message = message; - this.urlEncodedMessage = urlEncodeMessage(message); - this.timestamp = new Date(); - this.identifier = AeSimpleSHA1.SHA1(message + Math.random()); - } - - public Date getTimestamp() { - return timestamp; - } - - public String getUrlEncodedMessage() { - return urlEncodedMessage; - } - - public String getMessage() { - return message; - } - - public String getIdentifier() { - return identifier; - } - - private String urlEncodeMessage(String messageToEncode) { - try { - return URLEncoder.encode(messageToEncode, Util.UTF_8.name()); - } catch (UnsupportedEncodingException e) { - return ""; - } - } -} diff --git a/app/src/test/java/de/stephanlindauer/criticalmaps/model/ChatModelTest.java b/app/src/test/java/de/stephanlindauer/criticalmaps/model/ChatModelTest.java index fe3dc4dd..0dbf4b38 100644 --- a/app/src/test/java/de/stephanlindauer/criticalmaps/model/ChatModelTest.java +++ b/app/src/test/java/de/stephanlindauer/criticalmaps/model/ChatModelTest.java @@ -13,7 +13,6 @@ import java.nio.channels.FileChannel; import java.nio.charset.Charset; -import de.stephanlindauer.criticalmaps.model.chat.OutgoingChatMessage; import de.stephanlindauer.criticalmaps.model.chat.ReceivedChatMessage; import static com.google.common.truth.Truth.assertThat;