Pass reference time / locales of messages to the model

1. It is required to set Person object when constructing a Message object
   now. As it is very important to know whether the message is from
   local user or remote user. Introduced PERSON_USER_REMOTE if
   the caller just want a simple way to specify a remote user.

2. Use detectLanguages to detect the locale of the messages
   If the model finds the detected language is not something
   it supports, model may suppress smart reply.

3. Pass the reference time to the model. So model can resolve
   the absolute time from a relative date string like "tomorrow 6pm".

BUG: 120809869

Test: atest ActionsSuggestionsHelperTest.java
Test: atest ConversationActionsTest.java

Change-Id: Ie079848e9b3d9bb8800f7f95d73e289e831968f8
diff --git a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
index 797b861..b41096c 100644
--- a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
+++ b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
@@ -16,7 +16,6 @@
 
 package android.view.textclassifier;
 
-import android.annotation.NonNull;
 import android.app.Person;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -30,6 +29,7 @@
 import java.util.Deque;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 /**
@@ -57,9 +57,9 @@
      * </ul>
      * User A will be encoded as 2, user B will be encoded as 1 and local user will be encoded as 0.
      */
-    @NonNull
     public static ActionsSuggestionsModel.ConversationMessage[] toNativeMessages(
-            @NonNull List<ConversationActions.Message> messages) {
+            List<ConversationActions.Message> messages,
+            Function<CharSequence, String> languageDetector) {
         List<ConversationActions.Message> messagesWithText =
                 messages.stream()
                         .filter(message -> !TextUtils.isEmpty(message.getText()))
@@ -67,31 +67,18 @@
         if (messagesWithText.isEmpty()) {
             return new ActionsSuggestionsModel.ConversationMessage[0];
         }
-        int size = messagesWithText.size();
-        // If the last message (the most important one) does not have the Person object, we will
-        // just use the last message and consider this message is sent from a remote user.
-        ConversationActions.Message lastMessage = messages.get(size - 1);
-        boolean useLastMessageOnly = lastMessage.getAuthor() == null;
-        if (useLastMessageOnly) {
-            return new ActionsSuggestionsModel.ConversationMessage[]{
-                    new ActionsSuggestionsModel.ConversationMessage(
-                            FIRST_NON_LOCAL_USER,
-                            lastMessage.getText().toString(),
-                            0,
-                            null)};
-        }
-
-        // Encode the messages in the reverse order, stop whenever the Person object is missing.
         Deque<ActionsSuggestionsModel.ConversationMessage> nativeMessages = new ArrayDeque<>();
         PersonEncoder personEncoder = new PersonEncoder();
+        int size = messagesWithText.size();
         for (int i = size - 1; i >= 0; i--) {
             ConversationActions.Message message = messagesWithText.get(i);
-            if (message.getAuthor() == null) {
-                break;
-            }
+            long referenceTime = message.getReferenceTime() == null
+                    ? 0
+                    : message.getReferenceTime().toInstant().toEpochMilli();
             nativeMessages.push(new ActionsSuggestionsModel.ConversationMessage(
                     personEncoder.encode(message.getAuthor()),
-                    message.getText().toString(), 0, null));
+                    message.getText().toString(), referenceTime,
+                    languageDetector.apply(message.getText())));
         }
         return nativeMessages.toArray(
                 new ActionsSuggestionsModel.ConversationMessage[nativeMessages.size()]);