message) {
- int index = adapter.add(message);
- recyclerView.smoothScrollToPosition(index);
- onAdapterCountMightHaveChanged();
- }
-
- private void onAdapterCountMightHaveChanged() {
- int count = adapter != null ? adapter.getItemCount() : 0;
- emptyView.setVisibility(count > 0 ? View.INVISIBLE : View.VISIBLE);
- supportInvalidateOptionsMenu();
- }
-}
diff --git a/app/src/main/java/fr/smarquis/fcm/Message.java b/app/src/main/java/fr/smarquis/fcm/Message.java
deleted file mode 100644
index c0b515d..0000000
--- a/app/src/main/java/fr/smarquis/fcm/Message.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package fr.smarquis.fcm;
-
-import androidx.annotation.NonNull;
-
-import com.google.firebase.messaging.RemoteMessage;
-import com.squareup.moshi.Json;
-
-import java.util.Map;
-
-import fr.smarquis.fcm.payloads.Payload;
-import fr.smarquis.fcm.payloads.Payloads;
-
-public class Message implements Comparable> {
-
- @Json(name = "from")
- private final String from;
- @Json(name = "to")
- private final String to;
- @Json(name = "data")
- private final Map data;
- @Json(name = "collapseKey")
- private final String collapseKey;
- @Json(name = "messageId")
- private final String messageId;
- @Json(name = "messageType")
- private final String messageType;
- @Json(name = "sentTime")
- private final long sentTime;
- @Json(name = "ttl")
- private final int ttl;
- @Json(name = "priority")
- private final int priority;
- @Json(name = "originalPriority")
- private final int originalPriority;
-
- @Json(name = "payload")
- private final Payload payload;
-
- private Message(String from, String to, Map data, String collapseKey, String messageId, String messageType, long sentTime, int ttl, int priority, int originalPriority, P payload) {
- this.from = from;
- this.to = to;
- this.data = data;
- this.collapseKey = collapseKey;
- this.messageId = messageId;
- this.messageType = messageType;
- this.sentTime = sentTime;
- this.ttl = ttl;
- this.priority = priority;
- this.originalPriority = originalPriority;
- this.payload = payload;
- }
-
- @NonNull
- static Message from(@NonNull RemoteMessage message) {
- return new Message<>(
- message.getFrom(),
- message.getTo(),
- message.getData(),
- message.getCollapseKey(),
- message.getMessageId(),
- message.getMessageType(),
- message.getSentTime(),
- message.getTtl(),
- message.getOriginalPriority(),
- message.getPriority(),
- Payloads.extract(message));
- }
-
- public String id() {
- return messageId;
- }
-
- public Map data() {
- return data;
- }
-
- @NonNull
- public Payload payload() {
- return payload;
- }
-
- public long sentTime() {
- return sentTime;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- Message> message = (Message>) o;
-
- return messageId != null ? messageId.equals(message.messageId) : message.messageId == null;
- }
-
- @Override
- public int hashCode() {
- return messageId != null ? messageId.hashCode() : 0;
- }
-
- @Override
- public int compareTo(@NonNull Message other) {
- return (other.sentTime() < sentTime()) ? -1 : ((other.sentTime() == sentTime()) ? id().compareTo(other.id()) : 1);
- }
-}
diff --git a/app/src/main/java/fr/smarquis/fcm/MessageAdapter.java b/app/src/main/java/fr/smarquis/fcm/MessageAdapter.java
deleted file mode 100644
index 9f16d92..0000000
--- a/app/src/main/java/fr/smarquis/fcm/MessageAdapter.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright 2017 Simon Marquis
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package fr.smarquis.fcm;
-
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.recyclerview.widget.RecyclerView;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import fr.smarquis.fcm.payloads.Payload;
-import fr.smarquis.fcm.payloads.ViewHolder;
-
-class MessageAdapter extends RecyclerView.Adapter {
-
- private static final Map stableIds = new HashMap<>();
-
- private static final Map selection = new HashMap<>();
-
- @NonNull
- private final List> messages = new ArrayList<>();
-
- MessageAdapter(@NonNull List> messages) {
- this.messages.addAll(messages);
- }
-
- @NonNull
- @Override
- public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
- View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_payload, parent, false);
- return new ViewHolder(view, this::onClick);
- }
-
- private void onClick(@Nullable Message message) {
- if (message == null) {
- return;
- }
- Boolean value = selection.get(message);
- selection.put(message, value != null ? Boolean.valueOf(!value) : Boolean.TRUE);
- notifyItemChanged(messages.indexOf(message));
- }
-
- @Override
- public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) {
- Message message = messages.get(position);
- Boolean selected = selection.get(message);
- viewHolder.onBind(message, selected != null ? selected : Boolean.FALSE);
- }
-
- @Override
- public void onViewRecycled(@NonNull ViewHolder holder) {
- holder.onUnbind();
- }
-
- @Override
- public int getItemCount() {
- return messages.size();
- }
-
- @Override
- public long getItemId(int position) {
- String key = messages.get(position).id();
- Long value = stableIds.get(key);
- if (value == null) {
- value = (long) stableIds.size();
- stableIds.put(key, value);
- }
- return value;
- }
-
- Message removeItemAtPosition(int position) {
- Message message = messages.remove(position);
- notifyItemRemoved(position);
- return message;
- }
-
- void clear() {
- messages.clear();
- notifyDataSetChanged();
- }
-
- int add(@NonNull Message message) {
- messages.add(0, message);
- Collections.sort(messages);
- int indexOf = messages.indexOf(message);
- notifyItemInserted(indexOf);
- return indexOf;
- }
-
-}
diff --git a/app/src/main/java/fr/smarquis/fcm/Messages.java b/app/src/main/java/fr/smarquis/fcm/Messages.java
deleted file mode 100644
index 3c4f26c..0000000
--- a/app/src/main/java/fr/smarquis/fcm/Messages.java
+++ /dev/null
@@ -1,146 +0,0 @@
-package fr.smarquis.fcm;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.text.TextUtils;
-
-import androidx.annotation.NonNull;
-
-import com.squareup.moshi.JsonAdapter;
-import com.squareup.moshi.Moshi;
-import com.squareup.moshi.Types;
-
-import java.io.IOException;
-import java.lang.reflect.Type;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import fr.smarquis.fcm.payloads.Payload;
-import fr.smarquis.fcm.payloads.Payloads;
-
-public final class Messages {
-
- private static final String SHARED_PREFERENCES_NAME = "messages";
-
- private static final String KEY = "data";
-
- private static final Moshi MOSHI = new Moshi.Builder().add(Payloads.JSON_ADAPTER).build();
-
- @SuppressLint("StaticFieldLeak")
- private static volatile Messages instance = null;
-
- private final SharedPreferences sp;
-
- @NonNull
- private final List> messages = new ArrayList<>();
-
- private static final Type TYPE = Types.newParameterizedType(List.class, Message.class);
-
- private static final JsonAdapter>> ADAPTER = MOSHI.adapter(TYPE);
-
- private final List listeners = Collections.synchronizedList(new ArrayList<>());
-
- interface Listener {
- void onNewMessage(@NonNull Message message);
- }
-
- public static Moshi moshi() {
- return MOSHI;
- }
-
- @NonNull
- static Messages instance(@NonNull Context context) {
- if (instance == null) {
- synchronized (Messages.class) {
- if (instance == null) {
- instance = new Messages(context);
- }
- }
- }
- return instance;
- }
-
- private Messages(@NonNull Context context) {
- sp = context.getApplicationContext().getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
- String value = sp.getString(KEY, null);
- if (!TextUtils.isEmpty(value)) {
- try {
- List> list = ADAPTER.fromJson(value);
- if (list != null) {
- messages.addAll(list);
- Collections.sort(messages);
- }
- } catch (IOException e) {
- e.printStackTrace();
- sp.edit().remove(KEY).apply();
- }
- }
- }
-
- void register(@NonNull Listener listener) {
- synchronized (listeners) {
- listeners.add(listener);
- }
- }
-
- void unregister(@NonNull Listener listener) {
- synchronized (listeners) {
- listeners.remove(listener);
- }
- }
-
- @NonNull
- List> get() {
- return new ArrayList<>(messages);
- }
-
- void add(@NonNull Message message) {
- if (messages.contains(message)) {
- return;
- }
- messages.add(message);
- Collections.sort(messages);
- persist();
- notifyListeners(message);
- }
-
- void add(@NonNull List> messages) {
- this.messages.addAll(messages);
- Collections.sort(this.messages);
- persist();
- for (int i = messages.size() - 1; i >= 0; i--) {
- notifyListeners(messages.get(i));
- }
- }
-
- private void notifyListeners(@NonNull Message message) {
- synchronized (listeners) {
- for (Listener listener : listeners) {
- listener.onNewMessage(message);
- }
- }
- }
-
- void remove(@NonNull Message message) {
- if (!messages.contains(message)) {
- return;
- }
- messages.remove(message);
- persist();
- }
-
- void clear() {
- if (messages.isEmpty()) {
- return;
- }
- messages.clear();
- persist();
- }
-
- private void persist() {
- sp.edit().putString(KEY, ADAPTER.toJson(messages)).apply();
- }
-
-}
diff --git a/app/src/main/java/fr/smarquis/fcm/Notifications.java b/app/src/main/java/fr/smarquis/fcm/Notifications.java
deleted file mode 100644
index 700e509..0000000
--- a/app/src/main/java/fr/smarquis/fcm/Notifications.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package fr.smarquis.fcm;
-
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Build;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
-import androidx.core.app.NotificationCompat;
-import androidx.core.content.ContextCompat;
-
-import fr.smarquis.fcm.payloads.Payload;
-
-final class Notifications {
-
- private Notifications() {
- }
-
- private static NotificationManager getNotificationManager(Context context) {
- return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- }
-
- @RequiresApi(api = Build.VERSION_CODES.O)
- private static void createNotificationChannel(Context context) {
- String id = context.getString(R.string.notification_channel_id);
- CharSequence name = context.getString(R.string.notification_channel_name);
- int importance = NotificationManager.IMPORTANCE_HIGH;
- NotificationChannel channel = new NotificationChannel(id, name, importance);
- channel.enableLights(true);
- channel.enableVibration(true);
- channel.setShowBadge(true);
- getNotificationManager(context).createNotificationChannel(channel);
- }
-
- @NonNull
- private static NotificationCompat.Builder getNotificationBuilder(@NonNull Context context) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- createNotificationChannel(context);
- }
- return new NotificationCompat.Builder(context, context.getString(R.string.notification_channel_id))
- .setColor(ContextCompat.getColor(context, R.color.colorPrimary))
- .setContentIntent(PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class), 0))
- .setLocalOnly(true)
- .setAutoCancel(true)
- .setDefaults(NotificationCompat.DEFAULT_ALL)
- .setPriority(NotificationCompat.PRIORITY_MAX)
- .setCategory(NotificationCompat.CATEGORY_MESSAGE);
- }
-
- static void show(@NonNull Context context, @NonNull Message message) {
- Payload payload = message.payload();
- Notification notification = payload.configure(Notifications.getNotificationBuilder(context).setSmallIcon(payload.icon())).build();
- getNotificationManager(context).notify(message.id(), payload.notificationId(), notification);
- }
-
- static void removeAll(Context context) {
- getNotificationManager(context).cancelAll();
- }
-
-}
diff --git a/app/src/main/java/fr/smarquis/fcm/Presence.java b/app/src/main/java/fr/smarquis/fcm/Presence.java
deleted file mode 100644
index 114f687..0000000
--- a/app/src/main/java/fr/smarquis/fcm/Presence.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package fr.smarquis.fcm;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-
-import androidx.annotation.Keep;
-import androidx.annotation.NonNull;
-import androidx.localbroadcastmanager.content.LocalBroadcastManager;
-
-@Keep
-final class Presence {
-
- private static final String INTENT_ACTION = Presence.class.getName() + ".Update";
-
- private static final IntentFilter INTENT_FILTER = new IntentFilter(INTENT_ACTION);
-
- private static final Intent INTENT = new Intent(INTENT_ACTION);
-
- private static final String EXTRA_KEY = "presence";
-
-
- interface Handler {
- void handle(boolean presence);
- }
-
- private static LocalBroadcastManager manager(@NonNull Context context) {
- return LocalBroadcastManager.getInstance(context);
- }
-
- static void broadcast(@NonNull Context context, boolean presence) {
- Intent intent = new Intent(INTENT);
- intent.putExtra(EXTRA_KEY, presence);
- manager(context).sendBroadcast(new Intent(INTENT));
- }
-
- @NonNull
- static BroadcastReceiver create(Handler handler) {
- return new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- handler.handle(intent.getBooleanExtra(EXTRA_KEY, false));
- }
- };
- }
-
- static void register(@NonNull Context context, @NonNull BroadcastReceiver receiver) {
- manager(context).registerReceiver(receiver, INTENT_FILTER);
- }
-
- static void unregister(@NonNull Context context, @NonNull BroadcastReceiver receiver) {
- manager(context).unregisterReceiver(receiver);
- }
-
-}
diff --git a/app/src/main/java/fr/smarquis/fcm/PresenceEventListener.java b/app/src/main/java/fr/smarquis/fcm/PresenceEventListener.java
deleted file mode 100644
index 3d175c3..0000000
--- a/app/src/main/java/fr/smarquis/fcm/PresenceEventListener.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright 2017 Simon Marquis
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package fr.smarquis.fcm;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-
-import androidx.annotation.NonNull;
-
-import com.google.android.gms.tasks.Task;
-import com.google.firebase.database.DataSnapshot;
-import com.google.firebase.database.DatabaseError;
-import com.google.firebase.database.DatabaseReference;
-import com.google.firebase.database.FirebaseDatabase;
-import com.google.firebase.database.ServerValue;
-import com.google.firebase.database.ValueEventListener;
-import com.google.firebase.iid.FirebaseInstanceId;
-import com.google.firebase.iid.InstanceIdResult;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Locale;
-import java.util.Set;
-
-import static android.os.Build.MANUFACTURER;
-import static android.os.Build.MODEL;
-
-class PresenceEventListener implements ValueEventListener {
-
- @SuppressLint("StaticFieldLeak")
- private static volatile PresenceEventListener instance;
-
- private final Context context;
-
- private final DatabaseReference presenceRef;
-
- private final DatabaseReference connectionRef;
-
- private boolean isConnected = false;
-
- @NonNull
- static PresenceEventListener instance(@NonNull Context context) {
- if (instance == null) {
- synchronized (Messages.class) {
- if (instance == null) {
- instance = new PresenceEventListener(context);
- }
- }
- }
- return instance;
- }
-
- private PresenceEventListener(Context context) {
- this.context = context.getApplicationContext();
- String uuid = Uuid.get(context);
- FirebaseDatabase database = FirebaseDatabase.getInstance();
- presenceRef = database.getReference(".info/connected");
- connectionRef = database.getReference("devices/" + uuid);
- connectionRef.onDisconnect().removeValue();
- }
-
- boolean isConnected() {
- return isConnected;
- }
-
- @Override
- public void onCancelled(@NonNull DatabaseError error) {
- if (isConnected) {
- isConnected = false;
- Presence.broadcast(context, false);
- }
- }
-
- @Override
- public void onDataChange(@NonNull DataSnapshot snapshot) {
- boolean connected = Boolean.TRUE.equals(snapshot.getValue(Boolean.class));
- if (connected == isConnected) {
- return;
- }
- isConnected = connected;
- Presence.broadcast(context, isConnected);
- if (connected) {
- Task instanceId = FirebaseInstanceId.getInstance().getInstanceId();
- instanceId.addOnSuccessListener(instanceIdResult -> setConnectionReference(instanceIdResult.getToken()));
- }
- }
-
- private void setConnectionReference(String token) {
- HashMap result = new HashMap<>(3);
- Locale locale = Locale.getDefault();
- final String displayName = MODEL.toLowerCase(locale).startsWith(MANUFACTURER.toLowerCase(locale)) ? MODEL : MANUFACTURER.toUpperCase(locale) + " " + MODEL;
- result.put("name", displayName);
- result.put("token", token);
- result.put("timestamp", ServerValue.TIMESTAMP);
- connectionRef.setValue(result);
- }
-
- @NonNull
- private final Set