Skip to content

Commit 783fe87

Browse files
committed
FIX: Shortcut is not working as expected on Android R.
Also rename the fields "id" to "nid" and "key" to "id" with comments to better reflect their actual roles.
1 parent ce16f1c commit 783fe87

File tree

4 files changed

+29
-30
lines changed

4 files changed

+29
-30
lines changed

src/main/java/com/oasisfeng/nevo/decorators/wechat/AgentShortcuts.kt

+3-5
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import android.content.pm.PackageManager
77
import android.content.pm.PackageManager.GET_ACTIVITIES
88
import android.content.pm.ShortcutInfo
99
import android.content.pm.ShortcutManager
10-
import android.graphics.drawable.Icon
1110
import android.graphics.drawable.Icon.TYPE_RESOURCE
1211
import android.os.Build.VERSION.SDK_INT
1312
import android.os.Build.VERSION_CODES.N
@@ -21,7 +20,6 @@ import android.util.Log
2120
import android.util.LruCache
2221
import androidx.annotation.RequiresApi
2322
import androidx.core.content.getSystemService
24-
import androidx.core.graphics.drawable.IconCompat
2523
import com.oasisfeng.nevo.decorators.wechat.ConversationManager.Conversation
2624
import com.oasisfeng.nevo.decorators.wechat.WeChatDecorator.AGENT_PACKAGE
2725
import com.oasisfeng.nevo.decorators.wechat.WeChatDecorator.TAG
@@ -50,8 +48,8 @@ import java.lang.reflect.Method
5048
if (count >= sm.maxShortcutCountPerActivity - sm.manifestShortcuts.size)
5149
sm.removeDynamicShortcuts(listOf(shortcuts.removeAt(0).id.also { Log.i(TAG, "Evict excess shortcut: $it") }))
5250

53-
val intent = if (conversation.ext != null) Intent().setClassName(WECHAT_PACKAGE, "com.tencent.mm.ui.LauncherUI")
54-
.putExtra("Main_User", conversation.key).putExtra(@Suppress("SpellCheckingInspection") "Intro_Is_Muti_Talker", false)
51+
val intent = if (conversation.id != null) Intent().setClassName(WECHAT_PACKAGE, "com.tencent.mm.ui.LauncherUI")
52+
.putExtra("Main_User", conversation.id).putExtra(@Suppress("SpellCheckingInspection") "Intro_Is_Muti_Talker", false)
5553
.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
5654
else {
5755
val bubbleActivity = (mAgentBubbleActivity
@@ -71,7 +69,7 @@ import java.lang.reflect.Method
7169
if (SDK_INT >= Q) @SuppressLint("RestrictedApi") {
7270
setLongLived(true).setLocusId(LocusId(id))
7371
if (! conversation.isGroupChat) setPerson(conversation.sender().build().toAndroidPerson()) }}.build()
74-
if (BuildConfig.DEBUG) { Log.i(TAG, "Updating shortcut \"${shortcut.id}\": ${shortcut.intent.toString()}") }
72+
Log.i(TAG, "Updating shortcut \"${shortcut.id}\"${if (BuildConfig.DEBUG) ": " + shortcut.intent.toString() else ""}")
7573
return if (sm.addDynamicShortcuts(listOf(shortcut))) true.also { Log.i(TAG, "Shortcut updated: $id") }
7674
else false.also { Log.e(TAG, "Unexpected rate limit.") }
7775
}

