Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 13:58:55 +01:00
parent 4af19165ec
commit 68073add76
12458 changed files with 12350765 additions and 2 deletions

3
android/sdk/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
.cxx
build
nativeOutputs

163
android/sdk/build.gradle Normal file
View file

@ -0,0 +1,163 @@
plugins {
id 'com.android.library'
}
android {
namespace = 'app.organicmaps.sdk'
compileSdk = propCompileSdkVersion.toInteger()
ndkVersion = '28.2.13676358'
buildFeatures {
buildConfig = true
}
defaultConfig {
minSdk = propMinSdkVersion.toInteger()
targetSdk = propTargetSdkVersion.toInteger()
externalNativeBuild {
def pchFlag = 'OFF'
if (project.hasProperty('pch')) pchFlag = 'ON'
def njobs = ''
if (project.hasProperty('njobs')) njobs = project.getProperty('njobs')
def enableVulkanDiagnostics = 'OFF'
if (project.hasProperty('enableVulkanDiagnostics')) {
enableVulkanDiagnostics = project.getProperty('enableVulkanDiagnostics')
}
def enableTrace = 'OFF'
if (project.hasProperty('enableTrace')) {
enableTrace = project.getProperty('enableTrace')
}
cmake {
cppFlags '-fexceptions', '-frtti'
// There is no sense to enable sections without gcc's --gc-sections flag.
cFlags '-fno-function-sections', '-fno-data-sections',
'-Wno-extern-c-compat'
arguments '-DANDROID_TOOLCHAIN=clang', '-DANDROID_STL=c++_static',
'-DSKIP_TESTS=ON', '-DSKIP_TOOLS=ON', "-DUSE_PCH=$pchFlag",
"-DNJOBS=$njobs", "-DENABLE_VULKAN_DIAGNOSTICS=$enableVulkanDiagnostics",
"-DENABLE_TRACE=$enableTrace"
targets 'organicmaps'
}
}
// Use, for example, -Parm32 gradle parameter to build only for armeabi-v7a.
ndk {
abiFilters = new HashSet<>()
if (project.hasProperty('arm32') || project.hasProperty('armeabi-v7a')) {
abiFilters.add('armeabi-v7a')
}
if (project.hasProperty('arm64') || project.hasProperty('arm64-v8a')) {
abiFilters.add('arm64-v8a')
}
if (project.hasProperty('x86')) {
abiFilters.add('x86')
}
if (project.hasProperty('x86_64') || project.hasProperty('x64')) {
abiFilters.add('x86_64')
}
if (abiFilters.isEmpty()) {
abiFilters.add('armeabi-v7a')
abiFilters.add('arm64-v8a')
// For the emulator, chromebooks and some Intel Atom devices.
abiFilters.add('x86_64')
}
println('Building for ' + abiFilters + ' archs.')
}
}
buildTypes {
debug {
jniDebuggable true // Enable jni debug build
}
release {
// minifyEnabled true
// proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
beta {
// minifyEnabled true
// proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
matchingFallbacks = ['release']
}
}
externalNativeBuild {
cmake {
version = '3.22.1+'
buildStagingDirectory './nativeOutputs'
path '../../CMakeLists.txt'
}
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
lint {
disable 'MissingTranslation'
// https://github.com/organicmaps/organicmaps/issues/3551
disable 'MissingQuantity', 'UnusedQuantity'
// https://github.com/organicmaps/organicmaps/issues/3550
disable 'ByteOrderMark'
// https://github.com/organicmaps/organicmaps/issues/1077
disable 'CustomSplashScreen'
// https://github.com/organicmaps/organicmaps/issues/3610
disable 'InsecureBaseConfiguration'
abortOnError = true
}
}
dependencies {
coreLibraryDesugaring libs.android.tools.desugar
implementation libs.androidx.core
implementation libs.androidx.annotation
implementation libs.androidx.fragment
implementation libs.androidx.lifecycle.process
implementation libs.androidx.media
implementation libs.androidx.recyclerview
implementation libs.android.material
testImplementation libs.junit
}
// TODO: Running lint task triggers native build. Find a better solution.
project.afterEvaluate {
boolean isLintRun = project.gradle.startParameter.taskNames.any { it.toLowerCase().contains('lint') }
if (isLintRun) {
tasks.findAll { task ->
(task.name.startsWith('Native') || task.name.contains('CMake')) &&
task.project == project
}.each { nativeTask ->
logger.warn("Disabling task ${nativeTask.path} because lint is running.")
nativeTask.onlyIf { false }
}
}
final taskName = gradle.startParameter.taskNames
if (['assemble', 'bundle', 'compile', 'install', 'run'].any{taskName.any{task->task.startsWith(it)}}) {
exec {
workingDir '../..'
if (!taskName.toString().contains('Google')) {
environment 'SKIP_MAP_DOWNLOAD', '1'
}
commandLine './configure.sh'
}
}
}
tasks.withType(JavaCompile).configureEach {
options.compilerArgs << '-Xlint:unchecked' << '-Xlint:deprecation'
}

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:installLocation="auto">
<!-- Requiring "android.hardware.touchscreen" here breaks DeX mode -->
<uses-feature
android:glEsVersion="0x00030000"
android:required="true" />
<uses-feature
android:name="android.hardware.wifi"
android:required="false" />
<uses-feature
android:name="android.hardware.location"
android:required="false" />
<uses-feature
android:name="android.hardware.location.network"
android:required="false" />
<uses-feature
android:name="android.hardware.location.gps"
android:required="false" />
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="22" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>

View file

@ -0,0 +1 @@
../../../../../data/categories.txt

View file

@ -0,0 +1 @@
../../../../../data/categories_brands.txt

View file

@ -0,0 +1 @@
../../../../../data/categories_cuisines.txt

View file

@ -0,0 +1 @@
../../../../../data/classificator.txt

View file

@ -0,0 +1 @@
../../../../../data/colors.txt

View file

@ -0,0 +1 @@
../../../../../data/countries-strings

View file

@ -0,0 +1 @@
../../../../../data/countries.txt

View file

@ -0,0 +1 @@
../../../../../data/drules_proto_default_dark.bin

View file

@ -0,0 +1 @@
../../../../../data/drules_proto_default_light.bin

View file

@ -0,0 +1 @@
../../../../../data/drules_proto_outdoors_dark.bin

View file

@ -0,0 +1 @@
../../../../../data/drules_proto_outdoors_light.bin

View file

@ -0,0 +1 @@
../../../../../data/drules_proto_vehicle_dark.bin

View file

@ -0,0 +1 @@
../../../../../data/drules_proto_vehicle_light.bin

View file

@ -0,0 +1 @@
../../../../../data/editor.config

View file

@ -0,0 +1 @@
../../../../../data/fonts

View file

@ -0,0 +1 @@
../../../../../data/icudt75l.dat

View file

@ -0,0 +1 @@
../../../../../data/languages.txt

View file

@ -0,0 +1 @@
../../../../../data/packed_polygons.bin

View file

@ -0,0 +1 @@
../../../../../data/patterns.txt

View file

@ -0,0 +1 @@
../../../../../data/sound-strings

View file

@ -0,0 +1 @@
../../../../../data/symbols

View file

@ -0,0 +1 @@
../../../../../data/transit_colors.txt

View file

@ -0,0 +1 @@
../../../../../data/types.txt

View file

@ -0,0 +1 @@
../../../../../data/vulkan_shaders

View file

@ -0,0 +1,140 @@
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/LaneInfo.cpp
app/organicmaps/sdk/routing/LaneInfo.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/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/bookmarks/data/Icon.cpp
app/organicmaps/sdk/bookmarks/data/Icon.hpp
app/organicmaps/sdk/bookmarks/data/PredefinedColors.cpp
app/organicmaps/sdk/bookmarks/data/PredefinedColors.hpp
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,180 @@
#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,213 @@
#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/graphics_context_factory.hpp"
#include "drape/pointers.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(bool restoreViewport);
// 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);
};
} // namespace android
extern std::unique_ptr<android::Framework> g_framework;
::Framework * frm();

