[android][sdk] Move cpp code into sdk lib

Signed-off-by: Andrei Shkrob <github@shkrob.dev>
This commit is contained in:
Andrei Shkrob
2025-06-25 21:00:47 +02:00
committed by Konstantin Pastbin
parent 0c8648d1e3
commit dd023b65c7
86 changed files with 137 additions and 108 deletions

View File

@@ -0,0 +1,135 @@
cmake_minimum_required(VERSION 3.22.1)
project(organicmaps C CXX)
set(SRC
# JNI headers
../../../../../private.h
app/organicmaps/sdk/core/jni_helper.hpp
app/organicmaps/sdk/core/jni_java_methods.hpp
app/organicmaps/sdk/core/logging.hpp
app/organicmaps/sdk/core/ScopedEnv.hpp
app/organicmaps/sdk/core/ScopedLocalRef.hpp
app/organicmaps/sdk/Framework.hpp
app/organicmaps/sdk/opengl/android_gl_utils.hpp
app/organicmaps/sdk/opengl/androidoglcontext.hpp
app/organicmaps/sdk/opengl/androidoglcontextfactory.hpp
app/organicmaps/sdk/opengl/gl3stub.h
app/organicmaps/sdk/platform/GuiThread.hpp
app/organicmaps/sdk/platform/AndroidPlatform.hpp
app/organicmaps/sdk/util/Distance.hpp
app/organicmaps/sdk/util/FeatureIdBuilder.hpp
app/organicmaps/sdk/vulkan/android_vulkan_context_factory.hpp
# JNI sources
app/organicmaps/sdk/search/DisplayedCategories.cpp
app/organicmaps/sdk/search/SearchEngine.cpp
app/organicmaps/sdk/search/SearchRecents.cpp
app/organicmaps/sdk/routing/JunctionInfo.hpp
app/organicmaps/sdk/routing/RouteMarkData.hpp
app/organicmaps/sdk/routing/RouteMarkType.hpp
app/organicmaps/sdk/routing/RoutePointInfo.hpp
app/organicmaps/sdk/routing/RouteRecommendationType.hpp
app/organicmaps/sdk/routing/RoutingInfo.hpp
app/organicmaps/sdk/routing/RoutingOptions.cpp
app/organicmaps/sdk/routing/SingleLaneInfo.hpp
app/organicmaps/sdk/routing/TransitRouteInfo.hpp
app/organicmaps/sdk/routing/TransitStepInfo.hpp
app/organicmaps/sdk/ChoosePositionMode.cpp
app/organicmaps/sdk/MapStyle.cpp
app/organicmaps/sdk/OrganicMaps.cpp
app/organicmaps/sdk/Router.cpp
app/organicmaps/sdk/core/jni_helper.cpp
app/organicmaps/sdk/core/jni_java_methods.cpp
app/organicmaps/sdk/core/logging.cpp
app/organicmaps/sdk/bookmarks/data/BookmarkManager.cpp
app/organicmaps/sdk/DownloadResourcesLegacyActivity.cpp
app/organicmaps/sdk/editor/Editor.cpp
app/organicmaps/sdk/editor/OpeningHours.cpp
app/organicmaps/sdk/editor/OsmOAuth.cpp
app/organicmaps/sdk/Framework.cpp
app/organicmaps/sdk/isolines/IsolinesManager.cpp
app/organicmaps/sdk/LocationState.cpp
app/organicmaps/sdk/Map.cpp
app/organicmaps/sdk/MapManager.cpp
app/organicmaps/sdk/settings/UnitLocale.cpp
app/organicmaps/sdk/settings/MapLanguageCode.cpp
app/organicmaps/sdk/sound/tts.cpp
app/organicmaps/sdk/subway/SubwayManager.cpp
app/organicmaps/sdk/TrackRecorder.cpp
app/organicmaps/sdk/TrafficState.cpp
app/organicmaps/sdk/UserMarkHelper.cpp
app/organicmaps/sdk/opengl/android_gl_utils.cpp
app/organicmaps/sdk/opengl/androidoglcontext.cpp
app/organicmaps/sdk/opengl/androidoglcontextfactory.cpp
app/organicmaps/sdk/opengl/gl3stub.cpp
app/organicmaps/sdk/platform/GuiThread.cpp
app/organicmaps/sdk/platform/HttpThread.cpp
app/organicmaps/sdk/platform/Language.cpp
app/organicmaps/sdk/platform/Localization.cpp
app/organicmaps/sdk/platform/AndroidPlatform.cpp
app/organicmaps/sdk/platform/PThreadImpl.cpp
app/organicmaps/sdk/platform/SecureStorage.cpp
app/organicmaps/sdk/platform/SocketImpl.cpp
app/organicmaps/sdk/util/Config.cpp
app/organicmaps/sdk/util/GeoUtils.cpp
app/organicmaps/sdk/util/HttpClient.cpp
app/organicmaps/sdk/util/Language.cpp
app/organicmaps/sdk/util/LogsManager.cpp
app/organicmaps/sdk/util/NetworkPolicy.cpp
app/organicmaps/sdk/util/StringUtils.cpp
app/organicmaps/sdk/util/UiThread.cpp
app/organicmaps/sdk/vulkan/android_vulkan_context_factory.cpp
)
omim_add_library(${PROJECT_NAME} SHARED ${SRC})
target_include_directories(${PROJECT_NAME} PRIVATE .)
target_link_libraries(${PROJECT_NAME}
# CoMaps libs
map
# ge0
# tracking
# routing
# traffic
# routing_common
# drape_frontend
# shaders
# search
# storage
# descriptions
# drape
# kml
# editor
# transit
# indexer
# platform
# mwm_diff
# bsdiff
# geometry
# coding
# base
# opening_hours
# pugixml
# expat
# freetype
# minizip
# cppjansson
# protobuf
# succinct
# stb_image
# icu
# agg
# vulkan_wrapper
# Android libs
log
android
EGL
GLESv2
atomic
z
)
#target_link_options(${PROJECT_NAME} PRIVATE "-fuse-ld=gold")

View File

@@ -0,0 +1,26 @@
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/Framework.hpp"
#include "indexer/map_style.hpp"
extern "C"
{
JNIEXPORT void JNICALL Java_app_organicmaps_sdk_ChoosePositionMode_nativeSet(JNIEnv *, jclass, jint mode,
jboolean isBusiness,
jboolean applyPosition)
{
// TODO(AB): Move this code into the Framework to share with iOS and other platforms.
auto const f = frm();
if (applyPosition && f->HasPlacePageInfo())
g_framework->SetChoosePositionMode(static_cast<android::ChoosePositionMode>(mode), isBusiness,
&f->GetCurrentPlacePageInfo().GetMercator());
else
g_framework->SetChoosePositionMode(static_cast<android::ChoosePositionMode>(mode), isBusiness, nullptr);
}
JNIEXPORT jint JNICALL Java_app_organicmaps_sdk_ChoosePositionMode_nativeGet(JNIEnv *, jclass)
{
return static_cast<jint>(g_framework->GetChoosePositionMode());
}
}

View File

@@ -0,0 +1,186 @@
#include "Framework.hpp"
#include "defines.hpp"
#include "storage/downloader.hpp"
#include "storage/storage.hpp"
#include "platform/downloader_defines.hpp"
#include "platform/http_request.hpp"
#include "platform/platform.hpp"
#include "coding/internal/file_data.hpp"
#include "coding/reader_streambuf.hpp"
#include "base/file_name_utils.hpp"
#include "base/logging.hpp"
#include "base/string_utils.hpp"
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
using namespace downloader;
using namespace storage;
using namespace std::placeholders;
/// Special error codes to notify GUI about free space
//@{
#define ERR_DOWNLOAD_SUCCESS 0
#define ERR_DISK_ERROR -1
#define ERR_NOT_ENOUGH_FREE_SPACE -2
#define ERR_STORAGE_DISCONNECTED -3
#define ERR_DOWNLOAD_ERROR -4
#define ERR_NO_MORE_FILES -5
#define ERR_FILE_IN_PROGRESS -6
//@}
namespace
{
static std::vector<platform::CountryFile> g_filesToDownload;
static int g_totalDownloadedBytes;
static int g_totalBytesToDownload;
static std::shared_ptr<HttpRequest> g_currentRequest;
} // namespace
extern "C"
{
using Callback = HttpRequest::Callback;
static int HasSpaceForFiles(Platform & pl, std::string const & sdcardPath, size_t fileSize)
{
switch (pl.GetWritableStorageStatus(fileSize))
{
case Platform::STORAGE_DISCONNECTED:
return ERR_STORAGE_DISCONNECTED;
case Platform::NOT_ENOUGH_SPACE:
return ERR_NOT_ENOUGH_FREE_SPACE;
default:
return static_cast<int>(fileSize);
}
}
JNIEXPORT jint JNICALL
Java_app_organicmaps_sdk_DownloadResourcesLegacyActivity_nativeGetBytesToDownload(JNIEnv * env, jclass clazz)
{
// clear all
g_filesToDownload.clear();
g_totalBytesToDownload = 0;
g_totalDownloadedBytes = 0;
using namespace storage;
Storage const & storage = g_framework->GetStorage();
auto const status = storage.GetForceDownloadWorlds(g_filesToDownload);
for (auto const & cf : g_filesToDownload)
g_totalBytesToDownload += cf.GetRemoteSize();
int res;
if (status == Storage::WorldStatus::ERROR_CREATE_FOLDER ||
status == Storage::WorldStatus::ERROR_MOVE_FILE)
{
res = ERR_DISK_ERROR;
}
else
{
Platform & pl = GetPlatform();
res = HasSpaceForFiles(pl, pl.WritableDir(), g_totalBytesToDownload);
}
if (res == ERR_STORAGE_DISCONNECTED)
LOG(LWARNING, ("External file system is not available"));
else if (res == ERR_NOT_ENOUGH_FREE_SPACE)
LOG(LWARNING, ("Not enough space to extract files"));
g_currentRequest.reset();
if (status == Storage::WorldStatus::WAS_MOVED)
{
g_framework->ReloadWorldMaps();
res = ERR_DOWNLOAD_SUCCESS; // reset possible storage error if we moved files
}
return res;
}
static void DownloadFileFinished(std::shared_ptr<jobject> obj, HttpRequest const & req)
{
auto const status = req.GetStatus();
ASSERT_NOT_EQUAL(status, DownloadStatus::InProgress, ());
int errorCode = ERR_DOWNLOAD_ERROR;
if (status == DownloadStatus::Completed)
errorCode = ERR_DOWNLOAD_SUCCESS;
g_currentRequest.reset();
if (errorCode == ERR_DOWNLOAD_SUCCESS)
{
auto const & curFile = g_filesToDownload.back();
size_t const sz = curFile.GetRemoteSize();
LOG(LDEBUG, ("finished downloading", curFile.GetName(), "size", sz, "bytes"));
g_totalDownloadedBytes += sz;
LOG(LDEBUG, ("totalDownloadedBytes:", g_totalDownloadedBytes));
g_filesToDownload.pop_back();
}
JNIEnv * env = jni::GetEnv();
jmethodID methodID = jni::GetMethodID(env, *obj, "onFinish", "(I)V");
env->CallVoidMethod(*obj, methodID, errorCode);
}
static void DownloadFileProgress(std::shared_ptr<jobject> listener, HttpRequest const & req)
{
JNIEnv * env = jni::GetEnv();
static jmethodID methodID = jni::GetMethodID(env, *listener, "onProgress", "(I)V");
env->CallVoidMethod(*listener, methodID, static_cast<jint>(g_totalDownloadedBytes + req.GetProgress().m_bytesDownloaded));
}
JNIEXPORT jint JNICALL
Java_app_organicmaps_sdk_DownloadResourcesLegacyActivity_nativeStartNextFileDownload(JNIEnv * env, jclass clazz, jobject listener)
{
if (g_filesToDownload.empty())
return ERR_NO_MORE_FILES;
/// @todo One downloader instance with cached servers. All this routine will be refactored some time.
static auto downloader = storage::GetDownloader();
storage::Storage const & storage = g_framework->GetStorage();
downloader->SetDataVersion(storage.GetCurrentDataVersion());
downloader->EnsureMetaConfigReady([&storage, ptr = jni::make_global_ref(listener)]()
{
auto const & curFile = g_filesToDownload.back();
auto const fileName = curFile.GetFileName(MapFileType::Map);
LOG(LINFO, ("Downloading file", fileName));
g_currentRequest.reset(HttpRequest::GetFile(
downloader->MakeUrlListLegacy(fileName),
storage.GetFilePath(curFile.GetName(), MapFileType::Map),
curFile.GetRemoteSize(),
std::bind(&DownloadFileFinished, ptr, _1),
std::bind(&DownloadFileProgress, ptr, _1),
0, false));
});
return ERR_FILE_IN_PROGRESS;
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_DownloadResourcesLegacyActivity_nativeCancelCurrentFile(JNIEnv * env, jclass clazz)
{
LOG(LDEBUG, ("cancelCurrentFile, currentRequest=", g_currentRequest));
g_currentRequest.reset();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,222 @@
#pragma once
#include <jni.h>
#include "map/framework.hpp"
#include "map/place_page_info.hpp"
#include "map/power_management/power_manager.hpp"
#include "search/result.hpp"
#include "drape_frontend/gui/skin.hpp"
#include "drape/pointers.hpp"
#include "drape/graphics_context_factory.hpp"
#include "indexer/feature_decl.hpp"
#include "indexer/map_style.hpp"
#include "platform/country_defines.hpp"
#include "platform/location.hpp"
#include "geometry/avg_vector.hpp"
#include "base/timer.hpp"
#include <cstdint>
#include <map>
#include <memory>
#include <mutex>
class DataSource;
struct FeatureID;
namespace search
{
struct EverywhereSearchParams;
}
namespace android
{
enum CoordinatesFormat // See Java enum app.organicmaps.widget.placepage.CoordinatesFormat for all possible values.
{
LatLonDMS = 0, // Latitude, Longitude in degrees minutes seconds format, comma separated
LatLonDecimal = 1, // Latitude, Longitude in decimal format, comma separated
OLCFull = 2, // Open location code, full format
OSMLink = 3, // Link to the OSM. E.g. https://osm.org/go/xcXjyqQlq-?m=
UTM = 4, // Universal Transverse Mercator
MGRS = 5 // Military Grid Reference System
};
// Keep in sync `public @interface ChoosePositionMode`in Framework.java.
enum class ChoosePositionMode
{
None = 0,
Editor = 1,
Api = 2,
};
class Framework : private power_management::PowerManager::Subscriber
{
private:
drape_ptr<dp::ThreadSafeFactory> m_oglContextFactory;
drape_ptr<dp::GraphicsContextFactory> m_vulkanContextFactory;
::Framework m_work;
math::LowPassVector<float, 3> m_sensors[2];
double m_lastCompass = 0;
std::string m_searchQuery;
std::map<gui::EWidget, gui::Position> m_guiPositions;
void TrafficStateChanged(TrafficManager::TrafficState state);
void TransitSchemeStateChanged(TransitReadManager::TransitSchemeState state);
void IsolinesSchemeStateChanged(IsolinesManager::IsolinesState state);
void MyPositionModeChanged(location::EMyPositionMode mode, bool routingActive);
location::TMyPositionModeChanged m_myPositionModeSignal;
TrafficManager::TrafficStateChangedFn m_onTrafficStateChangedFn;
TransitReadManager::TransitStateChangedFn m_onTransitStateChangedFn;
IsolinesManager::IsolinesStateChangedFn m_onIsolinesStateChangedFn;
ChoosePositionMode m_isChoosePositionMode = ChoosePositionMode::None;
bool m_isSurfaceDestroyed = false;
public:
Framework(std::function<void()> && afterMapsLoaded);
storage::Storage & GetStorage();
DataSource const & GetDataSource();
void ShowNode(storage::CountryId const & countryId, bool zoomToDownloadButton);
void OnLocationError(int/* == location::TLocationStatus*/ newStatus);
void OnLocationUpdated(location::GpsInfo const & info);
void OnCompassUpdated(location::CompassInfo const & info, bool forceRedraw);
bool CreateDrapeEngine(JNIEnv * env, jobject jSurface, int densityDpi, bool firstLaunch,
bool launchByDeepLink, uint32_t appVersionCode, bool isCustomROM);
bool IsDrapeEngineCreated() const;
void UpdateDpi(int dpi);
bool DestroySurfaceOnDetach();
void DetachSurface(bool destroySurface);
bool AttachSurface(JNIEnv * env, jobject jSurface);
void PauseSurfaceRendering();
void ResumeSurfaceRendering();
void SetMapStyle(MapStyle mapStyle);
void MarkMapStyle(MapStyle mapStyle);
MapStyle GetMapStyle() const;
void SetupMeasurementSystem();
RoutingManager & GetRoutingManager() { return m_work.GetRoutingManager(); }
void SetRouter(routing::RouterType type) { m_work.GetRoutingManager().SetRouter(type); }
routing::RouterType GetRouter() const { return m_work.GetRoutingManager().GetRouter(); }
routing::RouterType GetLastUsedRouter() const
{
return m_work.GetRoutingManager().GetLastUsedRouter();
}
void Resize(JNIEnv * env, jobject jSurface, int w, int h);
struct Finger
{
Finger(int64_t id, float x, float y)
: m_id(id)
, m_x(x)
, m_y(y)
{
}
int64_t m_id;
float m_x, m_y;
};
void Scale(double factor, m2::PointD const & pxPoint, bool isAnim);
void Scroll(double distanceX, double distanceY);
void Touch(int action, Finger const & f1, Finger const & f2, uint8_t maskedPointer);
bool Search(search::EverywhereSearchParams const & params);
std::string GetLastSearchQuery() { return m_searchQuery; }
void ClearLastSearchQuery() { m_searchQuery.clear(); }
void AddLocalMaps();
void RemoveLocalMaps();
void ReloadWorldMaps();
m2::PointD GetViewportCenter() const;
void AddString(std::string const & name, std::string const & value);
void Scale(::Framework::EScaleMode mode);
void Scale(m2::PointD const & centerPt, int targetZoom, bool animate);
void ChangeTrackColor(kml::TrackId trackId, dp::Color color);
void ReplaceBookmark(kml::MarkId markId, kml::BookmarkData & bm);
void ReplaceTrack(kml::TrackId trackId, kml::TrackData & trackData);
void MoveBookmark(kml::MarkId markId, kml::MarkGroupId curCat, kml::MarkGroupId newCat);
void MoveTrack(kml::TrackId trackId, kml::MarkGroupId curCat, kml::MarkGroupId newCat);
::Framework * NativeFramework();
bool IsDownloadingActive();
void ExecuteMapApiRequest();
void DeactivatePopup();
void DeactivateMapSelectionCircle();
// std::string GetOutdatedCountriesString();
void SetMyPositionModeListener(location::TMyPositionModeChanged const & fn);
location::EMyPositionMode GetMyPositionMode() const;
void SwitchMyPositionNextMode();
void SetTrafficStateListener(TrafficManager::TrafficStateChangedFn const & fn);
void SetTransitSchemeListener(TransitReadManager::TransitStateChangedFn const & fn);
void SetIsolinesListener(IsolinesManager::IsolinesStateChangedFn const & fn);
bool IsTrafficEnabled();
void EnableTraffic();
void DisableTraffic();
void Save3dMode(bool allow3d, bool allow3dBuildings);
void Set3dMode(bool allow3d, bool allow3dBuildings);
void Get3dMode(bool & allow3d, bool & allow3dBuildings);
void SetMapLanguageCode(std::string const & languageCode);
std::string GetMapLanguageCode();
void SetChoosePositionMode(ChoosePositionMode mode, bool isBusiness, m2::PointD const * optionalPosition);
ChoosePositionMode GetChoosePositionMode();
void UpdateMyPositionRoutingOffset(int offsetY);
void SetupWidget(gui::EWidget widget, float x, float y, dp::Anchor anchor);
void ApplyWidgets();
void CleanWidgets();
place_page::Info & GetPlacePageInfo();
bool IsAutoRetryDownloadFailed();
bool IsDownloadOn3gEnabled();
void EnableDownloadOn3g();
// int ToDoAfterUpdate() const;
// PowerManager::Subscriber overrides:
void OnPowerFacilityChanged(power_management::Facility const facility, bool enabled) override;
void OnPowerSchemeChanged(power_management::Scheme const actualScheme) override;
FeatureID BuildFeatureId(JNIEnv * env, jobject featureId);
};
}
extern std::unique_ptr<android::Framework> g_framework;
::Framework * frm();

View File

@@ -0,0 +1,93 @@
#include "Framework.hpp"
#include "map/gps_tracker.hpp"
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/platform/AndroidPlatform.hpp"
extern "C"
{
static void LocationStateModeChanged(location::EMyPositionMode mode,
std::shared_ptr<jobject> const & listener)
{
JNIEnv * env = jni::GetEnv();
env->CallVoidMethod(*listener, jni::GetMethodID(env, *listener.get(),
"onMyPositionModeChanged", "(I)V"), static_cast<jint>(mode));
}
// public static void nativeSwitchToNextMode();
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_location_LocationState_nativeSwitchToNextMode(JNIEnv * env, jclass clazz)
{
ASSERT(g_framework, ());
g_framework->SwitchMyPositionNextMode();
}
// private static int nativeGetMode();
JNIEXPORT jint JNICALL
Java_app_organicmaps_sdk_location_LocationState_nativeGetMode(JNIEnv * env, jclass clazz)
{
// GetMyPositionMode() is initialized only after drape creation.
// https://github.com/organicmaps/organicmaps/issues/1128#issuecomment-1784435190
ASSERT(g_framework && g_framework->IsDrapeEngineCreated(), ());
return g_framework->GetMyPositionMode();
}
// public static void nativeSetListener(ModeChangeListener listener);
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_location_LocationState_nativeSetListener(JNIEnv * env, jclass clazz,
jobject listener)
{
ASSERT(g_framework, ());
g_framework->SetMyPositionModeListener(std::bind(&LocationStateModeChanged, std::placeholders::_1,
jni::make_global_ref(listener)));
}
// public static void nativeRemoveListener();
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_location_LocationState_nativeRemoveListener(JNIEnv * env, jclass clazz)
{
ASSERT(g_framework, ());
g_framework->SetMyPositionModeListener(location::TMyPositionModeChanged());
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_location_LocationState_nativeOnLocationError(JNIEnv * env, jclass clazz, int errorCode)
{
ASSERT(g_framework, ());
g_framework->OnLocationError(errorCode);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_location_LocationState_nativeLocationUpdated(JNIEnv * env, jclass clazz, jlong time,
jdouble lat, jdouble lon, jfloat accuracy,
jdouble altitude, jfloat speed, jfloat bearing)
{
ASSERT(g_framework, ());
location::GpsInfo info;
info.m_source = location::EAndroidNative;
info.m_timestamp = static_cast<double>(time) / 1000.0;
info.m_latitude = lat;
info.m_longitude = lon;
if (accuracy > 0.0)
info.m_horizontalAccuracy = accuracy;
if (altitude != 0.0)
{
info.m_altitude = altitude;
info.m_verticalAccuracy = accuracy;
}
if (bearing > 0.0)
info.m_bearing = bearing;
if (speed > 0.0)
info.m_speed = speed;
g_framework->OnLocationUpdated(info);
GpsTracker::Instance().OnLocationUpdated(info);
}
} // extern "C"

View File

@@ -0,0 +1,190 @@
#include "Framework.hpp"
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/platform/AndroidPlatform.hpp"
#include "storage/storage_defines.hpp"
#include "base/logging.hpp"
#include "platform/settings.hpp"
namespace
{
void OnRenderingInitializationFinished(std::shared_ptr<jobject> const & listener)
{
JNIEnv * env = jni::GetEnv();
env->CallVoidMethod(*listener, jni::GetMethodID(env, *listener.get(),
"onRenderingInitializationFinished", "()V"));
}
} // namespace
extern "C"
{
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_Map_nativeCreateEngine(JNIEnv * env, jclass,
jobject surface, jint density,
jboolean firstLaunch,
jboolean isLaunchByDeepLink,
jint appVersionCode,
jboolean isCustomROM)
{
return g_framework->CreateDrapeEngine(env, surface, density, firstLaunch, isLaunchByDeepLink,
base::asserted_cast<uint32_t>(appVersionCode), isCustomROM);
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_Map_nativeIsEngineCreated(JNIEnv *, jclass)
{
return g_framework->IsDrapeEngineCreated();
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_Map_nativeUpdateEngineDpi(JNIEnv *, jclass, jint dpi)
{
return g_framework->UpdateDpi(dpi);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_Map_nativeExecuteMapApiRequest(JNIEnv * env, jclass)
{
return g_framework->ExecuteMapApiRequest();
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_Map_nativeSetRenderingInitializationFinishedListener(
JNIEnv *, jclass, jobject listener)
{
if (listener)
{
g_framework->NativeFramework()->SetGraphicsContextInitializationHandler(
std::bind(&OnRenderingInitializationFinished, jni::make_global_ref(listener)));
}
else
{
g_framework->NativeFramework()->SetGraphicsContextInitializationHandler(nullptr);
}
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_Map_nativeAttachSurface(JNIEnv * env, jclass, jobject surface)
{
return g_framework->AttachSurface(env, surface);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_Map_nativeDetachSurface(JNIEnv *, jclass, jboolean destroySurface)
{
g_framework->DetachSurface(destroySurface);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_Map_nativeSurfaceChanged(JNIEnv * env, jclass, jobject surface, jint w, jint h)
{
g_framework->Resize(env, surface, w, h);
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_Map_nativeDestroySurfaceOnDetach(JNIEnv *, jclass)
{
return g_framework->DestroySurfaceOnDetach();
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_Map_nativePauseSurfaceRendering(JNIEnv *, jclass)
{
g_framework->PauseSurfaceRendering();
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_Map_nativeResumeSurfaceRendering(JNIEnv *, jclass)
{
g_framework->ResumeSurfaceRendering();
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_Map_nativeUpdateMyPositionRoutingOffset(JNIEnv * env, jclass clazz, int offsetY)
{
g_framework->UpdateMyPositionRoutingOffset(offsetY);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_Map_nativeApplyWidgets(JNIEnv *, jclass)
{
g_framework->ApplyWidgets();
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_Map_nativeCleanWidgets(JNIEnv *, jclass)
{
g_framework->CleanWidgets();
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_Map_nativeSetupWidget(
JNIEnv *, jclass, jint widget, jfloat x, jfloat y, jint anchor)
{
g_framework->SetupWidget(static_cast<gui::EWidget>(widget), x, y, static_cast<dp::Anchor>(anchor));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_Map_nativeCompassUpdated(JNIEnv *, jclass, jdouble north, jboolean forceRedraw)
{
location::CompassInfo info;
info.m_bearing = north;
g_framework->OnCompassUpdated(info, forceRedraw);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_Map_nativeScalePlus(JNIEnv *, jclass)
{
g_framework->Scale(::Framework::SCALE_MAG);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_Map_nativeScaleMinus(JNIEnv *, jclass)
{
g_framework->Scale(::Framework::SCALE_MIN);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_Map_nativeOnScroll(
JNIEnv *, jclass, jdouble distanceX, jdouble distanceY)
{
g_framework->Scroll(distanceX, distanceY);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_Map_nativeOnScale(
JNIEnv *, jclass, jdouble factor, jdouble focusX, jdouble focusY, jboolean isAnim)
{
g_framework->Scale(factor, {focusX, focusY}, isAnim);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_Map_nativeOnTouch(JNIEnv *, jclass, jint action,
jint id1, jfloat x1, jfloat y1,
jint id2, jfloat x2, jfloat y2,
jint maskedPointer)
{
g_framework->Touch(action,
android::Framework::Finger(id1, x1, y1),
android::Framework::Finger(id2, x2, y2), maskedPointer);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_Map_nativeStorageConnected(JNIEnv *, jclass)
{
android::Platform::Instance().OnExternalStorageStatusChanged(true);
g_framework->AddLocalMaps();
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_Map_nativeStorageDisconnected(JNIEnv *, jclass)
{
android::Platform::Instance().OnExternalStorageStatusChanged(false);
g_framework->RemoveLocalMaps();
}
} // extern "C"

View File

@@ -0,0 +1,576 @@
#include "Framework.hpp"
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/core/jni_java_methods.hpp"
#include "coding/internal/file_data.hpp"
#include "storage/country_info_getter.hpp"
#include "storage/storage.hpp"
#include "storage/storage_helpers.hpp"
#include "base/thread_checker.hpp"
#include "platform/downloader_defines.hpp"
#include "platform/downloader_utils.hpp"
#include "platform/local_country_file_utils.hpp"
#include "platform/mwm_version.hpp"
#include <functional>
#include <memory>
#include <unordered_map>
#include <vector>
namespace
{
// The last 5% are left for applying diffs.
float const kMaxProgress = 95.0f;
float const kMaxProgressWithoutDiffs = 100.0f;
enum ItemCategory : uint32_t
{
NEAR_ME,
DOWNLOADED,
AVAILABLE,
};
struct TBatchedData
{
storage::CountryId const m_countryId;
storage::NodeStatus const m_newStatus;
storage::NodeErrorCode const m_errorCode;
bool const m_isLeaf;
TBatchedData(storage::CountryId const & countryId, storage::NodeStatus const newStatus,
storage::NodeErrorCode const errorCode, bool isLeaf)
: m_countryId(countryId), m_newStatus(newStatus), m_errorCode(errorCode), m_isLeaf(isLeaf)
{}
};
jobject g_countryChangedListener = nullptr;
DECLARE_THREAD_CHECKER(g_batchingThreadChecker);
std::unordered_map<jobject, std::vector<TBatchedData>> g_batchedCallbackData;
bool g_isBatched;
storage::Storage & GetStorage()
{
ASSERT(g_framework != nullptr, ());
return g_framework->GetStorage();
}
struct CountryItemBuilder
{
jclass m_class;
jmethodID m_ctor;
jfieldID m_Id, m_Name, m_DirectParentId, m_TopmostParentId, m_DirectParentName, m_TopmostParentName,
m_Description, m_Size, m_EnqueuedSize, m_TotalSize, m_ChildCount, m_TotalChildCount,
m_Present, m_Progress, m_DownloadedBytes, m_BytesToDownload, m_Category, m_Status, m_ErrorCode;
CountryItemBuilder(JNIEnv *env)
{
m_class = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/downloader/CountryItem");
m_ctor = jni::GetConstructorID(env, m_class, "(Ljava/lang/String;)V");
m_Id = env->GetFieldID(m_class, "id", "Ljava/lang/String;");
m_Name = env->GetFieldID(m_class, "name", "Ljava/lang/String;");
m_DirectParentId = env->GetFieldID(m_class, "directParentId", "Ljava/lang/String;");
m_TopmostParentId = env->GetFieldID(m_class, "topmostParentId", "Ljava/lang/String;");
m_DirectParentName = env->GetFieldID(m_class, "directParentName", "Ljava/lang/String;");
m_TopmostParentName = env->GetFieldID(m_class, "topmostParentName", "Ljava/lang/String;");
m_Description = env->GetFieldID(m_class, "description", "Ljava/lang/String;");
m_Size = env->GetFieldID(m_class, "size", "J");
m_EnqueuedSize = env->GetFieldID(m_class, "enqueuedSize", "J");
m_TotalSize = env->GetFieldID(m_class, "totalSize", "J");
m_ChildCount = env->GetFieldID(m_class, "childCount", "I");
m_TotalChildCount = env->GetFieldID(m_class, "totalChildCount", "I");
m_Present = env->GetFieldID(m_class, "present", "Z");
m_Progress = env->GetFieldID(m_class, "progress", "F");
m_DownloadedBytes = env->GetFieldID(m_class, "downloadedBytes", "J");
m_BytesToDownload = env->GetFieldID(m_class, "bytesToDownload", "J");
m_Category = env->GetFieldID(m_class, "category", "I");
m_Status = env->GetFieldID(m_class, "status", "I");
m_ErrorCode = env->GetFieldID(m_class, "errorCode", "I");
}
DECLARE_BUILDER_INSTANCE(CountryItemBuilder);
jobject Create(JNIEnv * env, jobject id) const
{
return env->NewObject(m_class, m_ctor, id);
}
};
static storage::CountryId const GetRootId(JNIEnv * env, jstring root)
{
return (root ? jni::ToNativeString(env, root) : GetStorage().GetRootId());
}
} // namespace
extern "C"
{
// static String nativeGetRoot();
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeGetRoot(JNIEnv * env, jclass clazz)
{
return jni::ToJavaString(env, GetStorage().GetRootId());
}
// static boolean nativeMoveFile(String oldFile, String newFile);
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeMoveFile(JNIEnv * env, jclass clazz, jstring oldFile, jstring newFile)
{
return base::MoveFileX(jni::ToNativeString(env, oldFile), jni::ToNativeString(env, newFile));
}
// static boolean nativeHasSpaceToDownloadAmount(long bytes);
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeHasSpaceToDownloadAmount(JNIEnv * env, jclass clazz, jlong bytes)
{
return storage::IsEnoughSpaceForDownload(bytes);
}
// static boolean nativeHasSpaceToDownloadCountry(String root);
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeHasSpaceToDownloadCountry(JNIEnv * env, jclass clazz, jstring root)
{
return storage::IsEnoughSpaceForDownload(jni::ToNativeString(env, root), GetStorage());
}
// static boolean nativeHasSpaceToUpdate(String root);
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeHasSpaceToUpdate(JNIEnv * env, jclass clazz, jstring root)
{
return IsEnoughSpaceForUpdate(jni::ToNativeString(env, root), GetStorage());
}
// static int nativeGetDownloadedCount();
JNIEXPORT jint JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeGetDownloadedCount(JNIEnv * env, jclass clazz)
{
return static_cast<jint>(GetStorage().GetDownloadedFilesCount());
}
// static @Nullable UpdateInfo nativeGetUpdateInfo(@Nullable String root);
JNIEXPORT jobject JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeGetUpdateInfo(JNIEnv * env, jclass clazz, jstring root)
{
storage::Storage::UpdateInfo info;
if (!GetStorage().GetUpdateInfo(GetRootId(env, root), info))
return nullptr;
static jclass const infoClass = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/downloader/UpdateInfo");
ASSERT(infoClass, (jni::DescribeException()));
static jmethodID const ctor = jni::GetConstructorID(env, infoClass, "(IJ)V");
ASSERT(ctor, (jni::DescribeException()));
return env->NewObject(infoClass, ctor, info.m_numberOfMwmFilesToUpdate, info.m_totalDownloadSizeInBytes);
}
static void UpdateItemShort(JNIEnv * env, jobject item, storage::NodeStatus const status, storage::NodeErrorCode const error)
{
auto const & ciBuilder = CountryItemBuilder::Instance(env);
env->SetIntField(item, ciBuilder.m_Status, static_cast<jint>(status));
env->SetIntField(item, ciBuilder.m_ErrorCode, static_cast<jint>(error));
}
static void UpdateItem(JNIEnv * env, jobject item, storage::NodeAttrs const & attrs)
{
auto const & ciBuilder = CountryItemBuilder::Instance(env);
using SLR = jni::TScopedLocalRef;
// Localized name
env->SetObjectField(item, ciBuilder.m_Name, SLR(env, jni::ToJavaString(env, attrs.m_nodeLocalName)).get());
// Direct parent[s]. Do not specify if there are multiple or none.
if (attrs.m_parentInfo.size() == 1)
{
storage::CountryIdAndName const & info = attrs.m_parentInfo[0];
env->SetObjectField(item, ciBuilder.m_DirectParentId, SLR(env, jni::ToJavaString(env, info.m_id)).get());
env->SetObjectField(item, ciBuilder.m_DirectParentName, SLR(env, jni::ToJavaString(env, info.m_localName)).get());
}
else
{
env->SetObjectField(item, ciBuilder.m_DirectParentId, nullptr);
env->SetObjectField(item, ciBuilder.m_DirectParentName, nullptr);
}
// Topmost parent[s]. Do not specify if there are multiple or none.
if (attrs.m_topmostParentInfo.size() == 1)
{
storage::CountryIdAndName const & info = attrs.m_topmostParentInfo[0];
env->SetObjectField(item, ciBuilder.m_TopmostParentId, SLR(env, jni::ToJavaString(env, info.m_id)).get());
env->SetObjectField(item, ciBuilder.m_TopmostParentName, SLR(env, jni::ToJavaString(env, info.m_localName)).get());
}
else
{
env->SetObjectField(item, ciBuilder.m_TopmostParentId, nullptr);
env->SetObjectField(item, ciBuilder.m_TopmostParentName, nullptr);
}
// Description
env->SetObjectField(item, ciBuilder.m_Description, SLR(env, jni::ToJavaString(env, attrs.m_nodeLocalDescription)).get());
// Sizes
env->SetLongField(item, ciBuilder.m_Size, attrs.m_localMwmSize);
env->SetLongField(item, ciBuilder.m_EnqueuedSize, attrs.m_downloadingMwmSize);
env->SetLongField(item, ciBuilder.m_TotalSize, attrs.m_mwmSize);
// Child counts
env->SetIntField(item, ciBuilder.m_ChildCount, attrs.m_downloadingMwmCounter);
env->SetIntField(item, ciBuilder.m_TotalChildCount, attrs.m_mwmCounter);
// Status and error code
UpdateItemShort(env, item, attrs.m_status, attrs.m_error);
// Presence flag
env->SetBooleanField(item, ciBuilder.m_Present, attrs.m_present);
// Progress
float percentage = 0;
if (attrs.m_downloadingProgress.m_bytesTotal != 0)
{
auto const & progress = attrs.m_downloadingProgress;
percentage = progress.m_bytesDownloaded * kMaxProgress / progress.m_bytesTotal;
}
env->SetFloatField(item, ciBuilder.m_Progress, percentage);
env->SetLongField(item, ciBuilder.m_DownloadedBytes, attrs.m_downloadingProgress.m_bytesDownloaded);
env->SetLongField(item, ciBuilder.m_BytesToDownload, attrs.m_downloadingProgress.m_bytesTotal);
}
static void PutItemsToList(
JNIEnv * env, jobject const list, storage::CountriesVec const & children, int category,
std::function<bool(storage::CountryId const & countryId, storage::NodeAttrs const & attrs)> const & predicate)
{
auto const & ciBuilder = CountryItemBuilder::Instance(env);
auto const listAddMethod = jni::ListBuilder::Instance(env).m_add;
storage::NodeAttrs attrs;
for (storage::CountryId const & child : children)
{
GetStorage().GetNodeAttrs(child, attrs);
if (predicate && !predicate(child, attrs))
continue;
using SLR = jni::TScopedLocalRef;
SLR const item(env, ciBuilder.Create(env, SLR(env, jni::ToJavaString(env, child))));
env->SetIntField(item.get(), ciBuilder.m_Category, category);
UpdateItem(env, item.get(), attrs);
// Put to resulting list
env->CallBooleanMethod(list, listAddMethod, item.get());
}
}
// static void nativeListItems(@Nullable String root, double lat, double lon, boolean hasLocation, boolean myMapsMode, List<CountryItem> result);
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeListItems(JNIEnv * env, jclass clazz, jstring parent, jdouble lat, jdouble lon, jboolean hasLocation, jboolean myMapsMode, jobject result)
{
if (hasLocation && !myMapsMode)
{
storage::CountriesVec near;
g_framework->NativeFramework()->GetCountryInfoGetter().GetRegionsCountryId(mercator::FromLatLon(lat, lon), near);
PutItemsToList(env, result, near, ItemCategory::NEAR_ME,
[](storage::CountryId const & countryId, storage::NodeAttrs const & attrs) -> bool {
return !attrs.m_present;
});
}
storage::CountriesVec downloaded, available;
GetStorage().GetChildrenInGroups(GetRootId(env, parent), downloaded, available, true);
if (myMapsMode)
PutItemsToList(env, result, downloaded, ItemCategory::DOWNLOADED, nullptr);
else
PutItemsToList(env, result, available, ItemCategory::AVAILABLE, nullptr);
}
// static void nativeUpdateItem(CountryItem item);
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeGetAttributes(JNIEnv * env, jclass, jobject item)
{
auto const & ciBuilder = CountryItemBuilder::Instance(env);
jstring id = static_cast<jstring>(env->GetObjectField(item, ciBuilder.m_Id));
storage::NodeAttrs attrs;
GetStorage().GetNodeAttrs(jni::ToNativeString(env, id), attrs);
UpdateItem(env, item, attrs);
}
// static void nativeGetStatus(String root);
JNIEXPORT jint JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeGetStatus(JNIEnv * env, jclass clazz, jstring root)
{
storage::NodeStatuses ns;
GetStorage().GetNodeStatuses(jni::ToNativeString(env, root), ns);
return static_cast<jint>(ns.m_status);
}
// static void nativeGetError(String root);
JNIEXPORT jint JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeGetError(JNIEnv * env, jclass clazz, jstring root)
{
storage::NodeStatuses ns;
GetStorage().GetNodeStatuses(jni::ToNativeString(env, root), ns);
return static_cast<jint>(ns.m_error);
}
// static String nativeGetName(String root);
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeGetName(JNIEnv * env, jclass clazz, jstring root)
{
return jni::ToJavaString(env, GetStorage().GetNodeLocalName(jni::ToNativeString(env, root)));
}
// static @Nullable String nativeFindCountry(double lat, double lon);
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeFindCountry(JNIEnv * env, jclass clazz, jdouble lat, jdouble lon)
{
return jni::ToJavaString(env, g_framework->NativeFramework()->GetCountryInfoGetter().GetRegionCountryId(mercator::FromLatLon(lat, lon)));
}
// static boolean nativeIsDownloading();
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeIsDownloading(JNIEnv * env, jclass clazz)
{
return static_cast<jboolean>(GetStorage().IsDownloadInProgress());
}
static void StartBatchingCallbacks()
{
CHECK_THREAD_CHECKER(g_batchingThreadChecker, ("StartBatchingCallbacks"));
ASSERT(!g_isBatched, ());
ASSERT(g_batchedCallbackData.empty(), ());
g_isBatched = true;
}
static void EndBatchingCallbacks(JNIEnv * env)
{
CHECK_THREAD_CHECKER(g_batchingThreadChecker, ("EndBatchingCallbacks"));
auto const & listBuilder = jni::ListBuilder::Instance(env);
for (auto & key : g_batchedCallbackData)
{
// Allocate resulting ArrayList
jni::TScopedLocalRef const list(env, listBuilder.CreateArray(env, key.second.size()));
for (TBatchedData const & dataItem : key.second)
{
// Create StorageCallbackData instance…
static jclass batchDataClass = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/downloader/MapManager$StorageCallbackData");
static jmethodID batchDataCtor = jni::GetConstructorID(env, batchDataClass, "(Ljava/lang/String;IIZ)V");
jni::TScopedLocalRef const id(env, jni::ToJavaString(env, dataItem.m_countryId));
jni::TScopedLocalRef const item(env, env->NewObject(batchDataClass, batchDataCtor, id.get(),
static_cast<jint>(dataItem.m_newStatus),
static_cast<jint>(dataItem.m_errorCode),
dataItem.m_isLeaf));
// …and put it into the resulting list
env->CallBooleanMethod(list.get(), listBuilder.m_add, item.get());
}
// Invoke Java callback
jmethodID const method = jni::GetMethodID(env, key.first, "onStatusChanged", "(Ljava/util/List;)V");
env->CallVoidMethod(key.first, method, list.get());
}
g_batchedCallbackData.clear();
g_isBatched = false;
}
// static void nativeDownload(String root);
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeDownload(JNIEnv * env, jclass clazz, jstring root)
{
StartBatchingCallbacks();
GetStorage().DownloadNode(jni::ToNativeString(env, root));
EndBatchingCallbacks(env);
}
// static boolean nativeRetry(String root);
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeRetry(JNIEnv * env, jclass clazz, jstring root)
{
StartBatchingCallbacks();
GetStorage().RetryDownloadNode(jni::ToNativeString(env, root));
EndBatchingCallbacks(env);
}
// static void nativeUpdate(String root);
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeUpdate(JNIEnv * env, jclass clazz, jstring root)
{
StartBatchingCallbacks();
GetStorage().UpdateNode(GetRootId(env, root));
EndBatchingCallbacks(env);
}
// static void nativeCancel(String root);
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeCancel(JNIEnv * env, jclass clazz, jstring root)
{
StartBatchingCallbacks();
GetStorage().CancelDownloadNode(GetRootId(env, root));
EndBatchingCallbacks(env);
}
// static void nativeDelete(String root);
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeDelete(JNIEnv * env, jclass clazz, jstring root)
{
StartBatchingCallbacks();
auto const countryId = jni::ToNativeString(env, root);
GetStorage().DeleteNode(countryId);
EndBatchingCallbacks(env);
}
static void StatusChangedCallback(std::shared_ptr<jobject> const & listenerRef,
storage::CountryId const & countryId)
{
storage::NodeStatuses ns;
GetStorage().GetNodeStatuses(countryId, ns);
TBatchedData const data(countryId, ns.m_status, ns.m_error, !ns.m_groupNode);
g_batchedCallbackData[*listenerRef].push_back(std::move(data));
if (!g_isBatched)
EndBatchingCallbacks(jni::GetEnv());
}
static void ProgressChangedCallback(std::shared_ptr<jobject> const & listenerRef,
storage::CountryId const & countryId, downloader::Progress const & progress)
{
JNIEnv * env = jni::GetEnv();
jmethodID const methodID = jni::GetMethodID(env, *listenerRef, "onProgress", "(Ljava/lang/String;JJ)V");
env->CallVoidMethod(*listenerRef, methodID, jni::ToJavaString(env, countryId),
progress.m_bytesDownloaded, progress.m_bytesTotal);
}
// static int nativeSubscribe(StorageCallback listener);
JNIEXPORT jint JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeSubscribe(JNIEnv * env, jclass clazz, jobject listener)
{
return GetStorage().Subscribe(std::bind(&StatusChangedCallback, jni::make_global_ref(listener), std::placeholders::_1),
std::bind(&ProgressChangedCallback, jni::make_global_ref(listener), std::placeholders::_1, std::placeholders::_2));
}
// static void nativeUnsubscribe(int slot);
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeUnsubscribe(JNIEnv * env, jclass clazz, jint slot)
{
GetStorage().Unsubscribe(slot);
}
// static void nativeSubscribeOnCountryChanged(CurrentCountryChangedListener listener);
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeSubscribeOnCountryChanged(JNIEnv * env, jclass clazz, jobject listener)
{
ASSERT(!g_countryChangedListener, ());
g_countryChangedListener = env->NewGlobalRef(listener);
auto const callback = [](storage::CountryId const & countryId) {
JNIEnv * env = jni::GetEnv();
jmethodID methodID = jni::GetMethodID(env, g_countryChangedListener, "onCurrentCountryChanged", "(Ljava/lang/String;)V");
env->CallVoidMethod(g_countryChangedListener, methodID, jni::TScopedLocalRef(env, jni::ToJavaString(env, countryId)).get());
};
storage::CountryId const & prev = g_framework->NativeFramework()->GetLastReportedCountry();
g_framework->NativeFramework()->SetCurrentCountryChangedListener(callback);
// Report previous value
callback(prev);
}
// static void nativeUnsubscribeOnCountryChanged();
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeUnsubscribeOnCountryChanged(JNIEnv * env, jclass clazz)
{
g_framework->NativeFramework()->SetCurrentCountryChangedListener(nullptr);
env->DeleteGlobalRef(g_countryChangedListener);
g_countryChangedListener = nullptr;
}
// static boolean nativeHasUnsavedEditorChanges(String root);
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeHasUnsavedEditorChanges(JNIEnv * env, jclass clazz, jstring root)
{
return g_framework->NativeFramework()->HasUnsavedEdits(jni::ToNativeString(env, root));
}
// static void nativeGetPathTo(String root, List<String> result);
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeGetPathTo(JNIEnv * env, jclass clazz, jstring root, jobject result)
{
auto const listAddMethod = jni::ListBuilder::Instance(env).m_add;
storage::CountriesVec path;
GetStorage().GetGroupNodePathToRoot(jni::ToNativeString(env, root), path);
for (storage::CountryId const & node : path)
env->CallBooleanMethod(result, listAddMethod, jni::TScopedLocalRef(env, jni::ToJavaString(env, node)).get());
}
// static int nativeGetOverallProgress(String[] countries);
JNIEXPORT jint JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeGetOverallProgress(JNIEnv * env, jclass clazz, jobjectArray jcountries)
{
int const size = env->GetArrayLength(jcountries);
storage::CountriesVec countries;
countries.reserve(size);
for (int i = 0; i < size; i++)
{
jni::TScopedLocalRef const item(env, env->GetObjectArrayElement(jcountries, i));
countries.push_back(jni::ToNativeString(env, static_cast<jstring>(item.get())));
}
downloader::Progress const progress = GetStorage().GetOverallProgress(countries);
jint res = 0;
if (progress.m_bytesTotal)
res = static_cast<jint>(progress.m_bytesDownloaded * kMaxProgressWithoutDiffs / progress.m_bytesTotal);
return res;
}
// static boolean nativeIsAutoretryFailed();
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeIsAutoretryFailed(JNIEnv * env, jclass clazz)
{
return g_framework->IsAutoRetryDownloadFailed();
}
// static boolean nativeIsDownloadOn3gEnabled();
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeIsDownloadOn3gEnabled(JNIEnv * env, jclass clazz)
{
return g_framework->IsDownloadOn3gEnabled();
}
// static void nativeEnableDownloadOn3g();
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeEnableDownloadOn3g(JNIEnv * env, jclass clazz)
{
g_framework->EnableDownloadOn3g();
}
// static @Nullable String nativeGetSelectedCountry();
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_downloader_MapManager_nativeGetSelectedCountry(JNIEnv * env, jclass clazz)
{
if (!g_framework->NativeFramework()->HasPlacePageInfo())
return nullptr;
storage::CountryId const & res = g_framework->GetPlacePageInfo().GetCountryId();
return (res == storage::kInvalidCountryId ? nullptr : jni::ToJavaString(env, res));
}
} // extern "C"

View File

@@ -0,0 +1,27 @@
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/Framework.hpp"
#include "indexer/map_style.hpp"
extern "C"
{
JNIEXPORT void JNICALL Java_app_organicmaps_sdk_MapStyle_nativeSet(JNIEnv *, jclass, jint mapStyle)
{
auto const val = static_cast<MapStyle>(mapStyle);
if (val != g_framework->GetMapStyle())
g_framework->SetMapStyle(val);
}
JNIEXPORT jint JNICALL Java_app_organicmaps_sdk_MapStyle_nativeGet(JNIEnv *, jclass)
{
return g_framework->GetMapStyle();
}
JNIEXPORT void JNICALL Java_app_organicmaps_sdk_MapStyle_nativeMark(JNIEnv *, jclass, jint mapStyle)
{
auto const val = static_cast<MapStyle>(mapStyle);
if (val != g_framework->GetMapStyle())
g_framework->MarkMapStyle(val);
}
}

View File

@@ -0,0 +1,56 @@
#include "app/organicmaps/sdk/Framework.hpp"
#include "app/organicmaps/sdk/platform/AndroidPlatform.hpp"
#include "app/organicmaps/sdk/core/jni_helper.hpp"
extern "C"
{
// static void nativeSetSettingsDir(String settingsPath);
JNIEXPORT void JNICALL Java_app_organicmaps_sdk_OrganicMaps_nativeSetSettingsDir(JNIEnv * env, jclass clazz,
jstring settingsPath)
{
android::Platform::Instance().SetSettingsDir(jni::ToNativeString(env, settingsPath));
}
// static void nativeInitPlatform(Context context, String apkPath, String storagePath, String privatePath, String
// tmpPath, String flavorName, String buildType, boolean isTablet);
JNIEXPORT void JNICALL Java_app_organicmaps_sdk_OrganicMaps_nativeInitPlatform(
JNIEnv * env, jclass clazz, jobject context, jstring apkPath, jstring writablePath, jstring privatePath,
jstring tmpPath, jstring flavorName, jstring buildType, jboolean isTablet)
{
android::Platform::Instance().Initialize(env, context, apkPath, writablePath, privatePath, tmpPath, flavorName,
buildType, isTablet);
}
// static void nativeInitFramework(@NonNull Runnable onComplete);
JNIEXPORT void JNICALL Java_app_organicmaps_sdk_OrganicMaps_nativeInitFramework(JNIEnv * env, jclass clazz,
jobject onComplete)
{
if (!g_framework)
{
g_framework = std::make_unique<android::Framework>(
[onComplete = jni::make_global_ref(onComplete)]()
{
JNIEnv * env = jni::GetEnv();
jmethodID const methodId = jni::GetMethodID(env, *onComplete, "run", "()V");
env->CallVoidMethod(*onComplete, methodId);
});
}
}
// static void nativeAddLocalization(String name, String value);
JNIEXPORT void JNICALL Java_app_organicmaps_sdk_OrganicMaps_nativeAddLocalization(JNIEnv * env, jclass clazz,
jstring name, jstring value)
{
g_framework->AddString(jni::ToNativeString(env, name), jni::ToNativeString(env, value));
}
JNIEXPORT void JNICALL Java_app_organicmaps_sdk_OrganicMaps_nativeOnTransit(JNIEnv *, jclass, jboolean foreground)
{
if (static_cast<bool>(foreground))
g_framework->NativeFramework()->EnterForeground();
else
g_framework->NativeFramework()->EnterBackground();
}
}

View File

@@ -0,0 +1,41 @@
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/Framework.hpp"
#include "indexer/map_style.hpp"
extern "C"
{
JNIEXPORT void JNICALL Java_app_organicmaps_sdk_Router_nativeSet(JNIEnv *, jclass, jint routerType)
{
using Type = routing::RouterType;
Type type;
switch (routerType)
{
case 0: type = Type::Vehicle; break;
case 1: type = Type::Pedestrian; break;
case 2: type = Type::Bicycle; break;
case 3: type = Type::Transit; break;
case 4: type = Type::Ruler; break;
default: ASSERT(false, (routerType)); return;
}
frm()->GetRoutingManager().SetRouter(type);
}
JNIEXPORT jint JNICALL Java_app_organicmaps_sdk_Router_nativeGet(JNIEnv *, jclass)
{
return static_cast<jint>(frm()->GetRoutingManager().GetRouter());
}
JNIEXPORT jint JNICALL Java_app_organicmaps_sdk_Router_nativeGetLastUsed(JNIEnv *, jclass)
{
return static_cast<jint>(frm()->GetRoutingManager().GetLastUsedRouter());
}
JNIEXPORT jint JNICALL Java_app_organicmaps_sdk_Router_nativeGetBest(JNIEnv *, jclass, jdouble srcLat, jdouble srcLon,
jdouble dstLat, jdouble dstLon)
{
return static_cast<jint>(frm()->GetRoutingManager().GetBestRouter(mercator::FromLatLon(srcLat, srcLon),
mercator::FromLatLon(dstLat, dstLon)));
}
}

View File

@@ -0,0 +1,59 @@
#include "Framework.hpp"
#include "map/gps_tracker.hpp"
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include <chrono>
extern "C"
{
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_location_TrackRecorder_nativeSetEnabled(JNIEnv * env, jclass clazz, jboolean enable)
{
GpsTracker::Instance().SetEnabled(enable);
Framework * const f = frm();
if (f == nullptr)
return;
if (enable)
f->ConnectToGpsTracker();
else
f->DisconnectFromGpsTracker();
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_location_TrackRecorder_nativeIsEnabled(JNIEnv * env, jclass clazz)
{
return GpsTracker::Instance().IsEnabled();
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_location_TrackRecorder_nativeStartTrackRecording(JNIEnv * env, jclass clazz)
{
frm()->StartTrackRecording();
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_location_TrackRecorder_nativeStopTrackRecording(JNIEnv * env, jclass clazz)
{
frm()->StopTrackRecording();
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_location_TrackRecorder_nativeSaveTrackRecordingWithName(JNIEnv * env, jclass clazz, jstring name)
{
frm()->SaveTrackRecordingWithName(jni::ToNativeString(env, name));
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_location_TrackRecorder_nativeIsTrackRecordingEmpty(JNIEnv * env, jclass clazz)
{
return frm()->IsTrackRecordingEmpty();
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_location_TrackRecorder_nativeIsTrackRecordingEnabled(JNIEnv * env, jclass clazz)
{
return frm()->IsTrackRecordingEnabled();
}
}

View File

@@ -0,0 +1,49 @@
#include "Framework.hpp"
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/platform/AndroidPlatform.hpp"
extern "C"
{
static void TrafficStateChanged(TrafficManager::TrafficState state, std::shared_ptr<jobject> const & listener)
{
JNIEnv * env = jni::GetEnv();
env->CallVoidMethod(*listener, jni::GetMethodID(env, *listener, "onTrafficStateChanged", "(I)V"), static_cast<jint>(state));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_maplayer_traffic_TrafficState_nativeSetListener(JNIEnv * env, jclass clazz, jobject listener)
{
CHECK(g_framework, ("Framework isn't created yet!"));
g_framework->SetTrafficStateListener(std::bind(&TrafficStateChanged, std::placeholders::_1, jni::make_global_ref(listener)));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_maplayer_traffic_TrafficState_nativeRemoveListener(JNIEnv * env, jclass clazz)
{
CHECK(g_framework, ("Framework isn't created yet!"));
g_framework->SetTrafficStateListener(TrafficManager::TrafficStateChangedFn());
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_maplayer_traffic_TrafficState_nativeEnable(JNIEnv * env, jclass clazz)
{
CHECK(g_framework, ("Framework isn't created yet!"));
g_framework->EnableTraffic();
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_maplayer_traffic_TrafficState_nativeIsEnabled(JNIEnv * env, jclass clazz)
{
CHECK(g_framework, ("Framework isn't created yet!"));
return static_cast<jboolean>(g_framework->IsTrafficEnabled());
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_maplayer_traffic_TrafficState_nativeDisable(JNIEnv * env, jclass clazz)
{
CHECK(g_framework, ("Framework isn't created yet!"));
g_framework->DisableTraffic();
}
} // extern "C"

View File

@@ -0,0 +1,240 @@
#include "UserMarkHelper.hpp"
#include "app/organicmaps/sdk/routing/RoutePointInfo.hpp"
#include "map/elevation_info.hpp"
#include "map/place_page_info.hpp"
#include "base/string_utils.hpp"
namespace usermark_helper
{
void InjectMetadata(JNIEnv * env, jclass const clazz, jobject const mapObject, osm::MapObject const & src)
{
static jmethodID const addId = env->GetMethodID(clazz, "addMetadata", "(ILjava/lang/String;)V");
ASSERT(addId, ());
src.ForEachMetadataReadable([env, &mapObject](osm::MapObject::MetadataID id, std::string const & meta)
{
/// @todo Make separate processing of non-string values like FMD_DESCRIPTION.
/// Actually, better to call separate getters instead of ToString processing.
if (!meta.empty())
{
jni::TScopedLocalRef metaString(env, jni::ToJavaString(env, meta));
env->CallVoidMethod(mapObject, addId, static_cast<jint>(id), metaString.get());
}
});
}
//jobject CreatePopularity(JNIEnv * env, place_page::Info const & info)
//{
// static jclass const popularityClass =
// jni::GetGlobalClassRef(env, "app/organicmaps/sdk/search/Popularity");
// static jmethodID const popularityConstructor =
// jni::GetConstructorID(env, popularityClass, "(I)V");
// auto const popularityValue = info.GetPopularity();
// return env->NewObject(popularityClass, popularityConstructor, static_cast<jint>(popularityValue));
//}
jobject CreateMapObject(JNIEnv * env, place_page::Info const & info, int mapObjectType,
double lat, double lon, bool parseMeta, bool parseApi,
jobject const & routingPointInfo, jobject const & popularity, jobjectArray jrawTypes)
{
// public MapObject(@NonNull FeatureId featureId, @MapObjectType int mapObjectType, String title,
// @Nullable String secondaryTitle, String subtitle, String address,
// double lat, double lon, String apiId, @Nullable RoutePointInfo routePointInfo,
// @OpeningMode int openingMode, @NonNull Popularity popularity, @NonNull String description,
// int roadWarningType, @Nullable String[] rawTypes)
static jmethodID const ctorId = jni::GetConstructorID(
env, g_mapObjectClazz,
"("
"Lapp/organicmaps/sdk/bookmarks/data/FeatureId;" // featureId
"I" // mapObjectType
"Ljava/lang/String;" // title
"Ljava/lang/String;" // secondaryTitle
"Ljava/lang/String;" // subtitle
"Ljava/lang/String;" // address
"DD" // lat, lon
"Ljava/lang/String;" // appId
"Lapp/organicmaps/sdk/routing/RoutePointInfo;" // routePointInfo
"I" // openingMode
"Lapp/organicmaps/sdk/search/Popularity;" // popularity
"Ljava/lang/String;" // description
"I" // roadWarnType
"[Ljava/lang/String;" // rawTypes
")V");
//public FeatureId(@NonNull String mwmName, long mwmVersion, int featureIndex)
static jmethodID const featureCtorId =
jni::GetConstructorID(env, g_featureIdClazz, "(Ljava/lang/String;JI)V");
auto const fID = info.GetID();
jni::TScopedLocalRef jMwmName(env, jni::ToJavaString(env, fID.GetMwmName()));
jni::TScopedLocalRef jFeatureId(
env, env->NewObject(g_featureIdClazz, featureCtorId, jMwmName.get(), (jlong)fID.GetMwmVersion(),
(jint)fID.m_index));
jni::TScopedLocalRef jTitle(env, jni::ToJavaString(env, info.GetTitle()));
jni::TScopedLocalRef jSecondaryTitle(env, jni::ToJavaString(env, info.GetSecondaryTitle()));
jni::TScopedLocalRef jSubtitle(env, jni::ToJavaStringWithSupplementalCharsFix(env, info.GetSubtitle()));
jni::TScopedLocalRef jAddress(env, jni::ToJavaString(env, info.GetSecondarySubtitle()));
jni::TScopedLocalRef jApiId(env, jni::ToJavaString(env, parseApi ? info.GetApiUrl() : ""));
jni::TScopedLocalRef jWikiDescription(env, jni::ToJavaString(env, info.GetWikiDescription()));
jobject mapObject =
env->NewObject(g_mapObjectClazz, ctorId, jFeatureId.get(), mapObjectType, jTitle.get(),
jSecondaryTitle.get(), jSubtitle.get(), jAddress.get(), lat, lon, jApiId.get(),
routingPointInfo,
static_cast<jint>(info.GetOpeningMode()), popularity, jWikiDescription.get(),
static_cast<jint>(info.GetRoadType()), jrawTypes);
if (parseMeta)
InjectMetadata(env, g_mapObjectClazz, mapObject, info);
return mapObject;
}
jobject CreateBookmark(JNIEnv *env, const place_page::Info &info,
const jni::TScopedLocalObjectArrayRef &jrawTypes,
const jni::TScopedLocalRef &routingPointInfo,
jobject const & popularity)
{
//public Bookmark(@NonNull FeatureId featureId, @IntRange(from = 0) long categoryId,
// @IntRange(from = 0) long bookmarkId, String title, @Nullable String secondaryTitle,
// @Nullable String subtitle, @Nullable String address, @Nullable RoutePointInfo routePointInfo,
// @OpeningMode int openingMode, @NonNull Popularity popularity, @NonNull String description,
// @Nullable String[] rawTypes)
static jmethodID const ctorId =
jni::GetConstructorID(env, g_bookmarkClazz,
"(Lapp/organicmaps/sdk/bookmarks/data/FeatureId;JJLjava/lang/String;"
"Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;"
"Lapp/organicmaps/sdk/routing/RoutePointInfo;"
"ILapp/organicmaps/sdk/search/Popularity;Ljava/lang/String;"
"[Ljava/lang/String;)V");
static jmethodID const featureCtorId =
jni::GetConstructorID(env, g_featureIdClazz, "(Ljava/lang/String;JI)V");
auto const bookmarkId = info.GetBookmarkId();
auto const categoryId = info.GetBookmarkCategoryId();
jni::TScopedLocalRef jMwmName(env, jni::ToJavaString(env, info.GetID().GetMwmName()));
jni::TScopedLocalRef jFeatureId(
env, env->NewObject(g_featureIdClazz, featureCtorId, jMwmName.get(),
(jlong)info.GetID().GetMwmVersion(), (jint)info.GetID().m_index));
jni::TScopedLocalRef jTitle(env, jni::ToJavaString(env, info.GetTitle()));
jni::TScopedLocalRef jSecondaryTitle(env, jni::ToJavaString(env, info.GetSecondaryTitle()));
jni::TScopedLocalRef jSubtitle(env, jni::ToJavaStringWithSupplementalCharsFix(env, info.GetSubtitle()));
jni::TScopedLocalRef jAddress(env, jni::ToJavaString(env, info.GetSecondarySubtitle()));
jni::TScopedLocalRef jWikiDescription(env, jni::ToJavaString(env, info.GetWikiDescription()));
jobject mapObject = env->NewObject(
g_bookmarkClazz, ctorId, jFeatureId.get(), static_cast<jlong>(categoryId),
static_cast<jlong>(bookmarkId), jTitle.get(), jSecondaryTitle.get(), jSubtitle.get(),
jAddress.get(), routingPointInfo.get(), info.GetOpeningMode(), popularity,
jWikiDescription.get(), jrawTypes.get());
if (info.HasMetadata())
InjectMetadata(env, g_mapObjectClazz, mapObject, info);
return mapObject;
}
jobject CreateElevationPoint(JNIEnv * env, ElevationInfo::Point const & point)
{
static jclass const pointClass =
jni::GetGlobalClassRef(env, "app/organicmaps/sdk/bookmarks/data/ElevationInfo$Point");
// public Point(double distance, int altitude)
static jmethodID const pointCtorId =
jni::GetConstructorID(env, pointClass, "(DI)V");
return env->NewObject(pointClass, pointCtorId, static_cast<jdouble >(point.m_distance),
static_cast<jint>(point.m_point.GetAltitude()));
}
jobjectArray ToElevationPointArray(JNIEnv * env, ElevationInfo::Points const & points)
{
CHECK(!points.empty(), ("Elevation points must be non empty!"));
static jclass const pointClass =
jni::GetGlobalClassRef(env, "app/organicmaps/sdk/bookmarks/data/ElevationInfo$Point");
return jni::ToJavaArray(env, pointClass, points,
[](JNIEnv * env, ElevationInfo::Point const & item)
{
return CreateElevationPoint(env, item);
});
}
jobject CreateElevationInfo(JNIEnv * env, ElevationInfo const & info)
{
// public ElevationInfo(long trackId, @NonNull String name, @NonNull Point[] points,
// int ascent, int descent, int minAltitude, int maxAltitude, int difficulty,
// long m_duration)
static jmethodID const ctorId =
jni::GetConstructorID(env, g_elevationInfoClazz, "(JLjava/lang/String;Ljava/lang/String;"
"[Lapp/organicmaps/sdk/bookmarks/data/ElevationInfo$Point;"
"IIIIIJ)V");
jni::TScopedLocalObjectArrayRef jPoints(env, ToElevationPointArray(env, info.GetPoints()));
// TODO (KK): elevation info should have only the elevation data - see the https://github.com/organicmaps/organicmaps/pull/10063
return env->NewObject(g_elevationInfoClazz, ctorId,
jPoints.get(),
// static_cast<jint>(info.GetAscent()),
// static_cast<jint>(info.GetDescent()),
// static_cast<jint>(info.GetMinAltitude()),
// static_cast<jint>(info.GetMaxAltitude()),
static_cast<jint>(info.GetDifficulty()));
}
jobject CreateMapObject(JNIEnv * env, place_page::Info const & info)
{
jni::TScopedLocalObjectArrayRef jrawTypes(env, jni::ToJavaStringArray(env, info.GetRawTypes()));
jni::TScopedLocalRef routingPointInfo(env, nullptr);
if (info.IsRoutePoint())
routingPointInfo.reset(CreateRoutePointInfo(env, info));
//jni::TScopedLocalRef popularity(env, CreatePopularity(env, info));
jobject popularity = nullptr;
if (info.IsBookmark())
{
return CreateBookmark(env, info, jrawTypes, routingPointInfo, popularity);
}
ms::LatLon const ll = info.GetLatLon();
// TODO(yunikkk): object can be POI + API + search result + bookmark simultaneously.
// TODO(yunikkk): Should we pass localized strings here and in other methods as byte arrays?
if (info.IsMyPosition())
{
return CreateMapObject(env, info, kMyPosition, ll.m_lat, ll.m_lon,
false /* parseMeta */, false /* parseApi */,
routingPointInfo.get(), popularity, jrawTypes.get());
}
if (info.HasApiUrl())
{
return CreateMapObject(env, info, kApiPoint, ll.m_lat, ll.m_lon,
true /* parseMeta */, true /* parseApi */,
routingPointInfo.get(), popularity, jrawTypes.get());
}
return CreateMapObject(env, info, kPoi, ll.m_lat, ll.m_lon,
true /* parseMeta */, false /* parseApi */,
routingPointInfo.get(), popularity, jrawTypes.get());
}
jobject CreateFeatureId(JNIEnv * env, FeatureID const & fid)
{
static jmethodID const featureCtorId =
jni::GetConstructorID(env, g_featureIdClazz, "(Ljava/lang/String;JI)V");
auto const & info = fid.m_mwmId.GetInfo();
jni::TScopedLocalRef jMwmName(env, jni::ToJavaString(env, info ? info->GetCountryName() : ""));
return env->NewObject(g_featureIdClazz, featureCtorId, jMwmName.get(),
info ? static_cast<jlong>(info->GetVersion()) : 0,
static_cast<jint>(fid.m_index));
}
jobjectArray ToFeatureIdArray(JNIEnv * env, std::vector<FeatureID> const & ids)
{
if (ids.empty())
return nullptr;
return jni::ToJavaArray(env, g_featureIdClazz, ids,
[](JNIEnv * env, FeatureID const & fid) {
return CreateFeatureId(env, fid);
});
}
} // namespace usermark_helper

View File

@@ -0,0 +1,45 @@
#pragma once
#include <jni.h>
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/Framework.hpp"
#include <vector>
namespace place_page
{
class Info;
} // namespace place_page
// TODO(yunikkk): this helper is redundant with new place page info approach.
// It's better to refactor MapObject in Java, may be removing it at all, and to make simple jni getters for
// globally stored place_page::Info object. Code should be clean and easy to support in this way.
namespace usermark_helper
{
// TODO(yunikkk): PP can be POI and bookmark at the same time. And can be even POI + bookmark + API at the same time.
// The same for search result: it can be also a POI and bookmark (and API!).
// That is one of the reasons why existing solution should be refactored.
// should be equal with definitions in MapObject.java
static constexpr int kPoi = 0;
static constexpr int kApiPoint = 1;
static constexpr int kBookmark = 2;
static constexpr int kMyPosition = 3;
static constexpr int kSearch = 4;
static constexpr int kPriceRateUndefined = -1;
// Fills mapobject's metadata.
void InjectMetadata(JNIEnv * env, jclass clazz, jobject const mapObject, feature::Metadata const & metadata);
jobject CreateMapObject(JNIEnv * env, place_page::Info const & info);
jobject CreateElevationInfo(JNIEnv * env, ElevationInfo const & info);
jobjectArray ToRatingArray(JNIEnv * env, std::vector<std::string> const & ratingCategories);
jobject CreateLocalAdInfo(JNIEnv * env, place_page::Info const & info);
jobject CreateFeatureId(JNIEnv * env, FeatureID const & fid);
jobjectArray ToFeatureIdArray(JNIEnv * env, std::vector<FeatureID> const & ids);
} // namespace usermark_helper

View File

@@ -0,0 +1,943 @@
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/Framework.hpp"
#include "app/organicmaps/sdk/UserMarkHelper.hpp"
#include "app/organicmaps/sdk/util/Distance.hpp"
#include "map/bookmark_helpers.hpp"
#include "map/place_page_info.hpp"
#include "coding/zip_creator.hpp"
#include "platform/localization.hpp"
#include "platform/preferred_languages.hpp"
#include "base/macros.hpp"
#include "base/string_utils.hpp"
#include <limits>
#include <utility>
using namespace jni;
using namespace std::placeholders;
namespace
{
jclass g_bookmarkManagerClass;
jfieldID g_bookmarkManagerInstanceField;
jmethodID g_onBookmarksChangedMethod;
jmethodID g_onBookmarksLoadingStartedMethod;
jmethodID g_onBookmarksLoadingFinishedMethod;
jmethodID g_onBookmarksFileLoadedMethod;
jmethodID g_onPreparedFileForSharingMethod;
jmethodID g_onElevationActivePointChangedMethod;
jmethodID g_onElevationCurrentPositionChangedMethod;
jclass g_bookmarkCategoryClass;
jmethodID g_bookmarkCategoryConstructor;
jclass g_sortedBlockClass;
jmethodID g_sortedBlockConstructor;
jclass g_longClass;
jmethodID g_longConstructor;
jmethodID g_onBookmarksSortingCompleted;
jmethodID g_onBookmarksSortingCancelled;
jmethodID g_bookmarkInfoConstructor;
jclass g_bookmarkInfoClass;
void PrepareClassRefs(JNIEnv * env)
{
if (g_bookmarkManagerClass)
return;
g_bookmarkManagerClass =
jni::GetGlobalClassRef(env, "app/organicmaps/sdk/bookmarks/data/BookmarkManager");
g_bookmarkManagerInstanceField = jni::GetStaticFieldID(env, g_bookmarkManagerClass, "INSTANCE",
"Lapp/organicmaps/sdk/bookmarks/data/BookmarkManager;");
jobject bookmarkManagerInstance = env->GetStaticObjectField(g_bookmarkManagerClass,
g_bookmarkManagerInstanceField);
g_onBookmarksChangedMethod =
jni::GetMethodID(env, bookmarkManagerInstance, "onBookmarksChanged", "()V");
g_onBookmarksLoadingStartedMethod =
jni::GetMethodID(env, bookmarkManagerInstance, "onBookmarksLoadingStarted", "()V");
g_onBookmarksLoadingFinishedMethod =
jni::GetMethodID(env, bookmarkManagerInstance, "onBookmarksLoadingFinished", "()V");
g_onBookmarksFileLoadedMethod =
jni::GetMethodID(env, bookmarkManagerInstance, "onBookmarksFileLoaded",
"(ZLjava/lang/String;Z)V");
g_onPreparedFileForSharingMethod =
jni::GetMethodID(env, bookmarkManagerInstance, "onPreparedFileForSharing",
"(Lapp/organicmaps/sdk/bookmarks/data/BookmarkSharingResult;)V");
g_longClass = jni::GetGlobalClassRef(env,"java/lang/Long");
g_longConstructor = jni::GetConstructorID(env, g_longClass, "(J)V");
g_sortedBlockClass =
jni::GetGlobalClassRef(env, "app/organicmaps/sdk/bookmarks/data/SortedBlock");
g_sortedBlockConstructor =
jni::GetConstructorID(env, g_sortedBlockClass,
"(Ljava/lang/String;[Ljava/lang/Long;[Ljava/lang/Long;)V");
g_onBookmarksSortingCompleted = jni::GetMethodID(env, bookmarkManagerInstance,
"onBookmarksSortingCompleted", "([Lapp/organicmaps/sdk/bookmarks/data/SortedBlock;J)V");
g_onBookmarksSortingCancelled = jni::GetMethodID(env, bookmarkManagerInstance,
"onBookmarksSortingCancelled", "(J)V");
g_bookmarkInfoClass =
jni::GetGlobalClassRef(env, "app/organicmaps/sdk/bookmarks/data/BookmarkInfo");
g_bookmarkInfoConstructor =
jni::GetConstructorID(env, g_bookmarkInfoClass, "(JJ)V" );
g_bookmarkCategoryClass =
jni::GetGlobalClassRef(env, "app/organicmaps/sdk/bookmarks/data/BookmarkCategory");
//public BookmarkCategory(long id,
// String name,
// String annotation,
// String desc,
// int tracksCount,
// int bookmarksCount,
// boolean isVisible)
g_bookmarkCategoryConstructor =
jni::GetConstructorID(env, g_bookmarkCategoryClass,
"("
"J" // id
"Ljava/lang/String;" // name
"Ljava/lang/String;" // annotation
"Ljava/lang/String;" // desc
"I" // tracksCount
"I" // bookmarksCount
"Z" // isVisible
")V");
g_onElevationCurrentPositionChangedMethod =
jni::GetMethodID(env, bookmarkManagerInstance, "onElevationCurrentPositionChanged", "()V");
g_onElevationActivePointChangedMethod =
jni::GetMethodID(env, bookmarkManagerInstance, "onElevationActivePointChanged", "()V");
}
void OnElevationCurPositionChanged(JNIEnv * env)
{
ASSERT(g_bookmarkManagerClass, ());
jobject bookmarkManagerInstance =
env->GetStaticObjectField(g_bookmarkManagerClass, g_bookmarkManagerInstanceField);
env->CallVoidMethod(bookmarkManagerInstance, g_onElevationCurrentPositionChangedMethod);
jni::HandleJavaException(env);
}
void OnElevationActivePointChanged(JNIEnv * env)
{
ASSERT(g_bookmarkManagerClass, ());
jobject bookmarkManagerInstance = env->GetStaticObjectField(g_bookmarkManagerClass,
g_bookmarkManagerInstanceField);
env->CallVoidMethod(bookmarkManagerInstance, g_onElevationActivePointChangedMethod);
jni::HandleJavaException(env);
}
void OnBookmarksChanged(JNIEnv * env)
{
ASSERT(g_bookmarkManagerClass, ());
jobject bookmarkManagerInstance = env->GetStaticObjectField(g_bookmarkManagerClass,
g_bookmarkManagerInstanceField);
env->CallVoidMethod(bookmarkManagerInstance, g_onBookmarksChangedMethod);
jni::HandleJavaException(env);
}
void OnAsyncLoadingStarted(JNIEnv * env)
{
ASSERT(g_bookmarkManagerClass, ());
jobject bookmarkManagerInstance = env->GetStaticObjectField(g_bookmarkManagerClass,
g_bookmarkManagerInstanceField);
env->CallVoidMethod(bookmarkManagerInstance, g_onBookmarksLoadingStartedMethod);
jni::HandleJavaException(env);
}
void OnAsyncLoadingFinished(JNIEnv * env)
{
ASSERT(g_bookmarkManagerClass, ());
jobject bookmarkManagerInstance = env->GetStaticObjectField(g_bookmarkManagerClass,
g_bookmarkManagerInstanceField);
env->CallVoidMethod(bookmarkManagerInstance, g_onBookmarksLoadingFinishedMethod);
jni::HandleJavaException(env);
}
void OnAsyncLoadingFileSuccess(JNIEnv * env, std::string const & fileName, bool isTemporaryFile)
{
ASSERT(g_bookmarkManagerClass, ());
jobject bookmarkManagerInstance = env->GetStaticObjectField(g_bookmarkManagerClass,
g_bookmarkManagerInstanceField);
jni::TScopedLocalRef jFileName(env, jni::ToJavaString(env, fileName));
env->CallVoidMethod(bookmarkManagerInstance, g_onBookmarksFileLoadedMethod,
true /* success */, jFileName.get(), isTemporaryFile);
jni::HandleJavaException(env);
}
void OnAsyncLoadingFileError(JNIEnv * env, std::string const & fileName, bool isTemporaryFile)
{
ASSERT(g_bookmarkManagerClass, ());
jobject bookmarkManagerInstance = env->GetStaticObjectField(g_bookmarkManagerClass,
g_bookmarkManagerInstanceField);
jni::TScopedLocalRef jFileName(env, jni::ToJavaString(env, fileName));
env->CallVoidMethod(bookmarkManagerInstance, g_onBookmarksFileLoadedMethod,
false /* success */, jFileName.get(), isTemporaryFile);
jni::HandleJavaException(env);
}
void OnPreparedFileForSharing(JNIEnv * env, BookmarkManager::SharingResult const & result)
{
static jclass const classBookmarkSharingResult = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/bookmarks/data/BookmarkSharingResult");
// BookmarkSharingResult(long[] categoriesIds, @Code int code, @NonNull String sharingPath, @NonNull String mimeType, @NonNull String errorString)
static jmethodID const ctorBookmarkSharingResult = jni::GetConstructorID(env, classBookmarkSharingResult, "([JILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
static_assert(sizeof(jlong) == sizeof(decltype(result.m_categoriesIds)::value_type));
jsize const categoriesIdsSize = static_cast<jsize>(result.m_categoriesIds.size());
jni::ScopedLocalRef<jlongArray> categoriesIds(env, env->NewLongArray(categoriesIdsSize));
env->SetLongArrayRegion(categoriesIds.get(), 0, categoriesIdsSize, reinterpret_cast<jlong const *>(result.m_categoriesIds.data()));
jni::TScopedLocalRef const sharingPath(env, jni::ToJavaString(env, result.m_sharingPath));
jni::TScopedLocalRef const mimeType(env, jni::ToJavaString(env, result.m_mimeType));
jni::TScopedLocalRef const errorString(env, jni::ToJavaString(env, result.m_errorString));
jni::TScopedLocalRef const sharingResult(env, env->NewObject(classBookmarkSharingResult, ctorBookmarkSharingResult,
categoriesIds.get(), static_cast<jint>(result.m_code), sharingPath.get(), mimeType.get(), errorString.get()));
ASSERT(g_bookmarkManagerClass, ());
jobject bookmarkManagerInstance = env->GetStaticObjectField(g_bookmarkManagerClass, g_bookmarkManagerInstanceField);
env->CallVoidMethod(bookmarkManagerInstance, g_onPreparedFileForSharingMethod, sharingResult.get());
jni::HandleJavaException(env);
}
void OnCategorySortingResults(JNIEnv * env, long long timestamp,
BookmarkManager::SortedBlocksCollection && sortedBlocks,
BookmarkManager::SortParams::Status status)
{
ASSERT(g_bookmarkManagerClass, ());
ASSERT(g_sortedBlockClass, ());
ASSERT(g_sortedBlockConstructor, ());
jobject bookmarkManagerInstance = env->GetStaticObjectField(g_bookmarkManagerClass,
g_bookmarkManagerInstanceField);
if (status == BookmarkManager::SortParams::Status::Cancelled)
{
env->CallVoidMethod(bookmarkManagerInstance, g_onBookmarksSortingCancelled,
static_cast<jlong>(timestamp));
jni::HandleJavaException(env);
return;
}
jni::TScopedLocalObjectArrayRef blocksRef(env,
jni::ToJavaArray(env, g_sortedBlockClass, sortedBlocks,
[](JNIEnv * env, BookmarkManager::SortedBlock const & block)
{
jni::TScopedLocalRef blockNameRef(env, jni::ToJavaString(env, block.m_blockName));
jni::TScopedLocalObjectArrayRef marksRef(env,
jni::ToJavaArray(env, g_longClass, block.m_markIds,
[](JNIEnv * env, kml::MarkId const & markId)
{
return env->NewObject(g_longClass, g_longConstructor,
static_cast<jlong>(markId));
}));
jni::TScopedLocalObjectArrayRef tracksRef(env,
jni::ToJavaArray(env, g_longClass, block.m_trackIds,
[](JNIEnv * env, kml::TrackId const & trackId)
{
return env->NewObject(g_longClass, g_longConstructor,
static_cast<jlong>(trackId));
}));
return env->NewObject(g_sortedBlockClass, g_sortedBlockConstructor,
blockNameRef.get(), marksRef.get(), tracksRef.get());
}));
env->CallVoidMethod(bookmarkManagerInstance, g_onBookmarksSortingCompleted,
blocksRef.get(), static_cast<jlong>(timestamp));
jni::HandleJavaException(env);
}
Bookmark const * getBookmark(jlong bokmarkId)
{
Bookmark const * pBmk = frm()->GetBookmarkManager().GetBookmark(static_cast<kml::MarkId>(bokmarkId));
ASSERT(pBmk, ("Bookmark not found, id", bokmarkId));
return pBmk;
}
jobject MakeCategory(JNIEnv * env, kml::MarkGroupId id)
{
auto const & manager = frm()->GetBookmarkManager();
auto const & data = manager.GetCategoryData(id);
auto const tracksCount = manager.GetTrackIds(data.m_id).size();
auto const bookmarksCount = manager.GetUserMarkIds(data.m_id).size();
auto const isVisible = manager.IsVisible(data.m_id);
auto const preferBookmarkStr = GetPreferredBookmarkStr(data.m_name);
auto const annotation = GetPreferredBookmarkStr(data.m_annotation);
auto const description = GetPreferredBookmarkStr(data.m_description);
jni::TScopedLocalRef preferBookmarkStrRef(env, jni::ToJavaString(env, preferBookmarkStr));
jni::TScopedLocalRef annotationRef(env, jni::ToJavaString(env, annotation));
jni::TScopedLocalRef descriptionRef(env, jni::ToJavaString(env, description));
return env->NewObject(g_bookmarkCategoryClass,
g_bookmarkCategoryConstructor,
static_cast<jlong>(data.m_id),
preferBookmarkStrRef.get(),
annotationRef.get(),
descriptionRef.get(),
static_cast<jint>(tracksCount),
static_cast<jint>(bookmarksCount),
static_cast<jboolean>(isVisible));
}
jobjectArray MakeCategories(JNIEnv * env, kml::GroupIdCollection const & ids)
{
return ToJavaArray(env, g_bookmarkCategoryClass, ids, std::bind(&MakeCategory, _1, _2));
}
} // namespace
extern "C"
{
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeShowBookmarkOnMap(
JNIEnv *, jobject, jlong bmkId)
{
frm()->ShowBookmark(static_cast<kml::MarkId>(bmkId));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeShowBookmarkCategoryOnMap(
JNIEnv *, jobject, jlong catId)
{
frm()->ShowBookmarkCategory(static_cast<kml::MarkGroupId>(catId), true /* animated */);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeLoadBookmarks(JNIEnv * env, jclass)
{
PrepareClassRefs(env);
BookmarkManager::AsyncLoadingCallbacks callbacks;
callbacks.m_onStarted = std::bind(&OnAsyncLoadingStarted, env);
callbacks.m_onFinished = std::bind(&OnAsyncLoadingFinished, env);
callbacks.m_onFileSuccess = std::bind(&OnAsyncLoadingFileSuccess, env, _1, _2);
callbacks.m_onFileError = std::bind(&OnAsyncLoadingFileError, env, _1, _2);
frm()->GetBookmarkManager().SetAsyncLoadingCallbacks(std::move(callbacks));
frm()->GetBookmarkManager().SetBookmarksChangedCallback(std::bind(&OnBookmarksChanged, env));
frm()->LoadBookmarks();
}
JNIEXPORT jlong JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeCreateCategory(
JNIEnv * env, jobject, jstring name)
{
auto const categoryId = frm()->GetBookmarkManager().CreateBookmarkCategory(ToNativeString(env, name));
frm()->GetBookmarkManager().SetLastEditedBmCategory(categoryId);
return static_cast<jlong>(categoryId);
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeDeleteCategory(
JNIEnv *, jobject, jlong catId)
{
auto const categoryId = static_cast<kml::MarkGroupId>(catId);
// `permanently` should be set to false when the Recently Deleted Lists feature be implemented
return static_cast<jboolean>(frm()->GetBookmarkManager().GetEditSession().DeleteBmCategory(categoryId, true /* permanently */));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeDeleteBookmark(JNIEnv *, jobject, jlong bmkId)
{
frm()->GetBookmarkManager().GetEditSession().DeleteBookmark(static_cast<kml::MarkId>(bmkId));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeDeleteTrack(
JNIEnv *, jobject, jlong trkId)
{
frm()->GetBookmarkManager().GetEditSession().DeleteTrack(static_cast<kml::TrackId>(trkId));
}
JNIEXPORT jobject JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeAddBookmarkToLastEditedCategory(
JNIEnv * env, jobject, double lat, double lon)
{
if (!frm()->HasPlacePageInfo())
return nullptr;
BookmarkManager & bmMng = frm()->GetBookmarkManager();
place_page::Info const & info = g_framework->GetPlacePageInfo();
kml::BookmarkData bmData;
bmData.m_name = info.FormatNewBookmarkName();
bmData.m_color.m_predefinedColor = frm()->LastEditedBMColor();
bmData.m_point = mercator::FromLatLon(lat, lon);
auto const lastEditedCategory = frm()->LastEditedBMCategory();
if (info.IsFeature())
SaveFeatureTypes(info.GetTypes(), bmData);
auto const * createdBookmark = bmMng.GetEditSession().CreateBookmark(std::move(bmData),
lastEditedCategory);
auto buildInfo = info.GetBuildInfo();
buildInfo.m_match = place_page::BuildInfo::Match::Everything;
buildInfo.m_userMarkId = createdBookmark->GetId();
frm()->UpdatePlacePageInfoForCurrentSelection(buildInfo);
return usermark_helper::CreateMapObject(env, g_framework->GetPlacePageInfo());
}
JNIEXPORT jlong JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetLastEditedCategory(
JNIEnv *, jobject)
{
return static_cast<jlong>(frm()->LastEditedBMCategory());
}
JNIEXPORT jint JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetLastEditedColor(
JNIEnv *, jobject)
{
return static_cast<jint>(frm()->LastEditedBMColor());
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeLoadBookmarksFile(JNIEnv * env, jclass,
jstring path, jboolean isTemporaryFile)
{
frm()->AddBookmarksFile(ToNativeString(env, path), isTemporaryFile);
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeIsAsyncBookmarksLoadingInProgress(JNIEnv *, jclass)
{
return static_cast<jboolean>(frm()->GetBookmarkManager().IsAsyncLoadingInProgress());
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeIsVisible(
JNIEnv *, jobject, jlong catId)
{
return static_cast<jboolean>(frm()->GetBookmarkManager().IsVisible(static_cast<kml::MarkGroupId>(catId)));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeSetVisibility(
JNIEnv *, jobject, jlong catId, jboolean isVisible)
{
frm()->GetBookmarkManager().GetEditSession().SetIsVisible(static_cast<kml::MarkGroupId>(catId), isVisible);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeSetCategoryName(
JNIEnv * env, jobject, jlong catId, jstring name)
{
frm()->GetBookmarkManager().GetEditSession().SetCategoryName(static_cast<kml::MarkGroupId>(catId),
jni::ToNativeString(env, name));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeSetCategoryDescription(JNIEnv * env,
jobject,
jlong catId,
jstring desc)
{
frm()->GetBookmarkManager().GetEditSession().SetCategoryDescription(
static_cast<kml::MarkGroupId>(catId), jni::ToNativeString(env, desc));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeSetCategoryTags(
JNIEnv * env, jobject, jlong catId, jobjectArray tagsIds)
{
auto const size = env->GetArrayLength(tagsIds);
std::vector<std::string> categoryTags;
categoryTags.reserve(static_cast<size_t>(size));
for (auto i = 0; i < size; i++)
{
jni::TScopedLocalRef const item(env, env->GetObjectArrayElement(tagsIds, i));
categoryTags.push_back(jni::ToNativeString(env, static_cast<jstring>(item.get())));
}
frm()->GetBookmarkManager().GetEditSession().SetCategoryTags(static_cast<kml::MarkGroupId>(catId),
categoryTags);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeSetCategoryAccessRules(
JNIEnv *, jobject, jlong catId, jint accessRules)
{
frm()->GetBookmarkManager().GetEditSession().SetCategoryAccessRules(
static_cast<kml::MarkGroupId>(catId), static_cast<kml::AccessRules>(accessRules));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeSetCategoryCustomProperty(
JNIEnv * env, jobject, jlong catId, jstring key, jstring value)
{
frm()->GetBookmarkManager().GetEditSession().SetCategoryCustomProperty(
static_cast<kml::MarkGroupId>(catId), ToNativeString(env, key), ToNativeString(env, value));
}
JNIEXPORT jobject JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeUpdateBookmarkPlacePage(
JNIEnv * env, jobject, jlong bmkId)
{
if (!frm()->HasPlacePageInfo())
return nullptr;
auto & info = g_framework->GetPlacePageInfo();
auto buildInfo = info.GetBuildInfo();
buildInfo.m_userMarkId = static_cast<kml::MarkId>(bmkId);
frm()->UpdatePlacePageInfoForCurrentSelection(buildInfo);
return usermark_helper::CreateMapObject(env, g_framework->GetPlacePageInfo());
}
JNIEXPORT jobject JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetBookmarkInfo(
JNIEnv * env, jobject, jlong bmkId)
{
auto const bookmark = frm()->GetBookmarkManager().GetBookmark(static_cast<kml::MarkId>(bmkId));
if (!bookmark)
return nullptr;
return env->NewObject(g_bookmarkInfoClass,
g_bookmarkInfoConstructor, static_cast<jlong>(bookmark->GetGroupId()),
static_cast<jlong>(bmkId));
}
JNIEXPORT jlong JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetBookmarkIdByPosition(
JNIEnv *, jobject, jlong catId, jint positionInCategory)
{
auto const & ids = frm()->GetBookmarkManager().GetUserMarkIds(static_cast<kml::MarkGroupId>(catId));
if (positionInCategory >= static_cast<jlong>(ids.size()))
return static_cast<jlong>(kml::kInvalidMarkId);
auto it = ids.begin();
std::advance(it, positionInCategory);
return static_cast<jlong>(*it);
}
static uint32_t shift(uint32_t v, uint8_t bitCount) { return v << bitCount; }
JNIEXPORT jobject JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetTrack(
JNIEnv * env, jobject, jlong trackId, jclass trackClazz)
{
// Track(long trackId, long categoryId, String name, String lengthString, int color)
static jmethodID const cId = jni::GetConstructorID(env, trackClazz,
"(JJLjava/lang/String;Lapp/organicmaps/sdk/util/Distance;I)V");
auto const * nTrack = frm()->GetBookmarkManager().GetTrack(static_cast<kml::TrackId>(trackId));
ASSERT(nTrack, ("Track must not be null with id:)", trackId));
dp::Color nColor = nTrack->GetColor(0);
jint androidColor = shift(nColor.GetAlpha(), 24) +
shift(nColor.GetRed(), 16) +
shift(nColor.GetGreen(), 8) +
nColor.GetBlue();
return env->NewObject(trackClazz, cId,
trackId, static_cast<jlong>(nTrack->GetGroupId()), jni::ToJavaString(env, nTrack->GetName()),
ToJavaDistance(env, platform::Distance::CreateFormatted(nTrack->GetLengthMeters())), androidColor);
}
JNIEXPORT jlong JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetTrackIdByPosition(
JNIEnv *, jobject, jlong catId, jint positionInCategory)
{
auto const & ids = frm()->GetBookmarkManager().GetTrackIds(static_cast<kml::MarkGroupId>(catId));
if (positionInCategory >= static_cast<jlong>(ids.size()))
return static_cast<jlong>(kml::kInvalidTrackId);
auto it = ids.begin();
std::advance(it, positionInCategory);
return static_cast<jlong>(*it);
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeIsUsedCategoryName(
JNIEnv * env, jclass, jstring name)
{
return static_cast<jboolean>(frm()->GetBookmarkManager().IsUsedCategoryName(ToNativeString(env, name)));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativePrepareForSearch(
JNIEnv *, jclass, jlong catId)
{
frm()->GetBookmarkManager().PrepareForSearch(static_cast<kml::MarkGroupId>(catId));
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeAreAllCategoriesInvisible(
JNIEnv *, jclass)
{
return static_cast<jboolean>(frm()->GetBookmarkManager().AreAllCategoriesInvisible());
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeAreAllCategoriesVisible(
JNIEnv *, jclass)
{
return static_cast<jboolean>(frm()->GetBookmarkManager().AreAllCategoriesVisible());
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeSetAllCategoriesVisibility(
JNIEnv *, jclass, jboolean visible)
{
frm()->GetBookmarkManager().SetAllCategoriesVisibility(static_cast<bool>(visible));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativePrepareTrackFileForSharing(JNIEnv * env, jclass, jlong trackId, jint kmlFileType)
{
frm()->GetBookmarkManager().PrepareTrackFileForSharing(static_cast<kml::TrackId>(trackId), [env](BookmarkManager::SharingResult const & result)
{
OnPreparedFileForSharing(env, result);
}, static_cast<KmlFileType>(kmlFileType));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativePrepareFileForSharing(JNIEnv * env, jclass, jlongArray catIds, jint kmlFileType)
{
auto const size = env->GetArrayLength(catIds);
kml::GroupIdCollection catIdsVector(size);
static_assert(sizeof(jlong) == sizeof(decltype(catIdsVector)::value_type));
env->GetLongArrayRegion(catIds, 0, size, reinterpret_cast<jlong *>(catIdsVector.data()));
frm()->GetBookmarkManager().PrepareFileForSharing(std::move(catIdsVector), [env](BookmarkManager::SharingResult const & result)
{
OnPreparedFileForSharing(env, result);
}, static_cast<KmlFileType>(kmlFileType));
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeIsCategoryEmpty(
JNIEnv *, jclass, jlong catId)
{
return static_cast<jboolean>(frm()->GetBookmarkManager().IsCategoryEmpty(
static_cast<kml::MarkGroupId>(catId)));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeSetNotificationsEnabled(
JNIEnv *, jclass, jboolean enabled)
{
frm()->GetBookmarkManager().SetNotificationsEnabled(static_cast<bool>(enabled));
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeAreNotificationsEnabled(
JNIEnv *, jclass)
{
return static_cast<jboolean>(frm()->GetBookmarkManager().AreNotificationsEnabled());
}
JNIEXPORT jobject JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetBookmarkCategory(JNIEnv *env, jobject, jlong id)
{
return MakeCategory(env, static_cast<kml::MarkGroupId>(id));
}
JNIEXPORT jobjectArray JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetBookmarkCategories(JNIEnv *env, jobject)
{
auto const & bm = frm()->GetBookmarkManager();
auto const & ids = bm.GetSortedBmGroupIdList();
return MakeCategories(env, ids);
}
JNIEXPORT jint JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetBookmarkCategoriesCount(JNIEnv *env, jobject)
{
auto const & bm = frm()->GetBookmarkManager();
auto const count = bm.GetBmGroupsCount();
return static_cast<jint>(count);
}
JNIEXPORT jobjectArray JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetChildrenCategories(JNIEnv *env, jobject, jlong parentId)
{
auto const & bm = frm()->GetBookmarkManager();
auto const ids = bm.GetChildrenCategories(static_cast<kml::MarkGroupId>(parentId));
return MakeCategories(env, ids);
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeHasLastSortingType(
JNIEnv *, jobject, jlong catId)
{
auto const & bm = frm()->GetBookmarkManager();
BookmarkManager::SortingType type;
return static_cast<jboolean>(bm.GetLastSortingType(static_cast<kml::MarkGroupId>(catId), type));
}
JNIEXPORT jint JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetLastSortingType(
JNIEnv *, jobject, jlong catId)
{
auto const & bm = frm()->GetBookmarkManager();
BookmarkManager::SortingType type;
auto const hasType = bm.GetLastSortingType(static_cast<kml::MarkGroupId>(catId), type);
ASSERT(hasType, ());
UNUSED_VALUE(hasType);
return static_cast<jint>(type);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeSetLastSortingType(
JNIEnv *, jobject, jlong catId, jint type)
{
auto & bm = frm()->GetBookmarkManager();
bm.SetLastSortingType(static_cast<kml::MarkGroupId>(catId),
static_cast<BookmarkManager::SortingType>(type));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeResetLastSortingType(
JNIEnv *, jobject, jlong catId)
{
auto & bm = frm()->GetBookmarkManager();
bm.ResetLastSortingType(static_cast<kml::MarkGroupId>(catId));
}
JNIEXPORT jintArray JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetAvailableSortingTypes(JNIEnv *env,
jobject, jlong catId, jboolean hasMyPosition)
{
auto const & bm = frm()->GetBookmarkManager();
auto const types = bm.GetAvailableSortingTypes(static_cast<kml::MarkGroupId>(catId),
static_cast<bool>(hasMyPosition));
int const size = static_cast<int>(types.size());
jintArray jTypes = env->NewIntArray(size);
jint * arr = env->GetIntArrayElements(jTypes, 0);
for (int i = 0; i < size; ++i)
arr[i] = static_cast<int>(types[i]);
env->ReleaseIntArrayElements(jTypes, arr, 0);
return jTypes;
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetSortedCategory(JNIEnv *env,
jobject, jlong catId, jint sortingType, jboolean hasMyPosition, jdouble lat, jdouble lon,
jlong timestamp)
{
auto & bm = frm()->GetBookmarkManager();
BookmarkManager::SortParams sortParams;
sortParams.m_groupId = static_cast<kml::MarkGroupId>(catId);
sortParams.m_sortingType = static_cast<BookmarkManager::SortingType>(sortingType);
sortParams.m_hasMyPosition = static_cast<bool>(hasMyPosition);
sortParams.m_myPosition = mercator::FromLatLon(static_cast<double>(lat),
static_cast<double>(lon));
sortParams.m_onResults = bind(&OnCategorySortingResults, env, timestamp, _1, _2);
bm.GetSortedCategory(sortParams);
}
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetBookmarkName(
JNIEnv * env, jclass, jlong bmk)
{
return jni::ToJavaString(env, getBookmark(bmk)->GetPreferredName());
}
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetBookmarkFeatureType(
JNIEnv * env, jclass, jlong bmk)
{
return jni::ToJavaString(env,
kml::GetLocalizedFeatureType(getBookmark(bmk)->GetData().m_featureTypes));
}
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetBookmarkDescription(
JNIEnv * env, jclass, jlong bmk)
{
return jni::ToJavaString(env, getBookmark(bmk)->GetDescription());
}
JNIEXPORT jint JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetBookmarkColor(
JNIEnv *, jclass, jlong bmk)
{
auto const * mark = getBookmark(bmk);
return static_cast<jint>(mark != nullptr ? mark->GetColor()
: frm()->LastEditedBMColor());
}
JNIEXPORT jint JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetBookmarkIcon(
JNIEnv *, jclass, jlong bmk)
{
auto const * mark = getBookmark(bmk);
return static_cast<jint>(mark != nullptr ? mark->GetData().m_icon
: kml::BookmarkIcon::None);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeSetBookmarkParams(
JNIEnv * env, jclass, jlong bmk,
jstring name, jint color, jstring descr)
{
auto const * mark = getBookmark(bmk);
// initialize new bookmark
kml::BookmarkData bmData(mark->GetData());
auto const bmName = jni::ToNativeString(env, name);
if (mark->GetPreferredName() != bmName)
kml::SetDefaultStr(bmData.m_customName, bmName);
if (descr)
kml::SetDefaultStr(bmData.m_description, jni::ToNativeString(env, descr));
bmData.m_color.m_predefinedColor = static_cast<kml::PredefinedColor>(color);
g_framework->ReplaceBookmark(static_cast<kml::MarkId>(bmk), bmData);
}
constexpr static uint8_t ExtractByte(uint32_t number, uint8_t byteIdx) { return (number >> (8 * byteIdx)) & 0xFF; }
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeSetTrackParams(
JNIEnv * env, jclass, jlong trackId,
jstring name, jint color, jstring descr)
{
auto const * nTrack = frm()->GetBookmarkManager().GetTrack(static_cast<kml::TrackId>(trackId));
CHECK(nTrack, ("Track must not be null with id:", trackId));
kml::TrackData trackData(nTrack->GetData());
auto const trkName = jni::ToNativeString(env, name);
kml::SetDefaultStr(trackData.m_name, trkName);
kml::SetDefaultStr(trackData.m_description, jni::ToNativeString(env, descr));
uint8_t alpha = ExtractByte(color, 3);
trackData.m_layers[0].m_color.m_rgba = static_cast<uint32_t>(shift(color,8) + alpha);
g_framework->ReplaceTrack(static_cast<kml::TrackId>(trackId), trackData);
}
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetTrackDescription(
JNIEnv * env, jclass, jlong trackId)
{
return jni::ToJavaString(env, frm()->GetBookmarkManager().GetTrack(static_cast<kml::TrackId>(trackId))->GetDescription());
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeChangeBookmarkCategory(
JNIEnv *, jclass, jlong oldCat, jlong newCat, jlong bmk)
{
g_framework->MoveBookmark(static_cast<kml::MarkId>(bmk), static_cast<kml::MarkGroupId>(oldCat),
static_cast<kml::MarkGroupId>(newCat));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeChangeTrackCategory(
JNIEnv *, jclass, jlong oldCat, jlong newCat, jlong trackId)
{
g_framework->MoveTrack(static_cast<kml::TrackId>(trackId), static_cast<kml::MarkGroupId>(oldCat),
static_cast<kml::MarkGroupId>(newCat));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeChangeTrackColor(
JNIEnv *, jclass, jlong trackId, jint color)
{
uint8_t alpha = ExtractByte(color, 3);
g_framework->ChangeTrackColor(static_cast<kml::TrackId>(trackId), static_cast<dp::Color>(shift(color,8) + alpha));
}
JNIEXPORT jobject JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetBookmarkXY(
JNIEnv * env, jclass, jlong bmk)
{
return jni::GetNewParcelablePointD(env, getBookmark(bmk)->GetPivot());
}
JNIEXPORT jdouble JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetBookmarkScale(
JNIEnv *, jclass, jlong bmk)
{
return getBookmark(bmk)->GetScale();
}
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeEncode2Ge0Url(
JNIEnv * env, jclass, jlong bmk, jboolean addName)
{
return jni::ToJavaString(env, frm()->CodeGe0url(getBookmark(bmk), addName));
}
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetBookmarkAddress(
JNIEnv * env, jclass, jlong bmkId)
{
auto const address = frm()->GetAddressAtPoint(getBookmark(bmkId)->GetPivot()).FormatAddress();
return jni::ToJavaString(env, address);
}
JNIEXPORT jdouble JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetElevationCurPositionDistance(
JNIEnv *, jclass, jlong trackId)
{
auto const & bm = frm()->GetBookmarkManager();
return static_cast<jdouble>(bm.GetElevationMyPosition(static_cast<kml::TrackId>(trackId)));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeSetElevationCurrentPositionChangedListener(
JNIEnv * env, jclass)
{
frm()->GetBookmarkManager().SetElevationMyPositionChangedCallback(
std::bind(&OnElevationCurPositionChanged, env));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeRemoveElevationCurrentPositionChangedListener(
JNIEnv *, jclass)
{
frm()->GetBookmarkManager().SetElevationMyPositionChangedCallback(nullptr);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeSetElevationActivePoint(
JNIEnv *, jclass, jlong trackId, jdouble distanceInMeters)
{
auto & bm = frm()->GetBookmarkManager();
bm.SetElevationActivePoint(static_cast<kml::TrackId>(trackId),
{0,0}, // todo(KK): replace with coordinates from the elevation profile point to show selection mark on the track
static_cast<double>(distanceInMeters));
}
JNIEXPORT jdouble JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetElevationActivePointDistance(
JNIEnv *, jclass, jlong trackId)
{
auto & bm = frm()->GetBookmarkManager();
return static_cast<jdouble>(bm.GetElevationActivePoint(static_cast<kml::TrackId>(trackId)));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeSetElevationActiveChangedListener(
JNIEnv *env, jclass)
{
frm()->GetBookmarkManager().SetElevationActivePointChangedCallback(std::bind(&OnElevationActivePointChanged, env));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeRemoveElevationActiveChangedListener(
JNIEnv *, jclass)
{
frm()->GetBookmarkManager().SetElevationActivePointChangedCallback(nullptr);
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_widget_placepage_PlacePageButtonFactory_nativeHasRecentlyDeletedBookmark(JNIEnv *, jclass)
{
return frm()->GetBookmarkManager().HasRecentlyDeletedBookmark();
}
} // extern "C"

View File

@@ -0,0 +1,40 @@
#pragma once
#include <jni.h>
// Scoped environment which can attach to any thread and automatically detach
class ScopedEnv final
{
public:
ScopedEnv(JavaVM * vm)
{
JNIEnv * env;
auto result = vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
if (result == JNI_EDETACHED)
{
result = vm->AttachCurrentThread(&env, nullptr);
m_needToDetach = (result == JNI_OK);
}
if (result == JNI_OK)
{
m_env = env;
m_vm = vm;
}
}
~ScopedEnv()
{
if (m_vm != nullptr && m_needToDetach)
m_vm->DetachCurrentThread();
}
JNIEnv * operator->() { return m_env; }
operator bool() const { return m_env != nullptr; }
JNIEnv * get() { return m_env; }
private:
bool m_needToDetach = false;
JNIEnv * m_env = nullptr;
JavaVM * m_vm = nullptr;
};

View File

@@ -0,0 +1,38 @@
#pragma once
#include <jni.h>
namespace jni
{
// A smart pointer that deletes a JNI local reference when it goes out of scope.
template <typename T>
class ScopedLocalRef {
public:
ScopedLocalRef(JNIEnv * env, T localRef) : m_env(env), m_localRef(localRef) {}
~ScopedLocalRef() { reset(); }
void reset(T ptr = nullptr)
{
if (ptr == m_localRef)
return;
if (m_localRef != nullptr)
m_env->DeleteLocalRef(m_localRef);
m_localRef = ptr;
}
T get() const { return m_localRef; }
operator T() const { return m_localRef; }
private:
JNIEnv * m_env;
T m_localRef;
// Disallow copy and assignment.
ScopedLocalRef(ScopedLocalRef const &) = delete;
void operator=(ScopedLocalRef const &) = delete;
};
} // namespace jni

View File

@@ -0,0 +1,332 @@
#include "jni_helper.hpp"
#include "logging.hpp"
#include "ScopedLocalRef.hpp"
#include "base/assert.hpp"
#include "base/exception.hpp"
#include "base/string_utils.hpp"
#include <vector>
static JavaVM * g_jvm = 0;
extern JavaVM * GetJVM()
{
return g_jvm;
}
// Caching is necessary to create class from native threads.
jclass g_mapObjectClazz;
jclass g_featureIdClazz;
jclass g_bookmarkClazz;
jclass g_httpClientClazz;
jclass g_httpParamsClazz;
jclass g_platformSocketClazz;
jclass g_utilsClazz;
jclass g_loggerClazz;
jclass g_keyValueClazz;
jclass g_networkPolicyClazz;
jclass g_elevationInfoClazz;
extern "C"
{
int __system_property_get(char const * name, char * value);
static bool IsAndroidLowerThan7()
{
char value[92] = { 0 };
if (__system_property_get("ro.build.version.sdk", value) < 1)
return false;
const int apiLevel = atoi(value);
if (apiLevel > 0 && apiLevel < 24)
return true;
return false;
}
static bool const g_isAndroidLowerThan7 = IsAndroidLowerThan7();
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM * jvm, void *)
{
g_jvm = jvm;
jni::InitSystemLog();
jni::InitAssertLog();
JNIEnv * env = jni::GetEnv();
g_mapObjectClazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/bookmarks/data/MapObject");
g_featureIdClazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/bookmarks/data/FeatureId");
g_bookmarkClazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/bookmarks/data/Bookmark");
g_httpClientClazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/util/HttpClient");
g_httpParamsClazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/util/HttpClient$Params");
g_platformSocketClazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/location/PlatformSocket");
g_utilsClazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/util/Utils");
g_loggerClazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/util/log/Logger");
g_keyValueClazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/util/KeyValue");
g_networkPolicyClazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/util/NetworkPolicy");
g_elevationInfoClazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/bookmarks/data/ElevationInfo");
return JNI_VERSION_1_6;
}
JNIEXPORT void JNICALL
JNI_OnUnload(JavaVM *, void *)
{
g_jvm = 0;
JNIEnv * env = jni::GetEnv();
env->DeleteGlobalRef(g_mapObjectClazz);
env->DeleteGlobalRef(g_featureIdClazz);
env->DeleteGlobalRef(g_bookmarkClazz);
env->DeleteGlobalRef(g_httpClientClazz);
env->DeleteGlobalRef(g_httpParamsClazz);
env->DeleteGlobalRef(g_platformSocketClazz);
env->DeleteGlobalRef(g_utilsClazz);
env->DeleteGlobalRef(g_loggerClazz);
env->DeleteGlobalRef(g_keyValueClazz);
env->DeleteGlobalRef(g_networkPolicyClazz);
env->DeleteGlobalRef(g_elevationInfoClazz);
}
} // extern "C"
namespace jni
{
JNIEnv * GetEnv()
{
JNIEnv * env;
auto const res = g_jvm->GetEnv((void **)&env, JNI_VERSION_1_6);
if (res != JNI_OK)
{
LOG(LERROR, ("Can't get JNIEnv. Is the thread attached to JVM?", res));
MYTHROW(RootException, ("Can't get JNIEnv. Is the thread attached to JVM?", res));
}
return env;
}
JavaVM * GetJVM()
{
ASSERT(g_jvm, ("JVM is not initialized"));
return g_jvm;
}
jmethodID GetMethodID(JNIEnv * env, jobject obj, char const * name, char const * signature)
{
// GetObjectClass may hang in WaitHoldingLocks.
TScopedLocalClassRef clazz(env, env->GetObjectClass(obj));
ASSERT(clazz.get(), ("Can't get class: ", DescribeException()));
jmethodID mid = env->GetMethodID(clazz.get(), name, signature);
ASSERT(mid, ("Can't get method ID", name, signature, DescribeException()));
return mid;
}
jmethodID GetStaticMethodID(JNIEnv * env, jclass clazz, char const * name, char const * signature)
{
jmethodID mid = env->GetStaticMethodID(clazz, name, signature);
ASSERT(mid, ("Can't get static method ID", name, signature, DescribeException()));
return mid;
}
jfieldID GetStaticFieldID(JNIEnv * env, jclass clazz, char const * name, char const * signature)
{
jfieldID fid = env->GetStaticFieldID(clazz, name, signature);
ASSERT(fid, ("Can't get static field ID", name, signature, DescribeException()));
return fid;
}
jmethodID GetConstructorID(JNIEnv * env, jclass clazz, char const * signature)
{
jmethodID const ctorID = env->GetMethodID(clazz, "<init>", signature);
ASSERT(ctorID, (DescribeException()));
return ctorID;
}
jclass GetGlobalClassRef(JNIEnv * env, char const * sig)
{
jclass klass = env->FindClass(sig);
ASSERT(klass, ("Can't get class : ", DescribeException()));
return static_cast<jclass>(env->NewGlobalRef(klass));
}
std::string ToNativeString(JNIEnv * env, jstring str)
{
std::string result;
char const * utfBuffer = env->GetStringUTFChars(str, 0);
if (utfBuffer)
{
result = utfBuffer;
env->ReleaseStringUTFChars(str, utfBuffer);
}
return result;
}
std::string ToNativeString(JNIEnv * env, jbyteArray const & bytes)
{
int const len = env->GetArrayLength(bytes);
std::vector<char> buffer(len);
env->GetByteArrayRegion(bytes, 0, len, reinterpret_cast<jbyte *>(buffer.data()));
return std::string(buffer.data(), len);
}
jstring ToJavaString(JNIEnv * env, char const * s)
{
return env->NewStringUTF(s);
}
jstring ToJavaStringWithSupplementalCharsFix(JNIEnv * env, std::string const & s)
{
// Android 5 and 6 do not support unicode characters greater than 0xFFFF encoded in UTF-8.
if (g_isAndroidLowerThan7)
{
// Detect 4-byte sequence start marker to avoid unnecessary allocation + copy.
for (const auto c : s)
{
if (0b11110000 == (c & 0b11111000))
{
const auto utf16 = strings::ToUtf16(s);
return env->NewString(reinterpret_cast<jchar const *>(utf16.data()), utf16.size());
}
}
}
return env->NewStringUTF(s.c_str());
}
jclass GetStringClass(JNIEnv * env)
{
return env->FindClass(GetStringClassName());
}
char const * GetStringClassName()
{
return "java/lang/String";
}
std::shared_ptr<jobject> make_global_ref(jobject obj)
{
jobject * ref = new jobject(GetEnv()->NewGlobalRef(obj));
return std::shared_ptr<jobject>(ref, [](jobject * ref)
{
GetEnv()->DeleteGlobalRef(*ref);
delete ref;
});
}
std::string ToNativeString(JNIEnv * env, const jthrowable & e)
{
jni::TScopedLocalClassRef logClassRef(env, env->FindClass("android/util/Log"));
ASSERT(logClassRef.get(), ());
static jmethodID const getStacktraceMethod =
jni::GetStaticMethodID(env, logClassRef.get(), "getStackTraceString",
"(Ljava/lang/Throwable;)Ljava/lang/String;");
ASSERT(getStacktraceMethod, ());
TScopedLocalRef resultRef(env, env->CallStaticObjectMethod(logClassRef.get(), getStacktraceMethod, e));
return ToNativeString(env, (jstring) resultRef.get());
}
bool HandleJavaException(JNIEnv * env)
{
if (env->ExceptionCheck())
{
jni::ScopedLocalRef<jthrowable> const e(env, env->ExceptionOccurred());
env->ExceptionDescribe();
env->ExceptionClear();
base::LogLevel level = GetLogLevelForException(env, e.get());
LOG(level, (ToNativeString(env, e.get())));
return true;
}
return false;
}
base::LogLevel GetLogLevelForException(JNIEnv * env, const jthrowable & e)
{
static jclass const errorClass = jni::GetGlobalClassRef(env, "java/lang/Error");
ASSERT(errorClass, (jni::DescribeException()));
static jclass const runtimeExceptionClass =
jni::GetGlobalClassRef(env, "java/lang/RuntimeException");
ASSERT(runtimeExceptionClass, (jni::DescribeException()));
// If Unchecked Exception or Error is occurred during Java call the app should fail immediately.
// In other cases, just a warning message about exception (Checked Exception)
// will be written into LogCat.
if (env->IsInstanceOf(e, errorClass) || env->IsInstanceOf(e, runtimeExceptionClass))
return LERROR;
return LWARNING;
}
std::string DescribeException()
{
JNIEnv * env = GetEnv();
if (env->ExceptionCheck())
{
jni::ScopedLocalRef<jthrowable> const e(env, env->ExceptionOccurred());
// have to clear the exception before JNI will work again.
env->ExceptionClear();
return ToNativeString(env, e.get());
}
return {};
}
jobject GetNewParcelablePointD(JNIEnv * env, m2::PointD const & point)
{
jclass klass = env->FindClass("app/organicmaps/sdk/bookmarks/data/ParcelablePointD");
ASSERT ( klass, () );
jmethodID methodID = GetConstructorID(env, klass, "(DD)V");
return env->NewObject(klass, methodID,
static_cast<jdouble>(point.x),
static_cast<jdouble>(point.y));
}
jobject GetNewPoint(JNIEnv * env, m2::PointD const & point)
{
return GetNewPoint(env, m2::PointI(static_cast<int>(point.x), static_cast<int>(point.y)));
}
jobject GetNewPoint(JNIEnv * env, m2::PointI const & point)
{
jclass klass = env->FindClass("android/graphics/Point");
ASSERT ( klass, () );
jmethodID methodID = GetConstructorID(env, klass, "(II)V");
return env->NewObject(klass, methodID,
static_cast<jint>(point.x),
static_cast<jint>(point.y));
}
// This util method dumps content of local and global reference jni tables to logcat for debug and testing purposes
void DumpDalvikReferenceTables()
{
JNIEnv * env = GetEnv();
jclass vm_class = env->FindClass("dalvik/system/VMDebug");
jmethodID dump_mid = env->GetStaticMethodID(vm_class, "dumpReferenceTables", "()V");
env->CallStaticVoidMethod(vm_class, dump_mid);
env->DeleteLocalRef(vm_class);
}
jobject ToKeyValue(JNIEnv * env, std::pair<std::string, std::string> src)
{
static jmethodID const keyValueInit = jni::GetConstructorID(
env, g_keyValueClazz, "(Ljava/lang/String;Ljava/lang/String;)V");
jni::TScopedLocalRef key(env, jni::ToJavaString(env, src.first));
jni::TScopedLocalRef value(env, jni::ToJavaString(env, src.second));
return env->NewObject(g_keyValueClazz, keyValueInit, key.get(), value.get());
}
std::pair<std::string, std::string> ToNativeKeyValue(JNIEnv * env, jobject pairOfStrings)
{
static jfieldID const keyId = env->GetFieldID(g_keyValueClazz, "mKey",
"Ljava/lang/String;");
static jfieldID const valueId = env->GetFieldID(g_keyValueClazz, "mValue",
"Ljava/lang/String;");
jni::ScopedLocalRef<jstring> const key(
env, static_cast<jstring>(env->GetObjectField(pairOfStrings, keyId)));
jni::ScopedLocalRef<jstring> const value(
env, static_cast<jstring>(env->GetObjectField(pairOfStrings, valueId)));
return { jni::ToNativeString(env, key.get()), jni::ToNativeString(env, value.get()) };
}
} // namespace jni

View File

@@ -0,0 +1,137 @@
#pragma once
#include <jni.h>
#include "ScopedLocalRef.hpp"
#include "geometry/point2d.hpp"
#include "base/buffer_vector.hpp"
#include "base/logging.hpp"
#include <iterator>
#include <memory>
#include <string>
#include <utility>
#include <vector>
extern jclass g_mapObjectClazz;
extern jclass g_featureIdClazz;
extern jclass g_bookmarkClazz;
extern jclass g_httpClientClazz;
extern jclass g_httpParamsClazz;
extern jclass g_platformSocketClazz;
extern jclass g_utilsClazz;
extern jclass g_loggerClazz;
extern jclass g_keyValueClazz;
extern jclass g_networkPolicyClazz;
extern jclass g_elevationInfoClazz;
namespace jni
{
JNIEnv * GetEnv();
JavaVM * GetJVM();
jmethodID GetMethodID(JNIEnv * env, jobject obj, char const * name, char const * signature);
jmethodID GetStaticMethodID(JNIEnv * env, jclass clazz, char const * name, char const * signature);
jmethodID GetConstructorID(JNIEnv * env, jclass clazz, char const * signature);
jfieldID GetStaticFieldID(JNIEnv * env, jclass clazz, char const * name, char const * signature);
// Result value should be DeleteGlobalRef`ed by caller
jclass GetGlobalClassRef(JNIEnv * env, char const * s);
std::string ToNativeString(JNIEnv * env, jstring str);
// Converts UTF-8 array to native UTF-8 string. Result differs from simple GetStringUTFChars call for characters greater than U+10000,
// since jni uses modified UTF (MUTF-8) for strings.
std::string ToNativeString(JNIEnv * env, jbyteArray const & utfBytes);
jstring ToJavaString(JNIEnv * env, char const * s);
inline jstring ToJavaString(JNIEnv * env, std::string const & s)
{
return ToJavaString(env, s.c_str());
}
inline jstring ToJavaString(JNIEnv * env, std::string_view sv)
{
/// @todo Make conversion without a temporary some day.
return ToJavaString(env, std::string(sv).c_str());
}
// Remove after dropping Android 5 and 6 support.
jstring ToJavaStringWithSupplementalCharsFix(JNIEnv * env, std::string const & s);
jclass GetStringClass(JNIEnv * env);
char const * GetStringClassName();
std::string DescribeException();
bool HandleJavaException(JNIEnv * env);
base::LogLevel GetLogLevelForException(JNIEnv * env, const jthrowable & e);
std::shared_ptr<jobject> make_global_ref(jobject obj);
using TScopedLocalRef = ScopedLocalRef<jobject>;
using TScopedLocalClassRef = ScopedLocalRef<jclass>;
using TScopedLocalObjectArrayRef = ScopedLocalRef<jobjectArray>;
using TScopedLocalIntArrayRef = ScopedLocalRef<jintArray>;
using TScopedLocalByteArrayRef = ScopedLocalRef<jbyteArray>;
jobject GetNewParcelablePointD(JNIEnv * env, m2::PointD const & point);
jobject GetNewPoint(JNIEnv * env, m2::PointD const & point);
jobject GetNewPoint(JNIEnv * env, m2::PointI const & point);
template<typename TIt, typename TToJavaFn>
jobjectArray ToJavaArray(JNIEnv * env, jclass clazz, TIt begin, TIt end, size_t const size, TToJavaFn && toJavaFn)
{
jobjectArray jArray = env->NewObjectArray((jint) size, clazz, 0);
jint i = 0;
for (auto it = begin; it != end; ++it)
{
TScopedLocalRef jItem(env, toJavaFn(env, *it));
env->SetObjectArrayElement(jArray, i, jItem.get());
++i;
}
return jArray;
}
template<typename TContainer, typename TToJavaFn>
jobjectArray ToJavaArray(JNIEnv * env, jclass clazz, TContainer const & src, TToJavaFn && toJavaFn)
{
return ToJavaArray(env, clazz, std::begin(src), std::end(src), src.size(),
std::forward<TToJavaFn>(toJavaFn));
}
template <typename Cont>
jobjectArray ToJavaStringArray(JNIEnv * env, Cont const & src)
{
return ToJavaArray(env, GetStringClass(env), src,
[](JNIEnv * env, std::string const & item)
{
return ToJavaString(env, item.c_str());
});
}
void DumpDalvikReferenceTables();
jobject ToKeyValue(JNIEnv * env, std::pair<std::string, std::string> src);
template <typename Container>
jobjectArray ToKeyValueArray(JNIEnv * env, Container const & src)
{
return jni::ToJavaArray(env, g_keyValueClazz, src,
std::bind(&ToKeyValue, std::placeholders::_1, std::placeholders::_2));
}
std::pair<std::string, std::string> ToNativeKeyValue(JNIEnv * env, jobject pairOfStrings);
template <typename OutputIt>
void ToNativekeyValueContainer(JNIEnv * env, jobjectArray src, OutputIt it)
{
jint const length = env->GetArrayLength(src);
for (jint i = 0; i < length; ++i)
{
jni::ScopedLocalRef<jobject> const arrayItem(env, env->GetObjectArrayElement(src, i));
*it = ToNativeKeyValue(env, arrayItem.get());
++it;
}
}
} // namespace jni

View File

@@ -0,0 +1,32 @@
#include "jni_java_methods.hpp"
#include "jni_helper.hpp"
namespace jni
{
PairBuilder::PairBuilder(JNIEnv * env)
{
m_class = jni::GetGlobalClassRef(env, "android/util/Pair");
m_ctor = jni::GetConstructorID(env, m_class, "(Ljava/lang/Object;Ljava/lang/Object;)V");
ASSERT(m_ctor, ());
}
jobject PairBuilder::Create(JNIEnv * env, jobject o1, jobject o2) const
{
return env->NewObject(m_class, m_ctor, o1, o2);
}
ListBuilder::ListBuilder(JNIEnv * env)
{
m_arrayClass = jni::GetGlobalClassRef(env, "java/util/ArrayList");
m_arrayCtor = jni::GetConstructorID(env, m_arrayClass, "(I)V");
jclass clazz = env->FindClass("java/util/List");
m_add = env->GetMethodID(clazz, "add", "(Ljava/lang/Object;)Z");
}
jobject ListBuilder::CreateArray(JNIEnv * env, size_t sz) const
{
return env->NewObject(m_arrayClass, m_arrayCtor, sz);
}
} // namespace jni

View File

@@ -0,0 +1,37 @@
#pragma once
#include <jni.h>
#define DECLARE_BUILDER_INSTANCE(BuilderType) static BuilderType const & Instance(JNIEnv * env) { \
static BuilderType const inst(env); return inst; }
namespace jni
{
class PairBuilder
{
jclass m_class;
jmethodID m_ctor;
explicit PairBuilder(JNIEnv * env);
public:
DECLARE_BUILDER_INSTANCE(PairBuilder);
jobject Create(JNIEnv * env, jobject o1, jobject o2) const;
};
class ListBuilder
{
jclass m_arrayClass;
jmethodID m_arrayCtor;
public:
jmethodID m_add;
explicit ListBuilder(JNIEnv * env);
DECLARE_BUILDER_INSTANCE(ListBuilder);
jobject CreateArray(JNIEnv * env, size_t sz) const;
};
} // namespace jni

View File

@@ -0,0 +1,71 @@
#include "platform/platform.hpp"
#include "base/exception.hpp"
#include "base/logging.hpp"
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/core/logging.hpp"
#include "app/organicmaps/sdk/core/ScopedEnv.hpp"
#include <android/log.h>
#include <cassert>
#include <cstdlib>
namespace jni
{
using namespace base;
void AndroidMessage(LogLevel level, SrcPoint const & src, std::string const & s)
{
android_LogPriority pr = ANDROID_LOG_SILENT;
switch (level)
{
case LINFO: pr = ANDROID_LOG_INFO; break;
case LDEBUG: pr = ANDROID_LOG_DEBUG; break;
case LWARNING: pr = ANDROID_LOG_WARN; break;
case LERROR: pr = ANDROID_LOG_ERROR; break;
case LCRITICAL: pr = ANDROID_LOG_ERROR; break;
case NUM_LOG_LEVELS: break;
}
ScopedEnv env(jni::GetJVM());
static jmethodID const logMethod = jni::GetStaticMethodID(env.get(), g_loggerClazz,
"log", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V");
std::string const out = DebugPrint(src) + s;
jni::TScopedLocalRef msg(env.get(), jni::ToJavaString(env.get(), out));
env->CallStaticVoidMethod(g_loggerClazz, logMethod, pr, NULL, msg.get(), NULL);
}
void AndroidLogMessage(LogLevel level, SrcPoint const & src, std::string const & s)
{
AndroidMessage(level, src, s);
CHECK_LESS(level, g_LogAbortLevel, ("Abort. Log level is too serious", level));
}
bool AndroidAssertMessage(SrcPoint const & src, std::string const & s)
{
AndroidMessage(LCRITICAL, src, s);
return true;
}
void InitSystemLog()
{
SetLogMessageFn(&AndroidLogMessage);
}
void InitAssertLog()
{
SetAssertFunction(&AndroidAssertMessage);
}
void ToggleDebugLogs(bool enabled)
{
if (enabled)
g_LogLevel = LDEBUG;
else
g_LogLevel = LINFO;
}
}

View File

@@ -0,0 +1,8 @@
#pragma once
namespace jni
{
void InitSystemLog();
void InitAssertLog();
void ToggleDebugLogs(bool enabled);
}

View File

@@ -0,0 +1,17 @@
#include "render_context.hpp"
namespace android
{
void RenderContext::makeCurrent()
{
}
graphics::RenderContext * RenderContext::createShared()
{
RenderContext * rc = new RenderContext();
rc->setResourceManager(resourceManager());
return rc;
}
}

View File

@@ -0,0 +1,17 @@
#pragma once
#include "graphics/opengl/gl_render_context.hpp"
#include <memory>
namespace android
{
class RenderContext : public graphics::gl::RenderContext
{
public:
void makeCurrent();
graphics::RenderContext * createShared();
};
}

View File

@@ -0,0 +1,555 @@
#include <jni.h>
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/Framework.hpp"
#include "editor/osm_editor.hpp"
#include "indexer/cuisines.hpp"
#include "indexer/editable_map_object.hpp"
#include "indexer/feature_utils.hpp"
#include "indexer/validate_and_format_contacts.hpp"
#include "coding/string_utf8_multilang.hpp"
#include "base/assert.hpp"
#include "base/logging.hpp"
#include "base/string_utils.hpp"
#include "std/target_os.hpp"
#include <algorithm>
#include <set>
#include <vector>
namespace
{
using TCuisine = std::pair<std::string, std::string>;
osm::EditableMapObject g_editableMapObject;
jclass g_localNameClazz;
jmethodID g_localNameCtor;
jfieldID g_localNameFieldCode;
jfieldID g_localNameFieldName;
jclass g_localStreetClazz;
jmethodID g_localStreetCtor;
jfieldID g_localStreetFieldDef;
jfieldID g_localStreetFieldLoc;
jclass g_namesDataSourceClassID;
jmethodID g_namesDataSourceConstructorID;
jobject ToJavaName(JNIEnv * env, osm::LocalizedName const & name)
{
jni::TScopedLocalRef jName(env, jni::ToJavaString(env, name.m_name));
jni::TScopedLocalRef jLang(env, jni::ToJavaString(env, name.m_lang));
jni::TScopedLocalRef jLangName(env, jni::ToJavaString(env, name.m_langName));
return env->NewObject(g_localNameClazz, g_localNameCtor, name.m_code,
jName.get(), jLang.get(), jLangName.get());
}
jobject ToJavaStreet(JNIEnv * env, osm::LocalizedStreet const & street)
{
return env->NewObject(g_localStreetClazz, g_localStreetCtor,
jni::TScopedLocalRef(env, jni::ToJavaString(env, street.m_defaultName)).get(),
jni::TScopedLocalRef(env, jni::ToJavaString(env, street.m_localizedName)).get());
}
osm::NewFeatureCategories & GetFeatureCategories()
{
static osm::NewFeatureCategories categories = g_framework->NativeFramework()->GetEditorCategories();
return categories;
}
} // namespace
extern "C"
{
using osm::Editor;
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeInit(JNIEnv * env, jclass)
{
g_localNameClazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/editor/data/LocalizedName");
// LocalizedName(int code, @NonNull String name, @NonNull String lang, @NonNull String langName)
g_localNameCtor = jni::GetConstructorID(env, g_localNameClazz, "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
g_localNameFieldCode = env->GetFieldID(g_localNameClazz, "code", "I");
g_localNameFieldName = env->GetFieldID(g_localNameClazz, "name", "Ljava/lang/String;");
g_localStreetClazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/editor/data/LocalizedStreet");
// LocalizedStreet(@NonNull String defaultName, @NonNull String localizedName)
g_localStreetCtor = jni::GetConstructorID(env, g_localStreetClazz, "(Ljava/lang/String;Ljava/lang/String;)V");
g_localStreetFieldDef = env->GetFieldID(g_localStreetClazz, "defaultName", "Ljava/lang/String;");
g_localStreetFieldLoc = env->GetFieldID(g_localStreetClazz, "localizedName", "Ljava/lang/String;");
g_namesDataSourceClassID = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/editor/data/NamesDataSource");
g_namesDataSourceConstructorID = jni::GetConstructorID(env, g_namesDataSourceClassID, "([Lapp/organicmaps/sdk/editor/data/LocalizedName;I)V");
}
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeGetOpeningHours(JNIEnv * env, jclass)
{
return jni::ToJavaString(env, g_editableMapObject.GetOpeningHours());
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeSetOpeningHours(JNIEnv * env, jclass, jstring value)
{
g_editableMapObject.SetOpeningHours(jni::ToNativeString(env, value));
}
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeGetMetadata(JNIEnv * env, jclass, jint id)
{
auto const metaID = static_cast<osm::MapObject::MetadataID>(id);
ASSERT_LESS(metaID, osm::MapObject::MetadataID::FMD_COUNT, ());
if (osm::isSocialContactTag(metaID))
{
auto const value = g_editableMapObject.GetMetadata(metaID);
if (value.find('/') == std::string::npos) // `value` contains pagename.
return jni::ToJavaString(env, value);
// `value` contains URL.
return jni::ToJavaString(env, osm::socialContactToURL(metaID, value));
}
return jni::ToJavaString(env, g_editableMapObject.GetMetadata(metaID));
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeIsMetadataValid(JNIEnv * env, jclass, jint id, jstring value)
{
auto const metaID = static_cast<osm::MapObject::MetadataID>(id);
ASSERT_LESS(metaID, osm::MapObject::MetadataID::FMD_COUNT, ());
return osm::EditableMapObject::IsValidMetadata(metaID, jni::ToNativeString(env, value));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeSetMetadata(JNIEnv * env, jclass, jint id, jstring value)
{
auto const metaID = static_cast<osm::MapObject::MetadataID>(id);
ASSERT_LESS(metaID, osm::MapObject::MetadataID::FMD_COUNT, ());
g_editableMapObject.SetMetadata(metaID, jni::ToNativeString(env, value));
}
JNIEXPORT jint JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeGetStars(JNIEnv * env, jclass)
{
return g_editableMapObject.GetStars();
}
JNIEXPORT jint JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeGetMaxEditableBuildingLevels(JNIEnv *, jclass)
{
return osm::EditableMapObject::kMaximumLevelsEditableByUsers;
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeHasWifi(JNIEnv *, jclass)
{
return g_editableMapObject.GetInternet() == feature::Internet::Wlan;
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeSetHasWifi(JNIEnv *, jclass, jboolean hasWifi)
{
if (hasWifi != (g_editableMapObject.GetInternet() == feature::Internet::Wlan))
g_editableMapObject.SetInternet(hasWifi ? feature::Internet::Wlan : feature::Internet::Unknown);
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeSaveEditedFeature(JNIEnv *, jclass)
{
switch (g_framework->NativeFramework()->SaveEditedMapObject(g_editableMapObject))
{
case osm::Editor::SaveResult::NothingWasChanged:
case osm::Editor::SaveResult::SavedSuccessfully:
return true;
case osm::Editor::SaveResult::NoFreeSpaceError:
case osm::Editor::SaveResult::NoUnderlyingMapError:
case osm::Editor::SaveResult::SavingError:
return false;
}
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeShouldShowEditPlace(JNIEnv *, jclass)
{
::Framework * frm = g_framework->NativeFramework();
if (!frm->HasPlacePageInfo())
return static_cast<jboolean>(false);
return g_framework->GetPlacePageInfo().ShouldShowEditPlace();
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeShouldShowAddBusiness(JNIEnv *, jclass)
{
::Framework * frm = g_framework->NativeFramework();
if (!frm->HasPlacePageInfo())
return static_cast<jboolean>(false);
return g_framework->GetPlacePageInfo().ShouldShowAddBusiness();
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeShouldShowAddPlace(JNIEnv *, jclass)
{
::Framework * frm = g_framework->NativeFramework();
if (!frm->HasPlacePageInfo())
return static_cast<jboolean>(false);
return g_framework->GetPlacePageInfo().ShouldShowAddPlace();
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeShouldEnableEditPlace(JNIEnv *, jclass)
{
::Framework * frm = g_framework->NativeFramework();
if (!frm->HasPlacePageInfo())
return static_cast<jboolean>(false);
return g_framework->GetPlacePageInfo().ShouldEnableEditPlace();
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeShouldEnableAddPlace(JNIEnv *, jclass)
{
::Framework * frm = g_framework->NativeFramework();
if (!frm->HasPlacePageInfo())
return static_cast<jboolean>(false);
return g_framework->GetPlacePageInfo().ShouldEnableAddPlace();
}
JNIEXPORT jintArray JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeGetEditableProperties(JNIEnv * env, jclass clazz)
{
auto const & editable = g_editableMapObject.GetEditableProperties();
size_t const size = editable.size();
jintArray jEditableFields = env->NewIntArray(static_cast<jsize>(size));
jint * arr = env->GetIntArrayElements(jEditableFields, 0);
for (size_t i = 0; i < size; ++i)
arr[i] = base::Underlying(editable[i]);
env->ReleaseIntArrayElements(jEditableFields, arr, 0);
return jEditableFields;
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeIsAddressEditable(JNIEnv * env, jclass clazz)
{
return g_editableMapObject.IsAddressEditable();
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeIsNameEditable(JNIEnv * env, jclass clazz)
{
return g_editableMapObject.IsNameEditable();
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeIsPointType(JNIEnv * env, jclass clazz)
{
return g_editableMapObject.IsPointType();
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeIsBuilding(JNIEnv * env, jclass clazz)
{
return g_editableMapObject.IsBuilding();
}
JNIEXPORT jobject JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeGetNamesDataSource(JNIEnv * env, jclass)
{
auto const namesDataSource = g_editableMapObject.GetNamesDataSource();
jobjectArray names = jni::ToJavaArray(env, g_localNameClazz, namesDataSource.names, ToJavaName);
jsize const mandatoryNamesCount = static_cast<jsize>(namesDataSource.mandatoryNamesCount);
return env->NewObject(g_namesDataSourceClassID, g_namesDataSourceConstructorID, names, mandatoryNamesCount);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeSetNames(JNIEnv * env, jclass, jobjectArray names)
{
int const length = env->GetArrayLength(names);
for (int i = 0; i < length; i++)
{
auto jName = env->GetObjectArrayElement(names, i);
g_editableMapObject.SetName(jni::ToNativeString(env, static_cast<jstring>(env->GetObjectField(jName, g_localNameFieldName))),
env->GetIntField(jName, g_localNameFieldCode));
}
}
JNIEXPORT jobject JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeGetStreet(JNIEnv * env, jclass)
{
return ToJavaStreet(env, g_editableMapObject.GetStreet());
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeSetStreet(JNIEnv * env, jclass, jobject street)
{
g_editableMapObject.SetStreet({jni::ToNativeString(env, (jstring) env->GetObjectField(street, g_localStreetFieldDef)),
jni::ToNativeString(env, (jstring) env->GetObjectField(street, g_localStreetFieldLoc))});
}
JNIEXPORT jobjectArray JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeGetNearbyStreets(JNIEnv * env, jclass clazz)
{
return jni::ToJavaArray(env, g_localStreetClazz, g_editableMapObject.GetNearbyStreets(), ToJavaStreet);
}
JNIEXPORT jobjectArray JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeGetSupportedLanguages(JNIEnv * env, jclass clazz, jboolean includeServiceLangs)
{
using TLang = StringUtf8Multilang::Lang;
//public Language(@NonNull String code, @NonNull String name)
static jclass const langClass = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/editor/data/Language");
static jmethodID const langCtor = jni::GetConstructorID(env, langClass, "(Ljava/lang/String;Ljava/lang/String;)V");
return jni::ToJavaArray(env, langClass, StringUtf8Multilang::GetSupportedLanguages(includeServiceLangs),
[](JNIEnv * env, TLang const & lang)
{
jni::TScopedLocalRef const code(env, jni::ToJavaString(env, lang.m_code));
jni::TScopedLocalRef const name(env, jni::ToJavaString(env, lang.m_name));
return env->NewObject(langClass, langCtor, code.get(), name.get());
});
}
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeGetHouseNumber(JNIEnv * env, jclass)
{
return jni::ToJavaString(env, g_editableMapObject.GetHouseNumber());
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeSetHouseNumber(JNIEnv * env, jclass, jstring houseNumber)
{
g_editableMapObject.SetHouseNumber(jni::ToNativeString(env, houseNumber));
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeHasSomethingToUpload(JNIEnv * env, jclass clazz)
{
return Editor::Instance().HaveMapEditsOrNotesToUpload();
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeUploadChanges(JNIEnv * env, jclass clazz, jstring token, jstring appVersion, jstring appId)
{
// TODO: Handle upload status in callback
Editor::Instance().UploadChanges(jni::ToNativeString(env, token),
{{"created_by", "CoMaps " OMIM_OS_NAME " " + jni::ToNativeString(env, appVersion)},
{"bundle_id", jni::ToNativeString(env, appId)}}, nullptr);
}
JNIEXPORT jlongArray JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeGetStats(JNIEnv * env, jclass clazz)
{
auto const stats = Editor::Instance().GetStats();
jlongArray result = env->NewLongArray(3);
jlong buf[] = {static_cast<jlong>(stats.m_edits.size()), static_cast<jlong>(stats.m_uploadedCount),
stats.m_lastUploadTimestamp};
env->SetLongArrayRegion(result, 0, 3, buf);
return result;
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeClearLocalEdits(JNIEnv * env, jclass clazz)
{
Editor::Instance().ClearAllLocalEdits();
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeStartEdit(JNIEnv *, jclass)
{
::Framework * frm = g_framework->NativeFramework();
if (!frm->HasPlacePageInfo())
{
ASSERT(g_editableMapObject.GetEditingLifecycle() == osm::EditingLifecycle::CREATED,
("PlacePageInfo should only be empty for new features."));
return;
}
place_page::Info const & info = g_framework->GetPlacePageInfo();
CHECK(frm->GetEditableMapObject(info.GetID(), g_editableMapObject), ("Invalid feature in the place page."));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeCreateMapObject(JNIEnv * env, jclass,
jstring featureType)
{
::Framework * frm = g_framework->NativeFramework();
auto const type = classif().GetTypeByReadableObjectName(jni::ToNativeString(env, featureType));
CHECK(frm->CreateMapObject(frm->GetViewportCenter(), type, g_editableMapObject),
("Couldn't create mapobject, wrong coordinates of missing mwm"));
}
// static void nativeCreateNote(String text);
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeCreateNote(JNIEnv * env, jclass clazz, jstring text)
{
g_framework->NativeFramework()->CreateNote(
g_editableMapObject, osm::Editor::NoteProblemType::General, jni::ToNativeString(env, text));
}
// static void nativePlaceDoesNotExist(String comment);
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativePlaceDoesNotExist(JNIEnv * env, jclass clazz, jstring comment)
{
g_framework->NativeFramework()->CreateNote(g_editableMapObject,
osm::Editor::NoteProblemType::PlaceDoesNotExist,
jni::ToNativeString(env, comment));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeRollbackMapObject(JNIEnv * env, jclass clazz)
{
g_framework->NativeFramework()->RollBackChanges(g_editableMapObject.GetID());
}
JNIEXPORT jobjectArray JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeGetAllCreatableFeatureTypes(JNIEnv * env, jclass clazz,
jstring jLang)
{
std::string const & lang = jni::ToNativeString(env, jLang);
auto & categories = GetFeatureCategories();
categories.AddLanguage(lang);
categories.AddLanguage("en");
return jni::ToJavaStringArray(env, categories.GetAllCreatableTypeNames());
}
JNIEXPORT jobjectArray JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeSearchCreatableFeatureTypes(JNIEnv * env, jclass clazz,
jstring query,
jstring jLang)
{
std::string const & lang = jni::ToNativeString(env, jLang);
auto & categories = GetFeatureCategories();
categories.AddLanguage(lang);
categories.AddLanguage("en");
return jni::ToJavaStringArray(env, categories.Search(jni::ToNativeString(env, query)));
}
JNIEXPORT jobjectArray JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeGetCuisines(JNIEnv * env, jclass clazz)
{
osm::AllCuisines const & cuisines = osm::Cuisines::Instance().AllSupportedCuisines();
std::vector<std::string> keys;
keys.reserve(cuisines.size());
for (TCuisine const & cuisine : cuisines)
keys.push_back(cuisine.first);
return jni::ToJavaStringArray(env, keys);
}
JNIEXPORT jobjectArray JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeGetSelectedCuisines(JNIEnv * env, jclass clazz)
{
return jni::ToJavaStringArray(env, g_editableMapObject.GetCuisines());
}
JNIEXPORT jobjectArray JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeFilterCuisinesKeys(JNIEnv * env, jclass thiz, jstring jSubstr)
{
std::string const substr = jni::ToNativeString(env, jSubstr);
bool const noFilter = substr.length() == 0;
osm::AllCuisines const & cuisines = osm::Cuisines::Instance().AllSupportedCuisines();
std::vector<std::string> keys;
keys.reserve(cuisines.size());
for (TCuisine const & cuisine : cuisines)
{
std::string const & key = cuisine.first;
std::string const & label = cuisine.second;
if (noFilter || search::ContainsNormalized(key, substr) || search::ContainsNormalized(label, substr))
keys.push_back(key);
}
return jni::ToJavaStringArray(env, keys);
}
JNIEXPORT jobjectArray JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeTranslateCuisines(JNIEnv * env, jclass clazz, jobjectArray jKeys)
{
int const length = env->GetArrayLength(jKeys);
auto const & cuisines = osm::Cuisines::Instance();
std::vector<std::string> translations;
translations.reserve(length);
for (int i = 0; i < length; i++)
{
std::string const key = jni::ToNativeString(env, static_cast<jstring>(env->GetObjectArrayElement(jKeys, i)));
translations.push_back(cuisines.Translate(key));
}
return jni::ToJavaStringArray(env, translations);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeSetSelectedCuisines(JNIEnv * env, jclass clazz, jobjectArray jKeys)
{
int const length = env->GetArrayLength(jKeys);
std::vector<std::string> cuisines;
cuisines.reserve(length);
for (int i = 0; i < length; i++)
cuisines.push_back(jni::ToNativeString(env, static_cast<jstring>(env->GetObjectArrayElement(jKeys, i))));
g_editableMapObject.SetCuisines(cuisines);
}
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeGetFormattedCuisine(JNIEnv * env, jclass clazz)
{
return jni::ToJavaString(env, g_editableMapObject.FormatCuisines());
}
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeGetMwmName(JNIEnv * env, jclass clazz)
{
return jni::ToJavaString(env, g_editableMapObject.GetID().GetMwmName());
}
JNIEXPORT jlong JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeGetMwmVersion(JNIEnv * env, jclass clazz)
{
return g_editableMapObject.GetID().GetMwmVersion();
}
// static boolean nativeIsHouseValid(String houseNumber);
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeIsHouseValid(JNIEnv * env, jclass clazz, jstring houseNumber)
{
return osm::EditableMapObject::ValidateHouseNumber(jni::ToNativeString(env, houseNumber));
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeIsNameValid(JNIEnv * env, jclass clazz, jstring name)
{
return osm::EditableMapObject::ValidateName(jni::ToNativeString(env, name));
}
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeGetCategory(JNIEnv * env, jclass clazz)
{
auto types = g_editableMapObject.GetTypes();
types.SortBySpec();
return jni::ToJavaString(env, classif().GetReadableObjectName(*types.begin()));
}
// @FeatureStatus
// static native int nativeGetMapObjectStatus();
JNIEXPORT jint JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeGetMapObjectStatus(JNIEnv * env, jclass clazz)
{
return static_cast<jint>(osm::Editor::Instance().GetFeatureStatus(g_editableMapObject.GetID()));
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeIsMapObjectUploaded(JNIEnv * env, jclass clazz)
{
return osm::Editor::Instance().IsFeatureUploaded(g_editableMapObject.GetID().m_mwmId, g_editableMapObject.GetID().m_index);
}
// static nativeMakeLocalizedName(String langCode, String name);
JNIEXPORT jobject JNICALL
Java_app_organicmaps_sdk_editor_Editor_nativeMakeLocalizedName(JNIEnv * env, jclass clazz, jstring code, jstring name)
{
osm::LocalizedName localizedName(jni::ToNativeString(env, code), jni::ToNativeString(env, name));
return ToJavaName(env, localizedName);
}
} // extern "C"

View File

@@ -0,0 +1,350 @@
#include <jni.h>
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/platform/AndroidPlatform.hpp"
#include "editor/opening_hours_ui.hpp"
#include "editor/ui2oh.hpp"
#include "base/logging.hpp"
#include "3party/opening_hours/opening_hours.hpp"
#include <algorithm>
#include <set>
#include <vector>
namespace
{
using namespace editor;
using namespace editor::ui;
using namespace osmoh;
using THours = std::chrono::hours;
using TMinutes = std::chrono::minutes;
// ID-s for HoursMinutes class
jclass g_clazzHoursMinutes;
jmethodID g_ctorHoursMinutes;
jfieldID g_fidHours;
jfieldID g_fidMinutes;
// ID-s for Timespan class
jclass g_clazzTimespan;
jmethodID g_ctorTimespan;
jfieldID g_fidStart;
jfieldID g_fidEnd;
// ID-s for Timetable class
jclass g_clazzTimetable;
jmethodID g_ctorTimetable;
jfieldID g_fidWorkingTimespan;
jfieldID g_fidClosedTimespans;
jfieldID g_fidIsFullday;
jfieldID g_fidWeekdays;
jobject JavaHoursMinutes(JNIEnv * env, jlong hours, jlong minutes)
{
static const jclass dateUtilsClass = jni::GetGlobalClassRef(env,
"app/organicmaps/sdk/util/DateUtils");
static jmethodID const is24HourFormatMethod =
jni::GetStaticMethodID(env,
dateUtilsClass,
"is24HourFormat",
"(Landroid/content/Context;)Z");
jobject context = android::Platform::Instance().GetContext();
jboolean const is24HourFormat = env->CallStaticBooleanMethod(dateUtilsClass,
is24HourFormatMethod,
context);
jobject const hoursMinutes = env->NewObject(g_clazzHoursMinutes,
g_ctorHoursMinutes,
hours,
minutes,
is24HourFormat);
ASSERT(hoursMinutes, (jni::DescribeException()));
return hoursMinutes;
}
jobject JavaTimespan(JNIEnv * env, jobject start, jobject end)
{
jobject const span = env->NewObject(g_clazzTimespan, g_ctorTimespan, start, end);
ASSERT(span, (jni::DescribeException()));
return span;
}
jobject JavaTimespan(JNIEnv * env, osmoh::Timespan const & timespan)
{
auto const start = timespan.GetStart();
auto const end = timespan.GetEnd();
return JavaTimespan(env,
JavaHoursMinutes(env, start.GetHoursCount(), start.GetMinutesCount()),
JavaHoursMinutes(env, end.GetHoursCount(), end.GetMinutesCount()));
}
jobject JavaTimetable(JNIEnv * env, jobject workingHours, jobject closedHours, bool isFullday, jintArray weekdays)
{
jobject const tt = env->NewObject(g_clazzTimetable, g_ctorTimetable, workingHours, closedHours, isFullday, weekdays);
ASSERT(tt, (jni::DescribeException()));
return tt;
}
jobject JavaTimetable(JNIEnv * env, TimeTable const & tt)
{
auto const excludeSpans = tt.GetExcludeTime();
std::set<Weekday> weekdays = tt.GetOpeningDays();
std::vector<int> weekdaysVector;
weekdaysVector.reserve(weekdays.size());
std::transform(weekdays.begin(), weekdays.end(), std::back_inserter(weekdaysVector), [](Weekday weekday)
{
return static_cast<int>(weekday);
});
jintArray jWeekdays = env->NewIntArray(static_cast<jsize>(weekdays.size()));
env->SetIntArrayRegion(jWeekdays, 0, static_cast<jsize>(weekdaysVector.size()),
&weekdaysVector[0]);
return JavaTimetable(env,
JavaTimespan(env, tt.GetOpeningTime()),
jni::ToJavaArray(env, g_clazzTimespan, tt.GetExcludeTime(), [](JNIEnv * env, osmoh::Timespan const & timespan)
{
return JavaTimespan(env, timespan);
}),
tt.IsTwentyFourHours(),
jWeekdays);
}
jobjectArray JavaTimetables(JNIEnv * env, TimeTableSet & tts)
{
size_t const size = tts.Size();
jobjectArray const result = env->NewObjectArray(static_cast<jsize>(size), g_clazzTimetable, 0);
for (size_t i = 0; i < size; i++)
{
jni::TScopedLocalRef jTable(env, JavaTimetable(env, tts.Get(i)));
env->SetObjectArrayElement(result, static_cast<jsize>(i), jTable.get());
}
return result;
}
HourMinutes NativeHoursMinutes(JNIEnv * env, jobject jHourMinutes)
{
jlong const hours = env->GetLongField(jHourMinutes, g_fidHours);
jlong const minutes = env->GetLongField(jHourMinutes, g_fidMinutes);
return HourMinutes(THours(hours) + TMinutes(minutes));
}
Timespan NativeTimespan(JNIEnv * env, jobject jTimespan)
{
Timespan span;
span.SetStart(NativeHoursMinutes(env, env->GetObjectField(jTimespan, g_fidStart)));
span.SetEnd(NativeHoursMinutes(env, env->GetObjectField(jTimespan, g_fidEnd)));
return span;
}
TimeTable NativeTimetable(JNIEnv * env, jobject jTimetable)
{
TimeTable tt = TimeTable::GetPredefinedTimeTable();
jintArray const jWeekdays = static_cast<jintArray>(env->GetObjectField(jTimetable, g_fidWeekdays));
int * weekdaysArr = static_cast<int*>(env->GetIntArrayElements(jWeekdays, nullptr));
jint size = env->GetArrayLength(jWeekdays);
std::set<Weekday> weekdays;
for (int i = 0; i < size; i++)
weekdays.insert(ToWeekday(weekdaysArr[i]));
tt.SetOpeningDays(weekdays);
env->ReleaseIntArrayElements(jWeekdays, weekdaysArr, 0);
tt.SetTwentyFourHours(env->GetBooleanField(jTimetable, g_fidIsFullday));
tt.SetOpeningTime(NativeTimespan(env, env->GetObjectField(jTimetable, g_fidWorkingTimespan)));
jobjectArray jClosedSpans = static_cast<jobjectArray>(env->GetObjectField(jTimetable, g_fidClosedTimespans));
size = env->GetArrayLength(jClosedSpans);
for (int i = 0; i < size; i++)
{
jni::TScopedLocalRef jSpan(env, env->GetObjectArrayElement(jClosedSpans, i));
if (jSpan.get())
tt.AddExcludeTime(NativeTimespan(env, jSpan.get()));
}
return tt;
}
TimeTableSet NativeTimetableSet(JNIEnv * env, jobjectArray jTimetables)
{
TimeTableSet tts;
int const size = env->GetArrayLength(jTimetables);
tts.Replace(NativeTimetable(env, env->GetObjectArrayElement(jTimetables, 0)), 0);
for (int i = 1; i < size; i++)
{
jni::TScopedLocalRef timetable(env, env->GetObjectArrayElement(jTimetables, i));
tts.Append(NativeTimetable(env, timetable.get()));
}
return tts;
}
} // namespace
extern "C"
{
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_editor_OpeningHours_nativeInit(JNIEnv * env, jclass clazz)
{
g_clazzHoursMinutes = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/editor/data/HoursMinutes");
// Java signature : HoursMinutes(@IntRange(from = 0, to = 24) long hours, @IntRange(from = 0, to = 60) long minutes)
g_ctorHoursMinutes = env->GetMethodID(g_clazzHoursMinutes, "<init>", "(JJZ)V");
ASSERT(g_ctorHoursMinutes, (jni::DescribeException()));
g_fidHours = env->GetFieldID(g_clazzHoursMinutes, "hours", "J");
ASSERT(g_fidHours, (jni::DescribeException()));
g_fidMinutes = env->GetFieldID(g_clazzHoursMinutes, "minutes", "J");
ASSERT(g_fidMinutes, (jni::DescribeException()));
g_clazzTimespan = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/editor/data/Timespan");
// Java signature : Timespan(HoursMinutes start, HoursMinutes end)
g_ctorTimespan =
env->GetMethodID(g_clazzTimespan, "<init>","(Lapp/organicmaps/sdk/editor/data/HoursMinutes;Lapp/organicmaps/sdk/editor/data/HoursMinutes;)V");
ASSERT(g_ctorTimespan, (jni::DescribeException()));
g_fidStart = env->GetFieldID(g_clazzTimespan, "start", "Lapp/organicmaps/sdk/editor/data/HoursMinutes;");
ASSERT(g_fidStart, (jni::DescribeException()));
g_fidEnd = env->GetFieldID(g_clazzTimespan, "end", "Lapp/organicmaps/sdk/editor/data/HoursMinutes;");
ASSERT(g_fidEnd, (jni::DescribeException()));
g_clazzTimetable = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/editor/data/Timetable");
// Java signature : Timetable(Timespan workingTime, Timespan[] closedHours, boolean isFullday, int weekdays[])
g_ctorTimetable =
env->GetMethodID(g_clazzTimetable, "<init>","(Lapp/organicmaps/sdk/editor/data/Timespan;[Lapp/organicmaps/sdk/editor/data/Timespan;Z[I)V");
ASSERT(g_ctorTimetable, (jni::DescribeException()));
g_fidWorkingTimespan = env->GetFieldID(g_clazzTimetable, "workingTimespan", "Lapp/organicmaps/sdk/editor/data/Timespan;");
ASSERT(g_fidWorkingTimespan, (jni::DescribeException()));
g_fidClosedTimespans = env->GetFieldID(g_clazzTimetable, "closedTimespans", "[Lapp/organicmaps/sdk/editor/data/Timespan;");
ASSERT(g_fidClosedTimespans, (jni::DescribeException()));
g_fidIsFullday = env->GetFieldID(g_clazzTimetable, "isFullday", "Z");
ASSERT(g_fidIsFullday, (jni::DescribeException()));
g_fidWeekdays = env->GetFieldID(g_clazzTimetable, "weekdays", "[I");
ASSERT(g_fidWeekdays, (jni::DescribeException()));
}
JNIEXPORT jobjectArray JNICALL
Java_app_organicmaps_sdk_editor_OpeningHours_nativeGetDefaultTimetables(JNIEnv * env, jclass clazz)
{
TimeTableSet tts;
return JavaTimetables(env, tts);
}
JNIEXPORT jobject JNICALL
Java_app_organicmaps_sdk_editor_OpeningHours_nativeGetComplementTimetable(JNIEnv * env, jclass clazz, jobjectArray timetables)
{
TimeTableSet const tts = NativeTimetableSet(env, timetables);
return JavaTimetable(env, tts.GetComplementTimeTable());
}
JNIEXPORT jobjectArray JNICALL
Java_app_organicmaps_sdk_editor_OpeningHours_nativeRemoveWorkingDay(JNIEnv * env, jclass clazz,
jobjectArray timetables, jint ttIndex, jint dayIndex)
{
TimeTableSet tts = NativeTimetableSet(env, timetables);
auto tt = tts.Get(ttIndex);
tt.RemoveWorkingDay(ToWeekday(dayIndex));
tt.Commit();
return JavaTimetables(env, tts);
}
JNIEXPORT jobjectArray JNICALL
Java_app_organicmaps_sdk_editor_OpeningHours_nativeAddWorkingDay(JNIEnv * env, jclass clazz,
jobjectArray timetables, jint ttIndex, jint dayIndex)
{
TimeTableSet tts = NativeTimetableSet(env, timetables);
auto tt = tts.Get(ttIndex);
tt.AddWorkingDay(ToWeekday(dayIndex));
tt.Commit();
return JavaTimetables(env, tts);
}
JNIEXPORT jobject JNICALL
Java_app_organicmaps_sdk_editor_OpeningHours_nativeSetIsFullday(JNIEnv * env, jclass clazz,
jobject jTimetable, jboolean jIsFullday)
{
TimeTable tt = NativeTimetable(env, jTimetable);
if (jIsFullday)
tt.SetTwentyFourHours(true);
else
{
tt.SetTwentyFourHours(false);
tt.SetOpeningTime(tt.GetPredefinedOpeningTime());
}
return JavaTimetable(env, tt);
}
JNIEXPORT jobject JNICALL
Java_app_organicmaps_sdk_editor_OpeningHours_nativeSetOpeningTime(JNIEnv * env, jclass clazz,
jobject jTimetable, jobject jOpeningTime)
{
TimeTable tt = NativeTimetable(env, jTimetable);
tt.SetOpeningTime(NativeTimespan(env, jOpeningTime));
return JavaTimetable(env, tt);
}
JNIEXPORT jobject JNICALL
Java_app_organicmaps_sdk_editor_OpeningHours_nativeAddClosedSpan(JNIEnv * env, jclass clazz,
jobject jTimetable, jobject jClosedSpan)
{
TimeTable tt = NativeTimetable(env, jTimetable);
tt.AddExcludeTime(NativeTimespan(env, jClosedSpan));
return JavaTimetable(env, tt);
}
JNIEXPORT jobject JNICALL
Java_app_organicmaps_sdk_editor_OpeningHours_nativeRemoveClosedSpan(JNIEnv * env, jclass clazz,
jobject jTimetable, jint jClosedSpanIndex)
{
TimeTable tt = NativeTimetable(env, jTimetable);
tt.RemoveExcludeTime(static_cast<size_t>(jClosedSpanIndex));
return JavaTimetable(env, tt);
}
JNIEXPORT jobjectArray JNICALL
Java_app_organicmaps_sdk_editor_OpeningHours_nativeTimetablesFromString(JNIEnv * env, jclass clazz, jstring jSource)
{
TimeTableSet tts;
std::string const source = jni::ToNativeString(env, jSource);
if (!source.empty() && MakeTimeTableSet(OpeningHours(source), tts))
return JavaTimetables(env, tts);
return nullptr;
}
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_editor_OpeningHours_nativeTimetablesToString(JNIEnv * env, jclass clazz, jobjectArray jTts)
{
TimeTableSet tts = NativeTimetableSet(env, jTts);
std::stringstream sstr;
sstr << MakeOpeningHours(tts).GetRule();
return jni::ToJavaString(env, sstr.str());
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_editor_OpeningHours_nativeIsTimetableStringValid(JNIEnv * env, jclass clazz, jstring jSource)
{
return OpeningHours(jni::ToNativeString(env, jSource)).IsValid();
}
JNIEXPORT jobject JNICALL
Java_app_organicmaps_sdk_editor_OpeningHours_nativeCurrentState(JNIEnv * env, jclass clazz, jobjectArray jTts)
{
TimeTableSet tts = NativeTimetableSet(env, jTts);
time_t const now = time(nullptr);
/// @todo We should check closed/open time for specific feature's timezone.
OpeningHours::InfoT ohInfo = MakeOpeningHours(tts).GetInfo(now);
jclass ohStateClass = jni::GetGlobalClassRef(env, "app/organicmaps/editor/OhState");
jclass ruleStateClass = jni::GetGlobalClassRef(env, "app/organicmaps/editor/OhState$State");
static const std::unordered_map<RuleState, const char*> ruleState = {
{RuleState::Open, "Open"},
{RuleState::Closed, "Closed"},
{RuleState::Unknown, "Unknown"}
};
jfieldID stateField = env->GetStaticFieldID(ruleStateClass, ruleState.at(ohInfo.state), "Lapp/organicmaps/editor/OhState$State;");
jobject stateObj = env->GetStaticObjectField(ruleStateClass, stateField);
jmethodID constructor = env->GetMethodID(ohStateClass, "<init>", "(Lapp/organicmaps/editor/OhState$State;JJ)V");
jobject javaOhState = env->NewObject(ohStateClass, constructor, stateObj, (jlong) ohInfo.nextTimeOpen, (jlong) ohInfo.nextTimeClosed);
return javaOhState;
}
} // extern "C"

View File

@@ -0,0 +1,113 @@
#include <jni.h>
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/Framework.hpp"
#include "base/logging.hpp"
#include "base/string_utils.hpp"
#include "base/timer.hpp"
#include "editor/osm_auth.hpp"
#include "editor/server_api.hpp"
namespace
{
using namespace osm;
using namespace jni;
bool LoadOsmUserPreferences(std::string const & oauthToken, UserPreferences & outPrefs)
{
ServerApi06 const api(OsmOAuth::ServerAuth(oauthToken));
outPrefs = api.GetUserPreferences();
return (outPrefs.m_id != 0);
}
} // namespace
extern "C"
{
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_editor_OsmOAuth_nativeGetOAuth2Url(JNIEnv * env, jclass)
{
auto const auth = OsmOAuth::ServerAuth();
return ToJavaString(env, auth.BuildOAuth2Url());
}
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_editor_OsmOAuth_nativeAuthWithPassword(JNIEnv * env, jclass clazz,
jstring login, jstring password)
{
OsmOAuth auth = OsmOAuth::ServerAuth();
try
{
if (auth.AuthorizePassword(ToNativeString(env, login), ToNativeString(env, password)))
return ToJavaString(env, auth.GetAuthToken());
LOG(LWARNING, ("nativeAuthWithPassword: invalid login or password."));
}
catch (std::exception const & ex)
{
LOG(LWARNING, ("nativeAuthWithPassword error ", ex.what()));
}
return nullptr;
}
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_editor_OsmOAuth_nativeAuthWithOAuth2Code(JNIEnv * env, jclass, jstring oauth2code)
{
OsmOAuth auth = OsmOAuth::ServerAuth();
try
{
auto token = auth.FinishAuthorization(ToNativeString(env, oauth2code));
if (!token.empty())
{
auth.SetAuthToken(token);
return ToJavaString(env, token);
}
LOG(LWARNING, ("nativeAuthWithOAuth2Code: invalid OAuth2 code", oauth2code));
}
catch (std::exception const & ex)
{
LOG(LWARNING, ("nativeAuthWithOAuth2Code error ", ex.what()));
}
return nullptr;
}
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_editor_OsmOAuth_nativeGetOsmUsername(JNIEnv * env, jclass, jstring oauthToken)
{
UserPreferences prefs;
if (LoadOsmUserPreferences(jni::ToNativeString(env, oauthToken), prefs))
return jni::ToJavaString(env, prefs.m_displayName);
return nullptr;
}
JNIEXPORT jint JNICALL
Java_app_organicmaps_sdk_editor_OsmOAuth_nativeGetOsmChangesetsCount(JNIEnv * env, jclass, jstring oauthToken)
{
UserPreferences prefs;
if (LoadOsmUserPreferences(jni::ToNativeString(env, oauthToken), prefs))
return prefs.m_changesets;
return -1;
}
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_editor_OsmOAuth_nativeGetOsmProfilePictureUrl(JNIEnv * env, jclass, jstring oauthToken)
{
UserPreferences prefs;
if (LoadOsmUserPreferences(jni::ToNativeString(env, oauthToken), prefs))
return jni::ToJavaString(env, prefs.m_imageUrl);
return nullptr;
}
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_editor_OsmOAuth_nativeGetHistoryUrl(JNIEnv * env, jclass, jstring user)
{
return jni::ToJavaString(env, OsmOAuth::ServerAuth().GetHistoryURL(jni::ToNativeString(env, user)));
}
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_editor_OsmOAuth_nativeGetNotesUrl(JNIEnv * env, jclass, jstring user)
{
return jni::ToJavaString(env, OsmOAuth::ServerAuth().GetNotesURL(jni::ToNativeString(env, user)));
}
} // extern "C"

View File

@@ -0,0 +1,47 @@
#include <jni.h>
#include "app/organicmaps/sdk/Framework.hpp"
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/platform/AndroidPlatform.hpp"
using namespace std::placeholders;
extern "C"
{
static void IsolinesStateChanged(IsolinesManager::IsolinesState state,
std::shared_ptr<jobject> const & listener)
{
LOG(LINFO, (static_cast<int>(state)));
JNIEnv * env = jni::GetEnv();
env->CallVoidMethod(*listener,
jni::GetMethodID(env, *listener, "onStateChanged", "(I)V"),
static_cast<jint>(state));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_maplayer_isolines_IsolinesManager_nativeAddListener(JNIEnv *env, jclass clazz, jobject listener)
{
CHECK(g_framework, ("Framework isn't created yet!"));
g_framework->SetIsolinesListener(std::bind(&IsolinesStateChanged,
std::placeholders::_1,
jni::make_global_ref(listener)));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_maplayer_isolines_IsolinesManager_nativeRemoveListener(JNIEnv * env, jclass clazz)
{
CHECK(g_framework, ("Framework isn't created yet!"));
g_framework->SetIsolinesListener(nullptr);
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_maplayer_isolines_IsolinesManager_nativeShouldShowNotification(JNIEnv *env,
jclass clazz)
{
CHECK(g_framework, ("Framework isn't created yet!"));
auto const &manager = g_framework->NativeFramework()->GetIsolinesManager();
auto const visible = manager.IsVisible();
auto const enabled = manager.GetState() == IsolinesManager::IsolinesState::Enabled;
return static_cast<jboolean>(!visible && enabled);
}
}

View File

@@ -0,0 +1,86 @@
#include "android_gl_utils.hpp"
#include "base/logging.hpp"
#include "base/src_point.hpp"
#include "base/string_utils.hpp"
namespace android
{
ConfigComparator::ConfigComparator(EGLDisplay display)
: m_display(display)
{
}
bool ConfigComparator::operator()(EGLConfig const & l, EGLConfig const & r) const
{
int const weight = configWeight(l) - configWeight(r);
if (weight == 0)
return configAlphaSize(l) < configAlphaSize(r);
return weight < 0;
}
int ConfigComparator::configWeight(EGLConfig const & config) const
{
int val = -1;
eglGetConfigAttrib(m_display, config, EGL_CONFIG_CAVEAT, &val);
switch (val)
{
case EGL_NONE:
return 0;
case EGL_SLOW_CONFIG:
return 1;
case EGL_NON_CONFORMANT_CONFIG:
return 2;
default:
return 0;
}
}
int ConfigComparator::configAlphaSize(EGLConfig const & config) const
{
int val = 0;
eglGetConfigAttrib(m_display, config, EGL_ALPHA_SIZE, &val);
return val;
}
namespace
{
std::string GetEglError(EGLint error)
{
switch (error)
{
case EGL_NOT_INITIALIZED : return "EGL_NOT_INITIALIZED";
case EGL_BAD_ACCESS : return "EGL_BAD_ACCESS";
case EGL_BAD_ALLOC : return "EGL_BAD_ALLOC";
case EGL_BAD_ATTRIBUTE : return "EGL_BAD_ATTRIBUTE";
case EGL_BAD_CONFIG : return "EGL_BAD_CONFIG";
case EGL_BAD_CONTEXT : return "EGL_BAD_CONTEXT";
case EGL_BAD_CURRENT_SURFACE : return "EGL_BAD_CURRENT_SURFACE";
case EGL_BAD_DISPLAY : return "EGL_BAD_DISPLAY";
case EGL_BAD_MATCH : return "EGL_BAD_MATCH";
case EGL_BAD_NATIVE_PIXMAP : return "EGL_BAD_NATIVE_PIXMAP";
case EGL_BAD_NATIVE_WINDOW : return "EGL_BAD_NATIVE_WINDOW";
case EGL_BAD_PARAMETER : return "EGL_BAD_PARAMETER";
case EGL_BAD_SURFACE : return "EGL_BAD_SURFACE";
case EGL_CONTEXT_LOST : return "EGL_CONTEXT_LOST";
default: return strings::to_string(error);
}
}
} // namespace
void CheckEGL(base::SrcPoint const & src)
{
EGLint error = eglGetError();
while (error != EGL_SUCCESS)
{
LOG(LERROR, ("SrcPoint : ", src, ". EGL error : ", GetEglError(error)));
error = eglGetError();
}
}
} // namespace android

View File

@@ -0,0 +1,29 @@
#pragma once
#include "drape/gl_includes.hpp"
namespace base
{
class SrcPoint;
} // namespace base
namespace android
{
class ConfigComparator
{
public:
explicit ConfigComparator(EGLDisplay display);
bool operator()(EGLConfig const & l, EGLConfig const & r) const;
int configWeight(EGLConfig const & config) const;
int configAlphaSize(EGLConfig const & config) const;
private:
EGLDisplay m_display;
};
void CheckEGL(base::SrcPoint const & src);
} // namespace android
#define CHECK_EGL(x) do { (x); android::CheckEGL(SRC());} while(false);
#define CHECK_EGL_CALL() do { android::CheckEGL(SRC());} while (false);

View File

@@ -0,0 +1,113 @@
#include "androidoglcontext.hpp"
#include "android_gl_utils.hpp"
#include "base/assert.hpp"
#include "base/logging.hpp"
#include "base/src_point.hpp"
namespace android
{
static EGLint * getContextAttributesList(bool supportedES3)
{
static EGLint contextAttrList[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
static EGLint contextAttrListES3[] = {
EGL_CONTEXT_CLIENT_VERSION, 3,
EGL_NONE
};
return supportedES3 ? contextAttrListES3 : contextAttrList;
}
AndroidOGLContext::AndroidOGLContext(bool supportedES3, EGLDisplay display, EGLSurface surface,
EGLConfig config, AndroidOGLContext * contextToShareWith)
: m_nativeContext(EGL_NO_CONTEXT)
, m_surface(surface)
, m_display(display)
, m_presentAvailable(true)
{
ASSERT(m_surface != EGL_NO_SURFACE, ());
ASSERT(m_display != EGL_NO_DISPLAY, ());
EGLContext sharedContext = (contextToShareWith == NULL) ? EGL_NO_CONTEXT : contextToShareWith->m_nativeContext;
m_nativeContext = eglCreateContext(m_display, config, sharedContext, getContextAttributesList(supportedES3));
CHECK(m_nativeContext != EGL_NO_CONTEXT, ());
}
AndroidOGLContext::~AndroidOGLContext()
{
// Native context must exist
if (eglDestroyContext(m_display, m_nativeContext) == EGL_FALSE)
CHECK_EGL_CALL();
}
void AndroidOGLContext::SetFramebuffer(ref_ptr<dp::BaseFramebuffer> framebuffer)
{
if (framebuffer)
framebuffer->Bind();
else
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void AndroidOGLContext::MakeCurrent()
{
ASSERT(m_surface != EGL_NO_SURFACE, ());
if (eglMakeCurrent(m_display, m_surface, m_surface, m_nativeContext) == EGL_FALSE)
CHECK_EGL_CALL();
}
void AndroidOGLContext::DoneCurrent()
{
ClearCurrent();
}
void AndroidOGLContext::ClearCurrent()
{
if (eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) == EGL_FALSE)
CHECK_EGL_CALL();
}
void AndroidOGLContext::SetRenderingEnabled(bool enabled)
{
if (enabled)
MakeCurrent();
else
ClearCurrent();
}
void AndroidOGLContext::SetPresentAvailable(bool available)
{
m_presentAvailable = available;
}
bool AndroidOGLContext::Validate()
{
if (!m_presentAvailable)
return false;
return eglGetCurrentDisplay() != EGL_NO_DISPLAY &&
eglGetCurrentSurface(EGL_DRAW) != EGL_NO_SURFACE &&
eglGetCurrentContext() != EGL_NO_CONTEXT;
}
void AndroidOGLContext::Present()
{
if (!m_presentAvailable)
return;
ASSERT(m_surface != EGL_NO_SURFACE, ());
if (eglSwapBuffers(m_display, m_surface) == EGL_FALSE)
CHECK_EGL_CALL();
}
void AndroidOGLContext::SetSurface(EGLSurface surface)
{
m_surface = surface;
ASSERT(m_surface != EGL_NO_SURFACE, ());
}
void AndroidOGLContext::ResetSurface()
{
m_surface = EGL_NO_SURFACE;
}
} // namespace android

View File

@@ -0,0 +1,42 @@
#pragma once
#include "drape/gl_includes.hpp"
#include "drape/oglcontext.hpp"
#include <atomic>
namespace android
{
class AndroidOGLContext : public dp::OGLContext
{
public:
AndroidOGLContext(bool supportedES3, EGLDisplay display, EGLSurface surface,
EGLConfig config, AndroidOGLContext * contextToShareWith);
~AndroidOGLContext();
void MakeCurrent() override;
void DoneCurrent() override;
void Present() override;
void SetFramebuffer(ref_ptr<dp::BaseFramebuffer> framebuffer) override;
void SetRenderingEnabled(bool enabled) override;
void SetPresentAvailable(bool available) override;
bool Validate() override;
void SetSurface(EGLSurface surface);
void ResetSurface();
void ClearCurrent();
private:
// {@ Owned by Context
EGLContext m_nativeContext;
// @}
// {@ Owned by Factory
EGLSurface m_surface;
EGLDisplay m_display;
// @}
std::atomic<bool> m_presentAvailable;
};
} // namespace android

View File

@@ -0,0 +1,388 @@
#include "androidoglcontextfactory.hpp"
#include "android_gl_utils.hpp"
#include "app/organicmaps/sdk/platform/AndroidPlatform.hpp"
#include "base/assert.hpp"
#include "base/logging.hpp"
#include "base/src_point.hpp"
#include <algorithm>
#include <EGL/egl.h>
#include <android/api-level.h>
#include <android/native_window.h>
#include <android/native_window_jni.h>
#define EGL_OPENGL_ES3_BIT 0x00000040
int constexpr kMinSdkVersionForES3 = 21;
namespace android
{
namespace
{
static EGLint * getConfigAttributesListRGB8(bool supportedES3)
{
static EGLint attr_list[] = {
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 0,
EGL_STENCIL_SIZE, 0,
EGL_DEPTH_SIZE, 16,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT | EGL_WINDOW_BIT,
EGL_NONE
};
static EGLint attr_list_es3[] = {
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 0,
EGL_STENCIL_SIZE, 0,
EGL_DEPTH_SIZE, 16,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT | EGL_WINDOW_BIT,
EGL_NONE
};
return supportedES3 ? attr_list_es3 : attr_list;
}
int const kMaxConfigCount = 40;
static EGLint * getConfigAttributesListR5G6B5()
{
// We do not support OpenGL ES3 for R5G6B5, because some Android devices
// are not able to create OpenGL context in such mode.
static EGLint attr_list[] = {
EGL_RED_SIZE, 5,
EGL_GREEN_SIZE, 6,
EGL_BLUE_SIZE, 5,
EGL_STENCIL_SIZE, 0,
EGL_DEPTH_SIZE, 16,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT | EGL_WINDOW_BIT,
EGL_NONE
};
return attr_list;
}
bool IsSupportedRGB8(EGLDisplay display, bool es3)
{
EGLConfig configs[kMaxConfigCount];
int count = 0;
return eglChooseConfig(display, getConfigAttributesListRGB8(es3), configs,
kMaxConfigCount, &count) == EGL_TRUE && count != 0;
}
size_t constexpr kGLThreadsCount = 2;
} // namespace
AndroidOGLContextFactory::AndroidOGLContextFactory(JNIEnv * env, jobject jsurface)
: m_drawContext(NULL)
, m_uploadContext(NULL)
, m_windowSurface(EGL_NO_SURFACE)
, m_pixelbufferSurface(EGL_NO_SURFACE)
, m_config(NULL)
, m_nativeWindow(NULL)
, m_display(EGL_NO_DISPLAY)
, m_surfaceWidth(0)
, m_surfaceHeight(0)
, m_windowSurfaceValid(false)
, m_supportedES3(false)
{
m_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (m_display == EGL_NO_DISPLAY)
{
CHECK_EGL_CALL();
return;
}
EGLint version[2] = {0};
if (!eglInitialize(m_display, &version[0], &version[1]))
{
CHECK_EGL_CALL();
return;
}
// Check ES3 availability.
bool const isES3Supported = IsSupportedRGB8(m_display, true /* es3 */) &&
android_get_device_api_level() >= kMinSdkVersionForES3;
m_supportedES3 = isES3Supported && gl3stubInit();
SetSurface(env, jsurface);
if (!CreatePixelbufferSurface())
{
CHECK_EGL(eglTerminate(m_display));
return;
}
}
AndroidOGLContextFactory::~AndroidOGLContextFactory()
{
if (m_drawContext != nullptr)
{
delete m_drawContext;
m_drawContext = nullptr;
}
if (m_uploadContext != nullptr)
{
delete m_uploadContext;
m_uploadContext = nullptr;
}
ResetSurface();
if (m_pixelbufferSurface != EGL_NO_SURFACE)
{
eglDestroySurface(m_display, m_pixelbufferSurface);
CHECK_EGL_CALL();
m_pixelbufferSurface = EGL_NO_SURFACE;
}
if (m_display != EGL_NO_DISPLAY)
{
eglTerminate(m_display);
CHECK_EGL_CALL();
}
}
void AndroidOGLContextFactory::SetSurface(JNIEnv * env, jobject jsurface)
{
if (!jsurface)
return;
m_nativeWindow = ANativeWindow_fromSurface(env, jsurface);
if (!m_nativeWindow)
{
LOG(LINFO, ("Can't get native window from Java surface"));
return;
}
if (!CreateWindowSurface())
{
CHECK_EGL(eglTerminate(m_display));
return;
}
if (!QuerySurfaceSize())
return;
if (m_drawContext != nullptr)
m_drawContext->SetSurface(m_windowSurface);
m_windowSurfaceValid = true;
}
void AndroidOGLContextFactory::ResetSurface()
{
{
std::unique_lock<std::mutex> lock(m_initializationMutex);
if (m_initializationCounter > 0 && m_initializationCounter < kGLThreadsCount)
m_initializationCondition.wait(lock, [this] { return m_isInitialized; });
m_initializationCounter = 0;
m_isInitialized = false;
}
if (m_drawContext != nullptr)
m_drawContext->ResetSurface();
if (IsValid())
{
eglDestroySurface(m_display, m_windowSurface);
CHECK_EGL_CALL();
m_windowSurface = EGL_NO_SURFACE;
ANativeWindow_release(m_nativeWindow);
m_nativeWindow = NULL;
m_windowSurfaceValid = false;
}
}
bool AndroidOGLContextFactory::IsValid() const
{
return m_windowSurfaceValid && m_pixelbufferSurface != EGL_NO_SURFACE;
}
int AndroidOGLContextFactory::GetWidth() const
{
ASSERT(IsValid(), ());
return m_surfaceWidth;
}
int AndroidOGLContextFactory::GetHeight() const
{
ASSERT(IsValid(), ());
return m_surfaceHeight;
}
void AndroidOGLContextFactory::UpdateSurfaceSize(int w, int h)
{
ASSERT(IsValid(), ());
if ((m_surfaceWidth != w && m_surfaceWidth != h) ||
(m_surfaceHeight != w && m_surfaceHeight != h))
{
LOG(LINFO, ("Surface size changed and must be re-queried."));
if (!QuerySurfaceSize())
{
m_surfaceWidth = w;
m_surfaceHeight = h;
}
}
else
{
m_surfaceWidth = w;
m_surfaceHeight = h;
}
}
bool AndroidOGLContextFactory::QuerySurfaceSize()
{
EGLint queryResult;
if (eglQuerySurface(m_display, m_windowSurface, EGL_WIDTH, &queryResult) == EGL_FALSE)
{
CHECK_EGL_CALL();
return false;
}
m_surfaceWidth = static_cast<int>(queryResult);
if (eglQuerySurface(m_display, m_windowSurface, EGL_HEIGHT, &queryResult) == EGL_FALSE)
{
CHECK_EGL_CALL();
return false;
}
m_surfaceHeight = static_cast<int>(queryResult);
return true;
}
dp::GraphicsContext * AndroidOGLContextFactory::GetDrawContext()
{
ASSERT(IsValid(), ());
ASSERT(m_windowSurface != EGL_NO_SURFACE, ());
if (m_drawContext == nullptr)
{
m_drawContext = new AndroidOGLContext(m_supportedES3, m_display, m_windowSurface,
m_config, m_uploadContext);
}
return m_drawContext;
}
dp::GraphicsContext * AndroidOGLContextFactory::GetResourcesUploadContext()
{
ASSERT(IsValid(), ());
ASSERT(m_pixelbufferSurface != EGL_NO_SURFACE, ());
if (m_uploadContext == nullptr)
{
m_uploadContext = new AndroidOGLContext(m_supportedES3, m_display, m_pixelbufferSurface,
m_config, m_drawContext);
}
return m_uploadContext;
}
bool AndroidOGLContextFactory::IsDrawContextCreated() const
{
return m_drawContext != nullptr;
}
bool AndroidOGLContextFactory::IsUploadContextCreated() const
{
return m_uploadContext != nullptr;
}
void AndroidOGLContextFactory::WaitForInitialization(dp::GraphicsContext *)
{
std::unique_lock<std::mutex> lock(m_initializationMutex);
if (m_isInitialized)
return;
m_initializationCounter++;
if (m_initializationCounter >= kGLThreadsCount)
{
m_isInitialized = true;
m_initializationCondition.notify_all();
}
else
{
m_initializationCondition.wait(lock, [this] { return m_isInitialized; });
}
}
void AndroidOGLContextFactory::SetPresentAvailable(bool available)
{
if (m_drawContext != nullptr)
m_drawContext->SetPresentAvailable(available);
}
bool AndroidOGLContextFactory::CreateWindowSurface()
{
EGLConfig configs[kMaxConfigCount];
int count = 0;
if (eglChooseConfig(m_display, getConfigAttributesListRGB8(m_supportedES3), configs,
kMaxConfigCount, &count) != EGL_TRUE)
{
ASSERT(!m_supportedES3, ());
VERIFY(eglChooseConfig(m_display, getConfigAttributesListR5G6B5(), configs,
kMaxConfigCount, &count) == EGL_TRUE, ());
LOG(LDEBUG, ("Backbuffer format: R5G6B5"));
}
else
{
LOG(LDEBUG, ("Backbuffer format: RGB8"));
}
ASSERT(count > 0, ("Didn't find any configs."));
std::sort(&configs[0], &configs[count], ConfigComparator(m_display));
for (int i = 0; i < count; ++i)
{
EGLConfig currentConfig = configs[i];
EGLint format;
eglGetConfigAttrib(m_display, currentConfig, EGL_NATIVE_VISUAL_ID, &format);
ANativeWindow_setBuffersGeometry(m_nativeWindow, 0, 0, format);
EGLint surfaceAttributes[] = { EGL_RENDER_BUFFER, EGL_BACK_BUFFER, EGL_NONE };
m_windowSurface = eglCreateWindowSurface(m_display, currentConfig, m_nativeWindow, surfaceAttributes);
if (m_windowSurface == EGL_NO_SURFACE)
continue;
else
m_config = currentConfig;
break;
}
if (m_windowSurface == EGL_NO_SURFACE)
{
CHECK_EGL_CALL();
return false;
}
return true;
}
bool AndroidOGLContextFactory::CreatePixelbufferSurface()
{
//ASSERT(m_config != NULL, ());
const GLuint size = 1; // yes, 1 is the correct size, we dont really draw on it
static EGLint surfaceConfig[] = {
EGL_WIDTH, size,
EGL_HEIGHT, size,
EGL_NONE
};
m_pixelbufferSurface = eglCreatePbufferSurface(m_display, m_config, surfaceConfig);
if (m_pixelbufferSurface == EGL_NO_SURFACE)
{
CHECK_EGL_CALL();
return false;
}
return true;
}
} // namespace android

View File

@@ -0,0 +1,66 @@
#pragma once
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "androidoglcontext.hpp"
#include "drape/graphics_context_factory.hpp"
#include "base/src_point.hpp"
#include <condition_variable>
#include <mutex>
namespace android
{
class AndroidOGLContextFactory : public dp::GraphicsContextFactory
{
public:
AndroidOGLContextFactory(JNIEnv * env, jobject jsurface);
~AndroidOGLContextFactory();
bool IsValid() const;
dp::GraphicsContext * GetDrawContext() override;
dp::GraphicsContext * GetResourcesUploadContext() override;
bool IsDrawContextCreated() const override;
bool IsUploadContextCreated() const override;
void WaitForInitialization(dp::GraphicsContext * context) override;
void SetPresentAvailable(bool available) override;
void SetSurface(JNIEnv * env, jobject jsurface);
void ResetSurface();
int GetWidth() const;
int GetHeight() const;
void UpdateSurfaceSize(int w, int h);
bool IsSupportedOpenGLES3() const { return m_supportedES3; }
private:
bool QuerySurfaceSize();
private:
bool CreateWindowSurface();
bool CreatePixelbufferSurface();
AndroidOGLContext * m_drawContext;
AndroidOGLContext * m_uploadContext;
EGLSurface m_windowSurface;
EGLSurface m_pixelbufferSurface;
EGLConfig m_config;
ANativeWindow * m_nativeWindow;
EGLDisplay m_display;
int m_surfaceWidth;
int m_surfaceHeight;
bool m_windowSurfaceValid;
bool m_supportedES3;
bool m_isInitialized = false;
size_t m_initializationCounter = 0;
std::condition_variable m_initializationCondition;
std::mutex m_initializationMutex;
};
} // namespace android

View File

@@ -0,0 +1,342 @@
/*
* Copyright 2013 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 "gl3stub.h"
GLboolean gl3stubInit() {
#define FIND_PROC(s) s = reinterpret_cast<decltype(s)>(eglGetProcAddress(#s))
FIND_PROC(glReadBuffer);
FIND_PROC(glDrawRangeElements);
FIND_PROC(glTexImage3D);
FIND_PROC(glTexSubImage3D);
FIND_PROC(glCopyTexSubImage3D);
FIND_PROC(glCompressedTexImage3D);
FIND_PROC(glCompressedTexSubImage3D);
FIND_PROC(glGenQueries);
FIND_PROC(glDeleteQueries);
FIND_PROC(glIsQuery);
FIND_PROC(glBeginQuery);
FIND_PROC(glEndQuery);
FIND_PROC(glGetQueryiv);
FIND_PROC(glGetQueryObjectuiv);
FIND_PROC(glUnmapBuffer);
FIND_PROC(glGetBufferPointerv);
FIND_PROC(glDrawBuffers);
FIND_PROC(glUniformMatrix2x3fv);
FIND_PROC(glUniformMatrix3x2fv);
FIND_PROC(glUniformMatrix2x4fv);
FIND_PROC(glUniformMatrix4x2fv);
FIND_PROC(glUniformMatrix3x4fv);
FIND_PROC(glUniformMatrix4x3fv);
FIND_PROC(glBlitFramebuffer);
FIND_PROC(glRenderbufferStorageMultisample);
FIND_PROC(glFramebufferTextureLayer);
FIND_PROC(glMapBufferRange);
FIND_PROC(glFlushMappedBufferRange);
FIND_PROC(glBindVertexArray);
FIND_PROC(glDeleteVertexArrays);
FIND_PROC(glGenVertexArrays);
FIND_PROC(glIsVertexArray);
FIND_PROC(glGetIntegeri_v);
FIND_PROC(glBeginTransformFeedback);
FIND_PROC(glEndTransformFeedback);
FIND_PROC(glBindBufferRange);
FIND_PROC(glBindBufferBase);
FIND_PROC(glTransformFeedbackVaryings);
FIND_PROC(glGetTransformFeedbackVarying);
FIND_PROC(glVertexAttribIPointer);
FIND_PROC(glGetVertexAttribIiv);
FIND_PROC(glGetVertexAttribIuiv);
FIND_PROC(glVertexAttribI4i);
FIND_PROC(glVertexAttribI4ui);
FIND_PROC(glVertexAttribI4iv);
FIND_PROC(glVertexAttribI4uiv);
FIND_PROC(glGetUniformuiv);
FIND_PROC(glGetFragDataLocation);
FIND_PROC(glUniform1ui);
FIND_PROC(glUniform2ui);
FIND_PROC(glUniform3ui);
FIND_PROC(glUniform4ui);
FIND_PROC(glUniform1uiv);
FIND_PROC(glUniform2uiv);
FIND_PROC(glUniform3uiv);
FIND_PROC(glUniform4uiv);
FIND_PROC(glClearBufferiv);
FIND_PROC(glClearBufferuiv);
FIND_PROC(glClearBufferfv);
FIND_PROC(glClearBufferfi);
FIND_PROC(glGetStringi);
FIND_PROC(glCopyBufferSubData);
FIND_PROC(glGetUniformIndices);
FIND_PROC(glGetActiveUniformsiv);
FIND_PROC(glGetUniformBlockIndex);
FIND_PROC(glGetActiveUniformBlockiv);
FIND_PROC(glGetActiveUniformBlockName);
FIND_PROC(glUniformBlockBinding);
FIND_PROC(glDrawArraysInstanced);
FIND_PROC(glDrawElementsInstanced);
FIND_PROC(glFenceSync);
FIND_PROC(glIsSync);
FIND_PROC(glDeleteSync);
FIND_PROC(glClientWaitSync);
FIND_PROC(glWaitSync);
FIND_PROC(glGetInteger64v);
FIND_PROC(glGetSynciv);
FIND_PROC(glGetInteger64i_v);
FIND_PROC(glGetBufferParameteri64v);
FIND_PROC(glGenSamplers);
FIND_PROC(glDeleteSamplers);
FIND_PROC(glIsSampler);
FIND_PROC(glBindSampler);
FIND_PROC(glSamplerParameteri);
FIND_PROC(glSamplerParameteriv);
FIND_PROC(glSamplerParameterf);
FIND_PROC(glSamplerParameterfv);
FIND_PROC(glGetSamplerParameteriv);
FIND_PROC(glGetSamplerParameterfv);
FIND_PROC(glVertexAttribDivisor);
FIND_PROC(glBindTransformFeedback);
FIND_PROC(glDeleteTransformFeedbacks);
FIND_PROC(glGenTransformFeedbacks);
FIND_PROC(glIsTransformFeedback);
FIND_PROC(glPauseTransformFeedback);
FIND_PROC(glResumeTransformFeedback);
FIND_PROC(glGetProgramBinary);
FIND_PROC(glProgramBinary);
FIND_PROC(glProgramParameteri);
FIND_PROC(glInvalidateFramebuffer);
FIND_PROC(glInvalidateSubFramebuffer);
FIND_PROC(glTexStorage2D);
FIND_PROC(glTexStorage3D);
FIND_PROC(glGetInternalformativ);
#undef FIND_PROC
if (!glReadBuffer ||
!glDrawRangeElements ||
!glTexImage3D ||
!glTexSubImage3D ||
!glCopyTexSubImage3D ||
!glCompressedTexImage3D ||
!glCompressedTexSubImage3D ||
!glGenQueries ||
!glDeleteQueries ||
!glIsQuery ||
!glBeginQuery ||
!glEndQuery ||
!glGetQueryiv ||
!glGetQueryObjectuiv ||
!glUnmapBuffer ||
!glGetBufferPointerv ||
!glDrawBuffers ||
!glUniformMatrix2x3fv ||
!glUniformMatrix3x2fv ||
!glUniformMatrix2x4fv ||
!glUniformMatrix4x2fv ||
!glUniformMatrix3x4fv ||
!glUniformMatrix4x3fv ||
!glBlitFramebuffer ||
!glRenderbufferStorageMultisample ||
!glFramebufferTextureLayer ||
!glMapBufferRange ||
!glFlushMappedBufferRange ||
!glBindVertexArray ||
!glDeleteVertexArrays ||
!glGenVertexArrays ||
!glIsVertexArray ||
!glGetIntegeri_v ||
!glBeginTransformFeedback ||
!glEndTransformFeedback ||
!glBindBufferRange ||
!glBindBufferBase ||
!glTransformFeedbackVaryings ||
!glGetTransformFeedbackVarying ||
!glVertexAttribIPointer ||
!glGetVertexAttribIiv ||
!glGetVertexAttribIuiv ||
!glVertexAttribI4i ||
!glVertexAttribI4ui ||
!glVertexAttribI4iv ||
!glVertexAttribI4uiv ||
!glGetUniformuiv ||
!glGetFragDataLocation ||
!glUniform1ui ||
!glUniform2ui ||
!glUniform3ui ||
!glUniform4ui ||
!glUniform1uiv ||
!glUniform2uiv ||
!glUniform3uiv ||
!glUniform4uiv ||
!glClearBufferiv ||
!glClearBufferuiv ||
!glClearBufferfv ||
!glClearBufferfi ||
!glGetStringi ||
!glCopyBufferSubData ||
!glGetUniformIndices ||
!glGetActiveUniformsiv ||
!glGetUniformBlockIndex ||
!glGetActiveUniformBlockiv ||
!glGetActiveUniformBlockName ||
!glUniformBlockBinding ||
!glDrawArraysInstanced ||
!glDrawElementsInstanced ||
!glFenceSync ||
!glIsSync ||
!glDeleteSync ||
!glClientWaitSync ||
!glWaitSync ||
!glGetInteger64v ||
!glGetSynciv ||
!glGetInteger64i_v ||
!glGetBufferParameteri64v ||
!glGenSamplers ||
!glDeleteSamplers ||
!glIsSampler ||
!glBindSampler ||
!glSamplerParameteri ||
!glSamplerParameteriv ||
!glSamplerParameterf ||
!glSamplerParameterfv ||
!glGetSamplerParameteriv ||
!glGetSamplerParameterfv ||
!glVertexAttribDivisor ||
!glBindTransformFeedback ||
!glDeleteTransformFeedbacks ||
!glGenTransformFeedbacks ||
!glIsTransformFeedback ||
!glPauseTransformFeedback ||
!glResumeTransformFeedback ||
!glGetProgramBinary ||
!glProgramBinary ||
!glProgramParameteri ||
!glInvalidateFramebuffer ||
!glInvalidateSubFramebuffer ||
!glTexStorage2D ||
!glTexStorage3D ||
!glGetInternalformativ)
{
return GL_FALSE;
}
return GL_TRUE;
}
/* Function pointer definitions */
GL_APICALL void (* GL_APIENTRY glReadBuffer) (GLenum mode);
GL_APICALL void (* GL_APIENTRY glDrawRangeElements) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices);
GL_APICALL void (* GL_APIENTRY glTexImage3D) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
GL_APICALL void (* GL_APIENTRY glTexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels);
GL_APICALL void (* GL_APIENTRY glCopyTexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
GL_APICALL void (* GL_APIENTRY glCompressedTexImage3D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data);
GL_APICALL void (* GL_APIENTRY glCompressedTexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data);
GL_APICALL void (* GL_APIENTRY glGenQueries) (GLsizei n, GLuint* ids);
GL_APICALL void (* GL_APIENTRY glDeleteQueries) (GLsizei n, const GLuint* ids);
GL_APICALL GLboolean (* GL_APIENTRY glIsQuery) (GLuint id);
GL_APICALL void (* GL_APIENTRY glBeginQuery) (GLenum target, GLuint id);
GL_APICALL void (* GL_APIENTRY glEndQuery) (GLenum target);
GL_APICALL void (* GL_APIENTRY glGetQueryiv) (GLenum target, GLenum pname, GLint* params);
GL_APICALL void (* GL_APIENTRY glGetQueryObjectuiv) (GLuint id, GLenum pname, GLuint* params);
GL_APICALL GLboolean (* GL_APIENTRY glUnmapBuffer) (GLenum target);
GL_APICALL void (* GL_APIENTRY glGetBufferPointerv) (GLenum target, GLenum pname, GLvoid** params);
GL_APICALL void (* GL_APIENTRY glDrawBuffers) (GLsizei n, const GLenum* bufs);
GL_APICALL void (* GL_APIENTRY glUniformMatrix2x3fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
GL_APICALL void (* GL_APIENTRY glUniformMatrix3x2fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
GL_APICALL void (* GL_APIENTRY glUniformMatrix2x4fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
GL_APICALL void (* GL_APIENTRY glUniformMatrix4x2fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
GL_APICALL void (* GL_APIENTRY glUniformMatrix3x4fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
GL_APICALL void (* GL_APIENTRY glUniformMatrix4x3fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
GL_APICALL void (* GL_APIENTRY glBlitFramebuffer) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
GL_APICALL void (* GL_APIENTRY glRenderbufferStorageMultisample) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
GL_APICALL void (* GL_APIENTRY glFramebufferTextureLayer) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
GL_APICALL GLvoid* (* GL_APIENTRY glMapBufferRange) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
GL_APICALL void (* GL_APIENTRY glFlushMappedBufferRange) (GLenum target, GLintptr offset, GLsizeiptr length);
GL_APICALL void (* GL_APIENTRY glBindVertexArray) (GLuint array);
GL_APICALL void (* GL_APIENTRY glDeleteVertexArrays) (GLsizei n, const GLuint* arrays);
GL_APICALL void (* GL_APIENTRY glGenVertexArrays) (GLsizei n, GLuint* arrays);
GL_APICALL GLboolean (* GL_APIENTRY glIsVertexArray) (GLuint array);
GL_APICALL void (* GL_APIENTRY glGetIntegeri_v) (GLenum target, GLuint index, GLint* data);
GL_APICALL void (* GL_APIENTRY glBeginTransformFeedback) (GLenum primitiveMode);
GL_APICALL void (* GL_APIENTRY glEndTransformFeedback) (void);
GL_APICALL void (* GL_APIENTRY glBindBufferRange) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
GL_APICALL void (* GL_APIENTRY glBindBufferBase) (GLenum target, GLuint index, GLuint buffer);
GL_APICALL void (* GL_APIENTRY glTransformFeedbackVaryings) (GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode);
GL_APICALL void (* GL_APIENTRY glGetTransformFeedbackVarying) (GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name);
GL_APICALL void (* GL_APIENTRY glVertexAttribIPointer) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer);
GL_APICALL void (* GL_APIENTRY glGetVertexAttribIiv) (GLuint index, GLenum pname, GLint* params);
GL_APICALL void (* GL_APIENTRY glGetVertexAttribIuiv) (GLuint index, GLenum pname, GLuint* params);
GL_APICALL void (* GL_APIENTRY glVertexAttribI4i) (GLuint index, GLint x, GLint y, GLint z, GLint w);
GL_APICALL void (* GL_APIENTRY glVertexAttribI4ui) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
GL_APICALL void (* GL_APIENTRY glVertexAttribI4iv) (GLuint index, const GLint* v);
GL_APICALL void (* GL_APIENTRY glVertexAttribI4uiv) (GLuint index, const GLuint* v);
GL_APICALL void (* GL_APIENTRY glGetUniformuiv) (GLuint program, GLint location, GLuint* params);
GL_APICALL GLint (* GL_APIENTRY glGetFragDataLocation) (GLuint program, const GLchar *name);
GL_APICALL void (* GL_APIENTRY glUniform1ui) (GLint location, GLuint v0);
GL_APICALL void (* GL_APIENTRY glUniform2ui) (GLint location, GLuint v0, GLuint v1);
GL_APICALL void (* GL_APIENTRY glUniform3ui) (GLint location, GLuint v0, GLuint v1, GLuint v2);
GL_APICALL void (* GL_APIENTRY glUniform4ui) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
GL_APICALL void (* GL_APIENTRY glUniform1uiv) (GLint location, GLsizei count, const GLuint* value);
GL_APICALL void (* GL_APIENTRY glUniform2uiv) (GLint location, GLsizei count, const GLuint* value);
GL_APICALL void (* GL_APIENTRY glUniform3uiv) (GLint location, GLsizei count, const GLuint* value);
GL_APICALL void (* GL_APIENTRY glUniform4uiv) (GLint location, GLsizei count, const GLuint* value);
GL_APICALL void (* GL_APIENTRY glClearBufferiv) (GLenum buffer, GLint drawbuffer, const GLint* value);
GL_APICALL void (* GL_APIENTRY glClearBufferuiv) (GLenum buffer, GLint drawbuffer, const GLuint* value);
GL_APICALL void (* GL_APIENTRY glClearBufferfv) (GLenum buffer, GLint drawbuffer, const GLfloat* value);
GL_APICALL void (* GL_APIENTRY glClearBufferfi) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
GL_APICALL const GLubyte* (* GL_APIENTRY glGetStringi) (GLenum name, GLuint index);
GL_APICALL void (* GL_APIENTRY glCopyBufferSubData) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
GL_APICALL void (* GL_APIENTRY glGetUniformIndices) (GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices);
GL_APICALL void (* GL_APIENTRY glGetActiveUniformsiv) (GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params);
GL_APICALL GLuint (* GL_APIENTRY glGetUniformBlockIndex) (GLuint program, const GLchar* uniformBlockName);
GL_APICALL void (* GL_APIENTRY glGetActiveUniformBlockiv) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params);
GL_APICALL void (* GL_APIENTRY glGetActiveUniformBlockName) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName);
GL_APICALL void (* GL_APIENTRY glUniformBlockBinding) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
GL_APICALL void (* GL_APIENTRY glDrawArraysInstanced) (GLenum mode, GLint first, GLsizei count, GLsizei instanceCount);
GL_APICALL void (* GL_APIENTRY glDrawElementsInstanced) (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instanceCount);
GL_APICALL GLsync (* GL_APIENTRY glFenceSync) (GLenum condition, GLbitfield flags);
GL_APICALL GLboolean (* GL_APIENTRY glIsSync) (GLsync sync);
GL_APICALL void (* GL_APIENTRY glDeleteSync) (GLsync sync);
GL_APICALL GLenum (* GL_APIENTRY glClientWaitSync) (GLsync sync, GLbitfield flags, GLuint64 timeout);
GL_APICALL void (* GL_APIENTRY glWaitSync) (GLsync sync, GLbitfield flags, GLuint64 timeout);
GL_APICALL void (* GL_APIENTRY glGetInteger64v) (GLenum pname, GLint64* params);
GL_APICALL void (* GL_APIENTRY glGetSynciv) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values);
GL_APICALL void (* GL_APIENTRY glGetInteger64i_v) (GLenum target, GLuint index, GLint64* data);
GL_APICALL void (* GL_APIENTRY glGetBufferParameteri64v) (GLenum target, GLenum pname, GLint64* params);
GL_APICALL void (* GL_APIENTRY glGenSamplers) (GLsizei count, GLuint* samplers);
GL_APICALL void (* GL_APIENTRY glDeleteSamplers) (GLsizei count, const GLuint* samplers);
GL_APICALL GLboolean (* GL_APIENTRY glIsSampler) (GLuint sampler);
GL_APICALL void (* GL_APIENTRY glBindSampler) (GLuint unit, GLuint sampler);
GL_APICALL void (* GL_APIENTRY glSamplerParameteri) (GLuint sampler, GLenum pname, GLint param);
GL_APICALL void (* GL_APIENTRY glSamplerParameteriv) (GLuint sampler, GLenum pname, const GLint* param);
GL_APICALL void (* GL_APIENTRY glSamplerParameterf) (GLuint sampler, GLenum pname, GLfloat param);
GL_APICALL void (* GL_APIENTRY glSamplerParameterfv) (GLuint sampler, GLenum pname, const GLfloat* param);
GL_APICALL void (* GL_APIENTRY glGetSamplerParameteriv) (GLuint sampler, GLenum pname, GLint* params);
GL_APICALL void (* GL_APIENTRY glGetSamplerParameterfv) (GLuint sampler, GLenum pname, GLfloat* params);
GL_APICALL void (* GL_APIENTRY glVertexAttribDivisor) (GLuint index, GLuint divisor);
GL_APICALL void (* GL_APIENTRY glBindTransformFeedback) (GLenum target, GLuint id);
GL_APICALL void (* GL_APIENTRY glDeleteTransformFeedbacks) (GLsizei n, const GLuint* ids);
GL_APICALL void (* GL_APIENTRY glGenTransformFeedbacks) (GLsizei n, GLuint* ids);
GL_APICALL GLboolean (* GL_APIENTRY glIsTransformFeedback) (GLuint id);
GL_APICALL void (* GL_APIENTRY glPauseTransformFeedback) (void);
GL_APICALL void (* GL_APIENTRY glResumeTransformFeedback) (void);
GL_APICALL void (* GL_APIENTRY glGetProgramBinary) (GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary);
GL_APICALL void (* GL_APIENTRY glProgramBinary) (GLuint program, GLenum binaryFormat, const GLvoid* binary, GLsizei length);
GL_APICALL void (* GL_APIENTRY glProgramParameteri) (GLuint program, GLenum pname, GLint value);
GL_APICALL void (* GL_APIENTRY glInvalidateFramebuffer) (GLenum target, GLsizei numAttachments, const GLenum* attachments);
GL_APICALL void (* GL_APIENTRY glInvalidateSubFramebuffer) (GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height);
GL_APICALL void (* GL_APIENTRY glTexStorage2D) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
GL_APICALL void (* GL_APIENTRY glTexStorage3D) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
GL_APICALL void (* GL_APIENTRY glGetInternalformativ) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params);

View File

@@ -0,0 +1,492 @@
#ifndef __gl3_h_
#define __gl3_h_
/*
* stub gl3.h for dynamic loading, based on:
* gl3.h last updated on $Date: 2013-02-12 14:37:24 -0800 (Tue, 12 Feb 2013) $
*
* Changes:
* - Added #include <GLES2/gl2.h>
* - Removed duplicate OpenGL ES 2.0 declarations
* - Converted OpenGL ES 3.0 function prototypes to function pointer
* declarations
* - Added gl3stubInit() declaration
*/
#include <EGL/egl.h>
#include <GLES2/gl2.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
** Copyright (c) 2007-2013 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be included
** in all copies or substantial portions of the Materials.
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
/* Call this function before calling any OpenGL ES 3.0 functions. It will
* return GL_TRUE if the OpenGL ES 3.0 was successfully initialized, GL_FALSE
* otherwise. */
GLboolean gl3stubInit();
/*-------------------------------------------------------------------------
* Data type definitions
*-----------------------------------------------------------------------*/
/* OpenGL ES 3.0 */
typedef unsigned short GLhalf;
typedef khronos_int64_t GLint64;
typedef khronos_uint64_t GLuint64;
typedef struct __GLsync *GLsync;
/*-------------------------------------------------------------------------
* Token definitions
*-----------------------------------------------------------------------*/
/* OpenGL ES core versions */
#define GL_ES_VERSION_3_0 1
/* OpenGL ES 3.0 */
#define GL_READ_BUFFER 0x0C02
#define GL_UNPACK_ROW_LENGTH 0x0CF2
#define GL_UNPACK_SKIP_ROWS 0x0CF3
#define GL_UNPACK_SKIP_PIXELS 0x0CF4
#define GL_PACK_ROW_LENGTH 0x0D02
#define GL_PACK_SKIP_ROWS 0x0D03
#define GL_PACK_SKIP_PIXELS 0x0D04
#define GL_COLOR 0x1800
#define GL_DEPTH 0x1801
#define GL_STENCIL 0x1802
#define GL_RED 0x1903
#define GL_RGB8 0x8051
#define GL_RGBA8 0x8058
#define GL_RGB10_A2 0x8059
#define GL_TEXTURE_BINDING_3D 0x806A
#define GL_UNPACK_SKIP_IMAGES 0x806D
#define GL_UNPACK_IMAGE_HEIGHT 0x806E
#define GL_TEXTURE_3D 0x806F
#define GL_TEXTURE_WRAP_R 0x8072
#define GL_MAX_3D_TEXTURE_SIZE 0x8073
#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
#define GL_MAX_ELEMENTS_VERTICES 0x80E8
#define GL_MAX_ELEMENTS_INDICES 0x80E9
#define GL_TEXTURE_MIN_LOD 0x813A
#define GL_TEXTURE_MAX_LOD 0x813B
#define GL_TEXTURE_BASE_LEVEL 0x813C
#define GL_TEXTURE_MAX_LEVEL 0x813D
#define GL_MIN 0x8007
#define GL_MAX 0x8008
#define GL_DEPTH_COMPONENT24 0x81A6
#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD
#define GL_TEXTURE_COMPARE_MODE 0x884C
#define GL_TEXTURE_COMPARE_FUNC 0x884D
#define GL_CURRENT_QUERY 0x8865
#define GL_QUERY_RESULT 0x8866
#define GL_QUERY_RESULT_AVAILABLE 0x8867
#define GL_BUFFER_MAPPED 0x88BC
#define GL_BUFFER_MAP_POINTER 0x88BD
#define GL_STREAM_READ 0x88E1
#define GL_STREAM_COPY 0x88E2
#define GL_STATIC_READ 0x88E5
#define GL_STATIC_COPY 0x88E6
#define GL_DYNAMIC_READ 0x88E9
#define GL_DYNAMIC_COPY 0x88EA
#define GL_MAX_DRAW_BUFFERS 0x8824
#define GL_DRAW_BUFFER0 0x8825
#define GL_DRAW_BUFFER1 0x8826
#define GL_DRAW_BUFFER2 0x8827
#define GL_DRAW_BUFFER3 0x8828
#define GL_DRAW_BUFFER4 0x8829
#define GL_DRAW_BUFFER5 0x882A
#define GL_DRAW_BUFFER6 0x882B
#define GL_DRAW_BUFFER7 0x882C
#define GL_DRAW_BUFFER8 0x882D
#define GL_DRAW_BUFFER9 0x882E
#define GL_DRAW_BUFFER10 0x882F
#define GL_DRAW_BUFFER11 0x8830
#define GL_DRAW_BUFFER12 0x8831
#define GL_DRAW_BUFFER13 0x8832
#define GL_DRAW_BUFFER14 0x8833
#define GL_DRAW_BUFFER15 0x8834
#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49
#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A
#define GL_SAMPLER_3D 0x8B5F
#define GL_SAMPLER_2D_SHADOW 0x8B62
#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B
#define GL_PIXEL_PACK_BUFFER 0x88EB
#define GL_PIXEL_UNPACK_BUFFER 0x88EC
#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED
#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF
#define GL_FLOAT_MAT2x3 0x8B65
#define GL_FLOAT_MAT2x4 0x8B66
#define GL_FLOAT_MAT3x2 0x8B67
#define GL_FLOAT_MAT3x4 0x8B68
#define GL_FLOAT_MAT4x2 0x8B69
#define GL_FLOAT_MAT4x3 0x8B6A
#define GL_SRGB 0x8C40
#define GL_SRGB8 0x8C41
#define GL_SRGB8_ALPHA8 0x8C43
#define GL_COMPARE_REF_TO_TEXTURE 0x884E
#define GL_MAJOR_VERSION 0x821B
#define GL_MINOR_VERSION 0x821C
#define GL_NUM_EXTENSIONS 0x821D
#define GL_RGBA32F 0x8814
#define GL_RGB32F 0x8815
#define GL_RGBA16F 0x881A
#define GL_RGB16F 0x881B
#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD
#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF
#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904
#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905
#define GL_MAX_VARYING_COMPONENTS 0x8B4B
#define GL_TEXTURE_2D_ARRAY 0x8C1A
#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D
#define GL_R11F_G11F_B10F 0x8C3A
#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B
#define GL_RGB9_E5 0x8C3D
#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E
#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76
#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F
#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80
#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83
#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84
#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85
#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88
#define GL_RASTERIZER_DISCARD 0x8C89
#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A
#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B
#define GL_INTERLEAVED_ATTRIBS 0x8C8C
#define GL_SEPARATE_ATTRIBS 0x8C8D
#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E
#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F
#define GL_RGBA32UI 0x8D70
#define GL_RGB32UI 0x8D71
#define GL_RGBA16UI 0x8D76
#define GL_RGB16UI 0x8D77
#define GL_RGBA8UI 0x8D7C
#define GL_RGB8UI 0x8D7D
#define GL_RGBA32I 0x8D82
#define GL_RGB32I 0x8D83
#define GL_RGBA16I 0x8D88
#define GL_RGB16I 0x8D89
#define GL_RGBA8I 0x8D8E
#define GL_RGB8I 0x8D8F
#define GL_RED_INTEGER 0x8D94
#define GL_RGB_INTEGER 0x8D98
#define GL_RGBA_INTEGER 0x8D99
#define GL_SAMPLER_2D_ARRAY 0x8DC1
#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4
#define GL_SAMPLER_CUBE_SHADOW 0x8DC5
#define GL_UNSIGNED_INT_VEC2 0x8DC6
#define GL_UNSIGNED_INT_VEC3 0x8DC7
#define GL_UNSIGNED_INT_VEC4 0x8DC8
#define GL_INT_SAMPLER_2D 0x8DCA
#define GL_INT_SAMPLER_3D 0x8DCB
#define GL_INT_SAMPLER_CUBE 0x8DCC
#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF
#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2
#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3
#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4
#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7
#define GL_BUFFER_ACCESS_FLAGS 0x911F
#define GL_BUFFER_MAP_LENGTH 0x9120
#define GL_BUFFER_MAP_OFFSET 0x9121
#define GL_DEPTH_COMPONENT32F 0x8CAC
#define GL_DEPTH32F_STENCIL8 0x8CAD
#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD
#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210
#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211
#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212
#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213
#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214
#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215
#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216
#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217
#define GL_FRAMEBUFFER_DEFAULT 0x8218
#define GL_FRAMEBUFFER_UNDEFINED 0x8219
#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
#define GL_DEPTH_STENCIL 0x84F9
#define GL_UNSIGNED_INT_24_8 0x84FA
#define GL_DEPTH24_STENCIL8 0x88F0
#define GL_UNSIGNED_NORMALIZED 0x8C17
#define GL_DRAW_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING
#define GL_READ_FRAMEBUFFER 0x8CA8
#define GL_DRAW_FRAMEBUFFER 0x8CA9
#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA
#define GL_RENDERBUFFER_SAMPLES 0x8CAB
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4
#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF
#define GL_COLOR_ATTACHMENT1 0x8CE1
#define GL_COLOR_ATTACHMENT2 0x8CE2
#define GL_COLOR_ATTACHMENT3 0x8CE3
#define GL_COLOR_ATTACHMENT4 0x8CE4
#define GL_COLOR_ATTACHMENT5 0x8CE5
#define GL_COLOR_ATTACHMENT6 0x8CE6
#define GL_COLOR_ATTACHMENT7 0x8CE7
#define GL_COLOR_ATTACHMENT8 0x8CE8
#define GL_COLOR_ATTACHMENT9 0x8CE9
#define GL_COLOR_ATTACHMENT10 0x8CEA
#define GL_COLOR_ATTACHMENT11 0x8CEB
#define GL_COLOR_ATTACHMENT12 0x8CEC
#define GL_COLOR_ATTACHMENT13 0x8CED
#define GL_COLOR_ATTACHMENT14 0x8CEE
#define GL_COLOR_ATTACHMENT15 0x8CEF
#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56
#define GL_MAX_SAMPLES 0x8D57
#define GL_HALF_FLOAT 0x140B
#define GL_MAP_READ_BIT 0x0001
#define GL_MAP_WRITE_BIT 0x0002
#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004
#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008
#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010
#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020
#define GL_RG 0x8227
#define GL_RG_INTEGER 0x8228
#define GL_R8 0x8229
#define GL_RG8 0x822B
#define GL_R16F 0x822D
#define GL_R32F 0x822E
#define GL_RG16F 0x822F
#define GL_RG32F 0x8230
#define GL_R8I 0x8231
#define GL_R8UI 0x8232
#define GL_R16I 0x8233
#define GL_R16UI 0x8234
#define GL_R32I 0x8235
#define GL_R32UI 0x8236
#define GL_RG8I 0x8237
#define GL_RG8UI 0x8238
#define GL_RG16I 0x8239
#define GL_RG16UI 0x823A
#define GL_RG32I 0x823B
#define GL_RG32UI 0x823C
#define GL_VERTEX_ARRAY_BINDING 0x85B5
#define GL_R8_SNORM 0x8F94
#define GL_RG8_SNORM 0x8F95
#define GL_RGB8_SNORM 0x8F96
#define GL_RGBA8_SNORM 0x8F97
#define GL_SIGNED_NORMALIZED 0x8F9C
#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69
#define GL_COPY_READ_BUFFER 0x8F36
#define GL_COPY_WRITE_BUFFER 0x8F37
#define GL_COPY_READ_BUFFER_BINDING GL_COPY_READ_BUFFER
#define GL_COPY_WRITE_BUFFER_BINDING GL_COPY_WRITE_BUFFER
#define GL_UNIFORM_BUFFER 0x8A11
#define GL_UNIFORM_BUFFER_BINDING 0x8A28
#define GL_UNIFORM_BUFFER_START 0x8A29
#define GL_UNIFORM_BUFFER_SIZE 0x8A2A
#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B
#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D
#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E
#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F
#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30
#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31
#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33
#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34
#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35
#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36
#define GL_UNIFORM_TYPE 0x8A37
#define GL_UNIFORM_SIZE 0x8A38
#define GL_UNIFORM_NAME_LENGTH 0x8A39
#define GL_UNIFORM_BLOCK_INDEX 0x8A3A
#define GL_UNIFORM_OFFSET 0x8A3B
#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C
#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D
#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E
#define GL_UNIFORM_BLOCK_BINDING 0x8A3F
#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40
#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41
#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42
#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43
#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44
#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46
#define GL_INVALID_INDEX 0xFFFFFFFFu
#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122
#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125
#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111
#define GL_OBJECT_TYPE 0x9112
#define GL_SYNC_CONDITION 0x9113
#define GL_SYNC_STATUS 0x9114
#define GL_SYNC_FLAGS 0x9115
#define GL_SYNC_FENCE 0x9116
#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117
#define GL_UNSIGNALED 0x9118
#define GL_SIGNALED 0x9119
#define GL_ALREADY_SIGNALED 0x911A
#define GL_TIMEOUT_EXPIRED 0x911B
#define GL_CONDITION_SATISFIED 0x911C
#define GL_WAIT_FAILED 0x911D
#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001
#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull
#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE
#define GL_ANY_SAMPLES_PASSED 0x8C2F
#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A
#define GL_SAMPLER_BINDING 0x8919
#define GL_RGB10_A2UI 0x906F
#define GL_TEXTURE_SWIZZLE_R 0x8E42
#define GL_TEXTURE_SWIZZLE_G 0x8E43
#define GL_TEXTURE_SWIZZLE_B 0x8E44
#define GL_TEXTURE_SWIZZLE_A 0x8E45
#define GL_GREEN 0x1904
#define GL_BLUE 0x1905
#define GL_INT_2_10_10_10_REV 0x8D9F
#define GL_TRANSFORM_FEEDBACK 0x8E22
#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23
#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24
#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25
#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257
#define GL_PROGRAM_BINARY_LENGTH 0x8741
#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
#define GL_PROGRAM_BINARY_FORMATS 0x87FF
#define GL_COMPRESSED_R11_EAC 0x9270
#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271
#define GL_COMPRESSED_RG11_EAC 0x9272
#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273
#define GL_COMPRESSED_RGB8_ETC2 0x9274
#define GL_COMPRESSED_SRGB8_ETC2 0x9275
#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276
#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277
#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279
#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F
#define GL_MAX_ELEMENT_INDEX 0x8D6B
#define GL_NUM_SAMPLE_COUNTS 0x9380
#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF
/*-------------------------------------------------------------------------
* Entrypoint definitions
*-----------------------------------------------------------------------*/
/* OpenGL ES 3.0 */
extern GL_APICALL void (* GL_APIENTRY glReadBuffer) (GLenum mode);
extern GL_APICALL void (* GL_APIENTRY glDrawRangeElements) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices);
extern GL_APICALL void (* GL_APIENTRY glTexImage3D) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
extern GL_APICALL void (* GL_APIENTRY glTexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels);
extern GL_APICALL void (* GL_APIENTRY glCopyTexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
extern GL_APICALL void (* GL_APIENTRY glCompressedTexImage3D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data);
extern GL_APICALL void (* GL_APIENTRY glCompressedTexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data);
extern GL_APICALL void (* GL_APIENTRY glGenQueries) (GLsizei n, GLuint* ids);
extern GL_APICALL void (* GL_APIENTRY glDeleteQueries) (GLsizei n, const GLuint* ids);
extern GL_APICALL GLboolean (* GL_APIENTRY glIsQuery) (GLuint id);
extern GL_APICALL void (* GL_APIENTRY glBeginQuery) (GLenum target, GLuint id);
extern GL_APICALL void (* GL_APIENTRY glEndQuery) (GLenum target);
extern GL_APICALL void (* GL_APIENTRY glGetQueryiv) (GLenum target, GLenum pname, GLint* params);
extern GL_APICALL void (* GL_APIENTRY glGetQueryObjectuiv) (GLuint id, GLenum pname, GLuint* params);
extern GL_APICALL GLboolean (* GL_APIENTRY glUnmapBuffer) (GLenum target);
extern GL_APICALL void (* GL_APIENTRY glGetBufferPointerv) (GLenum target, GLenum pname, GLvoid** params);
extern GL_APICALL void (* GL_APIENTRY glDrawBuffers) (GLsizei n, const GLenum* bufs);
extern GL_APICALL void (* GL_APIENTRY glUniformMatrix2x3fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
extern GL_APICALL void (* GL_APIENTRY glUniformMatrix3x2fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
extern GL_APICALL void (* GL_APIENTRY glUniformMatrix2x4fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
extern GL_APICALL void (* GL_APIENTRY glUniformMatrix4x2fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
extern GL_APICALL void (* GL_APIENTRY glUniformMatrix3x4fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
extern GL_APICALL void (* GL_APIENTRY glUniformMatrix4x3fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
extern GL_APICALL void (* GL_APIENTRY glBlitFramebuffer) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
extern GL_APICALL void (* GL_APIENTRY glRenderbufferStorageMultisample) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
extern GL_APICALL void (* GL_APIENTRY glFramebufferTextureLayer) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
extern GL_APICALL GLvoid* (* GL_APIENTRY glMapBufferRange) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
extern GL_APICALL void (* GL_APIENTRY glFlushMappedBufferRange) (GLenum target, GLintptr offset, GLsizeiptr length);
extern GL_APICALL void (* GL_APIENTRY glBindVertexArray) (GLuint array);
extern GL_APICALL void (* GL_APIENTRY glDeleteVertexArrays) (GLsizei n, const GLuint* arrays);
extern GL_APICALL void (* GL_APIENTRY glGenVertexArrays) (GLsizei n, GLuint* arrays);
extern GL_APICALL GLboolean (* GL_APIENTRY glIsVertexArray) (GLuint array);
extern GL_APICALL void (* GL_APIENTRY glGetIntegeri_v) (GLenum target, GLuint index, GLint* data);
extern GL_APICALL void (* GL_APIENTRY glBeginTransformFeedback) (GLenum primitiveMode);
extern GL_APICALL void (* GL_APIENTRY glEndTransformFeedback) (void);
extern GL_APICALL void (* GL_APIENTRY glBindBufferRange) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
extern GL_APICALL void (* GL_APIENTRY glBindBufferBase) (GLenum target, GLuint index, GLuint buffer);
extern GL_APICALL void (* GL_APIENTRY glTransformFeedbackVaryings) (GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode);
extern GL_APICALL void (* GL_APIENTRY glGetTransformFeedbackVarying) (GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name);
extern GL_APICALL void (* GL_APIENTRY glVertexAttribIPointer) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer);
extern GL_APICALL void (* GL_APIENTRY glGetVertexAttribIiv) (GLuint index, GLenum pname, GLint* params);
extern GL_APICALL void (* GL_APIENTRY glGetVertexAttribIuiv) (GLuint index, GLenum pname, GLuint* params);
extern GL_APICALL void (* GL_APIENTRY glVertexAttribI4i) (GLuint index, GLint x, GLint y, GLint z, GLint w);
extern GL_APICALL void (* GL_APIENTRY glVertexAttribI4ui) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
extern GL_APICALL void (* GL_APIENTRY glVertexAttribI4iv) (GLuint index, const GLint* v);
extern GL_APICALL void (* GL_APIENTRY glVertexAttribI4uiv) (GLuint index, const GLuint* v);
extern GL_APICALL void (* GL_APIENTRY glGetUniformuiv) (GLuint program, GLint location, GLuint* params);
extern GL_APICALL GLint (* GL_APIENTRY glGetFragDataLocation) (GLuint program, const GLchar *name);
extern GL_APICALL void (* GL_APIENTRY glUniform1ui) (GLint location, GLuint v0);
extern GL_APICALL void (* GL_APIENTRY glUniform2ui) (GLint location, GLuint v0, GLuint v1);
extern GL_APICALL void (* GL_APIENTRY glUniform3ui) (GLint location, GLuint v0, GLuint v1, GLuint v2);
extern GL_APICALL void (* GL_APIENTRY glUniform4ui) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
extern GL_APICALL void (* GL_APIENTRY glUniform1uiv) (GLint location, GLsizei count, const GLuint* value);
extern GL_APICALL void (* GL_APIENTRY glUniform2uiv) (GLint location, GLsizei count, const GLuint* value);
extern GL_APICALL void (* GL_APIENTRY glUniform3uiv) (GLint location, GLsizei count, const GLuint* value);
extern GL_APICALL void (* GL_APIENTRY glUniform4uiv) (GLint location, GLsizei count, const GLuint* value);
extern GL_APICALL void (* GL_APIENTRY glClearBufferiv) (GLenum buffer, GLint drawbuffer, const GLint* value);
extern GL_APICALL void (* GL_APIENTRY glClearBufferuiv) (GLenum buffer, GLint drawbuffer, const GLuint* value);
extern GL_APICALL void (* GL_APIENTRY glClearBufferfv) (GLenum buffer, GLint drawbuffer, const GLfloat* value);
extern GL_APICALL void (* GL_APIENTRY glClearBufferfi) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
extern GL_APICALL const GLubyte* (* GL_APIENTRY glGetStringi) (GLenum name, GLuint index);
extern GL_APICALL void (* GL_APIENTRY glCopyBufferSubData) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
extern GL_APICALL void (* GL_APIENTRY glGetUniformIndices) (GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices);
extern GL_APICALL void (* GL_APIENTRY glGetActiveUniformsiv) (GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params);
extern GL_APICALL GLuint (* GL_APIENTRY glGetUniformBlockIndex) (GLuint program, const GLchar* uniformBlockName);
extern GL_APICALL void (* GL_APIENTRY glGetActiveUniformBlockiv) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params);
extern GL_APICALL void (* GL_APIENTRY glGetActiveUniformBlockName) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName);
extern GL_APICALL void (* GL_APIENTRY glUniformBlockBinding) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
extern GL_APICALL void (* GL_APIENTRY glDrawArraysInstanced) (GLenum mode, GLint first, GLsizei count, GLsizei instanceCount);
extern GL_APICALL void (* GL_APIENTRY glDrawElementsInstanced) (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instanceCount);
extern GL_APICALL GLsync (* GL_APIENTRY glFenceSync) (GLenum condition, GLbitfield flags);
extern GL_APICALL GLboolean (* GL_APIENTRY glIsSync) (GLsync sync);
extern GL_APICALL void (* GL_APIENTRY glDeleteSync) (GLsync sync);
extern GL_APICALL GLenum (* GL_APIENTRY glClientWaitSync) (GLsync sync, GLbitfield flags, GLuint64 timeout);
extern GL_APICALL void (* GL_APIENTRY glWaitSync) (GLsync sync, GLbitfield flags, GLuint64 timeout);
extern GL_APICALL void (* GL_APIENTRY glGetInteger64v) (GLenum pname, GLint64* params);
extern GL_APICALL void (* GL_APIENTRY glGetSynciv) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values);
extern GL_APICALL void (* GL_APIENTRY glGetInteger64i_v) (GLenum target, GLuint index, GLint64* data);
extern GL_APICALL void (* GL_APIENTRY glGetBufferParameteri64v) (GLenum target, GLenum pname, GLint64* params);
extern GL_APICALL void (* GL_APIENTRY glGenSamplers) (GLsizei count, GLuint* samplers);
extern GL_APICALL void (* GL_APIENTRY glDeleteSamplers) (GLsizei count, const GLuint* samplers);
extern GL_APICALL GLboolean (* GL_APIENTRY glIsSampler) (GLuint sampler);
extern GL_APICALL void (* GL_APIENTRY glBindSampler) (GLuint unit, GLuint sampler);
extern GL_APICALL void (* GL_APIENTRY glSamplerParameteri) (GLuint sampler, GLenum pname, GLint param);
extern GL_APICALL void (* GL_APIENTRY glSamplerParameteriv) (GLuint sampler, GLenum pname, const GLint* param);
extern GL_APICALL void (* GL_APIENTRY glSamplerParameterf) (GLuint sampler, GLenum pname, GLfloat param);
extern GL_APICALL void (* GL_APIENTRY glSamplerParameterfv) (GLuint sampler, GLenum pname, const GLfloat* param);
extern GL_APICALL void (* GL_APIENTRY glGetSamplerParameteriv) (GLuint sampler, GLenum pname, GLint* params);
extern GL_APICALL void (* GL_APIENTRY glGetSamplerParameterfv) (GLuint sampler, GLenum pname, GLfloat* params);
extern GL_APICALL void (* GL_APIENTRY glVertexAttribDivisor) (GLuint index, GLuint divisor);
extern GL_APICALL void (* GL_APIENTRY glBindTransformFeedback) (GLenum target, GLuint id);
extern GL_APICALL void (* GL_APIENTRY glDeleteTransformFeedbacks) (GLsizei n, const GLuint* ids);
extern GL_APICALL void (* GL_APIENTRY glGenTransformFeedbacks) (GLsizei n, GLuint* ids);
extern GL_APICALL GLboolean (* GL_APIENTRY glIsTransformFeedback) (GLuint id);
extern GL_APICALL void (* GL_APIENTRY glPauseTransformFeedback) (void);
extern GL_APICALL void (* GL_APIENTRY glResumeTransformFeedback) (void);
extern GL_APICALL void (* GL_APIENTRY glGetProgramBinary) (GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary);
extern GL_APICALL void (* GL_APIENTRY glProgramBinary) (GLuint program, GLenum binaryFormat, const GLvoid* binary, GLsizei length);
extern GL_APICALL void (* GL_APIENTRY glProgramParameteri) (GLuint program, GLenum pname, GLint value);
extern GL_APICALL void (* GL_APIENTRY glInvalidateFramebuffer) (GLenum target, GLsizei numAttachments, const GLenum* attachments);
extern GL_APICALL void (* GL_APIENTRY glInvalidateSubFramebuffer) (GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height);
extern GL_APICALL void (* GL_APIENTRY glTexStorage2D) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
extern GL_APICALL void (* GL_APIENTRY glTexStorage3D) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
extern GL_APICALL void (* GL_APIENTRY glGetInternalformativ) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,266 @@
#include "app/organicmaps/sdk/platform/AndroidPlatform.hpp"
#include "app/organicmaps/sdk/platform/GuiThread.hpp"
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/util/NetworkPolicy.hpp"
#include "platform/network_policy.hpp"
#include "platform/settings.hpp"
#include "base/logging.hpp"
#include "base/macros.hpp"
#include "base/string_utils.hpp"
#include <algorithm>
#include <memory>
#include <utility>
std::string Platform::GetMemoryInfo() const
{
JNIEnv * env = jni::GetEnv();
if (env == nullptr)
return std::string();
static std::shared_ptr<jobject> classLogsManager = jni::make_global_ref(env->FindClass("app/organicmaps/sdk/util/log/LogsManager"));
ASSERT(classLogsManager, ());
jobject context = android::Platform::Instance().GetContext();
static jmethodID const getMemoryInfoId
= jni::GetStaticMethodID(env,
static_cast<jclass>(*classLogsManager),
"getMemoryInfo",
"(Landroid/content/Context;)Ljava/lang/String;");
jstring const memInfoString = static_cast<jstring>(env->CallStaticObjectMethod(
static_cast<jclass>(*classLogsManager), getMemoryInfoId, context));
ASSERT(memInfoString, ());
return jni::ToNativeString(env, memInfoString);
}
std::string Platform::DeviceName() const
{
JNIEnv * env = jni::GetEnv();
static jmethodID const getDeviceNameId = jni::GetStaticMethodID(env, g_utilsClazz, "getDeviceName",
"()Ljava/lang/String;");
auto const deviceName = static_cast<jstring>(env->CallStaticObjectMethod(g_utilsClazz,
getDeviceNameId));
return jni::ToNativeString(env, deviceName);
}
std::string Platform::DeviceModel() const
{
JNIEnv * env = jni::GetEnv();
static jmethodID const getDeviceModelId = jni::GetStaticMethodID(env, g_utilsClazz, "getDeviceModel",
"()Ljava/lang/String;");
auto const deviceModel = static_cast<jstring>(env->CallStaticObjectMethod(g_utilsClazz,
getDeviceModelId));
return jni::ToNativeString(env, deviceModel);
}
std::string Platform::Version() const
{
JNIEnv * env = jni::GetEnv();
static jmethodID const getVersionId = jni::GetStaticMethodID(env, g_utilsClazz, "getVersion", "()Ljava/lang/String;");
auto const version = static_cast<jstring>(env->CallStaticObjectMethod(g_utilsClazz, getVersionId));
return jni::ToNativeString(env, version);
}
int32_t Platform::IntVersion() const
{
JNIEnv * env = jni::GetEnv();
static jmethodID const getIntVersionId = jni::GetStaticMethodID(env, g_utilsClazz, "getIntVersion", "()I");
return env->CallStaticIntMethod(g_utilsClazz, getIntVersionId);
}
Platform::EConnectionType Platform::ConnectionStatus()
{
JNIEnv * env = jni::GetEnv();
if (env == nullptr)
return EConnectionType::CONNECTION_NONE;
static std::shared_ptr<jobject> clazzConnectionState = jni::make_global_ref(env->FindClass("app/organicmaps/sdk/util/ConnectionState"));
ASSERT(clazzConnectionState, ());
static jmethodID const getConnectionMethodId = jni::GetStaticMethodID(env, static_cast<jclass>(*clazzConnectionState), "getConnectionState", "()B");
return static_cast<Platform::EConnectionType>(env->CallStaticByteMethod(static_cast<jclass>(*clazzConnectionState), getConnectionMethodId));
}
Platform::ChargingStatus Platform::GetChargingStatus()
{
JNIEnv * env = jni::GetEnv();
if (env == nullptr)
return Platform::ChargingStatus::Unknown;
static jclass const clazzBatteryState =
jni::GetGlobalClassRef(env, "app/organicmaps/sdk/util/BatteryState");
ASSERT(clazzBatteryState, ());
static jmethodID const getChargingMethodId =
jni::GetStaticMethodID(env, clazzBatteryState, "getChargingStatus", "(Landroid/content/Context;)I");
jobject context = android::Platform::Instance().GetContext();
return static_cast<Platform::ChargingStatus>(
env->CallStaticIntMethod(clazzBatteryState, getChargingMethodId, context));
}
uint8_t Platform::GetBatteryLevel()
{
JNIEnv * env = jni::GetEnv();
if (env == nullptr)
return 100;
static auto const clazzBatteryState =
jni::GetGlobalClassRef(env, "app/organicmaps/sdk/util/BatteryState");
ASSERT(clazzBatteryState, ());
static auto const getLevelMethodId =
jni::GetStaticMethodID(env, clazzBatteryState, "getLevel", "(Landroid/content/Context;)I");
jobject context = android::Platform::Instance().GetContext();
return static_cast<uint8_t>(env->CallStaticIntMethod(clazzBatteryState, getLevelMethodId, context));
}
namespace platform
{
platform::NetworkPolicy GetCurrentNetworkPolicy()
{
JNIEnv *env = jni::GetEnv();
return platform::NetworkPolicy(network_policy::GetCurrentNetworkUsageStatus(env));
}
}
namespace android
{
Platform::~Platform()
{
JNIEnv *env = jni::GetEnv();
env->DeleteGlobalRef(m_context);
}
void Platform::Initialize(JNIEnv * env, jobject context, jstring apkPath,
jstring writablePath, jstring privatePath, jstring tmpPath,
jstring flavorName, jstring buildType, bool isTablet)
{
m_context = env->NewGlobalRef(context);
m_guiThread = std::make_unique<GuiThread>();
std::string const flavor = jni::ToNativeString(env, flavorName);
std::string const build = jni::ToNativeString(env, buildType);
LOG(LINFO, ("Flavor name:", flavor));
LOG(LINFO, ("Build type name:", build));
m_isTablet = isTablet;
m_resourcesDir = jni::ToNativeString(env, apkPath);
m_tmpDir = jni::ToNativeString(env, tmpPath);
SetWritableDir(jni::ToNativeString(env, writablePath));
LOG(LINFO, ("Apk path = ", m_resourcesDir));
LOG(LINFO, ("Temporary path = ", m_tmpDir));
// IMPORTANT: This method SHOULD be called from UI thread to cache static jni ID-s inside.
(void) ConnectionStatus();
}
void Platform::OnExternalStorageStatusChanged(bool isAvailable)
{
}
void Platform::SetWritableDir(std::string const & dir)
{
m_writableDir = dir;
LOG(LINFO, ("Writable path = ", m_writableDir));
}
void Platform::SetSettingsDir(std::string const & dir)
{
m_settingsDir = dir;
// Logger is not fully initialized here.
//LOG(LINFO, ("Settings path = ", m_settingsDir));
}
bool Platform::HasAvailableSpaceForWriting(uint64_t size) const
{
return (GetWritableStorageStatus(size) == ::Platform::STORAGE_OK);
}
Platform & Platform::Instance()
{
static Platform platform;
return platform;
}
jobject Platform::GetContext() const
{
return m_context;
}
void Platform::AndroidSecureStorage::Init(JNIEnv * env)
{
if (m_secureStorageClass != nullptr)
return;
m_secureStorageClass = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/util/SecureStorage");
ASSERT(m_secureStorageClass, ());
}
void Platform::AndroidSecureStorage::Save(std::string const & key, std::string const & value)
{
JNIEnv * env = jni::GetEnv();
if (env == nullptr)
return;
Init(env);
static jmethodID const saveMethodId =
jni::GetStaticMethodID(env, m_secureStorageClass, "save",
"(Landroid/content/Context;Ljava/lang/String;"
"Ljava/lang/String;)V");
jobject context = android::Platform::Instance().GetContext();
env->CallStaticVoidMethod(m_secureStorageClass, saveMethodId,
context,
jni::TScopedLocalRef(env, jni::ToJavaString(env, key)).get(),
jni::TScopedLocalRef(env, jni::ToJavaString(env, value)).get());
}
bool Platform::AndroidSecureStorage::Load(std::string const & key, std::string & value)
{
JNIEnv * env = jni::GetEnv();
if (env == nullptr)
return false;
Init(env);
static jmethodID const loadMethodId =
jni::GetStaticMethodID(env, m_secureStorageClass, "load",
"(Landroid/content/Context;Ljava/lang/String;)"
"Ljava/lang/String;");
jobject context = android::Platform::Instance().GetContext();
auto const resultString = static_cast<jstring>(env->CallStaticObjectMethod(m_secureStorageClass,
loadMethodId, context,
jni::TScopedLocalRef(env, jni::ToJavaString(env, key)).get()));
if (resultString == nullptr)
return false;
value = jni::ToNativeString(env, resultString);
return true;
}
void Platform::AndroidSecureStorage::Remove(std::string const & key)
{
JNIEnv * env = jni::GetEnv();
if (env == nullptr)
return;
Init(env);
static jmethodID const removeMethodId =
jni::GetStaticMethodID(env, m_secureStorageClass, "remove",
"(Landroid/content/Context;Ljava/lang/String;)V");
jobject context = android::Platform::Instance().GetContext();
env->CallStaticVoidMethod(m_secureStorageClass, removeMethodId, context,
jni::TScopedLocalRef(env, jni::ToJavaString(env, key)).get());
}
} // namespace android
Platform & GetPlatform()
{
return android::Platform::Instance();
}

View File

@@ -0,0 +1,56 @@
#pragma once
#include <jni.h>
#include "platform/platform.hpp"
#include <memory>
#include <string>
namespace base
{
class TaskLoop;
}
namespace android
{
class Platform : public ::Platform
{
public:
~Platform() override;
void Initialize(JNIEnv * env, jobject functorProcessObject, jstring apkPath, jstring writablePath,
jstring privatePath, jstring tmpPath, jstring flavorName,
jstring buildType, bool isTablet);
void OnExternalStorageStatusChanged(bool isAvailable);
void SetWritableDir(std::string const & dir);
void SetSettingsDir(std::string const & dir);
bool HasAvailableSpaceForWriting(uint64_t size) const;
class AndroidSecureStorage
{
public:
void Save(std::string const & key, std::string const & value);
bool Load(std::string const & key, std::string & value);
void Remove(std::string const & key);
private:
void Init(JNIEnv * env);
jclass m_secureStorageClass = nullptr;
};
AndroidSecureStorage & GetSecureStorage() { return m_secureStorage; }
jobject GetContext() const;
static Platform & Instance();
private:
AndroidSecureStorage m_secureStorage;
jobject m_context;
};
} // namespace android

View File

@@ -0,0 +1,48 @@
#include "app/organicmaps/sdk/platform/GuiThread.hpp"
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include <memory>
namespace android
{
GuiThread::GuiThread()
{
JNIEnv * env = jni::GetEnv();
m_class = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/util/concurrency/UiThread");
ASSERT(m_class, ());
m_method = env->GetStaticMethodID(m_class, "forwardToMainThread", "(J)V");
ASSERT(m_method, ());
}
GuiThread::~GuiThread()
{
JNIEnv * env = jni::GetEnv();
env->DeleteGlobalRef(m_class);
}
// static
void GuiThread::ProcessTask(jlong task)
{
std::unique_ptr<Task> t(reinterpret_cast<Task *>(task));
(*t)();
}
base::TaskLoop::PushResult GuiThread::Push(Task && task)
{
// Pointer will be deleted in ProcessTask.
auto t = new Task(std::move(task));
jni::GetEnv()->CallStaticVoidMethod(m_class, m_method, reinterpret_cast<jlong>(t));
return {true, kNoId};
}
base::TaskLoop::PushResult GuiThread::Push(Task const & task)
{
// Pointer will be deleted in ProcessTask.
auto t = new Task(task);
jni::GetEnv()->CallStaticVoidMethod(m_class, m_method, reinterpret_cast<jlong>(t));
return {true, kNoId};
}
} // namespace android

View File

@@ -0,0 +1,25 @@
#pragma once
#include "base/task_loop.hpp"
#include <jni.h>
namespace android
{
class GuiThread : public base::TaskLoop
{
public:
GuiThread();
~GuiThread() override;
static void ProcessTask(jlong task);
// TaskLoop overrides:
PushResult Push(Task && task) override;
PushResult Push(Task const & task) override;
private:
jclass m_class = nullptr;
jmethodID m_method = nullptr;
};
} // namespace android

View File

@@ -0,0 +1,109 @@
#include "AndroidPlatform.hpp"
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "base/logging.hpp"
#include "platform/http_thread_callback.hpp"
class HttpThread
{
private:
jobject m_self;
jclass m_klass;
public:
HttpThread(std::string const & url,
downloader::IHttpThreadCallback & cb,
int64_t beg,
int64_t end,
int64_t expectedFileSize,
std::string const & pb)
{
JNIEnv * env = jni::GetEnv();
static jclass const klass = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/downloader/ChunkTask");
m_klass = klass;
// public ChunkTask(long httpCallbackID, String url, long beg, long end,
// long expectedFileSize, byte[] postBody, String userAgent)
static jmethodID const initMethodId = jni::GetConstructorID(env, klass, "(JLjava/lang/String;JJJ[B)V");
static jmethodID const startMethodId = env->GetMethodID(klass, "start", "()V");
jni::TScopedLocalByteArrayRef postBody(env, nullptr);
jsize const postBodySize = static_cast<jsize>(pb.size());
if (postBodySize)
{
postBody.reset(env->NewByteArray(postBodySize));
env->SetByteArrayRegion(postBody.get(), 0, postBodySize, reinterpret_cast<jbyte const *>(pb.c_str()));
}
jni::TScopedLocalRef jUrl(env, jni::ToJavaString(env, url.c_str()));
jni::TScopedLocalRef localSelf(env, env->NewObject(klass,
initMethodId,
reinterpret_cast<jlong>(&cb),
jUrl.get(),
static_cast<jlong>(beg),
static_cast<jlong>(end),
static_cast<jlong>(expectedFileSize),
postBody.get()));
m_self = env->NewGlobalRef(localSelf.get());
ASSERT(m_self, ());
env->CallVoidMethod(m_self, startMethodId);
}
~HttpThread()
{
JNIEnv * env = jni::GetEnv();
static jmethodID const cancelMethodId = env->GetMethodID(m_klass, "cancel", "(Z)Z");
env->CallBooleanMethod(m_self, cancelMethodId, false);
env->DeleteGlobalRef(m_self);
}
};
namespace downloader
{
HttpThread * CreateNativeHttpThread(std::string const & url,
downloader::IHttpThreadCallback & cb,
int64_t beg,
int64_t end,
int64_t size,
std::string const & pb)
{
return new HttpThread(url, cb, beg, end, size, pb);
}
void DeleteNativeHttpThread(HttpThread * request)
{
delete request;
}
} // namespace downloader
extern "C"
{
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_downloader_ChunkTask_nativeOnWrite(JNIEnv * env, jclass clazz, jlong httpCallbackID, jlong beg, jbyteArray data, jlong size)
{
downloader::IHttpThreadCallback * cb = reinterpret_cast<downloader::IHttpThreadCallback*>(httpCallbackID);
jbyte * buf = env->GetByteArrayElements(data, 0);
ASSERT(buf, ());
bool ret = false;
try
{
ret = cb->OnWrite(beg, buf, static_cast<jsize>(size));
}
catch (std::exception const & ex)
{
LOG(LERROR, ("Failed to write chunk:", ex.what()));
}
env->ReleaseByteArrayElements(data, buf, 0);
return ret;
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_downloader_ChunkTask_nativeOnFinish(JNIEnv * env, jclass clazz, jlong httpCallbackID, jlong httpCode, jlong beg, jlong end)
{
downloader::IHttpThreadCallback * cb = reinterpret_cast<downloader::IHttpThreadCallback*>(httpCallbackID);
cb->OnFinish(static_cast<long>(httpCode), beg, end);
}
} // extern "C"

View File

@@ -0,0 +1,67 @@
#include "android/sdk/src/main/cpp/app/organicmaps/sdk/core/jni_helper.hpp"
#include "android/sdk/src/main/cpp/app/organicmaps/sdk/core/ScopedLocalRef.hpp"
#include "platform/locale.hpp"
#include "base/assert.hpp"
#include "base/logging.hpp"
#include "base/string_utils.hpp"
#include <string>
/// This function is called from native c++ code
std::string GetAndroidSystemLanguage()
{
static char const * DEFAULT_LANG = "en";
JNIEnv * env = jni::GetEnv();
if (!env)
{
LOG(LWARNING, ("Can't get JNIEnv"));
return DEFAULT_LANG;
}
static jclass const languageClass = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/util/Language");
static jmethodID const getDefaultLocaleId = jni::GetStaticMethodID(env, languageClass, "getDefaultLocale", "()Ljava/lang/String;");
jni::TScopedLocalRef localeRef(env, env->CallStaticObjectMethod(languageClass, getDefaultLocaleId));
std::string res = jni::ToNativeString(env, (jstring) localeRef.get());
if (res.empty())
res = DEFAULT_LANG;
return res;
}
namespace platform
{
Locale GetCurrentLocale()
{
JNIEnv * env = jni::GetEnv();
static jmethodID const getLanguageCodeId = jni::GetStaticMethodID(env, g_utilsClazz, "getLanguageCode",
"()Ljava/lang/String;");
jni::ScopedLocalRef languageCode(env, env->CallStaticObjectMethod(g_utilsClazz, getLanguageCodeId));
static jmethodID const getCountryCodeId = jni::GetStaticMethodID(env, g_utilsClazz, "getCountryCode",
"()Ljava/lang/String;");
jni::ScopedLocalRef countryCode(env, env->CallStaticObjectMethod(g_utilsClazz, getCountryCodeId));
static jmethodID const getCurrencyCodeId = jni::GetStaticMethodID(env, g_utilsClazz, "getCurrencyCode",
"()Ljava/lang/String;");
jni::ScopedLocalRef currencyCode(env, env->CallStaticObjectMethod(g_utilsClazz, getCurrencyCodeId));
static jmethodID const getDecimalSeparatorId = jni::GetStaticMethodID(env, g_utilsClazz, "getDecimalSeparator",
"()Ljava/lang/String;");
jni::ScopedLocalRef decimalSeparatorChar(env, env->CallStaticObjectMethod(g_utilsClazz, getDecimalSeparatorId));
static jmethodID const getGroupingSeparatorId = jni::GetStaticMethodID(env, g_utilsClazz, "getGroupingSeparator",
"()Ljava/lang/String;");
jni::ScopedLocalRef groupingSeparatorChar(env, env->CallStaticObjectMethod(g_utilsClazz, getGroupingSeparatorId));
return {jni::ToNativeString(env, static_cast<jstring>(languageCode.get())),
jni::ToNativeString(env, static_cast<jstring>(countryCode.get())),
currencyCode.get() ? jni::ToNativeString(env, static_cast<jstring>(currencyCode.get())) : "",
jni::ToNativeString(env, static_cast<jstring>(decimalSeparatorChar.get())),
jni::ToNativeString(env, static_cast<jstring>(groupingSeparatorChar.get()))};
}
} // namespace platform

View File

@@ -0,0 +1,74 @@
#include <jni.h>
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/core/ScopedLocalRef.hpp"
#include "app/organicmaps/sdk/platform/AndroidPlatform.hpp"
#include "platform/localization.hpp"
#include <string>
namespace
{
jmethodID GetMethodId(std::string const & methodName)
{
JNIEnv * env = jni::GetEnv();
return jni::GetStaticMethodID(env, g_utilsClazz, methodName.c_str(),
"(Landroid/content/Context;Ljava/lang/String;)Ljava/lang/String;");
}
std::string GetLocalizedStringByUtil(jmethodID const & methodId, std::string const & str)
{
JNIEnv * env = jni::GetEnv();
jni::TScopedLocalRef strRef(env, jni::ToJavaString(env, str));
jobject context = android::Platform::Instance().GetContext();
jni::TScopedLocalRef localizedStrRef(env, env->CallStaticObjectMethod(g_utilsClazz, methodId,
context, strRef.get()));
return jni::ToNativeString(env, static_cast<jstring>(localizedStrRef.get()));
}
} // namespace
namespace platform
{
std::string GetLocalizedTypeName(std::string const & type)
{
static auto const methodId = GetMethodId("getLocalizedFeatureType");
return GetLocalizedStringByUtil(methodId, type);
}
std::string GetLocalizedBrandName(std::string const & brand)
{
static auto const methodId = GetMethodId("getLocalizedBrand");
return GetLocalizedStringByUtil(methodId, brand);
}
std::string GetLocalizedString(std::string const & key)
{
static auto const methodId = GetMethodId("getStringValueByKey");
return GetLocalizedStringByUtil(methodId, key);
}
std::string GetCurrencySymbol(std::string const & currencyCode)
{
JNIEnv * env = jni::GetEnv();
static auto const methodId = jni::GetStaticMethodID(env, g_utilsClazz, "getCurrencySymbol",
"(Ljava/lang/String;)Ljava/lang/String;");
jni::TScopedLocalRef currencyCodeRef(env, jni::ToJavaString(env, currencyCode));
jni::TScopedLocalRef localizedStrRef(
env, env->CallStaticObjectMethod(g_utilsClazz, methodId, currencyCodeRef.get()));
return jni::ToNativeString(env, static_cast<jstring>(localizedStrRef.get()));
}
std::string GetLocalizedMyPositionBookmarkName()
{
JNIEnv * env = jni::GetEnv();
static auto const methodId = jni::GetStaticMethodID(env, g_utilsClazz, "getMyPositionBookmarkName",
"(Landroid/content/Context;)Ljava/lang/String;");
jobject context = android::Platform::Instance().GetContext();
jni::TScopedLocalRef localizedStrRef(env, env->CallStaticObjectMethod(g_utilsClazz, methodId, context));
return jni::ToNativeString(env, static_cast<jstring>(localizedStrRef.get()));
}
} // namespace platform

View File

@@ -0,0 +1,14 @@
#include "app/organicmaps/sdk/core/jni_helper.hpp"
/// Implements bodies of base/thread.hpp functions for Android
void AndroidThreadAttachToJVM()
{
JNIEnv * env;
jni::GetJVM()->AttachCurrentThread(&env, 0);
}
void AndroidThreadDetachFromJVM()
{
jni::GetJVM()->DetachCurrentThread();
}

View File

@@ -0,0 +1,21 @@
#include "platform/secure_storage.hpp"
#include "AndroidPlatform.hpp"
namespace platform
{
void SecureStorage::Save(std::string const & key, std::string const & value)
{
android::Platform::Instance().GetSecureStorage().Save(key, value);
}
bool SecureStorage::Load(std::string const & key, std::string & value)
{
return android::Platform::Instance().GetSecureStorage().Load(key, value);
}
void SecureStorage::Remove(std::string const & key)
{
android::Platform::Instance().GetSecureStorage().Remove(key);
}
} // namespace platform

View File

@@ -0,0 +1,91 @@
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "platform/socket.hpp"
#include "base/logging.hpp"
#include <memory>
namespace platform
{
class SocketImpl : public Socket
{
public:
SocketImpl()
{
JNIEnv * env = jni::GetEnv();
static jmethodID const socketConstructor = jni::GetConstructorID(env, g_platformSocketClazz, "()V");
jni::TScopedLocalRef localSelf(env, env->NewObject(g_platformSocketClazz, socketConstructor));
m_self = env->NewGlobalRef(localSelf.get());
ASSERT(m_self, ());
}
~SocketImpl()
{
Close();
JNIEnv * env = jni::GetEnv();
env->DeleteGlobalRef(m_self);
}
bool Open(std::string const & host, uint16_t port)
{
JNIEnv * env = jni::GetEnv();
static jmethodID const openMethod =
jni::GetMethodID(env, m_self, "open", "(Ljava/lang/String;I)Z");
jni::TScopedLocalRef hostRef(env, jni::ToJavaString(env, host));
jboolean result = env->CallBooleanMethod(m_self, openMethod, hostRef.get(), static_cast<jint>(port));
if (jni::HandleJavaException(env))
return false;
return result;
}
void Close()
{
JNIEnv * env = jni::GetEnv();
static jmethodID const closeMethod = jni::GetMethodID(env, m_self, "close", "()V");
env->CallVoidMethod(m_self, closeMethod);
jni::HandleJavaException(env);
}
bool Read(uint8_t * data, uint32_t count)
{
JNIEnv * env = jni::GetEnv();
jbyteArray array = env->NewByteArray(count);
static jmethodID const readMethod = jni::GetMethodID(env, m_self, "read", "([BI)Z");
jboolean result = env->CallBooleanMethod(m_self, readMethod, array, static_cast<jint>(count));
if (jni::HandleJavaException(env))
return false;
//this call copies java byte array to native buffer
env->GetByteArrayRegion(array, 0, count, reinterpret_cast<jbyte *>(data));
if (jni::HandleJavaException(env))
return false;
return result;
}
bool Write(uint8_t const * data, uint32_t count)
{
JNIEnv * env = jni::GetEnv();
jni::TScopedLocalByteArrayRef arrayRef(env, env->NewByteArray(count));
//this call copies native buffer to java byte array
env->SetByteArrayRegion(arrayRef.get(), 0, count, reinterpret_cast<const jbyte *>(data));
static jmethodID const writeMethod = jni::GetMethodID(env, m_self, "write", "([BI)Z");
jboolean result = env->CallBooleanMethod(m_self, writeMethod, arrayRef.get(), static_cast<jint>(count));
if (jni::HandleJavaException(env))
return false;
return result;
}
void SetTimeout(uint32_t milliseconds)
{
JNIEnv * env = jni::GetEnv();
static jmethodID const setTimeoutMethod = jni::GetMethodID(env, m_self, "setTimeout", "(I)V");
env->CallVoidMethod(m_self, setTimeoutMethod, static_cast<jint>(milliseconds));
jni::HandleJavaException(env);
};
private:
jobject m_self;
};
std::unique_ptr<Socket> CreateSocket() { return std::make_unique<SocketImpl>(); }
}

View File

@@ -0,0 +1,22 @@
#pragma once
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "geometry/point_with_altitude.hpp"
#include <vector>
jobjectArray CreateJunctionInfoArray(JNIEnv * env, std::vector<geometry::PointWithAltitude> const & junctionPoints)
{
static jclass const junctionClazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/routing/JunctionInfo");
// Java signature : JunctionInfo(double lat, double lon)
static jmethodID const junctionConstructor = jni::GetConstructorID(env, junctionClazz, "(DD)V");
return jni::ToJavaArray(env, junctionClazz, junctionPoints,
[](JNIEnv * env, geometry::PointWithAltitude const & pointWithAltitude)
{
auto & point = pointWithAltitude.GetPoint();
return env->NewObject(junctionClazz, junctionConstructor, mercator::YToLat(point.y),
mercator::XToLon(point.x));
});
}

View File

@@ -0,0 +1,29 @@
#pragma once
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "geometry/point2d.hpp"
#include <vector>
jobjectArray CreateRouteMarkDataArray(JNIEnv * env, std::vector<RouteMarkData> const & points)
{
static jclass const pointClazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/routing/RouteMarkData");
// Java signature : RouteMarkData(String title, String subtitle, int pointType,
// int intermediateIndex, boolean isVisible, boolean isMyPosition,
// boolean isPassed, double lat, double lon)
static jmethodID const pointConstructor =
jni::GetConstructorID(env, pointClazz, "(Ljava/lang/String;Ljava/lang/String;IIZZZDD)V");
return jni::ToJavaArray(env, pointClazz, points,
[&](JNIEnv * jEnv, RouteMarkData const & data)
{
jni::TScopedLocalRef const title(env, jni::ToJavaString(env, data.m_title));
jni::TScopedLocalRef const subtitle(env, jni::ToJavaString(env, data.m_subTitle));
return env->NewObject(
pointClazz, pointConstructor, title.get(), subtitle.get(),
static_cast<jint>(data.m_pointType), static_cast<jint>(data.m_intermediateIndex),
static_cast<jboolean>(data.m_isVisible), static_cast<jboolean>(data.m_isMyPosition),
static_cast<jboolean>(data.m_isPassed), mercator::YToLat(data.m_position.y),
mercator::XToLon(data.m_position.x));
});
}

View File

@@ -0,0 +1,12 @@
#pragma once
#include "app/organicmaps/sdk/routing/RouteMarkType.hpp"
#include "map/routing_mark.hpp"
RouteMarkType GetRouteMarkType(JNIEnv * env, jobject markType)
{
static jmethodID const ordinal = jni::GetMethodID(env, markType, "ordinal", "()I");
return static_cast<RouteMarkType>(env->CallIntMethod(markType, ordinal));
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "map/place_page_info.hpp"
jobject CreateRoutePointInfo(JNIEnv * env, place_page::Info const & info)
{
static jclass const clazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/routing/RoutePointInfo");
static jmethodID const ctorId = jni::GetConstructorID(env, clazz, "(II)V");
int const markType = static_cast<int>(info.GetRouteMarkType());
return env->NewObject(clazz, ctorId, markType, info.GetIntermediateIndex());
}

View File

@@ -0,0 +1,38 @@
#pragma once
#include "app/organicmaps/sdk/core/jni_helper.hpp"
jobject GetRebuildAfterPointsLoading(JNIEnv * env)
{
static jobject rebuildAfterPointsLoading = nullptr;
if (rebuildAfterPointsLoading)
return rebuildAfterPointsLoading;
// Find the RouteRecommendationType class
jclass routeRecommendationTypeClass = env->FindClass("app/organicmaps/sdk/routing/RouteRecommendationType");
ASSERT(routeRecommendationTypeClass, ());
// Get the values() method of RouteRecommendationType
jmethodID valuesMethod = env->GetStaticMethodID(routeRecommendationTypeClass, "values",
"()[Lapp/organicmaps/sdk/routing/RouteRecommendationType;");
ASSERT(valuesMethod, ());
// Call values() to get all enum constants
jobjectArray enumConstants = (jobjectArray)env->CallStaticObjectMethod(routeRecommendationTypeClass, valuesMethod);
ASSERT(enumConstants, ());
// Retrieve the first (and only) constant, RebuildAfterPointsLoading
rebuildAfterPointsLoading = env->NewGlobalRef(env->GetObjectArrayElement(enumConstants, 0));
ASSERT(rebuildAfterPointsLoading, ());
return rebuildAfterPointsLoading;
}
jobject GetRouteRecommendationType(JNIEnv * env, RoutingManager::Recommendation recommendation)
{
switch (recommendation)
{
case RoutingManager::Recommendation::RebuildAfterPointsLoading: return GetRebuildAfterPointsLoading(env);
default: ASSERT_FAIL("Unknown recommendation type");
}
}

View File

@@ -0,0 +1,35 @@
#pragma once
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/routing/SingleLaneInfo.hpp"
#include "app/organicmaps/sdk/util/Distance.hpp"
#include "map/routing_manager.hpp"
jobject CreateRoutingInfo(JNIEnv * env, routing::FollowingInfo const & info, RoutingManager & rm)
{
static jclass const klass = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/routing/RoutingInfo");
// Java signature : RoutingInfo(Distance distToTarget, Distance distToTurn,
// String currentStreet, String nextStreet, String nextNextStreet,
// double completionPercent, int vehicleTurnOrdinal, int
// vehicleNextTurnOrdinal, int pedestrianTurnOrdinal, int exitNum,
// int totalTime, SingleLaneInfo[] lanes)
static jmethodID const ctorRouteInfoID =
jni::GetConstructorID(env, klass,
"(Lapp/organicmaps/sdk/util/Distance;Lapp/organicmaps/sdk/util/Distance;"
"Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;DIIIII"
"[Lapp/organicmaps/sdk/routing/SingleLaneInfo;DZZ)V");
jobjectArray jLanes = CreateLanesInfo(env, info.m_lanes);
auto const isSpeedCamLimitExceeded = rm.IsSpeedCamLimitExceeded();
auto const shouldPlaySignal = rm.GetSpeedCamManager().ShouldPlayBeepSignal();
jobject const result = env->NewObject(
klass, ctorRouteInfoID, ToJavaDistance(env, info.m_distToTarget), ToJavaDistance(env, info.m_distToTurn),
jni::ToJavaString(env, info.m_currentStreetName), jni::ToJavaString(env, info.m_nextStreetName),
jni::ToJavaString(env, info.m_nextNextStreetName), info.m_completionPercent, info.m_turn, info.m_nextTurn,
info.m_pedestrianTurn, info.m_exitNum, info.m_time, jLanes, info.m_speedLimitMps,
static_cast<jboolean>(isSpeedCamLimitExceeded), static_cast<jboolean>(shouldPlaySignal));
ASSERT(result, (jni::DescribeException()));
return result;
}

View File

@@ -0,0 +1,41 @@
#include <jni.h>
#include "app/organicmaps/sdk/Framework.hpp"
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "routing/routing_options.hpp"
routing::RoutingOptions::Road makeValue(jint option)
{
auto const road = static_cast<uint8_t>(1u << static_cast<int>(option));
CHECK_LESS(road, static_cast<uint8_t>(routing::RoutingOptions::Road::Max), ());
return static_cast<routing::RoutingOptions::Road>(road);
}
extern "C"
{
JNIEXPORT jboolean JNICALL Java_app_organicmaps_sdk_routing_RoutingOptions_nativeHasOption(JNIEnv *, jclass,
jint option)
{
CHECK(g_framework, ("Framework isn't created yet!"));
routing::RoutingOptions routingOptions = routing::RoutingOptions::LoadCarOptionsFromSettings();
routing::RoutingOptions::Road road = makeValue(option);
return static_cast<jboolean>(routingOptions.Has(road));
}
JNIEXPORT void JNICALL Java_app_organicmaps_sdk_routing_RoutingOptions_nativeAddOption(JNIEnv *, jclass, jint option)
{
CHECK(g_framework, ("Framework isn't created yet!"));
routing::RoutingOptions routingOptions = routing::RoutingOptions::LoadCarOptionsFromSettings();
routing::RoutingOptions::Road road = makeValue(option);
routingOptions.Add(road);
routing::RoutingOptions::SaveCarOptionsToSettings(routingOptions);
}
JNIEXPORT void JNICALL Java_app_organicmaps_sdk_routing_RoutingOptions_nativeRemoveOption(JNIEnv *, jclass, jint option)
{
CHECK(g_framework, ("Framework isn't created yet!"));
routing::RoutingOptions routingOptions = routing::RoutingOptions::LoadCarOptionsFromSettings();
routing::RoutingOptions::Road road = makeValue(option);
routingOptions.Remove(road);
routing::RoutingOptions::SaveCarOptionsToSettings(routingOptions);
}
}

View File

@@ -0,0 +1,34 @@
#pragma once
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "routing/following_info.hpp"
#include <vector>
jobjectArray CreateLanesInfo(JNIEnv * env, std::vector<routing::FollowingInfo::SingleLaneInfoClient> const & lanes)
{
if (lanes.empty())
return nullptr;
static jclass const laneClass = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/routing/SingleLaneInfo");
auto const lanesSize = static_cast<jsize>(lanes.size());
jobjectArray jLanes = env->NewObjectArray(lanesSize, laneClass, nullptr);
ASSERT(jLanes, (jni::DescribeException()));
static jmethodID const ctorSingleLaneInfoID = jni::GetConstructorID(env, laneClass, "([BZ)V");
for (jsize j = 0; j < lanesSize; ++j)
{
auto const laneSize = static_cast<jsize>(lanes[j].m_lane.size());
jni::TScopedLocalByteArrayRef singleLane(env, env->NewByteArray(laneSize));
ASSERT(singleLane.get(), (jni::DescribeException()));
env->SetByteArrayRegion(singleLane.get(), 0, laneSize, lanes[j].m_lane.data());
jni::TScopedLocalRef singleLaneInfo(
env, env->NewObject(laneClass, ctorSingleLaneInfoID, singleLane.get(), lanes[j].m_isRecommended));
ASSERT(singleLaneInfo.get(), (jni::DescribeException()));
env->SetObjectArrayElement(jLanes, j, singleLaneInfo.get());
}
return jLanes;
}

View File

@@ -0,0 +1,32 @@
#pragma once
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/routing/TransitStepInfo.hpp"
#include "map/transit/transit_display.hpp"
jobject CreateTransitRouteInfo(JNIEnv * env, TransitRouteInfo const & routeInfo)
{
jobjectArray steps = CreateTransitStepInfoArray(env, routeInfo.m_steps);
static jclass const transitRouteInfoClass =
jni::GetGlobalClassRef(env, "app/organicmaps/sdk/routing/TransitRouteInfo");
// Java signature : TransitRouteInfo(@NonNull String totalDistance, @NonNull String totalDistanceUnits,
// int totalTimeInSec, @NonNull String totalPedestrianDistance, @NonNull String
// totalPedestrianDistanceUnits, int totalPedestrianTimeInSec, @NonNull
// TransitStepInfo[] steps)
static jmethodID const transitRouteInfoConstructor =
jni::GetConstructorID(env, transitRouteInfoClass,
"(Ljava/lang/String;Ljava/lang/String;I"
"Ljava/lang/String;Ljava/lang/String;I"
"[Lapp/organicmaps/sdk/routing/TransitStepInfo;)V");
jni::TScopedLocalRef const distance(env, jni::ToJavaString(env, routeInfo.m_totalDistanceStr));
jni::TScopedLocalRef const distanceUnits(env, jni::ToJavaString(env, routeInfo.m_totalDistanceUnitsSuffix));
jni::TScopedLocalRef const distancePedestrian(env, jni::ToJavaString(env, routeInfo.m_totalPedestrianDistanceStr));
jni::TScopedLocalRef const distancePedestrianUnits(env,
jni::ToJavaString(env, routeInfo.m_totalPedestrianUnitsSuffix));
return env->NewObject(transitRouteInfoClass, transitRouteInfoConstructor, distance.get(), distanceUnits.get(),
static_cast<jint>(routeInfo.m_totalTimeInSec), distancePedestrian.get(),
distancePedestrianUnits.get(), static_cast<jint>(routeInfo.m_totalPedestrianTimeInSec), steps);
}

View File

@@ -0,0 +1,28 @@
#pragma once
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "map/transit/transit_display.hpp"
#include <vector>
jobjectArray CreateTransitStepInfoArray(JNIEnv * env, std::vector<TransitStepInfo> const & steps)
{
static jclass const transitStepClass = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/routing/TransitStepInfo");
// Java signature : TransitStepInfo(int type, @Nullable String distance, @Nullable String distanceUnits,
// int timeInSec, @Nullable String number, int color, int intermediateIndex)
static jmethodID const transitStepConstructor =
jni::GetConstructorID(env, transitStepClass, "(ILjava/lang/String;Ljava/lang/String;ILjava/lang/String;II)V");
return jni::ToJavaArray(
env, transitStepClass, steps,
[&](JNIEnv * jEnv, TransitStepInfo const & stepInfo)
{
jni::TScopedLocalRef const distance(env, jni::ToJavaString(env, stepInfo.m_distanceStr));
jni::TScopedLocalRef const distanceUnits(env, jni::ToJavaString(env, stepInfo.m_distanceUnitsSuffix));
jni::TScopedLocalRef const number(env, jni::ToJavaString(env, stepInfo.m_number));
return env->NewObject(transitStepClass, transitStepConstructor, static_cast<jint>(stepInfo.m_type),
distance.get(), distanceUnits.get(), static_cast<jint>(stepInfo.m_timeInSec), number.get(),
static_cast<jint>(stepInfo.m_colorARGB), static_cast<jint>(stepInfo.m_intermediateIndex));
});
}

View File

@@ -0,0 +1,21 @@
#include "app/organicmaps/sdk/Framework.hpp"
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "search/displayed_categories.hpp"
extern "C"
{
JNIEXPORT jobjectArray JNICALL Java_app_organicmaps_sdk_search_DisplayedCategories_nativeGetKeys(JNIEnv * env, jclass)
{
::Framework * fr = g_framework->NativeFramework();
ASSERT(fr, ());
search::DisplayedCategories const & categories = fr->GetDisplayedCategories();
return jni::ToJavaStringArray(env, categories.GetKeys());
}
JNIEXPORT jboolean JNICALL Java_app_organicmaps_sdk_search_DisplayedCategories_nativeIsLangSupported(
JNIEnv * env, jclass, jstring langCode)
{
return search::DisplayedCategories::IsLanguageSupported(jni::ToNativeString(env, langCode));
}
} // extern "C"

View File

@@ -0,0 +1,375 @@
#include "app/organicmaps/sdk/Framework.hpp"
#include "app/organicmaps/sdk/UserMarkHelper.hpp"
#include "app/organicmaps/sdk/platform/AndroidPlatform.hpp"
#include "app/organicmaps/sdk/util/Distance.hpp"
#include "map/bookmarks_search_params.hpp"
#include "map/everywhere_search_params.hpp"
#include "map/place_page_info.hpp"
#include "map/viewport_search_params.hpp"
#include "search/mode.hpp"
#include "search/result.hpp"
#include "platform/network_policy.hpp"
#include "geometry/distance_on_sphere.hpp"
#include "base/assert.hpp"
#include "base/logging.hpp"
#include "defines.hpp"
#include <chrono>
#include <memory>
#include <vector>
using namespace std;
using namespace std::placeholders;
using search::Result;
using search::Results;
namespace
{
FeatureID const kEmptyFeatureId;
// This cache is needed only for showing a specific result on the map after click on the list item.
// Don't use it with another intentions!
Results g_results;
// Timestamp of last search query. Results with older stamps are ignored.
jlong g_queryTimestamp;
// Implements 'SearchListener' java interface.
jobject g_javaListener;
jmethodID g_updateResultsId;
jmethodID g_endResultsId;
// Cached classes and methods to return results.
jclass g_resultClass;
jmethodID g_resultConstructor;
jmethodID g_suggestConstructor;
jclass g_descriptionClass;
jmethodID g_descriptionConstructor;
jclass g_popularityClass;
jmethodID g_popularityConstructor;
// Implements 'MapSearchListener' java interface.
jmethodID g_mapResultsMethod;
jclass g_mapResultClass;
jmethodID g_mapResultCtor;
jmethodID g_updateBookmarksResultsId;
jmethodID g_endBookmarksResultsId;
bool PopularityHasHigherPriority(bool hasPosition, double distanceInMeters)
{
return !hasPosition || distanceInMeters > search::Result::kPopularityHighPriorityMinDistance;
}
jobject ToJavaResult(Result const & result, search::ProductInfo const & productInfo,
bool hasPosition, double lat, double lon)
{
JNIEnv * env = jni::GetEnv();
jni::TScopedLocalIntArrayRef ranges(
env, env->NewIntArray(static_cast<jsize>(result.GetHighlightRangesCount() * 2)));
jint * rawArr = env->GetIntArrayElements(ranges, nullptr);
for (size_t i = 0; i < result.GetHighlightRangesCount(); i++)
{
auto const & range = result.GetHighlightRange(i);
rawArr[2 * i] = range.first;
rawArr[2 * i + 1] = range.second;
}
env->ReleaseIntArrayElements(ranges.get(), rawArr, 0);
jni::TScopedLocalIntArrayRef descRanges(env, env->NewIntArray(
static_cast<jsize>(result.GetDescHighlightRangesCount() * 2)));
jint * rawArr2 = env->GetIntArrayElements(descRanges, nullptr);
for (size_t i = 0; i < result.GetDescHighlightRangesCount(); i++)
{
auto const & range = result.GetDescHighlightRange(i);
rawArr2[2 * i] = range.first;
rawArr2[2 * i + 1] = range.second;
}
env->ReleaseIntArrayElements(descRanges.get(), rawArr2, 0);
ms::LatLon ll = ms::LatLon::Zero();
if (result.HasPoint())
ll = mercator::ToLatLon(result.GetFeatureCenter());
if (result.IsSuggest())
{
jni::TScopedLocalRef name(env, jni::ToJavaString(env, result.GetString()));
jni::TScopedLocalRef suggest(env, jni::ToJavaString(env, result.GetSuggestionString()));
return env->NewObject(g_resultClass, g_suggestConstructor, name.get(), suggest.get(), ll.m_lat, ll.m_lon, ranges.get(),descRanges.get());
}
platform::Distance distance;
double distanceInMeters = 0.0;
if (result.HasPoint() && hasPosition)
{
distanceInMeters = ms::DistanceOnEarth(lat, lon, ll.m_lat, ll.m_lon);
distance = platform::Distance::CreateFormatted(distanceInMeters);
}
bool const popularityHasHigherPriority = PopularityHasHigherPriority(hasPosition, distanceInMeters);
bool const isFeature = result.GetResultType() == Result::Type::Feature;
jni::TScopedLocalRef featureId(env, usermark_helper::CreateFeatureId(env, isFeature ?
result.GetFeatureID() :
kEmptyFeatureId));
jni::TScopedLocalRef featureType(env, jni::ToJavaString(env, result.GetLocalizedFeatureType()));
jni::TScopedLocalRef address(env, jni::ToJavaString(env, result.GetAddress()));
jni::TScopedLocalRef dist(env, ToJavaDistance(env, distance));
jni::TScopedLocalRef description(env, jni::ToJavaString(env, result.GetFeatureDescription()));
jni::TScopedLocalRef desc(env, env->NewObject(g_descriptionClass, g_descriptionConstructor,
featureId.get(), featureType.get(), address.get(),
dist.get(), description.get(),
static_cast<jint>(result.IsOpenNow()),
result.GetMinutesUntilOpen(),result.GetMinutesUntilClosed(),
static_cast<jboolean>(popularityHasHigherPriority)));
jni::TScopedLocalRef name(env, jni::ToJavaString(env, result.GetString()));
jni::TScopedLocalRef popularity(env, env->NewObject(g_popularityClass,
g_popularityConstructor,
/// @todo Restore when popularity will be available
0/*static_cast<jint>(result.GetRankingInfo().m_popularity)*/));
return env->NewObject(g_resultClass, g_resultConstructor, name.get(), desc.get(), ll.m_lat, ll.m_lon,
ranges.get(), descRanges.get(), popularity.get());
}
jobjectArray BuildSearchResults(vector<search::ProductInfo> const & productInfo,
bool hasPosition, double lat, double lon)
{
JNIEnv * env = jni::GetEnv();
auto const count = static_cast<jsize>(g_results.GetCount());
jobjectArray const jResults = env->NewObjectArray(count, g_resultClass, nullptr);
for (jsize i = 0; i < count; i++)
{
jni::TScopedLocalRef jRes(env, ToJavaResult(g_results[i], productInfo[i], hasPosition, lat, lon));
env->SetObjectArrayElement(jResults, i, jRes.get());
}
return jResults;
}
void OnResults(Results results, vector<search::ProductInfo> const & productInfo,
jlong timestamp, bool isMapAndTable, bool hasPosition, double lat, double lon)
{
// Ignore results from obsolete searches.
if (g_queryTimestamp > timestamp)
return;
JNIEnv * env = jni::GetEnv();
if (!results.IsEndMarker() || results.IsEndedNormal())
{
g_results = std::move(results);
jni::TScopedLocalObjectArrayRef jResults(env, BuildSearchResults(productInfo, hasPosition, lat, lon));
env->CallVoidMethod(g_javaListener, g_updateResultsId, jResults.get(), timestamp);
}
if (results.IsEndMarker())
{
env->CallVoidMethod(g_javaListener, g_endResultsId, timestamp);
if (isMapAndTable && results.IsEndedNormal())
g_framework->NativeFramework()->GetSearchAPI().PokeSearchInViewport();
}
}
jobjectArray BuildJavaMapResults(vector<storage::DownloaderSearchResult> const & results)
{
JNIEnv * env = jni::GetEnv();
auto const count = static_cast<jsize>(results.size());
jobjectArray const res = env->NewObjectArray(count, g_mapResultClass, nullptr);
for (jsize i = 0; i < count; i++)
{
jni::TScopedLocalRef country(env, jni::ToJavaString(env, results[i].m_countryId));
jni::TScopedLocalRef matched(env, jni::ToJavaString(env, results[i].m_matchedName));
jni::TScopedLocalRef item(env, env->NewObject(g_mapResultClass, g_mapResultCtor, country.get(), matched.get()));
env->SetObjectArrayElement(res, i, item.get());
}
return res;
}
void OnMapSearchResults(storage::DownloaderSearchResults const & results, long long timestamp)
{
// Ignore results from obsolete searches.
if (g_queryTimestamp > timestamp)
return;
JNIEnv * env = jni::GetEnv();
jni::TScopedLocalObjectArrayRef jResults(env, BuildJavaMapResults(results.m_results));
env->CallVoidMethod(g_javaListener, g_mapResultsMethod, jResults.get(),
static_cast<jlong>(timestamp), results.m_endMarker);
}
void OnBookmarksSearchResults(search::BookmarksSearchParams::Results results,
search::BookmarksSearchParams::Status status, long long timestamp)
{
// Ignore results from obsolete searches.
if (g_queryTimestamp > timestamp)
return;
JNIEnv * env = jni::GetEnv();
g_framework->NativeFramework()->GetBookmarkManager().FilterInvalidBookmarks(results);
jni::ScopedLocalRef<jlongArray> jResults(env, env->NewLongArray(static_cast<jsize>(results.size())));
vector<jlong> const tmp(results.cbegin(), results.cend());
env->SetLongArrayRegion(jResults.get(), 0, static_cast<jsize>(tmp.size()), tmp.data());
auto const method = (status == search::BookmarksSearchParams::Status::InProgress) ?
g_updateBookmarksResultsId : g_endBookmarksResultsId;
env->CallVoidMethod(g_javaListener, method, jResults.get(), static_cast<jlong>(timestamp));
}
} // namespace
extern "C"
{
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_search_SearchEngine_nativeInit(JNIEnv * env, jobject thiz)
{
g_javaListener = env->NewGlobalRef(thiz);
// public void onResultsUpdate(@NonNull SearchResult[] results, long timestamp)
g_updateResultsId = jni::GetMethodID(env, g_javaListener, "onResultsUpdate",
"([Lapp/organicmaps/sdk/search/SearchResult;J)V");
// public void onResultsEnd(long timestamp)
g_endResultsId = jni::GetMethodID(env, g_javaListener, "onResultsEnd", "(J)V");
g_resultClass = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/search/SearchResult");
g_resultConstructor = jni::GetConstructorID(
env, g_resultClass,
"(Ljava/lang/String;Lapp/organicmaps/sdk/search/SearchResult$Description;DD[I[I"
"Lapp/organicmaps/sdk/search/Popularity;)V");
g_suggestConstructor = jni::GetConstructorID(env, g_resultClass, "(Ljava/lang/String;Ljava/lang/String;DD[I[I)V");
g_descriptionClass = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/search/SearchResult$Description");
/*
Description(FeatureId featureId, String featureType, String region, Distance distance,
String description, int openNow, int minutesUntilOpen, int minutesUntilClosed,
boolean hasPopularityHigherPriority)
*/
g_descriptionConstructor = jni::GetConstructorID(env, g_descriptionClass,
"(Lapp/organicmaps/sdk/bookmarks/data/FeatureId;"
"Ljava/lang/String;Ljava/lang/String;Lapp/organicmaps/sdk/util/Distance;"
"Ljava/lang/String;IIIZ)V");
g_popularityClass = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/search/Popularity");
g_popularityConstructor = jni::GetConstructorID(env, g_popularityClass, "(I)V");
g_mapResultsMethod = jni::GetMethodID(env, g_javaListener, "onMapSearchResults",
"([Lapp/organicmaps/sdk/search/MapSearchListener$Result;JZ)V");
g_mapResultClass = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/search/MapSearchListener$Result");
g_mapResultCtor = jni::GetConstructorID(env, g_mapResultClass, "(Ljava/lang/String;Ljava/lang/String;)V");
g_updateBookmarksResultsId =
jni::GetMethodID(env, g_javaListener, "onBookmarkSearchResultsUpdate", "([JJ)V");
g_endBookmarksResultsId =
jni::GetMethodID(env, g_javaListener, "onBookmarkSearchResultsEnd", "([JJ)V");
}
JNIEXPORT jboolean JNICALL Java_app_organicmaps_sdk_search_SearchEngine_nativeRunSearch(
JNIEnv * env, jclass clazz, jbyteArray bytes, jboolean isCategory,
jstring lang, jlong timestamp, jboolean hasPosition, jdouble lat, jdouble lon)
{
search::EverywhereSearchParams params{
jni::ToNativeString(env, bytes),
jni::ToNativeString(env, lang),
{}, // default timeout
static_cast<bool>(isCategory),
bind(&OnResults, _1, _2, timestamp, false, hasPosition, lat, lon)
};
bool const searchStarted = g_framework->NativeFramework()->GetSearchAPI().SearchEverywhere(std::move(params));
if (searchStarted)
g_queryTimestamp = timestamp;
return searchStarted;
}
JNIEXPORT void JNICALL Java_app_organicmaps_sdk_search_SearchEngine_nativeRunInteractiveSearch(
JNIEnv * env, jclass clazz, jbyteArray bytes, jboolean isCategory,
jstring lang, jlong timestamp, jboolean isMapAndTable, jboolean hasPosition, jdouble lat, jdouble lon)
{
search::ViewportSearchParams vparams{
jni::ToNativeString(env, bytes),
jni::ToNativeString(env, lang),
{}, // Default timeout
static_cast<bool>(isCategory),
{}, // Empty m_onStarted callback
{}, // Empty m_onCompleted callback
};
// TODO (@alexzatsepin): set up vparams.m_onCompleted here and use
// HotelsClassifier for hotel queries detection.
// Don't move vparams here, because it's used below.
g_framework->NativeFramework()->GetSearchAPI().SearchInViewport(vparams);
if (isMapAndTable)
{
search::EverywhereSearchParams eparams{
std::move(vparams.m_query),
std::move(vparams.m_inputLocale),
{}, // default timeout
static_cast<bool>(isCategory),
bind(&OnResults, _1, _2, timestamp, isMapAndTable, hasPosition, lat, lon)
};
if (g_framework->NativeFramework()->GetSearchAPI().SearchEverywhere(std::move(eparams)))
g_queryTimestamp = timestamp;
}
}
JNIEXPORT void JNICALL Java_app_organicmaps_sdk_search_SearchEngine_nativeRunSearchMaps(
JNIEnv * env, jclass clazz, jbyteArray bytes, jstring lang, jlong timestamp)
{
storage::DownloaderSearchParams params{
jni::ToNativeString(env, bytes),
jni::ToNativeString(env, lang),
bind(&OnMapSearchResults, _1, timestamp)
};
if (g_framework->NativeFramework()->GetSearchAPI().SearchInDownloader(std::move(params)))
g_queryTimestamp = timestamp;
}
JNIEXPORT jboolean JNICALL Java_app_organicmaps_sdk_search_SearchEngine_nativeRunSearchInBookmarks(
JNIEnv * env, jclass clazz, jbyteArray query, jlong catId, jlong timestamp)
{
search::BookmarksSearchParams params{
jni::ToNativeString(env, query),
static_cast<kml::MarkGroupId>(catId),
bind(&OnBookmarksSearchResults, _1, _2, timestamp)
};
bool const searchStarted = g_framework->NativeFramework()->GetSearchAPI().SearchInBookmarks(std::move(params));
if (searchStarted)
g_queryTimestamp = timestamp;
return searchStarted;
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_search_SearchEngine_nativeShowResult(JNIEnv * env, jclass clazz, jint index)
{
g_framework->NativeFramework()->ShowSearchResult(g_results[index]);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_search_SearchEngine_nativeCancelInteractiveSearch(JNIEnv * env, jclass clazz)
{
g_framework->NativeFramework()->GetSearchAPI().CancelSearch(search::Mode::Viewport);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_search_SearchEngine_nativeCancelEverywhereSearch(JNIEnv * env, jclass clazz)
{
g_framework->NativeFramework()->GetSearchAPI().CancelSearch(search::Mode::Everywhere);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_search_SearchEngine_nativeCancelAllSearches(JNIEnv * env, jclass clazz)
{
g_framework->NativeFramework()->GetSearchAPI().CancelAllSearches();
}
} // extern "C"

View File

@@ -0,0 +1,37 @@
#include "app/organicmaps/sdk/Framework.hpp"
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/core/jni_java_methods.hpp"
#include "search/result.hpp"
using SearchRequest = search::QuerySaver::SearchRequest;
extern "C"
{
JNIEXPORT void JNICALL Java_app_organicmaps_sdk_search_SearchRecents_nativeGetList(JNIEnv * env, jclass, jobject result)
{
auto const & items = g_framework->NativeFramework()->GetSearchAPI().GetLastSearchQueries();
if (items.empty())
return;
auto const listAddMethod = jni::ListBuilder::Instance(env).m_add;
for (SearchRequest const & item : items)
{
jni::TScopedLocalRef str(env, jni::ToJavaString(env, item.second));
env->CallBooleanMethod(result, listAddMethod, str.get());
}
}
JNIEXPORT void JNICALL Java_app_organicmaps_sdk_search_SearchRecents_nativeAdd(JNIEnv * env, jclass, jstring locale,
jstring query)
{
SearchRequest const sr(jni::ToNativeString(env, locale), jni::ToNativeString(env, query));
g_framework->NativeFramework()->GetSearchAPI().SaveSearchQuery(sr);
}
JNIEXPORT void JNICALL Java_app_organicmaps_sdk_search_SearchRecents_nativeClear(JNIEnv * env, jclass)
{
g_framework->NativeFramework()->GetSearchAPI().ClearSearchHistory();
}
}

View File

@@ -0,0 +1,20 @@
#include "app/organicmaps/sdk/Framework.hpp"
#include "platform/settings.hpp"
#include "app/organicmaps/sdk/core/jni_helper.hpp"
extern "C"
{
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_settings_MapLanguageCode_setMapLanguageCode(JNIEnv * env, jobject, jstring languageCode)
{
g_framework->SetMapLanguageCode(jni::ToNativeString(env, languageCode));
}
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_settings_MapLanguageCode_getMapLanguageCode(JNIEnv * env, jobject)
{
return jni::ToJavaString(env, g_framework->GetMapLanguageCode());
}
}

View File

@@ -0,0 +1,23 @@
#include "app/organicmaps/sdk/Framework.hpp"
#include "platform/measurement_utils.hpp"
#include "platform/settings.hpp"
extern "C"
{
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_settings_UnitLocale_setCurrentUnits(JNIEnv * env, jobject thiz, jint units)
{
measurement_utils::Units const u = static_cast<measurement_utils::Units>(units);
settings::Set(settings::kMeasurementUnits, u);
g_framework->SetupMeasurementSystem();
}
JNIEXPORT jint JNICALL
Java_app_organicmaps_sdk_settings_UnitLocale_getCurrentUnits(JNIEnv * env, jobject thiz)
{
measurement_utils::Units u;
return static_cast<jint>(
settings::Get(settings::kMeasurementUnits, u) ? u : measurement_utils::Units::Metric);
}
}

View File

@@ -0,0 +1,30 @@
#include "app/organicmaps/sdk/Framework.hpp"
#include "app/organicmaps/sdk/core/jni_helper.hpp"
extern "C"
{
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_sound_TtsPlayer_nativeEnableTurnNotifications(JNIEnv *, jclass, jboolean enable)
{
return frm()->GetRoutingManager().EnableTurnNotifications(static_cast<bool>(enable));
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_sound_TtsPlayer_nativeAreTurnNotificationsEnabled(JNIEnv *, jclass)
{
return static_cast<jboolean>(frm()->GetRoutingManager().AreTurnNotificationsEnabled());
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_sound_TtsPlayer_nativeSetTurnNotificationsLocale(JNIEnv * env, jclass, jstring jLocale)
{
frm()->GetRoutingManager().SetTurnNotificationsLocale(jni::ToNativeString(env, jLocale));
}
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_sound_TtsPlayer_nativeGetTurnNotificationsLocale(JNIEnv * env, jclass)
{
return jni::ToJavaString(env, frm()->GetRoutingManager().GetTurnNotificationsLocale());
}
} // extern "C"

View File

@@ -0,0 +1,32 @@
#include <jni.h>
#include "app/organicmaps/sdk/Framework.hpp"
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/platform/AndroidPlatform.hpp"
extern "C"
{
static void TransitSchemeStateChanged(TransitReadManager::TransitSchemeState state,
std::shared_ptr<jobject> const & listener)
{
JNIEnv * env = jni::GetEnv();
env->CallVoidMethod(*listener,
jni::GetMethodID(env, *listener, "onTransitStateChanged", "(I)V"),
static_cast<jint>(state));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_maplayer_subway_SubwayManager_nativeAddListener(JNIEnv *env, jclass clazz, jobject listener)
{
CHECK(g_framework, ("Framework isn't created yet!"));
g_framework->SetTransitSchemeListener(std::bind(&TransitSchemeStateChanged,
std::placeholders::_1,
jni::make_global_ref(listener)));
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_maplayer_subway_SubwayManager_nativeRemoveListener(JNIEnv * env, jclass clazz)
{
CHECK(g_framework, ("Framework isn't created yet!"));
g_framework->SetTransitSchemeListener(TransitReadManager::TransitStateChangedFn());
}
}

View File

@@ -0,0 +1,126 @@
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/Framework.hpp"
#include "platform/settings.hpp"
extern "C"
{
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_util_Config_nativeHasConfigValue(JNIEnv * env, jclass thiz, jstring name)
{
std::string value;
return settings::Get(jni::ToNativeString(env, name), value);
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_util_Config_nativeDeleteConfigValue(JNIEnv * env, jclass thiz, jstring name)
{
settings::Delete(jni::ToNativeString(env, name));
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_util_Config_nativeGetBoolean(JNIEnv * env, jclass thiz, jstring name, jboolean defaultVal)
{
bool val;
if (settings::Get(jni::ToNativeString(env, name), val))
return static_cast<jboolean>(val);
return defaultVal;
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_util_Config_nativeSetBoolean(JNIEnv * env, jclass thiz, jstring name, jboolean val)
{
(void)settings::Set(jni::ToNativeString(env, name), static_cast<bool>(val));
}
JNIEXPORT jint JNICALL
Java_app_organicmaps_sdk_util_Config_nativeGetInt(JNIEnv * env, jclass thiz, jstring name, jint defaultValue)
{
int32_t value;
if (settings::Get(jni::ToNativeString(env, name), value))
return static_cast<jint>(value);
return defaultValue;
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_util_Config_nativeSetInt(JNIEnv * env, jclass thiz, jstring name, jint value)
{
(void)settings::Set(jni::ToNativeString(env, name), static_cast<int32_t>(value));
}
JNIEXPORT jlong JNICALL
Java_app_organicmaps_sdk_util_Config_nativeGetLong(JNIEnv * env, jclass thiz, jstring name, jlong defaultValue)
{
int64_t value;
if (settings::Get(jni::ToNativeString(env, name), value))
return static_cast<jlong>(value);
return defaultValue;
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_util_Config_nativeSetLong(JNIEnv * env, jclass thiz, jstring name, jlong value)
{
(void)settings::Set(jni::ToNativeString(env, name), static_cast<int64_t>(value));
}
JNIEXPORT jdouble JNICALL
Java_app_organicmaps_sdk_util_Config_nativeGetDouble(JNIEnv * env, jclass thiz, jstring name, jdouble defaultValue)
{
double value;
if (settings::Get(jni::ToNativeString(env, name), value))
return static_cast<jdouble>(value);
return defaultValue;
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_util_Config_nativeSetDouble(JNIEnv * env, jclass thiz, jstring name, jdouble value)
{
(void)settings::Set(jni::ToNativeString(env, name), static_cast<double>(value));
}
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_util_Config_nativeGetString(JNIEnv * env, jclass thiz, jstring name, jstring defaultValue)
{
std::string value;
if (settings::Get(jni::ToNativeString(env, name), value))
return jni::ToJavaString(env, value);
return defaultValue;
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_util_Config_nativeSetString(JNIEnv * env, jclass thiz, jstring name, jstring value)
{
(void)settings::Set(jni::ToNativeString(env, name), jni::ToNativeString(env, value));
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_util_Config_nativeGetLargeFontsSize(JNIEnv * env, jclass thiz)
{
return frm()->LoadLargeFontsSize();
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_util_Config_nativeSetLargeFontsSize(JNIEnv * env, jclass thiz,
jboolean value)
{
frm()->SetLargeFontsSize(value);
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_util_Config_nativeGetTransliteration(JNIEnv * env, jclass thiz)
{
return frm()->LoadTransliteration();
}
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_util_Config_nativeSetTransliteration(JNIEnv * env, jclass thiz,
jboolean value)
{
frm()->SaveTransliteration(value);
frm()->AllowTransliteration(value);
}
} // extern "C"

View File

@@ -0,0 +1,18 @@
#pragma once
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "platform/distance.hpp"
inline jobject ToJavaDistance(JNIEnv * env, platform::Distance const & distance)
{
static jclass const distanceClass = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/util/Distance");
static jmethodID const distanceConstructor = jni::GetConstructorID(env, distanceClass, "(DLjava/lang/String;B)V");
jobject distanceObject = env->NewObject(
distanceClass, distanceConstructor,
distance.GetDistance(), jni::ToJavaString(env, distance.GetDistanceString()), static_cast<uint8_t>(distance.GetUnits()));
return distanceObject;
}

View File

@@ -0,0 +1,32 @@
#pragma once
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "indexer/feature_decl.hpp"
class FeatureIdBuilder
{
public:
explicit FeatureIdBuilder(JNIEnv * env)
{
jclass clazz = env->FindClass("app/organicmaps/sdk/bookmarks/data/FeatureId");
m_countryName = env->GetFieldID(clazz, "mMwmName", "Ljava/lang/String;");
ASSERT(m_countryName, ());
m_index = env->GetFieldID(clazz, "mFeatureIndex", "I");
ASSERT(m_index, ());
}
FeatureID Build(JNIEnv * env, jobject obj) const
{
jstring jcountryName = static_cast<jstring>(env->GetObjectField(obj, m_countryName));
jint jindex = env->GetIntField(obj, m_index);
auto const & ds = g_framework->GetDataSource();
auto const id = ds.GetMwmIdByCountryFile(platform::CountryFile(jni::ToNativeString(env, jcountryName)));
return FeatureID(id, static_cast<uint32_t>(jindex));
}
private:
jfieldID m_countryName;
jfieldID m_index;
};

View File

@@ -0,0 +1,17 @@
#include "android/sdk/src/main/cpp/app/organicmaps/sdk/core/jni_helper.hpp"
#include "geometry/mercator.hpp"
extern "C"
{
JNIEXPORT jobject JNICALL
Java_app_organicmaps_sdk_util_GeoUtils_nativeToLatLon(
JNIEnv * env, jobject thiz, jdouble mercX, jdouble mercY)
{
auto const mercPoint = m2::PointD(static_cast<double>(mercX), static_cast<double>(mercY));
auto const latLon = mercator::ToLatLon(mercPoint);
auto const latlonPoint = m2::PointD(latLon.m_lat, latLon.m_lon);
return jni::GetNewParcelablePointD(env, latlonPoint);
}
}

View File

@@ -0,0 +1,265 @@
/*******************************************************************************
The MIT License (MIT)
Copyright (c) 2015 Alexander Borsuk <me@alex.bio> from Minsk, Belarus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*******************************************************************************/
#include <jni.h>
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/core/ScopedEnv.hpp"
#include "app/organicmaps/sdk/core/ScopedLocalRef.hpp"
#include "platform/http_client.hpp"
#include "base/assert.hpp"
#include "base/exception.hpp"
#include "base/logging.hpp"
#include <string>
#include <iterator>
#include <unordered_map>
DECLARE_EXCEPTION(JniException, RootException);
namespace
{
void RethrowOnJniException(ScopedEnv & env)
{
if (!env->ExceptionCheck())
return;
env->ExceptionDescribe();
env->ExceptionClear();
MYTHROW(JniException, ());
}
jfieldID GetHttpParamsFieldId(ScopedEnv & env, const char * name,
const char * signature = "Ljava/lang/String;")
{
return env->GetFieldID(g_httpParamsClazz, name, signature);
}
// Set string value to HttpClient.Params object, throws JniException and
void SetString(ScopedEnv & env, jobject params, jfieldID const fieldId, std::string const & value)
{
if (value.empty())
return;
jni::ScopedLocalRef<jstring> const wrappedValue(env.get(), jni::ToJavaString(env.get(), value));
RethrowOnJniException(env);
env->SetObjectField(params, fieldId, wrappedValue.get());
RethrowOnJniException(env);
}
void SetBoolean(ScopedEnv & env, jobject params, jfieldID const fieldId, bool const value)
{
env->SetBooleanField(params, fieldId, value);
RethrowOnJniException(env);
}
void SetInt(ScopedEnv & env, jobject params, jfieldID const fieldId, int const value)
{
env->SetIntField(params, fieldId, value);
RethrowOnJniException(env);
}
// Get string value from HttpClient.Params object, throws JniException.
void GetString(ScopedEnv & env, jobject const params, jfieldID const fieldId, std::string & result)
{
jni::ScopedLocalRef<jstring> const wrappedValue(
env.get(), static_cast<jstring>(env->GetObjectField(params, fieldId)));
RethrowOnJniException(env);
if (wrappedValue)
result = jni::ToNativeString(env.get(), wrappedValue.get());
}
void GetInt(ScopedEnv & env, jobject const params, jfieldID const fieldId, int & result)
{
result = env->GetIntField(params, fieldId);
RethrowOnJniException(env);
}
void SetHeaders(ScopedEnv & env, jobject const params, platform::HttpClient::Headers const & headers)
{
if (headers.empty())
return;
static jmethodID const setHeaders = env->GetMethodID(
g_httpParamsClazz, "setHeaders", "([Lapp/organicmaps/sdk/util/KeyValue;)V");
RethrowOnJniException(env);
jni::TScopedLocalObjectArrayRef jHeaders(env.get(), jni::ToKeyValueArray(env.get(), headers));
env->CallVoidMethod(params, setHeaders, jHeaders.get());
RethrowOnJniException(env);
}
void LoadHeaders(ScopedEnv & env, jobject const params, platform::HttpClient::Headers & headers)
{
static jmethodID const getHeaders =
env->GetMethodID(g_httpParamsClazz, "getHeaders", "()[Ljava/lang/Object;");
jni::ScopedLocalRef<jobjectArray> const headersArray(
env.get(), static_cast<jobjectArray>(env->CallObjectMethod(params, getHeaders)));
RethrowOnJniException(env);
headers.clear();
jni::ToNativekeyValueContainer(env.get(), headersArray, std::inserter(headers, headers.end()));
RethrowOnJniException(env);
}
class Ids
{
public:
explicit Ids(ScopedEnv & env)
{
m_fieldIds =
{{"httpMethod", GetHttpParamsFieldId(env, "httpMethod")},
{"inputFilePath", GetHttpParamsFieldId(env, "inputFilePath")},
{"outputFilePath", GetHttpParamsFieldId(env, "outputFilePath")},
{"cookies", GetHttpParamsFieldId(env, "cookies")},
{"receivedUrl", GetHttpParamsFieldId(env, "receivedUrl")},
{"followRedirects", GetHttpParamsFieldId(env, "followRedirects", "Z")},
{"loadHeaders", GetHttpParamsFieldId(env, "loadHeaders", "Z")},
{"httpResponseCode", GetHttpParamsFieldId(env, "httpResponseCode", "I")},
{"timeoutMillisec", GetHttpParamsFieldId(env, "timeoutMillisec", "I")}};
}
jfieldID GetId(std::string const & fieldName) const
{
auto const it = m_fieldIds.find(fieldName);
CHECK(it != m_fieldIds.end(), ("Incorrect field name:", fieldName));
return it->second;
}
private:
std::unordered_map<std::string, jfieldID> m_fieldIds;
};
} // namespace
//***********************************************************************
// Exported functions implementation
//***********************************************************************
namespace platform
{
bool HttpClient::RunHttpRequest()
{
ScopedEnv env(jni::GetJVM());
if (!env)
return false;
static Ids ids(env);
// Create and fill request params.
jni::ScopedLocalRef<jstring> const jniUrl(env.get(),
jni::ToJavaString(env.get(), m_urlRequested));
if (jni::HandleJavaException(env.get()))
return false;
static jmethodID const httpParamsConstructor =
jni::GetConstructorID(env.get(), g_httpParamsClazz, "(Ljava/lang/String;)V");
jni::ScopedLocalRef<jobject> const httpParamsObject(
env.get(), env->NewObject(g_httpParamsClazz, httpParamsConstructor, jniUrl.get()));
if (jni::HandleJavaException(env.get()))
return false;
// Cache it on the first call.
static jfieldID const dataField = env->GetFieldID(g_httpParamsClazz, "data", "[B");
if (!m_bodyData.empty())
{
jni::ScopedLocalRef<jbyteArray> const jniPostData(
env.get(), env->NewByteArray(static_cast<jsize>(m_bodyData.size())));
if (jni::HandleJavaException(env.get()))
return false;
env->SetByteArrayRegion(jniPostData.get(), 0, static_cast<jsize>(m_bodyData.size()),
reinterpret_cast<const jbyte *>(m_bodyData.data()));
if (jni::HandleJavaException(env.get()))
return false;
env->SetObjectField(httpParamsObject.get(), dataField, jniPostData.get());
if (jni::HandleJavaException(env.get()))
return false;
}
ASSERT(!m_httpMethod.empty(), ("Http method type can not be empty."));
try
{
SetString(env, httpParamsObject.get(), ids.GetId("httpMethod"), m_httpMethod);
SetString(env, httpParamsObject.get(), ids.GetId("inputFilePath"), m_inputFile);
SetString(env, httpParamsObject.get(), ids.GetId("outputFilePath"), m_outputFile);
SetString(env, httpParamsObject.get(), ids.GetId("cookies"), m_cookies);
SetBoolean(env, httpParamsObject.get(), ids.GetId("followRedirects"), m_followRedirects);
SetBoolean(env, httpParamsObject.get(), ids.GetId("loadHeaders"), m_loadHeaders);
SetInt(env, httpParamsObject.get(), ids.GetId("timeoutMillisec"),
static_cast<int>(m_timeoutSec * 1000));
SetHeaders(env, httpParamsObject.get(), m_headers);
}
catch (JniException const & ex)
{
return false;
}
static jmethodID const httpClientClassRun =
env->GetStaticMethodID(g_httpClientClazz, "run",
"(Lapp/organicmaps/sdk/util/HttpClient$Params;)Lapp/organicmaps/sdk/util/HttpClient$Params;");
jni::ScopedLocalRef<jobject> const response(env.get(), env->CallStaticObjectMethod(g_httpClientClazz,
httpClientClassRun, httpParamsObject.get()));
if (jni::HandleJavaException(env.get()))
return false;
try
{
GetInt(env, response.get(), ids.GetId("httpResponseCode"), m_errorCode);
GetString(env, response.get(), ids.GetId("receivedUrl"), m_urlReceived);
::LoadHeaders(env, httpParamsObject.get(), m_headers);
}
catch (JniException const & ex)
{
return false;
}
// dataField is already cached above.
jni::ScopedLocalRef<jbyteArray> const jniData(
env.get(), static_cast<jbyteArray>(env->GetObjectField(response, dataField)));
if (jni::HandleJavaException(env.get()))
return false;
if (jniData)
{
jbyte * buffer = env->GetByteArrayElements(jniData.get(), nullptr);
if (buffer)
{
m_serverResponse.assign(reinterpret_cast<const char *>(buffer), env->GetArrayLength(jniData.get()));
env->ReleaseByteArrayElements(jniData.get(), buffer, JNI_ABORT);
}
}
return true;
}
} // namespace platform

View File

@@ -0,0 +1,12 @@
#include "android/sdk/src/main/cpp/app/organicmaps/sdk/core/jni_helper.hpp"
#include "platform/preferred_languages.hpp"
extern "C"
{
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_util_Language_nativeNormalize(JNIEnv *env, jclass type, jstring lang)
{
std::string locale = languages::Normalize(jni::ToNativeString(env, lang));
return jni::ToJavaString(env, locale);
}
}

View File

@@ -0,0 +1,11 @@
#include <jni.h>
#include "app/organicmaps/sdk/core/logging.hpp"
extern "C" {
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_util_log_LogsManager_nativeToggleCoreDebugLogs(
JNIEnv * /*env*/, jclass /*clazz*/, jboolean enabled)
{
jni::ToggleDebugLogs(enabled);
}
} // extern "C"

View File

@@ -0,0 +1,18 @@
#include "app/organicmaps/sdk/core/jni_helper.hpp"
namespace network_policy
{
bool GetNetworkPolicyStatus(JNIEnv * env, jobject obj)
{
static jmethodID const networkPolicyCanUseMethod =
jni::GetMethodID(env, obj, "canUseNetwork", "()Z");
return env->CallBooleanMethod(obj, networkPolicyCanUseMethod);
}
bool GetCurrentNetworkUsageStatus(JNIEnv * env)
{
static jmethodID const method =
jni::GetStaticMethodID(env, g_networkPolicyClazz, "getCurrentNetworkUsageStatus", "()Z");
return env->CallStaticBooleanMethod(g_networkPolicyClazz, method);
}
} // namespace network_policy

View File

@@ -0,0 +1,7 @@
#pragma once
namespace network_policy
{
bool GetNetworkPolicyStatus(JNIEnv * env, jobject obj);
bool GetCurrentNetworkUsageStatus(JNIEnv * env);
}

View File

@@ -0,0 +1,91 @@
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/core/jni_java_methods.hpp"
#include "app/organicmaps/sdk/util/Distance.hpp"
#include "indexer/search_string_utils.hpp"
#include "platform/localization.hpp"
#include "platform/measurement_utils.hpp"
#include "platform/settings.hpp"
#include <string>
namespace
{
jobject MakeJavaPair(JNIEnv * env, std::string const & first, std::string const & second)
{
return jni::PairBuilder::Instance(env).Create(env, jni::ToJavaString(env, first), jni::ToJavaString(env, second));
}
} // namespace
extern "C"
{
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_util_StringUtils_nativeIsHtml(JNIEnv * env, jclass thiz, jstring text)
{
return strings::IsHTML(jni::ToNativeString(env, text));
}
JNIEXPORT jboolean JNICALL
Java_app_organicmaps_sdk_util_StringUtils_nativeContainsNormalized(JNIEnv * env, jclass thiz, jstring str, jstring substr)
{
return search::ContainsNormalized(jni::ToNativeString(env, str), jni::ToNativeString(env, substr));
}
JNIEXPORT jobjectArray JNICALL
Java_app_organicmaps_sdk_util_StringUtils_nativeFilterContainsNormalized(JNIEnv * env, jclass thiz, jobjectArray src, jstring jSubstr)
{
std::string const substr = jni::ToNativeString(env, jSubstr);
int const length = env->GetArrayLength(src);
std::vector<std::string> filtered;
filtered.reserve(length);
for (int i = 0; i < length; i++)
{
std::string const str = jni::ToNativeString(env, static_cast<jstring>(env->GetObjectArrayElement(src, i)));
if (search::ContainsNormalized(str, substr))
filtered.push_back(str);
}
return jni::ToJavaStringArray(env, filtered);
}
JNIEXPORT jint JNICALL Java_app_organicmaps_sdk_util_StringUtils_nativeFormatSpeed(
JNIEnv * env, jclass thiz, jdouble metersPerSecond)
{
return measurement_utils::FormatSpeed(metersPerSecond, measurement_utils::GetMeasurementUnits());
}
JNIEXPORT jobject JNICALL Java_app_organicmaps_sdk_util_StringUtils_nativeFormatSpeedAndUnits(
JNIEnv * env, jclass thiz, jdouble metersPerSecond)
{
auto const units = measurement_utils::GetMeasurementUnits();
return MakeJavaPair(env, measurement_utils::FormatSpeedNumeric(metersPerSecond, units),
platform::GetLocalizedSpeedUnits(units));
}
JNIEXPORT jobject JNICALL
Java_app_organicmaps_sdk_util_StringUtils_nativeFormatDistance(JNIEnv * env, jclass, jdouble distanceInMeters)
{
return ToJavaDistance(env, platform::Distance::CreateFormatted(distanceInMeters));
}
JNIEXPORT jobject JNICALL
Java_app_organicmaps_sdk_util_StringUtils_nativeGetLocalizedDistanceUnits(JNIEnv * env, jclass)
{
auto const localizedUnits = platform::GetLocalizedDistanceUnits();
return MakeJavaPair(env, localizedUnits.m_high, localizedUnits.m_low);
}
JNIEXPORT jobject JNICALL
Java_app_organicmaps_sdk_util_StringUtils_nativeGetLocalizedAltitudeUnits(JNIEnv * env, jclass)
{
auto const localizedUnits = platform::GetLocalizedAltitudeUnits();
return MakeJavaPair(env, localizedUnits.m_high, localizedUnits.m_low);
}
JNIEXPORT jstring JNICALL
Java_app_organicmaps_sdk_util_StringUtils_nativeGetLocalizedSpeedUnits(JNIEnv * env, jclass)
{
return jni::ToJavaString(env, platform::GetLocalizedSpeedUnits());
}
} // extern "C"

View File

@@ -0,0 +1,12 @@
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/platform/GuiThread.hpp"
extern "C"
{
// static void nativeProcessTask(long taskPointer);
JNIEXPORT void JNICALL
Java_app_organicmaps_sdk_util_concurrency_UiThread_nativeProcessTask(JNIEnv * env, jclass clazz, jlong taskPointer)
{
android::GuiThread::ProcessTask(taskPointer);
}
}

View File

@@ -0,0 +1,125 @@
#include "android_vulkan_context_factory.hpp"
#include "app/organicmaps/sdk/platform/AndroidPlatform.hpp"
#include "base/assert.hpp"
#include "base/logging.hpp"
#include "base/macros.hpp"
#include "base/src_point.hpp"
namespace android
{
AndroidVulkanContextFactory::AndroidVulkanContextFactory(uint32_t appVersionCode, int sdkVersion, bool isCustomROM)
: dp::vulkan::VulkanContextFactory(appVersionCode, sdkVersion, isCustomROM)
{}
void AndroidVulkanContextFactory::SetSurface(JNIEnv * env, jobject jsurface)
{
if (!jsurface)
{
LOG_ERROR_VK("Java surface is not found.");
return;
}
m_nativeWindow = ANativeWindow_fromSurface(env, jsurface);
if (!m_nativeWindow)
{
LOG_ERROR_VK("Can't get native window from Java surface.");
return;
}
SetVulkanSurface();
}
void AndroidVulkanContextFactory::SetVulkanSurface()
{
if (m_windowSurfaceValid)
return;
VkAndroidSurfaceCreateInfoKHR createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.window = m_nativeWindow;
VkResult statusCode;
statusCode = vkCreateAndroidSurfaceKHR(m_vulkanInstance, &createInfo, nullptr,
&m_surface);
if (statusCode != VK_SUCCESS)
{
LOG_ERROR_VK_CALL(vkCreateAndroidSurfaceKHR, statusCode);
return;
}
uint32_t const renderingQueueIndex = m_drawContext->GetRenderingQueueFamilyIndex();
VkBool32 supportsPresent;
statusCode = vkGetPhysicalDeviceSurfaceSupportKHR(m_gpu, renderingQueueIndex, m_surface, &supportsPresent);
if (statusCode != VK_SUCCESS)
{
LOG_ERROR_VK_CALL(vkGetPhysicalDeviceSurfaceSupportKHR, statusCode);
return;
}
CHECK_EQUAL(supportsPresent, VK_TRUE, ());
CHECK(QuerySurfaceSize(), ());
if (m_drawContext)
m_drawContext->SetSurface(m_surface, m_surfaceFormat, m_surfaceCapabilities);
m_windowSurfaceValid = true;
}
void AndroidVulkanContextFactory::ResetSurface(bool allowPipelineDump)
{
ResetVulkanSurface(allowPipelineDump);
if (m_nativeWindow != nullptr)
{
ANativeWindow_release(m_nativeWindow);
m_nativeWindow = nullptr;
}
}
void AndroidVulkanContextFactory::ResetVulkanSurface(bool allowPipelineDump)
{
if (!m_windowSurfaceValid)
return;
if (m_drawContext)
m_drawContext->ResetSurface(allowPipelineDump);
vkDestroySurfaceKHR(m_vulkanInstance, m_surface, nullptr);
m_surface = 0;
m_windowSurfaceValid = false;
}
void AndroidVulkanContextFactory::ChangeSurface(JNIEnv * env, jobject jsurface, int w, int h)
{
if (w == m_surfaceWidth && m_surfaceHeight == h)
return;
auto nativeWindow = ANativeWindow_fromSurface(env, jsurface);
if (m_nativeWindow == nullptr)
{
CHECK(!m_windowSurfaceValid, ());
m_nativeWindow = nativeWindow;
}
else
{
ResetVulkanSurface(false /* allowPipelineDump */);
if (nativeWindow != m_nativeWindow)
{
ANativeWindow_release(m_nativeWindow);
m_nativeWindow = nativeWindow;
}
}
SetVulkanSurface();
LOG(LINFO, ("Surface changed", m_surfaceWidth, m_surfaceHeight));
}
bool AndroidVulkanContextFactory::IsValid() const
{
return IsVulkanSupported() && m_windowSurfaceValid;
}
} // namespace android

View File

@@ -0,0 +1,32 @@
#pragma once
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "drape/vulkan/vulkan_context_factory.hpp"
#include <vulkan/vulkan_android.h>
#include <android/native_window.h>
#include <android/native_window_jni.h>
namespace android
{
class AndroidVulkanContextFactory : public dp::vulkan::VulkanContextFactory
{
public:
AndroidVulkanContextFactory(uint32_t appVersionCode, int sdkVersion, bool isCustomROM);
bool IsValid() const;
void SetSurface(JNIEnv * env, jobject jsurface);
void ResetSurface(bool allowPipelineDump);
void ChangeSurface(JNIEnv * env, jobject jsurface, int w, int h);
private:
void SetVulkanSurface();
void ResetVulkanSurface(bool allowPipelineDump);
ANativeWindow * m_nativeWindow = nullptr;
bool m_windowSurfaceValid = false;
};
} // namespace android