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