1 /*
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
17 // JNI wrapper for actions.
18
19 #include "actions/actions_jni.h"
20
21 #include <jni.h>
22
23 #include <map>
24 #include <type_traits>
25 #include <vector>
26
27 #include "actions/actions-suggestions.h"
28 #include "annotator/annotator.h"
29 #include "annotator/annotator_jni_common.h"
30 #include "utils/base/integral_types.h"
31 #include "utils/base/status_macros.h"
32 #include "utils/base/statusor.h"
33 #include "utils/intents/intent-generator.h"
34 #include "utils/intents/jni.h"
35 #include "utils/intents/remote-action-template.h"
36 #include "utils/java/jni-base.h"
37 #include "utils/java/jni-cache.h"
38 #include "utils/java/jni-helper.h"
39 #include "utils/memory/mmap.h"
40
41 using libtextclassifier3::ActionsSuggestions;
42 using libtextclassifier3::ActionsSuggestionsResponse;
43 using libtextclassifier3::ActionSuggestionOptions;
44 using libtextclassifier3::Annotator;
45 using libtextclassifier3::Conversation;
46 using libtextclassifier3::IntentGenerator;
47 using libtextclassifier3::JStringToUtf8String;
48 using libtextclassifier3::ScopedLocalRef;
49 using libtextclassifier3::StatusOr;
50
51 // When using the Java's ICU, UniLib needs to be instantiated with a JavaVM
52 // pointer from JNI. When using a standard ICU the pointer is not needed and the
53 // objects are instantiated implicitly.
54 #ifdef TC3_UNILIB_JAVAICU
55 using libtextclassifier3::UniLib;
56 #endif
57
58 namespace libtextclassifier3 {
59
60 namespace {
61
62 // Cached state for model inference.
63 // Keeps a jni cache, intent generator and model instance so that they don't
64 // have to be recreated for each call.
65 class ActionsSuggestionsJniContext {
66 public:
Create(const std::shared_ptr<libtextclassifier3::JniCache> & jni_cache,std::unique_ptr<ActionsSuggestions> model)67 static ActionsSuggestionsJniContext* Create(
68 const std::shared_ptr<libtextclassifier3::JniCache>& jni_cache,
69 std::unique_ptr<ActionsSuggestions> model) {
70 if (jni_cache == nullptr || model == nullptr) {
71 return nullptr;
72 }
73 std::unique_ptr<IntentGenerator> intent_generator =
74 IntentGenerator::Create(model->model()->android_intent_options(),
75 model->model()->resources(), jni_cache);
76 if (intent_generator == nullptr) {
77 return nullptr;
78 }
79
80 TC3_ASSIGN_OR_RETURN_NULL(
81 std::unique_ptr<RemoteActionTemplatesHandler> template_handler,
82 libtextclassifier3::RemoteActionTemplatesHandler::Create(jni_cache));
83
84 return new ActionsSuggestionsJniContext(jni_cache, std::move(model),
85 std::move(intent_generator),
86 std::move(template_handler));
87 }
88
jni_cache() const89 std::shared_ptr<libtextclassifier3::JniCache> jni_cache() const {
90 return jni_cache_;
91 }
92
model() const93 ActionsSuggestions* model() const { return model_.get(); }
94
intent_generator() const95 IntentGenerator* intent_generator() const { return intent_generator_.get(); }
96
template_handler() const97 RemoteActionTemplatesHandler* template_handler() const {
98 return template_handler_.get();
99 }
100
101 private:
ActionsSuggestionsJniContext(const std::shared_ptr<libtextclassifier3::JniCache> & jni_cache,std::unique_ptr<ActionsSuggestions> model,std::unique_ptr<IntentGenerator> intent_generator,std::unique_ptr<RemoteActionTemplatesHandler> template_handler)102 ActionsSuggestionsJniContext(
103 const std::shared_ptr<libtextclassifier3::JniCache>& jni_cache,
104 std::unique_ptr<ActionsSuggestions> model,
105 std::unique_ptr<IntentGenerator> intent_generator,
106 std::unique_ptr<RemoteActionTemplatesHandler> template_handler)
107 : jni_cache_(jni_cache),
108 model_(std::move(model)),
109 intent_generator_(std::move(intent_generator)),
110 template_handler_(std::move(template_handler)) {}
111
112 std::shared_ptr<libtextclassifier3::JniCache> jni_cache_;
113 std::unique_ptr<ActionsSuggestions> model_;
114 std::unique_ptr<IntentGenerator> intent_generator_;
115 std::unique_ptr<RemoteActionTemplatesHandler> template_handler_;
116 };
117
FromJavaActionSuggestionOptions(JNIEnv * env,jobject joptions)118 ActionSuggestionOptions FromJavaActionSuggestionOptions(JNIEnv* env,
119 jobject joptions) {
120 ActionSuggestionOptions options = ActionSuggestionOptions::Default();
121 return options;
122 }
123
ActionSuggestionsToJObject(JNIEnv * env,const ActionsSuggestionsJniContext * context,jobject app_context,const reflection::Schema * annotations_entity_data_schema,const ActionsSuggestionsResponse & action_response,const Conversation & conversation,const jstring device_locales,const bool generate_intents)124 StatusOr<ScopedLocalRef<jobject>> ActionSuggestionsToJObject(
125 JNIEnv* env, const ActionsSuggestionsJniContext* context,
126 jobject app_context,
127 const reflection::Schema* annotations_entity_data_schema,
128 const ActionsSuggestionsResponse& action_response,
129 const Conversation& conversation, const jstring device_locales,
130 const bool generate_intents) {
131 // Find the class ActionSuggestion.
132 auto status_or_action_class = JniHelper::FindClass(
133 env, TC3_PACKAGE_PATH TC3_ACTIONS_CLASS_NAME_STR "$ActionSuggestion");
134 if (!status_or_action_class.ok()) {
135 TC3_LOG(ERROR) << "Couldn't find ActionSuggestion class.";
136 return status_or_action_class.status();
137 }
138 ScopedLocalRef<jclass> action_class =
139 std::move(status_or_action_class.ValueOrDie());
140
141 // Find the class ActionSuggestions
142 auto status_or_result_class = JniHelper::FindClass(
143 env, TC3_PACKAGE_PATH TC3_ACTIONS_CLASS_NAME_STR "$ActionSuggestions");
144 if (!status_or_result_class.ok()) {
145 TC3_LOG(ERROR) << "Couldn't find ActionSuggestions class.";
146 return status_or_result_class.status();
147 }
148 ScopedLocalRef<jclass> result_class =
149 std::move(status_or_result_class.ValueOrDie());
150
151 // Find the class Slot.
152 auto status_or_slot_class = JniHelper::FindClass(
153 env, TC3_PACKAGE_PATH TC3_ACTIONS_CLASS_NAME_STR "$Slot");
154 if (!status_or_slot_class.ok()) {
155 TC3_LOG(ERROR) << "Couldn't find Slot class.";
156 return status_or_slot_class.status();
157 }
158 ScopedLocalRef<jclass> slot_class =
159 std::move(status_or_slot_class.ValueOrDie());
160
161 TC3_ASSIGN_OR_RETURN(
162 const jmethodID action_class_constructor,
163 JniHelper::GetMethodID(
164 env, action_class.get(), "<init>",
165 "(Ljava/lang/String;Ljava/lang/String;F[L" TC3_PACKAGE_PATH
166 TC3_NAMED_VARIANT_CLASS_NAME_STR
167 ";[B[L" TC3_PACKAGE_PATH TC3_REMOTE_ACTION_TEMPLATE_CLASS_NAME_STR
168 ";[L" TC3_PACKAGE_PATH TC3_ACTIONS_CLASS_NAME_STR "$Slot;)V"));
169 TC3_ASSIGN_OR_RETURN(const jmethodID slot_class_constructor,
170 JniHelper::GetMethodID(env, slot_class.get(), "<init>",
171 "(Ljava/lang/String;IIIF)V"));
172 TC3_ASSIGN_OR_RETURN(
173 ScopedLocalRef<jobjectArray> actions,
174 JniHelper::NewObjectArray(env, action_response.actions.size(),
175 action_class.get(), nullptr));
176 for (int i = 0; i < action_response.actions.size(); i++) {
177 ScopedLocalRef<jobjectArray> extras;
178 const reflection::Schema* actions_entity_data_schema =
179 context->model()->entity_data_schema();
180 if (actions_entity_data_schema != nullptr &&
181 !action_response.actions[i].serialized_entity_data.empty()) {
182 TC3_ASSIGN_OR_RETURN(
183 extras, context->template_handler()->EntityDataAsNamedVariantArray(
184 actions_entity_data_schema,
185 action_response.actions[i].serialized_entity_data));
186 }
187
188 ScopedLocalRef<jbyteArray> serialized_entity_data;
189 if (!action_response.actions[i].serialized_entity_data.empty()) {
190 TC3_ASSIGN_OR_RETURN(
191 serialized_entity_data,
192 JniHelper::NewByteArray(
193 env, action_response.actions[i].serialized_entity_data.size()));
194 TC3_RETURN_IF_ERROR(JniHelper::SetByteArrayRegion(
195 env, serialized_entity_data.get(), 0,
196 action_response.actions[i].serialized_entity_data.size(),
197 reinterpret_cast<const jbyte*>(
198 action_response.actions[i].serialized_entity_data.data())));
199 }
200
201 ScopedLocalRef<jobjectArray> remote_action_templates_result;
202 if (generate_intents) {
203 std::vector<RemoteActionTemplate> remote_action_templates;
204 if (context->intent_generator()->GenerateIntents(
205 device_locales, action_response.actions[i], conversation,
206 app_context,
207 /*annotations_entity_data_schema=*/annotations_entity_data_schema,
208 /*actions_entity_data_schema=*/actions_entity_data_schema,
209 &remote_action_templates)) {
210 TC3_ASSIGN_OR_RETURN(
211 remote_action_templates_result,
212 context->template_handler()->RemoteActionTemplatesToJObjectArray(
213 remote_action_templates));
214 }
215 }
216
217 TC3_ASSIGN_OR_RETURN(ScopedLocalRef<jstring> reply,
218 context->jni_cache()->ConvertToJavaString(
219 action_response.actions[i].response_text));
220
221 TC3_ASSIGN_OR_RETURN(
222 ScopedLocalRef<jstring> action_type,
223 JniHelper::NewStringUTF(env, action_response.actions[i].type.c_str()));
224
225 ScopedLocalRef<jobjectArray> slots;
226 if (!action_response.actions[i].slots.empty()) {
227 TC3_ASSIGN_OR_RETURN(slots,
228 JniHelper::NewObjectArray(
229 env, action_response.actions[i].slots.size(),
230 slot_class.get(), nullptr));
231 for (int j = 0; j < action_response.actions[i].slots.size(); j++) {
232 const Slot& slot_c = action_response.actions[i].slots[j];
233 TC3_ASSIGN_OR_RETURN(ScopedLocalRef<jstring> slot_type,
234 JniHelper::NewStringUTF(env, slot_c.type.c_str()));
235
236 TC3_ASSIGN_OR_RETURN(
237 ScopedLocalRef<jobject> slot,
238 JniHelper::NewObject(
239 env, slot_class.get(), slot_class_constructor, slot_type.get(),
240 slot_c.span.message_index, slot_c.span.span.first,
241 slot_c.span.span.second, slot_c.confidence_score));
242
243 TC3_RETURN_IF_ERROR(
244 JniHelper::SetObjectArrayElement(env, slots.get(), j, slot.get()));
245 }
246 }
247
248 TC3_ASSIGN_OR_RETURN(
249 ScopedLocalRef<jobject> action,
250 JniHelper::NewObject(
251 env, action_class.get(), action_class_constructor, reply.get(),
252 action_type.get(),
253 static_cast<jfloat>(action_response.actions[i].score), extras.get(),
254 serialized_entity_data.get(), remote_action_templates_result.get(),
255 slots.get()));
256 TC3_RETURN_IF_ERROR(
257 JniHelper::SetObjectArrayElement(env, actions.get(), i, action.get()));
258 }
259
260 // Create the ActionSuggestions object.
261 TC3_ASSIGN_OR_RETURN(
262 const jmethodID result_class_constructor,
263 JniHelper::GetMethodID(env, result_class.get(), "<init>",
264 "([L" TC3_PACKAGE_PATH TC3_ACTIONS_CLASS_NAME_STR
265 "$ActionSuggestion;Z)V"));
266 TC3_ASSIGN_OR_RETURN(
267 ScopedLocalRef<jobject> result,
268 JniHelper::NewObject(env, result_class.get(), result_class_constructor,
269 actions.get(), action_response.is_sensitive));
270 return result;
271 }
272
FromJavaConversationMessage(JNIEnv * env,jobject jmessage)273 StatusOr<ConversationMessage> FromJavaConversationMessage(JNIEnv* env,
274 jobject jmessage) {
275 if (!jmessage) {
276 return {};
277 }
278
279 TC3_ASSIGN_OR_RETURN(
280 ScopedLocalRef<jclass> message_class,
281 JniHelper::FindClass(env, TC3_PACKAGE_PATH TC3_ACTIONS_CLASS_NAME_STR
282 "$ConversationMessage"));
283 // .getText()
284 TC3_ASSIGN_OR_RETURN(
285 jmethodID get_text_method,
286 JniHelper::GetMethodID(env, message_class.get(), "getText",
287 "()Ljava/lang/String;"));
288 TC3_ASSIGN_OR_RETURN(
289 ScopedLocalRef<jstring> text,
290 JniHelper::CallObjectMethod<jstring>(env, jmessage, get_text_method));
291
292 // .getUserId()
293 TC3_ASSIGN_OR_RETURN(
294 jmethodID get_user_id_method,
295 JniHelper::GetMethodID(env, message_class.get(), "getUserId", "()I"));
296 TC3_ASSIGN_OR_RETURN(int32 user_id, JniHelper::CallIntMethod(
297 env, jmessage, get_user_id_method));
298
299 // .getReferenceTimeMsUtc()
300 TC3_ASSIGN_OR_RETURN(jmethodID get_reference_time_method,
301 JniHelper::GetMethodID(env, message_class.get(),
302 "getReferenceTimeMsUtc", "()J"));
303 TC3_ASSIGN_OR_RETURN(
304 int64 reference_time,
305 JniHelper::CallLongMethod(env, jmessage, get_reference_time_method));
306
307 // .getReferenceTimezone()
308 TC3_ASSIGN_OR_RETURN(
309 jmethodID get_reference_timezone_method,
310 JniHelper::GetMethodID(env, message_class.get(), "getReferenceTimezone",
311 "()Ljava/lang/String;"));
312 TC3_ASSIGN_OR_RETURN(ScopedLocalRef<jstring> reference_timezone,
313 JniHelper::CallObjectMethod<jstring>(
314 env, jmessage, get_reference_timezone_method));
315
316 // .getDetectedTextLanguageTags()
317 TC3_ASSIGN_OR_RETURN(jmethodID get_detected_text_language_tags_method,
318 JniHelper::GetMethodID(env, message_class.get(),
319 "getDetectedTextLanguageTags",
320 "()Ljava/lang/String;"));
321 TC3_ASSIGN_OR_RETURN(
322 ScopedLocalRef<jstring> detected_text_language_tags,
323 JniHelper::CallObjectMethod<jstring>(
324 env, jmessage, get_detected_text_language_tags_method));
325
326 ConversationMessage message;
327 TC3_ASSIGN_OR_RETURN(message.text, JStringToUtf8String(env, text.get()));
328 message.user_id = user_id;
329 message.reference_time_ms_utc = reference_time;
330 TC3_ASSIGN_OR_RETURN(message.reference_timezone,
331 JStringToUtf8String(env, reference_timezone.get()));
332 TC3_ASSIGN_OR_RETURN(
333 message.detected_text_language_tags,
334 JStringToUtf8String(env, detected_text_language_tags.get()));
335 return message;
336 }
337
FromJavaConversation(JNIEnv * env,jobject jconversation)338 StatusOr<Conversation> FromJavaConversation(JNIEnv* env,
339 jobject jconversation) {
340 if (!jconversation) {
341 return {Status::UNKNOWN};
342 }
343
344 TC3_ASSIGN_OR_RETURN(
345 ScopedLocalRef<jclass> conversation_class,
346 JniHelper::FindClass(
347 env, TC3_PACKAGE_PATH TC3_ACTIONS_CLASS_NAME_STR "$Conversation"));
348
349 TC3_ASSIGN_OR_RETURN(
350 jmethodID get_conversation_messages_method,
351 JniHelper::GetMethodID(env, conversation_class.get(),
352 "getConversationMessages",
353 "()[L" TC3_PACKAGE_PATH TC3_ACTIONS_CLASS_NAME_STR
354 "$ConversationMessage;"));
355 TC3_ASSIGN_OR_RETURN(
356 ScopedLocalRef<jobjectArray> jmessages,
357 JniHelper::CallObjectMethod<jobjectArray>(
358 env, jconversation, get_conversation_messages_method));
359
360 std::vector<ConversationMessage> messages;
361 TC3_ASSIGN_OR_RETURN(const int size,
362 JniHelper::GetArrayLength(env, jmessages.get()));
363 for (int i = 0; i < size; i++) {
364 TC3_ASSIGN_OR_RETURN(
365 ScopedLocalRef<jobject> jmessage,
366 JniHelper::GetObjectArrayElement<jobject>(env, jmessages.get(), i));
367 TC3_ASSIGN_OR_RETURN(ConversationMessage message,
368 FromJavaConversationMessage(env, jmessage.get()));
369 messages.push_back(message);
370 }
371 Conversation conversation;
372 conversation.messages = messages;
373 return conversation;
374 }
375
GetLocalesFromMmap(JNIEnv * env,libtextclassifier3::ScopedMmap * mmap)376 StatusOr<ScopedLocalRef<jstring>> GetLocalesFromMmap(
377 JNIEnv* env, libtextclassifier3::ScopedMmap* mmap) {
378 if (!mmap->handle().ok()) {
379 return JniHelper::NewStringUTF(env, "");
380 }
381 const ActionsModel* model = libtextclassifier3::ViewActionsModel(
382 mmap->handle().start(), mmap->handle().num_bytes());
383 if (!model || !model->locales()) {
384 return JniHelper::NewStringUTF(env, "");
385 }
386 return JniHelper::NewStringUTF(env, model->locales()->c_str());
387 }
388
GetVersionFromMmap(JNIEnv * env,libtextclassifier3::ScopedMmap * mmap)389 jint GetVersionFromMmap(JNIEnv* env, libtextclassifier3::ScopedMmap* mmap) {
390 if (!mmap->handle().ok()) {
391 return 0;
392 }
393 const ActionsModel* model = libtextclassifier3::ViewActionsModel(
394 mmap->handle().start(), mmap->handle().num_bytes());
395 if (!model) {
396 return 0;
397 }
398 return model->version();
399 }
400
GetNameFromMmap(JNIEnv * env,libtextclassifier3::ScopedMmap * mmap)401 StatusOr<ScopedLocalRef<jstring>> GetNameFromMmap(
402 JNIEnv* env, libtextclassifier3::ScopedMmap* mmap) {
403 if (!mmap->handle().ok()) {
404 return JniHelper::NewStringUTF(env, "");
405 }
406 const ActionsModel* model = libtextclassifier3::ViewActionsModel(
407 mmap->handle().start(), mmap->handle().num_bytes());
408 if (!model || !model->name()) {
409 return JniHelper::NewStringUTF(env, "");
410 }
411 return JniHelper::NewStringUTF(env, model->name()->c_str());
412 }
413 } // namespace
414 } // namespace libtextclassifier3
415
416 using libtextclassifier3::ActionsSuggestionsJniContext;
417 using libtextclassifier3::ActionSuggestionsToJObject;
418 using libtextclassifier3::FromJavaActionSuggestionOptions;
419 using libtextclassifier3::FromJavaConversation;
420 using libtextclassifier3::JByteArrayToString;
421
TC3_JNI_METHOD(jlong,TC3_ACTIONS_CLASS_NAME,nativeNewActionsModel)422 TC3_JNI_METHOD(jlong, TC3_ACTIONS_CLASS_NAME, nativeNewActionsModel)
423 (JNIEnv* env, jobject clazz, jint fd, jbyteArray jserialized_preconditions) {
424 std::shared_ptr<libtextclassifier3::JniCache> jni_cache =
425 libtextclassifier3::JniCache::Create(env);
426 std::string serialized_preconditions;
427 if (jserialized_preconditions != nullptr) {
428 TC3_ASSIGN_OR_RETURN_0(
429 serialized_preconditions,
430 JByteArrayToString(env, jserialized_preconditions),
431 TC3_LOG(ERROR) << "Could not convert serialized preconditions.");
432 }
433
434 #ifdef TC3_UNILIB_JAVAICU
435 return reinterpret_cast<jlong>(ActionsSuggestionsJniContext::Create(
436 jni_cache, ActionsSuggestions::FromFileDescriptor(
437 fd, std::unique_ptr<UniLib>(new UniLib(jni_cache)),
438 serialized_preconditions)));
439 #else
440 return reinterpret_cast<jlong>(ActionsSuggestionsJniContext::Create(
441 jni_cache, ActionsSuggestions::FromFileDescriptor(
442 fd, /*unilib=*/nullptr, serialized_preconditions)));
443 #endif // TC3_UNILIB_JAVAICU
444 }
445
TC3_JNI_METHOD(jlong,TC3_ACTIONS_CLASS_NAME,nativeNewActionsModelFromPath)446 TC3_JNI_METHOD(jlong, TC3_ACTIONS_CLASS_NAME, nativeNewActionsModelFromPath)
447 (JNIEnv* env, jobject clazz, jstring path,
448 jbyteArray jserialized_preconditions) {
449 std::shared_ptr<libtextclassifier3::JniCache> jni_cache =
450 libtextclassifier3::JniCache::Create(env);
451 TC3_ASSIGN_OR_RETURN_0(const std::string path_str,
452 JStringToUtf8String(env, path));
453 std::string serialized_preconditions;
454 if (jserialized_preconditions != nullptr) {
455 TC3_ASSIGN_OR_RETURN_0(
456 serialized_preconditions,
457 JByteArrayToString(env, jserialized_preconditions),
458 TC3_LOG(ERROR) << "Could not convert serialized preconditions.");
459 }
460 #ifdef TC3_UNILIB_JAVAICU
461 return reinterpret_cast<jlong>(ActionsSuggestionsJniContext::Create(
462 jni_cache, ActionsSuggestions::FromPath(
463 path_str, std::unique_ptr<UniLib>(new UniLib(jni_cache)),
464 serialized_preconditions)));
465 #else
466 return reinterpret_cast<jlong>(ActionsSuggestionsJniContext::Create(
467 jni_cache, ActionsSuggestions::FromPath(path_str, /*unilib=*/nullptr,
468 serialized_preconditions)));
469 #endif // TC3_UNILIB_JAVAICU
470 }
471
TC3_JNI_METHOD(jlong,TC3_ACTIONS_CLASS_NAME,nativeNewActionsModelWithOffset)472 TC3_JNI_METHOD(jlong, TC3_ACTIONS_CLASS_NAME, nativeNewActionsModelWithOffset)
473 (JNIEnv* env, jobject clazz, jint fd, jlong offset, jlong size,
474 jbyteArray jserialized_preconditions) {
475 std::shared_ptr<libtextclassifier3::JniCache> jni_cache =
476 libtextclassifier3::JniCache::Create(env);
477 std::string serialized_preconditions;
478 if (jserialized_preconditions != nullptr) {
479 TC3_ASSIGN_OR_RETURN_0(
480 serialized_preconditions,
481 JByteArrayToString(env, jserialized_preconditions),
482 TC3_LOG(ERROR) << "Could not convert serialized preconditions.");
483 }
484 #ifdef TC3_UNILIB_JAVAICU
485 return reinterpret_cast<jlong>(ActionsSuggestionsJniContext::Create(
486 jni_cache,
487 ActionsSuggestions::FromFileDescriptor(
488 fd, offset, size, std::unique_ptr<UniLib>(new UniLib(jni_cache)),
489 serialized_preconditions)));
490 #else
491 return reinterpret_cast<jlong>(ActionsSuggestionsJniContext::Create(
492 jni_cache,
493 ActionsSuggestions::FromFileDescriptor(
494 fd, offset, size, /*unilib=*/nullptr, serialized_preconditions)));
495 #endif // TC3_UNILIB_JAVAICU
496 }
497
TC3_JNI_METHOD(jobject,TC3_ACTIONS_CLASS_NAME,nativeSuggestActions)498 TC3_JNI_METHOD(jobject, TC3_ACTIONS_CLASS_NAME, nativeSuggestActions)
499 (JNIEnv* env, jobject thiz, jlong ptr, jobject jconversation, jobject joptions,
500 jlong annotatorPtr, jobject app_context, jstring device_locales,
501 jboolean generate_intents) {
502 if (!ptr) {
503 return nullptr;
504 }
505 TC3_ASSIGN_OR_RETURN_NULL(const Conversation conversation,
506 FromJavaConversation(env, jconversation));
507 const ActionSuggestionOptions options =
508 FromJavaActionSuggestionOptions(env, joptions);
509 const ActionsSuggestionsJniContext* context =
510 reinterpret_cast<ActionsSuggestionsJniContext*>(ptr);
511 const Annotator* annotator = reinterpret_cast<Annotator*>(annotatorPtr);
512
513 const ActionsSuggestionsResponse response =
514 context->model()->SuggestActions(conversation, annotator, options);
515
516 const reflection::Schema* anntotations_entity_data_schema =
517 annotator ? annotator->entity_data_schema() : nullptr;
518
519 TC3_ASSIGN_OR_RETURN_NULL(
520 ScopedLocalRef<jobject> result,
521 ActionSuggestionsToJObject(
522 env, context, app_context, anntotations_entity_data_schema, response,
523 conversation, device_locales, generate_intents));
524 return result.release();
525 }
526
TC3_JNI_METHOD(void,TC3_ACTIONS_CLASS_NAME,nativeCloseActionsModel)527 TC3_JNI_METHOD(void, TC3_ACTIONS_CLASS_NAME, nativeCloseActionsModel)
528 (JNIEnv* env, jobject thiz, jlong model_ptr) {
529 const ActionsSuggestionsJniContext* context =
530 reinterpret_cast<ActionsSuggestionsJniContext*>(model_ptr);
531 delete context;
532 }
533
TC3_JNI_METHOD(jstring,TC3_ACTIONS_CLASS_NAME,nativeGetLocales)534 TC3_JNI_METHOD(jstring, TC3_ACTIONS_CLASS_NAME, nativeGetLocales)
535 (JNIEnv* env, jobject clazz, jint fd) {
536 const std::unique_ptr<libtextclassifier3::ScopedMmap> mmap(
537 new libtextclassifier3::ScopedMmap(fd));
538 TC3_ASSIGN_OR_RETURN_NULL(
539 ScopedLocalRef<jstring> result,
540 libtextclassifier3::GetLocalesFromMmap(env, mmap.get()));
541 return result.release();
542 }
543
TC3_JNI_METHOD(jstring,TC3_ACTIONS_CLASS_NAME,nativeGetLocalesWithOffset)544 TC3_JNI_METHOD(jstring, TC3_ACTIONS_CLASS_NAME, nativeGetLocalesWithOffset)
545 (JNIEnv* env, jobject clazz, jint fd, jlong offset, jlong size) {
546 const std::unique_ptr<libtextclassifier3::ScopedMmap> mmap(
547 new libtextclassifier3::ScopedMmap(fd, offset, size));
548 TC3_ASSIGN_OR_RETURN_NULL(
549 ScopedLocalRef<jstring> result,
550 libtextclassifier3::GetLocalesFromMmap(env, mmap.get()));
551 return result.release();
552 }
553
TC3_JNI_METHOD(jstring,TC3_ACTIONS_CLASS_NAME,nativeGetName)554 TC3_JNI_METHOD(jstring, TC3_ACTIONS_CLASS_NAME, nativeGetName)
555 (JNIEnv* env, jobject clazz, jint fd) {
556 const std::unique_ptr<libtextclassifier3::ScopedMmap> mmap(
557 new libtextclassifier3::ScopedMmap(fd));
558 TC3_ASSIGN_OR_RETURN_NULL(
559 ScopedLocalRef<jstring> result,
560 libtextclassifier3::GetNameFromMmap(env, mmap.get()));
561 return result.release();
562 }
563
TC3_JNI_METHOD(jstring,TC3_ACTIONS_CLASS_NAME,nativeGetNameWithOffset)564 TC3_JNI_METHOD(jstring, TC3_ACTIONS_CLASS_NAME, nativeGetNameWithOffset)
565 (JNIEnv* env, jobject clazz, jint fd, jlong offset, jlong size) {
566 const std::unique_ptr<libtextclassifier3::ScopedMmap> mmap(
567 new libtextclassifier3::ScopedMmap(fd, offset, size));
568 TC3_ASSIGN_OR_RETURN_NULL(
569 ScopedLocalRef<jstring> result,
570 libtextclassifier3::GetNameFromMmap(env, mmap.get()));
571 return result.release();
572 }
573
TC3_JNI_METHOD(jint,TC3_ACTIONS_CLASS_NAME,nativeGetVersion)574 TC3_JNI_METHOD(jint, TC3_ACTIONS_CLASS_NAME, nativeGetVersion)
575 (JNIEnv* env, jobject clazz, jint fd) {
576 const std::unique_ptr<libtextclassifier3::ScopedMmap> mmap(
577 new libtextclassifier3::ScopedMmap(fd));
578 return libtextclassifier3::GetVersionFromMmap(env, mmap.get());
579 }
580
TC3_JNI_METHOD(jint,TC3_ACTIONS_CLASS_NAME,nativeGetVersionWithOffset)581 TC3_JNI_METHOD(jint, TC3_ACTIONS_CLASS_NAME, nativeGetVersionWithOffset)
582 (JNIEnv* env, jobject clazz, jint fd, jlong offset, jlong size) {
583 const std::unique_ptr<libtextclassifier3::ScopedMmap> mmap(
584 new libtextclassifier3::ScopedMmap(fd, offset, size));
585 return libtextclassifier3::GetVersionFromMmap(env, mmap.get());
586 }
587
TC3_JNI_METHOD(jlong,TC3_ACTIONS_CLASS_NAME,nativeGetNativeModelPtr)588 TC3_JNI_METHOD(jlong, TC3_ACTIONS_CLASS_NAME, nativeGetNativeModelPtr)
589 (JNIEnv* env, jobject thiz, jlong ptr) {
590 if (!ptr) {
591 return 0L;
592 }
593 return reinterpret_cast<jlong>(
594 reinterpret_cast<ActionsSuggestionsJniContext*>(ptr)->model());
595 }
596
TC3_JNI_METHOD(jboolean,TC3_ACTIONS_CLASS_NAME,nativeInitializeConversationIntentDetection)597 TC3_JNI_METHOD(jboolean, TC3_ACTIONS_CLASS_NAME,
598 nativeInitializeConversationIntentDetection)
599 (JNIEnv* env, jobject thiz, jlong ptr, jbyteArray jserialized_config) {
600 if (!ptr) {
601 return false;
602 }
603
604 ActionsSuggestions* model =
605 reinterpret_cast<ActionsSuggestionsJniContext*>(ptr)->model();
606
607 std::string serialized_config;
608 TC3_ASSIGN_OR_RETURN_0(
609 serialized_config, JByteArrayToString(env, jserialized_config),
610 TC3_LOG(ERROR) << "Could not convert serialized conversation intent "
611 "detection config.");
612 return model->InitializeConversationIntentDetection(serialized_config);
613 }
614