View file

@ -0,0 +1,87 @@
#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,165 @@
#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,590 @@
#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,55 @@
#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_safe(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,50 @@
#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,250 @@
#include "UserMarkHelper.hpp"
#include "app/organicmaps/sdk/routing/RoutePointInfo.hpp"
#include "app/organicmaps/sdk/util/Distance.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 CreateTrack(JNIEnv * env, place_page::Info const & info, jni::TScopedLocalObjectArrayRef const & jrawTypes,
jni::TScopedLocalRef const & routingPointInfo, jobject const & popularity)
{
static jmethodID const ctorId =
jni::GetConstructorID(env, g_trackClazz,
"(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;ILapp/organicmaps/sdk/util/Distance;DD)V");
static jmethodID const featureCtorId = jni::GetConstructorID(env, g_featureIdClazz, "(Ljava/lang/String;JI)V");
auto const trackId = info.GetTrackId();
auto const track = frm()->GetBookmarkManager().GetTrack(trackId);
jint androidColor = track->GetColor(0).GetARGB();
auto const categoryId = track->GetGroupId();
ms::LatLon const ll = info.GetLatLon();
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::ToJavaString(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_trackClazz, ctorId, jFeatureId.get(), static_cast<jlong>(categoryId),
static_cast<jlong>(trackId), jTitle.get(), jSecondaryTitle.get(), jSubtitle.get(), jAddress.get(),
routingPointInfo.get(), info.GetOpeningMode(), popularity, jWikiDescription.get(), jrawTypes.get(),
androidColor, ToJavaDistance(env, platform::Distance::CreateFormatted(track->GetLengthMeters())),
static_cast<jdouble>(ll.m_lat), static_cast<jdouble>(ll.m_lon));
if (info.HasMetadata())
InjectMetadata(env, g_mapObjectClazz, mapObject, info);
return mapObject;
}
jobject CreateBookmark(JNIEnv * env, place_page::Info const & info, jni::TScopedLocalObjectArrayRef const & jrawTypes,
jni::TScopedLocalRef const & 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, double latitude, double longitude)
static jmethodID const pointCtorId = jni::GetConstructorID(env, pointClass, "(DIDD)V");
return env->NewObject(
pointClass, pointCtorId, static_cast<jdouble>(point.m_distance), static_cast<jint>(point.m_point.GetAltitude()),
static_cast<jdouble>(point.m_point.GetPoint().x), static_cast<jdouble>(point.m_point.GetPoint().y));
}
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(@NonNull Point[] points, int difficulty);
static jmethodID const ctorId =
jni::GetConstructorID(env, g_elevationInfoClazz, "([Lapp/organicmaps/sdk/bookmarks/data/ElevationInfo$Point;I)V");
jni::TScopedLocalObjectArrayRef jPoints(env, ToElevationPointArray(env, info.GetPoints()));
return env->NewObject(g_elevationInfoClazz, ctorId, jPoints.get(), 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());
}
if (info.IsTrack())
return CreateTrack(env, info, jrawTypes, routingPointInfo, popularity);
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,49 @@
#pragma once
#include <jni.h>
#include "app/organicmaps/sdk/Framework.hpp"
#include "app/organicmaps/sdk/core/jni_helper.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 kTrack = 5;
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 CreateTrack(JNIEnv * env, place_page::Info const & info, jni::TScopedLocalObjectArrayRef const & jrawTypes,
jni::TScopedLocalRef const & routingPointInfo, jobject const & popularity);
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,898 @@
#include "app/organicmaps/sdk/Framework.hpp"
#include "app/organicmaps/sdk/UserMarkHelper.hpp"
#include "app/organicmaps/sdk/core/jni_helper.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>(kml::kColorIndexMap[E2I(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 void JNICALL Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeUpdateTrackPlacePage(JNIEnv * env,
jobject)
{
if (!frm()->HasPlacePageInfo())
return;
frm()->UpdatePlacePageInfoForCurrentSelection();
}
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));
return env->NewObject(trackClazz, cId, trackId, static_cast<jlong>(nTrack->GetGroupId()),
jni::ToJavaString(env, nTrack->GetName()),
ToJavaDistance(env, platform::Distance::CreateFormatted(nTrack->GetLengthMeters())),
nTrack->GetColor(0).GetARGB());
}
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>(kml::kColorIndexMap[E2I(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 = kml::kOrderedPredefinedColors[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, jdouble latitude, jdouble longitude)
{
auto & bm = frm()->GetBookmarkManager();
bm.SetElevationActivePoint(static_cast<kml::TrackId>(trackId), {latitude, longitude},
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();
}
JNIEXPORT jobject JNICALL Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetTrackElevationInfo(
JNIEnv * env, jclass clazz, jlong track_id)
{
auto const & track = frm()->GetBookmarkManager().GetTrack(track_id);
auto const & elevationInfo = track->GetElevationInfo();
return track->GetElevationInfo().has_value() ? usermark_helper::CreateElevationInfo(env, elevationInfo.value())
: nullptr;
}
JNIEXPORT jobject JNICALL Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetTrackStatistics(
JNIEnv * env, jclass clazz, jlong track_id)
{
static jmethodID const cId = jni::GetConstructorID(env, g_trackStatisticsClazz, "(DDDDII)V");
auto const trackStats = frm()->GetBookmarkManager().GetTrack(track_id)->GetStatistics();
return env->NewObject(g_trackStatisticsClazz, cId, trackStats.m_length, trackStats.m_duration, trackStats.m_ascent,
trackStats.m_descent, trackStats.m_minElevation, static_cast<jint>(trackStats.m_maxElevation));
}
JNIEXPORT jobject JNICALL
Java_app_organicmaps_sdk_bookmarks_data_BookmarkManager_nativeGetElevationActivePointCoordinates(JNIEnv * env,
jclass clazz,
jlong track_id)
{
static jclass const pointClass =
jni::GetGlobalClassRef(env, "app/organicmaps/sdk/bookmarks/data/ElevationInfo$Point");
static jmethodID const pointCtorId = jni::GetConstructorID(env, pointClass, "(DIDD)V");
auto const & trackInfo = frm()->GetBookmarkManager().GetTrackSelectionInfo(track_id);
auto const latlon = mercator::ToLatLon(trackInfo.m_trackPoint);
return env->NewObject(pointClass, pointCtorId, 0.0, 0, latlon.m_lat, latlon.m_lon);
}
} // extern "C"

View file

@ -0,0 +1,37 @@
#include <jni.h>
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "kml/types.hpp"
extern "C"
{
JNIEXPORT jobjectArray JNICALL Java_app_organicmaps_sdk_bookmarks_data_Icon_nativeGetBookmarkIconNames(JNIEnv * env,
jclass)
{
std::vector<std::string> icons;
for (uint16_t i = 0; i < static_cast<uint16_t>(kml::BookmarkIcon::Count); ++i)
icons.emplace_back(kml::DebugPrint(static_cast<kml::BookmarkIcon>(i)));
return jni::ToJavaStringArray(env, icons);
}
}
namespace
{
JNINativeMethod const iconMethods[] = {
{"nativeGetBookmarkIconNames", "()[Ljava/lang/String;",
reinterpret_cast<void *>(&Java_app_organicmaps_sdk_bookmarks_data_Icon_nativeGetBookmarkIconNames)},
};
}
namespace icon
{
jint registerNativeMethods(JNIEnv * env)
{
jclass clazz = env->FindClass("app/organicmaps/sdk/bookmarks/data/Icon");
if (clazz == nullptr)
return JNI_ERR;
return env->RegisterNatives(clazz, iconMethods, std::size(iconMethods));
}
} // namespace icon

View file

@ -0,0 +1,8 @@
#pragma once
#include <jni.h>
namespace icon
{
jint registerNativeMethods(JNIEnv * env);
} // namespace icon

View file

@ -0,0 +1,41 @@
#include "PredefinedColors.hpp"
#include "kml/types.hpp"
#include <array>
extern "C"
{
JNIEXPORT jintArray JNICALL
Java_app_organicmaps_sdk_bookmarks_data_PredefinedColors_nativeGetPredefinedColors(JNIEnv * env, jclass)
{
using kml::kOrderedPredefinedColors;
std::array<jint, kOrderedPredefinedColors.size()> colors;
for (size_t i = 0; i < kOrderedPredefinedColors.size(); ++i)
colors[i] = static_cast<jint>(kml::ColorFromPredefinedColor(kOrderedPredefinedColors[i]).GetARGB());
jintArray jColors = env->NewIntArray(colors.size());
env->SetIntArrayRegion(jColors, 0, static_cast<jsize>(colors.size()), colors.data());
return jColors;
}
}
namespace
{
JNINativeMethod const predefinedColorsMethods[] = {
{"nativeGetPredefinedColors", "()[I",
reinterpret_cast<void *>(&Java_app_organicmaps_sdk_bookmarks_data_PredefinedColors_nativeGetPredefinedColors)},
};
}
namespace predefined_colors
{
jint registerNativeMethods(JNIEnv * env)
{
jclass clazz = env->FindClass("app/organicmaps/sdk/bookmarks/data/PredefinedColors");
if (clazz == nullptr)
return JNI_ERR;
return env->RegisterNatives(clazz, predefinedColorsMethods, std::size(predefinedColorsMethods));
}
} // namespace predefined_colors

View file

@ -0,0 +1,8 @@
#pragma once
#include <jni.h>
namespace predefined_colors
{
jint registerNativeMethods(JNIEnv * env);
} // namespace predefined_colors

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,39 @@
#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,359 @@
#include "jni_helper.hpp"
#include "ScopedLocalRef.hpp"
#include "logging.hpp"
#include "base/assert.hpp"
#include "base/exception.hpp"
#include "base/string_utils.hpp"
#include "app/organicmaps/sdk/bookmarks/data/Icon.hpp"
#include "app/organicmaps/sdk/bookmarks/data/PredefinedColors.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_trackClazz;
jclass g_trackStatisticsClazz;
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 IsAndroidApiLowerThan(int apiLevel)
{
char value[92] = {0};
if (__system_property_get("ro.build.version.sdk", value) < 1)
return false;
int const deviceApiLevel = atoi(value);
if (deviceApiLevel > 0 && deviceApiLevel < apiLevel)
return true;
return false;
}
static bool const g_isAndroidLowerThan12 = IsAndroidApiLowerThan(30);
static bool const g_isAndroidLowerThan7 = g_isAndroidLowerThan12 && IsAndroidApiLowerThan(24);
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_trackClazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/bookmarks/data/Track");
g_trackStatisticsClazz = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/bookmarks/data/TrackStatistics");
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");
if (g_isAndroidLowerThan12)
{
if (predefined_colors::registerNativeMethods(env) != JNI_OK)
return JNI_ERR;
if (icon::registerNativeMethods(env) != JNI_OK)
return JNI_ERR;
}
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_trackClazz);
env->DeleteGlobalRef(g_trackStatisticsClazz);
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 * GetEnvSafe()
{
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));
env = nullptr;
}
return env;
}
JNIEnv * GetEnv()
{
JNIEnv * env = GetEnvSafe();
if (env == nullptr)
MYTHROW(RootException, ("Can't get JNIEnv. Is the thread attached to JVM?"));
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 (auto const c : s)
{
if (0b11110000 == (c & 0b11111000))
{
auto const 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;
});
}
// https://github.com/organicmaps/organicmaps/issues/9397
/// @todo There are no other ideas, let's try a safe version with a forever global ref ..
std::shared_ptr<jobject> make_global_ref_safe(jobject obj)
{
jobject * ref = new jobject(GetEnv()->NewGlobalRef(obj));
return std::shared_ptr<jobject>(ref, [](jobject * ref)
{
JNIEnv * env = GetEnvSafe();
if (env)
env->DeleteGlobalRef(*ref);
delete ref;
});
}
std::string ToNativeString(JNIEnv * env, jthrowable const & 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, jthrowable const & 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_trackClazz;
extern jclass g_trackStatisticsClazz;
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, jthrowable const & e);
std::shared_ptr<jobject> make_global_ref(jobject obj);
std::shared_ptr<jobject> make_global_ref_safe(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,41 @@
#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/ScopedEnv.hpp"
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/core/logging.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;
}
} // namespace jni

