Merge pull request #2449 from mapsme/new-search

New search into master.
This commit is contained in:
Lev Dragunov 2016-03-23 19:31:02 +04:00
commit b7c2a29903
4143 changed files with 10934130 additions and 3267609 deletions

View file

@ -8,6 +8,7 @@ IndentWidth: 2
Language: Cpp
AccessModifierOffset: -2
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: true
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false

1
.gitignore vendored
View file

@ -129,4 +129,5 @@ private.h
tools/android/mapswithme.keystore
tools/android/yota.keystore
android/secure.properties
android/fabric.properties
server

View file

@ -7,7 +7,7 @@ TEMPLATE = subdirs
CONFIG *= desktop
}
SUBDIRS = freetype fribidi minizip jansson tomcrypt protobuf osrm expat succinct pugixml
SUBDIRS = freetype fribidi minizip jansson tomcrypt protobuf osrm expat succinct pugixml liboauthcpp
# TODO(mgsrergio): Move opening hours out of 3party to the main project tree.
# See https://trello.com/c/tWYSnXSS/22-opening-hours-3party-boost-test-framework.

View file

@ -19,6 +19,7 @@ SOURCES += \
src/error.c \
src/strconv.c \
jansson_handle.cpp \
myjansson.cpp \
HEADERS += \
myjansson.hpp \

View file

@ -0,0 +1,84 @@
#include "3party/jansson/myjansson.hpp"
namespace my
{
void FromJSON(json_t * root, string & result)
{
if (!json_is_string(root))
MYTHROW(my::Json::Exception, ("The field must contain a json string."));
result = string(json_string_value(root));
}
void FromJSONObject(json_t * root, string const & field, string & result)
{
if (!json_is_object(root))
MYTHROW(my::Json::Exception, ("Bad json object when parsing", field));
json_t * val = json_object_get(root, field.c_str());
if (!val)
MYTHROW(my::Json::Exception, ("Obligatory field", field, "is absent."));
if (!json_is_string(val))
MYTHROW(my::Json::Exception, ("The field", field, "must contain a json string."));
result = string(json_string_value(val));
}
void FromJSONObject(json_t * root, string const & field, strings::UniString & result)
{
string s;
FromJSONObject(root, field, s);
result = strings::MakeUniString(s);
}
void FromJSONObject(json_t * root, string const & field, double & result)
{
if (!json_is_object(root))
MYTHROW(my::Json::Exception, ("Bad json object when parsing", field));
json_t * val = json_object_get(root, field.c_str());
if (!val)
MYTHROW(my::Json::Exception, ("Obligatory field", field, "is absent."));
if (!json_is_number(val))
MYTHROW(my::Json::Exception, ("The field", field, "must contain a json number."));
result = json_number_value(val);
}
void FromJSONObject(json_t * root, string const & field, json_int_t & result)
{
if (!json_is_object(root))
MYTHROW(my::Json::Exception, ("Bad json object when parsing", field));
json_t * val = json_object_get(root, field.c_str());
if (!val)
MYTHROW(my::Json::Exception, ("Obligatory field", field, "is absent."));
if (!json_is_number(val))
MYTHROW(my::Json::Exception, ("The field", field, "must contain a json number."));
result = json_integer_value(val);
}
void FromJSONObjectOptionalField(json_t * root, string const & field, string & result)
{
if (!json_is_object(root))
MYTHROW(my::Json::Exception, ("Bad json object when parsing", field));
json_t * val = json_object_get(root, field.c_str());
if (!val)
{
result.clear();
return;
}
if (!json_is_string(val))
MYTHROW(my::Json::Exception, ("The field", field, "must contain a json string."));
result = string(json_string_value(val));
}
void FromJSONObjectOptionalField(json_t * root, string const & field, json_int_t & result)
{
if (!json_is_object(root))
MYTHROW(my::Json::Exception, ("Bad json object when parsing", field));
json_t * val = json_object_get(root, field.c_str());
if (!val)
{
result = 0;
return;
}
if (!json_is_number(val))
MYTHROW(my::Json::Exception, ("The field", field, "must contain a json number."));
result = json_integer_value(val);
}
} // namespace my

View file

@ -3,13 +3,14 @@
#include "jansson_handle.hpp"
#include "base/exception.hpp"
#include "base/string_utils.hpp"
#include <jansson.h>
#include "std/vector.hpp"
namespace my
{
class Json
{
JsonHandle m_handle;
@ -28,4 +29,44 @@ public:
json_t * get() const { return m_handle.get(); }
};
void FromJSON(json_t * root, string & result);
inline void FromJSON(json_t * root, json_t *& value) { value = root; }
void FromJSONObject(json_t * root, string const & field, string & result);
void FromJSONObject(json_t * root, string const & field, strings::UniString & result);
void FromJSONObject(json_t * root, string const & field, double & result);
void FromJSONObject(json_t * root, string const & field, json_int_t & result);
template <typename T>
void FromJSONObject(json_t * root, string const & field, vector<T> & result)
{
json_t * arr = json_object_get(root, field.c_str());
if (!arr)
MYTHROW(my::Json::Exception, ("Obligatory field", field, "is absent."));
if (!json_is_array(arr))
MYTHROW(my::Json::Exception, ("The field", field, "must contain a json array."));
size_t sz = json_array_size(arr);
result.resize(sz);
for (size_t i = 0; i < sz; ++i)
FromJSON(json_array_get(arr, i), result[i]);
}
void FromJSONObjectOptionalField(json_t * root, string const & field, string & result);
void FromJSONObjectOptionalField(json_t * root, string const & field, json_int_t & result);
template <typename T>
void FromJSONObjectOptionalField(json_t * root, string const & field, vector<T> & result)
{
json_t * arr = json_object_get(root, field.c_str());
if (!arr)
{
result.clear();
return;
}
if (!json_is_array(arr))
MYTHROW(my::Json::Exception, ("The field", field, "must contain a json array."));
size_t sz = json_array_size(arr);
result.resize(sz);
for (size_t i = 0; i < sz; ++i)
FromJSON(json_array_get(arr, i), result[i]);
}
} // namespace my

9
3party/liboauthcpp/.gitignore vendored Normal file
View file

@ -0,0 +1,9 @@
# Build (by)products
build/CMakeCache.txt
build/CMakeFiles
build/Makefile
build/cmake_install.cmake
build/liboauthcpp.a
build/simple_auth
build/simple_request
build/tests

View file

