aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/de/pixart/messenger
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/de/pixart/messenger')
-rw-r--r--src/main/java/de/pixart/messenger/entities/Message.java5
-rw-r--r--src/main/java/de/pixart/messenger/services/AbstractEmojiService.java21
-rw-r--r--src/main/java/de/pixart/messenger/services/EmojiService.java17
-rw-r--r--src/main/java/de/pixart/messenger/services/NotificationService.java2
-rw-r--r--src/main/java/de/pixart/messenger/ui/ConversationActivity.java2
-rw-r--r--src/main/java/de/pixart/messenger/ui/ConversationFragment.java1
-rw-r--r--src/main/java/de/pixart/messenger/ui/ShareWithActivity.java3
-rw-r--r--src/main/java/de/pixart/messenger/ui/ShowLocationActivity.java6
-rw-r--r--src/main/java/de/pixart/messenger/ui/StartUI.java4
-rw-r--r--src/main/java/de/pixart/messenger/ui/XmppActivity.java4
-rw-r--r--src/main/java/de/pixart/messenger/ui/adapter/ConversationAdapter.java5
-rw-r--r--src/main/java/de/pixart/messenger/ui/adapter/MessageAdapter.java17
-rw-r--r--src/main/java/de/pixart/messenger/ui/widget/CopyTextView.java5
-rw-r--r--src/main/java/de/pixart/messenger/ui/widget/EditMessage.java (renamed from src/main/java/de/pixart/messenger/ui/EditMessage.java)6
-rw-r--r--src/main/java/de/pixart/messenger/utils/EmojiWrapper.java43
-rw-r--r--src/main/java/de/pixart/messenger/utils/Emoticons.java282
16 files changed, 393 insertions, 30 deletions
diff --git a/src/main/java/de/pixart/messenger/entities/Message.java b/src/main/java/de/pixart/messenger/entities/Message.java
index 9d1209830..828d810bf 100644
--- a/src/main/java/de/pixart/messenger/entities/Message.java
+++ b/src/main/java/de/pixart/messenger/entities/Message.java
@@ -5,8 +5,6 @@ import android.database.Cursor;
import android.text.SpannableStringBuilder;
import android.util.Log;
-import com.vdurmont.emoji.EmojiManager;
-
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
@@ -20,6 +18,7 @@ import de.pixart.messenger.crypto.axolotl.FingerprintStatus;
import de.pixart.messenger.http.AesGcmURLStreamHandler;
import de.pixart.messenger.ui.adapter.MessageAdapter;
import de.pixart.messenger.utils.CryptoHelper;
+import de.pixart.messenger.utils.Emoticons;
import de.pixart.messenger.utils.GeoHelper;
import de.pixart.messenger.utils.MimeUtils;
import de.pixart.messenger.utils.UIHelper;
@@ -742,7 +741,7 @@ public class Message extends AbstractEntity {
public synchronized boolean bodyIsOnlyEmojis() {
if (isEmojisOnly == null) {
- isEmojisOnly = EmojiManager.isOnlyEmojis(body.replaceAll("\\s", ""));
+ isEmojisOnly = Emoticons.isOnlyEmoji(body.replaceAll("\\s", ""));
}
return isEmojisOnly;
}
diff --git a/src/main/java/de/pixart/messenger/services/AbstractEmojiService.java b/src/main/java/de/pixart/messenger/services/AbstractEmojiService.java
new file mode 100644
index 000000000..75f1a4c98
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/services/AbstractEmojiService.java
@@ -0,0 +1,21 @@
+package de.pixart.messenger.services;
+
+import android.content.Context;
+import android.support.text.emoji.EmojiCompat;
+
+public abstract class AbstractEmojiService {
+
+ protected final Context context;
+
+ public AbstractEmojiService(Context context) {
+ this.context = context;
+ }
+
+ protected abstract EmojiCompat.Config buildConfig();
+
+ public void init() {
+ final EmojiCompat.Config config = buildConfig();
+ config.setReplaceAll(true);
+ EmojiCompat.init(config);
+ }
+} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/services/EmojiService.java b/src/main/java/de/pixart/messenger/services/EmojiService.java
new file mode 100644
index 000000000..6f8d8facd
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/services/EmojiService.java
@@ -0,0 +1,17 @@
+package de.pixart.messenger.services;
+
+import android.content.Context;
+import android.support.text.emoji.EmojiCompat;
+import android.support.text.emoji.bundled.BundledEmojiCompatConfig;
+
+public class EmojiService extends AbstractEmojiService {
+
+ public EmojiService(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected EmojiCompat.Config buildConfig() {
+ return new BundledEmojiCompatConfig(context);
+ }
+} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/services/NotificationService.java b/src/main/java/de/pixart/messenger/services/NotificationService.java
index f7416bca6..9f78fa751 100644
--- a/src/main/java/de/pixart/messenger/services/NotificationService.java
+++ b/src/main/java/de/pixart/messenger/services/NotificationService.java
@@ -510,7 +510,7 @@ public class NotificationService {
for (Message message : messages) {
Pair<String, Boolean> preview = UIHelper.getMessagePreview(mXmppConnectionService, message);
// only show user written text
- if (preview.second == false) {
+ if (!preview.second) {
uBuilder.addMessage(preview.first);
uBuilder.setLatestTimestamp(message.getTimeSent());
}
diff --git a/src/main/java/de/pixart/messenger/ui/ConversationActivity.java b/src/main/java/de/pixart/messenger/ui/ConversationActivity.java
index ad8566693..2a65570de 100644
--- a/src/main/java/de/pixart/messenger/ui/ConversationActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/ConversationActivity.java
@@ -71,6 +71,7 @@ import de.pixart.messenger.entities.MucOptions;
import de.pixart.messenger.entities.Presence;
import de.pixart.messenger.entities.Transferable;
import de.pixart.messenger.persistance.FileBackend;
+import de.pixart.messenger.services.EmojiService;
import de.pixart.messenger.services.UpdateService;
import de.pixart.messenger.services.XmppConnectionService;
import de.pixart.messenger.services.XmppConnectionService.OnAccountUpdate;
@@ -205,6 +206,7 @@ public class ConversationActivity extends XmppActivity
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ new EmojiService(this).init();
if (savedInstanceState != null) {
mOpenConversation = savedInstanceState.getString(STATE_OPEN_CONVERSATION, null);
mPanelOpen = savedInstanceState.getBoolean(STATE_PANEL_OPEN, true);
diff --git a/src/main/java/de/pixart/messenger/ui/ConversationFragment.java b/src/main/java/de/pixart/messenger/ui/ConversationFragment.java
index 8a5863313..560db367a 100644
--- a/src/main/java/de/pixart/messenger/ui/ConversationFragment.java
+++ b/src/main/java/de/pixart/messenger/ui/ConversationFragment.java
@@ -77,6 +77,7 @@ import de.pixart.messenger.ui.XmppActivity.OnValueEdited;
import de.pixart.messenger.ui.adapter.MessageAdapter;
import de.pixart.messenger.ui.adapter.MessageAdapter.OnContactPictureClicked;
import de.pixart.messenger.ui.adapter.MessageAdapter.OnContactPictureLongClicked;
+import de.pixart.messenger.ui.widget.EditMessage;
import de.pixart.messenger.utils.MessageUtils;
import de.pixart.messenger.utils.NickValidityChecker;
import de.pixart.messenger.utils.StylingHelper;
diff --git a/src/main/java/de/pixart/messenger/ui/ShareWithActivity.java b/src/main/java/de/pixart/messenger/ui/ShareWithActivity.java
index af1f0e77e..161a5c366 100644
--- a/src/main/java/de/pixart/messenger/ui/ShareWithActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/ShareWithActivity.java
@@ -26,6 +26,7 @@ import de.pixart.messenger.entities.Account;
import de.pixart.messenger.entities.Conversation;
import de.pixart.messenger.entities.Message;
import de.pixart.messenger.persistance.FileBackend;
+import de.pixart.messenger.services.EmojiService;
import de.pixart.messenger.services.XmppConnectionService;
import de.pixart.messenger.ui.adapter.ConversationAdapter;
import de.pixart.messenger.xmpp.XmppConnection;
@@ -172,7 +173,7 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
+ new EmojiService(this).init();
if (getActionBar() != null) {
getActionBar().setDisplayHomeAsUpEnabled(false);
getActionBar().setHomeButtonEnabled(false);
diff --git a/src/main/java/de/pixart/messenger/ui/ShowLocationActivity.java b/src/main/java/de/pixart/messenger/ui/ShowLocationActivity.java
index 79daee589..f57b53446 100644
--- a/src/main/java/de/pixart/messenger/ui/ShowLocationActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/ShowLocationActivity.java
@@ -26,14 +26,13 @@ import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
-import com.vanniktech.emoji.EmojiManager;
-import com.vanniktech.emoji.ios.IosEmojiProvider;
import java.util.List;
import java.util.Locale;
import de.pixart.messenger.Config;
import de.pixart.messenger.R;
+import de.pixart.messenger.services.EmojiService;
public class ShowLocationActivity extends Activity implements OnMapReadyCallback {
@@ -71,8 +70,7 @@ public class ShowLocationActivity extends Activity implements OnMapReadyCallback
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- EmojiManager.install(new IosEmojiProvider());
-
+ new EmojiService(this).init();
if (getActionBar() != null) {
getActionBar().setHomeButtonEnabled(true);
getActionBar().setDisplayHomeAsUpEnabled(true);
diff --git a/src/main/java/de/pixart/messenger/ui/StartUI.java b/src/main/java/de/pixart/messenger/ui/StartUI.java
index 102484756..08bd844ba 100644
--- a/src/main/java/de/pixart/messenger/ui/StartUI.java
+++ b/src/main/java/de/pixart/messenger/ui/StartUI.java
@@ -13,9 +13,6 @@ import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
-import com.vanniktech.emoji.EmojiManager;
-import com.vanniktech.emoji.ios.IosEmojiProvider;
-
import java.util.List;
import de.pixart.messenger.Config;
@@ -36,7 +33,6 @@ public class StartUI extends AppCompatActivity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start_ui);
- EmojiManager.install(new IosEmojiProvider()); // This line needs to be executed before any usage of EmojiTextView or EmojiEditText.
requestNeededPermissions();
}
diff --git a/src/main/java/de/pixart/messenger/ui/XmppActivity.java b/src/main/java/de/pixart/messenger/ui/XmppActivity.java
index 36c4e20b3..44ef30a85 100644
--- a/src/main/java/de/pixart/messenger/ui/XmppActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/XmppActivity.java
@@ -53,9 +53,6 @@ import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;
-import com.vanniktech.emoji.EmojiManager;
-import com.vanniktech.emoji.ios.IosEmojiProvider;
-
import net.java.otr4j.session.SessionID;
import java.io.FileNotFoundException;
@@ -404,7 +401,6 @@ public abstract class XmppActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- EmojiManager.install(new IosEmojiProvider()); // This line needs to be executed before any usage of EmojiTextView or EmojiEditText.
metrics = getResources().getDisplayMetrics();
ExceptionHelper.init(getApplicationContext());
mPrimaryTextColor = ContextCompat.getColor(this, R.color.black87);
diff --git a/src/main/java/de/pixart/messenger/ui/adapter/ConversationAdapter.java b/src/main/java/de/pixart/messenger/ui/adapter/ConversationAdapter.java
index 02b671e3d..c867dc068 100644
--- a/src/main/java/de/pixart/messenger/ui/adapter/ConversationAdapter.java
+++ b/src/main/java/de/pixart/messenger/ui/adapter/ConversationAdapter.java
@@ -29,6 +29,7 @@ import de.pixart.messenger.entities.MucOptions;
import de.pixart.messenger.entities.Transferable;
import de.pixart.messenger.ui.ConversationActivity;
import de.pixart.messenger.ui.XmppActivity;
+import de.pixart.messenger.utils.EmojiWrapper;
import de.pixart.messenger.utils.UIHelper;
import de.pixart.messenger.xmpp.chatstate.ChatState;
@@ -82,7 +83,7 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
}
ViewHolder viewHolder = ViewHolder.get(view);
if (conversation.getMode() == Conversation.MODE_SINGLE || activity.useSubjectToIdentifyConference()) {
- viewHolder.name.setText(conversation.getName());
+ viewHolder.name.setText(EmojiWrapper.transform(conversation.getName()));
} else {
viewHolder.name.setText(conversation.getJid().toBareJid().toString());
}
@@ -142,7 +143,7 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
final Pair<String, Boolean> preview = UIHelper.getMessagePreview(activity, message);
if (showPreviewText) {
- viewHolder.lastMessage.setText(preview.first);
+ viewHolder.lastMessage.setText(EmojiWrapper.transform(preview.first));
} else {
viewHolder.lastMessageIcon.setContentDescription(preview.first);
}
diff --git a/src/main/java/de/pixart/messenger/ui/adapter/MessageAdapter.java b/src/main/java/de/pixart/messenger/ui/adapter/MessageAdapter.java
index 80d2b8f3a..dabf104bf 100644
--- a/src/main/java/de/pixart/messenger/ui/adapter/MessageAdapter.java
+++ b/src/main/java/de/pixart/messenger/ui/adapter/MessageAdapter.java
@@ -43,7 +43,6 @@ import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
-import com.vdurmont.emoji.EmojiManager;
import java.io.UnsupportedEncodingException;
import java.lang.ref.WeakReference;
@@ -76,6 +75,8 @@ import de.pixart.messenger.ui.widget.ClickableMovementMethod;
import de.pixart.messenger.ui.widget.CopyTextView;
import de.pixart.messenger.ui.widget.ListSelectionManager;
import de.pixart.messenger.utils.CryptoHelper;
+import de.pixart.messenger.utils.EmojiWrapper;
+import de.pixart.messenger.utils.Emoticons;
import de.pixart.messenger.utils.GeoHelper;
import de.pixart.messenger.utils.Patterns;
import de.pixart.messenger.utils.StylingHelper;
@@ -361,9 +362,9 @@ public class MessageAdapter extends ArrayAdapter<Message> implements CopyTextVie
viewHolder.image.setVisibility(View.GONE);
viewHolder.messageBody.setVisibility(View.VISIBLE);
Spannable span = new SpannableString(body);
- float size = EmojiManager.isEmoji(body) ? 3.0f : 2.0f;
+ float size = Emoticons.isEmoji(body) ? 3.0f : 2.0f;
span.setSpan(new RelativeSizeSpan(size), 0, body.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- viewHolder.messageBody.setText(span);
+ viewHolder.messageBody.setText(EmojiWrapper.transform(span));
}
private void displayXmppMessage(final ViewHolder viewHolder, final String body) {
@@ -525,13 +526,19 @@ public class MessageAdapter extends ArrayAdapter<Message> implements CopyTextVie
body.setSpan(new StyleSpan(Typeface.BOLD), matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
+ Matcher matcher = Emoticons.generatePattern(body).matcher(body);
+ while (matcher.find()) {
+ if (matcher.start() < matcher.end()) {
+ body.setSpan(new RelativeSizeSpan(1.5f), matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ }
StylingHelper.format(body, viewHolder.messageBody.getCurrentTextColor());
Linkify.addLinks(body, XMPP_PATTERN, "xmpp");
Linkify.addLinks(body, Patterns.AUTOLINK_WEB_URL, "http", WEBURL_MATCH_FILTER, WEBURL_TRANSFORM_FILTER);
Linkify.addLinks(body, GeoHelper.GEO_URI, "geo");
FixedURLSpan.fix(body);
viewHolder.messageBody.setAutoLinkMask(0);
- viewHolder.messageBody.setText(body);
+ viewHolder.messageBody.setText(EmojiWrapper.transform(body));
viewHolder.messageBody.setTextIsSelectable(true);
viewHolder.messageBody.setMovementMethod(ClickableMovementMethod.getInstance());
listSelectionManager.onUpdate(viewHolder.messageBody, message);
@@ -919,7 +926,7 @@ public class MessageAdapter extends ArrayAdapter<Message> implements CopyTextVie
if (message.isGeoUri()) {
displayLocationMessage(viewHolder, message);
} else if (message.bodyIsOnlyEmojis() && message.getType() != Message.TYPE_PRIVATE) {
- displayEmojiMessage(viewHolder, message.getBody().replaceAll("\\s", ""));
+ displayEmojiMessage(viewHolder, message.getBody().trim());
} else if (message.isXmppUri()) {
displayXmppMessage(viewHolder, message.getBody().trim());
} else if (message.treatAsDownloadable()) {
diff --git a/src/main/java/de/pixart/messenger/ui/widget/CopyTextView.java b/src/main/java/de/pixart/messenger/ui/widget/CopyTextView.java
index ebd268bd0..ce126fa1f 100644
--- a/src/main/java/de/pixart/messenger/ui/widget/CopyTextView.java
+++ b/src/main/java/de/pixart/messenger/ui/widget/CopyTextView.java
@@ -6,10 +6,9 @@ import android.content.ClipboardManager;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
+import android.widget.TextView;
-import com.vanniktech.emoji.EmojiTextView;
-
-public class CopyTextView extends EmojiTextView {
+public class CopyTextView extends TextView {
public CopyTextView(Context context) {
super(context);
diff --git a/src/main/java/de/pixart/messenger/ui/EditMessage.java b/src/main/java/de/pixart/messenger/ui/widget/EditMessage.java
index 46922b98a..3b9b50f1c 100644
--- a/src/main/java/de/pixart/messenger/ui/EditMessage.java
+++ b/src/main/java/de/pixart/messenger/ui/widget/EditMessage.java
@@ -1,10 +1,11 @@
-package de.pixart.messenger.ui;
+package de.pixart.messenger.ui.widget;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.Nullable;
+import android.support.text.emoji.widget.EmojiEditText;
import android.support.v13.view.inputmethod.EditorInfoCompat;
import android.support.v13.view.inputmethod.InputConnectionCompat;
import android.support.v13.view.inputmethod.InputContentInfoCompat;
@@ -15,11 +16,10 @@ import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
-import android.widget.EditText;
import de.pixart.messenger.Config;
-public class EditMessage extends EditText {
+public class EditMessage extends EmojiEditText {
private static final InputFilter SPAN_FILTER = new InputFilter() {
diff --git a/src/main/java/de/pixart/messenger/utils/EmojiWrapper.java b/src/main/java/de/pixart/messenger/utils/EmojiWrapper.java
new file mode 100644
index 000000000..db2bf1242
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/utils/EmojiWrapper.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017, Daniel Gultsch All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package de.pixart.messenger.utils;
+
+import android.support.text.emoji.EmojiCompat;
+
+public class EmojiWrapper {
+
+ public static CharSequence transform(CharSequence input) {
+ final CharSequence charSequence;
+ if (EmojiCompat.get().getLoadState() == EmojiCompat.LOAD_STATE_SUCCEEDED) {
+ return EmojiCompat.get().process(input);
+ } else {
+ return input;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/utils/Emoticons.java b/src/main/java/de/pixart/messenger/utils/Emoticons.java
new file mode 100644
index 000000000..8cfddf8a4
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/utils/Emoticons.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2017, Daniel Gultsch All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package de.pixart.messenger.utils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Pattern;
+
+public class Emoticons {
+
+ private static final UnicodeRange MISC_SYMBOLS_AND_PICTOGRAPHS = new UnicodeRange(0x1F300, 0x1F5FF);
+ private static final UnicodeRange SUPPLEMENTAL_SYMBOLS = new UnicodeRange(0x1F900, 0x1F9FF);
+ private static final UnicodeRange EMOTICONS = new UnicodeRange(0x1F600, 0x1F64F);
+ private static final UnicodeRange TRANSPORT_SYMBOLS = new UnicodeRange(0x1F680, 0x1F6FF);
+ private static final UnicodeRange MISC_SYMBOLS = new UnicodeRange(0x2600, 0x26FF);
+ private static final UnicodeRange DINGBATS = new UnicodeRange(0x2700, 0x27BF);
+ private static final UnicodeRange ENCLOSED_ALPHANUMERIC_SUPPLEMENT = new UnicodeRange(0x1F100, 0x1F1FF);
+ private static final UnicodeRange ENCLOSED_IDEOGRAPHIC_SUPPLEMENT = new UnicodeRange(0x1F200, 0x1F2FF);
+ private static final UnicodeRange REGIONAL_INDICATORS = new UnicodeRange(0x1F1E6, 0x1F1FF);
+ private static final UnicodeRange GEOMETRIC_SHAPES = new UnicodeRange(0x25A0, 0x25FF);
+ private static final UnicodeRange LATIN_SUPPLEMENT = new UnicodeRange(0x80, 0xFF);
+ private static final UnicodeRange MISC_TECHNICAL = new UnicodeRange(0x2300, 0x23FF);
+ private static final UnicodeRange TAGS = new UnicodeRange(0xE0020, 0xE007F);
+ private static final UnicodeList CYK_SYMBOLS_AND_PUNCTUATION = new UnicodeList(0x3030, 0x303D);
+ private static final UnicodeList LETTERLIKE_SYMBOLS = new UnicodeList(0x2122, 0x2139);
+
+ private static final UnicodeBlocks KEYCAP_COMBINEABLE = new UnicodeBlocks(new UnicodeList(0x23), new UnicodeList(0x2A), new UnicodeRange(0x30, 0x39));
+
+ private static final UnicodeBlocks SYMBOLIZE = new UnicodeBlocks(
+ GEOMETRIC_SHAPES,
+ LATIN_SUPPLEMENT,
+ CYK_SYMBOLS_AND_PUNCTUATION,
+ LETTERLIKE_SYMBOLS,
+ KEYCAP_COMBINEABLE);
+ private static final UnicodeBlocks EMOJIS = new UnicodeBlocks(
+ MISC_SYMBOLS_AND_PICTOGRAPHS,
+ SUPPLEMENTAL_SYMBOLS,
+ EMOTICONS,
+ TRANSPORT_SYMBOLS,
+ MISC_SYMBOLS,
+ DINGBATS,
+ ENCLOSED_ALPHANUMERIC_SUPPLEMENT,
+ ENCLOSED_IDEOGRAPHIC_SUPPLEMENT,
+ MISC_TECHNICAL);
+ private static final int ZWJ = 0x200D;
+ private static final int VARIATION_16 = 0xFE0F;
+ private static final int COMBINING_ENCLOSING_KEYCAP = 0x20E3;
+ private static final int BLACK_FLAG = 0x1F3F4;
+ private static final UnicodeRange FITZPATRICK = new UnicodeRange(0x1F3FB, 0x1F3FF);
+
+ private static List<Symbol> parse(String input) {
+ List<Symbol> symbols = new ArrayList<>();
+ Builder builder = new Builder();
+ boolean needsFinalBuild = false;
+ for (int cp, i = 0; i < input.length(); i += Character.charCount(cp)) {
+ cp = input.codePointAt(i);
+ if (builder.offer(cp)) {
+ needsFinalBuild = true;
+ } else {
+ symbols.add(builder.build());
+ builder = new Builder();
+ if (builder.offer(cp)) {
+ needsFinalBuild = true;
+ }
+ }
+ }
+ if (needsFinalBuild) {
+ symbols.add(builder.build());
+ }
+ return symbols;
+ }
+
+ public static Pattern generatePattern(CharSequence input) {
+ final StringBuilder pattern = new StringBuilder();
+ for (Symbol symbol : parse(input.toString())) {
+ if (symbol instanceof Emoji) {
+ if (pattern.length() != 0) {
+ pattern.append('|');
+ }
+ pattern.append(Pattern.quote(symbol.toString()));
+ }
+ }
+ return Pattern.compile(pattern.toString());
+ }
+
+ public static boolean isEmoji(String input) {
+ List<Symbol> symbols = parse(input);
+ return symbols.size() == 1 && symbols.get(0).isEmoji();
+ }
+
+ public static boolean isOnlyEmoji(String input) {
+ List<Symbol> symbols = parse(input);
+ for (Symbol symbol : symbols) {
+ if (!symbol.isEmoji()) {
+ return false;
+ }
+ }
+ return symbols.size() > 0;
+ }
+
+ private static abstract class Symbol {
+
+ private final String value;
+
+ public Symbol(List<Integer> codepoints) {
+ StringBuilder builder = new StringBuilder();
+ for (Integer codepoint : codepoints) {
+ builder.appendCodePoint(codepoint);
+ }
+ this.value = builder.toString();
+ }
+
+ abstract boolean isEmoji();
+
+ @Override
+ public String toString() {
+ return value;
+ }
+ }
+
+ public static class Emoji extends Symbol {
+
+ public Emoji(List<Integer> codepoints) {
+ super(codepoints);
+ }
+
+ @Override
+ boolean isEmoji() {
+ return true;
+ }
+ }
+
+ public static class Other extends Symbol {
+
+ public Other(List<Integer> codepoints) {
+ super(codepoints);
+ }
+
+ @Override
+ boolean isEmoji() {
+ return false;
+ }
+ }
+
+ private static class Builder {
+ private final List<Integer> codepoints = new ArrayList<>();
+
+
+ public boolean offer(int codepoint) {
+ boolean add = false;
+ if (this.codepoints.size() == 0) {
+ if (SYMBOLIZE.contains(codepoint)) {
+ add = true;
+ } else if (REGIONAL_INDICATORS.contains(codepoint)) {
+ add = true;
+ } else if (EMOJIS.contains(codepoint) && !FITZPATRICK.contains(codepoint) && codepoint != ZWJ) {
+ add = true;
+ }
+ } else {
+ int previous = codepoints.get(codepoints.size() - 1);
+ if (codepoints.get(0) == BLACK_FLAG) {
+ add = TAGS.contains(codepoint);
+ } else if (COMBINING_ENCLOSING_KEYCAP == codepoint) {
+ add = KEYCAP_COMBINEABLE.contains(previous) || previous == VARIATION_16;
+ } else if (SYMBOLIZE.contains(previous)) {
+ add = codepoint == VARIATION_16;
+ } else if (REGIONAL_INDICATORS.contains(previous) && REGIONAL_INDICATORS.contains(codepoint)) {
+ add = codepoints.size() == 1;
+ } else if (previous == VARIATION_16) {
+ add = isMerger(codepoint);
+ } else if (FITZPATRICK.contains(previous)) {
+ add = codepoint == ZWJ;
+ } else if (ZWJ == previous) {
+ add = EMOJIS.contains(codepoint);
+ } else if (isMerger(codepoint)) {
+ add = true;
+ } else if (codepoint == VARIATION_16 && EMOJIS.contains(previous)) {
+ add = true;
+ }
+ }
+ if (add) {
+ codepoints.add(codepoint);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ static boolean isMerger(int codepoint) {
+ return codepoint == ZWJ || FITZPATRICK.contains(codepoint);
+ }
+
+ public Symbol build() {
+ if (codepoints.size() > 0 && SYMBOLIZE.contains(codepoints.get(codepoints.size() - 1))) {
+ return new Other(codepoints);
+ } else if (codepoints.size() > 1 && KEYCAP_COMBINEABLE.contains(codepoints.get(0)) && codepoints.get(codepoints.size() - 1) != COMBINING_ENCLOSING_KEYCAP) {
+ return new Other(codepoints);
+ }
+ return codepoints.size() == 0 ? new Other(codepoints) : new Emoji(codepoints);
+ }
+ }
+
+ public static class UnicodeBlocks implements UnicodeSet {
+ final UnicodeSet[] unicodeSets;
+
+ public UnicodeBlocks(UnicodeSet... sets) {
+ this.unicodeSets = sets;
+ }
+
+ @Override
+ public boolean contains(int codepoint) {
+ for(UnicodeSet unicodeSet : unicodeSets) {
+ if (unicodeSet.contains(codepoint)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ public interface UnicodeSet {
+ boolean contains(int codepoint);
+ }
+
+ public static class UnicodeList implements UnicodeSet {
+
+ private final List<Integer> list;
+
+ public UnicodeList(Integer... codes) {
+ this.list = Arrays.asList(codes);
+ }
+
+ @Override
+ public boolean contains(int codepoint) {
+ return this.list.contains(codepoint);
+ }
+ }
+
+
+ public static class UnicodeRange implements UnicodeSet {
+
+ private final int lower;
+ private final int upper;
+
+ UnicodeRange(int lower, int upper) {
+ this.lower = lower;
+ this.upper = upper;
+ }
+
+ public boolean contains(int codePoint) {
+ return codePoint >= lower && codePoint <= upper;
+ }
+ }
+} \ No newline at end of file