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 #include "annotator/annotator_jni_common.h"
18
19 #include "annotator/knowledge/knowledge-engine-types.h"
20 #include "utils/java/jni-base.h"
21 #include "utils/java/jni-helper.h"
22
23 namespace libtextclassifier3 {
24 namespace {
25
EntityTypesFromJObject(JNIEnv * env,const jobject & jobject)26 StatusOr<std::unordered_set<std::string>> EntityTypesFromJObject(
27 JNIEnv* env, const jobject& jobject) {
28 std::unordered_set<std::string> entity_types;
29 jobjectArray jentity_types = reinterpret_cast<jobjectArray>(jobject);
30 TC3_ASSIGN_OR_RETURN(const int size,
31 JniHelper::GetArrayLength(env, jentity_types));
32 for (int i = 0; i < size; ++i) {
33 TC3_ASSIGN_OR_RETURN(
34 ScopedLocalRef<jstring> jentity_type,
35 JniHelper::GetObjectArrayElement<jstring>(env, jentity_types, i));
36 TC3_ASSIGN_OR_RETURN(std::string entity_type,
37 JStringToUtf8String(env, jentity_type.get()));
38 entity_types.insert(entity_type);
39 }
40 return entity_types;
41 }
42
43 template <typename T>
FromJavaOptionsInternal(JNIEnv * env,jobject joptions,const std::string & class_name)44 StatusOr<T> FromJavaOptionsInternal(JNIEnv* env, jobject joptions,
45 const std::string& class_name) {
46 if (!joptions) {
47 return {Status::UNKNOWN};
48 }
49
50 TC3_ASSIGN_OR_RETURN(ScopedLocalRef<jclass> options_class,
51 JniHelper::FindClass(env, class_name.c_str()));
52
53 // .getLocale()
54 TC3_ASSIGN_OR_RETURN(
55 jmethodID get_locale,
56 JniHelper::GetMethodID(env, options_class.get(), "getLocale",
57 "()Ljava/lang/String;"));
58 TC3_ASSIGN_OR_RETURN(
59 ScopedLocalRef<jstring> locales,
60 JniHelper::CallObjectMethod<jstring>(env, joptions, get_locale));
61
62 // .getReferenceTimeMsUtc()
63 TC3_ASSIGN_OR_RETURN(jmethodID get_reference_time_method,
64 JniHelper::GetMethodID(env, options_class.get(),
65 "getReferenceTimeMsUtc", "()J"));
66 TC3_ASSIGN_OR_RETURN(
67 int64 reference_time,
68 JniHelper::CallLongMethod(env, joptions, get_reference_time_method));
69
70 // .getReferenceTimezone()
71 TC3_ASSIGN_OR_RETURN(
72 jmethodID get_reference_timezone_method,
73 JniHelper::GetMethodID(env, options_class.get(), "getReferenceTimezone",
74 "()Ljava/lang/String;"));
75 TC3_ASSIGN_OR_RETURN(ScopedLocalRef<jstring> reference_timezone,
76 JniHelper::CallObjectMethod<jstring>(
77 env, joptions, get_reference_timezone_method));
78
79 // .getDetectedTextLanguageTags()
80 TC3_ASSIGN_OR_RETURN(jmethodID get_detected_text_language_tags_method,
81 JniHelper::GetMethodID(env, options_class.get(),
82 "getDetectedTextLanguageTags",
83 "()Ljava/lang/String;"));
84 TC3_ASSIGN_OR_RETURN(
85 ScopedLocalRef<jstring> detected_text_language_tags,
86 JniHelper::CallObjectMethod<jstring>(
87 env, joptions, get_detected_text_language_tags_method));
88
89 // .getAnnotationUsecase()
90 TC3_ASSIGN_OR_RETURN(jmethodID get_annotation_usecase,
91 JniHelper::GetMethodID(env, options_class.get(),
92 "getAnnotationUsecase", "()I"));
93 TC3_ASSIGN_OR_RETURN(
94 int32 annotation_usecase,
95 JniHelper::CallIntMethod(env, joptions, get_annotation_usecase));
96
97 // .getUserLocationLat()
98 TC3_ASSIGN_OR_RETURN(jmethodID get_user_location_lat,
99 JniHelper::GetMethodID(env, options_class.get(),
100 "getUserLocationLat", "()D"));
101 TC3_ASSIGN_OR_RETURN(
102 double user_location_lat,
103 JniHelper::CallDoubleMethod(env, joptions, get_user_location_lat));
104
105 // .getUserLocationLng()
106 TC3_ASSIGN_OR_RETURN(jmethodID get_user_location_lng,
107 JniHelper::GetMethodID(env, options_class.get(),
108 "getUserLocationLng", "()D"));
109 TC3_ASSIGN_OR_RETURN(
110 double user_location_lng,
111 JniHelper::CallDoubleMethod(env, joptions, get_user_location_lng));
112
113 // .getUserLocationAccuracyMeters()
114 TC3_ASSIGN_OR_RETURN(
115 jmethodID get_user_location_accuracy_meters,
116 JniHelper::GetMethodID(env, options_class.get(),
117 "getUserLocationAccuracyMeters", "()F"));
118 TC3_ASSIGN_OR_RETURN(float user_location_accuracy_meters,
119 JniHelper::CallFloatMethod(
120 env, joptions, get_user_location_accuracy_meters));
121
122 // .getUsePodNer()
123 TC3_ASSIGN_OR_RETURN(
124 jmethodID get_use_pod_ner,
125 JniHelper::GetMethodID(env, options_class.get(), "getUsePodNer", "()Z"));
126 TC3_ASSIGN_OR_RETURN(bool use_pod_ner, JniHelper::CallBooleanMethod(
127 env, joptions, get_use_pod_ner));
128
129 // .getUseVocabAnnotator()
130 TC3_ASSIGN_OR_RETURN(jmethodID get_use_vocab_annotator,
131 JniHelper::GetMethodID(env, options_class.get(),
132 "getUseVocabAnnotator", "()Z"));
133 TC3_ASSIGN_OR_RETURN(
134 bool use_vocab_annotator,
135 JniHelper::CallBooleanMethod(env, joptions, get_use_vocab_annotator));
136 T options;
137 TC3_ASSIGN_OR_RETURN(options.locales,
138 JStringToUtf8String(env, locales.get()));
139 TC3_ASSIGN_OR_RETURN(options.reference_timezone,
140 JStringToUtf8String(env, reference_timezone.get()));
141 options.reference_time_ms_utc = reference_time;
142 TC3_ASSIGN_OR_RETURN(
143 options.detected_text_language_tags,
144 JStringToUtf8String(env, detected_text_language_tags.get()));
145 options.annotation_usecase =
146 static_cast<AnnotationUsecase>(annotation_usecase);
147 options.location_context = {user_location_lat, user_location_lng,
148 user_location_accuracy_meters};
149 options.use_pod_ner = use_pod_ner;
150 options.use_vocab_annotator = use_vocab_annotator;
151 return options;
152 }
153 } // namespace
154
FromJavaSelectionOptions(JNIEnv * env,jobject joptions)155 StatusOr<SelectionOptions> FromJavaSelectionOptions(JNIEnv* env,
156 jobject joptions) {
157 if (!joptions) {
158 // Falling back to default options in case joptions is null
159 SelectionOptions default_selection_options;
160 return default_selection_options;
161 }
162
163 TC3_ASSIGN_OR_RETURN(
164 ScopedLocalRef<jclass> options_class,
165 JniHelper::FindClass(env, TC3_PACKAGE_PATH TC3_ANNOTATOR_CLASS_NAME_STR
166 "$SelectionOptions"));
167
168 // .getLocale()
169 TC3_ASSIGN_OR_RETURN(
170 jmethodID get_locales,
171 JniHelper::GetMethodID(env, options_class.get(), "getLocales",
172 "()Ljava/lang/String;"));
173 TC3_ASSIGN_OR_RETURN(
174 ScopedLocalRef<jstring> locales,
175 JniHelper::CallObjectMethod<jstring>(env, joptions, get_locales));
176
177 // .getDetectedTextLanguageTags()
178 TC3_ASSIGN_OR_RETURN(jmethodID get_detected_text_language_tags_method,
179 JniHelper::GetMethodID(env, options_class.get(),
180 "getDetectedTextLanguageTags",
181 "()Ljava/lang/String;"));
182 TC3_ASSIGN_OR_RETURN(
183 ScopedLocalRef<jstring> detected_text_language_tags,
184 JniHelper::CallObjectMethod<jstring>(
185 env, joptions, get_detected_text_language_tags_method));
186
187 // .getAnnotationUsecase()
188 TC3_ASSIGN_OR_RETURN(jmethodID get_annotation_usecase,
189 JniHelper::GetMethodID(env, options_class.get(),
190 "getAnnotationUsecase", "()I"));
191 TC3_ASSIGN_OR_RETURN(
192 int32 annotation_usecase,
193 JniHelper::CallIntMethod(env, joptions, get_annotation_usecase));
194
195 // .getUserLocationLat()
196 TC3_ASSIGN_OR_RETURN(jmethodID get_user_location_lat,
197 JniHelper::GetMethodID(env, options_class.get(),
198 "getUserLocationLat", "()D"));
199 TC3_ASSIGN_OR_RETURN(
200 double user_location_lat,
201 JniHelper::CallDoubleMethod(env, joptions, get_user_location_lat));
202
203 // .getUserLocationLng()
204 TC3_ASSIGN_OR_RETURN(jmethodID get_user_location_lng,
205 JniHelper::GetMethodID(env, options_class.get(),
206 "getUserLocationLng", "()D"));
207 TC3_ASSIGN_OR_RETURN(
208 double user_location_lng,
209 JniHelper::CallDoubleMethod(env, joptions, get_user_location_lng));
210
211 // .getUserLocationAccuracyMeters()
212 TC3_ASSIGN_OR_RETURN(
213 jmethodID get_user_location_accuracy_meters,
214 JniHelper::GetMethodID(env, options_class.get(),
215 "getUserLocationAccuracyMeters", "()F"));
216 TC3_ASSIGN_OR_RETURN(float user_location_accuracy_meters,
217 JniHelper::CallFloatMethod(
218 env, joptions, get_user_location_accuracy_meters));
219
220 // .getUsePodNer()
221 TC3_ASSIGN_OR_RETURN(
222 jmethodID get_use_pod_ner,
223 JniHelper::GetMethodID(env, options_class.get(), "getUsePodNer", "()Z"));
224 TC3_ASSIGN_OR_RETURN(bool use_pod_ner, JniHelper::CallBooleanMethod(
225 env, joptions, get_use_pod_ner));
226
227 SelectionOptions options;
228 TC3_ASSIGN_OR_RETURN(options.locales,
229 JStringToUtf8String(env, locales.get()));
230 options.annotation_usecase =
231 static_cast<AnnotationUsecase>(annotation_usecase);
232 TC3_ASSIGN_OR_RETURN(
233 options.detected_text_language_tags,
234 JStringToUtf8String(env, detected_text_language_tags.get()));
235 options.location_context = {user_location_lat, user_location_lng,
236 user_location_accuracy_meters};
237 options.use_pod_ner = use_pod_ner;
238 return options;
239 }
240
FromJavaClassificationOptions(JNIEnv * env,jobject joptions)241 StatusOr<ClassificationOptions> FromJavaClassificationOptions(
242 JNIEnv* env, jobject joptions) {
243 if (!joptions) {
244 // Falling back to default options in case joptions is null
245 ClassificationOptions default_classification_options;
246 return default_classification_options;
247 }
248
249 TC3_ASSIGN_OR_RETURN(ClassificationOptions classifier_options,
250 FromJavaOptionsInternal<ClassificationOptions>(
251 env, joptions,
252 TC3_PACKAGE_PATH TC3_ANNOTATOR_CLASS_NAME_STR
253 "$ClassificationOptions"));
254
255 TC3_ASSIGN_OR_RETURN(
256 ScopedLocalRef<jclass> options_class,
257 JniHelper::FindClass(env, TC3_PACKAGE_PATH TC3_ANNOTATOR_CLASS_NAME_STR
258 "$ClassificationOptions"));
259 // .getUserFamiliarLanguageTags()
260 TC3_ASSIGN_OR_RETURN(jmethodID get_user_familiar_language_tags,
261 JniHelper::GetMethodID(env, options_class.get(),
262 "getUserFamiliarLanguageTags",
263 "()Ljava/lang/String;"));
264 TC3_ASSIGN_OR_RETURN(ScopedLocalRef<jstring> user_familiar_language_tags,
265 JniHelper::CallObjectMethod<jstring>(
266 env, joptions, get_user_familiar_language_tags));
267
268 TC3_ASSIGN_OR_RETURN(
269 classifier_options.user_familiar_language_tags,
270 JStringToUtf8String(env, user_familiar_language_tags.get()));
271
272 // .getTriggerDictionaryOnBeginnerWords()
273 TC3_ASSIGN_OR_RETURN(
274 jmethodID get_trigger_dictionary_on_beginner_words,
275 JniHelper::GetMethodID(env, options_class.get(),
276 "getTriggerDictionaryOnBeginnerWords", "()Z"));
277 TC3_ASSIGN_OR_RETURN(
278 classifier_options.trigger_dictionary_on_beginner_words,
279 JniHelper::CallBooleanMethod(env, joptions,
280 get_trigger_dictionary_on_beginner_words));
281
282 // .getEnableAddContactIntent()
283 TC3_ASSIGN_OR_RETURN(
284 jmethodID get_enable_add_contact_intent,
285 JniHelper::GetMethodID(env, options_class.get(),
286 "getEnableAddContactIntent", "()Z"));
287 TC3_ASSIGN_OR_RETURN(classifier_options.enable_add_contact_intent,
288 JniHelper::CallBooleanMethod(
289 env, joptions, get_enable_add_contact_intent));
290
291 // .getEnableSearchIntent()
292 TC3_ASSIGN_OR_RETURN(jmethodID get_enable_search_intent,
293 JniHelper::GetMethodID(env, options_class.get(),
294 "getEnableSearchIntent", "()Z"));
295 TC3_ASSIGN_OR_RETURN(
296 classifier_options.enable_search_intent,
297 JniHelper::CallBooleanMethod(env, joptions, get_enable_search_intent));
298
299 return classifier_options;
300 }
301
FromJavaAnnotationOptions(JNIEnv * env,jobject joptions)302 StatusOr<AnnotationOptions> FromJavaAnnotationOptions(JNIEnv* env,
303 jobject joptions) {
304 if (!joptions) {
305 // Falling back to default options in case joptions is null
306 AnnotationOptions default_annotation_options;
307 return default_annotation_options;
308 }
309
310 TC3_ASSIGN_OR_RETURN(
311 ScopedLocalRef<jclass> options_class,
312 JniHelper::FindClass(env, TC3_PACKAGE_PATH TC3_ANNOTATOR_CLASS_NAME_STR
313 "$AnnotationOptions"));
314
315 // .getEntityTypes()
316 TC3_ASSIGN_OR_RETURN(
317 jmethodID get_entity_types,
318 JniHelper::GetMethodID(env, options_class.get(), "getEntityTypes",
319 "()[Ljava/lang/String;"));
320 TC3_ASSIGN_OR_RETURN(
321 ScopedLocalRef<jobject> entity_types,
322 JniHelper::CallObjectMethod<jobject>(env, joptions, get_entity_types));
323
324 // .isSerializedEntityDataEnabled()
325 TC3_ASSIGN_OR_RETURN(
326 jmethodID is_serialized_entity_data_enabled_method,
327 JniHelper::GetMethodID(env, options_class.get(),
328 "isSerializedEntityDataEnabled", "()Z"));
329 TC3_ASSIGN_OR_RETURN(
330 bool is_serialized_entity_data_enabled,
331 JniHelper::CallBooleanMethod(env, joptions,
332 is_serialized_entity_data_enabled_method));
333
334 // .hasLocationPermission()
335 TC3_ASSIGN_OR_RETURN(jmethodID has_location_permission_method,
336 JniHelper::GetMethodID(env, options_class.get(),
337 "hasLocationPermission", "()Z"));
338 TC3_ASSIGN_OR_RETURN(bool has_location_permission,
339 JniHelper::CallBooleanMethod(
340 env, joptions, has_location_permission_method));
341
342 // .hasPersonalizationPermission()
343 TC3_ASSIGN_OR_RETURN(
344 jmethodID has_personalization_permission_method,
345 JniHelper::GetMethodID(env, options_class.get(),
346 "hasPersonalizationPermission", "()Z"));
347 TC3_ASSIGN_OR_RETURN(
348 bool has_personalization_permission,
349 JniHelper::CallBooleanMethod(env, joptions,
350 has_personalization_permission_method));
351 // .getAnnotateMode()
352 TC3_ASSIGN_OR_RETURN(jmethodID get_annotate_mode,
353 JniHelper::GetMethodID(env, options_class.get(),
354 "getAnnotateMode", "()I"));
355 TC3_ASSIGN_OR_RETURN(
356 int32 annotate_mode,
357 JniHelper::CallIntMethod(env, joptions, get_annotate_mode));
358
359 TC3_ASSIGN_OR_RETURN(
360 AnnotationOptions annotation_options,
361 FromJavaOptionsInternal<AnnotationOptions>(
362 env, joptions,
363 TC3_PACKAGE_PATH TC3_ANNOTATOR_CLASS_NAME_STR "$AnnotationOptions"));
364 TC3_ASSIGN_OR_RETURN(annotation_options.entity_types,
365 EntityTypesFromJObject(env, entity_types.get()));
366 annotation_options.is_serialized_entity_data_enabled =
367 is_serialized_entity_data_enabled;
368 annotation_options.permissions.has_location_permission =
369 has_location_permission;
370 annotation_options.permissions.has_personalization_permission =
371 has_personalization_permission;
372 annotation_options.annotate_mode = static_cast<AnnotateMode>(annotate_mode);
373
374 // .getTriggerDictionaryOnBeginnerWords()
375 TC3_ASSIGN_OR_RETURN(
376 jmethodID get_trigger_dictionary_on_beginner_words,
377 JniHelper::GetMethodID(env, options_class.get(),
378 "getTriggerDictionaryOnBeginnerWords", "()Z"));
379 TC3_ASSIGN_OR_RETURN(
380 annotation_options.trigger_dictionary_on_beginner_words,
381 JniHelper::CallBooleanMethod(env, joptions,
382 get_trigger_dictionary_on_beginner_words));
383 return annotation_options;
384 }
385
FromJavaInputFragment(JNIEnv * env,jobject jfragment)386 StatusOr<InputFragment> FromJavaInputFragment(JNIEnv* env, jobject jfragment) {
387 if (!jfragment) {
388 return Status(StatusCode::INTERNAL, "Called with null input fragment.");
389 }
390 InputFragment fragment;
391
392 TC3_ASSIGN_OR_RETURN(
393 ScopedLocalRef<jclass> fragment_class,
394 JniHelper::FindClass(
395 env, TC3_PACKAGE_PATH TC3_ANNOTATOR_CLASS_NAME_STR "$InputFragment"));
396
397 // .getText()
398 TC3_ASSIGN_OR_RETURN(
399 jmethodID get_text,
400 JniHelper::GetMethodID(env, fragment_class.get(), "getText",
401 "()Ljava/lang/String;"));
402
403 TC3_ASSIGN_OR_RETURN(
404 ScopedLocalRef<jstring> text,
405 JniHelper::CallObjectMethod<jstring>(env, jfragment, get_text));
406
407 TC3_ASSIGN_OR_RETURN(fragment.text, JStringToUtf8String(env, text.get()));
408
409 // .hasDatetimeOptions()
410 TC3_ASSIGN_OR_RETURN(jmethodID has_date_time_options_method,
411 JniHelper::GetMethodID(env, fragment_class.get(),
412 "hasDatetimeOptions", "()Z"));
413
414 TC3_ASSIGN_OR_RETURN(bool has_date_time_options,
415 JniHelper::CallBooleanMethod(
416 env, jfragment, has_date_time_options_method));
417
418 if (has_date_time_options) {
419 // .getReferenceTimeMsUtc()
420 TC3_ASSIGN_OR_RETURN(
421 jmethodID get_reference_time_method,
422 JniHelper::GetMethodID(env, fragment_class.get(),
423 "getReferenceTimeMsUtc", "()J"));
424
425 TC3_ASSIGN_OR_RETURN(
426 int64 reference_time,
427 JniHelper::CallLongMethod(env, jfragment, get_reference_time_method));
428
429 // .getReferenceTimezone()
430 TC3_ASSIGN_OR_RETURN(
431 jmethodID get_reference_timezone_method,
432 JniHelper::GetMethodID(env, fragment_class.get(),
433 "getReferenceTimezone", "()Ljava/lang/String;"));
434
435 TC3_ASSIGN_OR_RETURN(ScopedLocalRef<jstring> jreference_timezone,
436 JniHelper::CallObjectMethod<jstring>(
437 env, jfragment, get_reference_timezone_method));
438
439 TC3_ASSIGN_OR_RETURN(std::string reference_timezone,
440 JStringToUtf8String(env, jreference_timezone.get()));
441
442 fragment.datetime_options =
443 DatetimeOptions{.reference_time_ms_utc = reference_time,
444 .reference_timezone = reference_timezone};
445 }
446
447 // .getBoundingBoxHeight()
448 TC3_ASSIGN_OR_RETURN(jmethodID get_bounding_box_height,
449 JniHelper::GetMethodID(env, fragment_class.get(),
450 "getBoundingBoxHeight", "()F"));
451 TC3_ASSIGN_OR_RETURN(
452 float bounding_box_height,
453 JniHelper::CallFloatMethod(env, jfragment, get_bounding_box_height));
454
455 fragment.bounding_box_height = bounding_box_height;
456
457 // .getBoundingBoxTop()
458 TC3_ASSIGN_OR_RETURN(jmethodID get_bounding_box_top,
459 JniHelper::GetMethodID(env, fragment_class.get(),
460 "getBoundingBoxTop", "()F"));
461 TC3_ASSIGN_OR_RETURN(
462 float bounding_box_top,
463 JniHelper::CallFloatMethod(env, jfragment, get_bounding_box_top));
464 fragment.bounding_box_top = bounding_box_top;
465 return fragment;
466 }
467 } // namespace libtextclassifier3
468