@ -0,0 +1,21 @@
Copyright (c) 2011 Stanford University (liboauthcpp)
Copyright (C) 2011 by swatkat (swatkat.thinkdigitATgmailDOTcom) (libtwitcurl)
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,172 @@
liboauthcpp
-----------
liboauthcpp is a pure C++ library for performing OAuth requests. It
doesn't contain any networking code -- you provide for performing HTTP
requests yourself, however you like -- instead focusing on performing
OAuth-specific functionality and providing a nice interface for it.
If you already have infrastructure for making HTTP requests and are
looking to add OAuth support, liboauthcpp is for you.
liboauthcpp currently implements OAuth 1.0a (see
http://tools.ietf.org/html/rfc5849).
Buildbot
--------
[![Build Status](https://secure.travis-ci.org/sirikata/liboauthcpp.png)](http://travis-ci.org/sirikata/liboauthcpp)
Requirements
------------
You should only need:
* CMake
* A C++ compiler for your platform (e.g. g++, Microsoft Visual C++)
Compiling
---------
The build process is simple:
cd liboauthcpp
cd build
cmake .
make # or open Visual Studio and build the solution
If your own project uses CMake you can also include
build/CMakeLists.txt directly into your project and reference the
target "oauthcpp", a static library, in your project.
Percent (URL) Encoding
----------------------
To get correct results, you need to pass your URL properly encoded to
liboauthcpp. If you are not at all familiar, you should probably start
by reading the [URI Spec](http://tools.ietf.org/html/rfc3986), especially
Section 2. Alternatively,
[this article](http://blog.lunatech.com/2009/02/03/what-every-web-developer-must-know-about-url-encoding)
gives a more readable overview.
The basic idea is that there are 3 classes of characters: reserved,
unreserved, and other. Reserved characters are special characters that
are used in the URI syntax itself, e.g. ':' (after the scheme), '/'
(the hierarchical path separator), and '?' (prefixing the query
string). Unreserved characters are characters that are always safe to
include unencoded, e.g. the alphanumerics. Other characters must
always be encoded, mainly covering special characters like ' ', '<' or
'>', and '{' or '}'.
The basic rule is that reserved characters must be encoded if they
appear in any part of the URI when not being used as a
separator. Unreserved characters are always safe. And the other
characters they didn't know if they would be safe or not so they must
always be encoded.
Unfortunately, the reserved set is a bit more complicated. They are
broken down into 'general delimiters' and 'sub delimiters'. The ones
already mentioned, like ':', can appear in many forms of URIs (say,
http, ftp, about, gopher, mailto, etc. Those are called general
delimiters. Others (e.g. '(', ')', '!', '$', '+', ',', '=', and more)
are called subdelimiters because their use depends on the URI
scheme. Worse, their use depends on the *part of the URI*. Depending
on the particular URI scheme, these may or may not have to be encoded,
and it might also depend on where they appear. (As an example, an '&'
in an http URI isn't an issue if it appears in the path -- before the
query string -- i.e. before a '?' appears. Worse, '=' can appear unencoded in
the path, or in a query parameter value, but not in a query parameter key since
it would be interpreted as the end of the key.)
*Additionally*, in many cases it is permitted to encode a character
unnecessarily and the result is supposed to be the same. This means
that it's possible to percent encode some URLs in multiple ways
(e.g. encoding the unreserved set unnecessarily). It is possible, but not
guaranteed, that if you pass *exactly* the same URI to liboauthcpp and the
OAuth server, it will handle it regardless of the variant of encoding, so long
as it is a valid encoding.
The short version: percent encoding a URL properly is non-trivial and
you can even encode the same URL multiple ways, but has to be done
correctly so that the OAuth signature can be computed. Sadly,
"correctly" in this case really means "in whatever way the server your
interacting with wants it encoded".
Internally, liboauthcpp needs to do another step of percent encoding,
but the OAuth spec is very precise about how that works (none of these
scheme-dependent issues). liboauth applies this percent encoding, but
assumes that you have encoded your URLs properly. This assumption
makes sense since the actual request is made separately, and the URI
has to be specified in it, so you should already have a form which the
server will accept.
However, in order to aid you, a very simple percent encoding API is exposed. It
should help you encode URLs minimally and in a way that many services accept. In
most cases you should use `HttpPercentEncodePath()`,
`HttpPercentEncodeQueryKey()`, and `HttpPercentEncodeQueryValue()` to encode
those parts of your http URL, then combine them and pass them to liboauthcpp for
signing.
Thread Safety
-------------
liboauthcpp doesn't provide any thread safety guarantees. That said, there is
very little shared state, and some classes (e.g. Consumer) are naturally
immutable and therefore thread safe. Similarly, nearly the entire library uses
no static/shared state, so as long as you create separate objects for separate
threads, you should be safe.
The one exception is nonces: the Client class needs to generate a nonce for
authorization. To do so, the random number generator needs to be seeded. We do
this with the current time, but fast, repeated use of the Client class from
different threads could result in the same nonce. To avoid requiring an entire
thread library just for this one case, you can call Client::initialize()
explicitly before using the Client from multiple threads. For single-threaded
use, you are not required to call it.
Demos
-----
There are two demos included in the demos/ directory, and they are built by
default with the instructions above. In both, you enter key/secret information
and it generates URLs for you to visit (in a browser) and copy data back into
the program.
simple_auth should be executed first. It starts with only a consumer key and
secret and performs 3-legged auth: you enter in consumer keys, it generates URLs
to authenticate the user and generate access tokens. It requires 3 steps:
request_token, authorize, and access_token (which correspond the URLs
accessed). At the end of this process, you'll be provided an access key/secret
pair which you can use to access actual resources.
simple_request actually does something useful now that your application is
authorized. Enter your consumer key/secret and the access key/secret from
simple_auth (or which you've generated elsewhere) and it will generate a URL you
can use to access your home timeline in JSON format. It adds a parameter to ask
for only 5 entries (demonstrating that signing works properly over additional
query parameters). This is a one-step process -- it just gives you the URL and
you get the results in your browser.
In both, the URLs accessed are specified at the top of the demo
files. simple_auth requires URLs for request_token, authorize_url, and
access_token. Some providers require additional parameters (notably an
oauth_callback for Twitter, even if its out of band, or oob), which you can also
specify in that location. simple_request only needs the URL of the resource
being accessed (i.e. the URL for the home_timeline JSON data used by default in
the demo), with optional parameters stored as a query string.
Both demos only use GET requests with query strings, but all HTTP methods
(e.g. POST, PUT, DELETE) and approaches to sending parameters (e.g. HTTP
headers, url-encoded body) should be supported in the API.
License
-------
liboauthcpp is MIT licensed. See the LICENSE file for more details.
liboauthcpp is mostly taken from libtwitcurl
(http://code.google.com/p/twitcurl/), which is similarly licensed. It
mostly serves to isolate the OAuth code from libtwitcurl's Twitter and
cURL specific code.
libtwitcurl also borrowed code from other projects:
twitcurl uses HMAC_SHA1 from http://www.codeproject.com/KB/recipes/HMACSHA1class.aspx
twitcurl uses base64 from http://www.adp-gmbh.ch/cpp/common/base64.html

View file

@ -0,0 +1,286 @@
#ifndef __LIBOAUTHCPP_LIBOAUTHCPP_H__
#define __LIBOAUTHCPP_LIBOAUTHCPP_H__
#include <string>
#include <list>
#include <map>
#include <stdexcept>
#include <ctime>
namespace OAuth {
namespace Http {
typedef enum _RequestType
{
Invalid = 0,
Head,
Get,
Post,
Delete,
Put
} RequestType;
} // namespace Http
typedef std::list<std::string> KeyValueList;
typedef std::multimap<std::string, std::string> KeyValuePairs;
typedef enum _LogLevel
{
LogLevelNone = 0,
LogLevelDebug = 1
} LogLevel;
/** Set the log level. Log messages are sent to stderr. Currently, and for the
* foreseeable future, logging only consists of debug messages to help track
* down protocol implementation issues.
*/
void SetLogLevel(LogLevel lvl);
/** Deprecated. Complete percent encoding of URLs. Equivalent to
* PercentEncode.
*/
std::string URLEncode(const std::string& decoded);
/** Percent encode a string value. This version is *thorough* about
* encoding: it encodes all reserved characters (even those safe in
* http URLs) and "other" characters not specified by the URI
* spec. If you're looking to encode http:// URLs, see the
* HttpEncode* functions.
*/
std::string PercentEncode(const std::string& decoded);
/** Percent encodes the path portion of an http URL (i.e. the /foo/bar
* in http://foo/bar?a=1&b=2). This encodes minimally, so reserved
* subdelimiters that have no meaning in the path are *not* encoded.
*/
std::string HttpEncodePath(const std::string& decoded);
/** Percent encodes a query string key in an http URL (i.e. 'a', 'b' in
* http://foo/bar?a=1&b=2). This encodes minimally, so reserved subdelimiters
* that have no meaning in the query string are *not* encoded.
*/
std::string HttpEncodeQueryKey(const std::string& decoded);
/** Percent encodes a query string value in an http URL (i.e. '1', '2' in
* http://foo/bar?a=1&b=2). This encodes minimally, so reserved subdelimiters
* that have no meaning in the query string are *not* encoded.
*/
std::string HttpEncodeQueryValue(const std::string& decoded);
/** Parses key value pairs into a map.
* \param encoded the encoded key value pairs, i.e. the url encoded parameters
* \returns a map of string keys to string values
* \throws ParseError if the encoded data cannot be decoded
*/
KeyValuePairs ParseKeyValuePairs(const std::string& encoded);
class ParseError : public std::runtime_error {
public:
ParseError(const std::string msg)
: std::runtime_error(msg)
{}
};
class MissingKeyError : public std::runtime_error {
public:
MissingKeyError(const std::string msg)
: std::runtime_error(msg)
{}
};
/** A consumer of OAuth-protected services. It is the client to an
* OAuth service provider and is usually registered with the service
* provider, resulting in a consumer *key* and *secret* used to
* identify the consumer. The key is included in all requests and the
* secret is used to *sign* all requests. Signed requests allow the
* consumer to securely perform operations, including kicking off
* three-legged authentication to enable performing operations on
* behalf of a user of the service provider.
*/
class Consumer {
public:
Consumer(const std::string& key, const std::string& secret);
const std::string& key() const { return mKey; }
const std::string& secret() const { return mSecret; }
private:
const std::string mKey;
const std::string mSecret;
};
/** An OAuth credential used to request authorization or a protected
* resource.
*
* Tokens in OAuth comprise a *key* and a *secret*. The key is
* included in requests to identify the token being used, but the
* secret is used only in the signature, to prove that the requester
* is who the server gave the token to.
*
* When first negotiating the authorization, the consumer asks for a
* *request token* that the live user authorizes with the service
* provider. The consumer then exchanges the request token for an
* *access token* that can be used to access protected resources.
*/
class Token {
public:
Token(const std::string& key, const std::string& secret);
Token(const std::string& key, const std::string& secret, const std::string& pin);
/** Construct a token, extracting the key and secret from a set of
* key-value pairs (e.g. those parsed from an request or access
* token request).
*/
static Token extract(const KeyValuePairs& response);
/** Construct a token, extracting the key and secret from a raw,
* encoded response.
*/
static Token extract(const std::string& requestTokenResponse);
const std::string& key() const { return mKey; }
const std::string& secret() const { return mSecret; }
const std::string& pin() const { return mPin; }
void setPin(const std::string& pin_) { mPin = pin_; }
private:
const std::string mKey;
const std::string mSecret;
std::string mPin;
};
class Client {
public:
/** Perform static initialization. This will be called automatically, but
* you can call it explicitly to ensure thread safety. If you do not call
* this explicitly before using the Client class, the same nonce may be
* generated twice.
*/
static void initialize();
/** Alternative initialize method which lets you specify the seed and
* control the timestamp used in generating signatures. This only exists
* for testing purposes and should not be used in practice.
*/
static void initialize(int nonce, time_t timestamp);
/** Exposed for testing only.
*/
static void __resetInitialize();
/** Construct an OAuth Client using only a consumer key and
* secret. You can use this to start a three-legged
* authentication (to acquire an access token for a user) or for
* simple two-legged authentication (signing with empty access
* token info).
*
* \param consumer Consumer information. The caller must ensure
* it remains valid during the lifetime of this object
*/
Client(const Consumer* consumer);
/** Construct an OAuth Client with consumer key and secret (yours)
* and access token key and secret (acquired and stored during
* three-legged authentication).
*
* \param consumer Consumer information. The caller must ensure
* it remains valid during the lifetime of this object
* \param token Access token information. The caller must ensure
* it remains valid during the lifetime of this object
*/
Client(const Consumer* consumer, const Token* token);
~Client();
/** Build an OAuth HTTP header for the given request. This version provides
* only the field value.
*
* \param eType the HTTP request type, e.g. GET or POST
* \param rawUrl the raw request URL (should include query parameters)
* \param rawData the raw HTTP request data (can be empty)
* \param includeOAuthVerifierPin if true, adds oauth_verifier parameter
* \returns a string containing the HTTP header
*/
std::string getHttpHeader(const Http::RequestType eType,
const std::string& rawUrl,
const std::string& rawData = "",
const bool includeOAuthVerifierPin = false);
/** Build an OAuth HTTP header for the given request. This version gives a
* fully formatted header, i.e. including the header field name.
*
* \param eType the HTTP request type, e.g. GET or POST
* \param rawUrl the raw request URL (should include query parameters)
* \param rawData the raw HTTP request data (can be empty)
* \param includeOAuthVerifierPin if true, adds oauth_verifier parameter
* \returns a string containing the HTTP header
*/
std::string getFormattedHttpHeader(const Http::RequestType eType,
const std::string& rawUrl,
const std::string& rawData = "",
const bool includeOAuthVerifierPin = false);
/** Build an OAuth HTTP header for the given request.
*
* \param eType the HTTP request type, e.g. GET or POST
* \param rawUrl the raw request URL (should include query parameters)
* \param rawData the raw HTTP request data (can be empty)
* \param includeOAuthVerifierPin if true, adds oauth_verifier parameter
* \returns a string containing the query string, including the query
* parameters in the rawUrl
*/
std::string getURLQueryString(const Http::RequestType eType,
const std::string& rawUrl,
const std::string& rawData = "",
const bool includeOAuthVerifierPin = false);
private:
/** Disable default constructur -- must provide consumer
* information.
*/
Client();
static bool initialized;
static int testingNonce;
static time_t testingTimestamp;
/* OAuth data */
const Consumer* mConsumer;
const Token* mToken;
std::string m_nonce;
std::string m_timeStamp;
/* OAuth related utility methods */
bool buildOAuthTokenKeyValuePairs( const bool includeOAuthVerifierPin, /* in */
const std::string& rawData, /* in */
const std::string& oauthSignature, /* in */
KeyValuePairs& keyValueMap /* out */,
const bool urlEncodeValues /* in */,
const bool generateTimestamp /* in */);
bool getStringFromOAuthKeyValuePairs( const KeyValuePairs& rawParamMap, /* in */
std::string& rawParams, /* out */
const std::string& paramsSeperator /* in */ );
typedef enum _ParameterStringType {
QueryStringString,
AuthorizationHeaderString
} ParameterStringType;
// Utility for building OAuth HTTP header or query string. The string type
// controls the separator and also filters parameters: for query strings,
// all parameters are included. For HTTP headers, only auth parameters are
// included.
std::string buildOAuthParameterString(
ParameterStringType string_type,
const Http::RequestType eType,
const std::string& rawUrl,
const std::string& rawData,
const bool includeOAuthVerifierPin);
bool getSignature( const Http::RequestType eType, /* in */
const std::string& rawUrl, /* in */
const KeyValuePairs& rawKeyValuePairs, /* in */
std::string& oAuthSignature /* out */ );
void generateNonceTimeStamp();
};
} // namespace OAuth
#endif // __LIBOAUTHCPP_LIBOAUTHCPP_H__

View file

@ -0,0 +1,18 @@
TARGET = oauthcpp
ROOT_DIR = ../..
include($$ROOT_DIR/common.pri)
INCLUDEPATH += src include
TEMPLATE = lib
CONFIG += staticlib
SOURCES += \
src/base64.cpp \
src/HMAC_SHA1.cpp \
src/SHA1.cpp \
src/urlencode.cpp \
src/liboauthcpp.cpp \
HEADERS += \
include/liboauthcpp/liboauthcpp.h \

View file

@ -0,0 +1,59 @@
//******************************************************************************
//* HMAC_SHA1.cpp : Implementation of HMAC SHA1 algorithm
//* Comfort to RFC 2104
//*
//******************************************************************************
#include "HMAC_SHA1.h"
#include <iostream>
#include <memory>
void CHMAC_SHA1::HMAC_SHA1(BYTE *text, int text_len, BYTE *key, int key_len, BYTE *digest)
{
memset(SHA1_Key, 0, SHA1_BLOCK_SIZE);
/* repeated 64 times for values in ipad and opad */
memset(m_ipad, 0x36, sizeof(m_ipad));
memset(m_opad, 0x5c, sizeof(m_opad));
/* STEP 1 */
if (key_len > SHA1_BLOCK_SIZE)
{
CSHA1::Reset();
CSHA1::Update((UINT_8 *)key, key_len);
CSHA1::Final();
CSHA1::GetHash((UINT_8 *)SHA1_Key);
}
else
memcpy(SHA1_Key, key, key_len);
/* STEP 2 */
for (int i=0; i<(int)sizeof(m_ipad); i++)
{
m_ipad[i] ^= SHA1_Key[i];
}
/* STEP 4 */
CSHA1::Reset();
CSHA1::Update((UINT_8 *)m_ipad, sizeof(m_ipad));
CSHA1::Update((UINT_8 *)text, text_len);
CSHA1::Final();
char szReport[SHA1_DIGEST_LENGTH];
CSHA1::GetHash((UINT_8 *)szReport);
/* STEP 5 */
for (int j=0; j<(int)sizeof(m_opad); j++)
{
m_opad[j] ^= SHA1_Key[j];
}
/*STEP 7 */
CSHA1::Reset();
CSHA1::Update((UINT_8 *)m_opad, sizeof(m_opad));
CSHA1::Update((UINT_8 *)szReport, SHA1_DIGEST_LENGTH);
CSHA1::Final();
CSHA1::GetHash((UINT_8 *)digest);
}

View file

@ -0,0 +1,37 @@
/*
100% free public domain implementation of the HMAC-SHA1 algorithm
by Chien-Chung, Chung (Jim Chung) <jimchung1221@gmail.com>
*/
#ifndef __HMAC_SHA1_H__
#define __HMAC_SHA1_H__
#include "SHA1.h"
typedef unsigned char BYTE ;
class CHMAC_SHA1 : public CSHA1
{
public:
enum {
SHA1_DIGEST_LENGTH = 20,
SHA1_BLOCK_SIZE = 64
} ;
private:
BYTE m_ipad[SHA1_BLOCK_SIZE];
BYTE m_opad[SHA1_BLOCK_SIZE];
// This holds one SHA1 block's worth of data, zero padded if necessary.
char SHA1_Key[SHA1_BLOCK_SIZE];
public:
CHMAC_SHA1() {}
void HMAC_SHA1(BYTE *text, int text_len, BYTE *key, int key_len, BYTE *digest);
};
#endif /* __HMAC_SHA1_H__ */

View file

@ -0,0 +1,277 @@
/*
100% free public domain implementation of the SHA-1 algorithm
by Dominik Reichl <dominik.reichl@t-online.de>
Web: http://www.dominik-reichl.de/
Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches)
- You can set the endianness in your files, no need to modify the
header file of the CSHA1 class any more
- Aligned data support
- Made support/compilation of the utility functions (ReportHash
and HashFile) optional (useful, if bytes count, for example in
embedded environments)
Version 1.5 - 2005-01-01
- 64-bit compiler compatibility added
- Made variable wiping optional (define SHA1_WIPE_VARIABLES)
- Removed unnecessary variable initializations
- ROL32 improvement for the Microsoft compiler (using _rotl)
======== Test Vectors (from FIPS PUB 180-1) ========
SHA1("abc") =
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") =
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
SHA1(A million repetitions of "a") =
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
*/
#include "SHA1.h"
#include <cassert>
#ifdef SHA1_UTILITY_FUNCTIONS
#define SHA1_MAX_FILE_BUFFER 8000
#endif
// Rotate x bits to the left
#ifndef ROL32
#ifdef _MSC_VER
#define ROL32(_val32, _nBits) _rotl(_val32, _nBits)
#else
#define ROL32(_val32, _nBits) (((_val32)<<(_nBits))|((_val32)>>(32-(_nBits))))
#endif
#endif
#ifdef SHA1_LITTLE_ENDIAN
#define SHABLK0(i) (m_block->l[i] = \
(ROL32(m_block->l[i],24) & 0xFF00FF00) | (ROL32(m_block->l[i],8) & 0x00FF00FF))
#else
#define SHABLK0(i) (m_block->l[i])
#endif
#define SHABLK(i) (m_block->l[i&15] = ROL32(m_block->l[(i+13)&15] ^ m_block->l[(i+8)&15] \
^ m_block->l[(i+2)&15] ^ m_block->l[i&15],1))
// SHA-1 rounds
#define _R0(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK0(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); }
#define _R1(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); }
#define _R2(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0x6ED9EBA1+ROL32(v,5); w=ROL32(w,30); }
#define _R3(v,w,x,y,z,i) { z+=(((w|x)&y)|(w&x))+SHABLK(i)+0x8F1BBCDC+ROL32(v,5); w=ROL32(w,30); }
#define _R4(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0xCA62C1D6+ROL32(v,5); w=ROL32(w,30); }
CSHA1::CSHA1()
{
m_block = (SHA1_WORKSPACE_BLOCK *)m_workspace;
Reset();
}
CSHA1::~CSHA1()
{
Reset();
}
void CSHA1::Reset()
{
// SHA1 initialization constants
m_state[0] = 0x67452301;
m_state[1] = 0xEFCDAB89;
m_state[2] = 0x98BADCFE;
m_state[3] = 0x10325476;
m_state[4] = 0xC3D2E1F0;
m_count[0] = 0;
m_count[1] = 0;
}
void CSHA1::Transform(UINT_32 *state, UINT_8 *buffer)
{
// Copy state[] to working vars
UINT_32 a = state[0], b = state[1], c = state[2], d = state[3], e = state[4];
memcpy(m_block, buffer, 64);
// 4 rounds of 20 operations each. Loop unrolled.
_R0(a,b,c,d,e, 0); _R0(e,a,b,c,d, 1); _R0(d,e,a,b,c, 2); _R0(c,d,e,a,b, 3);
_R0(b,c,d,e,a, 4); _R0(a,b,c,d,e, 5); _R0(e,a,b,c,d, 6); _R0(d,e,a,b,c, 7);
_R0(c,d,e,a,b, 8); _R0(b,c,d,e,a, 9); _R0(a,b,c,d,e,10); _R0(e,a,b,c,d,11);
_R0(d,e,a,b,c,12); _R0(c,d,e,a,b,13); _R0(b,c,d,e,a,14); _R0(a,b,c,d,e,15);
_R1(e,a,b,c,d,16); _R1(d,e,a,b,c,17); _R1(c,d,e,a,b,18); _R1(b,c,d,e,a,19);
_R2(a,b,c,d,e,20); _R2(e,a,b,c,d,21); _R2(d,e,a,b,c,22); _R2(c,d,e,a,b,23);
_R2(b,c,d,e,a,24); _R2(a,b,c,d,e,25); _R2(e,a,b,c,d,26); _R2(d,e,a,b,c,27);
_R2(c,d,e,a,b,28); _R2(b,c,d,e,a,29); _R2(a,b,c,d,e,30); _R2(e,a,b,c,d,31);
_R2(d,e,a,b,c,32); _R2(c,d,e,a,b,33); _R2(b,c,d,e,a,34); _R2(a,b,c,d,e,35);
_R2(e,a,b,c,d,36); _R2(d,e,a,b,c,37); _R2(c,d,e,a,b,38); _R2(b,c,d,e,a,39);
_R3(a,b,c,d,e,40); _R3(e,a,b,c,d,41); _R3(d,e,a,b,c,42); _R3(c,d,e,a,b,43);
_R3(b,c,d,e,a,44); _R3(a,b,c,d,e,45); _R3(e,a,b,c,d,46); _R3(d,e,a,b,c,47);
_R3(c,d,e,a,b,48); _R3(b,c,d,e,a,49); _R3(a,b,c,d,e,50); _R3(e,a,b,c,d,51);
_R3(d,e,a,b,c,52); _R3(c,d,e,a,b,53); _R3(b,c,d,e,a,54); _R3(a,b,c,d,e,55);
_R3(e,a,b,c,d,56); _R3(d,e,a,b,c,57); _R3(c,d,e,a,b,58); _R3(b,c,d,e,a,59);
_R4(a,b,c,d,e,60); _R4(e,a,b,c,d,61); _R4(d,e,a,b,c,62); _R4(c,d,e,a,b,63);
_R4(b,c,d,e,a,64); _R4(a,b,c,d,e,65); _R4(e,a,b,c,d,66); _R4(d,e,a,b,c,67);
_R4(c,d,e,a,b,68); _R4(b,c,d,e,a,69); _R4(a,b,c,d,e,70); _R4(e,a,b,c,d,71);
_R4(d,e,a,b,c,72); _R4(c,d,e,a,b,73); _R4(b,c,d,e,a,74); _R4(a,b,c,d,e,75);
_R4(e,a,b,c,d,76); _R4(d,e,a,b,c,77); _R4(c,d,e,a,b,78); _R4(b,c,d,e,a,79);
// Add the working vars back into state
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
// Wipe variables
#ifdef SHA1_WIPE_VARIABLES
a = b = c = d = e = 0;
#endif
}
// Use this function to hash in binary data and strings
void CSHA1::Update(UINT_8 *data, UINT_32 len)
{
UINT_32 i, j;
j = (m_count[0] >> 3) & 63;
if((m_count[0] += len << 3) < (len << 3)) m_count[1]++;
m_count[1] += (len >> 29);
if((j + len) > 63)
{
i = 64 - j;
memcpy(&m_buffer[j], data, i);
Transform(m_state, m_buffer);
for(; i + 63 < len; i += 64) Transform(m_state, &data[i]);
j = 0;
}
else i = 0;
memcpy(&m_buffer[j], &data[i], len - i);
}
#ifdef SHA1_UTILITY_FUNCTIONS
// Hash in file contents
bool CSHA1::HashFile(char *szFileName)
{
unsigned long ulFileSize, ulRest, ulBlocks;
unsigned long i;
UINT_8 uData[SHA1_MAX_FILE_BUFFER];
FILE *fIn;
if(szFileName == NULL) return false;
fIn = fopen(szFileName, "rb");
if(fIn == NULL) return false;
fseek(fIn, 0, SEEK_END);
ulFileSize = (unsigned long)ftell(fIn);
fseek(fIn, 0, SEEK_SET);
if(ulFileSize != 0)
{
ulBlocks = ulFileSize / SHA1_MAX_FILE_BUFFER;
ulRest = ulFileSize % SHA1_MAX_FILE_BUFFER;
}
else
{
ulBlocks = 0;
ulRest = 0;
}
for(i = 0; i < ulBlocks; i++)
{
size_t nread = fread(uData, 1, SHA1_MAX_FILE_BUFFER, fIn);
assert(nread == SHA1_MAX_FILE_BUFFER);
Update((UINT_8 *)uData, SHA1_MAX_FILE_BUFFER);
}
if(ulRest != 0)
{
size_t nread = fread(uData, 1, ulRest, fIn);
assert(nread == ulRest);
Update((UINT_8 *)uData, ulRest);
}
fclose(fIn); fIn = NULL;
return true;
}
#endif
void CSHA1::Final()
{
UINT_32 i;
UINT_8 finalcount[8];
for(i = 0; i < 8; i++)
finalcount[i] = (UINT_8)((m_count[((i >= 4) ? 0 : 1)]
>> ((3 - (i & 3)) * 8) ) & 255); // Endian independent
Update((UINT_8 *)"\200", 1);
while ((m_count[0] & 504) != 448)
Update((UINT_8 *)"\0", 1);
Update(finalcount, 8); // Cause a SHA1Transform()
for(i = 0; i < 20; i++)
{
m_digest[i] = (UINT_8)((m_state[i >> 2] >> ((3 - (i & 3)) * 8) ) & 255);
}
// Wipe variables for security reasons
#ifdef SHA1_WIPE_VARIABLES
i = 0;
memset(m_buffer, 0, 64);
memset(m_state, 0, 20);
memset(m_count, 0, 8);
memset(finalcount, 0, 8);
Transform(m_state, m_buffer);
#endif
}
#ifdef SHA1_UTILITY_FUNCTIONS
// Get the final hash as a pre-formatted string
void CSHA1::ReportHash(char *szReport, unsigned char uReportType)
{
unsigned char i;
char szTemp[16];
if(szReport == NULL) return;
if(uReportType == REPORT_HEX)
{
sprintf(szTemp, "%02X", m_digest[0]);
strcat(szReport, szTemp);
for(i = 1; i < 20; i++)
{
sprintf(szTemp, " %02X", m_digest[i]);
strcat(szReport, szTemp);
}
}
else if(uReportType == REPORT_DIGIT)
{
sprintf(szTemp, "%u", m_digest[0]);
strcat(szReport, szTemp);
for(i = 1; i < 20; i++)
{
sprintf(szTemp, " %u", m_digest[i]);
strcat(szReport, szTemp);
}
}
else strcpy(szReport, "Error: Unknown report type!");
}
#endif
// Get the raw message digest
void CSHA1::GetHash(UINT_8 *puDest)
{
memcpy(puDest, m_digest, 20);
}

View file

@ -0,0 +1,148 @@
/*
100% free public domain implementation of the SHA-1 algorithm
by Dominik Reichl <dominik.reichl@t-online.de>
Web: http://www.dominik-reichl.de/
Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches)
- You can set the endianness in your files, no need to modify the
header file of the CSHA1 class any more
- Aligned data support
- Made support/compilation of the utility functions (ReportHash
and HashFile) optional (useful, if bytes count, for example in
embedded environments)
Version 1.5 - 2005-01-01
- 64-bit compiler compatibility added
- Made variable wiping optional (define SHA1_WIPE_VARIABLES)
- Removed unnecessary variable initializations
- ROL32 improvement for the Microsoft compiler (using _rotl)
======== Test Vectors (from FIPS PUB 180-1) ========
SHA1("abc") =
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") =
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
SHA1(A million repetitions of "a") =
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
*/
#ifndef ___SHA1_HDR___
#define ___SHA1_HDR___
#if !defined(SHA1_UTILITY_FUNCTIONS) && !defined(SHA1_NO_UTILITY_FUNCTIONS)
#define SHA1_UTILITY_FUNCTIONS
#endif
#include <memory.h> // Needed for memset and memcpy
#ifdef SHA1_UTILITY_FUNCTIONS
#include <stdio.h> // Needed for file access and sprintf
#include <string.h> // Needed for strcat and strcpy
#endif
#ifdef _MSC_VER
#include <stdlib.h>
#endif
// You can define the endian mode in your files, without modifying the SHA1
// source files. Just #define SHA1_LITTLE_ENDIAN or #define SHA1_BIG_ENDIAN
// in your files, before including the SHA1.h header file. If you don't
// define anything, the class defaults to little endian.
#if !defined(SHA1_LITTLE_ENDIAN) && !defined(SHA1_BIG_ENDIAN)
#define SHA1_LITTLE_ENDIAN
#endif
// Same here. If you want variable wiping, #define SHA1_WIPE_VARIABLES, if
// not, #define SHA1_NO_WIPE_VARIABLES. If you don't define anything, it
// defaults to wiping.
#if !defined(SHA1_WIPE_VARIABLES) && !defined(SHA1_NO_WIPE_VARIABLES)
#define SHA1_WIPE_VARIABLES
#endif
/////////////////////////////////////////////////////////////////////////////
// Define 8- and 32-bit variables
#ifndef UINT_32
#ifdef _MSC_VER
#define UINT_8 unsigned __int8
#define UINT_32 unsigned __int32
#else
#define UINT_8 unsigned char
#if (ULONG_MAX == 0xFFFFFFFF)
#define UINT_32 unsigned long
#else
#define UINT_32 unsigned int
#endif
#endif
#endif
/////////////////////////////////////////////////////////////////////////////
// Declare SHA1 workspace
typedef union
{
UINT_8 c[64];
UINT_32 l[16];
} SHA1_WORKSPACE_BLOCK;
class CSHA1
{
public:
#ifdef SHA1_UTILITY_FUNCTIONS
// Two different formats for ReportHash(...)
enum
{
REPORT_HEX = 0,
REPORT_DIGIT = 1
};
#endif
// Constructor and Destructor
CSHA1();
~CSHA1();
UINT_32 m_state[5];
UINT_32 m_count[2];
UINT_32 __reserved1[1];
UINT_8 m_buffer[64];
UINT_8 m_digest[20];
UINT_32 __reserved2[3];
void Reset();
// Update the hash value
void Update(UINT_8 *data, UINT_32 len);
#ifdef SHA1_UTILITY_FUNCTIONS
bool HashFile(char *szFileName);
#endif
// Finalize hash and report
void Final();
// Report functions: as pre-formatted and raw data
#ifdef SHA1_UTILITY_FUNCTIONS
void ReportHash(char *szReport, unsigned char uReportType = REPORT_HEX);
#endif
void GetHash(UINT_8 *puDest);
private:
// Private SHA-1 transformation
void Transform(UINT_32 *state, UINT_8 *buffer);
// Member variables
UINT_8 m_workspace[64];
SHA1_WORKSPACE_BLOCK *m_block; // SHA1 pointer to the byte array above
};
#endif

View file

@ -0,0 +1,123 @@
/*
base64.cpp and base64.h
Copyright (C) 2004-2008 René Nyffenegger
This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.
3. This notice may not be removed or altered from any source distribution.
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
*/
#include "base64.h"
#include <iostream>
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(unsigned char c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (in_len--) {
char_array_3[i++] = *(bytes_to_encode++);
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for(i = 0; (i <4) ; i++)
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
if (i)
{
for(j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
ret += base64_chars[char_array_4[j]];
while((i++ < 3))
ret += '=';
}
return ret;
}
std::string base64_decode(std::string const& encoded_string) {
int in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_]; in_++;
if (i ==4) {
for (i = 0; i <4; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
ret += char_array_3[i];
i = 0;
}
}
if (i) {
for (j = i; j <4; j++)
char_array_4[j] = 0;
for (j = 0; j <4; j++)
char_array_4[j] = base64_chars.find(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
}
return ret;
}

View file

@ -0,0 +1,4 @@
#include <string>
std::string base64_encode(unsigned char const* , unsigned int len);
std::string base64_decode(std::string const& s);

View file

@ -0,0 +1,621 @@
#include <liboauthcpp/liboauthcpp.h>
#include "HMAC_SHA1.h"
#include "base64.h"
#include "urlencode.h"
#include <cstdlib>
#include <vector>
#include <cassert>
namespace OAuth {
namespace Defaults
{
/* Constants */
const int BUFFSIZE = 1024;
const int BUFFSIZE_LARGE = 1024;
const std::string CONSUMERKEY_KEY = "oauth_consumer_key";
const std::string CALLBACK_KEY = "oauth_callback";
const std::string VERSION_KEY = "oauth_version";
const std::string SIGNATUREMETHOD_KEY = "oauth_signature_method";
const std::string SIGNATURE_KEY = "oauth_signature";
const std::string TIMESTAMP_KEY = "oauth_timestamp";
const std::string NONCE_KEY = "oauth_nonce";
const std::string TOKEN_KEY = "oauth_token";
const std::string TOKENSECRET_KEY = "oauth_token_secret";
const std::string VERIFIER_KEY = "oauth_verifier";
const std::string AUTHHEADER_FIELD = "Authorization: ";
const std::string AUTHHEADER_PREFIX = "OAuth ";
};
/** std::string -> std::string conversion function */
typedef std::string(*StringConvertFunction)(const std::string&);
LogLevel gLogLevel = LogLevelNone;
void SetLogLevel(LogLevel lvl) {
gLogLevel = lvl;
}
#define LOG(lvl, msg) \
do { \
if (lvl <= gLogLevel) std::cerr << "OAUTH: " << msg << std::endl; \
} while(0)
std::string PercentEncode(const std::string& decoded) {
return urlencode(decoded, URLEncode_Everything);
}
std::string URLEncode(const std::string& decoded) {
return PercentEncode(decoded);
}
std::string HttpEncodePath(const std::string& decoded) {
return urlencode(decoded, URLEncode_Path);
}
std::string HttpEncodeQueryKey(const std::string& decoded) {
return urlencode(decoded, URLEncode_QueryKey);
}
std::string HttpEncodeQueryValue(const std::string& decoded) {
return urlencode(decoded, URLEncode_QueryValue);
}
namespace {
std::string PassThrough(const std::string& decoded) {
return decoded;
}
std::string RequestTypeString(const Http::RequestType rt) {
switch(rt) {
case Http::Invalid: return "Invalid Request Type"; break;
case Http::Head: return "HEAD"; break;
case Http::Get: return "GET"; break;
case Http::Post: return "POST"; break;
case Http::Delete: return "DELETE"; break;
case Http::Put: return "PUT"; break;
default: return "Unknown Request Type"; break;
}
return "";
}
}
// Parse a single key-value pair
static std::pair<std::string, std::string> ParseKeyValuePair(const std::string& encoded) {
std::size_t eq_pos = encoded.find("=");
if (eq_pos == std::string::npos)
throw ParseError("Failed to find '=' in key-value pair.");
return std::pair<std::string, std::string>(
encoded.substr(0, eq_pos),
encoded.substr(eq_pos+1)
);
}
KeyValuePairs ParseKeyValuePairs(const std::string& encoded) {
KeyValuePairs result;
if (encoded.length() == 0) return result;
// Split by &
std::size_t last_amp = 0;
// We can bail when the last one "found" was the end of the string
while(true) {
std::size_t next_amp = encoded.find('&', last_amp+1);
std::string keyval =
(next_amp == std::string::npos) ?
encoded.substr(last_amp) :
encoded.substr(last_amp, next_amp-last_amp);
result.insert(ParseKeyValuePair(keyval));
// Track spot after the & so the first iteration works without dealing
// with -1 index
last_amp = next_amp+1;
// Exit condition
if (next_amp == std::string::npos) break;
}
return result;
}
// Helper for parameters in key-value pair lists that should only appear
// once. Either replaces an existing entry or adds a new entry.
static void ReplaceOrInsertKeyValuePair(KeyValuePairs& kvp, const std::string& key, const std::string& value) {
assert(kvp.count(key) <= 1);
KeyValuePairs::iterator it = kvp.find(key);
if (it != kvp.end())
it->second = value;
else
kvp.insert(KeyValuePairs::value_type(key, value));
}
Consumer::Consumer(const std::string& key, const std::string& secret)
: mKey(key), mSecret(secret)
{
}
Token::Token(const std::string& key, const std::string& secret)
: mKey(key), mSecret(secret)
{
}
Token::Token(const std::string& key, const std::string& secret, const std::string& pin)
: mKey(key), mSecret(secret), mPin(pin)
{
}
Token Token::extract(const std::string& response) {
return Token::extract(ParseKeyValuePairs(response));
}
Token Token::extract(const KeyValuePairs& response) {
std::string token_key, token_secret;
KeyValuePairs::const_iterator it = response.find(Defaults::TOKEN_KEY);
if (it == response.end())
throw MissingKeyError("Couldn't find oauth_token in response");
token_key = it->second;
it = response.find(Defaults::TOKENSECRET_KEY);
if (it == response.end())
throw MissingKeyError("Couldn't find oauth_token_secret in response");
token_secret = it->second;
return Token(token_key, token_secret);
}
bool Client::initialized = false;
int Client::testingNonce = 0;
time_t Client::testingTimestamp = 0;
void Client::initialize() {
if(!initialized) {
srand( time( NULL ) );
initialized = true;
}
}
void Client::initialize(int nonce, time_t timestamp) {
if(!initialized) {
testingNonce = nonce;
testingTimestamp = timestamp;
initialized = true;
}
}
void Client::__resetInitialize() {
testingNonce = 0;
testingTimestamp = 0;
initialized = false;
}
Client::Client(const Consumer* consumer)
: mConsumer(consumer),
mToken(NULL)
{
}
Client::Client(const Consumer* consumer, const Token* token)
: mConsumer(consumer),
mToken(token)
{
}
Client::~Client()
{
}
/*++
* @method: Client::generateNonceTimeStamp
*
* @description: this method generates nonce and timestamp for OAuth header
*
* @input: none
*
* @output: none
*
* @remarks: internal method
*
*--*/
void Client::generateNonceTimeStamp()
{
// Make sure the random seed has been initialized
Client::initialize();
char szTime[Defaults::BUFFSIZE];
char szRand[Defaults::BUFFSIZE];
memset( szTime, 0, Defaults::BUFFSIZE );
memset( szRand, 0, Defaults::BUFFSIZE );
// Any non-zero timestamp triggers testing mode with fixed values. Fixing
// both values makes life easier because generating a signature is
// idempotent -- otherwise using macros can cause double evaluation and
// incorrect results because of repeated calls to rand().
sprintf( szRand, "%x", ((testingTimestamp != 0) ? testingNonce : rand()) );
sprintf( szTime, "%ld", ((testingTimestamp != 0) ? testingTimestamp : time( NULL )) );
m_nonce.assign( szTime );
m_nonce.append( szRand );
m_timeStamp.assign( szTime );
}
/*++
* @method: Client::buildOAuthTokenKeyValuePairs
*
* @description: this method prepares key-value pairs required for OAuth header
* and signature generation.
*
* @input: includeOAuthVerifierPin - flag to indicate whether oauth_verifer key-value
* pair needs to be included. oauth_verifer is only
* used during exchanging request token with access token.
* rawData - url encoded data. this is used during signature generation.
* oauthSignature - base64 and url encoded OAuth signature.
* generateTimestamp - If true, then generate new timestamp for nonce.
*
* @input: urlEncodeValues - if true, URLEncode the values inserted into the
* output keyValueMap
* @output: keyValueMap - map in which key-value pairs are populated
*
* @remarks: internal method
*
*--*/
bool Client::buildOAuthTokenKeyValuePairs( const bool includeOAuthVerifierPin,
const std::string& rawData,
const std::string& oauthSignature,
KeyValuePairs& keyValueMap,
const bool urlEncodeValues,
const bool generateTimestamp )
{
// Encodes value part of key-value pairs depending on type of output (query
// string vs. HTTP headers.
StringConvertFunction value_encoder = (urlEncodeValues ? HttpEncodeQueryValue : PassThrough);
/* Generate nonce and timestamp if required */
if( generateTimestamp )
{
generateNonceTimeStamp();
}
/* Consumer key and its value */
ReplaceOrInsertKeyValuePair(keyValueMap, Defaults::CONSUMERKEY_KEY, value_encoder(mConsumer->key()));
/* Nonce key and its value */
ReplaceOrInsertKeyValuePair(keyValueMap, Defaults::NONCE_KEY, value_encoder(m_nonce));
/* Signature if supplied */
if( oauthSignature.length() )
{
// Signature is exempt from encoding. The procedure for
// computing it already percent-encodes it as required by the
// spec for both query string and Auth header
// methods. Therefore, it's pass-through in both cases.
ReplaceOrInsertKeyValuePair(keyValueMap, Defaults::SIGNATURE_KEY, oauthSignature);
}
/* Signature method, only HMAC-SHA1 as of now */
ReplaceOrInsertKeyValuePair(keyValueMap, Defaults::SIGNATUREMETHOD_KEY, std::string( "HMAC-SHA1" ));
/* Timestamp */
ReplaceOrInsertKeyValuePair(keyValueMap, Defaults::TIMESTAMP_KEY, value_encoder(m_timeStamp));
/* Token */
if( mToken && mToken->key().length() )
{
ReplaceOrInsertKeyValuePair(keyValueMap, Defaults::TOKEN_KEY, value_encoder(mToken->key()));
}
/* Verifier */
if( includeOAuthVerifierPin && mToken && mToken->pin().length() )
{
ReplaceOrInsertKeyValuePair(keyValueMap, Defaults::VERIFIER_KEY, value_encoder(mToken->pin()));
}
/* Version */
ReplaceOrInsertKeyValuePair(keyValueMap, Defaults::VERSION_KEY, std::string( "1.0" ));
/* Data if it's present */
if( rawData.length() )
{
/* Data should already be urlencoded once */
std::string dummyStrKey;
std::string dummyStrValue;
size_t nPos = rawData.find_first_of( "=" );
if( std::string::npos != nPos )
{
dummyStrKey = rawData.substr( 0, nPos );
dummyStrValue = rawData.substr( nPos + 1 );
ReplaceOrInsertKeyValuePair(keyValueMap, dummyStrKey, dummyStrValue);
}
}
return ( keyValueMap.size() ) ? true : false;
}
/*++
* @method: Client::getSignature
*
* @description: this method calculates HMAC-SHA1 signature of OAuth header
*
* @input: eType - HTTP request type
* rawUrl - raw url of the HTTP request
* rawKeyValuePairs - key-value pairs containing OAuth headers and HTTP data
*
* @output: oAuthSignature - base64 and url encoded signature
*
* @remarks: internal method
*
*--*/
bool Client::getSignature( const Http::RequestType eType,
const std::string& rawUrl,
const KeyValuePairs& rawKeyValuePairs,
std::string& oAuthSignature )
{
std::string rawParams;
std::string paramsSeperator;
std::string sigBase;
/* Initially empty signature */
oAuthSignature.assign( "" );
/* Build a string using key-value pairs */
paramsSeperator = "&";
getStringFromOAuthKeyValuePairs( rawKeyValuePairs, rawParams, paramsSeperator );
LOG(LogLevelDebug, "Normalized parameters: " << rawParams);
/* Start constructing base signature string. Refer http://dev.twitter.com/auth#intro */
switch( eType )
{
case Http::Head:
{
sigBase.assign( "HEAD&" );
}
break;
case Http::Get:
{
sigBase.assign( "GET&" );
}
break;
case Http::Post:
{
sigBase.assign( "POST&" );
}
break;
case Http::Delete:
{
sigBase.assign( "DELETE&" );
}
break;
case Http::Put:
{
sigBase.assign( "PUT&" );
}
break;
default:
{
return false;
}
break;
}
sigBase.append( PercentEncode( rawUrl ) );
sigBase.append( "&" );
sigBase.append( PercentEncode( rawParams ) );
LOG(LogLevelDebug, "Signature base string: " << sigBase);
/* Now, hash the signature base string using HMAC_SHA1 class */
CHMAC_SHA1 objHMACSHA1;
std::string secretSigningKey;
unsigned char strDigest[Defaults::BUFFSIZE_LARGE];
memset( strDigest, 0, Defaults::BUFFSIZE_LARGE );
/* Signing key is composed of consumer_secret&token_secret */
secretSigningKey.assign( PercentEncode(mConsumer->secret()) );
secretSigningKey.append( "&" );
if( mToken && mToken->secret().length() )
{
secretSigningKey.append( PercentEncode(mToken->secret()) );
}
objHMACSHA1.HMAC_SHA1( (unsigned char*)sigBase.c_str(),
sigBase.length(),
(unsigned char*)secretSigningKey.c_str(),
secretSigningKey.length(),
strDigest );
/* Do a base64 encode of signature */
std::string base64Str = base64_encode( strDigest, 20 /* SHA 1 digest is 160 bits */ );
LOG(LogLevelDebug, "Signature: " << base64Str);
/* Do an url encode */
oAuthSignature = PercentEncode( base64Str );
LOG(LogLevelDebug, "Percent-encoded Signature: " << oAuthSignature);
return ( oAuthSignature.length() ) ? true : false;
}
std::string Client::getHttpHeader(const Http::RequestType eType,
const std::string& rawUrl,
const std::string& rawData,
const bool includeOAuthVerifierPin)
{
return Defaults::AUTHHEADER_PREFIX + buildOAuthParameterString(AuthorizationHeaderString, eType, rawUrl, rawData, includeOAuthVerifierPin);
}
std::string Client::getFormattedHttpHeader(const Http::RequestType eType,
const std::string& rawUrl,
const std::string& rawData,
const bool includeOAuthVerifierPin)
{
return Defaults::AUTHHEADER_FIELD + Defaults::AUTHHEADER_PREFIX + buildOAuthParameterString(AuthorizationHeaderString, eType, rawUrl, rawData, includeOAuthVerifierPin);
}
std::string Client::getURLQueryString(const Http::RequestType eType,
const std::string& rawUrl,
const std::string& rawData,
const bool includeOAuthVerifierPin)
{
return buildOAuthParameterString(QueryStringString, eType, rawUrl, rawData, includeOAuthVerifierPin);
}
std::string Client::buildOAuthParameterString(
ParameterStringType string_type,
const Http::RequestType eType,
const std::string& rawUrl,
const std::string& rawData,
const bool includeOAuthVerifierPin)
{
KeyValuePairs rawKeyValuePairs;
std::string rawParams;
std::string oauthSignature;
std::string paramsSeperator;
std::string pureUrl( rawUrl );
LOG(LogLevelDebug, "Signing request " << RequestTypeString(eType) << " " << rawUrl << " " << rawData);
std::string separator;
bool do_urlencode;
if (string_type == AuthorizationHeaderString) {
separator = ",";
do_urlencode = false;
}
else { // QueryStringString
separator = "&";
do_urlencode = true;
}
/* Clear header string initially */
rawKeyValuePairs.clear();
/* If URL itself contains ?key=value, then extract and put them in map */
size_t nPos = rawUrl.find_first_of( "?" );
if( std::string::npos != nPos )
{
/* Get only URL */
pureUrl = rawUrl.substr( 0, nPos );
/* Get only key=value data part */
std::string dataPart = rawUrl.substr( nPos + 1 );
rawKeyValuePairs = ParseKeyValuePairs(dataPart);
}
// NOTE: We always request URL encoding on the first pass so that the
// signature generation works properly. This *relies* on
// buildOAuthTokenKeyValuePairs overwriting values when we do the second
// pass to get the values in the form we actually want. The signature and
// rawdata are the only things that change, but the signature is only used
// in the second pass and the rawdata is already encoded, regardless of
// request type.
/* Build key-value pairs needed for OAuth request token, without signature */
buildOAuthTokenKeyValuePairs( includeOAuthVerifierPin, rawData, std::string( "" ), rawKeyValuePairs, true, true );
/* Get url encoded base64 signature using request type, url and parameters */
getSignature( eType, pureUrl, rawKeyValuePairs, oauthSignature );
/* Now, again build key-value pairs with signature this time */
buildOAuthTokenKeyValuePairs( includeOAuthVerifierPin, std::string( "" ), oauthSignature, rawKeyValuePairs, do_urlencode, false );
/* Get OAuth header in string format. If we're getting the Authorization
* header, we need to filter out other parameters.
*/
if (string_type == AuthorizationHeaderString) {
KeyValuePairs oauthKeyValuePairs;
std::vector<std::string> oauth_keys;
oauth_keys.push_back(Defaults::CONSUMERKEY_KEY);
oauth_keys.push_back(Defaults::NONCE_KEY);
oauth_keys.push_back(Defaults::SIGNATURE_KEY);
oauth_keys.push_back(Defaults::SIGNATUREMETHOD_KEY);
oauth_keys.push_back(Defaults::TIMESTAMP_KEY);
oauth_keys.push_back(Defaults::TOKEN_KEY);
oauth_keys.push_back(Defaults::VERIFIER_KEY);
oauth_keys.push_back(Defaults::VERSION_KEY);
for(size_t i = 0; i < oauth_keys.size(); i++) {
assert(rawKeyValuePairs.count(oauth_keys[i]) <= 1);
KeyValuePairs::iterator oauth_key_it = rawKeyValuePairs.find(oauth_keys[i]);
if (oauth_key_it != rawKeyValuePairs.end())
ReplaceOrInsertKeyValuePair(oauthKeyValuePairs, oauth_keys[i], oauth_key_it->second);
}
getStringFromOAuthKeyValuePairs( oauthKeyValuePairs, rawParams, separator );
}
else if (string_type == QueryStringString) {
getStringFromOAuthKeyValuePairs( rawKeyValuePairs, rawParams, separator );
}
/* Build authorization header */
return rawParams;
}
/*++
* @method: Client::getStringFromOAuthKeyValuePairs
*
* @description: this method builds a sorted string from key-value pairs
*
* @input: rawParamMap - key-value pairs map
* paramsSeperator - sepearator, either & or ,
*
* @output: rawParams - sorted string of OAuth parameters
*
* @remarks: internal method
*
*--*/
bool Client::getStringFromOAuthKeyValuePairs( const KeyValuePairs& rawParamMap,
std::string& rawParams,
const std::string& paramsSeperator )
{
rawParams.assign( "" );
if( rawParamMap.size() )
{
KeyValueList keyValueList;
std::string dummyStr;
/* Push key-value pairs to a list of strings */
keyValueList.clear();
KeyValuePairs::const_iterator itMap = rawParamMap.begin();
for( ; itMap != rawParamMap.end(); itMap++ )
{
dummyStr.assign( itMap->first );
dummyStr.append( "=" );
if( paramsSeperator == "," )
{
dummyStr.append( "\"" );
}
dummyStr.append( itMap->second );
if( paramsSeperator == "," )
{
dummyStr.append( "\"" );
}
keyValueList.push_back( dummyStr );
}
/* Sort key-value pairs based on key name */
keyValueList.sort();
/* Now, form a string */
dummyStr.assign( "" );
KeyValueList::iterator itKeyValue = keyValueList.begin();
for( ; itKeyValue != keyValueList.end(); itKeyValue++ )
{
if( dummyStr.length() )
{
dummyStr.append( paramsSeperator );
}
dummyStr.append( itKeyValue->c_str() );
}
rawParams.assign( dummyStr );
}
return ( rawParams.length() ) ? true : false;
}
} // namespace OAuth

View file

@ -0,0 +1,102 @@
#include "urlencode.h"
#include <cassert>
std::string char2hex( char dec )
{
char dig1 = (dec&0xF0)>>4;
char dig2 = (dec&0x0F);
if ( 0<= dig1 && dig1<= 9) dig1+=48; //0,48 in ascii
if (10<= dig1 && dig1<=15) dig1+=65-10; //A,65 in ascii
if ( 0<= dig2 && dig2<= 9) dig2+=48;
if (10<= dig2 && dig2<=15) dig2+=65-10;
std::string r;
r.append( &dig1, 1);
r.append( &dig2, 1);
return r;
}
std::string urlencode( const std::string &c, URLEncodeType enctype)
{
std::string escaped;
int max = c.length();
for(int i=0; i<max; i++)
{
// Unreserved chars
if ( (48 <= c[i] && c[i] <= 57) ||//0-9
(65 <= c[i] && c[i] <= 90) ||//ABC...XYZ
(97 <= c[i] && c[i] <= 122) || //abc...xyz
(c[i]=='~' || c[i]=='-' || c[i]=='_' || c[i]=='.')
)
{
escaped.append( &c[i], 1);
}
else if (c[i] != ':' && c[i] != '/' && c[i] != '?' && c[i] != '#' &&
c[i] != '[' && c[i] != ']' && c[i] != '@' && c[i] != '%' &&
c[i] != '!' && c[i] != '$' && c[i] != '&' && c[i] != '\'' &&
c[i] != '(' && c[i] != ')' && c[i] != '*' && c[i] != '+' &&
c[i] != ',' && c[i] != ';' && c[i] != '=')
{
// Characters not in unreserved (first if block) and not in
// the reserved set are always encoded.
escaped.append("%");
escaped.append( char2hex(c[i]) );//converts char 255 to string "FF"
}
else
{
// Finally, the reserved set. Encoding here depends on the
// context (where in the URI we are, what type of URI, and
// which character).
bool enc = false;
// Always encode reserved gen-delims + '%' (which always
// needs encoding
if (c[i] == ':' || c[i] == '/' || c[i] == '?' || c[i] == '#' ||
c[i] == '[' || c[i] == ']' || c[i] == '@' || c[i] == '%')
{
enc = true;
}
else {
switch (enctype) {
case URLEncode_Everything:
enc = true;
break;
case URLEncode_Path:
// Only reserved sub-delim that needs encoding is %,
// taken care of above. Otherwise, leave unencoded
enc = false;
break;
case URLEncode_QueryKey:
if (c[i] == '&' ||
c[i] == '+' ||
c[i] == '=')
enc = true;
else
enc = false;
break;
case URLEncode_QueryValue:
if (c[i] == '&' ||
c[i] == '+')
enc = true;
else
enc = false;
break;
default:
assert(false && "Unknown urlencode type");
break;
}
}
if (enc) {
escaped.append("%");
escaped.append( char2hex(c[i]) );//converts char 255 to string "FF"
} else {
escaped.append( &c[i], 1);
}
}
}
return escaped;
}

View file

@ -0,0 +1,16 @@
#ifndef __URLENCODE_H__
#define __URLENCODE_H__
#include <iostream>
#include <string>
std::string char2hex( char dec );
enum URLEncodeType {
URLEncode_Everything,
URLEncode_Path,
URLEncode_QueryKey,
URLEncode_QueryValue,
};
std::string urlencode( const std::string &c, URLEncodeType enctype );
#endif // __URLENCODE_H__

View file

@ -26,10 +26,13 @@
#include "rules_evaluation.hpp"
#include "parse_opening_hours.hpp"
#include <algorithm>
#include <cstdlib>
#include <functional>
#include <iomanip>
#include <ios>
#include <ostream>
#include <type_traits>
#include <vector>
namespace
@ -92,12 +95,28 @@ class StreamFlagsKeeper
std::ios_base::fmtflags m_flags;
};
void PrintPaddedNumber(std::ostream & ost, uint32_t const number, uint32_t const padding = 1)
template <typename TNumber>
constexpr bool IsChar(TNumber) noexcept
{
return std::is_same<signed char, TNumber>::value ||
std::is_same<unsigned char, TNumber>::value ||
std::is_same<char, TNumber>::value;
};
template <typename TNumber, typename std::enable_if<!IsChar(TNumber{}), void*>::type = nullptr>
void PrintPaddedNumber(std::ostream & ost, TNumber const number, uint32_t const padding = 1)
{
static_assert(std::is_integral<TNumber>::value, "number should be of integral type.");
StreamFlagsKeeper keeper(ost);
ost << std::setw(padding) << std::setfill('0') << number;
}
template <typename TNumber, typename std::enable_if<IsChar(TNumber{}), void*>::type = nullptr>
void PrintPaddedNumber(std::ostream & ost, TNumber const number, uint32_t const padding = 1)
{
PrintPaddedNumber(ost, static_cast<int32_t>(number), padding);
}
void PrintHoursMinutes(std::ostream & ost,
std::chrono::hours::rep hours,
std::chrono::minutes::rep minutes)
@ -299,7 +318,7 @@ bool Timespan::HasExtendedHours() const
if (endHM.IsExtended())
return true;
return endHM.GetDurationCount() != 0 && (endHM.GetDuration() < startHM.GetDuration());
return endHM.GetDuration() <= startHM.GetDuration();
}
std::ostream & operator<<(std::ostream & ost, Timespan const & span)
@ -333,7 +352,7 @@ std::ostream & operator<<(std::ostream & ost, NthWeekdayOfTheMonthEntry const en
}
// WeekdayRange ------------------------------------------------------------------------------------
bool WeekdayRange::HasWday(Weekday const & wday) const
bool WeekdayRange::HasWday(Weekday const wday) const
{
if (IsEmpty() || wday == Weekday::None)
return false;
@ -341,10 +360,11 @@ bool WeekdayRange::HasWday(Weekday const & wday) const
if (!HasEnd())
return GetStart() == wday;
return GetStart() <= wday && wday <= GetEnd();
return (GetStart() <= GetEnd())
? GetStart() <= wday && wday <= GetEnd()
: wday <= GetEnd() || GetStart() <= wday;
}
std::ostream & operator<<(std::ostream & ost, Weekday const wday)
{
switch (wday)
@ -748,4 +768,28 @@ bool OpeningHours::IsValid() const
{
return m_valid;
}
bool OpeningHours::IsTwentyFourHours() const
{
return m_rule.size() == 1 && m_rule[0].IsTwentyFourHours();
}
bool OpeningHours::HasWeekdaySelector() const
{
return std::any_of(begin(m_rule), end(m_rule), std::mem_fn(&osmoh::RuleSequence::HasWeekdays));
}
bool OpeningHours::HasMonthSelector() const
{
return std::any_of(begin(m_rule), end(m_rule), std::mem_fn(&osmoh::RuleSequence::HasMonths));
}
bool OpeningHours::HasWeekSelector() const
{
return std::any_of(begin(m_rule), end(m_rule), std::mem_fn(&osmoh::RuleSequence::HasWeeks));
}
bool OpeningHours::HasYearSelector() const
{
return std::any_of(begin(m_rule), end(m_rule), std::mem_fn(&osmoh::RuleSequence::HasYears));
}
} // namespace osmoh

View file

@ -40,8 +40,8 @@ public:
using TMinutes = std::chrono::minutes;
HourMinutes() = default;
explicit HourMinutes(THours const duration) { SetDuration(duration); }
explicit HourMinutes(TMinutes const duration) { SetDuration(duration); }
HourMinutes(THours const duration) { SetDuration(duration); }
HourMinutes(TMinutes const duration) { SetDuration(duration); }
bool IsEmpty() const { return m_empty; }
bool IsExtended() const;
@ -69,6 +69,16 @@ private:
HourMinutes operator-(HourMinutes const & hm);
std::ostream & operator<<(std::ostream & ost, HourMinutes const & hm);
inline bool operator<(HourMinutes const & a, HourMinutes const & b)
{
return a.GetDuration() < b.GetDuration();
}
inline bool operator==(HourMinutes const & a, HourMinutes const & b)
{
return a.GetDuration() == b.GetDuration();
}
class Time;
class TimeEvent
@ -195,6 +205,11 @@ std::ostream & operator<<(std::ostream & ost, TimespanPeriod const p);
class Timespan
{
public:
Timespan() = default;
Timespan(Time const & start, Time const & end): m_start(start), m_end(end) {}
Timespan(HourMinutes::TMinutes const & start,
HourMinutes::TMinutes const & end): m_start(start), m_end(end) {}
bool IsEmpty() const { return !HasStart() && !HasEnd(); }
bool IsOpen() const { return HasStart() && !HasEnd(); }
bool HasStart() const { return !GetStart().IsEmpty(); }
@ -291,7 +306,7 @@ class WeekdayRange
using TNths = std::vector<NthWeekdayOfTheMonthEntry>;
public:
bool HasWday(Weekday const & wday) const;
bool HasWday(Weekday const wday) const;
bool HasSunday() const { return HasWday(Weekday::Sunday); }
bool HasMonday() const { return HasWday(Weekday::Monday); }
@ -656,6 +671,13 @@ public:
bool IsValid() const;
bool IsTwentyFourHours() const;
bool HasWeekdaySelector() const;
bool HasMonthSelector() const;
bool HasWeekSelector() const;
bool HasYearSelector() const;
TRuleSequences const & GetRule() const { return m_rule; }
private:
TRuleSequences m_rule;
bool const m_valid;

View file

@ -312,7 +312,7 @@ BOOST_AUTO_TEST_CASE(OpeningHours_TestTimespan)
span.SetStart(HourMinutes(10_h));
span.SetEnd(HourMinutes(00_h));
BOOST_CHECK(!span.HasExtendedHours());
BOOST_CHECK(span.HasExtendedHours());
BOOST_CHECK_EQUAL(ToString(span), "10:00-00:00");
}
@ -392,7 +392,19 @@ BOOST_AUTO_TEST_CASE(OpeningHours_TestWeekdayRange)
range.AddNth(entry);
BOOST_CHECK(range.HasNth());
}
{
WeekdayRange range;
range.SetStart(Weekday::Monday);
range.SetEnd(Weekday::Sunday);
BOOST_CHECK(range.HasSunday());
BOOST_CHECK(range.HasMonday());
BOOST_CHECK(range.HasTuesday());
BOOST_CHECK(range.HasWednesday());
BOOST_CHECK(range.HasThursday());
BOOST_CHECK(range.HasFriday());
BOOST_CHECK(range.HasSaturday());
}
}
BOOST_AUTO_TEST_CASE(OpeningHours_Holidays)

View file

@ -93,15 +93,6 @@ uint8_t GetWeekNumber(std::tm const & date)
return weekNumber;
}
bool IsBetweenLooped(osmoh::Weekday const start,
osmoh::Weekday const end,
osmoh::Weekday const p)
{
if (start <= end)
return start <= p && p <= end;
return p >= end || start <= p;
}
osmoh::RuleState ModifierToRuleState(osmoh::RuleSequence::Modifier const modifier)
{
using Modifier = osmoh::RuleSequence::Modifier;
@ -196,6 +187,9 @@ std::tm MakeTimetuple(time_t const timestamp)
namespace osmoh
{
// ADL shadows ::operator==.
using ::operator==;
bool IsActive(Timespan const & span, std::tm const & time)
{
// Timespan with e.h. should be split into parts with no e.h.
@ -236,10 +230,7 @@ bool IsActive(WeekdayRange const & range, std::tm const & date)
if (wday == Weekday::None)
return false;
if (range.HasEnd())
return IsBetweenLooped(range.GetStart(), range.GetEnd(), wday);
return range.GetStart() == wday;
return range.HasWday(wday);
}
bool IsActive(Holiday const & holiday, std::tm const & date)

View file

@ -38,6 +38,7 @@ class named_mutex;
// Our plugin is first, because it has naming conflicts with osrm part.
#include "../plugins/MapsMePlugin.hpp"
#include "../plugins/WayIdPlugin.hpp"
#include "../plugins/distance_table.hpp"
#include "../plugins/hello_world.hpp"
#include "../plugins/locate.hpp"
@ -90,6 +91,7 @@ OSRM_impl::OSRM_impl(libosrm_config &lib_config)
RegisterPlugin(new ViaRoutePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
RegisterPlugin(new MapsMePlugin<BaseDataFacade<QueryEdge::EdgeData>>(
query_data_facade, lib_config.server_paths["borders"].string(), lib_config.server_paths["enodesdata"].string()));
RegisterPlugin(new WayIdPlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade, lib_config.server_paths["enodesdata"].string()));
}
OSRM_impl::~OSRM_impl()

View file

@ -0,0 +1,165 @@
#pragma once
#include "plugin_base.hpp"
#include "../algorithms/object_encoder.hpp"
#include "../data_structures/search_engine.hpp"
#include "../data_structures/edge_based_node_data.hpp"
#include "../descriptors/descriptor_base.hpp"
#include "../descriptors/gpx_descriptor.hpp"
#include "../descriptors/json_descriptor.hpp"
#include "../util/integer_range.hpp"
#include "../util/json_renderer.hpp"
#include "../util/make_unique.hpp"
#include "../util/simple_logger.hpp"
#include <algorithm>
#include <limits>
#include <memory>
#include <set>
#include <string>
#include <unordered_map>
#include <vector>
template <class DataFacadeT>
class WayIdPlugin final : public BasePlugin
{
public:
WayIdPlugin(DataFacadeT * facade, std::string const & nodeDataFile)
: m_descriptorString("wayid"), m_facade(facade)
{
#ifndef MT_STRUCTURES
SimpleLogger().Write(logWARNING) << "Multitreaded storage was not set on compile time!!! Do "
"not use osrm-routed in several threads."
#endif
if (!osrm::LoadNodeDataFromFile(nodeDataFile, m_nodeData))
{
SimpleLogger().Write(logDEBUG) << "Can't load node data";
return;
}
m_searchEngine = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
}
const std::string GetDescriptor() const override final { return m_descriptorString; }
int HandleRequest(const RouteParameters & route_parameters,
osrm::json::Object & reply) override final
{
double constexpr kMaxDistanceToFindMeters = 1000.0;
// We process only two points case
if (route_parameters.coordinates.size() != 2)
return 400;
if (!check_all_coordinates(route_parameters.coordinates))
{
return 400;
}
std::vector<phantom_node_pair> phantom_node_pair_list(route_parameters.coordinates.size());
for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size()))
{
std::vector<std::pair<PhantomNode, double>> phantom_node_vector;
//FixedPointCoordinate &coordinate = route_parameters.coordinates[i];
if (m_facade->IncrementalFindPhantomNodeForCoordinateWithMaxDistance(route_parameters.coordinates[i],
phantom_node_vector, kMaxDistanceToFindMeters,
0 /*min_number_of_phantom_nodes*/, 2 /*max_number_of_phantom_nodes*/))
{
BOOST_ASSERT(!phantom_node_vector.empty());
// Don't know why, but distance may be higher that maxDistance.
if (phantom_node_vector.front().second > kMaxDistanceToFindMeters)
continue;
phantom_node_pair_list[i].first = phantom_node_vector.front().first;
if (phantom_node_vector.size() > 1)
{
if (phantom_node_vector.back().second > kMaxDistanceToFindMeters)
continue;
phantom_node_pair_list[i].second = phantom_node_vector.back().first;
}
}
}
auto check_component_id_is_tiny = [](const phantom_node_pair & phantom_pair)
{
return phantom_pair.first.component_id != 0;
};
const bool every_phantom_is_in_tiny_cc =
std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
check_component_id_is_tiny);
// are all phantoms from a tiny cc?
const auto component_id = phantom_node_pair_list.front().first.component_id;
auto check_component_id_is_equal = [component_id](const phantom_node_pair & phantom_pair)
{
return component_id == phantom_pair.first.component_id;
};
const bool every_phantom_has_equal_id =
std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
check_component_id_is_equal);
auto swap_phantom_from_big_cc_into_front = [](phantom_node_pair & phantom_pair)
{
if (0 != phantom_pair.first.component_id)
{
using namespace std;
swap(phantom_pair.first, phantom_pair.second);
}
};
// this case is true if we take phantoms from the big CC
if (!every_phantom_is_in_tiny_cc || !every_phantom_has_equal_id)
{
std::for_each(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
swap_phantom_from_big_cc_into_front);
}
InternalRouteResult raw_route;
auto build_phantom_pairs = [&raw_route](const phantom_node_pair & first_pair,
const phantom_node_pair & second_pair)
{
raw_route.segment_end_coordinates.emplace_back(
PhantomNodes{first_pair.first, second_pair.first});
};
osrm::for_each_pair(phantom_node_pair_list, build_phantom_pairs);
vector<bool> uturns;
m_searchEngine->shortest_path(raw_route.segment_end_coordinates, uturns, raw_route);
if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
{
SimpleLogger().Write(logDEBUG) << "Error occurred, single path not found";
return 400;
}
// Get ids of ways used in path.
set<uint64_t> wayIds;
for (auto i : osrm::irange<std::size_t>(0, raw_route.unpacked_path_segments.size()))
{
size_t const n = raw_route.unpacked_path_segments[i].size();
for (size_t j = 0; j < n; ++j)
{
PathData const & path_data = raw_route.unpacked_path_segments[i][j];
auto const & data = m_nodeData[path_data.node];
for (auto const & seg : data.m_segments)
wayIds.insert(seg.wayId);
}
}
// Format answer.
osrm::json::Array json_array;
json_array.values.assign(wayIds.begin(), wayIds.end());
reply.values["way_ids"] = move(json_array);
return 200;
}
private:
std::unique_ptr<SearchEngine<DataFacadeT>> m_searchEngine;
std::string m_descriptorString;
DataFacadeT * m_facade;
osrm::NodeDataVectorT m_nodeData;
};

