blob: b41096c74bf7522f435d2b3fbee351031976f3eb [file] [log] [blame]
Tony Makf99ee172018-11-23 12:14:39 +00001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view.textclassifier;
18
Tony Makf99ee172018-11-23 12:14:39 +000019import android.app.Person;
20import android.text.TextUtils;
21import android.util.ArrayMap;
22
23import com.android.internal.annotations.VisibleForTesting;
24
25import com.google.android.textclassifier.ActionsSuggestionsModel;
26
27import java.util.ArrayDeque;
28import java.util.ArrayList;
29import java.util.Deque;
30import java.util.List;
31import java.util.Map;
Tony Mak82fa8d92018-12-07 17:37:43 +000032import java.util.function.Function;
Tony Makf99ee172018-11-23 12:14:39 +000033import java.util.stream.Collectors;
34
35/**
36 * Helper class for action suggestions.
37 *
38 * @hide
39 */
40@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
41public final class ActionsSuggestionsHelper {
42 private static final int USER_LOCAL = 0;
43 private static final int FIRST_NON_LOCAL_USER = 1;
44
45 private ActionsSuggestionsHelper() {}
46
47 /**
48 * Converts the messages to a list of native messages object that the model can understand.
49 * <p>
50 * User id encoding - local user is represented as 0, Other users are numbered according to
51 * how far before they spoke last time in the conversation. For example, considering this
52 * conversation:
53 * <ul>
54 * <li> User A: xxx
55 * <li> Local user: yyy
56 * <li> User B: zzz
57 * </ul>
58 * User A will be encoded as 2, user B will be encoded as 1 and local user will be encoded as 0.
59 */
Tony Makf99ee172018-11-23 12:14:39 +000060 public static ActionsSuggestionsModel.ConversationMessage[] toNativeMessages(
Tony Mak82fa8d92018-12-07 17:37:43 +000061 List<ConversationActions.Message> messages,
62 Function<CharSequence, String> languageDetector) {
Tony Makf99ee172018-11-23 12:14:39 +000063 List<ConversationActions.Message> messagesWithText =
64 messages.stream()
65 .filter(message -> !TextUtils.isEmpty(message.getText()))
66 .collect(Collectors.toCollection(ArrayList::new));
67 if (messagesWithText.isEmpty()) {
68 return new ActionsSuggestionsModel.ConversationMessage[0];
69 }
Tony Makf99ee172018-11-23 12:14:39 +000070 Deque<ActionsSuggestionsModel.ConversationMessage> nativeMessages = new ArrayDeque<>();
71 PersonEncoder personEncoder = new PersonEncoder();
Tony Mak82fa8d92018-12-07 17:37:43 +000072 int size = messagesWithText.size();
Tony Makf99ee172018-11-23 12:14:39 +000073 for (int i = size - 1; i >= 0; i--) {
74 ConversationActions.Message message = messagesWithText.get(i);
Tony Mak82fa8d92018-12-07 17:37:43 +000075 long referenceTime = message.getReferenceTime() == null
76 ? 0
77 : message.getReferenceTime().toInstant().toEpochMilli();
Tony Makf99ee172018-11-23 12:14:39 +000078 nativeMessages.push(new ActionsSuggestionsModel.ConversationMessage(
79 personEncoder.encode(message.getAuthor()),
Tony Mak82fa8d92018-12-07 17:37:43 +000080 message.getText().toString(), referenceTime,
81 languageDetector.apply(message.getText())));
Tony Makf99ee172018-11-23 12:14:39 +000082 }
83 return nativeMessages.toArray(
84 new ActionsSuggestionsModel.ConversationMessage[nativeMessages.size()]);
85 }
86
87 private static final class PersonEncoder {
88 private final Map<Person, Integer> mMapping = new ArrayMap<>();
89 private int mNextUserId = FIRST_NON_LOCAL_USER;
90
91 private int encode(Person person) {
92 if (ConversationActions.Message.PERSON_USER_LOCAL.equals(person)) {
93 return USER_LOCAL;
94 }
95 Integer result = mMapping.get(person);
96 if (result == null) {
97 mMapping.put(person, mNextUserId);
98 result = mNextUserId;
99 mNextUserId++;
100 }
101 return result;
102 }
103 }
104}