Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

修正了几个问题 #11

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Map;
import java.util.regex.Pattern;

import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
Expand All @@ -32,6 +34,7 @@ static class Conversation {
@IntDef({ TYPE_UNKNOWN, TYPE_DIRECT_MESSAGE, TYPE_GROUP_CHAT, TYPE_BOT_MESSAGE }) @Retention(RetentionPolicy.SOURCE) @interface ConversationType {}

private static final String SCHEME_ORIGINAL_NAME = "ON:";
private static final Pattern pattern = Pattern.compile("^[a-zA-Z0-9\\u4e00-\\u9fa5]");

final int id;
@Nullable String key;
Expand Down Expand Up @@ -71,7 +74,16 @@ Person getGroupParticipant(final String key, final String name) {
if (participant == null) builder = new Person.Builder().setKey(key);
else if (! TextUtils.equals(name, requireNonNull(participant.getUri()).substring(SCHEME_ORIGINAL_NAME.length()))) // Original name is changed
builder = participant.toBuilder();
if (builder != null) mParticipants.put(key, participant = builder.setUri(SCHEME_ORIGINAL_NAME + name).setName(EmojiTranslator.translate(name)).build());
if (builder != null) {
final CharSequence n = EmojiTranslator.translate(name);
builder.setUri(SCHEME_ORIGINAL_NAME + name);
if (pattern.matcher(n).find()) {
builder.setName(n);
} else {
builder.setName("\u200b" + n);
}
mParticipants.put(key, participant = builder.build());
}
return participant;
}

Expand All @@ -94,4 +106,5 @@ Conversation getConversation(final int id) {
}

private final SparseArray<Conversation> mConversations = new SparseArray<>();
private static final String TAG = WeChatDecorator.TAG;
}
28 changes: 24 additions & 4 deletions src/main/java/com/oasisfeng/nevo/decorators/wechat/EmojiMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,51 @@ public class EmojiMap {
// Pull Request is welcome. (columns are split by "tab" for visual alignment)
// Proper emoji is needed for commented lines.
static final String[][] MAP = new String[][] {
{ "表情", null, "㊙️" },
{ "链接", null, "🔗" },
{ "花", null, "🌺" },
{ "钱", null, "💰" },
{ "闪烁", null, "✨" },
{ "X", "X", "❌" },
{ "OK", "OK", "👌" },
{ "耶", "Yeah!", "✌" },
{ "嘘", "Silent", "🤫" },
{ "晕", "Dizzy", "😲" },
{ "衰", "BadLuck", "😳" },
{ "脸红", null, "😳" },
{ "色", "Drool", "😍" },
{ "囧", "Tension", "☺" },
{ "鸡", "Chick", "🐥" },
{ "热情", null, "☺" },
{ "鸡", "Chick", "🐥" }, // missing
{ "强", "Thumbs Up", "👍" },
{ "弱", "Weak", "👎" },
{ "睡", "Sleep", "😴" },
{ "睡", "Sleep", "😴" }, // missing
{ "吐", "Puke", "🤢" },
{ "困", "Drowsy", "😪" },
{ "睡觉", null, "😪" },
{ "發", "Rich", "🀅" },
{ "微笑", "Smile", "😃" },
{ "大笑", null, "😃" }, // iOS 7.0.4
{ "开心", null, "😃" }, // Android 7.0.4
{ "撇嘴", "Grimace", "😖" },
{ "呸", null, "😖" },
{ "发呆", "Scowl", "😳" },
{ "得意", "CoolGuy", "😎" },
{ "脸红", null, "😳" },
{ "得意", "CoolGuy", "😎" }, // missing
{ "流泪", "Sob", "😭" },
{ "哭", null, "😭" },
{ "害羞", "Shy", "☺" },
{ "闭嘴", "Shutup", "🤐" },
{ "闭嘴", "Shutup", "🤐" }, // missing
{ "大哭", "Cry", "😣" },
{ "悔恨", null, "😣" },
{ "尴尬", "Awkward", "😰" },
{ "担心", null, "😰" },
{ "发怒", "Angry", "😡" },
{ "生气", null, "😡" },
{ "调皮", "Tongue", "😜" },
{ "戏弄", null, "😜" },
{ "呲牙", "Grin", "😁" },
{ "露齿笑", null, "😁" },
{ "惊讶", "Surprise", "😱" },
{ "难过", "Frown", "🙁" },
{ "抓狂", "Scream", "😫" },
Expand Down Expand Up @@ -99,6 +118,7 @@ public class EmojiMap {
// { "机智", "Smart", "" },
// { "抠鼻", "DigNose", "" },
// { "可怜", "Whimper", "" },
{ "皇冠", null, "👑" },
{ "快哭了", "Puling", "😔" },
// { "左哼哼", "Bah!L", "" },
// { "右哼哼", "Bah!R", "" },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ public class EmojiTranslator {
private static final Map<String, String> ENGLISH_MAP = new HashMap<>(EmojiMap.MAP.length);
static {
for (final String[] entry : EmojiMap.MAP) {
CHINESE_MAP.put(entry[0], entry[2]);
ENGLISH_MAP.put(entry[1], entry[2]);
if (entry[0] != null)
CHINESE_MAP.put(entry[0], entry[2]);
if (entry[1] != null)
ENGLISH_MAP.put(entry[1], entry[2]);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
import androidx.core.app.NotificationCompat.MessagingStyle;
import androidx.core.app.NotificationCompat.MessagingStyle.Message;
import androidx.core.app.Person;
import androidx.core.graphics.drawable.IconCompat;

import static android.app.Notification.EXTRA_REMOTE_INPUT_HISTORY;
import static android.app.Notification.EXTRA_TEXT;
Expand Down Expand Up @@ -87,14 +86,16 @@ class MessagingBuilder {
return null;
}

final LongSparseArray<CharSequence> lines = new LongSparseArray<>(MAX_NUM_HISTORICAL_LINES);
final LongSparseArray<CharSequence> tickerArray = new LongSparseArray<>(MAX_NUM_HISTORICAL_LINES);
final LongSparseArray<CharSequence> textArray = new LongSparseArray<>(MAX_NUM_HISTORICAL_LINES);
CharSequence text;
int count = 0, num_lines_with_colon = 0;
final String redundant_prefix = title.toString() + SENDER_MESSAGE_SEPARATOR;
for (final StatusBarNotification each : archive) {
final Notification notification = each.getNotification();
tickerArray.put(notification.when, notification.tickerText);
final Bundle its_extras = notification.extras;
final CharSequence its_title = its_extras.getCharSequence(Notification.EXTRA_TITLE);
final CharSequence its_title = EmojiTranslator.translate(its_extras.getCharSequence(Notification.EXTRA_TITLE));
if (! title.equals(its_title)) {
Log.d(TAG, "Skip other conversation with the same key in archive: " + its_title); // ID reset by WeChat due to notification removal in previous evolving
continue;
Expand All @@ -111,27 +112,28 @@ class MessagingBuilder {
if (trimmed_text.toString().startsWith(redundant_prefix)) // Remove redundant prefix
trimmed_text = trimmed_text.subSequence(redundant_prefix.length(), trimmed_text.length());
else if (trimmed_text.toString().indexOf(SENDER_MESSAGE_SEPARATOR) > 0) num_lines_with_colon ++;
lines.put(notification.when, trimmed_text);
textArray.put(notification.when, trimmed_text);
} else {
count = 1;
lines.put(notification.when, text = its_text);
textArray.put(notification.when, text = its_text);
if (text.toString().indexOf(SENDER_MESSAGE_SEPARATOR) > 0) num_lines_with_colon ++;
}
}
n.number = count;
if (lines.size() == 0) {
if (textArray.size() == 0) {
Log.w(TAG, "No lines extracted, expected " + count);
return null;
}

final MessagingStyle messaging = new MessagingStyle(mUserSelf);
final boolean sender_inline = num_lines_with_colon == lines.size();
for (int i = 0, size = lines.size(); i < size; i++) // All lines have colon in text
messaging.addMessage(buildMessage(conversation, lines.keyAt(i), n.tickerText, lines.valueAt(i), sender_inline ? null : title.toString()));
final boolean sender_inline = num_lines_with_colon == textArray.size();
for (int i = 0, size = textArray.size(); i < size; i++) { // All lines have colon in text
messaging.addMessage(buildMessage(conversation, textArray.keyAt(i), tickerArray.valueAt(i), textArray.valueAt(i), sender_inline ? null : title.toString()));
}
return messaging;
}

@Nullable MessagingStyle buildFromExtender(final Conversation conversation, final MutableStatusBarNotification sbn) {
@Nullable MessagingStyle buildFromExtender(final Conversation conversation, final MutableStatusBarNotification sbn, final CharSequence title, final List<StatusBarNotification> archive) {
final MutableNotification n = sbn.getNotification();
final Notification.CarExtender extender = new Notification.CarExtender(n);
final CarExtender.UnreadConversation convs = extender.getUnreadConversation();
Expand All @@ -157,7 +159,7 @@ class MessagingBuilder {
}

final MessagingStyle messaging = new MessagingStyle(mUserSelf);
final Message[] messages = WeChatMessage.buildFromCarConversation(conversation, convs);
final Message[] messages = WeChatMessage.buildFromCarConversation(conversation, convs, archive);
for (final Message message : messages) messaging.addMessage(message);

final PendingIntent on_read = convs.getReadPendingIntent();
Expand Down Expand Up @@ -356,8 +358,7 @@ interface Controller { void recastNotification(String key, Bundle addition); }
}

private static Person buildPersonFromProfile(final Context context) {
return new Person.Builder().setName(context.getString(R.string.self_display_name))
.setIcon(IconCompat.createWithContentUri(Uri.withAppendedPath(Profile.CONTENT_URI, Contacts.Photo.DISPLAY_PHOTO))).build();
return new Person.Builder().setName(context.getString(R.string.self_display_name)).build();
}

void close() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ public class WeChatDecorator extends NevoDecoratorService {
else if (channel_id == null) n.setChannelId(CHANNEL_MESSAGE); // WeChat versions targeting O+ have its own channel for message
}

MessagingStyle messaging = mMessagingBuilder.buildFromExtender(conversation, evolving);
MessagingStyle messaging = mMessagingBuilder.buildFromExtender(conversation, evolving, title, getArchivedNotifications(evolving.getOriginalKey(), MAX_NUM_ARCHIVED)); // build message from android auto
if (messaging == null) // EXTRA_TEXT will be written in buildFromArchive()
messaging = mMessagingBuilder.buildFromArchive(conversation, n, title, getArchivedNotifications(evolving.getOriginalKey(), MAX_NUM_ARCHIVED));
if (messaging == null) return;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.oasisfeng.nevo.decorators.wechat;

import android.app.Notification;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.Log;

import com.oasisfeng.nevo.decorators.wechat.ConversationManager.Conversation;

import java.util.List;

import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat.MessagingStyle.Message;
import androidx.core.app.Person;
Expand All @@ -31,17 +34,22 @@ class WeChatMessage {
static final String SENDER_MESSAGE_SEPARATOR = ": ";
private static final String SELF = "";

static Message[] buildFromCarConversation(final Conversation conversation, final Notification.CarExtender.UnreadConversation convs) {
static Message[] buildFromCarConversation(final Conversation conversation, final Notification.CarExtender.UnreadConversation convs, final List<StatusBarNotification> archive) {
final String[] car_messages = convs.getMessages();
if (car_messages.length == 0) return new Message[] { buildFromBasicFields(conversation).toMessage() }; // No messages in car conversation

final WeChatMessage basic_msg = buildFromBasicFields(conversation);
final Message[] messages = new Message[car_messages.length];
final CharSequence[] tickerArray = new CharSequence[car_messages.length];
for (int i = archive.size() - 1, diff = archive.size() - car_messages.length; i >= 0 && i >= diff; i--) {
tickerArray[i - diff] = archive.get(i).getNotification().tickerText;
}
int end_of_peers = -1;
if (! conversation.isGroupChat()) for (end_of_peers = car_messages.length - 1; end_of_peers >= -1; end_of_peers --)
if (end_of_peers >= 0 && TextUtils.equals(basic_msg.text, car_messages[end_of_peers])) break; // Find the actual end line which matches basic fields, in case extra lines are sent by self
for (int i = 0, count = car_messages.length; i < count; i ++)
messages[i] = buildFromCarMessage(conversation, car_messages[i], end_of_peers >= 0 && i > end_of_peers).toMessage();
for (int i = 0, count = car_messages.length; i < count; i ++) {
messages[i] = buildFromCarMessage(conversation, car_messages[i], tickerArray[i], end_of_peers >= 0 && i > end_of_peers).toMessage();
}
return messages;
}

Expand Down Expand Up @@ -130,9 +138,11 @@ private static boolean startsWith(final CharSequence text, final CharSequence ne
&& TextUtils.regionMatches(text, needle1_length, needle2, 0, needle2_length);
}

private static WeChatMessage buildFromCarMessage(final Conversation conversation, final String message, final boolean from_self) {
private static WeChatMessage buildFromCarMessage(final Conversation conversation, final String message, final @Nullable CharSequence ticker, final boolean from_self) {
String text = message, sender = null;
final int pos = from_self ? 0 : TextUtils.indexOf(message, SENDER_MESSAGE_SEPARATOR);
int pos;
// parse text
pos = from_self ? 0 : TextUtils.indexOf(message, SENDER_MESSAGE_SEPARATOR);
if (pos > 0) {
sender = message.substring(0, pos);
final boolean title_as_sender = TextUtils.equals(sender, conversation.getTitle());
Expand All @@ -141,6 +151,15 @@ private static WeChatMessage buildFromCarMessage(final Conversation conversation
if (conversation.isGroupChat() && title_as_sender) sender = SELF; // WeChat incorrectly use group chat title as sender for self-sent messages.
} else sender = null; // Not really the sender name, revert the parsing result.
}
// parse sender (from ticker)
pos = from_self ? 0 : TextUtils.indexOf(ticker, SENDER_MESSAGE_SEPARATOR);
if (pos > 0) {
sender = ticker.toString().substring(0, pos);
final boolean title_as_sender = TextUtils.equals(sender, conversation.getTitle());
if (conversation.isGroupChat() || title_as_sender) { // Verify the sender with title for non-group conversation
if (conversation.isGroupChat() && title_as_sender) sender = SELF; // WeChat incorrectly use group chat title as sender for self-sent messages.
} else sender = null; // Not really the sender name, revert the parsing result.
}
return new WeChatMessage(conversation, from_self ? SELF : sender, EmojiTranslator.translate(text), 0);
}

Expand Down