/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "utils/intents/jni.h" #include #include "utils/base/status_macros.h" #include "utils/base/statusor.h" #include "utils/java/jni-base.h" #include "utils/java/jni-helper.h" namespace libtextclassifier3 { // The macros below are intended to reduce the boilerplate and avoid // easily introduced copy/paste errors. #define TC3_CHECK_JNI_PTR(PTR) TC3_CHECK((PTR) != nullptr) #define TC3_GET_CLASS(FIELD, NAME) \ { \ TC3_ASSIGN_OR_RETURN(ScopedLocalRef clazz, \ JniHelper::FindClass(env, NAME)); \ handler->FIELD = MakeGlobalRef(clazz.release(), env, jni_cache->jvm); \ TC3_CHECK_JNI_PTR(handler->FIELD) << "Error finding class: " << NAME; \ } #define TC3_GET_METHOD(CLASS, FIELD, NAME, SIGNATURE) \ TC3_ASSIGN_OR_RETURN( \ handler->FIELD, \ JniHelper::GetMethodID(env, handler->CLASS.get(), NAME, SIGNATURE)); StatusOr> RemoteActionTemplatesHandler::Create( const std::shared_ptr& jni_cache) { JNIEnv* env = jni_cache->GetEnv(); if (env == nullptr) { return nullptr; } std::unique_ptr handler( new RemoteActionTemplatesHandler(jni_cache)); TC3_GET_CLASS(integer_class_, "java/lang/Integer"); TC3_GET_METHOD(integer_class_, integer_init_, "", "(I)V"); TC3_GET_CLASS(remote_action_template_class_, TC3_PACKAGE_PATH TC3_REMOTE_ACTION_TEMPLATE_CLASS_NAME_STR); TC3_GET_METHOD( remote_action_template_class_, remote_action_template_init_, "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/" "String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/" "Integer;[Ljava/lang/String;Ljava/lang/String;[L" TC3_PACKAGE_PATH TC3_NAMED_VARIANT_CLASS_NAME_STR ";Ljava/lang/Integer;)V"); TC3_GET_CLASS(named_variant_class_, TC3_PACKAGE_PATH TC3_NAMED_VARIANT_CLASS_NAME_STR); TC3_GET_METHOD(named_variant_class_, named_variant_from_int_, "", "(Ljava/lang/String;I)V"); TC3_GET_METHOD(named_variant_class_, named_variant_from_long_, "", "(Ljava/lang/String;J)V"); TC3_GET_METHOD(named_variant_class_, named_variant_from_float_, "", "(Ljava/lang/String;F)V"); TC3_GET_METHOD(named_variant_class_, named_variant_from_double_, "", "(Ljava/lang/String;D)V"); TC3_GET_METHOD(named_variant_class_, named_variant_from_bool_, "", "(Ljava/lang/String;Z)V"); TC3_GET_METHOD(named_variant_class_, named_variant_from_string_, "", "(Ljava/lang/String;Ljava/lang/String;)V"); TC3_GET_METHOD(named_variant_class_, named_variant_from_string_array_, "", "(Ljava/lang/String;[Ljava/lang/String;)V"); TC3_GET_METHOD(named_variant_class_, named_variant_from_float_array_, "", "(Ljava/lang/String;[F)V"); TC3_GET_METHOD(named_variant_class_, named_variant_from_int_array_, "", "(Ljava/lang/String;[I)V"); TC3_GET_METHOD( named_variant_class_, named_variant_from_named_variant_array_, "", "(Ljava/lang/String;[L" TC3_PACKAGE_PATH TC3_NAMED_VARIANT_CLASS_NAME_STR ";)V"); return handler; } StatusOr> RemoteActionTemplatesHandler::AsUTF8String( const Optional& optional) const { if (!optional.has_value()) { return {{nullptr, jni_cache_->GetEnv()}}; } return jni_cache_->ConvertToJavaString(optional.value()); } StatusOr> RemoteActionTemplatesHandler::AsInteger( const Optional& optional) const { if (!optional.has_value()) { return {{nullptr, jni_cache_->GetEnv()}}; } TC3_ASSIGN_OR_RETURN( ScopedLocalRef result, JniHelper::NewObject(jni_cache_->GetEnv(), integer_class_.get(), integer_init_, optional.value())); return result; } StatusOr> RemoteActionTemplatesHandler::AsStringArray( const std::vector& values) const { if (values.empty()) { return {{nullptr, jni_cache_->GetEnv()}}; } TC3_ASSIGN_OR_RETURN( ScopedLocalRef result, JniHelper::NewObjectArray(jni_cache_->GetEnv(), values.size(), jni_cache_->string_class.get(), nullptr)); for (int k = 0; k < values.size(); k++) { TC3_ASSIGN_OR_RETURN(ScopedLocalRef value_str, jni_cache_->ConvertToJavaString(values[k])); TC3_RETURN_IF_ERROR(JniHelper::SetObjectArrayElement( jni_cache_->GetEnv(), result.get(), k, value_str.get())); } return result; } StatusOr> RemoteActionTemplatesHandler::AsFloatArray( const std::vector& values) const { if (values.empty()) { return {{nullptr, jni_cache_->GetEnv()}}; } TC3_ASSIGN_OR_RETURN( ScopedLocalRef result, JniHelper::NewFloatArray(jni_cache_->GetEnv(), values.size())); TC3_RETURN_IF_ERROR(JniHelper::SetFloatArrayRegion( jni_cache_->GetEnv(), result.get(), /*start=*/0, /*len=*/values.size(), &(values[0]))); return result; } StatusOr> RemoteActionTemplatesHandler::AsIntArray( const std::vector& values) const { if (values.empty()) { return {{nullptr, jni_cache_->GetEnv()}}; } TC3_ASSIGN_OR_RETURN( ScopedLocalRef result, JniHelper::NewIntArray(jni_cache_->GetEnv(), values.size())); TC3_RETURN_IF_ERROR(JniHelper::SetIntArrayRegion( jni_cache_->GetEnv(), result.get(), /*start=*/0, /*len=*/values.size(), &(values[0]))); return result; } StatusOr> RemoteActionTemplatesHandler::AsNamedVariant( const std::string& name_str, const Variant& value) const { TC3_ASSIGN_OR_RETURN(ScopedLocalRef name, jni_cache_->ConvertToJavaString(name_str)); JNIEnv* env = jni_cache_->GetEnv(); switch (value.GetType()) { case Variant::TYPE_INT_VALUE: return JniHelper::NewObject(env, named_variant_class_.get(), named_variant_from_int_, name.get(), value.Value()); case Variant::TYPE_INT64_VALUE: return JniHelper::NewObject(env, named_variant_class_.get(), named_variant_from_long_, name.get(), value.Value()); case Variant::TYPE_FLOAT_VALUE: return JniHelper::NewObject(env, named_variant_class_.get(), named_variant_from_float_, name.get(), value.Value()); case Variant::TYPE_DOUBLE_VALUE: return JniHelper::NewObject(env, named_variant_class_.get(), named_variant_from_double_, name.get(), value.Value()); case Variant::TYPE_BOOL_VALUE: return JniHelper::NewObject(env, named_variant_class_.get(), named_variant_from_bool_, name.get(), value.Value()); case Variant::TYPE_STRING_VALUE: { TC3_ASSIGN_OR_RETURN( ScopedLocalRef value_jstring, jni_cache_->ConvertToJavaString(value.ConstRefValue())); return JniHelper::NewObject(env, named_variant_class_.get(), named_variant_from_string_, name.get(), value_jstring.get()); } case Variant::TYPE_STRING_VECTOR_VALUE: { TC3_ASSIGN_OR_RETURN( ScopedLocalRef value_jstring_array, AsStringArray(value.ConstRefValue>())); return JniHelper::NewObject(env, named_variant_class_.get(), named_variant_from_string_array_, name.get(), value_jstring_array.get()); } case Variant::TYPE_FLOAT_VECTOR_VALUE: { TC3_ASSIGN_OR_RETURN( ScopedLocalRef value_jfloat_array, AsFloatArray(value.ConstRefValue>())); return JniHelper::NewObject(env, named_variant_class_.get(), named_variant_from_float_array_, name.get(), value_jfloat_array.get()); } case Variant::TYPE_INT_VECTOR_VALUE: { TC3_ASSIGN_OR_RETURN(ScopedLocalRef value_jint_array, AsIntArray(value.ConstRefValue>())); return JniHelper::NewObject(env, named_variant_class_.get(), named_variant_from_int_array_, name.get(), value_jint_array.get()); } case Variant::TYPE_STRING_VARIANT_MAP_VALUE: { TC3_ASSIGN_OR_RETURN( ScopedLocalRef value_jobect_array, AsNamedVariantArray( value.ConstRefValue>())); return JniHelper::NewObject(env, named_variant_class_.get(), named_variant_from_named_variant_array_, name.get(), value_jobect_array.get()); } case Variant::TYPE_EMPTY: return {Status::UNKNOWN}; default: TC3_LOG(ERROR) << "Unsupported NamedVariant type: " << value.GetType(); return {Status::UNKNOWN}; } } StatusOr> RemoteActionTemplatesHandler::AsNamedVariantArray( const std::map& values) const { JNIEnv* env = jni_cache_->GetEnv(); if (values.empty()) { return {{nullptr, env}}; } TC3_ASSIGN_OR_RETURN( ScopedLocalRef result, JniHelper::NewObjectArray(jni_cache_->GetEnv(), values.size(), named_variant_class_.get(), nullptr)); int element_index = 0; for (const auto& key_value_pair : values) { if (!key_value_pair.second.HasValue()) { element_index++; continue; } TC3_ASSIGN_OR_RETURN( StatusOr> named_extra, AsNamedVariant(key_value_pair.first, key_value_pair.second)); TC3_RETURN_IF_ERROR(JniHelper::SetObjectArrayElement( env, result.get(), element_index, named_extra.ValueOrDie().get())); element_index++; } return result; } StatusOr> RemoteActionTemplatesHandler::RemoteActionTemplatesToJObjectArray( const std::vector& remote_actions) const { JNIEnv* env = jni_cache_->GetEnv(); TC3_ASSIGN_OR_RETURN( ScopedLocalRef results, JniHelper::NewObjectArray(env, remote_actions.size(), remote_action_template_class_.get(), nullptr)); for (int i = 0; i < remote_actions.size(); i++) { const RemoteActionTemplate& remote_action = remote_actions[i]; TC3_ASSIGN_OR_RETURN( const StatusOr> title_without_entity, AsUTF8String(remote_action.title_without_entity)); TC3_ASSIGN_OR_RETURN( const StatusOr> title_with_entity, AsUTF8String(remote_action.title_with_entity)); TC3_ASSIGN_OR_RETURN(const StatusOr> description, AsUTF8String(remote_action.description)); TC3_ASSIGN_OR_RETURN( const StatusOr> description_with_app_name, AsUTF8String(remote_action.description_with_app_name)); TC3_ASSIGN_OR_RETURN(const StatusOr> action, AsUTF8String(remote_action.action)); TC3_ASSIGN_OR_RETURN(const StatusOr> data, AsUTF8String(remote_action.data)); TC3_ASSIGN_OR_RETURN(const StatusOr> type, AsUTF8String(remote_action.type)); TC3_ASSIGN_OR_RETURN(const StatusOr> flags, AsInteger(remote_action.flags)); TC3_ASSIGN_OR_RETURN(const StatusOr> category, AsStringArray(remote_action.category)); TC3_ASSIGN_OR_RETURN(const StatusOr> package, AsUTF8String(remote_action.package_name)); TC3_ASSIGN_OR_RETURN(const StatusOr> extra, AsNamedVariantArray(remote_action.extra)); TC3_ASSIGN_OR_RETURN(const StatusOr> request_code, AsInteger(remote_action.request_code)); TC3_ASSIGN_OR_RETURN( const ScopedLocalRef result, JniHelper::NewObject( env, remote_action_template_class_.get(), remote_action_template_init_, title_without_entity.ValueOrDie().get(), title_with_entity.ValueOrDie().get(), description.ValueOrDie().get(), description_with_app_name.ValueOrDie().get(), action.ValueOrDie().get(), data.ValueOrDie().get(), type.ValueOrDie().get(), flags.ValueOrDie().get(), category.ValueOrDie().get(), package.ValueOrDie().get(), extra.ValueOrDie().get(), request_code.ValueOrDie().get())); TC3_RETURN_IF_ERROR( JniHelper::SetObjectArrayElement(env, results.get(), i, result.get())); } return results; } StatusOr> RemoteActionTemplatesHandler::EntityDataAsNamedVariantArray( const reflection::Schema* entity_data_schema, const std::string& serialized_entity_data) const { MutableFlatbufferBuilder entity_data_builder(entity_data_schema); std::unique_ptr buffer = entity_data_builder.NewRoot(); buffer->MergeFromSerializedFlatbuffer(serialized_entity_data); std::map entity_data_map = buffer->AsFlatMap(); return AsNamedVariantArray(entity_data_map); } } // namespace libtextclassifier3