View file

@ -4525,6 +4525,26 @@ PUGI__NS_BEGIN
return strcpy_insitu(dest, header, header_mask, begin, end - begin);
}
template <typename String, typename Header>
PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, long value)
{
char_t buf[64];
char_t* end = buf + sizeof(buf) / sizeof(buf[0]);
char_t* begin = integer_to_string<unsigned long>(buf, end, value, value < 0);
return strcpy_insitu(dest, header, header_mask, begin, end - begin);
}
template <typename String, typename Header>
PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, unsigned long value)
{
char_t buf[64];
char_t* end = buf + sizeof(buf) / sizeof(buf[0]);
char_t* begin = integer_to_string<unsigned long>(buf, end, value, false);
return strcpy_insitu(dest, header, header_mask, begin, end - begin);
}
template <typename String, typename Header>
PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, float value)
{
@ -5129,6 +5149,18 @@ namespace pugi
return *this;
}
PUGI__FN xml_attribute& xml_attribute::operator=(long rhs)
{
set_value(rhs);
return *this;
}
PUGI__FN xml_attribute& xml_attribute::operator=(unsigned long rhs)
{
set_value(rhs);
return *this;
}
PUGI__FN xml_attribute& xml_attribute::operator=(double rhs)
{
set_value(rhs);
@ -5189,6 +5221,20 @@ namespace pugi
return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
}
PUGI__FN bool xml_attribute::set_value(long rhs)
{
if (!_attr) return false;
return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
}
PUGI__FN bool xml_attribute::set_value(unsigned long rhs)
{
if (!_attr) return false;
return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
}
PUGI__FN bool xml_attribute::set_value(double rhs)
{
if (!_attr) return false;
@ -6322,6 +6368,20 @@ namespace pugi
return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
}
PUGI__FN bool xml_text::set(long rhs)
{
xml_node_struct* dn = _data_new();
return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
}
PUGI__FN bool xml_text::set(unsigned long rhs)
{
xml_node_struct* dn = _data_new();
return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
}
PUGI__FN bool xml_text::set(float rhs)
{
xml_node_struct* dn = _data_new();
@ -6377,6 +6437,18 @@ namespace pugi
return *this;
}
PUGI__FN xml_text& xml_text::operator=(long rhs)
{
set(rhs);
return *this;
}
PUGI__FN xml_text& xml_text::operator=(unsigned long rhs)
{
set(rhs);
return *this;
}
PUGI__FN xml_text& xml_text::operator=(double rhs)
{
set(rhs);

View file

@ -354,6 +354,8 @@ namespace pugi
// Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false")
bool set_value(int rhs);
bool set_value(unsigned int rhs);
bool set_value(long rhs);
bool set_value(unsigned long rhs);
bool set_value(double rhs);
bool set_value(float rhs);
bool set_value(bool rhs);
@ -367,6 +369,8 @@ namespace pugi
xml_attribute& operator=(const char_t* rhs);
xml_attribute& operator=(int rhs);
xml_attribute& operator=(unsigned int rhs);
xml_attribute& operator=(long rhs);
xml_attribute& operator=(unsigned long rhs);
xml_attribute& operator=(double rhs);
xml_attribute& operator=(float rhs);
xml_attribute& operator=(bool rhs);
@ -701,6 +705,8 @@ namespace pugi
// Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false")
bool set(int rhs);
bool set(unsigned int rhs);
bool set(long rhs);
bool set(unsigned long rhs);
bool set(double rhs);
bool set(float rhs);
bool set(bool rhs);
@ -714,6 +720,8 @@ namespace pugi
xml_text& operator=(const char_t* rhs);
xml_text& operator=(int rhs);
xml_text& operator=(unsigned int rhs);
xml_text& operator=(long rhs);
xml_text& operator=(unsigned long rhs);
xml_text& operator=(double rhs);
xml_text& operator=(float rhs);
xml_text& operator=(bool rhs);

View file

@ -13,6 +13,18 @@
#include "intrinsics.hpp"
namespace coding
{
template<typename TWriter>
class FreezeVisitor;
template <typename TWriter>
class ReverseFreezeVisitor;
class MapVisitor;
class ReverseMapVisitor;
}
namespace succinct { namespace mapper {
namespace detail {
@ -115,6 +127,15 @@ namespace succinct { namespace mapper {
friend class detail::map_visitor;
friend class detail::sizeof_visitor;
template<typename TWriter>
friend class coding::FreezeVisitor;
template<typename TWriter>
friend class coding::ReverseFreezeVisitor;
friend class coding::MapVisitor;
friend class coding::ReverseMapVisitor;
protected:
const T* m_data;
uint64_t m_size;

View file

@ -69,6 +69,10 @@
android:name="com.parse.push.notification_icon"
android:resource="@drawable/ic_notification"/>
<meta-data
android:name="io.fabric.ApiKey"
android:value="${FABRIC_API_KEY}"/>
<activity
android:name="com.mapswithme.maps.DownloadResourcesActivity"
android:configChanges="orientation|screenLayout|screenSize"
@ -173,7 +177,7 @@
android:windowSoftInputMode="stateAlwaysHidden|adjustPan"/>
<activity
android:name="com.mapswithme.country.DownloadActivity"
android:name="com.mapswithme.maps.downloader.DownloaderActivity"
android:configChanges="orientation|screenLayout|screenSize"
android:label="@string/download_maps"
android:parentActivityName="com.mapswithme.maps.MwmActivity">
@ -228,6 +232,45 @@
android:value="com.mapswithme.maps.bookmarks.BookmarkCategoriesActivity"/>
</activity>
<activity
android:name="com.mapswithme.maps.editor.EditorActivity"
android:configChanges="orientation|screenLayout|screenSize"
android:label="@string/edit_place"
android:theme="@style/MwmTheme.EditorActivity"
android:parentActivityName="com.mapswithme.maps.MwmActivity">
<!-- The meta-data element is needed for versions lower than 4.1 -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.mapswithme.maps.MwmActivity"/>
</activity>
<activity
android:name="com.mapswithme.maps.editor.ProfileActivity"
android:parentActivityName="com.mapswithme.maps.settings.SettingsActivity">
<!-- The meta-data element is needed for versions lower than 4.1 -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.mapswithme.maps.settings.SettingsActivity"/>
</activity>
<activity
android:name="com.mapswithme.maps.editor.FeatureCategoryActivity"
android:parentActivityName="com.mapswithme.maps.MwmActivity">
<!-- The meta-data element is needed for versions lower than 4.1 -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.mapswithme.maps.MwmActivity"/>
</activity>
<activity
android:name="com.mapswithme.maps.editor.ReportActivity"
android:parentActivityName="com.mapswithme.maps.MwmActivity">
<!-- The meta-data element is needed for versions lower than 4.1 -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.mapswithme.maps.MwmActivity"/>
</activity>
<!-- facebook -->
<activity
android:name="com.facebook.FacebookActivity"

View file

@ -23,7 +23,7 @@ define add_prebuild_static_lib
include $(PREBUILT_STATIC_LIBRARY)
endef
prebuild_static_libs := minizip osrm protobuf tomcrypt jansson fribidi freetype expat base coding geometry anim platform graphics indexer storage search routing gui map opening_hours stats_client succinct
prebuild_static_libs := minizip osrm protobuf tomcrypt jansson fribidi freetype expat base coding geometry platform indexer storage search routing map opening_hours stats_client succinct
$(foreach item,$(prebuild_static_libs),$(eval $(call add_prebuild_static_lib,$(item))))
@ -59,6 +59,6 @@ LOCAL_SRC_FILES += $(ROOT_PATH_FROM_JNI)/testing/testingmain.cpp
LOCAL_SRC_FILES += $(ROOT_PATH_FROM_JNI)/android/UnitTests/jni/mock.cpp
LOCAL_SRC_FILES += ./test.cpp
LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv1_CM
LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv1_CM
LOCAL_LDLIBS += -lGLESv2 -latomic -lz
LOCAL_LDLIBS += -Wl,--gc-sections

View file

@ -53,7 +53,7 @@ namespace yopme
if (!m_framework.IsCountryLoaded(viewPortCenter) && (zoom > scales::GetUpperWorldScale()))
return false;
m_framework.ShowRect(vpLat, vpLon, zoom);
m_framework.SetViewportCenter(viewPortCenter, zoom);
m2::PointD const poi(MercatorBounds::FromLatLon(poiLat, poiLon));
m2::PointD const myLocation(MercatorBounds::FromLatLon(myLat, myLon));
ShowRect(hasPoi, poi, hasLocation, myLocation);

View file

@ -10,9 +10,6 @@ namespace
static shared_ptr<yopme::Framework> s_framework;
}
// @TODO refactor and remove that
void InitNVEvent(JavaVM * jvm) {}
extern "C"
{

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,10 +1,14 @@
buildscript {
repositories {
jcenter()
maven {
url 'https://maven.fabric.io/public'
}
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.1'
classpath 'io.fabric.tools:gradle:1.+'
}
}
@ -15,8 +19,15 @@ allprojects {
}
}
repositories {
maven {
url 'https://maven.fabric.io/public'
}
}
apply plugin: 'com.android.application'
apply from: 'secure.properties'
apply plugin: 'io.fabric'
dependencies {
// android support libs
@ -24,10 +35,15 @@ dependencies {
compile 'com.android.support:appcompat-v7:22.2.1'
compile 'com.android.support:recyclerview-v7:22.2.1'
compile 'com.android.support:design:22.2.1'
compile 'com.android.support:cardview-v7:22.2.1'
// google play services
compile 'com.google.android.gms:play-services-location:8.4.0'
compile 'com.google.android.gms:play-services-analytics:8.4.0'
compile 'com.google.android.gms:play-services-plus:8.4.0'
// crash reporting
compile 'net.hockeyapp.android:HockeySDK:3.7.1'
compile('com.crashlytics.sdk.android:crashlytics:2.5.5@aar') { transitive = true }
compile('com.crashlytics.sdk.android:crashlytics-ndk:1.1.2@aar') { transitive = true }
// 3-party
compile 'com.facebook.android:facebook-android-sdk:4.10.0'
compile 'com.parse.bolts:bolts-android:1.4.0'
@ -39,6 +55,7 @@ dependencies {
// LinearLayoutManager allowing wrap_content of RecyclerView-s
// TODO remove this library when default LinearLayoutManager will be fixed.
compile 'org.solovyev.android.views:linear-layout-manager:0.5@aar'
compile 'com.timehop.stickyheadersrecyclerview:library:0.4.3@aar'
}
def getDate() {
@ -50,6 +67,12 @@ def getDate() {
project.ext.versionCodes = ['armeabi-v7a': 1, 'x86': 2]
project.ext.appId = 'com.mapswithme.maps.pro'
crashlytics {
enableNdk true
androidNdkOut 'obj/local'
androidNdkLibsOut 'libs'
}
android {
// All properties are read from gradle.properties file
compileSdkVersion propTargetSdkVersion.toInteger()
@ -65,6 +88,12 @@ android {
buildConfigField 'String', 'SUPPORT_MAIL', '"android@maps.me"'
buildConfigField 'String', 'REVIEW_URL', '"market://details?id=com.mapswithme.maps.pro"'
buildConfigField 'int', 'RATING_THRESHOLD', '5'
// Crashlytics API key
Properties props = new Properties()
props.load(new FileInputStream("${projectDir}/fabric.properties"));
manifestPlaceholders = [ 'FABRIC_API_KEY': props['apiKey'] ]
buildConfigField 'String', 'FABRIC_API_KEY', /"${props['apiKey']}"/
}
sourceSets.main {
@ -251,9 +280,10 @@ android {
}
}
// We don't compress these extensions in assets/ because our random FileReader can't read zip-compressed files from apk
// We don't compress these extensions in assets/ because our random FileReader can't read zip-compressed files from apk.
// TODO: Load all minor files via separate call to ReadAsString which can correctly handle compressed files in zip containers.
aaptOptions {
noCompress 'txt', 'bin', 'html', 'png', 'json', 'mwm', 'ttf', 'sdf', 'ui'
noCompress 'txt', 'bin', 'html', 'png', 'json', 'mwm', 'ttf', 'sdf', 'ui', 'config'
ignoreAssetsPattern "!.svn:!.git:!.DS_Store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"
}
@ -370,10 +400,10 @@ task obbPush(dependsOn: ['obbGenerate', 'obbPushMain', 'obbPushPatch']) {
commandLine android.getAdbExe(), 'shell', 'rm', "${obbPath}*.obb"
}
tasks.create(type: Exec, name: 'obbPushMain', dependsOn: 'obbRemoveOnDevice') {
commandLine android.getAdbExe(), 'push', propObbWorldsOutput, "${obbPath}fonts.obb"
commandLine android.getAdbExe(), 'push', propObbFontsOutput, "${obbPath}fonts.obb"
}
tasks.create(type: Exec, name: 'obbPushPatch', dependsOn: 'obbRemoveOnDevice') {
commandLine android.getAdbExe(), 'push', propObbFontsOutput, "${obbPath}worlds.obb"
commandLine android.getAdbExe(), 'push', propObbWorldsOutput, "${obbPath}worlds.obb"
}
}

View file

@ -0,0 +1 @@
../../../data/WorldCoasts_obsolete.mwm

View file

@ -3,8 +3,8 @@ propMinSdkVersion=15
# https://code.google.com/p/android/issues/detail?id=184567
propTargetSdkVersion=22
propBuildToolsVersion=22.0.1
propVersionCode=564
propVersionName=5.6.4
propVersionCode=570
propVersionName=5.7.0
propDebugNdkFlags=V=1 NDK_DEBUG=1 DEBUG=1
propReleaseNdkFlags=V=1 NDK_DEBUG=0 PRODUCTION=1
@ -16,6 +16,8 @@ propObbFonts ../data/01_dejavusans.ttf \
../data/05_khmeros.ttf \
../data/06_code2000.ttf \
../data/07_roboto_medium.ttf
propObbWorlds ../data/World.mwm ../data/WorldCoasts.mwm
propObbWorlds ../data/World.mwm \
../data/WorldCoasts.mwm \
../data/WorldCoasts_obsolete.mwm
propObbWorldsOutput build/worlds.obb
propObbFontsOutput build/fonts.obb

View file

@ -25,7 +25,8 @@ define add_prebuild_static_lib
include $(PREBUILT_STATIC_LIBRARY)
endef
prebuild_static_libs := osrm protobuf tomcrypt jansson minizip fribidi freetype expat base coding geometry platform indexer storage search routing drape drape_frontend map stats_client succinct opening_hours
prebuild_static_libs := map drape_frontend routing search storage indexer drape platform editor geometry coding base opening_hours
prebuild_static_libs += pugixml oauthcpp expat freetype fribidi minizip jansson tomcrypt protobuf osrm stats_client succinct
$(foreach item,$(prebuild_static_libs),$(eval $(call add_prebuild_static_lib,$(item))))
@ -40,7 +41,8 @@ LOCAL_CPP_FEATURES += exceptions rtti
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../
LOCAL_MODULE := mapswithme
LOCAL_STATIC_LIBRARIES := map drape_frontend routing search storage indexer drape platform geometry coding base expat freetype fribidi minizip jansson tomcrypt protobuf osrm stats_client succinct opening_hours
LOCAL_STATIC_LIBRARIES := $(prebuild_static_libs)
LOCAL_CFLAGS := -ffunction-sections -fdata-sections -Wno-extern-c-compat
ifneq ($(NDK_DEBUG),1)
@ -59,12 +61,10 @@ TARGET_PLATFORM := android-15
LOCAL_HEADER_FILES := \
../../private.h \
com/mapswithme/core/jni_helper.hpp \
com/mapswithme/core/ScopedLocalRef.hpp \
com/mapswithme/core/logging.hpp \
com/mapswithme/maps/Framework.hpp \
com/mapswithme/maps/MapStorage.hpp \
com/mapswithme/platform/Platform.hpp \
com/mapswithme/platform/MethodRef.hpp \
com/mapswithme/platform/http_thread_android.hpp \
com/mapswithme/opengl/android_gl_utils.hpp \
com/mapswithme/opengl/androidoglcontext.hpp \
com/mapswithme/opengl/androidoglcontextfactory.hpp \
@ -72,9 +72,6 @@ LOCAL_HEADER_FILES := \
LOCAL_SRC_FILES := \
com/mapswithme/core/jni_helper.cpp \
com/mapswithme/core/logging.cpp \
com/mapswithme/country/country_helper.cpp \
com/mapswithme/country/CountryTree.cpp \
com/mapswithme/country/ActiveCountryTree.cpp \
com/mapswithme/maps/Framework.cpp \
com/mapswithme/maps/bookmarks/data/Bookmark.cpp \
com/mapswithme/maps/bookmarks/data/BookmarkManager.cpp \
@ -85,22 +82,25 @@ LOCAL_SRC_FILES := \
com/mapswithme/maps/LocationState.cpp \
com/mapswithme/maps/LocationHelper.cpp \
com/mapswithme/maps/TrackRecorder.cpp \
com/mapswithme/maps/MapStorage.cpp \
com/mapswithme/maps/MapManager.cpp \
com/mapswithme/maps/DownloadResourcesActivity.cpp \
com/mapswithme/maps/PrivateVariables.cpp \
com/mapswithme/maps/SearchEngine.cpp \
com/mapswithme/maps/SearchRecents.cpp \
com/mapswithme/maps/UserMarkHelper.cpp \
com/mapswithme/maps/settings/UnitLocale.cpp \
com/mapswithme/platform/Platform.cpp \
com/mapswithme/platform/HttpThread.cpp \
com/mapswithme/platform/Language.cpp \
com/mapswithme/platform/MethodRef.cpp \
com/mapswithme/platform/PThreadImpl.cpp \
com/mapswithme/util/StringUtils.cpp \
com/mapswithme/util/Config.cpp \
com/mapswithme/util/Config.cpp \
com/mapswithme/opengl/android_gl_utils.cpp \
com/mapswithme/opengl/androidoglcontext.cpp \
com/mapswithme/opengl/androidoglcontextfactory.cpp \
com/mapswithme/maps/editor/OpeningHours.cpp \
com/mapswithme/maps/editor/Editor.cpp \
com/mapswithme/maps/editor/OsmOAuth.cpp
LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv2 -latomic -lz

View file

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

View file

@ -1,7 +1,10 @@
#include "jni_helper.hpp"
#include "logging.hpp"
#include "ScopedLocalRef.hpp"
#include "base/assert.hpp"
#include "base/exception.hpp"
#include "base/logging.hpp"
#include "std/vector.hpp"
static JavaVM * g_jvm = 0;
@ -10,17 +13,9 @@ extern JavaVM * GetJVM()
return g_jvm;
}
// TODO refactor cached jclass to smth more
// TODO finish this logic after refactoring
// cached classloader that can be used to find classes & methods from native threads.
//static shared_ptr<jobject> g_classLoader;
//static jmethodID g_findClassMethod;
// caching is necessary to create class from native threads
jclass g_indexClazz;
// @TODO remove after refactoring. Needed for NVidia code
void InitNVEvent(JavaVM * jvm);
jclass g_mapObjectClazz;
jclass g_bookmarkClazz;
extern "C"
{
@ -32,20 +27,8 @@ extern "C"
jni::InitAssertLog();
JNIEnv * env = jni::GetEnv();
// TODO
// init classloader & findclass methodID.
// auto randomClass = env->FindClass("com/mapswithme/maps/MapStorage");
// jclass classClass = env->GetObjectClass(randomClass);
// auto classLoaderClass = env->FindClass("java/lang/ClassLoader");
// auto getClassLoaderMethod = env->GetMethodID(classClass, "getClassLoader",
// "()Ljava/lang/ClassLoader;");
// g_classLoader = jni::make_global_ref(env->CallObjectMethod(randomClass, getClassLoaderMethod));
// ASSERT(*g_classLoader, ("Classloader can't be 0"));
// g_findClassMethod = env->GetMethodID(classLoaderClass, "findClass",
// "(Ljava/lang/String;)Ljava/lang/Class;");
// ASSERT(g_findClassMethod, ("FindClass methodId can't be 0"));
g_indexClazz = static_cast<jclass>(env->NewGlobalRef(env->FindClass("com/mapswithme/maps/MapStorage$Index")));
ASSERT(g_indexClazz, ("Index class not found!"));
g_mapObjectClazz = jni::GetGlobalClassRef(env, "com/mapswithme/maps/bookmarks/data/MapObject");
g_bookmarkClazz = jni::GetGlobalClassRef(env, "com/mapswithme/maps/bookmarks/data/Bookmark");
return JNI_VERSION_1_6;
}
@ -54,38 +37,46 @@ extern "C"
JNI_OnUnload(JavaVM *, void *)
{
g_jvm = 0;
jni::GetEnv()->DeleteGlobalRef(g_indexClazz);
JNIEnv * env = jni::GetEnv();
env->DeleteGlobalRef(g_mapObjectClazz);
env->DeleteGlobalRef(g_bookmarkClazz);
}
} // extern "C"
namespace jni
{
//
// jclass FindClass(char const * name)
// {
// JNIEnv * env = GetEnv();
// jstring className = env->NewStringUTF(name);
// jclass clazz = static_cast<jclass>(GetEnv()->CallObjectMethod(*g_classLoader, g_findClassMethod, className));
// env->DeleteLocalRef(className);
// return clazz;
// }
jmethodID GetJavaMethodID(JNIEnv * env, jobject obj, char const * fn, char const * sig)
JNIEnv * GetEnv()
{
ASSERT(env, ("JNIEnv can't be 0"));
ASSERT(obj, ("jobject can't be 0"));
JNIEnv * env;
if (JNI_OK != g_jvm->GetEnv((void **)&env, JNI_VERSION_1_6))
MYTHROW(RootException, ("Can't get JNIEnv. Was thread attached to JVM?"));
jclass cls = env->GetObjectClass(obj);
ASSERT(cls, ("Can't get class: ", DescribeException()));
return env;
}
jmethodID mid = env->GetMethodID(cls, fn, sig);
JavaVM * GetJVM()
{
ASSERT(g_jvm, ("JVM is not initialized"));
return g_jvm;
}
jmethodID GetMethodID(JNIEnv * env, jobject obj, char const * fn, char const * sig)
{
TScopedLocalClassRef clazz(env, env->GetObjectClass(obj));
ASSERT(clazz.get(), ("Can't get class: ", DescribeException()));
jmethodID mid = env->GetMethodID(clazz.get(), fn, sig);
ASSERT(mid, ("Can't get methodID", fn, sig, DescribeException()));
env->DeleteLocalRef(cls);
return mid;
}
jmethodID GetConstructorID(JNIEnv * env, jclass clazz, char const * sig)
{
jmethodID const ctorID = env->GetMethodID(clazz, "<init>", sig);
ASSERT(ctorID, (DescribeException()));
return ctorID;
}
jclass GetGlobalClassRef(JNIEnv * env, char const * sig)
{
jclass klass = env->FindClass(sig);
@ -128,28 +119,11 @@ namespace jni
return "java/lang/String";
}
JNIEnv * GetEnv()
{
JNIEnv * env;
if (JNI_OK != g_jvm->GetEnv((void **)&env, JNI_VERSION_1_6))
{
ASSERT(false, ("Can't get JNIEnv. Was thread attached to JVM?"));
return 0;
}
return env;
}
JavaVM * GetJVM()
{
ASSERT(g_jvm, ("JVM is not initialized"));
return g_jvm;
}
struct global_ref_deleter
{
void operator()(jobject * ref)
{
jni::GetEnv()->DeleteGlobalRef(*ref);
GetEnv()->DeleteGlobalRef(*ref);
delete ref;
}
};
@ -157,13 +131,13 @@ namespace jni
shared_ptr<jobject> make_global_ref(jobject obj)
{
jobject * ref = new jobject;
*ref = jni::GetEnv()->NewGlobalRef(obj);
*ref = GetEnv()->NewGlobalRef(obj);
return shared_ptr<jobject>(ref, global_ref_deleter());
}
string DescribeException()
{
JNIEnv * env = jni::GetEnv();
JNIEnv * env = GetEnv();
if (env->ExceptionCheck())
{
@ -188,14 +162,11 @@ namespace jni
{
jclass klass = env->FindClass("com/mapswithme/maps/bookmarks/data/ParcelablePointD");
ASSERT ( klass, () );
jmethodID methodID = env->GetMethodID(
klass, "<init>",
"(DD)V");
ASSERT ( methodID, () );
jmethodID methodID = GetConstructorID(env, klass, "(DD)V");
return env->NewObject(klass, methodID,
static_cast<jdouble>(point.x),
static_cast<jdouble>(point.y));
static_cast<jdouble>(point.x),
static_cast<jdouble>(point.y));
}
jobject GetNewPoint(JNIEnv * env, m2::PointD const & point)
@ -207,27 +178,20 @@ namespace jni
{
jclass klass = env->FindClass("android/graphics/Point");
ASSERT ( klass, () );
jmethodID methodID = env->GetMethodID(
klass, "<init>",
"(II)V");
ASSERT ( methodID, () );
jmethodID methodID = GetConstructorID(env, klass, "(II)V");
return env->NewObject(klass, methodID,
static_cast<jint>(point.x),
static_cast<jint>(point.y));
}
// TODO
// make ScopedLocalRef wrapper similar to https://android.googlesource.com/platform/libnativehelper/+/jb-mr1.1-dev-plus-aosp/include/nativehelper/ScopedLocalRef.h
// for localrefs automatically removed after going out of scope
// This util method dumps content of local and global reference jni tables to logcat for debug and testing purposes
void DumpDalvikReferenceTables()
{
JNIEnv * env = jni::GetEnv();
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);
}
} // namespace jni
} // namespace jni

View file

@ -2,35 +2,32 @@
#include <jni.h>
#include "ScopedLocalRef.hpp"
#include "geometry/point2d.hpp"
#include "std/string.hpp"
#include "std/shared_ptr.hpp"
// cache MapIndex jclass
extern jclass g_indexClazz;
extern jclass g_mapObjectClazz;
extern jclass g_bookmarkClazz;
namespace jni
{
// TODO yunitsky uncomment and use to load classes from native threads.
// jclass FindClass(char const * name);
JNIEnv * GetEnv();
JavaVM * GetJVM();
jmethodID GetJavaMethodID(JNIEnv * env, jobject obj, char const * fn, char const * sig);
jmethodID GetMethodID(JNIEnv * env, jobject obj, char const * fn, char const * sig);
jmethodID GetConstructorID(JNIEnv * env, jclass clazz, char const * sig);
// Result value should be DeleteGlobalRef`ed by caller
jclass GetGlobalClassRef(JNIEnv * env, char const * s);
JNIEnv * GetEnv();
JavaVM * GetJVM();
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.
string ToNativeString(JNIEnv * env, jbyteArray const & utfBytes);
jstring ToJavaString(JNIEnv * env, char const * s);
inline jstring ToJavaString(JNIEnv * env, string const & s)
{
return ToJavaString(env, s.c_str());
@ -42,6 +39,11 @@ namespace jni
string DescribeException();
shared_ptr<jobject> make_global_ref(jobject obj);
using TScopedLocalRef = ScopedLocalRef<jobject>;
using TScopedLocalClassRef = ScopedLocalRef<jclass>;
using TScopedLocalObjectArrayRef = ScopedLocalRef<jobjectArray>;
using TScopedLocalIntArrayRef = ScopedLocalRef<jintArray>;
using TScopedLocalByteArrayRef = ScopedLocalRef<jbyteArray>;
jobject GetNewParcelablePointD(JNIEnv * env, m2::PointD const & point);

View file

@ -1,148 +0,0 @@
#include <jni.h>
#include "../maps/Framework.hpp"
#include "../maps/MapStorage.hpp"
#include "../core/jni_helper.hpp"
#include "country_helper.hpp"
using namespace storage_utils;
using namespace storage;
extern "C"
{
JNIEXPORT jint JNICALL
Java_com_mapswithme_country_ActiveCountryTree_getOutOfDateCount(JNIEnv * env, jclass clazz)
{
return GetMapLayout().GetOutOfDateCount();
}
JNIEXPORT jint JNICALL
Java_com_mapswithme_country_ActiveCountryTree_getCountInGroup(JNIEnv * env, jclass clazz, jint group)
{
return GetMapLayout().GetCountInGroup(ToGroup(group));
}
JNIEXPORT jobject JNICALL
Java_com_mapswithme_country_ActiveCountryTree_getCountryItem(JNIEnv * env, jclass clazz, jint group, jint position)
{
ActiveMapsLayout & layout = GetMapLayout();
ActiveMapsLayout::TGroup coreGroup = ToGroup(group);
int corePosition = static_cast<int>(position);
jstring name = jni::ToJavaString(env, layout.GetCountryName(coreGroup, corePosition));
jint status = static_cast<jint>(layout.GetCountryStatus(coreGroup, corePosition));
jint options = static_cast<jint>(layout.GetCountryOptions(coreGroup, corePosition));
jclass createClass = env->FindClass("com/mapswithme/country/CountryItem");
ASSERT(createClass, ());
jmethodID createMethodId = env->GetMethodID(createClass, "<init>", "(Ljava/lang/String;IIZ)V");
ASSERT(createMethodId, ());
return env->NewObject(createClass, createMethodId,
name, status, options, JNI_FALSE);
}
JNIEXPORT jlong JNICALL
Java_com_mapswithme_country_ActiveCountryTree_getCountrySize(JNIEnv * env, jclass clazz, jint group, jint position, jint options, jboolean isLocal)
{
ActiveMapsLayout & layout = GetMapLayout();
ActiveMapsLayout::TGroup coreGroup = ToGroup(group);
int pos = static_cast<int>(position);
bool const local = isLocal == JNI_TRUE;
MapOptions opt = ToOptions(options);
if (options == -1 || local)
{
LocalAndRemoteSizeT sizes = options == -1 ? layout.GetDownloadableCountrySize(coreGroup, pos)
: layout.GetCountrySize(coreGroup, pos, opt);
return local ? sizes.first : sizes.second;
}
LocalAndRemoteSizeT sizes = layout.GetRemoteCountrySizes(coreGroup, pos);
switch (opt)
{
case MapOptions::Map:
return sizes.first;
case MapOptions::CarRouting:
return sizes.second;
default:
return sizes.first + sizes.second;
}
}
JNIEXPORT void JNICALL
Java_com_mapswithme_country_ActiveCountryTree_cancelDownloading(JNIEnv * env, jclass clazz, jint group, jint position)
{
GetMapLayout().CancelDownloading(ToGroup(group), position);
}
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_country_ActiveCountryTree_isDownloadingActive(JNIEnv * env, jclass clazz)
{
return GetMapLayout().IsDownloadingActive();
}
JNIEXPORT void JNICALL
Java_com_mapswithme_country_ActiveCountryTree_retryDownloading(JNIEnv * env, jclass clazz, jint group, jint position)
{
GetMapLayout().RetryDownloading(ToGroup(group), position);
}
JNIEXPORT void JNICALL
Java_com_mapswithme_country_ActiveCountryTree_downloadMap(JNIEnv * env, jclass clazz, jint group, jint position, jint options)
{
GetMapLayout().DownloadMap(ToGroup(group), position, ToOptions(options));
}
JNIEXPORT void JNICALL
Java_com_mapswithme_country_ActiveCountryTree_deleteMap(JNIEnv * env, jclass clazz, jint group, jint position, jint options)
{
GetMapLayout().DeleteMap(ToGroup(group), position, ToOptions(options));
}
JNIEXPORT void JNICALL
Java_com_mapswithme_country_ActiveCountryTree_showOnMap(JNIEnv * env, jclass clazz, jint group, jint position)
{
g_framework->PostDrapeTask([group, position]()
{
GetMapLayout().ShowMap(ToGroup(group), position);
});
}
JNIEXPORT void JNICALL
Java_com_mapswithme_country_ActiveCountryTree_updateAll(JNIEnv * env, jclass clazz)
{
GetMapLayout().UpdateAll();
}
JNIEXPORT void JNICALL
Java_com_mapswithme_country_ActiveCountryTree_cancelAll(JNIEnv * env, jclass clazz)
{
GetMapLayout().CancelAll();
}
JNIEXPORT int JNICALL
Java_com_mapswithme_country_ActiveCountryTree_addListener(JNIEnv * env, jclass clazz, jobject listener)
{
return g_framework->AddActiveMapsListener(jni::make_global_ref(listener));
}
JNIEXPORT void JNICALL
Java_com_mapswithme_country_ActiveCountryTree_removeListener(JNIEnv * env, jclass clazz, jint slotID)
{
g_framework->RemoveActiveMapsListener(slotID);
}
JNIEXPORT jobject JNICALL
Java_com_mapswithme_country_ActiveCountryTree_getCoreIndex(JNIEnv * env, jclass clazz, jint group, jint position)
{
return storage::ToJava(GetMapLayout().GetCoreIndex(static_cast<storage::ActiveMapsLayout::TGroup>(group),
static_cast<int>(position)));
}
JNIEXPORT void JNICALL
Java_com_mapswithme_country_ActiveCountryTree_downloadMapForIndex(JNIEnv * env, jclass clazz, jobject index, jint options)
{
GetMapLayout().DownloadMap(storage::ToNative(index), ToOptions(options));
}
}

View file

@ -1,138 +0,0 @@
#include <jni.h>
#include "../maps/Framework.hpp"
#include "../core/jni_helper.hpp"
#include "country_helper.hpp"
using namespace storage_utils;
using namespace storage;
extern "C"
{
JNIEXPORT void JNICALL
Java_com_mapswithme_country_CountryTree_setDefaultRoot(JNIEnv * env, jclass clazz)
{
GetTree().SetDefaultRoot();
}
JNIEXPORT void JNICALL
Java_com_mapswithme_country_CountryTree_setParentAsRoot(JNIEnv * env, jclass clazz)
{
GetTree().SetParentAsRoot();
}
JNIEXPORT void JNICALL
Java_com_mapswithme_country_CountryTree_setChildAsRoot(JNIEnv * env, jclass clazz, jint position)
{
GetTree().SetChildAsRoot(position);
}
JNIEXPORT void JNICALL
Java_com_mapswithme_country_CountryTree_resetRoot(JNIEnv * env, jclass clazz)
{
GetTree().ResetRoot();
}
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_country_CountryTree_hasParent(JNIEnv * env, jclass clazz)
{
return GetTree().HasParent();
}
JNIEXPORT jint JNICALL
Java_com_mapswithme_country_CountryTree_getChildCount(JNIEnv * env, jclass clazz)
{
return GetTree().GetChildCount();
}
JNIEXPORT jobject JNICALL
Java_com_mapswithme_country_CountryTree_getChildItem(JNIEnv * env, jclass clazz, jint position)
{
CountryTree & tree = GetTree();
int corePosition = static_cast<int>(position);
bool const isLeaf = tree.IsLeaf(corePosition);
jstring name = jni::ToJavaString(env, tree.GetChildName(corePosition));
jint status = isLeaf ? static_cast<jint>(tree.GetLeafStatus(corePosition)) : 0;
jint options = isLeaf ? static_cast<jint>(tree.GetLeafOptions(corePosition)) : 0;
jclass createClass = env->FindClass("com/mapswithme/country/CountryItem");
ASSERT(createClass, ());
jmethodID createMethodId = env->GetMethodID(createClass, "<init>", "(Ljava/lang/String;IIZ)V");
ASSERT(createMethodId, ());
return env->NewObject(createClass, createMethodId,
name, status, options, (!isLeaf) == true ? JNI_TRUE : JNI_FALSE);
}
JNIEXPORT void JNICALL
Java_com_mapswithme_country_CountryTree_downloadCountry(JNIEnv * env, jclass clazz, jint position, jint options)
{
GetTree().DownloadCountry(position, ToOptions(options));
}
JNIEXPORT void JNICALL
Java_com_mapswithme_country_CountryTree_deleteCountry(JNIEnv * env, jclass clazz, jint position, jint options)
{
GetTree().DeleteCountry(position, ToOptions(options));
}
JNIEXPORT void JNICALL
Java_com_mapswithme_country_CountryTree_cancelDownloading(JNIEnv * env, jclass clazz, jint position)
{
GetTree().CancelDownloading(position);
}
JNIEXPORT void JNICALL
Java_com_mapswithme_country_CountryTree_retryDownloading(JNIEnv * env, jclass clazz, jint position)
{
GetTree().RetryDownloading(position);
}
JNIEXPORT void JNICALL
Java_com_mapswithme_country_CountryTree_showLeafOnMap(JNIEnv * env, jclass clazz, jint position)
{
g_framework->PostDrapeTask([position]()
{
GetTree().ShowLeafOnMap(position);
});
}
JNIEXPORT jlong JNICALL
Java_com_mapswithme_country_CountryTree_getLeafSize(JNIEnv * env, jclass clazz, jint position, jint options, jboolean isLocal)
{
CountryTree & tree = GetTree();
int pos = static_cast<int>(position);
bool const local = (isLocal == JNI_TRUE) ? true : false;
MapOptions opt = ToOptions(options);
if (options == -1 || local)
{
LocalAndRemoteSizeT sizes = options == -1 ? tree.GetDownloadableLeafSize(pos) : tree.GetLeafSize(pos, opt);
return local ? sizes.first : sizes.second;
}
LocalAndRemoteSizeT sizes = tree.GetRemoteLeafSizes(pos);
switch (opt)
{
case MapOptions::Map:
return sizes.first;
case MapOptions::CarRouting:
return sizes.second;
default:
return sizes.first + sizes.second;
}
}
JNIEXPORT void JNICALL
Java_com_mapswithme_country_CountryTree_setListener(JNIEnv * env, jclass clazz, jobject listener)
{
g_framework->SetCountryTreeListener(jni::make_global_ref(listener));
}
JNIEXPORT void JNICALL
Java_com_mapswithme_country_CountryTree_resetListener(JNIEnv * env, jclass clazz, jobject listener)
{
g_framework->ResetCountryTreeListener();
}
}

View file

@ -1,23 +0,0 @@
#include "country_helper.hpp"
namespace storage_utils
{
::Framework * frm() { return g_framework->NativeFramework(); }
storage::ActiveMapsLayout & GetMapLayout() { return frm()->GetCountryTree().GetActiveMapLayout(); }
storage::CountryTree & GetTree() { return frm()->GetCountryTree(); }
storage::ActiveMapsLayout::TGroup ToGroup(int group) { return static_cast<storage::ActiveMapsLayout::TGroup>(group); }
MapOptions ToOptions(int options) { return static_cast<MapOptions>(options); }
jlongArray ToArray(JNIEnv * env, storage::LocalAndRemoteSizeT const & size)
{
jlongArray result = env->NewLongArray(2);
jlong * arr = env->GetLongArrayElements(result, NULL);
arr[0] = size.first;
arr[1] = size.second;
env->ReleaseLongArrayElements(result, arr, 0);
return result;
}
}

View file

@ -1,19 +0,0 @@
#pragma once
#include "../core/jni_helper.hpp"
#include "../maps/MapStorage.hpp"
#include "../maps/Framework.hpp"
#include "platform/country_defines.hpp"
namespace storage_utils
{
::Framework * frm();
storage::ActiveMapsLayout & GetMapLayout();
storage::CountryTree & GetTree();
storage::ActiveMapsLayout::TGroup ToGroup(int group);
MapOptions ToOptions(int options);
jlongArray ToArray(JNIEnv * env, storage::LocalAndRemoteSizeT const & sizes);
}

View file

@ -1,5 +1,4 @@
#include "Framework.hpp"
#include "MapStorage.hpp"
#include "defines.hpp"
@ -15,6 +14,8 @@
#include "base/logging.hpp"
#include "base/string_utils.hpp"
#include "com/mapswithme/core/jni_helper.hpp"
#include "std/vector.hpp"
#include "std/string.hpp"
#include "std/bind.hpp"
@ -42,27 +43,37 @@ struct FileToDownload
uint64_t m_fileSize;
};
//static string g_apkPath;
//static string g_sdcardPath;
namespace
{
static vector<FileToDownload> g_filesToDownload;
static int g_totalDownloadedBytes;
static int g_totalBytesToDownload;
static shared_ptr<HttpRequest> g_currentRequest;
} // namespace
extern "C"
{
int HasSpaceForFiles(Platform & pl, string const & sdcardPath, size_t fileSize)
using TCallback = HttpRequest::CallbackT;
static int HasSpaceForFiles(Platform & pl, 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 fileSize;
case Platform::STORAGE_DISCONNECTED:
return ERR_STORAGE_DISCONNECTED;
case Platform::NOT_ENOUGH_SPACE:
return ERR_NOT_ENOUGH_FREE_SPACE;
default:
return fileSize;
}
}
// Check if we need to download mandatory resource file.
bool NeedToDownload(Platform & pl, string const & name, int size)
static bool NeedToDownload(Platform & pl, string const & name, int size)
{
try
{
@ -80,7 +91,7 @@ extern "C"
}
JNIEXPORT jint JNICALL
Java_com_mapswithme_maps_DownloadResourcesActivity_getBytesToDownload(JNIEnv * env, jobject thiz)
Java_com_mapswithme_maps_DownloadResourcesActivity_nativeGetBytesToDownload(JNIEnv * env, jclass clazz)
{
// clear all
g_filesToDownload.clear();
@ -90,7 +101,7 @@ extern "C"
Platform & pl = GetPlatform();
string const path = pl.WritableDir();
ReaderStreamBuf buffer(pl.GetReader("external_resources.txt"));
ReaderStreamBuf buffer(pl.GetReader(EXTERNAL_RESOURCES_FILE));
istream in(&buffer);
string name;
@ -107,7 +118,7 @@ extern "C"
if (NeedToDownload(pl, name, size))
{
LOG(LDEBUG, ("Should download", name, "sized", size, "bytes"));
LOG(LDEBUG, ("Should download", name, "size", size, "bytes"));
FileToDownload f;
f.m_pathOnSdcard = path + name;
@ -130,32 +141,23 @@ extern "C"
return res;
}
void DownloadFileFinished(shared_ptr<jobject> obj, HttpRequest const & req)
static void DownloadFileFinished(shared_ptr<jobject> obj, HttpRequest const & req)
{
HttpRequest::StatusT const status = req.Status();
ASSERT_NOT_EQUAL(status, HttpRequest::EInProgress, ());
int errorCode = 0;
switch (status)
{
case HttpRequest::ECompleted:
int errorCode = ERR_DOWNLOAD_ERROR;
if (status == HttpRequest::ECompleted)
errorCode = ERR_DOWNLOAD_SUCCESS;
break;
case HttpRequest::EFailed:
errorCode = ERR_DOWNLOAD_ERROR;
break;
};
g_currentRequest.reset();
if (errorCode == ERR_DOWNLOAD_SUCCESS)
{
FileToDownload & curFile = g_filesToDownload.back();
LOG(LDEBUG, ("finished downloading", curFile.m_fileName, "sized", curFile.m_fileSize, "bytes"));
LOG(LDEBUG, ("finished downloading", curFile.m_fileName, "size", curFile.m_fileSize, "bytes"));
g_totalDownloadedBytes += curFile.m_fileSize;
LOG(LDEBUG, ("totalDownloadedBytes:", g_totalDownloadedBytes));
g_filesToDownload.pop_back();
@ -163,33 +165,20 @@ extern "C"
JNIEnv * env = jni::GetEnv();
jmethodID methodID = jni::GetJavaMethodID(env, *obj.get(), "onDownloadFinished", "(I)V");
env->CallVoidMethod(*obj.get(), methodID, errorCode);
jmethodID methodID = jni::GetMethodID(env, *obj, "onFinish", "(I)V");
env->CallVoidMethod(*obj, methodID, errorCode);
}
void DownloadFileProgress(shared_ptr<jobject> obj, HttpRequest const & req)
static void DownloadFileProgress(shared_ptr<jobject> listener, HttpRequest const & req)
{
//LOG(LDEBUG, (req.Progress().first, "bytes for", g_filesToDownload.back().m_fileName, "was downloaded"));
FileToDownload & curFile = g_filesToDownload.back();
jint curTotal = req.Progress().second;
jint curProgress = req.Progress().first;
jint glbTotal = g_totalBytesToDownload;
jint glbProgress = g_totalDownloadedBytes + req.Progress().first;
JNIEnv * env = jni::GetEnv();
jmethodID methodID = jni::GetJavaMethodID(env, *obj.get(), "onDownloadProgress", "(IIII)V");
env->CallVoidMethod(*obj.get(), methodID,
curTotal, curProgress,
glbTotal, glbProgress);
static jmethodID methodID = jni::GetMethodID(env, *listener, "onProgress", "(I)V");
env->CallVoidMethod(*listener, methodID, static_cast<jint>(g_totalDownloadedBytes + req.Progress().first));
}
typedef HttpRequest::CallbackT CallbackT;
void DownloadURLListFinished(HttpRequest const & req,
CallbackT const & onFinish, CallbackT const & onProgress)
static void DownloadURLListFinished(HttpRequest const & req, TCallback const & onFinish, TCallback const & onProgress)
{
FileToDownload & curFile = g_filesToDownload.back();
@ -204,22 +193,11 @@ extern "C"
LOG(LDEBUG, (curFile.m_urls[i]));
}
g_currentRequest.reset(HttpRequest::GetFile(
curFile.m_urls, curFile.m_pathOnSdcard, curFile.m_fileSize,
onFinish, onProgress,
512 * 1024, false));
g_currentRequest.reset(HttpRequest::GetFile(curFile.m_urls, curFile.m_pathOnSdcard, curFile.m_fileSize, onFinish, onProgress, 512 * 1024, false));
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_DownloadResourcesActivity_cancelCurrentFile(JNIEnv * env, jobject thiz)
{
LOG(LDEBUG, ("cancelCurrentFile, currentRequest=", g_currentRequest.get()));
g_currentRequest.reset();
}
JNIEXPORT int JNICALL
Java_com_mapswithme_maps_DownloadResourcesActivity_startNextFileDownload(JNIEnv * env,
jobject thiz, jobject observer)
JNIEXPORT jint JNICALL
Java_com_mapswithme_maps_DownloadResourcesActivity_nativeStartNextFileDownload(JNIEnv * env, jclass clazz, jobject listener)
{
if (g_filesToDownload.empty())
return ERR_NO_MORE_FILES;
@ -228,13 +206,18 @@ extern "C"
LOG(LDEBUG, ("downloading", curFile.m_fileName, "sized", curFile.m_fileSize, "bytes"));
CallbackT onFinish(bind(&DownloadFileFinished, jni::make_global_ref(observer), _1));
CallbackT onProgress(bind(&DownloadFileProgress, jni::make_global_ref(observer), _1));
g_currentRequest.reset(HttpRequest::PostJson(
GetPlatform().ResourcesMetaServerUrl(), curFile.m_fileName,
bind(&DownloadURLListFinished, _1, onFinish, onProgress)));
TCallback onFinish(bind(&DownloadFileFinished, jni::make_global_ref(listener), _1));
TCallback onProgress(bind(&DownloadFileProgress, jni::make_global_ref(listener), _1));
g_currentRequest.reset(HttpRequest::PostJson(GetPlatform().ResourcesMetaServerUrl(), curFile.m_fileName,
bind(&DownloadURLListFinished, _1, onFinish, onProgress)));
return ERR_FILE_IN_PROGRESS;
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_DownloadResourcesActivity_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

@ -3,6 +3,7 @@
#include <jni.h>
#include "map/framework.hpp"
#include "map/place_page_info.hpp"
#include "search/result.hpp"
@ -28,21 +29,12 @@
namespace android
{
class Framework : public storage::CountryTree::CountryTreeListener,
public storage::ActiveMapsLayout::ActiveMapsListener
class Framework
{
private:
drape_ptr<dp::ThreadSafeFactory> m_contextFactory;
::Framework m_work;
typedef shared_ptr<jobject> TJobject;
TJobject m_javaCountryListener;
typedef map<int, TJobject> TListenerMap;
TListenerMap m_javaActiveMapListeners;
int m_currentSlotID;
int m_activeMapsConnectionID;
math::LowPassVector<float, 3> m_sensors[2];
double m_lastCompass;
@ -56,14 +48,16 @@ namespace android
location::EMyPositionMode m_currentMode;
bool m_isCurrentModeInitialized;
bool m_isChoosePositionMode;
place_page::Info m_info;
public:
Framework();
~Framework();
storage::Storage & Storage();
void ShowCountry(storage::TIndex const & idx, bool zoomToDownloadButton);
storage::TStatus GetCountryStatus(storage::TIndex const & idx) const;
void ShowNode(storage::TCountryId const & countryId, bool zoomToDownloadButton);
void OnLocationError(int/* == location::TLocationStatus*/ newStatus);
void OnLocationUpdated(location::GpsInfo const & info);
@ -106,32 +100,20 @@ namespace android
void Touch(int action, Finger const & f1, Finger const & f2, uint8_t maskedPointer);
/// Show rect from another activity. Ensure that no LoadState will be called,
/// when main map activity will become active.
void ShowSearchResult(search::Result const & r);
void ShowAllSearchResults(search::Results const & results);
bool Search(search::SearchParams const & params);
string GetLastSearchQuery() { return m_searchQuery; }
void ClearLastSearchQuery() { m_searchQuery.clear(); }
void LoadState();
void SaveState();
void AddLocalMaps();
void RemoveLocalMaps();
storage::TIndex GetCountryIndex(double lat, double lon) const;
string GetCountryCode(double lat, double lon) const;
string GetCountryNameIfAbsent(m2::PointD const & pt) const;
m2::PointD GetViewportCenter() const;
void AddString(string const & name, string const & value);
void Scale(::Framework::EScaleMode mode);
void Scale(m2::PointD const & centerPt, int targetZoom, bool animate);
BookmarkAndCategory AddBookmark(size_t category, m2::PointD const & pt, BookmarkData & bm);
void ReplaceBookmark(BookmarkAndCategory const & ind, BookmarkData & bm);
size_t ChangeBookmarkCategory(BookmarkAndCategory const & ind, size_t newCat);
@ -147,12 +129,6 @@ namespace android
void ShowTrack(int category, int track);
void SetCountryTreeListener(shared_ptr<jobject> objPtr);
void ResetCountryTreeListener();
int AddActiveMapsListener(shared_ptr<jobject> obj);
void RemoveActiveMapsListener(int slotID);
void SetMyPositionModeListener(location::TMyPositionModeChanged const & fn);
location::EMyPositionMode GetMyPositionMode() const;
void SetMyPositionMode(location::EMyPositionMode mode);
@ -161,30 +137,24 @@ namespace android
void Set3dMode(bool allow3d, bool allow3dBuildings);
void Get3dMode(bool & allow3d, bool & allow3dBuildings);
void SetChoosePositionMode(bool isChoosePositionMode);
void SetupWidget(gui::EWidget widget, float x, float y, dp::Anchor anchor);
void ApplyWidgets();
void CleanWidgets();
// Fills mapobject's metadata from UserMark
void InjectMetadata(JNIEnv * env, jclass clazz, jobject const mapObject, UserMark const * userMark);
using TDrapeTask = function<void()>;
// Posts a task which must be executed when Drape Engine is alive.
void PostDrapeTask(TDrapeTask && task);
public:
virtual void ItemStatusChanged(int childPosition);
virtual void ItemProgressChanged(int childPosition, storage::LocalAndRemoteSizeT const & sizes);
void SetPlacePageInfo(place_page::Info const & info);
place_page::Info & GetPlacePageInfo();
virtual void CountryGroupChanged(storage::ActiveMapsLayout::TGroup const & oldGroup, int oldPosition,
storage::ActiveMapsLayout::TGroup const & newGroup, int newPosition);
virtual void CountryStatusChanged(storage::ActiveMapsLayout::TGroup const & group, int position,
storage::TStatus const & oldStatus, storage::TStatus const & newStatus);
virtual void CountryOptionsChanged(storage::ActiveMapsLayout::TGroup const & group,
int position, MapOptions const & oldOpt,
MapOptions const & newOpt);
virtual void DownloadingProgressUpdate(storage::ActiveMapsLayout::TGroup const & group, int position,
storage::LocalAndRemoteSizeT const & progress);
bool HasSpaceForMigration();
bool NeedMigrate();
bool PreMigrate(ms::LatLon const & position, storage::Storage::TChangeCountryFunction const & statusChangeListener,
storage::Storage::TProgressFunction const & progressListener);
void Migrate(bool keepOldMaps);
private:
vector<TDrapeTask> m_drapeTasksQueue;

View file

@ -23,7 +23,7 @@ extern "C"
g_framework->SetMyPositionMode(mode);
JNIEnv * env = jni::GetEnv();
env->CallVoidMethod(*obj.get(), jni::GetJavaMethodID(env, *obj.get(), "onMyPositionModeChangedCallback", "(I)V"), static_cast<jint>(mode));
env->CallVoidMethod(*obj, jni::GetMethodID(env, *obj.get(), "onMyPositionModeChangedCallback", "(I)V"), static_cast<jint>(mode));
}
JNIEXPORT void JNICALL

View file

@ -1,7 +1,4 @@
#include "Framework.hpp"
#include "MapStorage.hpp"
#include "../country/country_helper.hpp"
#include "../core/jni_helper.hpp"
@ -12,10 +9,13 @@
#include "base/logging.hpp"
#include "platform/file_logging.hpp"
#include "platform/settings.hpp"
extern "C"
{
using namespace storage;
// Fixed optimization bug for x86 (reproduced on Asus ME302C).
#pragma clang push_options
#pragma clang optimize off
@ -31,125 +31,101 @@ extern "C"
#pragma clang pop_options
static void CallOnDownloadCountryClicked(shared_ptr<jobject> const & obj, storage::TIndex const & idx, int options, jmethodID methodID)
{
JNIEnv * env = jni::GetEnv();
env->CallVoidMethod(*obj.get(), methodID, idx.m_group, idx.m_country, idx.m_region, options);
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapFragment_nativeStorageConnected(JNIEnv * env, jclass clazz)
{
android::Platform::Instance().OnExternalStorageStatusChanged(true);
g_framework->AddLocalMaps();
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapFragment_nativeConnectDownloadButton(JNIEnv * env, jobject thiz)
{
jmethodID methodID = jni::GetJavaMethodID(env, thiz, "onDownloadCountryClicked", "(IIII)V");
g_framework->NativeFramework()->SetDownloadCountryListener(bind(&CallOnDownloadCountryClicked,
jni::make_global_ref(thiz), _1, _2, methodID));
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapFragment_nativeStorageDisconnected(JNIEnv * env, jclass clazz)
{
android::Platform::Instance().OnExternalStorageStatusChanged(false);
g_framework->RemoveLocalMaps();
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapFragment_nativeDownloadCountry(JNIEnv * env, jclass clazz, jobject idx, jint options)
{
storage::TIndex index = storage::ToNative(idx);
storage::ActiveMapsLayout & layout = storage_utils::GetMapLayout();
if (options == -1)
layout.RetryDownloading(index);
else
layout.DownloadMap(index, storage_utils::ToOptions(options));
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapFragment_nativeScalePlus(JNIEnv * env, jclass clazz)
{
g_framework->Scale(::Framework::SCALE_MAG);
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapFragment_nativeStorageConnected(JNIEnv * env, jclass clazz)
{
android::Platform::Instance().OnExternalStorageStatusChanged(true);
g_framework->AddLocalMaps();
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapFragment_nativeScaleMinus(JNIEnv * env, jclass clazz)
{
g_framework->Scale(::Framework::SCALE_MIN);
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapFragment_nativeStorageDisconnected(JNIEnv * env, jclass clazz)
{
android::Platform::Instance().OnExternalStorageStatusChanged(false);
g_framework->RemoveLocalMaps();
}
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_MapFragment_nativeShowMapForUrl(JNIEnv * env, jclass clazz, jstring url)
{
return g_framework->ShowMapForURL(jni::ToNativeString(env, url));
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapFragment_nativeScalePlus(JNIEnv * env, jclass clazz)
{
g_framework->Scale(::Framework::SCALE_MAG);
}
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_MapFragment_nativeCreateEngine(JNIEnv * env, jclass clazz, jobject surface, jint density)
{
return g_framework->CreateDrapeEngine(env, surface, density);
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapFragment_nativeScaleMinus(JNIEnv * env, jclass clazz)
{
g_framework->Scale(::Framework::SCALE_MIN);
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapFragment_nativeDestroyEngine(JNIEnv * env, jclass clazz)
{
g_framework->DeleteDrapeEngine();
}
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_MapFragment_nativeShowMapForUrl(JNIEnv * env, jclass clazz, jstring url)
{
return g_framework->ShowMapForURL(jni::ToNativeString(env, url));
}
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_MapFragment_nativeIsEngineCreated(JNIEnv * env, jclass clazz)
{
return g_framework->IsDrapeEngineCreated();
}
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_MapFragment_nativeCreateEngine(JNIEnv * env, jclass clazz, jobject surface, jint density)
{
return static_cast<jboolean>(g_framework->CreateDrapeEngine(env, surface, static_cast<int>(density)));
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapFragment_nativeAttachSurface(JNIEnv * env, jclass clazz, jobject surface)
{
g_framework->AttachSurface(env, surface);
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapFragment_nativeDestroyEngine(JNIEnv * env, jclass clazz)
{
g_framework->DeleteDrapeEngine();
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapFragment_nativeDetachSurface(JNIEnv * env, jclass clazz)
{
g_framework->DetachSurface();
}
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_MapFragment_nativeIsEngineCreated(JNIEnv * env, jclass clazz)
{
return static_cast<jboolean>(g_framework->IsDrapeEngineCreated());
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapFragment_nativeSurfaceChanged(JNIEnv * env, jclass clazz, jint w, jint h)
{
g_framework->Resize(w, h);
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapFragment_nativeAttachSurface(JNIEnv * env, jclass clazz, jobject surface)
{
g_framework->AttachSurface(env, surface);
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapFragment_nativeOnTouch(JNIEnv * env, jclass clazz, 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_com_mapswithme_maps_MapFragment_nativeDetachSurface(JNIEnv * env, jclass clazz)
{
g_framework->DetachSurface();
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapFragment_nativeSetupWidget(JNIEnv * env, jclass clazz, 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_com_mapswithme_maps_MapFragment_nativeSurfaceChanged(JNIEnv * env, jclass clazz, jint w, jint h)
{
g_framework->Resize(static_cast<int>(w), static_cast<int>(h));
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapFragment_nativeApplyWidgets(JNIEnv * env, jclass clazz)
{
g_framework->ApplyWidgets();
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapFragment_nativeOnTouch(JNIEnv * env, jclass clazz, jint action,
jint id1, jfloat x1, jfloat y1,
jint id2, jfloat x2, jfloat y2,
jint maskedPointer)
{
g_framework->Touch(static_cast<int>(action),
android::Framework::Finger(id1, x1, y1),
android::Framework::Finger(id2, x2, y2), maskedPointer);
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapFragment_nativeCleanWidgets(JNIEnv * env, jclass clazz)
{
g_framework->CleanWidgets();
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapFragment_nativeSetupWidget(JNIEnv * env, jclass clazz, jint widget, jfloat x, jfloat y, jint anchor)
{
g_framework->SetupWidget(static_cast<gui::EWidget>(widget), static_cast<float>(x), static_cast<float>(y), static_cast<dp::Anchor>(anchor));
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapFragment_nativeApplyWidgets(JNIEnv * env, jclass clazz)
{
g_framework->ApplyWidgets();
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapFragment_nativeCleanWidgets(JNIEnv * env, jclass clazz)
{
g_framework->CleanWidgets();
}
} // extern "C"

View file

@ -0,0 +1,527 @@
#include "Framework.hpp"
#include "../core/jni_helper.hpp"
#include "coding/internal/file_data.hpp"
#include "storage/storage.hpp"
#include "base/thread_checker.hpp"
#include "std/bind.hpp"
#include "std/shared_ptr.hpp"
#include "std/unordered_map.hpp"
namespace
{
using namespace storage;
enum ItemCategory : uint32_t
{
NEAR_ME,
DOWNLOADED,
AVAILABLE,
};
struct TBatchedData
{
TCountryId const m_countryId;
NodeStatus const m_newStatus;
NodeErrorCode const m_errorCode;
bool const m_isLeaf;
TBatchedData(TCountryId const & countryId, NodeStatus const newStatus, NodeErrorCode const errorCode, bool isLeaf)
: m_countryId(countryId)
, m_newStatus(newStatus)
, m_errorCode(errorCode)
, m_isLeaf(isLeaf)
{}
};
jmethodID g_listAddMethod;
jclass g_countryItemClass;
jobject g_countryChangedListener;
jobject g_migrationListener;
DECLARE_THREAD_CHECKER(g_batchingThreadChecker);
unordered_map<jobject, vector<TBatchedData>> g_batchedCallbackData;
bool g_isBatched;
Storage & GetStorage()
{
return g_framework->Storage();
}
void PrepareClassRefs(JNIEnv * env)
{
if (g_listAddMethod)
return;
jclass listClass = env->FindClass("java/util/List");
g_listAddMethod = env->GetMethodID(listClass, "add", "(Ljava/lang/Object;)Z");
g_countryItemClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/downloader/CountryItem");
}
static TCountryId const GetRootId(JNIEnv * env, jstring root)
{
return (root ? jni::ToNativeString(env, root) : GetStorage().GetRootId());
}
} // namespace
extern "C"
{
// static boolean nativeMoveFile(String oldFile, String newFile);
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_downloader_MapManager_nativeMoveFile(JNIEnv * env, jclass clazz, jstring oldFile, jstring newFile)
{
return my::RenameFileX(jni::ToNativeString(env, oldFile), jni::ToNativeString(env, newFile));
}
// static boolean nativeHasSpaceForMigration();
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_downloader_MapManager_nativeHasSpaceForMigration(JNIEnv * env, jclass clazz)
{
return g_framework->HasSpaceForMigration();
}
// static native boolean nativeIsLegacyMode();
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_downloader_MapManager_nativeIsLegacyMode(JNIEnv * env, jclass clazz)
{
return g_framework->NeedMigrate();
}
static void FinishMigration(JNIEnv * env)
{
env->DeleteGlobalRef(g_migrationListener);
}
static void OnPrefetchComplete(bool keepOldMaps)
{
g_framework->Migrate(keepOldMaps);
JNIEnv * env = jni::GetEnv();
static jmethodID const callback = jni::GetMethodID(env, g_migrationListener, "onComplete", "()V");
env->CallVoidMethod(g_migrationListener, callback);
FinishMigration(env);
}
static void OnMigrationError(NodeErrorCode error)
{
JNIEnv * env = jni::GetEnv();
static jmethodID const callback = jni::GetMethodID(env, g_migrationListener, "onError", "(I)V");
env->CallVoidMethod(g_migrationListener, callback, static_cast<jint>(error));
FinishMigration(env);
}
static void MigrationStatusChangedCallback(TCountryId const & countryId, bool keepOldMaps)
{
NodeAttrs attrs;
GetStorage().GetPrefetchStorage()->GetNodeAttrs(countryId, attrs);
switch (attrs.m_status)
{
case NodeStatus::OnDisk:
OnPrefetchComplete(keepOldMaps);
break;
case NodeStatus::Undefined:
case NodeStatus::Error:
if (attrs.m_mwmCounter == 1)
OnMigrationError(attrs.m_error);
break;
default:
break;
}
}
static void MigrationProgressCallback(TCountryId const & countryId, TLocalAndRemoteSize const & sizes)
{
JNIEnv * env = jni::GetEnv();
static jmethodID const callback = jni::GetMethodID(env, g_migrationListener, "onProgress", "(I)V");
env->CallVoidMethod(g_migrationListener, callback, static_cast<jint>(sizes.first * 100 / sizes.second));
}
// static boolean nativeMigrate(MigrationListener listener, double lat, double lon, boolean hasLocation, boolean keepOldMaps);
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_downloader_MapManager_nativeMigrate(JNIEnv * env, jclass clazz, jobject listener, jdouble lat, jdouble lon, jboolean hasLocation, jboolean keepOldMaps)
{
ms::LatLon position{};
if (hasLocation)
position = MercatorBounds::ToLatLon(g_framework->GetViewportCenter());
g_migrationListener = env->NewGlobalRef(listener);
if (g_framework->PreMigrate(position, bind(&MigrationStatusChangedCallback, _1, keepOldMaps),
bind(&MigrationProgressCallback, _1, _2)))
{
return true;
}
OnPrefetchComplete(keepOldMaps);
return false;
}
// static void nativeCancelMigration();
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_downloader_MapManager_nativeCancelMigration(JNIEnv * env, jclass clazz)
{
Storage * storage = GetStorage().GetPrefetchStorage();
TCountryId const & currentCountry = storage->GetCurrentDownloadingCountryId();
storage->CancelDownloadNode(currentCountry);
}
// static int nativeGetDownloadedCount();
JNIEXPORT jint JNICALL
Java_com_mapswithme_maps_downloader_MapManager_nativeGetDownloadedCount(JNIEnv * env, jclass clazz)
{
return GetStorage().GetDownloadedFilesCount();
}
// static @Nullable UpdateInfo nativeGetUpdateInfo(@Nullable String root);
JNIEXPORT jobject JNICALL
Java_com_mapswithme_maps_downloader_MapManager_nativeGetUpdateInfo(JNIEnv * env, jclass clazz, jstring root)
{
Storage::UpdateInfo info;
if (!GetStorage().GetUpdateInfo(GetRootId(env, root), info))
return nullptr;
static jclass const infoClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/downloader/UpdateInfo");
ASSERT(infoClass, (jni::DescribeException()));
static jmethodID const ctor = jni::GetConstructorID(env, infoClass, "(II)V");
ASSERT(ctor, (jni::DescribeException()));
return env->NewObject(infoClass, ctor, info.m_numberOfMwmFilesToUpdate, info.m_totalUpdateSizeInBytes);
}
static void UpdateItemShort(JNIEnv * env, jobject item, NodeStatus const status, NodeErrorCode const error)
{
static jfieldID const countryItemFieldStatus = env->GetFieldID(g_countryItemClass, "status", "I");
static jfieldID const countryItemFieldErrorCode = env->GetFieldID(g_countryItemClass, "errorCode", "I");
env->SetIntField(item, countryItemFieldStatus, static_cast<jint>(status));
env->SetIntField(item, countryItemFieldErrorCode, static_cast<jint>(error));
}
static void UpdateItem(JNIEnv * env, jobject item, NodeAttrs const & attrs)
{
static jfieldID const countryItemFieldName = env->GetFieldID(g_countryItemClass, "name", "Ljava/lang/String;");
static jfieldID const countryItemFieldParentId = env->GetFieldID(g_countryItemClass, "parentId", "Ljava/lang/String;");
static jfieldID const countryItemFieldParentName = env->GetFieldID(g_countryItemClass, "parentName", "Ljava/lang/String;");
static jfieldID const countryItemFieldSize = env->GetFieldID(g_countryItemClass, "size", "J");
static jfieldID const countryItemFieldTotalSize = env->GetFieldID(g_countryItemClass, "totalSize", "J");
static jfieldID const countryItemFieldChildCount = env->GetFieldID(g_countryItemClass, "childCount", "I");
static jfieldID const countryItemFieldTotalChildCount = env->GetFieldID(g_countryItemClass, "totalChildCount", "I");
static jfieldID const countryItemFieldPresent = env->GetFieldID(g_countryItemClass, "present", "Z");
static jfieldID const countryItemFieldProgress = env->GetFieldID(g_countryItemClass, "progress", "I");
// Localized name
jni::TScopedLocalRef const name(env, jni::ToJavaString(env, attrs.m_nodeLocalName));
env->SetObjectField(item, countryItemFieldName, name.get());
// Info about parent[s]. Do not specify if there are multiple parents or none.
if (attrs.m_parentInfo.size() == 1)
{
CountryIdAndName const & info = attrs.m_parentInfo[0];
jni::TScopedLocalRef const parentId(env, jni::ToJavaString(env, info.m_id));
env->SetObjectField(item, countryItemFieldParentId, parentId.get());
jni::TScopedLocalRef const parentName(env, jni::ToJavaString(env, info.m_localName));
env->SetObjectField(item, countryItemFieldParentName, parentName.get());
}
else
{
env->SetObjectField(item, countryItemFieldParentId, nullptr);
env->SetObjectField(item, countryItemFieldParentName, nullptr);
}
// Sizes
env->SetLongField(item, countryItemFieldSize, attrs.m_localMwmSize);
env->SetLongField(item, countryItemFieldTotalSize, attrs.m_mwmSize);
// Child counts
env->SetIntField(item, countryItemFieldChildCount, attrs.m_localMwmCounter);
env->SetIntField(item, countryItemFieldTotalChildCount, attrs.m_mwmCounter);
// Status and error code
UpdateItemShort(env, item, attrs.m_status, attrs.m_error);
// Presence flag
env->SetBooleanField(item, countryItemFieldPresent, attrs.m_present);
// Progress
int progress = 0;
if (attrs.m_downloadingProgress.second)
progress = (int)(attrs.m_downloadingProgress.first * 100.0 / attrs.m_downloadingProgress.second);
env->SetIntField(item, countryItemFieldProgress, progress);
}
static void PutItemsToList(JNIEnv * env, jobject const list, TCountriesVec const & children, int category,
function<bool (TCountryId const & countryId, NodeAttrs const & attrs)> const & predicate)
{
static jmethodID const countryItemCtor = jni::GetConstructorID(env, g_countryItemClass, "(Ljava/lang/String;)V");
static jfieldID const countryItemFieldCategory = env->GetFieldID(g_countryItemClass, "category", "I");
NodeAttrs attrs;
for (TCountryId const & child : children)
{
GetStorage().GetNodeAttrs(child, attrs);
if (predicate && !predicate(child, attrs))
continue;
jni::TScopedLocalRef const id(env, jni::ToJavaString(env, child));
jni::TScopedLocalRef const item(env, env->NewObject(g_countryItemClass, countryItemCtor, id.get()));
env->SetIntField(item.get(), countryItemFieldCategory, category);
UpdateItem(env, item.get(), attrs);
// Put to resulting list
env->CallBooleanMethod(list, g_listAddMethod, item.get());
}
}
// static void nativeListItems(@Nullable String root, double lat, double lon, boolean hasLocation, List<CountryItem> result);
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_downloader_MapManager_nativeListItems(JNIEnv * env, jclass clazz, jstring parent, jdouble lat, jdouble lon, jboolean hasLocation, jobject result)
{
PrepareClassRefs(env);
Storage const & storage = GetStorage();
static jfieldID const countryItemFieldParentId = env->GetFieldID(g_countryItemClass, "parentId", "Ljava/lang/String;");
if (hasLocation)
{
TCountriesVec near;
g_framework->NativeFramework()->CountryInfoGetter().GetRegionsCountryId(MercatorBounds::FromLatLon(lat, lon), near);
PutItemsToList(env, result, near, ItemCategory::NEAR_ME, [](TCountryId const & countryId, NodeAttrs const & attrs) -> bool
{
return (attrs.m_status == NodeStatus::NotDownloaded);
});
}
TCountriesVec downloaded, available;
storage.GetChildrenInGroups(GetRootId(env, parent), downloaded, available);
PutItemsToList(env, result, downloaded, ItemCategory::DOWNLOADED, nullptr);
PutItemsToList(env, result, available, ItemCategory::AVAILABLE, nullptr);
}
// static void nativeUpdateItem(CountryItem item);
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_downloader_MapManager_nativeGetAttributes(JNIEnv * env, jclass clazz, jobject item)
{
PrepareClassRefs(env);
static jfieldID countryItemFieldId = env->GetFieldID(g_countryItemClass, "id", "Ljava/lang/String;");
jstring id = static_cast<jstring>(env->GetObjectField(item, countryItemFieldId));
NodeAttrs attrs;
GetStorage().GetNodeAttrs(jni::ToNativeString(env, id), attrs);
UpdateItem(env, item, attrs);
}
// static void nativeGetShortAttributes(CountryItem item);
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_downloader_MapManager_nativeGetShortAttributes(JNIEnv * env, jclass clazz, jobject item)
{
PrepareClassRefs(env);
static jfieldID countryItemFieldId = env->GetFieldID(g_countryItemClass, "id", "Ljava/lang/String;");
jstring id = static_cast<jstring>(env->GetObjectField(item, countryItemFieldId));
NodeStatuses ns;
GetStorage().GetNodeStatuses(jni::ToNativeString(env, id), ns);
UpdateItemShort(env, item, ns.m_status, ns.m_error);
}
// static @Nullable String nativeFindCountry(double lat, double lon);
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_downloader_MapManager_nativeFindCountry(JNIEnv * env, jclass clazz, jdouble lat, jdouble lon)
{
return jni::ToJavaString(env, g_framework->NativeFramework()->CountryInfoGetter().GetRegionCountryId(MercatorBounds::FromLatLon(lat, lon)));
}
// static boolean nativeIsDownloading();
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_downloader_MapManager_nativeIsDownloading(JNIEnv * env, jclass clazz)
{
return GetStorage().IsDownloadInProgress();
}
static void StartBatchingCallbacks()
{
ASSERT_THREAD_CHECKER(g_batchingThreadChecker, ("StartBatchingCallbacks"));
ASSERT(!g_isBatched, ());
ASSERT(g_batchedCallbackData.empty(), ());
g_isBatched = true;
}
static void EndBatchingCallbacks(JNIEnv * env)
{
ASSERT_THREAD_CHECKER(g_batchingThreadChecker, ("EndBatchingCallbacks"));
static jclass arrayListClass = jni::GetGlobalClassRef(env, "java/util/ArrayList");
static jmethodID arrayListCtor = jni::GetConstructorID(env, arrayListClass, "(I)V");
static jmethodID arrayListAdd = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
for (auto & key : g_batchedCallbackData)
{
// Allocate resulting ArrayList
jni::TScopedLocalRef const list(env, env->NewObject(arrayListClass, arrayListCtor, key.second.size()));
for (TBatchedData const & dataItem : key.second)
{
// Create StorageCallbackData instance…
static jclass batchDataClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/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(), arrayListAdd, 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_com_mapswithme_maps_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_com_mapswithme_maps_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_com_mapswithme_maps_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_com_mapswithme_maps_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_com_mapswithme_maps_downloader_MapManager_nativeDelete(JNIEnv * env, jclass clazz, jstring root)
{
StartBatchingCallbacks();
GetStorage().DeleteNode(jni::ToNativeString(env, root));
EndBatchingCallbacks(env);
}
static void StatusChangedCallback(shared_ptr<jobject> const & listenerRef, TCountryId const & countryId)
{
NodeStatuses ns;
GetStorage().GetNodeStatuses(countryId, ns);
TBatchedData const data(countryId, ns.m_status, ns.m_error, !ns.m_groupNode);
g_batchedCallbackData[*listenerRef].push_back(move(data));
if (!g_isBatched)
EndBatchingCallbacks(jni::GetEnv());
}
static void ProgressChangedCallback(shared_ptr<jobject> const & listenerRef, TCountryId const & countryId, TLocalAndRemoteSize const & sizes)
{
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), sizes.first, sizes.second);
}
// static int nativeSubscribe(StorageCallback listener);
JNIEXPORT jint JNICALL
Java_com_mapswithme_maps_downloader_MapManager_nativeSubscribe(JNIEnv * env, jclass clazz, jobject listener)
{
PrepareClassRefs(env);
return GetStorage().Subscribe(bind(&StatusChangedCallback, jni::make_global_ref(listener), _1),
bind(&ProgressChangedCallback, jni::make_global_ref(listener), _1, _2));
}
// static void nativeUnsubscribe(int slot);
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_downloader_MapManager_nativeUnsubscribe(JNIEnv * env, jclass clazz, jint slot)
{
GetStorage().Unsubscribe(slot);
}
// static void nativeSubscribeOnCountryChanged(CurrentCountryChangedListener listener);
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_downloader_MapManager_nativeSubscribeOnCountryChanged(JNIEnv * env, jclass clazz, jobject listener)
{
ASSERT(!g_countryChangedListener, ());
g_countryChangedListener = env->NewGlobalRef(listener);
auto const callback = [](TCountryId 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());
};
TCountryId const & prev = g_framework->NativeFramework()->GetLastReportedCountry();
g_framework->NativeFramework()->SetCurrentCountryChangedListener(callback);
// Report previous value
callback(prev);
}
// static void nativeUnsubscribeOnCountryChanged();
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_downloader_MapManager_nativeUnsubscribeOnCountryChanged(JNIEnv * env, jclass clazz)
{
g_framework->NativeFramework()->SetCurrentCountryChangedListener(nullptr);
ASSERT(g_countryChangedListener, ());
env->DeleteGlobalRef(g_countryChangedListener);
g_countryChangedListener = nullptr;
}
// static boolean nativeHasUnsavedEditorChanges(String root);
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_downloader_MapManager_nativeHasUnsavedEditorChanges(JNIEnv * env, jclass clazz, jstring root)
{
return g_framework->NativeFramework()->HasUnsavedEdits(jni::ToNativeString(env, root));
}
} // extern "C"

View file

@ -1,178 +0,0 @@
#include "MapStorage.hpp"
#include "Framework.hpp"
#include "com/mapswithme/country/country_helper.hpp"
#include "com/mapswithme/platform/Platform.hpp"
#include "coding/internal/file_data.hpp"
using namespace storage;
namespace
{
::Framework * frm()
{
return g_framework->NativeFramework();
}
Storage & GetStorage()
{
return frm()->Storage();
}
}
extern "C"
{
class IndexBinding
{
private:
shared_ptr<jobject> m_self;
jfieldID m_groupID;
jfieldID m_countryID;
jfieldID m_regionID;
jobject object() const { return *m_self.get(); }
public:
IndexBinding(jobject self) : m_self(jni::make_global_ref(self))
{
jclass klass = jni::GetEnv()->GetObjectClass(object());
m_groupID = jni::GetEnv()->GetFieldID(klass, "mGroup", "I");
m_countryID = jni::GetEnv()->GetFieldID(klass, "mCountry", "I");
m_regionID = jni::GetEnv()->GetFieldID(klass, "mRegion", "I");
}
int group() const
{
return jni::GetEnv()->GetIntField(object(), m_groupID);
}
int country() const
{
return jni::GetEnv()->GetIntField(object(), m_countryID);
}
int region() const
{
return jni::GetEnv()->GetIntField(object(), m_regionID);
}
TIndex const toNative() const
{
return TIndex(group(), country(), region());
}
};
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_MapStorage_countryName(JNIEnv * env, jobject thiz, jobject idx)
{
string const name = GetStorage().CountryName(IndexBinding(idx).toNative());
return env->NewStringUTF(name.c_str());
}
JNIEXPORT jlong JNICALL
Java_com_mapswithme_maps_MapStorage_countryRemoteSizeInBytes(JNIEnv * env, jobject thiz, jobject idx, jint options)
{
ActiveMapsLayout & layout = storage_utils::GetMapLayout();
LocalAndRemoteSizeT const sizes = layout.GetRemoteCountrySizes(ToNative(idx));
switch (storage_utils::ToOptions(options))
{
case MapOptions::Map:
return sizes.first;
case MapOptions::CarRouting:
return sizes.second;
case MapOptions::MapWithCarRouting:
return sizes.first + sizes.second;
case MapOptions::Nothing:
return 0;
}
}
JNIEXPORT jint JNICALL
Java_com_mapswithme_maps_MapStorage_countryStatus(JNIEnv * env, jobject thiz, jobject idx)
{
return static_cast<jint>(g_framework->GetCountryStatus(IndexBinding(idx).toNative()));
}
JNIEXPORT jobject JNICALL
Java_com_mapswithme_maps_MapStorage_findIndexByFile(JNIEnv * env, jobject thiz, jstring name)
{
char const * s = env->GetStringUTFChars(name, 0);
if (s == 0)
return 0;
TIndex const idx = GetStorage().FindIndexByFile(s);
if (idx.IsValid())
return ToJava(idx);
else
return 0;
}
void ReportChangeCountryStatus(shared_ptr<jobject> const & obj, TIndex const & idx)
{
JNIEnv * env = jni::GetEnv();
jmethodID methodID = jni::GetJavaMethodID(env, *obj.get(), "onCountryStatusChanged", "(Lcom/mapswithme/maps/MapStorage$Index;)V");
env->CallVoidMethod(*obj.get(), methodID, ToJava(idx));
}
void ReportCountryProgress(shared_ptr<jobject> const & obj, TIndex const & idx, pair<int64_t, int64_t> const & p)
{
jlong const current = p.first;
jlong const total = p.second;
JNIEnv * env = jni::GetEnv();
jmethodID methodID = jni::GetJavaMethodID(env, *obj.get(), "onCountryProgress", "(Lcom/mapswithme/maps/MapStorage$Index;JJ)V");
env->CallVoidMethod(*obj.get(), methodID, ToJava(idx), current, total);
}
JNIEXPORT jint JNICALL
Java_com_mapswithme_maps_MapStorage_subscribe(JNIEnv * env, jobject thiz, jobject obj)
{
LOG(LDEBUG, ("Subscribe on storage"));
return GetStorage().Subscribe(bind(&ReportChangeCountryStatus, jni::make_global_ref(obj), _1),
bind(&ReportCountryProgress, jni::make_global_ref(obj), _1, _2));
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MapStorage_unsubscribe(JNIEnv * env, jobject thiz, jint slotID)
{
LOG(LDEBUG, ("UnSubscribe from storage"));
GetStorage().Unsubscribe(slotID);
}
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_MapStorage_nativeMoveFile(JNIEnv * env, jobject thiz, jstring oldFile, jstring newFile)
{
return my::RenameFileX(jni::ToNativeString(env, oldFile), jni::ToNativeString(env, newFile));
}
}
namespace storage
{
jobject ToJava(TIndex const & idx)
{
JNIEnv * env = jni::GetEnv();
jclass const klass = g_indexClazz;
ASSERT(klass, ());
jmethodID static const methodID = env->GetMethodID(klass, "<init>", "(III)V");
ASSERT(methodID, ());
return env->NewObject(klass, methodID,
static_cast<jint>(idx.m_group),
static_cast<jint>(idx.m_country),
static_cast<jint>(idx.m_region));
}
TIndex ToNative(jobject idx)
{
return IndexBinding(idx).toNative();
}
}

View file

@ -1,12 +0,0 @@
#pragma once
#include "storage/index.hpp"
#include "../core/jni_helper.hpp"
namespace storage
{
jobject ToJava(TIndex const & idx);
TIndex ToNative(jobject idx);
}

View file

@ -7,37 +7,33 @@
extern "C"
{
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MwmApplication_nativeInitPlatform(
JNIEnv * env, jobject thiz,
jstring apkPath, jstring storagePath, jstring tmpPath, jstring obbGooglePath,
jstring flavorName, jstring buildType, jboolean isYota, jboolean isTablet)
Java_com_mapswithme_maps_MwmApplication_nativeInitPlatform(JNIEnv * env, jobject thiz, jstring apkPath, jstring storagePath, jstring tmpPath,
jstring obbGooglePath, jstring flavorName, jstring buildType, jboolean isYota, jboolean isTablet)
{
android::Platform::Instance().InitAppMethodRefs(thiz);
android::Platform::Instance().Initialize(
env, apkPath, storagePath, tmpPath, obbGooglePath, flavorName, buildType, isYota, isTablet);
android::Platform::Instance().Initialize(env, thiz, apkPath, storagePath, tmpPath, obbGooglePath, flavorName, buildType, isYota, isTablet);
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MwmApplication_nativeInitFramework(JNIEnv * env, jobject thiz)
Java_com_mapswithme_maps_MwmApplication_nativeInitFramework(JNIEnv * env, jclass clazz)
{
if (!g_framework)
g_framework = new android::Framework();
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MwmApplication_runNativeFunctor(JNIEnv * env, jobject thiz, jlong functorPointer)
Java_com_mapswithme_maps_MwmApplication_nativeProcessFunctor(JNIEnv * env, jclass clazz, jlong functorPointer)
{
android::Platform::Instance().CallNativeFunctor(functorPointer);
android::Platform::Instance().ProcessFunctor(functorPointer);
}
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_MwmApplication_nativeHasFreeSpace(JNIEnv * env, jobject thiz, jlong size)
Java_com_mapswithme_maps_MwmApplication_nativeHasFreeSpace(JNIEnv * env, jclass clazz, jlong size)
{
return android::Platform::Instance().HasAvailableSpaceForWriting(size);
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MwmApplication_nativeAddLocalization(JNIEnv * env, jobject thiz, jstring name, jstring value)
Java_com_mapswithme_maps_MwmApplication_nativeAddLocalization(JNIEnv * env, jclass clazz, jstring name, jstring value)
{
g_framework->AddString(jni::ToNativeString(env, name),
jni::ToNativeString(env, value));

View file

@ -51,4 +51,16 @@ extern "C"
{
return static_cast<jlong>(AD_PERMISION_CHECK_DURATION);
}
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_PrivateVariables_hockeyAppId(JNIEnv * env, jclass clazz)
{
return env->NewStringUTF(HOCKEY_APP_KEY);
}
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_PrivateVariables_hockeyAppBetaId(JNIEnv * env, jclass clazz)
{
return env->NewStringUTF(HOCKEY_APP_BETA_KEY);
}
}

View file

@ -33,11 +33,12 @@ jmethodID g_suggestConstructor;
jclass g_descriptionClass;
jmethodID g_descriptionConstructor;
jobject ToJavaResult(Result result, bool hasPosition, double lat, double lon)
jobject ToJavaResult(Result & result, bool hasPosition, double lat, double lon)
{
JNIEnv * env = jni::GetEnv();
::Framework * fr = g_framework->NativeFramework();
jintArray ranges = env->NewIntArray(result.GetHighlightRangesCount() * 2);
jni::TScopedLocalIntArrayRef ranges(env, env->NewIntArray(result.GetHighlightRangesCount() * 2));
jint * rawArr = env->GetIntArrayElements(ranges, nullptr);
for (int i = 0; i < result.GetHighlightRangesCount(); i++)
{
@ -45,53 +46,42 @@ jobject ToJavaResult(Result result, bool hasPosition, double lat, double lon)
rawArr[2 * i] = range.first;
rawArr[2 * i + 1] = range.second;
}
env->ReleaseIntArrayElements(ranges, rawArr, 0);
env->ReleaseIntArrayElements(ranges.get(), rawArr, 0);
ms::LatLon ll = ms::LatLon::Zero();
string distance;
if (result.HasPoint())
{
ll = MercatorBounds::ToLatLon(result.GetFeatureCenter());
if (hasPosition)
{
double dummy;
(void) fr->GetDistanceAndAzimut(result.GetFeatureCenter(), lat, lon, 0, distance, dummy);
}
}
if (result.IsSuggest())
{
jstring name = jni::ToJavaString(env, result.GetString());
jstring suggest = jni::ToJavaString(env, result.GetSuggestionString());
jobject ret = env->NewObject(g_resultClass, g_suggestConstructor, name, suggest, ranges);
jni::TScopedLocalRef name(env, jni::ToJavaString(env, result.GetString()));
jni::TScopedLocalRef suggest(env, jni::ToJavaString(env, result.GetSuggestionString()));
jobject ret = env->NewObject(g_resultClass, g_suggestConstructor, name.get(), suggest.get(), ll.lat, ll.lon, ranges.get());
ASSERT(ret, ());
env->DeleteLocalRef(name);
env->DeleteLocalRef(suggest);
env->DeleteLocalRef(ranges);
return ret;
}
string distance;
if (hasPosition)
{
double dummy;
(void) g_framework->NativeFramework()->GetDistanceAndAzimut(result.GetFeatureCenter(), lat, lon, 0, distance, dummy);
}
jni::TScopedLocalRef featureType(env, jni::ToJavaString(env, result.GetFeatureType()));
jni::TScopedLocalRef address(env, jni::ToJavaString(env, result.GetAddress()));
jni::TScopedLocalRef dist(env, jni::ToJavaString(env, distance));
jni::TScopedLocalRef cuisine(env, jni::ToJavaString(env, result.GetCuisine()));
jni::TScopedLocalRef desc(env, env->NewObject(g_descriptionClass, g_descriptionConstructor,
featureType.get(), address.get(),
dist.get(), cuisine.get(),
result.GetStarsCount(),
static_cast<jint>(result.IsOpenNow())));
g_framework->NativeFramework()->LoadSearchResultMetadata(result);
jstring featureType = jni::ToJavaString(env, result.GetFeatureType());
jstring region = jni::ToJavaString(env, result.GetRegionString());
jstring dist = jni::ToJavaString(env, distance.c_str());
jstring cuisine = jni::ToJavaString(env, result.GetCuisine());
jobject desc = env->NewObject(g_descriptionClass, g_descriptionConstructor,
featureType, region,
dist, cuisine,
result.GetStarsCount(),
result.IsClosed());
ASSERT(desc, ());
env->DeleteLocalRef(featureType);
env->DeleteLocalRef(region);
env->DeleteLocalRef(dist);
env->DeleteLocalRef(cuisine);
jstring name = jni::ToJavaString(env, result.GetString());
double const poiLat = MercatorBounds::YToLat(result.GetFeatureCenter().y);
double const poiLon = MercatorBounds::XToLon(result.GetFeatureCenter().x);
jobject ret = env->NewObject(g_resultClass, g_resultConstructor, name, desc, poiLat, poiLon, ranges);
jni::TScopedLocalRef name(env, jni::ToJavaString(env, result.GetString()));
jobject ret = env->NewObject(g_resultClass, g_resultConstructor, name.get(), desc.get(), ll.lat, ll.lon, ranges.get());
ASSERT(ret, ());
env->DeleteLocalRef(name);
env->DeleteLocalRef(desc);
env->DeleteLocalRef(ranges);
return ret;
}
@ -106,9 +96,8 @@ jobjectArray BuildJavaResults(Results const & results, bool hasPosition, double
jobjectArray const jResults = env->NewObjectArray(count, g_resultClass, 0);
for (int i = 0; i < count; i++)
{
jobject jRes = ToJavaResult(g_results.GetResult(i), hasPosition, lat, lon);
env->SetObjectArrayElement(jResults, i, jRes);
env->DeleteLocalRef(jRes);
jni::TScopedLocalRef jRes(env, ToJavaResult(g_results.GetResult(i), hasPosition, lat, lon));
env->SetObjectArrayElement(jResults, i, jRes.get());
}
return jResults;
}
@ -130,11 +119,10 @@ void OnResults(Results const & results, long long timestamp, bool isMapAndTable,
return;
}
jobjectArray const & jResults = BuildJavaResults(results, hasPosition, lat, lon);
env->CallVoidMethod(g_javaListener, g_updateResultsId, jResults, static_cast<jlong>(timestamp));
env->DeleteLocalRef(jResults);
jni::TScopedLocalObjectArrayRef jResults(env, BuildJavaResults(results, hasPosition, lat, lon));
env->CallVoidMethod(g_javaListener, g_updateResultsId, jResults.get(), static_cast<jlong>(timestamp));
}
} // namespace
} // namespace
extern "C"
{
@ -144,20 +132,13 @@ extern "C"
if ( g_javaListener )
env->DeleteGlobalRef(g_javaListener);
g_javaListener = env->NewGlobalRef(thiz);
g_updateResultsId = jni::GetJavaMethodID(env, g_javaListener, "onResultsUpdate", "([Lcom/mapswithme/maps/search/SearchResult;J)V");
ASSERT(g_updateResultsId, ());
g_endResultsId = jni::GetJavaMethodID(env, g_javaListener, "onResultsEnd", "(J)V");
ASSERT(g_endResultsId, ());
g_resultClass = static_cast<jclass>(env->NewGlobalRef(env->FindClass("com/mapswithme/maps/search/SearchResult")));
ASSERT(g_resultClass, ());
g_resultConstructor = env->GetMethodID(g_resultClass, "<init>", "(Ljava/lang/String;Lcom/mapswithme/maps/search/SearchResult$Description;DD[I)V");
ASSERT(g_resultConstructor, ());
g_suggestConstructor = env->GetMethodID(g_resultClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;[I)V");
ASSERT(g_suggestConstructor, ());
g_descriptionClass = static_cast<jclass>(env->NewGlobalRef(env->FindClass("com/mapswithme/maps/search/SearchResult$Description")));
ASSERT(g_descriptionClass, ());
g_descriptionConstructor = env->GetMethodID(g_descriptionClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IZ)V");
ASSERT(g_descriptionConstructor, ());
g_updateResultsId = jni::GetMethodID(env, g_javaListener, "onResultsUpdate", "([Lcom/mapswithme/maps/search/SearchResult;J)V");
g_endResultsId = jni::GetMethodID(env, g_javaListener, "onResultsEnd", "(J)V");
g_resultClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/search/SearchResult");
g_resultConstructor = jni::GetConstructorID(env, g_resultClass, "(Ljava/lang/String;Lcom/mapswithme/maps/search/SearchResult$Description;DD[I)V");
g_suggestConstructor = jni::GetConstructorID(env, g_resultClass, "(Ljava/lang/String;Ljava/lang/String;DD[I)V");
g_descriptionClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/search/SearchResult$Description");
g_descriptionConstructor = jni::GetConstructorID(env, g_descriptionClass, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;II)V");
}
JNIEXPORT jboolean JNICALL
@ -170,7 +151,7 @@ extern "C"
params.SetForceSearch(force);
if (hasPosition)
params.SetPosition(lat, lon);
params.m_callback = bind(&OnResults, _1, timestamp, false, hasPosition, lat, lon);
params.m_onResults = bind(&OnResults, _1, timestamp, false, hasPosition, lat, lon);
bool const searchStarted = g_framework->NativeFramework()->Search(params);
if (searchStarted)
@ -190,13 +171,27 @@ extern "C"
if (isMapAndTable)
{
params.m_callback = bind(&OnResults, _1, timestamp, isMapAndTable,
false /* hasPosition */, 0, 0);
params.m_onResults = bind(&OnResults, _1, timestamp, isMapAndTable, false /* hasPosition */, 0.0, 0.0);
if (g_framework->NativeFramework()->Search(params))
g_queryTimestamp = timestamp;
}
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_search_SearchEngine_nativeRunSearchMaps(JNIEnv * env, jclass clazz, jbyteArray bytes, jstring lang, jlong timestamp)
{
search::SearchParams params;
params.m_query = jni::ToNativeString(env, bytes);
params.SetInputLocale(ReplaceDeprecatedLanguageCode(jni::ToNativeString(env, lang)));
params.SetForceSearch(true);
params.SetMode(search::Mode::World);
params.SetSuggestsEnabled(false);
params.m_onResults = bind(&OnResults, _1, timestamp, false /* isMapAndTable */, false /* hasPosition */, 0.0, 0.0);
g_framework->NativeFramework()->Search(params);
g_queryTimestamp = timestamp;
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_search_SearchEngine_nativeShowResult(JNIEnv * env, jclass clazz, jint index)
{
@ -215,7 +210,7 @@ extern "C"
auto const & results = g_results;
g_framework->PostDrapeTask([results]()
{
g_framework->NativeFramework()->ShowAllSearchResults(results);
g_framework->NativeFramework()->ShowSearchResults(results);
});
}

View file

@ -12,7 +12,7 @@ namespace
return (g_framework ? g_framework->NativeFramework() : nullptr);
}
} // namespace
} // namespace
extern "C"
{

View file

@ -0,0 +1,74 @@
#include "UserMarkHelper.hpp"
#include "map/place_page_info.hpp"
namespace usermark_helper
{
using search::AddressInfo;
using feature::Metadata;
void InjectMetadata(JNIEnv * env, jclass const clazz, jobject const mapObject, feature::Metadata const & metadata)
{
static jmethodID const addId = env->GetMethodID(clazz, "addMetadata", "(ILjava/lang/String;)V");
ASSERT(addId, ());
for (auto const t : metadata.GetPresentTypes())
{
// TODO: It is not a good idea to pass raw strings to UI. Calling separate getters should be a better way.
jni::TScopedLocalRef metaString(env, t == feature::Metadata::FMD_WIKIPEDIA ?
jni::ToJavaString(env, metadata.GetWikiURL()) :
jni::ToJavaString(env, metadata.Get(t)));
env->CallVoidMethod(mapObject, addId, t, metaString.get());
}
}
jobject CreateMapObject(JNIEnv * env, int mapObjectType, string const & title, string const & subtitle,
double lat, double lon, string const & address, Metadata const & metadata, string const & apiId)
{
// public MapObject(@MapObjectType int mapObjectType, String title, String subtitle, double lat, double lon, String address, String apiId)
static jmethodID const ctorId =
jni::GetConstructorID(env, g_mapObjectClazz, "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;DDLjava/lang/String;)V");
jobject mapObject = env->NewObject(g_mapObjectClazz, ctorId,
mapObjectType,
jni::ToJavaString(env, title),
jni::ToJavaString(env, subtitle),
jni::ToJavaString(env, address),
lat, lon,
jni::ToJavaString(env, apiId));
InjectMetadata(env, g_mapObjectClazz, mapObject, metadata);
return mapObject;
}
jobject CreateMapObject(JNIEnv * env, place_page::Info const & info)
{
ms::LatLon const ll = info.GetLatLon();
search::AddressInfo const address = g_framework->NativeFramework()->GetAddressInfoAtPoint(info.GetMercator());
// 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, kMyPosition, "", "", ll.lat, ll.lon, address.FormatAddress(), {}, "");
if (info.HasApiUrl())
return CreateMapObject(env, kApiPoint, info.GetTitle(), info.GetSubtitle(), ll.lat, ll.lon, address.FormatAddress(), info.GetMetadata(), info.GetApiUrl());
if (info.IsBookmark())
{
// public Bookmark(@IntRange(from = 0) int categoryId, @IntRange(from = 0) int bookmarkId, String name)
static jmethodID const ctorId = jni::GetConstructorID(env, g_bookmarkClazz, "(IILjava/lang/String;)V");
jni::TScopedLocalRef jName(env, jni::ToJavaString(env, info.GetTitle()));
jobject mapObject = env->NewObject(g_bookmarkClazz, ctorId,
static_cast<jint>(info.m_bac.first),
static_cast<jint>(info.m_bac.second),
jName.get());
if (info.IsFeature())
InjectMetadata(env, g_mapObjectClazz, mapObject, info.GetMetadata());
return mapObject;
}
return CreateMapObject(env, kPoi, info.GetTitle(), info.GetSubtitle(), ll.lat, ll.lon, address.FormatAddress(),
info.IsFeature() ? info.GetMetadata() : Metadata(), "");
}
} // namespace usermark_helper

View file

@ -0,0 +1,35 @@
#pragma once
#include <jni.h>
#include "com/mapswithme/core/jni_helper.hpp"
#include "com/mapswithme/maps/Framework.hpp"
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;
// Fills mapobject's metadata.
void InjectMetadata(JNIEnv * env, jclass clazz, jobject const mapObject, feature::Metadata const & metadata);
jobject CreateMapObject(JNIEnv * env, int mapObjectType, string const & title, string const & subtitle,
double lat, double lon, feature::Metadata const & metadata);
jobject CreateMapObject(JNIEnv * env, place_page::Info const & info);
} // namespace usermark_helper

View file

@ -5,82 +5,80 @@
namespace
{
::Framework * frm() { return g_framework->NativeFramework(); }
::Framework * frm() { return g_framework->NativeFramework(); }
Bookmark const * getBookmark(jint c, jlong b)
{
BookmarkCategory const * pCat = frm()->GetBmCategory(c);
ASSERT(pCat, ("Category not found", c));
Bookmark const * pBmk = static_cast<Bookmark const *>(pCat->GetUserMark(b));
return pBmk;
}
Bookmark const * getBookmark(jint c, jlong b)
{
BookmarkCategory const * pCat = frm()->GetBmCategory(c);
ASSERT(pCat, ("Category not found", c));
Bookmark const * pBmk = static_cast<Bookmark const *>(pCat->GetUserMark(b));
return pBmk;
}
}
extern "C"
{
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_bookmarks_data_Bookmark_getName(
JNIEnv * env, jobject thiz, jint cat, jlong bmk)
{
return jni::ToJavaString(env, getBookmark(cat, bmk)->GetName());
}
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_bookmarks_data_Bookmark_getBookmarkDescription(
JNIEnv * env, jobject thiz, jint cat, jlong bmk)
{
return jni::ToJavaString(env, getBookmark(cat, bmk)->GetDescription());
}
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_bookmarks_data_Bookmark_getIcon(
JNIEnv * env, jobject thiz, jint cat, jlong bmk)
{
return jni::ToJavaString(env, getBookmark(cat, bmk)->GetType());
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_bookmarks_data_Bookmark_setBookmarkParams(
JNIEnv * env, jobject thiz, jint cat, jlong bmk,
jstring name, jstring type, jstring descr)
{
Bookmark const * p = getBookmark(cat, bmk);
// initialize new bookmark
BookmarkData bm(jni::ToNativeString(env, name), jni::ToNativeString(env, type));
if (descr != 0)
bm.SetDescription(jni::ToNativeString(env, descr));
else
bm.SetDescription(p->GetDescription());
g_framework->ReplaceBookmark(BookmarkAndCategory(cat, bmk), bm);
}
JNIEXPORT jint JNICALL
Java_com_mapswithme_maps_bookmarks_data_Bookmark_changeCategory(
JNIEnv * env, jobject thiz, jint oldCat, jint newCat, jlong bmk)
{
return g_framework->ChangeBookmarkCategory(BookmarkAndCategory(oldCat, bmk), newCat);
}
JNIEXPORT jobject JNICALL
Java_com_mapswithme_maps_bookmarks_data_Bookmark_getXY(
JNIEnv * env, jobject thiz, jint cat, jlong bmk)
{
return jni::GetNewParcelablePointD(env, getBookmark(cat, bmk)->GetPivot());
}
JNIEXPORT jdouble JNICALL
Java_com_mapswithme_maps_bookmarks_data_Bookmark_getScale(
JNIEnv * env, jobject thiz, jint cat, jlong bmk)
{
return getBookmark(cat, bmk)->GetScale();
}
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_bookmarks_data_Bookmark_encode2Ge0Url(
JNIEnv * env, jobject thiz, jint cat, jlong bmk, jboolean addName)
{
return jni::ToJavaString(env, frm()->CodeGe0url(getBookmark(cat, bmk), addName));
}
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_bookmarks_data_Bookmark_nativeGetName(
JNIEnv * env, jobject thiz, jint cat, jlong bmk)
{
return jni::ToJavaString(env, getBookmark(cat, bmk)->GetName());
}
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_bookmarks_data_Bookmark_nativeGetBookmarkDescription(
JNIEnv * env, jobject thiz, jint cat, jlong bmk)
{
return jni::ToJavaString(env, getBookmark(cat, bmk)->GetDescription());
}
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_bookmarks_data_Bookmark_nativeGetIcon(
JNIEnv * env, jobject thiz, jint cat, jlong bmk)
{
return jni::ToJavaString(env, getBookmark(cat, bmk)->GetType());
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_bookmarks_data_Bookmark_nativeSetBookmarkParams(
JNIEnv * env, jobject thiz, jint cat, jlong bmk,
jstring name, jstring type, jstring descr)
{
Bookmark const * p = getBookmark(cat, bmk);
// initialize new bookmark
BookmarkData bm(jni::ToNativeString(env, name), jni::ToNativeString(env, type));
bm.SetDescription(descr ? jni::ToNativeString(env, descr)
: p->GetDescription());
g_framework->ReplaceBookmark(BookmarkAndCategory(cat, bmk), bm);
}
JNIEXPORT jint JNICALL
Java_com_mapswithme_maps_bookmarks_data_Bookmark_nativeChangeCategory(
JNIEnv * env, jobject thiz, jint oldCat, jint newCat, jlong bmk)
{
return g_framework->ChangeBookmarkCategory(BookmarkAndCategory(oldCat, bmk), newCat);
}
JNIEXPORT jobject JNICALL
Java_com_mapswithme_maps_bookmarks_data_Bookmark_nativeGetXY(
JNIEnv * env, jobject thiz, jint cat, jlong bmk)
{
return jni::GetNewParcelablePointD(env, getBookmark(cat, bmk)->GetPivot());
}
JNIEXPORT jdouble JNICALL
Java_com_mapswithme_maps_bookmarks_data_Bookmark_nativeGetScale(
JNIEnv * env, jobject thiz, jint cat, jlong bmk)
{
return getBookmark(cat, bmk)->GetScale();
}
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_bookmarks_data_Bookmark_nativeEncode2Ge0Url(
JNIEnv * env, jobject thiz, jint cat, jlong bmk, jboolean addName)
{
return jni::ToJavaString(env, frm()->CodeGe0url(getBookmark(cat, bmk), addName));
}
}

View file

@ -1,128 +1,122 @@
#include "../../Framework.hpp"
#include "com/mapswithme/maps/Framework.hpp"
#include "com/mapswithme/maps/UserMarkHelper.hpp"
#include "com/mapswithme/core/jni_helper.hpp"
#include "map/place_page_info.hpp"
#include "platform/measurement_utils.hpp"
#include "../../../core/jni_helper.hpp"
namespace
{
::Framework * frm() { return g_framework->NativeFramework(); }
::Framework * frm() { return g_framework->NativeFramework(); }
BookmarkCategory * getBmCategory(jint c)
{
BookmarkCategory * pCat = frm()->GetBmCategory(c);
ASSERT(pCat, ("Category not found", c));
return pCat;
}
BookmarkCategory * getBmCategory(jint c)
{
BookmarkCategory * pCat = frm()->GetBmCategory(c);
ASSERT(pCat, ("Category not found", c));
return pCat;
}
}
extern "C"
{
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkCategory_isVisible(
JNIEnv * env, jobject thiz, jint id)
{
return getBmCategory(id)->IsVisible();
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkCategory_setVisibility(
JNIEnv * env, jobject thiz, jint id, jboolean b)
{
BookmarkCategory * pCat = getBmCategory(id);
{
BookmarkCategory::Guard guard(*pCat);
guard.m_controller.SetIsVisible(b);
}
pCat->SaveToKMLFile();
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkCategory_setName(
JNIEnv * env, jobject thiz, jint id, jstring n)
{
BookmarkCategory * pCat = getBmCategory(id);
pCat->SetName(jni::ToNativeString(env, n));
pCat->SaveToKMLFile();
}
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkCategory_getName(
JNIEnv * env, jobject thiz, jint id)
{
return jni::ToJavaString(env, getBmCategory(id)->GetName());
}
JNIEXPORT jint JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkCategory_getSize(
JNIEnv * env, jobject thiz, jint id)
{
BookmarkCategory * category = getBmCategory(id);
return category->GetUserMarkCount() + category->GetTracksCount();
}
JNIEXPORT jint JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkCategory_getBookmarksCount(
JNIEnv * env, jobject thiz, jint id)
{
return getBmCategory(id)->GetUserMarkCount();
}
JNIEXPORT jint JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkCategory_getTracksCount(
JNIEnv * env, jobject thiz, jint id)
{
return getBmCategory(id)->GetTracksCount();
}
JNIEXPORT jobject JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkCategory_getBookmark(
JNIEnv * env, jobject thiz, jint id, jint index, jclass bookmarkClazz)
{
// Bookmark(int categoryId, int bookmarkId, String name)
jmethodID static const cId = env->GetMethodID(bookmarkClazz, "<init>", "(IILjava/lang/String;)V");
BookmarkCategory * category = getBmCategory(id);
Bookmark const * nBookmark = static_cast<Bookmark const *>(category->GetUserMark(index));
ASSERT(nBookmark, ("Bookmark must not be null with index:)", index));
jobject jBookmark = env->NewObject(bookmarkClazz, cId,
id, index, jni::ToJavaString(env, nBookmark->GetName()));
g_framework->InjectMetadata(env, bookmarkClazz, jBookmark, nBookmark);
return jBookmark;
}
static uint32_t shift(uint32_t v, uint8_t bitCount) { return v << bitCount; }
JNIEXPORT jobject JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkCategory_getTrack(
JNIEnv * env, jobject thiz, jint id, jint index, jclass trackClazz)
{
// Track(int trackId, int categoryId, String name, String lengthString, int color)
static jmethodID cId = env->GetMethodID(trackClazz, "<init>",
"(IILjava/lang/String;Ljava/lang/String;I)V");
BookmarkCategory * category = getBmCategory(id);
Track const * nTrack = category->GetTrack(index);
ASSERT(nTrack, ("Track must not be null with index:)", index));
string formattedLenght;
MeasurementUtils::FormatDistance(nTrack->GetLengthMeters(), formattedLenght);
dp::Color nColor = nTrack->GetColor(0);
jint androidColor = shift(nColor.GetAlfa(), 24) +
shift(nColor.GetRed(), 16) +
shift(nColor.GetGreen(), 8) +
nColor.GetBlue();
return env->NewObject(trackClazz, cId,
index, id, jni::ToJavaString(env, nTrack->GetName()),
jni::ToJavaString(env, formattedLenght), androidColor);
}
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkCategory_nativeIsVisible(
JNIEnv * env, jobject thiz, jint id)
{
return getBmCategory(id)->IsVisible();
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkCategory_nativeSetVisibility(
JNIEnv * env, jobject thiz, jint id, jboolean b)
{
BookmarkCategory * pCat = getBmCategory(id);
{
BookmarkCategory::Guard guard(*pCat);
guard.m_controller.SetIsVisible(b);
}
pCat->SaveToKMLFile();
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkCategory_nativeSetName(
JNIEnv * env, jobject thiz, jint id, jstring n)
{
BookmarkCategory * pCat = getBmCategory(id);
pCat->SetName(jni::ToNativeString(env, n));
pCat->SaveToKMLFile();
}
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkCategory_nativeGetName(
JNIEnv * env, jobject thiz, jint id)
{
return jni::ToJavaString(env, getBmCategory(id)->GetName());
}
JNIEXPORT jint JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkCategory_nativeGetSize(
JNIEnv * env, jobject thiz, jint id)
{
BookmarkCategory * category = getBmCategory(id);
return category->GetUserMarkCount() + category->GetTracksCount();
}
JNIEXPORT jint JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkCategory_nativeGetBookmarksCount(
JNIEnv * env, jobject thiz, jint id)
{
return getBmCategory(id)->GetUserMarkCount();
}
JNIEXPORT jint JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkCategory_nativeGetTracksCount(
JNIEnv * env, jobject thiz, jint id)
{
return getBmCategory(id)->GetTracksCount();
}
// TODO(AlexZ): Get rid of UserMarks completely in UI code.
// TODO(yunikkk): Refactor java code to get all necessary info without Bookmark wrapper, and without hierarchy.
// If bookmark information is needed in the BookmarkManager, it does not relate in any way to Place Page info
// and should be passed separately via simple name string and lat lon to calculate a distance.
JNIEXPORT jobject JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkCategory_nativeGetBookmark(
JNIEnv * env, jobject thiz, jint catId, jint bmkId)
{
BookmarkCategory * category = getBmCategory(catId);
place_page::Info info;
frm()->FillBookmarkInfo(*static_cast<Bookmark const *>(category->GetUserMark(bmkId)), {catId, bmkId}, info);
return usermark_helper::CreateMapObject(env, info);
}
static uint32_t shift(uint32_t v, uint8_t bitCount) { return v << bitCount; }
JNIEXPORT jobject JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkCategory_nativeGetTrack(
JNIEnv * env, jobject thiz, jint id, jint bmkId, jclass trackClazz)
{
// Track(int trackId, int categoryId, String name, String lengthString, int color)
static jmethodID const cId = jni::GetConstructorID(env, trackClazz,
"(IILjava/lang/String;Ljava/lang/String;I)V");
BookmarkCategory * category = getBmCategory(id);
Track const * nTrack = category->GetTrack(bmkId);
ASSERT(nTrack, ("Track must not be null with index:)", bmkId));
string formattedLenght;
MeasurementUtils::FormatDistance(nTrack->GetLengthMeters(), formattedLenght);
dp::Color nColor = nTrack->GetColor(0);
jint androidColor = shift(nColor.GetAlfa(), 24) +
shift(nColor.GetRed(), 16) +
shift(nColor.GetGreen(), 8) +
nColor.GetBlue();
return env->NewObject(trackClazz, cId,
bmkId, id, jni::ToJavaString(env, nTrack->GetName()),
jni::ToJavaString(env, formattedLenght), androidColor);
}
} // extern "C"

View file

@ -1,124 +1,133 @@
#include "../../Framework.hpp"
#include "../../../core/jni_helper.hpp"
#include "com/mapswithme/core/jni_helper.hpp"
#include "com/mapswithme/maps/Framework.hpp"
#include "com/mapswithme/maps/UserMarkHelper.hpp"
#include "coding/zip_creator.hpp"
#include "map/place_page_info.hpp"
namespace
{
::Framework * frm() { return g_framework->NativeFramework(); }
}
::Framework * frm() { return g_framework->NativeFramework(); }
} // namespace
extern "C"
{
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_showBookmarkOnMap(
JNIEnv * env, jobject thiz, jint c, jint b)
using namespace jni;
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeShowBookmarkOnMap(
JNIEnv * env, jobject thiz, jint c, jint b)
{
BookmarkAndCategory bnc = BookmarkAndCategory(c,b);
g_framework->PostDrapeTask([bnc]()
{
BookmarkAndCategory bnc = BookmarkAndCategory(c,b);
g_framework->PostDrapeTask([bnc]()
{
frm()->ShowBookmark(bnc);
frm()->SaveState();
});
}
frm()->ShowBookmark(bnc);
});
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_loadBookmarks(JNIEnv * env, jobject thiz)
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeLoadBookmarks(JNIEnv * env, jobject thiz)
{
frm()->LoadBookmarks();
}
JNIEXPORT jint JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetCategoriesCount(JNIEnv * env, jobject thiz)
{
return frm()->GetBmCategoriesCount();
}
JNIEXPORT jint JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeCreateCategory(
JNIEnv * env, jobject thiz, jstring name)
{
return frm()->AddCategory(ToNativeString(env, name));
}
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeDeleteCategory(
JNIEnv * env, jobject thiz, jint index)
{
return frm()->DeleteBmCategory(index);
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeDeleteBookmark(JNIEnv *, jobject, jint cat, jint bmk)
{
BookmarkCategory * pCat = frm()->GetBmCategory(cat);
if (pCat)
{
frm()->LoadBookmarks();
}
JNIEXPORT jint JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_getCategoriesCount(JNIEnv * env, jobject thiz)
{
return frm()->GetBmCategoriesCount();
}
JNIEXPORT jint JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_createCategory(
JNIEnv * env, jobject thiz, jstring name)
{
return frm()->AddCategory(jni::ToNativeString(env, name));
}
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_deleteCategory(
JNIEnv * env, jobject thiz, jint index)
{
return frm()->DeleteBmCategory(index) ? JNI_TRUE : JNI_FALSE;
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_deleteBookmark(
JNIEnv * env, jobject thiz, jint cat, jint bmk)
{
BookmarkCategory * pCat = frm()->GetBmCategory(cat);
if (pCat)
{
BookmarkCategory::Guard guard(*pCat);
guard.m_controller.DeleteUserMark(bmk);
pCat->SaveToKMLFile();
}
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeDeleteTrack(
JNIEnv * env, jobject thiz, jint cat, jint trk)
{
BookmarkCategory * pCat = frm()->GetBmCategory(cat);
if (pCat)
{
pCat->DeleteTrack(trk);
pCat->SaveToKMLFile();
}
}
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_saveToKmzFile(
JNIEnv * env, jobject thiz, jint catID, jstring tmpPath)
{
BookmarkCategory * pCat = frm()->GetBmCategory(catID);
if (pCat)
{
string const name = pCat->GetName();
if (CreateZipFromPathDeflatedAndDefaultCompression(pCat->GetFileName(), jni::ToNativeString(env, tmpPath) + name + ".kmz"))
return jni::ToJavaString(env, name);
}
return 0;
}
JNIEXPORT jint JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_addBookmarkToLastEditedCategory(
JNIEnv * env, jobject thiz, jstring name, double lat, double lon)
{
const m2::PointD glbPoint(MercatorBounds::FromLatLon(lat, lon));
::Framework * f = frm();
BookmarkData bmk(jni::ToNativeString(env, name), f->LastEditedBMType());
return g_framework->AddBookmark(f->LastEditedBMCategory(), glbPoint, bmk).second;
}
JNIEXPORT jint JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_getLastEditedCategory(
JNIEnv * env, jobject thiz)
{
return frm()->LastEditedBMCategory();
}
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_generateUniqueBookmarkName(JNIEnv * env, jclass thiz, jstring jBaseName)
{
string baseName = jni::ToNativeString(env, jBaseName);
string bookmarkFileName = BookmarkCategory::GenerateUniqueFileName(GetPlatform().SettingsDir(), baseName);
return jni::ToJavaString(env, bookmarkFileName);
}
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_loadKmzFile(JNIEnv * env, jobject thiz, jstring path)
{
return frm()->AddBookmarksFile(jni::ToNativeString(env, path)) ? JNI_TRUE : JNI_FALSE;
BookmarkCategory::Guard guard(*pCat);
guard.m_controller.DeleteUserMark(bmk);
pCat->SaveToKMLFile();
}
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeDeleteTrack(
JNIEnv * env, jobject thiz, jint cat, jint trk)
{
BookmarkCategory * pCat = frm()->GetBmCategory(cat);
if (pCat)
{
pCat->DeleteTrack(trk);
pCat->SaveToKMLFile();
}
}
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeSaveToKmzFile(
JNIEnv * env, jobject thiz, jint catID, jstring tmpPath)
{
BookmarkCategory * pCat = frm()->GetBmCategory(catID);
if (pCat)
{
string const name = pCat->GetName();
if (CreateZipFromPathDeflatedAndDefaultCompression(pCat->GetFileName(), ToNativeString(env, tmpPath) + name + ".kmz"))
return ToJavaString(env, name);
}
return nullptr;
}
JNIEXPORT jobject JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeAddBookmarkToLastEditedCategory(
JNIEnv * env, jobject thiz, jstring name, double lat, double lon)
{
m2::PointD const glbPoint(MercatorBounds::FromLatLon(lat, lon));
::Framework * f = frm();
BookmarkData bmkData(ToNativeString(env, name), f->LastEditedBMType());
size_t const lastEditedCategory = f->LastEditedBMCategory();
size_t const createdBookmarkIndex = f->AddBookmark(lastEditedCategory, glbPoint, bmkData);
place_page::Info & info = g_framework->GetPlacePageInfo();
info.m_bac = {lastEditedCategory, createdBookmarkIndex};
return usermark_helper::CreateMapObject(env, info);
}
JNIEXPORT jint JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_getLastEditedCategory(
JNIEnv * env, jobject thiz)
{
return frm()->LastEditedBMCategory();
}
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGenerateUniqueFileName(JNIEnv * env, jclass thiz, jstring jBaseName)
{
string baseName = ToNativeString(env, jBaseName);
string bookmarkFileName = BookmarkCategory::GenerateUniqueFileName(GetPlatform().SettingsDir(), baseName);
return ToJavaString(env, bookmarkFileName);
}
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeLoadKmzFile(JNIEnv * env, jobject thiz, jstring path)
{
return frm()->AddBookmarksFile(ToNativeString(env, path));
}
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeFormatNewBookmarkName(JNIEnv * env, jclass)
{
return ToJavaString(env, g_framework->GetPlacePageInfo().FormatNewBookmarkName());
}
} // extern "C"

View file

@ -0,0 +1,338 @@
#include <jni.h>
#include "com/mapswithme/core/jni_helper.hpp"
#include "com/mapswithme/maps/Framework.hpp"
#include "base/assert.hpp"
#include "base/logging.hpp"
#include "base/string_utils.hpp"
#include "indexer/cuisines.hpp"
#include "indexer/editable_map_object.hpp"
#include "indexer/osm_editor.hpp"
#include "std/algorithm.hpp"
#include "std/set.hpp"
#include "std/target_os.hpp"
#include "std/vector.hpp"
namespace
{
using TCuisine = pair<string, string>;
osm::EditableMapObject g_editableMapObject;
jclass g_featureCategoryClazz;
jmethodID g_featureCtor;
jobject ToJavaFeatureCategory(JNIEnv * env, osm::Category const & category)
{
return env->NewObject(g_featureCategoryClazz, g_featureCtor, category.m_type, jni::TScopedLocalRef(env, jni::ToJavaString(env, category.m_name)).get());
}
jobjectArray ToJavaArray(JNIEnv * env, vector<string> const & src)
{
int const size = src.size();
auto jArray = env->NewObjectArray(size, jni::GetStringClass(env), 0);
for (size_t i = 0; i < size; i++)
{
jni::TScopedLocalRef jItem(env, jni::ToJavaString(env, src[i]));
env->SetObjectArrayElement(jArray, i, jItem.get());
}
return jArray;
}
} // namespace
extern "C"
{
using osm::Editor;
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeInit(JNIEnv * env, jclass)
{
g_featureCategoryClazz = jni::GetGlobalClassRef(env, "com/mapswithme/maps/editor/data/FeatureCategory");;
// public FeatureCategory(int category, String name)
g_featureCtor = jni::GetConstructorID(env, g_featureCategoryClazz, "(ILjava/lang/String;)V");
}
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeGetMetadata(JNIEnv * env, jclass, jint type)
{
// TODO(yunikkk): Switch to osm::Props enum instead of metadata, and use separate getters instead a generic one.
return jni::ToJavaString(env, g_editableMapObject.GetMetadata().Get(static_cast<feature::Metadata::EType>(type)));
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeSetMetadata(JNIEnv * env, jclass clazz, jint type, jstring value)
{
// TODO(yunikkk): I would recommend to use separate setters/getters for each metadata field.
string const v = jni::ToNativeString(env, value);
using feature::Metadata;
switch (type)
{
case Metadata::FMD_OPEN_HOURS: g_editableMapObject.SetOpeningHours(v); break;
case Metadata::FMD_PHONE_NUMBER: g_editableMapObject.SetPhone(v); break;
case Metadata::FMD_FAX_NUMBER: g_editableMapObject.SetFax(v); break;
case Metadata::FMD_STARS:
{
// TODO(yunikkk): Pass stars in a separate integer setter.
int stars;
if (strings::to_int(v, stars))
g_editableMapObject.SetStars(stars);
break;
}
case Metadata::FMD_OPERATOR: g_editableMapObject.SetOperator(v); break;
case Metadata::FMD_URL: // We don't allow url in UI. Website should be used instead.
case Metadata::FMD_WEBSITE: g_editableMapObject.SetWebsite(v); break;
case Metadata::FMD_INTERNET: // TODO(yunikkk): use separate setter for Internet.
{
osm::Internet inet = osm::Internet::Unknown;
if (v == DebugPrint(osm::Internet::Wlan))
inet = osm::Internet::Wlan;
if (v == DebugPrint(osm::Internet::Wired))
inet = osm::Internet::Wired;
if (v == DebugPrint(osm::Internet::No))
inet = osm::Internet::No;
if (v == DebugPrint(osm::Internet::Yes))
inet = osm::Internet::Yes;
g_editableMapObject.SetInternet(inet);
}
break;
case Metadata::FMD_ELE:
{
double ele;
if (strings::to_double(v, ele))
g_editableMapObject.SetElevation(ele);
break;
}
case Metadata::FMD_EMAIL: g_editableMapObject.SetEmail(v); break;
case Metadata::FMD_POSTCODE: g_editableMapObject.SetPostcode(v); break;
case Metadata::FMD_WIKIPEDIA: g_editableMapObject.SetWikipedia(v); break;
case Metadata::FMD_FLATS: g_editableMapObject.SetFlats(v); break;
case Metadata::FMD_BUILDING_LEVELS: g_editableMapObject.SetBuildingLevels(v); break;
case Metadata::FMD_TURN_LANES:
case Metadata::FMD_TURN_LANES_FORWARD:
case Metadata::FMD_TURN_LANES_BACKWARD:
case Metadata::FMD_MAXSPEED:
case Metadata::FMD_HEIGHT:
case Metadata::FMD_MIN_HEIGHT:
case Metadata::FMD_DENOMINATION:
case Metadata::FMD_TEST_ID:
case Metadata::FMD_COUNT:
break;
}
}
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeSaveEditedFeature(JNIEnv *, jclass)
{
switch (g_framework->NativeFramework()->SaveEditedMapObject(g_editableMapObject))
{
case osm::Editor::NothingWasChanged:
case osm::Editor::SavedSuccessfully:
return true;
case osm::Editor::NoFreeSpaceError:
return false;
}
}
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeIsFeatureEditable(JNIEnv *, jclass)
{
return g_framework->GetPlacePageInfo().IsEditable();
}
JNIEXPORT jintArray JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeGetEditableFields(JNIEnv * env, jclass clazz)
{
auto const & editable = g_editableMapObject.GetEditableFields();
int const size = editable.size();
jintArray jEditableFields = env->NewIntArray(size);
jint * arr = env->GetIntArrayElements(jEditableFields, 0);
for (int i = 0; i < size; ++i)
arr[i] = editable[i];
env->ReleaseIntArrayElements(jEditableFields, arr, 0);
return jEditableFields;
}
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeIsAddressEditable(JNIEnv * env, jclass clazz)
{
return g_editableMapObject.IsAddressEditable();
}
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeIsNameEditable(JNIEnv * env, jclass clazz)
{
return g_editableMapObject.IsNameEditable();
}
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeGetDefaultName(JNIEnv * env, jclass)
{
// TODO(yunikkk): add multilanguage names support via EditableMapObject::GetLocalizedName().
return jni::ToJavaString(env, g_editableMapObject.GetDefaultName());
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeSetDefaultName(JNIEnv * env, jclass, jstring name)
{
// TODO(yunikkk): add multilanguage names support.
g_editableMapObject.SetName(jni::ToNativeString(env, name), StringUtf8Multilang::kDefaultCode);
}
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeGetStreet(JNIEnv * env, jclass)
{
return jni::ToJavaString(env, g_editableMapObject.GetStreet());
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeSetStreet(JNIEnv * env, jclass, jstring street)
{
g_editableMapObject.SetStreet(jni::ToNativeString(env, street));
}
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeGetHouseNumber(JNIEnv * env, jclass)
{
return jni::ToJavaString(env, g_editableMapObject.GetHouseNumber());
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeSetHouseNumber(JNIEnv * env, jclass, jstring houseNumber)
{
g_editableMapObject.SetHouseNumber(jni::ToNativeString(env, houseNumber));
}
JNIEXPORT jobjectArray JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeGetNearbyStreets(JNIEnv * env, jclass clazz)
{
auto const & streets = g_editableMapObject.GetNearbyStreets();
int const size = streets.size();
jobjectArray jStreets = env->NewObjectArray(size, jni::GetStringClass(env), 0);
for (int i = 0; i < size; ++i)
env->SetObjectArrayElement(jStreets, i, jni::TScopedLocalRef(env, jni::ToJavaString(env, streets[i])).get());
return jStreets;
}
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeHasWifi(JNIEnv *, jclass)
{
// TODO(AlexZ): Support 3-state: yes, no, unknown.
return g_editableMapObject.GetMetadata().Get(feature::Metadata::FMD_INTERNET) == "wlan";
}
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeHasSomethingToUpload(JNIEnv * env, jclass clazz)
{
return Editor::Instance().HaveSomethingToUpload();
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeUploadChanges(JNIEnv * env, jclass clazz, jstring token, jstring secret,
jstring appVersion, jstring appId)
{
// TODO: Handle upload status in callback
Editor::Instance().UploadChanges(jni::ToNativeString(env, token), jni::ToNativeString(env, secret),
{{"created_by", "MAPS.ME " OMIM_OS_NAME " " + jni::ToNativeString(env, appVersion)},
{"bundle_id", jni::ToNativeString(env, appId)}}, nullptr);
}
JNIEXPORT jlongArray JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeGetStats(JNIEnv * env, jclass clazz)
{
auto const stats = Editor::Instance().GetStats();
jlongArray result = env->NewLongArray(3);
jlong buf[] = {stats.m_edits.size(), stats.m_uploadedCount, stats.m_lastUploadTimestamp};
env->SetLongArrayRegion(result, 0, 3, buf);
return result;
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeClearLocalEdits(JNIEnv * env, jclass clazz)
{
Editor::Instance().ClearAllLocalEdits();
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeStartEdit(JNIEnv *, jclass)
{
::Framework * frm = g_framework->NativeFramework();
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_com_mapswithme_maps_editor_Editor_nativeCreateMapObject(JNIEnv *, jclass, jint featureCategory)
{
::Framework * frm = g_framework->NativeFramework();
CHECK(frm->CreateMapObject(frm->GetViewportCenter(), featureCategory, g_editableMapObject),
("Couldn't create mapobject, wrong coordinates of missing mwm"));
}
JNIEXPORT jobjectArray JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeGetNewFeatureCategories(JNIEnv * env, jclass clazz)
{
osm::NewFeatureCategories const & printableTypes = g_framework->NativeFramework()->GetEditorCategories();
int const size = printableTypes.m_allSorted.size();
auto jCategories = env->NewObjectArray(size, g_featureCategoryClazz, 0);
for (size_t i = 0; i < size; i++)
{
// TODO pass used categories section, too
jni::TScopedLocalRef jCategory(env, ToJavaFeatureCategory(env, printableTypes.m_allSorted[i]));
env->SetObjectArrayElement(jCategories, i, jCategory.get());
}
return jCategories;
}
JNIEXPORT jobjectArray JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeGetCuisines(JNIEnv * env, jclass clazz)
{
osm::TAllCuisines const & cuisines = osm::Cuisines::Instance().AllSupportedCuisines();
vector<string> keys;
keys.reserve(cuisines.size());
for (TCuisine const & cuisine : cuisines)
keys.push_back(cuisine.first);
return ToJavaArray(env, keys);
}
JNIEXPORT jobjectArray JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeGetSelectedCuisines(JNIEnv * env, jclass clazz)
{
return ToJavaArray(env, g_editableMapObject.GetCuisines());
}
JNIEXPORT jobjectArray JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeTranslateCuisines(JNIEnv * env, jclass clazz, jobjectArray jKeys)
{
int const length = env->GetArrayLength(jKeys);
vector<string> translations;
translations.reserve(length);
for (int i = 0; i < length; i++)
{
string const & key = jni::ToNativeString(env, (jstring) env->GetObjectArrayElement(jKeys, i));
translations.push_back(osm::Cuisines::Instance().Translate(key));
}
return ToJavaArray(env, translations);
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeSetSelectedCuisines(JNIEnv * env, jclass clazz, jobjectArray jKeys)
{
int const length = env->GetArrayLength(jKeys);
vector<string> cuisines;
cuisines.reserve(length);
for (int i = 0; i < length; i++)
cuisines.push_back(jni::ToNativeString(env, (jstring) env->GetObjectArrayElement(jKeys, i)));
g_editableMapObject.SetCuisines(cuisines);
}
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_editor_Editor_nativeGetFormattedCuisine(JNIEnv * env, jclass clazz)
{
return jni::ToJavaString(env, g_editableMapObject.FormatCuisines());
}
} // extern "C"

View file

@ -0,0 +1,317 @@
#include <jni.h>
#include "com/mapswithme/core/jni_helper.hpp"
#include "editor/opening_hours_ui.hpp"
#include "editor/ui2oh.hpp"
#include "base/logging.hpp"
#include "std/algorithm.hpp"
#include "std/set.hpp"
#include "std/vector.hpp"
#include "3party/opening_hours/opening_hours.hpp"
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)
{
jobject const hoursMinutes = env->NewObject(g_clazzHoursMinutes, g_ctorHoursMinutes, hours, minutes);
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()));
}
jobjectArray JavaTimespans(JNIEnv * env, vector<Timespan> const & spans)
{
int const size = spans.size();
jobjectArray const result = env->NewObjectArray(size, g_clazzTimespan, 0);
for (int i = 0; i < size; i++)
{
jobject const jSpan = JavaTimespan(env, spans[i]);
env->SetObjectArrayElement(result, i, jSpan);
env->DeleteLocalRef(jSpan);
}
return result;
}
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();
set<Weekday> weekdays = tt.GetOpeningDays();
vector<int> weekdaysVector;
weekdaysVector.reserve(weekdays.size());
transform(weekdays.begin(), weekdays.end(), back_inserter(weekdaysVector), [](Weekday weekday)
{
return static_cast<int>(weekday);
});
jintArray jWeekdays = env->NewIntArray(weekdays.size());
env->SetIntArrayRegion(jWeekdays, 0, weekdaysVector.size(), &weekdaysVector[0]);
return JavaTimetable(env,
JavaTimespan(env, tt.GetOpeningTime()),
JavaTimespans(env, tt.GetExcludeTime()),
tt.IsTwentyFourHours(),
jWeekdays);
}
jobjectArray JavaTimetables(JNIEnv * env, TimeTableSet & tts)
{
int const size = tts.Size();
jobjectArray const result = env->NewObjectArray(size, g_clazzTimetable, 0);
for (int i = 0; i < size; i++)
{
jobject const jTable = JavaTimetable(env, tts.Get(i));
env->SetObjectArrayElement(result, i, jTable);
env->DeleteLocalRef(jTable);
}
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++)
{
jobject const jSpan = env->GetObjectArrayElement(jClosedSpans, i);
if (jSpan)
{
tt.AddExcludeTime(NativeTimespan(env, jSpan));
env->DeleteLocalRef(jSpan);
}
}
return tt;
}
TimeTableSet NativeTimetableSet(JNIEnv * env, jobjectArray jTimetables)
{
TimeTableSet tts;
int const size = env->GetArrayLength(jTimetables);
jobject const timetable = env->GetObjectArrayElement(jTimetables, 0);
tts.Replace(NativeTimetable(env, timetable), 0);
for (int i = 1; i < size; i++)
{
jobject const timetable = env->GetObjectArrayElement(jTimetables, i);
tts.Append(NativeTimetable(env, timetable));
env->DeleteLocalRef(timetable);
}
return tts;
}
} // namespace
extern "C"
{
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_editor_OpeningHours_nativeInit(JNIEnv * env, jclass clazz)
{
g_clazzHoursMinutes = jni::GetGlobalClassRef(env, "com/mapswithme/maps/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>", "(JJ)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, "com/mapswithme/maps/editor/data/Timespan");
// Java signature : Timespan(HoursMinutes start, HoursMinutes end)
g_ctorTimespan =
env->GetMethodID(g_clazzTimespan, "<init>","(Lcom/mapswithme/maps/editor/data/HoursMinutes;Lcom/mapswithme/maps/editor/data/HoursMinutes;)V");
ASSERT(g_ctorTimespan, (jni::DescribeException()));
g_fidStart = env->GetFieldID(g_clazzTimespan, "start", "Lcom/mapswithme/maps/editor/data/HoursMinutes;");
ASSERT(g_fidStart, (jni::DescribeException()));
g_fidEnd = env->GetFieldID(g_clazzTimespan, "end", "Lcom/mapswithme/maps/editor/data/HoursMinutes;");
ASSERT(g_fidEnd, (jni::DescribeException()));
g_clazzTimetable = jni::GetGlobalClassRef(env, "com/mapswithme/maps/editor/data/Timetable");
// Java signature : Timetable(Timespan workingTime, Timespan[] closedHours, boolean isFullday, int weekdays[])
g_ctorTimetable =
env->GetMethodID(g_clazzTimetable, "<init>","(Lcom/mapswithme/maps/editor/data/Timespan;[Lcom/mapswithme/maps/editor/data/Timespan;Z[I)V");
ASSERT(g_ctorTimetable, (jni::DescribeException()));
g_fidWorkingTimespan = env->GetFieldID(g_clazzTimetable, "workingTimespan", "Lcom/mapswithme/maps/editor/data/Timespan;");
ASSERT(g_fidWorkingTimespan, (jni::DescribeException()));
g_fidClosedTimespans = env->GetFieldID(g_clazzTimetable, "closedTimespans", "[Lcom/mapswithme/maps/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_com_mapswithme_maps_editor_OpeningHours_nativeGetDefaultTimetables(JNIEnv * env, jclass clazz)
{
TimeTableSet tts;
return JavaTimetables(env, tts);
}
JNIEXPORT jobject JNICALL
Java_com_mapswithme_maps_editor_OpeningHours_nativeGetComplementTimetable(JNIEnv * env, jclass clazz, jobjectArray timetables)
{
TimeTableSet const tts = NativeTimetableSet(env, timetables);
return JavaTimetable(env, tts.GetComplementTimeTable());
}
JNIEXPORT jobject JNICALL
Java_com_mapswithme_maps_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 jobject JNICALL
Java_com_mapswithme_maps_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_com_mapswithme_maps_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_com_mapswithme_maps_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_com_mapswithme_maps_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_com_mapswithme_maps_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_com_mapswithme_maps_editor_OpeningHours_nativeTimetablesFromString(JNIEnv * env, jclass clazz, jstring jSource)
{
TimeTableSet tts;
string const source = jni::ToNativeString(env, jSource);
if (!source.empty() && MakeTimeTableSet(OpeningHours(source), tts))
return JavaTimetables(env, tts);
return nullptr;
}
JNIEXPORT jstring JNICALL
Java_com_mapswithme_maps_editor_OpeningHours_nativeTimetablesToString(JNIEnv * env, jclass clazz, jobjectArray jTts)
{
TimeTableSet tts = NativeTimetableSet(env, jTts);
stringstream sstr;
sstr << MakeOpeningHours(tts).GetRule();
return jni::ToJavaString(env, sstr.str());
}
}

View file

@ -0,0 +1,100 @@
#include <jni.h>
#include "com/mapswithme/core/jni_helper.hpp"
#include "base/logging.hpp"
#include "editor/osm_auth.hpp"
namespace
{
using namespace osm;
using namespace jni;
jobjectArray ToStringArray(JNIEnv * env, TKeySecret const & secret)
{
jobjectArray resultArray = env->NewObjectArray(2, GetStringClass(env), nullptr);
env->SetObjectArrayElement(resultArray, 0, ToJavaString(env, secret.first));
env->SetObjectArrayElement(resultArray, 1, ToJavaString(env, secret.second));
return resultArray;
}
// @returns [url, key, secret]
jobjectArray ToStringArray(JNIEnv * env, OsmOAuth::TUrlRequestToken const & uks)
{
jobjectArray resultArray = env->NewObjectArray(3, GetStringClass(env), nullptr);
env->SetObjectArrayElement(resultArray, 0, ToJavaString(env, uks.first));
env->SetObjectArrayElement(resultArray, 1, ToJavaString(env, uks.second.first));
env->SetObjectArrayElement(resultArray, 2, ToJavaString(env, uks.second.second));
return resultArray;
}
} // namespace
extern "C"
{
JNIEXPORT jobjectArray JNICALL
Java_com_mapswithme_maps_editor_OsmOAuth_nativeAuthWithPassword(JNIEnv * env, jclass clazz,
jstring login, jstring password)
{
OsmOAuth auth = OsmOAuth::ServerAuth();
try
{
if (auth.AuthorizePassword(ToNativeString(env, login), ToNativeString(env, password)))
return ToStringArray(env, auth.GetKeySecret());
LOG(LWARNING, ("nativeAuthWithPassword: invalid login or password."));
}
catch (exception const & ex)
{
LOG(LWARNING, ("nativeAuthWithPassword error ", ex.what()));
}
return nullptr;
}
JNIEXPORT jobjectArray JNICALL
Java_com_mapswithme_maps_editor_OsmOAuth_nativeAuthWithWebviewToken(JNIEnv * env, jclass clazz,
jstring key, jstring secret, jstring verifier)
{
try
{
TRequestToken const rt = { ToNativeString(env, key), ToNativeString(env, secret) };
OsmOAuth auth = OsmOAuth::ServerAuth();
TKeySecret const ks = auth.FinishAuthorization(rt, ToNativeString(env, verifier));
return ToStringArray(env, ks);
}
catch (exception const & ex)
{
LOG(LWARNING, ("nativeAuthWithWebviewToken error ", ex.what()));
return nullptr;
}
}
JNIEXPORT jobjectArray JNICALL
Java_com_mapswithme_maps_editor_OsmOAuth_nativeGetFacebookAuthUrl(JNIEnv * env, jclass clazz)
{
try
{
OsmOAuth::TUrlRequestToken const uks = OsmOAuth::ServerAuth().GetFacebookOAuthURL();
return ToStringArray(env, uks);
}
catch (exception const & ex)
{
LOG(LWARNING, ("nativeGetFacebookAuthUrl error ", ex.what()));
return nullptr;
}
}
JNIEXPORT jobjectArray JNICALL
Java_com_mapswithme_maps_editor_OsmOAuth_nativeGetGoogleAuthUrl(JNIEnv * env, jclass clazz)
{
try
{
OsmOAuth::TUrlRequestToken const uks = OsmOAuth::ServerAuth().GetGoogleOAuthURL();
return ToStringArray(env, uks);
}
catch (exception const & ex)
{
LOG(LWARNING, ("nativeGetGoogleAuthUrl error ", ex.what()));
return nullptr;
}
}
} // extern "C"

View file

@ -8,15 +8,15 @@ extern "C"
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_settings_UnitLocale_setCurrentUnits(JNIEnv * env, jobject thiz, jint units)
{
Settings::Units const u = static_cast<Settings::Units>(units);
Settings::Set("Units", u);
settings::Units const u = static_cast<settings::Units>(units);
settings::Set(settings::kMeasurementUnits, u);
g_framework->SetupMeasurementSystem();
}
JNIEXPORT jint JNICALL
Java_com_mapswithme_maps_settings_UnitLocale_getCurrentUnits(JNIEnv * env, jobject thiz)
{
Settings::Units u = Settings::Metric;
return (Settings::Get("Units", u) ? u : -1);
settings::Units u;
return (settings::Get(settings::kMeasurementUnits, u) ? u : -1);
}
}

View file

@ -70,7 +70,7 @@ string GetEglError(EGLint error)
}
}
} // namespace
} // namespace
void CheckEGL(my::SrcPoint const & src)
{
@ -82,4 +82,4 @@ void CheckEGL(my::SrcPoint const & src)
}
}
} // namespace android
} // namespace android

View file

@ -26,5 +26,5 @@ void CheckEGL(my::SrcPoint const & src);
#define CHECK_EGL(x) do { (x); CheckEGL(SRC());} while(false);
#define CHECK_EGL_CALL() do { CheckEGL(SRC());} while (false);
} // namespace android
} // namespace android

View file

@ -84,4 +84,4 @@ void AndroidOGLContext::resetSurface()
m_surface = EGL_NO_SURFACE;
}
} // namespace android
} // namespace android

View file

@ -36,4 +36,4 @@ private:
// @}
};
} // namespace android
} // namespace android

View file

@ -291,4 +291,4 @@ bool AndroidOGLContextFactory::createPixelbufferSurface()
return true;
}
} // namespace android
} // namespace android

View file

@ -50,4 +50,4 @@ private:
bool m_windowSurfaceValid;
};
} // namespace android
} // namespace android

View file

@ -21,7 +21,7 @@ public:
JNIEnv * env = jni::GetEnv();
ASSERT ( env, () );
jclass klass = env->FindClass("com/mapswithme/maps/downloader/DownloadChunkTask");
jclass klass = env->FindClass("com/mapswithme/maps/downloader/ChunkTask");
ASSERT ( klass, () );
static jmethodID initMethodId = env->GetMethodID(klass, "<init>", "(JLjava/lang/String;JJJ[BLjava/lang/String;)V");
@ -70,7 +70,7 @@ public:
JNIEnv * env = jni::GetEnv();
ASSERT ( env, () );
jmethodID methodId = jni::GetJavaMethodID(env, m_self, "cancel", "(Z)Z");
jmethodID methodId = jni::GetMethodID(env, m_self, "cancel", "(Z)Z");
ASSERT ( methodId, () );
env->CallBooleanMethod(m_self, methodId, false);
@ -96,13 +96,12 @@ namespace downloader
delete request;
}
} // namespace downloader
} // namespace downloader
extern "C"
{
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_maps_downloader_DownloadChunkTask_onWrite(JNIEnv * env, jobject thiz,
jlong httpCallbackID, jlong beg, jbyteArray data, jlong size)
Java_com_mapswithme_maps_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);
@ -114,8 +113,7 @@ extern "C"
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_downloader_DownloadChunkTask_onFinish(JNIEnv * env, jobject thiz,
jlong httpCallbackID, jlong httpCode, jlong beg, jlong end)
Java_com_mapswithme_maps_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(httpCode, beg, end);

View file

@ -33,34 +33,16 @@ string GetAndroidSystemLanguage()
return DEFAULT_LANG;
}
jclass localeClass = env->FindClass("java/util/Locale");
ASSERT(localeClass, ());
jmethodID localeGetDefaultId = env->GetStaticMethodID(localeClass, "getDefault", "()Ljava/util/Locale;");
static jclass const localeClass = jni::GetGlobalClassRef(env, "java/util/Locale");
static jmethodID const localeGetDefaultId = env->GetStaticMethodID(localeClass, "getDefault", "()Ljava/util/Locale;");
ASSERT(localeGetDefaultId, ());
static jmethodID const localeToStringId = env->GetMethodID(localeClass, "toString", "()Ljava/lang/String;");
ASSERT(localeToStringId, ());
jobject localeInstance = env->CallStaticObjectMethod(localeClass, localeGetDefaultId);
ASSERT(localeInstance, ());
jni::TScopedLocalRef localeInstance(env, env->CallStaticObjectMethod(localeClass, localeGetDefaultId));
jni::TScopedLocalRef langString(env, env->CallObjectMethod(localeInstance.get(), localeToStringId));
jmethodID localeGetLanguageId = env->GetMethodID(localeClass, "toString", "()Ljava/lang/String;");
ASSERT(localeGetLanguageId, ());
jstring langString = (jstring)env->CallObjectMethod(localeInstance, localeGetLanguageId);
ASSERT(langString, ());
// TODO FindClass method won't work from non-ui threads, so cache class, remove comment or use cached classloader after it's implemented
/*
jclass langClass = env->FindClass("com/mapswithme/util/Language");
ASSERT(langClass, ());
jmethodID langGetDefaultId = env->GetStaticMethodID(langClass, "getDefault", "()Ljava/lang/String;");
ASSERT(langGetDefaultId, ());
jstring langString = (jstring)env->CallStaticObjectMethod(langClass, langGetDefaultId);
ASSERT(langString, ());
*/
string res = jni::ToNativeString(env, langString);
string res = jni::ToNativeString(env, (jstring) langString.get());
if (res.empty())
res = DEFAULT_LANG;

View file

@ -1,38 +0,0 @@
#include "MethodRef.hpp"
#include <base/assert.hpp>
#include <base/logging.hpp>
MethodRef::MethodRef(char const * name, char const * signature)
: m_name(name)
, m_signature(signature)
, m_methodID(nullptr)
, m_object(nullptr)
{
LOG(LDEBUG, ("Name = ", name));
}
MethodRef::~MethodRef()
{
if (m_object != nullptr)
jni::GetEnv()->DeleteGlobalRef(m_object);
}
void MethodRef::Init(jobject obj)
{
JNIEnv * env = jni::GetEnv();
m_object = env->NewGlobalRef(obj);
jclass const k = env->GetObjectClass(m_object);
m_methodID = env->GetMethodID(k, m_name, m_signature);
ASSERT(m_object != nullptr, ());
ASSERT(m_methodID != nullptr, ());
}
void MethodRef::CallVoid(jlong arg)
{
JNIEnv * jniEnv = jni::GetEnv();
ASSERT(jniEnv != nullptr, ());
ASSERT(m_object != nullptr, ());
ASSERT(m_methodID != nullptr, ());
jniEnv->CallVoidMethod(m_object, m_methodID, arg);
}

View file

@ -1,19 +0,0 @@
#pragma once
#include "../core/jni_helper.hpp"
class MethodRef
{
public:
MethodRef(char const * name, char const * signature);
~MethodRef();
void Init(jobject obj);
void CallVoid(jlong arg);
private:
char const * m_name;
char const * m_signature;
jmethodID m_methodID;
jobject m_object;
};

View file

@ -13,7 +13,7 @@
string Platform::UniqueClientId() const
{
string res;
if (!Settings::Get("UniqueClientID", res))
if (!settings::Get("UniqueClientID", res))
{
JNIEnv * env = jni::GetEnv();
if (!env)
@ -44,7 +44,7 @@ string Platform::UniqueClientId() const
res = HashUniqueID(res);
Settings::Set("UniqueClientID", res);
settings::Set("UniqueClientID", res);
}
return res;
@ -59,10 +59,10 @@ string Platform::GetMemoryInfo() const
static shared_ptr<jobject> classMemLogging = jni::make_global_ref(env->FindClass("com/mapswithme/util/log/MemLogging"));
ASSERT(classMemLogging, ());
static jmethodID const getMemoryInfoId = env->GetStaticMethodID(static_cast<jclass>(*classMemLogging.get()), "getMemoryInfo", "()Ljava/lang/String;");
static jmethodID const getMemoryInfoId = env->GetStaticMethodID(static_cast<jclass>(*classMemLogging), "getMemoryInfo", "()Ljava/lang/String;");
ASSERT(getMemoryInfoId, ());
jstring const memInfoString = (jstring)env->CallStaticObjectMethod(static_cast<jclass>(*classMemLogging.get()), getMemoryInfoId);
jstring const memInfoString = (jstring)env->CallStaticObjectMethod(static_cast<jclass>(*classMemLogging), getMemoryInfoId);
ASSERT(memInfoString, ());
return jni::ToNativeString(env, memInfoString);
@ -82,25 +82,25 @@ Platform::EConnectionType Platform::ConnectionStatus()
static shared_ptr<jobject> clazzConnectionState = jni::make_global_ref(env->FindClass("com/mapswithme/util/ConnectionState"));
ASSERT(clazzConnectionState, ());
static jmethodID const getConnectionMethodId = env->GetStaticMethodID(static_cast<jclass>(*clazzConnectionState.get()), "getConnectionState", "()B");
static jmethodID const getConnectionMethodId = env->GetStaticMethodID(static_cast<jclass>(*clazzConnectionState), "getConnectionState", "()B");
ASSERT(getConnectionMethodId, ());
return static_cast<Platform::EConnectionType>(env->CallStaticByteMethod(static_cast<jclass>(*clazzConnectionState.get()), getConnectionMethodId));
return static_cast<Platform::EConnectionType>(env->CallStaticByteMethod(static_cast<jclass>(*clazzConnectionState), getConnectionMethodId));
}
namespace android
{
Platform::Platform()
: m_runOnUI("runNativeFunctorOnUiThread", "(J)V")
{
}
void Platform::Initialize(JNIEnv * env,
jobject functorProcessObject,
jstring apkPath, jstring storagePath,
jstring tmpPath, jstring obbGooglePath,
jstring flavorName, jstring buildType,
bool isYota, bool isTablet)
{
m_functorProcessObject = env->NewGlobalRef(functorProcessObject);
jclass const functorProcessClass = env->GetObjectClass(functorProcessObject);
m_functorProcessMethod = env->GetMethodID(functorProcessClass, "forwardToMainThread", "(J)V");
string const flavor = jni::ToNativeString(env, flavorName);
string const build = jni::ToNativeString(env, buildType);
LOG(LINFO, ("Flavor name:", flavor));
@ -121,7 +121,7 @@ namespace android
m_settingsDir = jni::ToNativeString(env, storagePath);
m_tmpDir = jni::ToNativeString(env, tmpPath);
if (!Settings::Get("StoragePath", m_writableDir) || !HasAvailableSpaceForWriting(1024))
if (!settings::Get("StoragePath", m_writableDir) || !HasAvailableSpaceForWriting(1024))
{
LOG(LINFO, ("Could not read writable dir. Use primary storage."));
m_writableDir = m_settingsDir;
@ -145,12 +145,7 @@ namespace android
(void) ConnectionStatus();
}
void Platform::InitAppMethodRefs(jobject appObject)
{
m_runOnUI.Init(appObject);
}
void Platform::CallNativeFunctor(jlong functionPointer)
void Platform::ProcessFunctor(jlong functionPointer)
{
TFunctor * fn = reinterpret_cast<TFunctor *>(functionPointer);
(*fn)();
@ -175,7 +170,7 @@ namespace android
void Platform::SetStoragePath(string const & path)
{
m_writableDir = path;
Settings::Set("StoragePath", m_writableDir);
settings::Set("StoragePath", m_writableDir);
}
bool Platform::HasAvailableSpaceForWriting(uint64_t size) const
@ -191,7 +186,9 @@ namespace android
void Platform::RunOnGuiThread(TFunctor const & fn)
{
m_runOnUI.CallVoid(reinterpret_cast<jlong>(new TFunctor(fn)));
// Pointer will be deleted in Platform::ProcessFunctor
TFunctor * functor = new TFunctor(fn);
jni::GetEnv()->CallVoidMethod(m_functorProcessObject, m_functorProcessMethod, reinterpret_cast<jlong>(functor));
}
}

View file

@ -2,8 +2,6 @@
#include <jni.h>
#include "MethodRef.hpp"
#include "platform/platform.hpp"
namespace android
@ -11,15 +9,14 @@ namespace android
class Platform : public ::Platform
{
public:
Platform();
void Initialize(JNIEnv * env,
jobject functorProcessObject,
jstring apkPath, jstring storagePath,
jstring tmpPath, jstring obbGooglePath,
jstring flavorName, jstring buildType,
bool isYota, bool isTablet);
void InitAppMethodRefs(jobject appObject);
void CallNativeFunctor(jlong functionPointer);
void ProcessFunctor(jlong functionPointer);
void OnExternalStorageStatusChanged(bool isAvailable);
@ -34,6 +31,7 @@ namespace android
static Platform & Instance();
private:
MethodRef m_runOnUI;
jobject m_functorProcessObject;
jmethodID m_functorProcessMethod;
};
}

View file

@ -8,7 +8,7 @@ extern "C"
Java_com_mapswithme_util_Config_nativeGetBoolean(JNIEnv * env, jclass thiz, jstring name, jboolean defaultVal)
{
bool val;
if (Settings::Get(jni::ToNativeString(env, name), val))
if (settings::Get(jni::ToNativeString(env, name), val))
return static_cast<jboolean>(val);
return defaultVal;
@ -17,14 +17,14 @@ extern "C"
JNIEXPORT void JNICALL
Java_com_mapswithme_util_Config_nativeSetBoolean(JNIEnv * env, jclass thiz, jstring name, jboolean val)
{
(void)Settings::Set(jni::ToNativeString(env, name), static_cast<bool>(val));
(void)settings::Set(jni::ToNativeString(env, name), static_cast<bool>(val));
}
JNIEXPORT jint JNICALL
Java_com_mapswithme_util_Config_nativeGetInt(JNIEnv * env, jclass thiz, jstring name, jint defaultValue)
{
int32_t value;
if (Settings::Get(jni::ToNativeString(env, name), value))
if (settings::Get(jni::ToNativeString(env, name), value))
return static_cast<jint>(value);
return defaultValue;
@ -33,14 +33,14 @@ extern "C"
JNIEXPORT void JNICALL
Java_com_mapswithme_util_Config_nativeSetInt(JNIEnv * env, jclass thiz, jstring name, jint value)
{
(void)Settings::Set(jni::ToNativeString(env, name), static_cast<int32_t>(value));
(void)settings::Set(jni::ToNativeString(env, name), static_cast<int32_t>(value));
}
JNIEXPORT jlong JNICALL
Java_com_mapswithme_util_Config_nativeGetLong(JNIEnv * env, jclass thiz, jstring name, jlong defaultValue)
{
int64_t value;
if (Settings::Get(jni::ToNativeString(env, name), value))
if (settings::Get(jni::ToNativeString(env, name), value))
return static_cast<jlong>(value);
return defaultValue;
@ -49,14 +49,14 @@ extern "C"
JNIEXPORT void JNICALL
Java_com_mapswithme_util_Config_nativeSetLong(JNIEnv * env, jclass thiz, jstring name, jlong value)
{
(void)Settings::Set(jni::ToNativeString(env, name), static_cast<int64_t>(value));
(void)settings::Set(jni::ToNativeString(env, name), static_cast<int64_t>(value));
}
JNIEXPORT jdouble JNICALL
Java_com_mapswithme_util_Config_nativeGetDouble(JNIEnv * env, jclass thiz, jstring name, jdouble defaultValue)
{
double value;
if (Settings::Get(jni::ToNativeString(env, name), value))
if (settings::Get(jni::ToNativeString(env, name), value))
return static_cast<jdouble>(value);
return defaultValue;
@ -65,14 +65,14 @@ extern "C"
JNIEXPORT void JNICALL
Java_com_mapswithme_util_Config_nativeSetDouble(JNIEnv * env, jclass thiz, jstring name, jdouble value)
{
(void)Settings::Set(jni::ToNativeString(env, name), static_cast<double>(value));
(void)settings::Set(jni::ToNativeString(env, name), static_cast<double>(value));
}
JNIEXPORT jstring JNICALL
Java_com_mapswithme_util_Config_nativeGetString(JNIEnv * env, jclass thiz, jstring name, jstring defaultValue)
{
string value;
if (Settings::Get(jni::ToNativeString(env, name), value))
if (settings::Get(jni::ToNativeString(env, name), value))
return jni::ToJavaString(env, value);
return defaultValue;
@ -81,6 +81,6 @@ extern "C"
JNIEXPORT void JNICALL
Java_com_mapswithme_util_Config_nativeSetString(JNIEnv * env, jclass thiz, jstring name, jstring value)
{
(void)Settings::Set(jni::ToNativeString(env, name), jni::ToNativeString(env, value));
(void)settings::Set(jni::ToNativeString(env, name), jni::ToNativeString(env, value));
}
} // extern "C"

View file

@ -1,12 +1,39 @@
#include "base/string_utils.hpp"
#include "../core/jni_helper.hpp"
#include "com/mapswithme/core/jni_helper.hpp"
#include "indexer/search_string_utils.hpp"
extern "C"
{
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_util_StringUtils_isHtml(JNIEnv * env, jclass thiz, jstring text)
Java_com_mapswithme_util_StringUtils_nativeIsHtml(JNIEnv * env, jclass thiz, jstring text)
{
return strings::IsHTML(jni::ToNativeString(env, text));
}
JNIEXPORT jboolean JNICALL
Java_com_mapswithme_util_StringUtils_nativeContainsNormalized(JNIEnv * env, jclass thiz, jstring str, jstring substr)
{
return search::ContainsNormalized(jni::ToNativeString(env, str), jni::ToNativeString(env, substr));
}
JNIEXPORT jobjectArray JNICALL
Java_com_mapswithme_util_StringUtils_nativeFilterContainsNormalized(JNIEnv * env, jclass thiz, jobjectArray src, jstring jSubstr)
{
string substr = jni::ToNativeString(env, jSubstr);
int const length = env->GetArrayLength(src);
vector<string> filtered;
filtered.reserve(length);
for (int i = 0; i < length; i++)
{
string str = jni::ToNativeString(env, (jstring) env->GetObjectArrayElement(src, i));
if (search::ContainsNormalized(str, substr))
filtered.push_back(str);
}
jobjectArray result = env->NewObjectArray(filtered.size(), jni::GetStringClass(env), nullptr);
for (int i = 0; i < filtered.size(); i++)
env->SetObjectArrayElement(result, i, jni::TScopedLocalRef(env, jni::ToJavaString(env, filtered[i])));
return result;
}
} // extern "C"

View file

@ -33,4 +33,8 @@
-keepclassmembers class * implements com.mapswithme.util.Gsonable {
<init>(...);
}
}
# HockeyApp
-dontwarn net.hockeyapp.android.UpdateActivity
-dontwarn net.hockeyapp.android.UpdateFragment

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/button_normal"
android:state_enabled="true"/>
<item android:color="@color/button_disabled"/>
</selector>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/button_accent_normal"
android:state_enabled="true"/>
<item android:color="@color/button_accent_disabled"/>
</selector>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/button_accent_normal_night"
android:state_enabled="true"/>
<item android:color="@color/button_accent_disabled_night"/>
</selector>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/button_normal_night"
android:state_enabled="true"/>
<item android:color="@color/button_disabled_night"/>
</selector>

View file

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/routing_start"
android:state_enabled="true"/>
<item android:color="@color/routing_start_disabled"/>
</selector>

View file

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/routing_start_night"
android:state_enabled="true"/>
<item android:color="@color/routing_start_disabled_night"/>
</selector>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:color="@color/base_accent"
android:state_selected="true"/>
<item
android:color="@color/text_dark_subtitle"/>
</selector>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:color="@color/base_accent_pressed"
android:state_selected="true"/>
<item
android:color="@color/base_accent"/>
</selector>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:color="@android:color/white"
android:state_enabled="true"/>
<item
android:color="@color/text_editor_add_disabled"/>
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 806 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 B

After

Width:  |  Height:  |  Size: 253 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 B

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