View file

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

View file

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

View file

@ -0,0 +1,16 @@
#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();
};
} // namespace android

View file

@ -0,0 +1,596 @@
#include <jni.h>
#include "app/organicmaps/sdk/Framework.hpp"
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "editor/osm_editor.hpp"
#include "indexer/cuisines.hpp"
#include "indexer/editable_map_object.hpp"
#include "indexer/feature_charge_sockets.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 jobjectArray JNICALL Java_app_organicmaps_sdk_editor_Editor_nativeGetChargeSockets(JNIEnv * env, jclass)
{
auto sockets = g_editableMapObject.GetChargeSockets();
jclass descClass = env->FindClass("app/organicmaps/sdk/bookmarks/data/ChargeSocketDescriptor");
jmethodID ctor = env->GetMethodID(descClass, "<init>", "(Ljava/lang/String;ID)V");
// Create a Java array
jobjectArray result = env->NewObjectArray(sockets.size(), descClass, nullptr);
for (size_t i = 0; i < sockets.size(); ++i)
{
auto const & s = sockets[i];
jstring jType = env->NewStringUTF(s.type.c_str());
jobject jDesc = env->NewObject(descClass, ctor, jType, (jint)s.count, (jdouble)s.power);
env->SetObjectArrayElement(result, i, jDesc);
env->DeleteLocalRef(jType);
env->DeleteLocalRef(jDesc);
}
return result;
}
JNIEXPORT void JNICALL Java_app_organicmaps_sdk_editor_Editor_nativeSetChargeSockets(JNIEnv * env, jclass,
jobjectArray jSockets)
{
ChargeSocketsHelper chargeSockets;
jsize len = env->GetArrayLength(jSockets);
jclass descClass = env->FindClass("app/organicmaps/sdk/bookmarks/data/ChargeSocketDescriptor");
jfieldID fidType = env->GetFieldID(descClass, "type", "Ljava/lang/String;");
jfieldID fidCount = env->GetFieldID(descClass, "count", "I");
jfieldID fidPower = env->GetFieldID(descClass, "power", "D");
for (jsize i = 0; i < len; ++i)
{
jobject jDesc = env->GetObjectArrayElement(jSockets, i);
jstring jType = (jstring)env->GetObjectField(jDesc, fidType);
char const * cType = env->GetStringUTFChars(jType, nullptr);
jint count = env->GetIntField(jDesc, fidCount);
jdouble power = env->GetDoubleField(jDesc, fidPower);
chargeSockets.AddSocket(cType, static_cast<unsigned int>(count), static_cast<double>(power));
env->ReleaseStringUTFChars(jType, cType);
env->DeleteLocalRef(jType);
env->DeleteLocalRef(jDesc);
}
g_editableMapObject.SetChargeSockets(chargeSockets.ToString());
}
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_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_nativeCanMarkPlaceAsDisused(JNIEnv * env,
jclass clazz)
{
return g_editableMapObject.CanMarkPlaceAsDisused();
}
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));
}
JNIEXPORT void JNICALL Java_app_organicmaps_sdk_editor_Editor_nativeCreateStandaloneNote(JNIEnv * env, jclass clazz,
jdouble lat, jdouble lon,
jstring text)
{
osm::Editor::Instance().CreateStandaloneNote(ms::LatLon(lat, lon), 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 void JNICALL Java_app_organicmaps_sdk_editor_Editor_nativeMarkPlaceAsDisused(JNIEnv * env, jclass clazz)
{
g_framework->NativeFramework()->MarkPlaceAsDisused(g_editableMapObject);
}
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_nativeCheckHouseNumberWhenIsAddress(JNIEnv * env,
jclass clazz)
{
return g_editableMapObject.CheckHouseNumberWhenIsAddress();
}
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,335 @@
#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 jclass const 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/sdk/editor/OhState");
jclass ruleStateClass = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/editor/OhState$State");
static std::unordered_map<RuleState, char const *> const ruleState = {
{RuleState::Open, "Open"}, {RuleState::Closed, "Closed"}, {RuleState::Unknown, "Unknown"}};
jfieldID stateField =
env->GetStaticFieldID(ruleStateClass, ruleState.at(ohInfo.state), "Lapp/organicmaps/sdk/editor/OhState$State;");
jobject stateObj = env->GetStaticObjectField(ruleStateClass, stateField);
jmethodID constructor = env->GetMethodID(ohStateClass, "<init>", "(Lapp/organicmaps/sdk/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,92 @@
#include <jni.h>
#include "app/organicmaps/sdk/Framework.hpp"
#include "app/organicmaps/sdk/core/jni_helper.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_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,42 @@
#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,79 @@
#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,40 @@
#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,105 @@
#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()
{
static EGLint contextAttrList[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
return contextAttrList;
}
AndroidOGLContext::AndroidOGLContext(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());
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,41 @@
#pragma once
#include "drape/gl_includes.hpp"
#include "drape/oglcontext.hpp"
#include <atomic>
namespace android
{
class AndroidOGLContext : public dp::OGLContext
{
public:
AndroidOGLContext(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,346 @@
#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
namespace android
{
namespace
{
static EGLint * getConfigAttributesListRGB8()
{
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_ES3_BIT,
EGL_SURFACE_TYPE,
EGL_PBUFFER_BIT | EGL_WINDOW_BIT,
EGL_NONE};
return attr_list;
}
int const kMaxConfigCount = 40;
bool IsSupportedRGB8(EGLDisplay display)
{
EGLConfig configs[kMaxConfigCount];
int count = 0;
return eglChooseConfig(display, getConfigAttributesListRGB8(), 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_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(gl3stubInit(), ("Could not initialize OpenGL ES3"));
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_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_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(), configs, kMaxConfigCount, &count) == EGL_TRUE)
{
CHECK(IsSupportedRGB8(m_display), ("RGB8 is not suported on this device"));
LOG(LDEBUG, ("Backbuffer format: RGB8"));
}
else
{
CHECK(false, ("OpenGL ES3 is not supported"));
}
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, ());
GLuint const 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,63 @@
#pragma once
#include "androidoglcontext.hpp"
#include "app/organicmaps/sdk/core/jni_helper.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);
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_isInitialized = false;
size_t m_initializationCounter = 0;
std::condition_variable m_initializationCondition;
std::mutex m_initializationMutex;
};
} // namespace android

View file

@ -0,0 +1,304 @@
/*
* 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,
GLvoid const * 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,
GLvoid const * 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,
GLvoid const * 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,
GLvoid const * 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, GLvoid const * data);
GL_APICALL void (*GL_APIENTRY glGenQueries)(GLsizei n, GLuint * ids);
GL_APICALL void (*GL_APIENTRY glDeleteQueries)(GLsizei n, GLuint const * 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, GLenum const * bufs);
GL_APICALL void (*GL_APIENTRY glUniformMatrix2x3fv)(GLint location, GLsizei count, GLboolean transpose,
GLfloat const * value);
GL_APICALL void (*GL_APIENTRY glUniformMatrix3x2fv)(GLint location, GLsizei count, GLboolean transpose,
GLfloat const * value);
GL_APICALL void (*GL_APIENTRY glUniformMatrix2x4fv)(GLint location, GLsizei count, GLboolean transpose,
GLfloat const * value);
GL_APICALL void (*GL_APIENTRY glUniformMatrix4x2fv)(GLint location, GLsizei count, GLboolean transpose,
GLfloat const * value);
GL_APICALL void (*GL_APIENTRY glUniformMatrix3x4fv)(GLint location, GLsizei count, GLboolean transpose,
GLfloat const * value);
GL_APICALL void (*GL_APIENTRY glUniformMatrix4x3fv)(GLint location, GLsizei count, GLboolean transpose,
GLfloat const * 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, GLuint const * 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,
GLchar const * 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,
GLvoid const * 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, GLint const * v);
GL_APICALL void (*GL_APIENTRY glVertexAttribI4uiv)(GLuint index, GLuint const * v);
GL_APICALL void (*GL_APIENTRY glGetUniformuiv)(GLuint program, GLint location, GLuint * params);
GL_APICALL GLint (*GL_APIENTRY glGetFragDataLocation)(GLuint program, GLchar const * 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, GLuint const * value);
GL_APICALL void (*GL_APIENTRY glUniform2uiv)(GLint location, GLsizei count, GLuint const * value);
GL_APICALL void (*GL_APIENTRY glUniform3uiv)(GLint location, GLsizei count, GLuint const * value);
GL_APICALL void (*GL_APIENTRY glUniform4uiv)(GLint location, GLsizei count, GLuint const * value);
GL_APICALL void (*GL_APIENTRY glClearBufferiv)(GLenum buffer, GLint drawbuffer, GLint const * value);
GL_APICALL void (*GL_APIENTRY glClearBufferuiv)(GLenum buffer, GLint drawbuffer, GLuint const * value);
GL_APICALL void (*GL_APIENTRY glClearBufferfv)(GLenum buffer, GLint drawbuffer, GLfloat const * 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,
GLchar const * const * uniformNames, GLuint * uniformIndices);
GL_APICALL void (*GL_APIENTRY glGetActiveUniformsiv)(GLuint program, GLsizei uniformCount,
GLuint const * uniformIndices, GLenum pname, GLint * params);
GL_APICALL GLuint (*GL_APIENTRY glGetUniformBlockIndex)(GLuint program, GLchar const * 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, GLvoid const * 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, GLuint const * 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, GLint const * param);
GL_APICALL void (*GL_APIENTRY glSamplerParameterf)(GLuint sampler, GLenum pname, GLfloat param);
GL_APICALL void (*GL_APIENTRY glSamplerParameterfv)(GLuint sampler, GLenum pname, GLfloat const * 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, GLuint const * 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, GLvoid const * 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,
GLenum const * attachments);
GL_APICALL void (*GL_APIENTRY glInvalidateSubFramebuffer)(GLenum target, GLsizei numAttachments,
GLenum const * 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,255 @@
#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 platform
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,55 @@
#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,99 @@
#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,68 @@
#include "android/sdk/src/main/cpp/app/organicmaps/sdk/core/ScopedLocalRef.hpp"
#include "android/sdk/src/main/cpp/app/organicmaps/sdk/core/jni_helper.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,72 @@
#include <jni.h>
#include "app/organicmaps/sdk/core/ScopedLocalRef.hpp"
#include "app/organicmaps/sdk/core/jni_helper.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,93 @@
#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<jbyte const *>(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>();
}
} // namespace platform

View file

@ -0,0 +1,19 @@
#pragma once
#include "app/organicmaps/sdk/core/jni_helper.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 const & ll = pointWithAltitude.ToLatLon();
return env->NewObject(junctionClazz, junctionConstructor, ll.m_lat, ll.m_lon);
});
}

View file

@ -0,0 +1,50 @@
#include "LaneInfo.hpp"
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include <vector>
namespace
{
jobject ToJavaLaneWay(JNIEnv * env, routing::turns::lanes::LaneWay const & laneWay)
{
static jclass const laneWayClass = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/routing/LaneWay");
jfieldID fieldID =
env->GetStaticFieldID(laneWayClass, DebugPrint(laneWay).c_str(), "Lapp/organicmaps/sdk/routing/LaneWay;");
return env->GetStaticObjectField(laneWayClass, fieldID);
}
} // namespace
jobjectArray CreateLanesInfo(JNIEnv * env, routing::turns::lanes::LanesInfo const & lanes)
{
if (lanes.empty())
return nullptr;
static jclass const laneWayClass = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/routing/LaneWay");
static jclass const laneInfoClass = jni::GetGlobalClassRef(env, "app/organicmaps/sdk/routing/LaneInfo");
auto const lanesSize = static_cast<jsize>(lanes.size());
jobjectArray jLanes = env->NewObjectArray(lanesSize, laneInfoClass, nullptr);
ASSERT(jLanes, (jni::DescribeException()));
// Java signature : LaneInfo(LaneWay[] laneWays, LaneWay activeLane)
static jmethodID const ctorLaneInfoID = jni::GetConstructorID(
env, laneInfoClass, "([Lapp/organicmaps/sdk/routing/LaneWay;Lapp/organicmaps/sdk/routing/LaneWay;)V");
for (jsize j = 0; j < lanesSize; ++j)
{
auto const laneWays = lanes[j].laneWays.GetActiveLaneWays();
auto const laneWaysSize = static_cast<jsize>(laneWays.size());
jni::TScopedLocalObjectArrayRef jLaneWays(env, env->NewObjectArray(laneWaysSize, laneWayClass, nullptr));
ASSERT(jLanes, (jni::DescribeException()));
for (jsize i = 0; i < laneWaysSize; ++i)
{
jni::TScopedLocalRef jLaneWay(env, ToJavaLaneWay(env, laneWays[i]));
env->SetObjectArrayElement(jLaneWays.get(), i, jLaneWay.get());
}
jni::TScopedLocalRef jLaneInfo(env, env->NewObject(laneInfoClass, ctorLaneInfoID, jLaneWays.get(),
ToJavaLaneWay(env, lanes[j].recommendedWay)));
ASSERT(jLaneInfo.get(), (jni::DescribeException()));
env->SetObjectArrayElement(jLanes, j, jLaneInfo.get());
}
return jLanes;
}

View file

@ -0,0 +1,7 @@
#pragma once
#include <jni.h>
#include "routing/lanes/lane_info.hpp"
jobjectArray CreateLanesInfo(JNIEnv * env, routing::turns::lanes::LanesInfo const & lanes);

View file

@ -0,0 +1,27 @@
#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,36 @@
#pragma once
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/routing/LaneInfo.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, LaneInfo[] lanes, double speedLimitMps, boolean speedLimitExceeded,
// boolean shouldPlayWarningSignal)
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/LaneInfo;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,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,26 @@
#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,22 @@
#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,366 @@
#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();
}
JNIEXPORT void JNICALL Java_app_organicmaps_sdk_search_SearchEngine_nativeUpdateViewportWithLastResults(JNIEnv * env,
jclass clazz)
{
g_framework->NativeFramework()->UpdateViewport(g_results);
}
} // 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,19 @@
#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,21 @@
#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,49 @@
#include "app/organicmaps/sdk/Framework.hpp"
#include "app/organicmaps/sdk/core/jni_helper.hpp"
#include "app/organicmaps/sdk/core/jni_java_methods.hpp"
#include "platform/languages.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());
}
JNIEXPORT jobject JNICALL Java_app_organicmaps_sdk_sound_TtsPlayer_nativeGetSupportedLanguages(JNIEnv * env, jclass)
{
auto const & supportedLanguages = routing::turns::sound::kLanguageList;
auto const & listBuilder = jni::ListBuilder::Instance(env);
jobject const list = listBuilder.CreateArray(env, supportedLanguages.size());
for (auto const & [lang, name] : supportedLanguages)
{
jni::TScopedLocalRef const jLangString(env, jni::ToJavaString(env, lang));
jni::TScopedLocalRef const jNameString(env, jni::ToJavaString(env, name));
jni::TScopedLocalRef const pair(env,
jni::PairBuilder::Instance(env).Create(env, jLangString.get(), jNameString.get()));
env->CallBooleanMethod(list, listBuilder.m_add, pair.get());
}
return list;
}
} // extern "C"

View file

@ -0,0 +1,31 @@
#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,122 @@
#include "app/organicmaps/sdk/Framework.hpp"
#include "app/organicmaps/sdk/core/jni_helper.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;
};

Some files were not shown because too many files have changed in this diff Show more