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 "utils/intents/jni.h"
18 
19 #include <memory>
20 
21 #include "utils/base/status_macros.h"
22 #include "utils/base/statusor.h"
23 #include "utils/java/jni-base.h"
24 #include "utils/java/jni-helper.h"
25 
26 namespace libtextclassifier3 {
27 
28 // The macros below are intended to reduce the boilerplate and avoid
29 // easily introduced copy/paste errors.
30 #define TC3_CHECK_JNI_PTR(PTR) TC3_CHECK((PTR) != nullptr)
31 #define TC3_GET_CLASS(FIELD, NAME)                                        \
32   {                                                                       \
33     TC3_ASSIGN_OR_RETURN(ScopedLocalRef<jclass> clazz,                    \
34                          JniHelper::FindClass(env, NAME));                \
35     handler->FIELD = MakeGlobalRef(clazz.release(), env, jni_cache->jvm); \
36     TC3_CHECK_JNI_PTR(handler->FIELD) << "Error finding class: " << NAME; \
37   }
38 #define TC3_GET_METHOD(CLASS, FIELD, NAME, SIGNATURE) \
39   TC3_ASSIGN_OR_RETURN(                               \
40       handler->FIELD,                                 \
41       JniHelper::GetMethodID(env, handler->CLASS.get(), NAME, SIGNATURE));
42 
43 StatusOr<std::unique_ptr<RemoteActionTemplatesHandler>>
Create(const std::shared_ptr<JniCache> & jni_cache)44 RemoteActionTemplatesHandler::Create(
45     const std::shared_ptr<JniCache>& jni_cache) {
46   JNIEnv* env = jni_cache->GetEnv();
47   if (env == nullptr) {
48     return nullptr;
49   }
50 
51   std::unique_ptr<RemoteActionTemplatesHandler> handler(
52       new RemoteActionTemplatesHandler(jni_cache));
53 
54   TC3_GET_CLASS(integer_class_, "java/lang/Integer");
55   TC3_GET_METHOD(integer_class_, integer_init_, "<init>", "(I)V");
56 
57   TC3_GET_CLASS(remote_action_template_class_,
58                 TC3_PACKAGE_PATH TC3_REMOTE_ACTION_TEMPLATE_CLASS_NAME_STR);
59   TC3_GET_METHOD(
60       remote_action_template_class_, remote_action_template_init_, "<init>",
61       "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
62       "String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
63       "Integer;[Ljava/lang/String;Ljava/lang/String;[L" TC3_PACKAGE_PATH
64           TC3_NAMED_VARIANT_CLASS_NAME_STR ";Ljava/lang/Integer;)V");
65 
66   TC3_GET_CLASS(named_variant_class_,
67                 TC3_PACKAGE_PATH TC3_NAMED_VARIANT_CLASS_NAME_STR);
68 
69   TC3_GET_METHOD(named_variant_class_, named_variant_from_int_, "<init>",
70                  "(Ljava/lang/String;I)V");
71   TC3_GET_METHOD(named_variant_class_, named_variant_from_long_, "<init>",
72                  "(Ljava/lang/String;J)V");
73   TC3_GET_METHOD(named_variant_class_, named_variant_from_float_, "<init>",
74                  "(Ljava/lang/String;F)V");
75   TC3_GET_METHOD(named_variant_class_, named_variant_from_double_, "<init>",
76                  "(Ljava/lang/String;D)V");
77   TC3_GET_METHOD(named_variant_class_, named_variant_from_bool_, "<init>",
78                  "(Ljava/lang/String;Z)V");
79   TC3_GET_METHOD(named_variant_class_, named_variant_from_string_, "<init>",
80                  "(Ljava/lang/String;Ljava/lang/String;)V");
81   TC3_GET_METHOD(named_variant_class_, named_variant_from_string_array_,
82                  "<init>", "(Ljava/lang/String;[Ljava/lang/String;)V");
83   TC3_GET_METHOD(named_variant_class_, named_variant_from_float_array_,
84                  "<init>", "(Ljava/lang/String;[F)V");
85   TC3_GET_METHOD(named_variant_class_, named_variant_from_int_array_, "<init>",
86                  "(Ljava/lang/String;[I)V");
87   TC3_GET_METHOD(
88       named_variant_class_, named_variant_from_named_variant_array_, "<init>",
89       "(Ljava/lang/String;[L" TC3_PACKAGE_PATH TC3_NAMED_VARIANT_CLASS_NAME_STR
90       ";)V");
91   return handler;
92 }
93 
AsUTF8String(const Optional<std::string> & optional) const94 StatusOr<ScopedLocalRef<jstring>> RemoteActionTemplatesHandler::AsUTF8String(
95     const Optional<std::string>& optional) const {
96   if (!optional.has_value()) {
97     return {{nullptr, jni_cache_->GetEnv()}};
98   }
99   return jni_cache_->ConvertToJavaString(optional.value());
100 }
101 
AsInteger(const Optional<int> & optional) const102 StatusOr<ScopedLocalRef<jobject>> RemoteActionTemplatesHandler::AsInteger(
103     const Optional<int>& optional) const {
104   if (!optional.has_value()) {
105     return {{nullptr, jni_cache_->GetEnv()}};
106   }
107 
108   TC3_ASSIGN_OR_RETURN(
109       ScopedLocalRef<jobject> result,
110       JniHelper::NewObject(jni_cache_->GetEnv(), integer_class_.get(),
111                            integer_init_, optional.value()));
112 
113   return result;
114 }
115 
116 StatusOr<ScopedLocalRef<jobjectArray>>
AsStringArray(const std::vector<std::string> & values) const117 RemoteActionTemplatesHandler::AsStringArray(
118     const std::vector<std::string>& values) const {
119   if (values.empty()) {
120     return {{nullptr, jni_cache_->GetEnv()}};
121   }
122 
123   TC3_ASSIGN_OR_RETURN(
124       ScopedLocalRef<jobjectArray> result,
125       JniHelper::NewObjectArray(jni_cache_->GetEnv(), values.size(),
126                                 jni_cache_->string_class.get(), nullptr));
127 
128   for (int k = 0; k < values.size(); k++) {
129     TC3_ASSIGN_OR_RETURN(ScopedLocalRef<jstring> value_str,
130                          jni_cache_->ConvertToJavaString(values[k]));
131     TC3_RETURN_IF_ERROR(JniHelper::SetObjectArrayElement(
132         jni_cache_->GetEnv(), result.get(), k, value_str.get()));
133   }
134   return result;
135 }
136 
137 StatusOr<ScopedLocalRef<jfloatArray>>
AsFloatArray(const std::vector<float> & values) const138 RemoteActionTemplatesHandler::AsFloatArray(
139     const std::vector<float>& values) const {
140   if (values.empty()) {
141     return {{nullptr, jni_cache_->GetEnv()}};
142   }
143 
144   TC3_ASSIGN_OR_RETURN(
145       ScopedLocalRef<jfloatArray> result,
146       JniHelper::NewFloatArray(jni_cache_->GetEnv(), values.size()));
147 
148   TC3_RETURN_IF_ERROR(JniHelper::SetFloatArrayRegion(
149       jni_cache_->GetEnv(), result.get(), /*start=*/0,
150       /*len=*/values.size(), &(values[0])));
151   return result;
152 }
153 
AsIntArray(const std::vector<int> & values) const154 StatusOr<ScopedLocalRef<jintArray>> RemoteActionTemplatesHandler::AsIntArray(
155     const std::vector<int>& values) const {
156   if (values.empty()) {
157     return {{nullptr, jni_cache_->GetEnv()}};
158   }
159 
160   TC3_ASSIGN_OR_RETURN(
161       ScopedLocalRef<jintArray> result,
162       JniHelper::NewIntArray(jni_cache_->GetEnv(), values.size()));
163 
164   TC3_RETURN_IF_ERROR(JniHelper::SetIntArrayRegion(
165       jni_cache_->GetEnv(), result.get(), /*start=*/0,
166       /*len=*/values.size(), &(values[0])));
167   return result;
168 }
169 
AsNamedVariant(const std::string & name_str,const Variant & value) const170 StatusOr<ScopedLocalRef<jobject>> RemoteActionTemplatesHandler::AsNamedVariant(
171     const std::string& name_str, const Variant& value) const {
172   TC3_ASSIGN_OR_RETURN(ScopedLocalRef<jstring> name,
173                        jni_cache_->ConvertToJavaString(name_str));
174 
175   JNIEnv* env = jni_cache_->GetEnv();
176   switch (value.GetType()) {
177     case Variant::TYPE_INT_VALUE:
178       return JniHelper::NewObject(env, named_variant_class_.get(),
179                                   named_variant_from_int_, name.get(),
180                                   value.Value<int>());
181 
182     case Variant::TYPE_INT64_VALUE:
183       return JniHelper::NewObject(env, named_variant_class_.get(),
184                                   named_variant_from_long_, name.get(),
185                                   value.Value<int64>());
186 
187     case Variant::TYPE_FLOAT_VALUE:
188       return JniHelper::NewObject(env, named_variant_class_.get(),
189                                   named_variant_from_float_, name.get(),
190                                   value.Value<float>());
191 
192     case Variant::TYPE_DOUBLE_VALUE:
193       return JniHelper::NewObject(env, named_variant_class_.get(),
194                                   named_variant_from_double_, name.get(),
195                                   value.Value<double>());
196 
197     case Variant::TYPE_BOOL_VALUE:
198       return JniHelper::NewObject(env, named_variant_class_.get(),
199                                   named_variant_from_bool_, name.get(),
200                                   value.Value<bool>());
201 
202     case Variant::TYPE_STRING_VALUE: {
203       TC3_ASSIGN_OR_RETURN(
204           ScopedLocalRef<jstring> value_jstring,
205           jni_cache_->ConvertToJavaString(value.ConstRefValue<std::string>()));
206       return JniHelper::NewObject(env, named_variant_class_.get(),
207                                   named_variant_from_string_, name.get(),
208                                   value_jstring.get());
209     }
210 
211     case Variant::TYPE_STRING_VECTOR_VALUE: {
212       TC3_ASSIGN_OR_RETURN(
213           ScopedLocalRef<jobjectArray> value_jstring_array,
214           AsStringArray(value.ConstRefValue<std::vector<std::string>>()));
215 
216       return JniHelper::NewObject(env, named_variant_class_.get(),
217                                   named_variant_from_string_array_, name.get(),
218                                   value_jstring_array.get());
219     }
220 
221     case Variant::TYPE_FLOAT_VECTOR_VALUE: {
222       TC3_ASSIGN_OR_RETURN(
223           ScopedLocalRef<jfloatArray> value_jfloat_array,
224           AsFloatArray(value.ConstRefValue<std::vector<float>>()));
225 
226       return JniHelper::NewObject(env, named_variant_class_.get(),
227                                   named_variant_from_float_array_, name.get(),
228                                   value_jfloat_array.get());
229     }
230 
231     case Variant::TYPE_INT_VECTOR_VALUE: {
232       TC3_ASSIGN_OR_RETURN(ScopedLocalRef<jintArray> value_jint_array,
233                            AsIntArray(value.ConstRefValue<std::vector<int>>()));
234 
235       return JniHelper::NewObject(env, named_variant_class_.get(),
236                                   named_variant_from_int_array_, name.get(),
237                                   value_jint_array.get());
238     }
239 
240     case Variant::TYPE_STRING_VARIANT_MAP_VALUE: {
241       TC3_ASSIGN_OR_RETURN(
242           ScopedLocalRef<jobjectArray> value_jobect_array,
243           AsNamedVariantArray(
244               value.ConstRefValue<std::map<std::string, Variant>>()));
245       return JniHelper::NewObject(env, named_variant_class_.get(),
246                                   named_variant_from_named_variant_array_,
247                                   name.get(), value_jobect_array.get());
248     }
249 
250     case Variant::TYPE_EMPTY:
251       return {Status::UNKNOWN};
252 
253     default:
254       TC3_LOG(ERROR) << "Unsupported NamedVariant type: " << value.GetType();
255       return {Status::UNKNOWN};
256   }
257 }
258 
259 StatusOr<ScopedLocalRef<jobjectArray>>
AsNamedVariantArray(const std::map<std::string,Variant> & values) const260 RemoteActionTemplatesHandler::AsNamedVariantArray(
261     const std::map<std::string, Variant>& values) const {
262   JNIEnv* env = jni_cache_->GetEnv();
263   if (values.empty()) {
264     return {{nullptr, env}};
265   }
266 
267   TC3_ASSIGN_OR_RETURN(
268       ScopedLocalRef<jobjectArray> result,
269       JniHelper::NewObjectArray(jni_cache_->GetEnv(), values.size(),
270                                 named_variant_class_.get(), nullptr));
271   int element_index = 0;
272   for (const auto& key_value_pair : values) {
273     if (!key_value_pair.second.HasValue()) {
274       element_index++;
275       continue;
276     }
277     TC3_ASSIGN_OR_RETURN(
278         StatusOr<ScopedLocalRef<jobject>> named_extra,
279         AsNamedVariant(key_value_pair.first, key_value_pair.second));
280     TC3_RETURN_IF_ERROR(JniHelper::SetObjectArrayElement(
281         env, result.get(), element_index, named_extra.ValueOrDie().get()));
282     element_index++;
283   }
284   return result;
285 }
286 
287 StatusOr<ScopedLocalRef<jobjectArray>>
RemoteActionTemplatesToJObjectArray(const std::vector<RemoteActionTemplate> & remote_actions) const288 RemoteActionTemplatesHandler::RemoteActionTemplatesToJObjectArray(
289     const std::vector<RemoteActionTemplate>& remote_actions) const {
290   JNIEnv* env = jni_cache_->GetEnv();
291   TC3_ASSIGN_OR_RETURN(
292       ScopedLocalRef<jobjectArray> results,
293       JniHelper::NewObjectArray(env, remote_actions.size(),
294                                 remote_action_template_class_.get(), nullptr));
295 
296   for (int i = 0; i < remote_actions.size(); i++) {
297     const RemoteActionTemplate& remote_action = remote_actions[i];
298 
299     TC3_ASSIGN_OR_RETURN(
300         const StatusOr<ScopedLocalRef<jstring>> title_without_entity,
301         AsUTF8String(remote_action.title_without_entity));
302     TC3_ASSIGN_OR_RETURN(
303         const StatusOr<ScopedLocalRef<jstring>> title_with_entity,
304         AsUTF8String(remote_action.title_with_entity));
305     TC3_ASSIGN_OR_RETURN(const StatusOr<ScopedLocalRef<jstring>> description,
306                          AsUTF8String(remote_action.description));
307     TC3_ASSIGN_OR_RETURN(
308         const StatusOr<ScopedLocalRef<jstring>> description_with_app_name,
309         AsUTF8String(remote_action.description_with_app_name));
310     TC3_ASSIGN_OR_RETURN(const StatusOr<ScopedLocalRef<jstring>> action,
311                          AsUTF8String(remote_action.action));
312     TC3_ASSIGN_OR_RETURN(const StatusOr<ScopedLocalRef<jstring>> data,
313                          AsUTF8String(remote_action.data));
314     TC3_ASSIGN_OR_RETURN(const StatusOr<ScopedLocalRef<jstring>> type,
315                          AsUTF8String(remote_action.type));
316     TC3_ASSIGN_OR_RETURN(const StatusOr<ScopedLocalRef<jobject>> flags,
317                          AsInteger(remote_action.flags));
318     TC3_ASSIGN_OR_RETURN(const StatusOr<ScopedLocalRef<jobjectArray>> category,
319                          AsStringArray(remote_action.category));
320     TC3_ASSIGN_OR_RETURN(const StatusOr<ScopedLocalRef<jstring>> package,
321                          AsUTF8String(remote_action.package_name));
322     TC3_ASSIGN_OR_RETURN(const StatusOr<ScopedLocalRef<jobjectArray>> extra,
323                          AsNamedVariantArray(remote_action.extra));
324     TC3_ASSIGN_OR_RETURN(const StatusOr<ScopedLocalRef<jobject>> request_code,
325                          AsInteger(remote_action.request_code));
326 
327     TC3_ASSIGN_OR_RETURN(
328         const ScopedLocalRef<jobject> result,
329         JniHelper::NewObject(
330             env, remote_action_template_class_.get(),
331             remote_action_template_init_,
332             title_without_entity.ValueOrDie().get(),
333             title_with_entity.ValueOrDie().get(),
334             description.ValueOrDie().get(),
335             description_with_app_name.ValueOrDie().get(),
336             action.ValueOrDie().get(), data.ValueOrDie().get(),
337             type.ValueOrDie().get(), flags.ValueOrDie().get(),
338             category.ValueOrDie().get(), package.ValueOrDie().get(),
339             extra.ValueOrDie().get(), request_code.ValueOrDie().get()));
340     TC3_RETURN_IF_ERROR(
341         JniHelper::SetObjectArrayElement(env, results.get(), i, result.get()));
342   }
343   return results;
344 }
345 
346 StatusOr<ScopedLocalRef<jobjectArray>>
EntityDataAsNamedVariantArray(const reflection::Schema * entity_data_schema,const std::string & serialized_entity_data) const347 RemoteActionTemplatesHandler::EntityDataAsNamedVariantArray(
348     const reflection::Schema* entity_data_schema,
349     const std::string& serialized_entity_data) const {
350   MutableFlatbufferBuilder entity_data_builder(entity_data_schema);
351   std::unique_ptr<MutableFlatbuffer> buffer = entity_data_builder.NewRoot();
352   buffer->MergeFromSerializedFlatbuffer(serialized_entity_data);
353   std::map<std::string, Variant> entity_data_map = buffer->AsFlatMap();
354   return AsNamedVariantArray(entity_data_map);
355 }
356 
357 }  // namespace libtextclassifier3
358