src/main/java/com/oasisfeng/nevo/decorators/wechat/ConversationManager.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ public static class Conversation {
3838

3939
private static final String SCHEME_ORIGINAL_NAME = "ON:";
4040

41-
final int id;
42-
volatile @Nullable String key; // The user name in WeChat
41+
final int nid; // The notification ID of conversation (hash code of "id" below)
42+
volatile @Nullable String id; // The unique ID of conversation in WeChat
4343
int count;
4444
CharSequence title;
4545
CharSequence summary;
@@ -54,7 +54,7 @@ int setType(final int type) {
5454
if (type == mType) return type;
5555
final int previous_type = mType;
5656
mType = type;
57-
sender = type == TYPE_UNKNOWN || type == TYPE_GROUP_CHAT ? null : sender().setKey(key).setBot(type == TYPE_BOT_MESSAGE); // Always set key as it may change
57+
sender = type == TYPE_UNKNOWN || type == TYPE_GROUP_CHAT ? null : sender().setKey(id).setBot(type == TYPE_BOT_MESSAGE); // Always set key as it may change
5858
if (type != TYPE_GROUP_CHAT) mParticipants.clear();
5959
return previous_type;
6060
}
@@ -98,7 +98,7 @@ static CharSequence getOriginalName(final Person person) {
9898
return uri != null && uri.startsWith(SCHEME_ORIGINAL_NAME) ? uri.substring(SCHEME_ORIGINAL_NAME.length()): person.getName();
9999
}
100100

101-
Conversation(final int id) { this.id = id; }
101+
Conversation(final int nid) { this.nid = nid; }
102102

103103
@ConversationType private int mType;
104104
private final Map<String, Person> mParticipants = new ArrayMap<>();

src/main/java/com/oasisfeng/nevo/decorators/wechat/MessagingBuilder.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,11 @@ class MessagingBuilder {
149149
final RemoteInput remote_input;
150150
if (SDK_INT >= N && on_reply != null && (remote_input = ext.getRemoteInput()) != null && conversation.isChat()) {
151151
final CharSequence[] input_history = n.extras.getCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY);
152-
final PendingIntent proxy = proxyDirectReply(conversation.id, sbn, on_reply, remote_input, input_history);
152+
final PendingIntent proxy = proxyDirectReply(conversation.nid, sbn, on_reply, remote_input, input_history);
153153
final RemoteInput.Builder reply_remote_input = new RemoteInput.Builder(remote_input.getResultKey()).addExtras(remote_input.getExtras())
154154
.setAllowFreeFormInput(true).setChoices(SmartReply.generateChoices(messages));
155155
final String participant = ext.getParticipant(); // No need to getParticipants() due to actually only one participant at most, see CarExtender.Builder().
156-
if (BuildConfig.DEBUG && conversation.key != null) reply_remote_input.setLabel(conversation.key);
156+
if (BuildConfig.DEBUG && conversation.id != null) reply_remote_input.setLabel(conversation.id);
157157
else if (participant != null) reply_remote_input.setLabel(participant);
158158

159159
final Action.Builder reply_action = new Action.Builder(null, mContext.getString(R.string.action_reply), proxy)
@@ -172,11 +172,11 @@ static void showDebugNotification(final Context context, final Conversation conv
172172
final String[] messages = convs.ext != null ? convs.ext.getMessages() : null;
173173
if (messages != null) for (final String msg : messages) bigText.append("\n").append(msg);
174174
final Builder n = new Builder(context).setSmallIcon(android.R.drawable.stat_sys_warning)
175-
.setContentTitle(convs.key).setContentText(convs.ticker).setSubText(summary).setShowWhen(true)
175+
.setContentTitle(convs.id).setContentText(convs.ticker).setSubText(summary).setShowWhen(true)
176176
.setStyle(new BigTextStyle().setBigContentTitle(convs.title).bigText(bigText.toString()));
177177
if (SDK_INT >= O) n.setChannelId("Debug");
178178
requireNonNull(context.getSystemService(NotificationManager.class))
179-
.notify(convs.key != null ? convs.key.hashCode() : convs.title.hashCode(), n.build());
179+
.notify(convs.id != null ? convs.id.hashCode() : convs.title.hashCode(), n.build());
180180
}
181181

182182
private static Message buildMessage(final Conversation conversation, final long when, final @Nullable CharSequence ticker,

src/main/java/com/oasisfeng/nevo/decorators/wechat/WeChatDecorator.java

+18-17
Original file line numberDiff line numberDiff line change
@@ -188,26 +188,27 @@ public class WeChatDecorator extends NevoDecoratorService {
188188
final List<MessagingStyle.Message> messages = messaging.getMessages();
189189
if (messages.isEmpty()) return true;
190190

191-
if (conversation.key == null && mActivityBlocker != null) try {
191+
if (conversation.id == null && mActivityBlocker != null) try {
192192
final CountDownLatch latch = new CountDownLatch(1);
193193
n.contentIntent.send(this, 0, new Intent().putExtra("", mActivityBlocker), (pi, intent, r, d, e) -> {
194-
final String key = intent.getStringExtra(EXTRA_USERNAME);
195-
if (key == null) { Log.e(TAG, "Unexpected null key received for conversation: " + conversation.title); return; }
196-
conversation.key = key; // setType() below will trigger rebuilding of conversation sender.
194+
final String id = intent.getStringExtra(EXTRA_USERNAME);
195+
if (id == null) { Log.e(TAG, "Unexpected null ID received for conversation: " + conversation.title); return; }
196+
conversation.id = id; // setType() below will trigger rebuilding of conversation sender.
197197
latch.countDown();
198+
if (BuildConfig.DEBUG && id.hashCode() != conversation.nid) Log.e(TAG, "NID is not hash code of CID");
198199
}, null);
199200
try {
200201
if (latch.await(100, TimeUnit.MILLISECONDS)) {
201-
if (BuildConfig.DEBUG) Log.d(TAG, "Key retrieved: " + conversation.key);
202-
} else Log.w(TAG, "Timeout retrieving conversation key");
202+
if (BuildConfig.DEBUG) Log.d(TAG, "Conversation ID retrieved: " + conversation.id);
203+
} else Log.w(TAG, "Timeout retrieving conversation ID");
203204
} catch (final InterruptedException ignored) {}
204205
} catch (final PendingIntent.CanceledException ignored) {}
205206

206-
final String key = conversation.key;
207-
if (key != null) {
208-
final int type = key.endsWith("@chatroom") || key.endsWith("@im.chatroom"/* WeWork */) ? TYPE_GROUP_CHAT
209-
: key.startsWith("gh_") || key.equals(KEY_SERVICE_MESSAGE) ? TYPE_BOT_MESSAGE
210-
: key.endsWith("@openim") ? TYPE_DIRECT_MESSAGE : TYPE_UNKNOWN;
207+
final String cid = conversation.id;
208+
if (cid != null) {
209+
final int type = cid.endsWith("@chatroom") || cid.endsWith("@im.chatroom"/* WeWork */) ? TYPE_GROUP_CHAT
210+
: cid.startsWith("gh_") || cid.equals(KEY_SERVICE_MESSAGE) ? TYPE_BOT_MESSAGE
211+
: cid.endsWith("@openim") ? TYPE_DIRECT_MESSAGE : TYPE_UNKNOWN;
211212
conversation.setType(type);
212213
} else if (conversation.isTypeUnknown())
213214
conversation.setType(WeChatMessage.guessConversationType(conversation));
@@ -219,7 +220,7 @@ public class WeChatDecorator extends NevoDecoratorService {
219220
}
220221

221222
final boolean is_group_chat = conversation.isGroupChat();
222-
if (SDK_INT >= P && KEY_SERVICE_MESSAGE.equals(key)) { // Setting conversation title before Android P will make it a group chat.
223+
if (SDK_INT >= P && KEY_SERVICE_MESSAGE.equals(cid)) { // Setting conversation title before Android P will make it a group chat.
223224
messaging.setConversationTitle(getString(R.string.header_service_message)); // A special header for this non-group conversation with multiple senders
224225
n.setGroup(GROUP_BOT);
225226
} else n.setGroup(is_group_chat ? GROUP_GROUP : conversation.isBotMessage() ? GROUP_BOT : GROUP_DIRECT);
@@ -233,8 +234,8 @@ public class WeChatDecorator extends NevoDecoratorService {
233234
MessagingBuilder.flatIntoExtras(messaging, extras);
234235
extras.putString(Notification.EXTRA_TEMPLATE, TEMPLATE_MESSAGING);
235236

236-
if (SDK_INT >= N_MR1 && key != null) {
237-
final String shortcut_id = AgentShortcuts.Companion.buildShortcutId(key);
237+
if (SDK_INT >= N_MR1 && cid != null) {
238+
final String shortcut_id = AgentShortcuts.Companion.buildShortcutId(cid);
238239
final boolean shortcut_ready = mAgentShortcuts.updateShortcutIfNeeded(shortcut_id, conversation, profile);
239240
if (SDK_INT >= O && shortcut_ready) n.setShortcutId(shortcut_id);
240241
if (SDK_INT >= Q) {
@@ -246,15 +247,15 @@ public class WeChatDecorator extends NevoDecoratorService {
246247
.addRemoteInput(new RemoteInput.Builder("").setAllowFreeFormInput(false).build());
247248
if (n.actions == null) n.actions = new Action[]{ action.build() };
248249
}
249-
} else if (SDK_INT > Q && shortcut_ready)
250-
setBubbleMetadata(n, conversation, conversation.ext != null ? shortcut_id : null);
250+
} else if (SDK_INT > Q && shortcut_ready) // Shortcut does not use conversation ID if it is absent.
251+
setBubbleMetadata(n, conversation, conversation.id != null ? shortcut_id : null);
251252
}
252253
}
253254
return true;
254255
}
255256

256257
@RequiresApi(Q) @SuppressWarnings("deprecation")
257-
private void setBubbleMetadata(final MutableNotification n, final Conversation conversation, final String shortcut_id) {
258+
private void setBubbleMetadata(final MutableNotification n, final Conversation conversation, final @Nullable String shortcut_id) {
258259
final BubbleMetadata.Builder builder = SDK_INT > Q && shortcut_id != null ? new BubbleMetadata.Builder(shortcut_id) // WeChat does not met the requirement of bubble on Android Q: "documentLaunchMode=always"
259260
: new BubbleMetadata.Builder().setIcon(IconHelper.convertToAdaptiveIcon(this, conversation.icon))
260261
.setIntent(SDK_INT > Q ? n.contentIntent : buildBubblePendingIntent(n.contentIntent, shortcut_id));

0 commit comments

Comments
 (0)