<commit_before>#pragma once

#include "onair/okui/config.h"

#if ONAIR_ANDROID

#include "onair/jni/JavaClass.h"
#include "onair/jni/NativeClass.h"
#include "onair/jni/JNIContext.h"
#include "onair/jni/android/app/Activity.h"
#include <android/asset_manager_jni.h>

namespace onair {
namespace okui {
namespace applications {

ONAIR_JNI_JAVA_CLASS_BEGIN(AndroidJavaHelper);
    ONAIR_JNI_JAVA_CLASS_CONSTRUCTOR(AndroidJavaHelper, android::app::Activity);

    struct OpenDialogCallback {
        OpenDialogCallback(std::function<void(int)> f) : f{std::move(f)} {}
        void invoke(int button) { f(button); delete this; }
        std::function<void(int)> f;
    };

    ONAIR_JNI_NATIVE_CLASS_BEGIN(JavaOpenDialogCallback, OpenDialogCallback);
        ONAIR_JNI_NATIVE_CLASS_METHOD(void, invoke, int);
    ONAIR_JNI_NATIVE_CLASS_END();

    ONAIR_JNI_JAVA_CLASS_METHOD(void, openDialog, const char*, const char*, const std::vector<std::string>&, OpenDialogCallback*);
    ONAIR_JNI_JAVA_CLASS_METHOD(std::string, distinctId);
    ONAIR_JNI_JAVA_CLASS_METHOD(std::string, operatingSystem);
    ONAIR_JNI_JAVA_CLASS_METHOD(std::string, deviceModel);
    ONAIR_JNI_JAVA_CLASS_METHOD(float, renderScale);
    ONAIR_JNI_JAVA_CLASS_METHOD(bool, wifiConnection);
ONAIR_JNI_JAVA_CLASS_END();

/**
* Provides some native Platform overrides for Android.
*
* This isn't intended to be a full implementation, but can be used to add native support to other implementations.
*/
template <typename Base>
class Android : public Base {
public:
    Android();
    virtual ~Android();

    virtual void openDialog(Window* window,
                            const char* title,
                            const char* message,
                            const std::vector<std::string>& buttons,
                            std::function<void(int)> action = std::function<void(int)>()) override;

    virtual double renderScale() const override;

    virtual std::string distinctId() const override;

    virtual std::string operatingSystem() const override;

    virtual std::string deviceModel() const override;

    virtual bool wifiConnection() const override;

    class AssetResourceManager : public ResourceManager {
    public:
        AssetResourceManager(JNIEnv* env, jobject assetManager)
            : _env{env}
            , _assetManagerReference{env->NewGlobalRef(assetManager)}
            , _assetManager{AAssetManager_fromJava(env, assetManager)}
        {}

        ~AssetResourceManager() {
            _env->DeleteGlobalRef(_assetManagerReference);
        }

        virtual std::shared_ptr<std::string> load(const char* name) override;

    private:
        JNIEnv* _env;
        jobject _assetManagerReference;
        AAssetManager* _assetManager;
    };

private:
    JNIEnv* _jniEnv = nullptr;
    jobject _activity = nullptr;

    std::shared_ptr<jni::JNIContext> _jniContext;
    std::unique_ptr<AndroidJavaHelper> _javaHelper;
    
    std::unique_ptr<ResourceManager> _resourceManager;

