Skip to content

Commit

Permalink
Added JNI wrappers; reworked JNIMiniHelper to use them
Browse files Browse the repository at this point in the history
  • Loading branch information
TheMostDiligent committed Dec 5, 2023
1 parent 9d94c3c commit dced29e
Show file tree
Hide file tree
Showing 3 changed files with 206 additions and 30 deletions.
1 change: 1 addition & 0 deletions Platforms/Android/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ set(INTERFACE
interface/AndroidPlatformMisc.hpp
interface/AndroidNativeWindow.h
interface/JNIMiniHelper.hpp
interface/JNIWrappers.hpp
../Linux/interface/LinuxPlatformMisc.hpp
)

Expand Down
46 changes: 16 additions & 30 deletions Platforms/Android/interface/JNIMiniHelper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
#include <android/native_activity.h>
#include <android/asset_manager.h>

#include "JNIWrappers.hpp"

namespace Diligent
{

Expand Down Expand Up @@ -70,12 +72,21 @@ class JNIMiniHelper

JNIEnv* env = nullptr;
bool DetachThread = AttachCurrentThread(env);
if (jstring jstr_path = GetExternalFilesDirJString(env))
if (env != nullptr)
{
const char* path = env->GetStringUTFChars(jstr_path, nullptr);
ExternalFilesPath = std::string(path);
env->ReleaseStringUTFChars(jstr_path, path);
env->DeleteLocalRef(jstr_path);
if (JNIWrappers::Clazz activity_cls{*env, activity_class_name_.c_str()})
{
if (JNIWrappers::Method get_external_files_dir_method{activity_cls.GetMethod("getExternalFilesDir", "(Ljava/lang/String;)Ljava/io/File;")})
{
if (JNIWrappers::File file{*env, get_external_files_dir_method.Call<jobject>(activity_->clazz, NULL)})
{
if (JNIWrappers::String path = file.GetPath())
{
ExternalFilesPath = path.GetStdString();
}
}
}
}
}
if (DetachThread)
DetachCurrentThread();
Expand Down Expand Up @@ -125,31 +136,6 @@ class JNIMiniHelper
JNIMiniHelper& operator=(JNIMiniHelper&&) = delete;
// clang-format on

jstring GetExternalFilesDirJString(JNIEnv* env)
{
if (activity_ == nullptr)
{
LOG_ERROR_MESSAGE("JNIHelper has not been initialized. Call init() to initialize the helper");
return NULL;
}

jstring obj_Path = nullptr;
// Invoking getExternalFilesDir() java API
jclass cls_Env = env->FindClass(activity_class_name_.c_str());
jmethodID mid = env->GetMethodID(cls_Env, "getExternalFilesDir", "(Ljava/lang/String;)Ljava/io/File;");
jobject obj_File = env->CallObjectMethod(activity_->clazz, mid, NULL);
if (obj_File)
{
jclass cls_File = env->FindClass("java/io/File");
jmethodID mid_getPath = env->GetMethodID(cls_File, "getPath", "()Ljava/lang/String;");
obj_Path = (jstring)env->CallObjectMethod(obj_File, mid_getPath);
env->DeleteLocalRef(cls_File);
env->DeleteLocalRef(obj_File);
}
env->DeleteLocalRef(cls_Env);
return obj_Path;
}

void DetachCurrentThread()
{
activity_->vm->DetachCurrentThread();
Expand Down
189 changes: 189 additions & 0 deletions Platforms/Android/interface/JNIWrappers.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/*
* Copyright 2023 Diligent Graphics LLC
*
* 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.
*
* In no event and under no legal theory, whether in tort (including negligence),
* contract, or otherwise, unless required by applicable law (such as deliberate
* and grossly negligent acts) or agreed to in writing, shall any Contributor be
* liable for any damages, including any direct, indirect, special, incidental,
* or consequential damages of any character arising as a result of this License or
* out of the use or inability to use the software (including but not limited to damages
* for loss of goodwill, work stoppage, computer failure or malfunction, or any and
* all other commercial damages or losses), even if such Contributor has been advised
* of the possibility of such damages.
*/

#pragma once

#include <jni.h>

namespace Diligent
{

namespace JNIWrappers
{

class Method
{
public:
Method(JNIEnv& env, jclass cls, const char* name, const char* sig) :
env_{env},
mid_{env.GetMethodID(cls, name, sig)}
{
}

template <typename RetType, typename... Args>
RetType Call(jobject obj, Args&&... args)
{
return static_cast<RetType>(env_.CallObjectMethod(obj, mid_, std::forward<Args>(args)...));
}

explicit operator bool() const
{
return mid_ != nullptr;
}

private:
JNIEnv& env_;
jmethodID mid_ = nullptr;
};

class Clazz
{
public:
Clazz(JNIEnv& env, const char* class_name) :
env_{env},
cls_{class_name != nullptr ? env_.FindClass(class_name) : nullptr}
{
}

Clazz(Clazz&& other) :
env_{other.env_},
cls_{other.cls_}
{
other.cls_ = nullptr;
}

Clazz(Clazz& other) = delete;

~Clazz()
{
if (cls_ != nullptr)
{
env_.DeleteLocalRef(cls_);
}
}

Method GetMethod(const char* name, const char* sig)
{
return Method{env_, cls_, name, sig};
}

explicit operator bool() const
{
return cls_ != nullptr;
}

protected:
JNIEnv& env_;
jclass cls_ = nullptr;
};

template <typename ObjType = jobject>
class Object : public Clazz
{
public:
Object(JNIEnv& env, ObjType obj, const char* class_name = nullptr) :
Clazz{env, class_name},
obj_{obj}
{
}

Object(Object&& other) :
Clazz(std::move(static_cast<Clazz&>(other))),
obj_{other.obj_}
{
other.obj_ = nullptr;
}

Object(Object& other) = delete;

~Object()
{
if (obj_ != nullptr)
{
env_.DeleteLocalRef(obj_);
}
}

ObjType Detach()
{
ObjType obj = obj_;
obj_ = nullptr;
return obj;
}

explicit operator bool() const
{
return static_cast<const Clazz&>(*this) && (obj_ != nullptr);
}

protected:
ObjType obj_ = nullptr;
};

class String : public Object<jstring>
{
public:
String(JNIEnv& env, jstring str_obj) :
Object{env, str_obj}
{
}

std::string GetStdString()
{
const char* chars = env_.GetStringUTFChars(obj_, nullptr);
std::string str{chars};
env_.ReleaseStringUTFChars(obj_, chars);
return str;
}

explicit operator bool() const
{
// Clazz is null
return obj_ != nullptr;
}
};

class File : public Object<>
{
public:
File(JNIEnv& env, jobject file_obj) :
Object{env, file_obj, "java/io/File"},
get_path_method_{env_, cls_, "getPath", "()Ljava/lang/String;"}
{
}

String GetPath()
{
return String{env_, get_path_method_.Call<jstring>(obj_)};
}

private:
Method get_path_method_;
};

} // namespace JNIWrappers

} // namespace Diligent

0 comments on commit dced29e

Please sign in to comment.