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 return classifier_options;
283 }
284
FromJavaAnnotationOptions(JNIEnv * env,jobject joptions)285 StatusOr<AnnotationOptions> FromJavaAnnotationOptions(JNIEnv* env,
286 jobject joptions) {
287 if (!joptions) {
288 // Falling back to default options in case joptions is null
289 AnnotationOptions default_annotation_options;
290 return default_annotation_options;
291 }
292
293 TC3_ASSIGN_OR_RETURN(
294 ScopedLocalRef<jclass> options_class,
295 JniHelper::FindClass(env, TC3_PACKAGE_PATH TC3_ANNOTATOR_CLASS_NAME_STR
296 "$AnnotationOptions"));
297
298 // .getEntityTypes()
299 TC3_ASSIGN_OR_RETURN(
300 jmethodID get_entity_types,
301 JniHelper::GetMethodID(env, options_class.get(), "getEntityTypes",
302 "()[Ljava/lang/String;"));
303 TC3_ASSIGN_OR_RETURN(
304 ScopedLocalRef<jobject> entity_types,
305 JniHelper::CallObjectMethod<jobject>(env, joptions, get_entity_types));
306
307 // .isSerializedEntityDataEnabled()
308 TC3_ASSIGN_OR_RETURN(
309 jmethodID is_serialized_entity_data_enabled_method,
310 JniHelper::GetMethodID(env, options_class.get(),
311 "isSerializedEntityDataEnabled", "()Z"));
312 TC3_ASSIGN_OR_RETURN(
313 bool is_serialized_entity_data_enabled,
314 JniHelper::CallBooleanMethod(env, joptions,
315 is_serialized_entity_data_enabled_method));
316
317 // .hasLocationPermission()
318 TC3_ASSIGN_OR_RETURN(jmethodID has_location_permission_method,
319 JniHelper::GetMethodID(env, options_class.get(),
320 "hasLocationPermission", "()Z"));
321 TC3_ASSIGN_OR_RETURN(bool has_location_permission,
322 JniHelper::CallBooleanMethod(
323 env, joptions, has_location_permission_method));
324
325 // .hasPersonalizationPermission()
326 TC3_ASSIGN_OR_RETURN(
327 jmethodID has_personalization_permission_method,
328 JniHelper::GetMethodID(env, options_class.get(),
329 "hasPersonalizationPermission", "()Z"));
330 TC3_ASSIGN_OR_RETURN(
331 bool has_personalization_permission,
332 JniHelper::CallBooleanMethod(env, joptions,
333 has_personalization_permission_method));
334 // .getAnnotateMode()
335 TC3_ASSIGN_OR_RETURN(jmethodID get_annotate_mode,
336 JniHelper::GetMethodID(env, options_class.get(),
337 "getAnnotateMode", "()I"));
338 TC3_ASSIGN_OR_RETURN(
339 int32 annotate_mode,
340 JniHelper::CallIntMethod(env, joptions, get_annotate_mode));
341
342 TC3_ASSIGN_OR_RETURN(
343 AnnotationOptions annotation_options,
344 FromJavaOptionsInternal<AnnotationOptions>(
345 env, joptions,
346 TC3_PACKAGE_PATH TC3_ANNOTATOR_CLASS_NAME_STR "$AnnotationOptions"));
347 TC3_ASSIGN_OR_RETURN(annotation_options.entity_types,
348 EntityTypesFromJObject(env, entity_types.get()));
349 annotation_options.is_serialized_entity_data_enabled =
350 is_serialized_entity_data_enabled;
351 annotation_options.permissions.has_location_permission =
352 has_location_permission;
353 annotation_options.permissions.has_personalization_permission =
354 has_personalization_permission;
355 annotation_options.annotate_mode = static_cast<AnnotateMode>(annotate_mode);
356
357 // .getTriggerDictionaryOnBeginnerWords()
358 TC3_ASSIGN_OR_RETURN(
359 jmethodID get_trigger_dictionary_on_beginner_words,
360 JniHelper::GetMethodID(env, options_class.get(),
361 "getTriggerDictionaryOnBeginnerWords", "()Z"));
362 TC3_ASSIGN_OR_RETURN(
363 annotation_options.trigger_dictionary_on_beginner_words,
364 JniHelper::CallBooleanMethod(env, joptions,
365 get_trigger_dictionary_on_beginner_words));
366 return annotation_options;
367 }
368
FromJavaInputFragment(JNIEnv * env,jobject jfragment)369 StatusOr<InputFragment> FromJavaInputFragment(JNIEnv* env, jobject jfragment) {
370 if (!jfragment) {
371 return Status(StatusCode::INTERNAL, "Called with null input fragment.");
372 }
373 InputFragment fragment;
374
375 TC3_ASSIGN_OR_RETURN(
376 ScopedLocalRef<jclass> fragment_class,
377 JniHelper::FindClass(
378 env, TC3_PACKAGE_PATH TC3_ANNOTATOR_CLASS_NAME_STR "$InputFragment"));
379
380 // .getText()
381 TC3_ASSIGN_OR_RETURN(
382 jmethodID get_text,
383 JniHelper::GetMethodID(env, fragment_class.get(), "getText",
384 "()Ljava/lang/String;"));
385
386 TC3_ASSIGN_OR_RETURN(
387 ScopedLocalRef<jstring> text,
388 JniHelper::CallObjectMethod<jstring>(env, jfragment, get_text));
389
390 TC3_ASSIGN_OR_RETURN(fragment.text, JStringToUtf8String(env, text.get()));
391
392 // .hasDatetimeOptions()
393 TC3_ASSIGN_OR_RETURN(jmethodID has_date_time_options_method,
394 JniHelper::GetMethodID(env, fragment_class.get(),
395 "hasDatetimeOptions", "()Z"));
396
397 TC3_ASSIGN_OR_RETURN(bool has_date_time_options,
398 JniHelper::CallBooleanMethod(
399 env, jfragment, has_date_time_options_method));
400
401 if (has_date_time_options) {
402 // .getReferenceTimeMsUtc()
403 TC3_ASSIGN_OR_RETURN(
404 jmethodID get_reference_time_method,
405 JniHelper::GetMethodID(env, fragment_class.get(),
406 "getReferenceTimeMsUtc", "()J"));
407
408 TC3_ASSIGN_OR_RETURN(
409 int64 reference_time,
410 JniHelper::CallLongMethod(env, jfragment, get_reference_time_method));
411
412 // .getReferenceTimezone()
413 TC3_ASSIGN_OR_RETURN(
414 jmethodID get_reference_timezone_method,
415 JniHelper::GetMethodID(env, fragment_class.get(),
416 "getReferenceTimezone", "()Ljava/lang/String;"));
417
418 TC3_ASSIGN_OR_RETURN(ScopedLocalRef<jstring> jreference_timezone,
419 JniHelper::CallObjectMethod<jstring>(
420 env, jfragment, get_reference_timezone_method));
421
422 TC3_ASSIGN_OR_RETURN(std::string reference_timezone,
423 JStringToUtf8String(env, jreference_timezone.get()));
424
425 fragment.datetime_options =
426 DatetimeOptions{.reference_time_ms_utc = reference_time,
427 .reference_timezone = reference_timezone};
428 }
429
430 // .getBoundingBoxHeight()
431 TC3_ASSIGN_OR_RETURN(jmethodID get_bounding_box_height,
432 JniHelper::GetMethodID(env, fragment_class.get(),
433 "getBoundingBoxHeight", "()F"));
434 TC3_ASSIGN_OR_RETURN(
435 float bounding_box_height,
436 JniHelper::CallFloatMethod(env, jfragment, get_bounding_box_height));
437
438 fragment.bounding_box_height = bounding_box_height;
439
440 // .getBoundingBoxTop()
441 TC3_ASSIGN_OR_RETURN(jmethodID get_bounding_box_top,
442 JniHelper::GetMethodID(env, fragment_class.get(),
443 "getBoundingBoxTop", "()F"));
444 TC3_ASSIGN_OR_RETURN(
445 float bounding_box_top,
446 JniHelper::CallFloatMethod(env, jfragment, get_bounding_box_top));
447 fragment.bounding_box_top = bounding_box_top;
448 return fragment;
449 }
450 } // namespace libtextclassifier3
451