    static std::weak_ptr<jni::JNIContext> _sJNIContext;
};

template <typename Base>
std::weak_ptr<jni::JNIContext> Android<Base>::_sJNIContext;

template <typename Base>
inline Android<Base>::Android() {
    auto activity = Base::nativeActivity(&_jniEnv);
    _activity = _jniEnv->NewGlobalRef(activity);
    _jniEnv->DeleteLocalRef(activity);

    JavaVM* jvm = nullptr;
    _jniEnv->GetJavaVM(&jvm);

    auto existingContext = _sJNIContext.lock();
    assert(!existingContext || existingContext->jvm == jvm);

    if (existingContext) {
        _jniContext = existingContext;
    } else {
        _jniContext = std::make_shared<jni::JNIContext>(jvm, _jniEnv->GetVersion());
        AndroidJavaHelper::Traits::Register(_jniContext.get(), "tv/watchonair/okui/Helper");
        AndroidJavaHelper::JavaOpenDialogCallback::Traits::Register(_jniContext.get(), "tv/watchonair/okui/Helper$OpenDialogCallback");
        _sJNIContext = _jniContext;
    }

    _javaHelper = std::make_unique<AndroidJavaHelper>(android::app::Activity{_jniEnv, _activity});
        
    _jniEnv->PushLocalFrame(10);

    auto c = _jniEnv->GetObjectClass(_activity);
    auto m = _jniEnv->GetMethodID(c, "getAssets", "()Landroid/content/res/AssetManager;");
    _resourceManager = std::make_unique<AssetResourceManager>(_jniEnv, _jniEnv->CallObjectMethod(_activity, m));
    Base::setResourceManager(_resourceManager.get());

    _jniEnv->PopLocalFrame(nullptr);
}

template <typename Base>
inline Android<Base>::~Android() {
    if (_javaHelper) {
        _javaHelper.reset();
    }
    if (_activity) {
        _jniEnv->DeleteGlobalRef(_activity);
    }
}

template <typename Base>
inline void Android<Base>::openDialog(Window* window,
                         const char* title,
                         const char* message,
                         const std::vector<std::string>& buttons,
                         std::function<void(int)> action) {
    _javaHelper->openDialog(title, message, buttons, new AndroidJavaHelper::OpenDialogCallback([=] (int button) {
        taskScheduler()->async([=] {
            action(button);
        });
    }));
}

template <typename Base><commit_msg>minor fixes<commit_after>#pragma once

#include "onair/okui/config.h"

#if ONAIR_ANDROID

#include "onair/jni/JavaClass.h"
#include "onair/jni/NativeClass.h"
#include "onair/jni/JNIContext.h"
#include "onair/jni/android/app/Activity.h"
#include <android/asset_manager_jni.h>

namespace onair {
namespace okui {
namespace applications {

ONAIR_JNI_JAVA_CLASS_BEGIN(AndroidJavaHelper);
    ONAIR_JNI_JAVA_CLASS_CONSTRUCTOR(AndroidJavaHelper, android::app::Activity);

    struct OpenDialogCallback {
        OpenDialogCallback(std::function<void(int)> f) : f{std::move(f)} {}
        void invoke(int button) { f(button); delete this; }
        std::function<void(int)> f;
    };

    ONAIR_JNI_NATIVE_CLASS_BEGIN(JavaOpenDialogCallback, OpenDialogCallback);
        ONAIR_JNI_NATIVE_CLASS_METHOD(void, invoke, int);
    ONAIR_JNI_NATIVE_CLASS_END();

    ONAIR_JNI_JAVA_CLASS_METHOD(void, openDialog, const char*, const char*, const std::vector<std::string>&, OpenDialogCallback*);
    ONAIR_JNI_JAVA_CLASS_METHOD(std::string, distinctId);
    ONAIR_JNI_JAVA_CLASS_METHOD(std::string, operatingSystem);
    ONAIR_JNI_JAVA_CLASS_METHOD(std::string, deviceModel);
    ONAIR_JNI_JAVA_CLASS_METHOD(float, renderScale);
    ONAIR_JNI_JAVA_CLASS_METHOD(bool, wifiConnection);
ONAIR_JNI_JAVA_CLASS_END();

/**
* Provides some native Platform overrides for Android.
*
* This isn't intended to be a full implementation, but can be used to add native support to other implementations.
*/
template <typename Base>
class Android : public Base {
public:
    Android();
    virtual ~Android();

    virtual void openDialog(Window* window,
                            const char* title,
                            const char* message,
                            const std::vector<std::string>& buttons,
                            std::function<void(int)> action = std::function<void(int)>()) override;

