* Copyright (c) 2024 Huawei Device Co., Ltd.
* 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 "filepicker_jni.h"
#include "log.h"
#include <unordered_map>
namespace OHOS::Plugin {
namespace {
const char CLASS_NAME[] = "ohos/ace/plugin/file/fs/picker/filepicker/FilePicker";
const JNINativeMethod METHODS[] = {
{ "nativeInit", "()V", reinterpret_cast<void*>(FilePickerJni::NativeInit) },
{ "onPickerResult", "(Ljava/util/List;II)V", reinterpret_cast<void*>(FilePickerJni::onPickerResult) },
};
const char METHOD_SELECT[] = "select";
const char METHOD_SAVE[] = "save";
const char SIGNATURE_SELECT[] = "(ILjava/lang/String;[Ljava/lang/String;II)V";
const char SIGNATURE_SAVE[] = "([Ljava/lang/String;Ljava/lang/String;I)V";
struct {
jmethodID select;
jmethodID save;
jobject globalRef;
} g_pluginClass;
std::unordered_map<int32_t, DocumentFilePicker*>& PickerRegistry()
{
static std::unordered_map<int32_t, DocumentFilePicker*> registry;
return registry;
}
}
bool FilePickerJni::Register(void* env)
{
LOGI("FilePicker JNI: Register enter");
auto* jniEnv = static_cast<JNIEnv*>(env);
CHECK_NULL_RETURN(jniEnv, false);
jclass cls = jniEnv->FindClass(CLASS_NAME);
CHECK_NULL_RETURN(cls, false);
bool ret = jniEnv->RegisterNatives(cls, METHODS, sizeof(METHODS) / sizeof(METHODS[0])) == 0;
jniEnv->DeleteLocalRef(cls);
if (!ret) {
LOGE("FilePicker JNI: RegisterNatives fail");
return false;
}
return true;
}
void FilePickerJni::RegisterPicker(int32_t requestId, DocumentFilePicker* picker)
{
PickerRegistry()[requestId] = picker;
}
DocumentFilePicker* FilePickerJni::UnregisterPicker(int32_t requestId)
{
auto& registry = PickerRegistry();
auto it = registry.find(requestId);
if (it == registry.end()) {
return nullptr;
}
DocumentFilePicker* picker = it->second;
registry.erase(it);
return picker;
}
void FilePickerJni::NativeInit(JNIEnv* env, jobject jobj)
{
LOGI("FilePicker JNI: NativeInit enter");
CHECK_NULL_VOID(env);
g_pluginClass.globalRef = env->NewGlobalRef(jobj);
CHECK_NULL_VOID(g_pluginClass.globalRef);
jclass cls = env->GetObjectClass(jobj);
CHECK_NULL_VOID(cls);
g_pluginClass.save = env->GetMethodID(cls, METHOD_SAVE, SIGNATURE_SAVE);
CHECK_NULL_VOID(g_pluginClass.save);
g_pluginClass.select = env->GetMethodID(cls, METHOD_SELECT, SIGNATURE_SELECT);
CHECK_NULL_VOID(g_pluginClass.select);
env->DeleteLocalRef(cls);
}
std::vector<std::string> jstringListToStdStringVector(JNIEnv* env, jobject list)
{
std::vector<std::string> result;
if (list == nullptr) {
return result;
}
jclass listClass = env->FindClass("java/util/List");
jmethodID sizeMethod = env->GetMethodID(listClass, "size", "()I");
jmethodID getMethod = env->GetMethodID(listClass, "get", "(I)Ljava/lang/Object;");
jsize listSize = env->CallIntMethod(list, sizeMethod);
for (jsize i = 0; i < listSize; ++i) {
jobject element = env->CallObjectMethod(list, getMethod, i);
auto jstr = (jstring)element;
const char* str = env->GetStringUTFChars(jstr, nullptr);
result.emplace_back(str);
env->ReleaseStringUTFChars(jstr, str);
}
return result;
}
void FilePickerJni::onPickerResult(JNIEnv* env, jobject thiz, jobject rst, jint errCode, jint requestId)
{
LOGI("FilePicker JNI: onPickerResult enter, requestId: %d", static_cast<int>(requestId));
CHECK_NULL_VOID(env);
DocumentFilePicker* picker = UnregisterPicker(static_cast<int32_t>(requestId));
if (picker == nullptr) {
LOGE("FilePicker JNI: onPickerResult unknown requestId %d", static_cast<int>(requestId));
return;
}
std::vector<std::string> cppStringList = jstringListToStdStringVector(env, rst);
picker->ResolvePendingRequest(static_cast<int32_t>(requestId), cppStringList, errCode);
}
void FilePickerJni::Select(DocumentSelectOptions& options, int32_t requestId, DocumentFilePicker* picker)
{
LOGI("FilePicker JNI: Select enter, requestId: %d", requestId);
RegisterPicker(requestId, picker);
auto env = ARKUI_X_Plugin_GetJniEnv();
CHECK_NULL_VOID(env);
jstring defaultFilePathUri = env->NewStringUTF(options.defaultFilePathUri.c_str());
jobjectArray fileSuffixFilters =
env->NewObjectArray(options.fileSuffixFilters.size(), env->FindClass("java/lang/String"), nullptr);
for (size_t i = 0; i < options.fileSuffixFilters.size(); ++i) {
env->SetObjectArrayElement(fileSuffixFilters, i, env->NewStringUTF(options.fileSuffixFilters[i].c_str()));
}
env->CallVoidMethod(g_pluginClass.globalRef, g_pluginClass.select, options.maxSelectNumber, defaultFilePathUri,
fileSuffixFilters, options.key_select_mode, static_cast<jint>(requestId));
env->DeleteLocalRef(defaultFilePathUri);
env->DeleteLocalRef(fileSuffixFilters);
}
void FilePickerJni::Save(DocumentSaveOptions& options, int32_t requestId, DocumentFilePicker* picker)
{
LOGI("FilePicker JNI: Save enter, requestId: %d", requestId);
RegisterPicker(requestId, picker);
auto env = ARKUI_X_Plugin_GetJniEnv();
CHECK_NULL_VOID(env);
jstring defaultFilePathUri = env->NewStringUTF(options.defaultFilePathUri.c_str());
jobjectArray newFileNames =
env->NewObjectArray(options.newFileNames.size(), env->FindClass("java/lang/String"), nullptr);
for (size_t i = 0; i < options.newFileNames.size(); ++i) {
env->SetObjectArrayElement(newFileNames, i, env->NewStringUTF(options.newFileNames[i].c_str()));
}
env->CallVoidMethod(g_pluginClass.globalRef, g_pluginClass.save, newFileNames, defaultFilePathUri,
static_cast<jint>(requestId));
env->DeleteLocalRef(defaultFilePathUri);
}
}