普通文本  |  228行  |  9.45 KB

/*
 * 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 <memory>
#include "utils/intents/intent-generator.h"
#include "utils/java/scoped_local_ref.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)                                           \
  handler->FIELD = MakeGlobalRef(env->FindClass(NAME), env, jni_cache->jvm); \
  TC3_CHECK_JNI_PTR(handler->FIELD) << "Error finding class: " << NAME;
#define TC3_GET_METHOD(CLASS, FIELD, NAME, SIGNATURE)                       \
  handler->FIELD = env->GetMethodID(handler->CLASS.get(), NAME, SIGNATURE); \
  TC3_CHECK(handler->FIELD) << "Error finding method: " << NAME;

std::unique_ptr<RemoteActionTemplatesHandler>
RemoteActionTemplatesHandler::Create(
    const std::shared_ptr<JniCache>& jni_cache) {
  JNIEnv* env = jni_cache->GetEnv();
  if (env == nullptr) {
    return nullptr;
  }

  std::unique_ptr<RemoteActionTemplatesHandler> handler(
      new RemoteActionTemplatesHandler(jni_cache));

  TC3_GET_CLASS(integer_class_, "java/lang/Integer");
  TC3_GET_METHOD(integer_class_, integer_init_, "<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_, "<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_, "<init>",
                 "(Ljava/lang/String;I)V");
  TC3_GET_METHOD(named_variant_class_, named_variant_from_long_, "<init>",
                 "(Ljava/lang/String;J)V");
  TC3_GET_METHOD(named_variant_class_, named_variant_from_float_, "<init>",
                 "(Ljava/lang/String;F)V");
  TC3_GET_METHOD(named_variant_class_, named_variant_from_double_, "<init>",
                 "(Ljava/lang/String;D)V");
  TC3_GET_METHOD(named_variant_class_, named_variant_from_bool_, "<init>",
                 "(Ljava/lang/String;Z)V");
  TC3_GET_METHOD(named_variant_class_, named_variant_from_string_, "<init>",
                 "(Ljava/lang/String;Ljava/lang/String;)V");

  return handler;
}

jstring RemoteActionTemplatesHandler::AsUTF8String(
    const Optional<std::string>& optional) const {
  if (!optional.has_value()) {
    return nullptr;
  }
  return jni_cache_->ConvertToJavaString(optional.value()).release();
}

jobject RemoteActionTemplatesHandler::AsInteger(
    const Optional<int>& optional) const {
  return (optional.has_value()
              ? jni_cache_->GetEnv()->NewObject(integer_class_.get(),
                                                integer_init_, optional.value())
              : nullptr);
}

jobjectArray RemoteActionTemplatesHandler::AsStringArray(
    const std::vector<std::string>& values) const {
  if (values.empty()) {
    return nullptr;
  }
  jobjectArray result = jni_cache_->GetEnv()->NewObjectArray(
      values.size(), jni_cache_->string_class.get(), nullptr);
  if (result == nullptr) {
    return nullptr;
  }
  for (int k = 0; k < values.size(); k++) {
    ScopedLocalRef<jstring> value_str =
        jni_cache_->ConvertToJavaString(values[k]);
    jni_cache_->GetEnv()->SetObjectArrayElement(result, k, value_str.get());
  }
  return result;
}

jobject RemoteActionTemplatesHandler::AsNamedVariant(
    const std::string& name_str, const Variant& value) const {
  ScopedLocalRef<jstring> name = jni_cache_->ConvertToJavaString(name_str);
  if (name == nullptr) {
    return nullptr;
  }
  switch (value.GetType()) {
    case Variant::TYPE_INT_VALUE:
      return jni_cache_->GetEnv()->NewObject(named_variant_class_.get(),
                                             named_variant_from_int_,
                                             name.get(), value.IntValue());
    case Variant::TYPE_INT64_VALUE:
      return jni_cache_->GetEnv()->NewObject(named_variant_class_.get(),
                                             named_variant_from_long_,
                                             name.get(), value.Int64Value());
    case Variant::TYPE_FLOAT_VALUE:
      return jni_cache_->GetEnv()->NewObject(named_variant_class_.get(),
                                             named_variant_from_float_,
                                             name.get(), value.FloatValue());
    case Variant::TYPE_DOUBLE_VALUE:
      return jni_cache_->GetEnv()->NewObject(named_variant_class_.get(),
                                             named_variant_from_double_,
                                             name.get(), value.DoubleValue());
    case Variant::TYPE_BOOL_VALUE:
      return jni_cache_->GetEnv()->NewObject(named_variant_class_.get(),
                                             named_variant_from_bool_,
                                             name.get(), value.BoolValue());
    case Variant::TYPE_STRING_VALUE: {
      ScopedLocalRef<jstring> value_jstring =
          jni_cache_->ConvertToJavaString(value.StringValue());
      if (value_jstring == nullptr) {
        return nullptr;
      }
      return jni_cache_->GetEnv()->NewObject(named_variant_class_.get(),
                                             named_variant_from_string_,
                                             name.get(), value_jstring.get());
    }
    default:
      return nullptr;
  }
}

jobjectArray RemoteActionTemplatesHandler::AsNamedVariantArray(
    const std::map<std::string, Variant>& values) const {
  if (values.empty()) {
    return nullptr;
  }
  jobjectArray result = jni_cache_->GetEnv()->NewObjectArray(
      values.size(), named_variant_class_.get(), nullptr);
  int element_index = 0;
  for (auto key_value_pair : values) {
    if (!key_value_pair.second.HasValue()) {
      element_index++;
      continue;
    }
    ScopedLocalRef<jobject> named_extra(
        AsNamedVariant(key_value_pair.first, key_value_pair.second),
        jni_cache_->GetEnv());
    if (named_extra == nullptr) {
      return nullptr;
    }
    jni_cache_->GetEnv()->SetObjectArrayElement(result, element_index,
                                                named_extra.get());
    element_index++;
  }
  return result;
}

jobjectArray RemoteActionTemplatesHandler::RemoteActionTemplatesToJObjectArray(
    const std::vector<RemoteActionTemplate>& remote_actions) const {
  const jobjectArray results = jni_cache_->GetEnv()->NewObjectArray(
      remote_actions.size(), remote_action_template_class_.get(), nullptr);
  if (results == nullptr) {
    return nullptr;
  }
  for (int i = 0; i < remote_actions.size(); i++) {
    const RemoteActionTemplate& remote_action = remote_actions[i];
    const jstring title_without_entity =
        AsUTF8String(remote_action.title_without_entity);
    const jstring title_with_entity =
        AsUTF8String(remote_action.title_with_entity);
    const jstring description = AsUTF8String(remote_action.description);
    const jstring description_with_app_name =
        AsUTF8String(remote_action.description_with_app_name);
    const jstring action = AsUTF8String(remote_action.action);
    const jstring data = AsUTF8String(remote_action.data);
    const jstring type = AsUTF8String(remote_action.type);
    const jobject flags = AsInteger(remote_action.flags);
    const jobjectArray category = AsStringArray(remote_action.category);
    const jstring package = AsUTF8String(remote_action.package_name);
    const jobjectArray extra = AsNamedVariantArray(remote_action.extra);
    const jobject request_code = AsInteger(remote_action.request_code);
    ScopedLocalRef<jobject> result(
        jni_cache_->GetEnv()->NewObject(
            remote_action_template_class_.get(), remote_action_template_init_,
            title_without_entity, title_with_entity, description,
            description_with_app_name, action, data, type, flags, category,
            package, extra, request_code),
        jni_cache_->GetEnv());
    if (result == nullptr) {
      return nullptr;
    }
    jni_cache_->GetEnv()->SetObjectArrayElement(results, i, result.get());
  }
  return results;
}

jobject RemoteActionTemplatesHandler::EntityDataAsNamedVariantArray(
    const reflection::Schema* entity_data_schema,
    const std::string& serialized_entity_data) const {
  ReflectiveFlatbufferBuilder entity_data_builder(entity_data_schema);
  std::unique_ptr<ReflectiveFlatbuffer> buffer = entity_data_builder.NewRoot();
  buffer->MergeFromSerializedFlatbuffer(serialized_entity_data);
  std::map<std::string, Variant> entity_data_map = buffer->AsFlatMap();
  return AsNamedVariantArray(entity_data_map);
}

}  // namespace libtextclassifier3