    virtual double renderScale() const override;

    virtual std::string distinctId() const override;

    virtual std::string operatingSystem() const override;

    virtual std::string deviceModel() const override;

    virtual bool wifiConnection() const override;

    class AssetResourceManager : public ResourceManager {
    public:
        AssetResourceManager(JNIEnv* env, jobject assetManager)
            : _env{env}
            , _assetManagerReference{env->NewGlobalRef(assetManager)}
            , _assetManager{AAssetManager_fromJava(env, assetManager)}
        {}

        ~AssetResourceManager() {
            _env->DeleteGlobalRef(_assetManagerReference);
        }

        virtual std::shared_ptr<std::string> load(const char* name) override;

    private:
        JNIEnv* _env;
        jobject _assetManagerReference;
        AAssetManager* _assetManager;
    };

private:
    JNIEnv* _jniEnv = nullptr;
    jobject _activity = nullptr;

    std::shared_ptr<jni::JNIContext> _jniContext;
    std::unique_ptr<AndroidJavaHelper> _javaHelper;
    
    std::unique_ptr<ResourceManager> _resourceManager;

    static std::weak_ptr<jni::JNIContext> _sJNIContext;
};

template <typename Base>
std::weak_ptr<jni::JNIContext> Android<Base>::_sJNIContext;

template <typename Base>
inline Android<Base>::Android() {
    auto activity = Base::nativeActivity(&_jniEnv);
    _activity = _jniEnv->NewGlobalRef(activity);
    _jniEnv->DeleteLocalRef(activity);

    JavaVM* jvm = nullptr;
    _jniEnv->GetJavaVM(&jvm);

    auto existingContext = _sJNIContext.lock();
    assert(!existingContext || existingContext->jvm == jvm);

    if (existingContext) {
        _jniContext = existingContext;
    } else {
        _jniContext = std::make_shared<jni::JNIContext>(jvm, _jniEnv->GetVersion());
        AndroidJavaHelper::Traits::Register(_jniContext.get(), "tv/watchonair/okui/Helper");
        AndroidJavaHelper::JavaOpenDialogCallback::Traits::Register(_jniContext.get(), "tv/watchonair/okui/Helper$OpenDialogCallback");
        _sJNIContext = _jniContext;
    }

    _javaHelper = std::make_unique<AndroidJavaHelper>(android::app::Activity{_jniEnv, _activity});
        
    _jniEnv->PushLocalFrame(10);

    auto c = _jniEnv->GetObjectClass(_activity);
    auto m = _jniEnv->GetMethodID(c, "getAssets", "()Landroid/content/res/AssetManager;");
    _resourceManager = std::make_unique<AssetResourceManager>(_jniEnv, _jniEnv->CallObjectMethod(_activity, m));
    Base::setResourceManager(_resourceManager.get());

    _jniEnv->PopLocalFrame(nullptr);
}

template <typename Base>
inline Android<Base>::~Android() {
    if (_javaHelper) {
        _javaHelper.reset();
    }
    if (_activity) {
        _jniEnv->DeleteGlobalRef(_activity);
    }
}

template <typename Base>
inline void Android<Base>::openDialog(Window* window,
                         const char* title,
                         const char* message,
                         const std::vector<std::string>& buttons,
                         std::function<void(int)> action) {
    _javaHelper->openDialog(title, message, buttons, new AndroidJavaHelper::OpenDialogCallback([=] (int button) {
        this->taskScheduler()->async([=] {
            action(button);
        });
    }));
}

template <typename Base>
{'fraction_non_alphanumeric': 0.11665699361578642, 'fraction_numerical': 0.0003869220352099052, 'mean_word_length': 3.7274805669867397, 'pattern_counts': {'":': 0, '<': 59, '<?xml version=': 0, '>': 90, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1553302', 'n_tokens_mistral': 3203, 'n_tokens_neox': 3092, 'n_words': 572}