Compare commits

...
Sign in to create a new pull request.

13 commits

Author SHA1 Message Date
879daa0ef0 Rehydrate
Signed-off-by: Roman Tsisyk <roman@tsisyk.com>
2024-08-03 09:05:50 +01:00
pratikshyachand
464cff7c02 Update README.md
Signed-off-by: pratikshyachand <131480787+pratikshyachand@users.noreply.github.com>
2024-05-04 10:46:19 +02:00
bbcf902d5c Update readme
Signed-off-by: Jean-BaptisteC <jeanbaptiste.charron@outlook.fr>
2024-01-06 09:43:18 +01:00
619243f528 Update Gradle plugin
Signed-off-by: Roman Tsisyk <roman@tsisyk.com>
2023-11-14 12:44:01 +02:00
ac6f13ecf9 Rehydrate
Signed-off-by: Roman Tsisyk <roman@tsisyk.com>
2023-11-12 19:47:00 +02:00
moving-bits
5cca3797ec Add isOrganicMapsPackageInstalled() 2023-08-16 22:17:43 +02:00
moving-bits
9113776e22 Remove outdated package query name 2023-08-16 22:17:43 +02:00
moving-bits
1619b32afb Switch installation check to intent resolution 2023-08-16 22:17:43 +02:00
moving-bits
f3a87782f0 Add basic API methods showPoint(s)OnMap 2023-08-16 22:17:43 +02:00
363d7f07d9 Rehydrate
Signed-off-by: Roman Tsisyk <roman@tsisyk.com>
2023-03-24 10:40:18 +02:00
Hélène Martin
dcd09663de Connect this library to deep link functionality 2022-10-09 11:13:26 +03:00
Alexander Borsuk
dff6e1decd Minor consistency fixes 2022-07-26 10:02:17 +03:00
7774cbb246 New API 2022-07-26 10:02:17 +03:00
42 changed files with 822 additions and 548 deletions

View file

@ -14,6 +14,8 @@ using Organic Maps to show points of interest (POI) and providing more informati
Please refer to [sample application][linkSampleSource] for demo.
**Note**: this library provides convenience wrappers for [deep links](https://omaps.app/api). Your application can also use deep links directly without including the library as a dependency. You can look at the library implementation for ideas on how to do that.
## Prerequisites
It is supposed that you are familiar with Android Development.
@ -30,9 +32,8 @@ You don't need any additional permissions in your AndroidManifest.xml to use API
## Classes Overview and HOW TO
Core classes you will work with are:
* [app.organicmaps.api.Api][linkApiClass] - static class with methods such as `showPointOnMap(Activity, double, double, String)` etc.
* [app.organicmaps.api.Point][linkPointClass] - model of POI, includes lat, lon, name, id, and style data.
* [app.organicmaps.api.Response][linkRespClass] - helps you to extract response from Organic Maps by applying `Response.extractFromIntent(Intent)` to Intent. Contains Point data.
* [app.organicmaps.api.PickPointResponse][linkRespClass] - helps you to extract response from Organic Maps by applying `Response.extractFromIntent(Intent)` to Intent. Contains Point data.
### Show Points on the Map
@ -74,7 +75,7 @@ For multiple points use [Point][linkPointClass] class:
We support PendingIntent interaction (just like Android native
NotificationManager does). You should specify ID for each point to
distinguish it later, and PentingIntent that Organic Maps will send back to
distinguish it later, and PendingIntent that Organic Maps will send back to
your application when user press "More Info" button :
// Here is how to pass points with ID ant PendingIntent
@ -124,13 +125,12 @@ your application when user press "More Info" button :
## FAQ
#### How should I detect if user has Organic Maps installed?
`Api.isOrganicMapsInstalled(Context)` will return `true` if user has *Lite* or *Pro* version that supports API call installed.
#### Which versions of Organic Maps support API calls?
All versions since 2.4.0 and above support API calls.
All versions since 2022-07-26 and above support API calls.
#### What will happen if I call for `Api.showPoint()` but Organic Maps application is not installed?
Nothing serious. API library will show simple dialog with gentle offer to download Organic Maps. You can see how it looks like below.
![Please install us](site/images/dlg.png)
@ -142,9 +142,12 @@ Nothing serious. API library will show simple dialog with gentle offer to downlo
-------------------------------------------------------------------------------
## API Code License
Copyright (c) 2022, Organic Maps OÜ.
Copyright (c) 2024, Organic Maps OÜ.
Copyright (c) 2019, MY.COM B.V.
Copyright (c) 2013, MapsWithMe GmbH.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
@ -155,11 +158,11 @@ Redistribution and use in source and binary forms, with or without modification,
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[linkOM]: https://organicmaps.app/ "Organic Maps"
[linkPIntent]: http://developer.android.com/reference/android/app/PendingIntent.html "PendingIntent"
[linkPIntent]: https://developer.android.com/reference/android/app/PendingIntent.html "PendingIntent"
[linkRepo]: https://github.com/organicmaps/api-android "GitHub Repository"
[linkLibProj]: http://developer.android.com/tools/projects/index.html#LibraryProjects "Android Library Project"
[linkIntents]: http://developer.android.com/guide/components/intents-filters.html "Intents and Intent Filters"
[linkApiClass]: lib/src/app/organicmaps/api/Api.java "Api.java"
[linkPointClass]: lib/src/app/organicmaps/api/Point.java "Point.java"
[linkRespClass]: lib/src/app/organicmaps/api/Response.java "Response.java"
[linkLibProj]: https://developer.android.com/tools/projects/index.html#LibraryProjects "Android Library Project"
[linkIntents]: https://developer.android.com/guide/components/intents-filters.html "Intents and Intent Filters"
[linkApiClass]: lib/src/main/java/app/organicmaps/api/OrganicMapsApi.java "OrganicMapsApi.java"
[linkPointClass]: lib/src/main/java/app/organicmaps/api/Point.java "Point.java"
[linkRespClass]: lib/src/main/java/app/organicmaps/api/PickPointResponse.java "PickPointResponse.java"
[linkSampleSource]: https://github.com/organicmaps/api-android/tree/master/sample-app-capitals "Api Source Code"

View file

@ -1,9 +1,15 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '7.2.1' apply false
id 'com.android.library' version '7.2.1' apply false
id 'com.android.application' version '8.5.1' apply false
id 'com.android.library' version '8.5.1' apply false
}
project.ext {
minSdkVersion = 21
targetSdkVersion = 34
javaVersion = JavaVersion.VERSION_11
}
task clean(type: Delete) {
delete rootProject.buildDir
}
}

View file

@ -1,6 +1,5 @@
#Mon Jun 06 09:48:49 TRT 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View file

@ -3,13 +3,13 @@ plugins {
}
android {
compileSdk 32
namespace 'app.organicmaps.api'
compileSdk project.targetSdkVersion
defaultConfig {
minSdk 21
targetSdk 32
minSdk project.minSdkVersion
targetSdk project.targetSdkVersion
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
@ -20,13 +20,16 @@ android {
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility project.javaVersion
targetCompatibility project.javaVersion
}
}
dependencies {
tasks.withType(JavaCompile) {
options.compilerArgs << '-Xlint:unchecked' << '-Xlint:deprecation'
}
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'com.google.android.material:material:1.6.1'
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.7.0'
implementation 'com.google.android.material:material:1.12.0'
}

View file

@ -1,8 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="app.organicmaps.api"
xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<queries>
<!-- packages we want to see using the package manager need to be declared starting with targetSDK 30, and we need to use specific strings / cannot use @string/xxx notation -->
<package android:name="app.organicmaps"/>
<package android:name="com.mapswithme.maps"/>
</queries>
</manifest>

View file

@ -1,154 +0,0 @@
/******************************************************************************
Copyright (c) 2022, Organic Maps . All rights reserved.
Copyright (c) 2013, MapsWithMe GmbH. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer. Redistributions in binary form must
reproduce the above copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided with the
distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
******************************************************************************/
package app.organicmaps.api;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
public final class Api
{
/**
* Most detailed level, buildings and trees are seen.
*/
public static final double ZOOM_MAX = 19;
/**
* Least detailed level, continents are seen.
*/
public static final double ZOOM_MIN = 1;
public static void showOrganicMapsUrl(Activity caller, PendingIntent pendingIntent, double zoomLevel, String url)
{
final Uri uri = Uri.parse(url);
final String[] latlon = uri.getQueryParameter("ll").split(",");
final double lat = Double.parseDouble(latlon[0]);
final double lon = Double.parseDouble(latlon[1]);
final String name = uri.getQueryParameter("n");
final String id = uri.getQueryParameter("id");
showPointsOnMap(caller, name, zoomLevel, pendingIntent, new Point(lat, lon, name, id));
}
public static void sendRequest(Activity caller, Request request)
{
final Intent mwmIntent = request.toIntent(caller);
if (isOrganicMapsInstalled(caller))
{
caller.startActivity(mwmIntent);
}
else
(new DownloadDialog(caller)).show();
}
/**
* Shows single point on the map.
*
* @param caller
* @param lat
* @param lon
* @param name
*/
public static void showPointOnMap(Activity caller, double lat, double lon, String name)
{
showPointsOnMap(caller, null, (PendingIntent) null, new Point(lat, lon, name));
}
/**
* Shows single point on the map using specified zoom level in range from
* {@link Api#ZOOM_MIN} to {@link Api#ZOOM_MAX}.
*
* @param caller
* @param lat
* @param lon
* @param name
* @param zoomLevel
*/
public static void showPointOnMap(Activity caller, double lat, double lon, String name, double zoomLevel)
{
showPointsOnMap(caller, null, zoomLevel, null, new Point(lat, lon, name));
}
/**
* Shows set of points on the map.
*
* @param caller
* @param title
* @param points
*/
public static void showPointsOnMap(Activity caller, String title, Point... points)
{
showPointsOnMap(caller, title, null, points);
}
/**
* Shows set of points on the maps and allows OrganicMapsApplication to send
* {@link PendingIntent} provided by client application.
*
* @param caller
* @param title
* @param pendingIntent
* @param points
*/
public static void showPointsOnMap(Activity caller, String title, PendingIntent pendingIntent, Point... points)
{
showPointsOnMap(caller, title, -1, pendingIntent, points);
}
private static void showPointsOnMap(Activity caller, String title, double zoomLevel, PendingIntent pendingIntent,
Point... points)
{
final Request request = new Request()
.setTitle(title)
.setZoomLevel(zoomLevel)
.setPendingIntent(pendingIntent)
.setPoints(points);
sendRequest(caller, request);
}
public static void pickPoint(Activity caller, String title, PendingIntent pi)
{
final Request request = new Request()
.setTitle(title)
.setPickPointMode(true)
.setPendingIntent(pi);
sendRequest(caller, request);
}
/**
* Detects if Organic Maps is installed on the device.
*
* @param context
* @return
*/
public static boolean isOrganicMapsInstalled(Context context)
{
final Intent intent = new Intent(Const.ACTION_OM_REQUEST);
return context.getPackageManager().resolveActivity(intent, 0) != null;
}
}

View file

@ -1,6 +1,5 @@
/******************************************************************************
/*
Copyright (c) 2022, Organic Maps . All rights reserved.
Copyright (c) 2013, MapsWithMe GmbH. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
@ -20,37 +19,25 @@
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
******************************************************************************/
*/
package app.organicmaps.api;
public class Const
{
// Common
static final String API_SCHEME = "om://";
static final String AUTHORITY = "app.organicmaps.api";
static final String EXTRA_PREFIX = AUTHORITY + ".extra";
/* Request extras */
static final String AUTHORITY = "com.mapswithme.maps.api";
public static final String EXTRA_URL = AUTHORITY + ".url";
public static final String EXTRA_TITLE = AUTHORITY + ".title";
public static final String EXTRA_API_VERSION = AUTHORITY + ".version";
public static final String EXTRA_CALLER_APP_INFO = AUTHORITY + ".caller_app_info";
public static final String EXTRA_HAS_PENDING_INTENT = AUTHORITY + ".has_pen_intent";
public static final String EXTRA_CALLER_PENDING_INTENT = AUTHORITY + ".pending_intent";
public static final String EXTRA_RETURN_ON_BALLOON_CLICK = AUTHORITY + ".return_on_balloon_click";
public static final String EXTRA_PICK_POINT = AUTHORITY + ".pick_point";
public static final String EXTRA_CUSTOM_BUTTON_NAME = AUTHORITY + ".custom_button_name";
// Request extras
public static final String EXTRA_PICK_POINT = EXTRA_PREFIX + ".PICK_POINT";
/* Response extras */
/* Point part-by-part*/
public static final String EXTRA_OM_RESPONSE_POINT_NAME = AUTHORITY + ".point_name";
public static final String EXTRA_OM_RESPONSE_POINT_LAT = AUTHORITY + ".point_lat";
public static final String EXTRA_OM_RESPONSE_POINT_LON = AUTHORITY + ".point_lon";
public static final String EXTRA_OM_RESPONSE_POINT_ID = AUTHORITY + ".point_id";
public static final String EXTRA_OM_RESPONSE_ZOOM = AUTHORITY + ".zoom_level";
public static final String ACTION_OM_REQUEST = AUTHORITY + ".request";
static final int API_VERSION = 2;
static final String CALLBACK_PREFIX = "mapswithme.client.";
// Response extras
public static final String EXTRA_POINT_NAME = EXTRA_PREFIX + ".POINT_NAME";
public static final String EXTRA_POINT_LAT = EXTRA_PREFIX + ".POINT_LAT";
public static final String EXTRA_POINT_LON = EXTRA_PREFIX + ".POINT_LON";
public static final String EXTRA_POINT_ID = EXTRA_PREFIX + ".POINT_ID";
public static final String EXTRA_ZOOM_LEVEL = EXTRA_PREFIX + ".ZOOM_LEVEL";
private Const() {}
}

View file

@ -0,0 +1,55 @@
/*
Copyright (c) 2022, Organic Maps . All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer. Redistributions in binary form must
reproduce the above copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided with the
distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/
package app.organicmaps.api;
import android.content.Intent;
import android.net.Uri;
import androidx.annotation.NonNull;
public class CrosshairRequest
{
private String mAppName;
public CrosshairRequest setAppName(String appName)
{
mAppName = appName;
return this;
}
public @NonNull
Intent toIntent()
{
final StringBuilder builder = new StringBuilder(Const.API_SCHEME);
builder.append("crosshair?");
// title
if (mAppName != null)
builder.append("appname").append("=").append(Uri.encode(mAppName)).append("&");
final Uri uri = Uri.parse(builder.toString());
final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.putExtra(Const.EXTRA_PICK_POINT, true);
return intent;
}
}

View file

@ -1,4 +1,4 @@
/******************************************************************************
/*
Copyright (c) 2022, Organic Maps . All rights reserved.
Copyright (c) 2013, MapsWithMe GmbH. All rights reserved.
@ -20,7 +20,8 @@
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
******************************************************************************/
*/
package app.organicmaps.api;
import android.app.Activity;

View file

@ -0,0 +1,111 @@
/*
Copyright (c) 2022, Organic Maps . All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer. Redistributions in binary form must
reproduce the above copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided with the
distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/
package app.organicmaps.api;
import android.content.Intent;
import android.net.Uri;
import androidx.annotation.NonNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
public class MapRequest
{
private List<Point> mPoints = new ArrayList<>();
private String mAppName;
private double mZoomLevel;
// pick point mode
private boolean mPickPointMode;
public @NonNull MapRequest
setAppName(String appName)
{
mAppName = appName;
return this;
}
public @NonNull
MapRequest addPoint(Point point)
{
mPoints.add(point);
return this;
}
public @NonNull
MapRequest setPoints(Collection<Point> points)
{
mPoints = new ArrayList<>(points);
return this;
}
public @NonNull
MapRequest setZoomLevel(double zoomLevel)
{
mZoomLevel = zoomLevel;
return this;
}
public @NonNull MapRequest setPickPointMode(boolean pickPointMode)
{
mPickPointMode = pickPointMode;
return this;
}
public @NonNull
Intent toIntent()
{
final StringBuilder builder = new StringBuilder(Const.API_SCHEME);
builder.append("map?");
// title
if (mAppName != null)
builder.append("appname").append("=").append(Uri.encode(mAppName)).append("&");
// zoom
if (mZoomLevel != 0.0)
builder.append("z").append("=").append(mZoomLevel).append("&");
// points
for (final Point point : mPoints)
{
if (point != null)
{
builder.append("ll=").append(String.format(Locale.US, "%f,%f&", point.getLat(), point.getLon()));
if (point.getName() != null)
builder.append("n").append("=").append(Uri.encode(point.getName())).append("&");
if (point.getId() != null)
builder.append("id").append("=").append(Uri.encode(point.getId())).append("&");
if (point.getStyle() != null)
builder.append("s").append("=").append(Uri.encode(point.getStyle().getName())).append("&");
}
}
final Uri uri = Uri.parse(builder.toString());
final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
if (mPickPointMode)
intent.putExtra(Const.EXTRA_PICK_POINT, true);
return intent;
}
}

View file

@ -0,0 +1,60 @@
package app.organicmaps.api;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import java.util.ArrayList;
public class OrganicMapsApi {
static final String PACKAGE_NAME_RELEASE = "app.organicmaps";
static final String PACKAGE_NAME_DEBUG = "app.organicmaps.debug";
static final String PACKAGE_NAME_BETA = "app.organicmaps.beta";
private OrganicMapsApi() {
// utility class
}
public static void showPointOnMap(final Activity activity, final double lat, final double lon, final String name) {
final ArrayList<Point> points = new ArrayList<>(1);
points.add(new Point(lat, lon, name));
showPointsOnMap(activity, name, points);
}
public static void showPointsOnMap(final Activity activity, final String name, final ArrayList<Point> points) {
final Intent intent = new MapRequest()
.setPoints(points)
.setAppName(name)
.toIntent();
sendRequest(activity, intent);
};
public static void sendRequest(final Activity caller, final Intent intent) {
if (canHandleOrganicMapsIntents(caller)) {
caller.startActivity(intent);
} else {
new DownloadDialog(caller).show();
}
}
/**
* Detects if any handler for OrganicMaps intents is installed on the device
*/
public static boolean canHandleOrganicMapsIntents(final Context context) {
final ComponentName c = new MapRequest().toIntent().resolveActivity(context.getPackageManager());
return c != null;
}
/**
* Detects if one of the specific OrganicMaps packages is installed
*/
public static boolean isOrganicMapsPackageInstalled(final Context context) {
final PackageManager pm = context.getPackageManager();
return (pm.getLaunchIntentForPackage(PACKAGE_NAME_RELEASE) != null
|| pm.getLaunchIntentForPackage(PACKAGE_NAME_BETA) != null
|| pm.getLaunchIntentForPackage(PACKAGE_NAME_DEBUG) != null);
}
}

View file

@ -1,6 +1,5 @@
/******************************************************************************
/*
Copyright (c) 2022, Organic Maps . All rights reserved.
Copyright (c) 2013, MapsWithMe GmbH. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
@ -20,59 +19,57 @@
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
******************************************************************************/
*/
package app.organicmaps.api;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
public class Response
public class PickPointResponse
{
private final static double INVALID_LL = Double.MIN_VALUE;
private Point mPoint;
private double mZoomLevel;
private Response() {}
private PickPointResponse() {}
/**
* Factory method to extract response data from intent.
* Factory method to extract response from intent.
*
* @param context
* @param intent
* @return
* @param intent an intent to extra data from
* @return PointResponse
*/
public static Response extractFromIntent(Context context, Intent intent)
public static PickPointResponse extractFromIntent(final Intent intent)
{
final Response response = new Response();
// parse point
final double lat = intent.getDoubleExtra(Const.EXTRA_OM_RESPONSE_POINT_LAT, INVALID_LL);
final double lon = intent.getDoubleExtra(Const.EXTRA_OM_RESPONSE_POINT_LON, INVALID_LL);
final String name = intent.getStringExtra(Const.EXTRA_OM_RESPONSE_POINT_NAME);
final String id = intent.getStringExtra(Const.EXTRA_OM_RESPONSE_POINT_ID);
// parse additional info
response.mZoomLevel = intent.getDoubleExtra(Const.EXTRA_OM_RESPONSE_ZOOM, 9);
if (lat != INVALID_LL && lon != INVALID_LL)
response.mPoint = new Point(lat, lon, name, id);
else
response.mPoint = null;
final PickPointResponse response = new PickPointResponse();
final Bundle extras = intent.getExtras();
final double lat = extras.getDouble(Const.EXTRA_POINT_LAT);
final double lon = extras.getDouble(Const.EXTRA_POINT_LON);
final String name = extras.getString(Const.EXTRA_POINT_NAME);
final String id = extras.getString(Const.EXTRA_POINT_ID);
response.mPoint = new Point(lat, lon, name, id);
response.mZoomLevel = extras.getDouble(Const.EXTRA_ZOOM_LEVEL);
return response;
}
/**
* @return point, for which user requested more information in Organic Maps application.
* @return selected point
*/
public Point getPoint() {return mPoint;}
public Point getPoint()
{
return mPoint;
}
public boolean hasPoint() {return mPoint != null;}
public double getZoomLevel() {return mZoomLevel;}
/**
* @return current zoom level
*/
public double getZoomLevel()
{
return mZoomLevel;
}
@Override
public String toString()
{
return "Response [SelectedPoint=" + mPoint + "]";
return "PointResponse [Point=" + mPoint + "]";
}
}

View file

@ -1,4 +1,4 @@
/******************************************************************************
/*
Copyright (c) 2022, Organic Maps . All rights reserved.
Copyright (c) 2013, MapsWithMe GmbH. All rights reserved.
@ -20,10 +20,13 @@
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
******************************************************************************/
*/
package app.organicmaps.api;
import androidx.annotation.NonNull;
import java.io.Serializable;
import java.util.Objects;
/**
* POI wrapper object.
@ -53,15 +56,6 @@ public final class Point implements Serializable
this.mId = id;
}
public Point(double lat, double lon, String name, String id, Style style)
{
this.mLat = lat;
this.mLon = lon;
this.mName = name;
this.mId = id;
this.mStyle = style;
}
public double getLat() {return mLat;}
public double getLon() {return mLon;}
@ -74,7 +68,7 @@ public final class Point implements Serializable
* Sets string ID for this point. Internally it is not used to distinguish point,
* it's purpose to help clients code to associate point with domain objects of their application.
*
* @param id
* @param id point id
*/
public void setId(String id) {mId = id;}
@ -90,9 +84,8 @@ public final class Point implements Serializable
this.mStyle = style;
}
public String getStyleForUrl() {return (mStyle == null) ? null : mStyle.getName();}
@Override
@NonNull
public String toString()
{
return "OMPoint [lat=" + mLat +
@ -135,9 +128,10 @@ public final class Point implements Serializable
if (Double.doubleToLongBits(mLon) != Double.doubleToLongBits(other.mLon))
return false;
return mName == null ? other.mName == null : mName.equals(other.mName);
return Objects.equals(mName, other.mName);
}
/**
* Supported styles for Organic Maps. Each appears as a small flag of the appropriate colour.
*/
@ -171,7 +165,7 @@ public final class Point implements Serializable
/**
* @return name as it should appear in the MAPS.ME URL.
*/
private String getName()
public String getName()
{
return name;
}

View file

@ -1,194 +0,0 @@
/******************************************************************************
Copyright (c) 2022, Organic Maps . All rights reserved.
Copyright (c) 2013, MapsWithMe GmbH. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer. Redistributions in binary form must
reproduce the above copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided with the
distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
******************************************************************************/
package app.organicmaps.api;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
public class Request
{
// **
private List<Point> mPoints = new ArrayList<>();
private PendingIntent mPendingIntent;
private String mTitle;
private double mZoomLevel = 1;
private boolean mReturnOnBalloonClick;
private boolean mPickPoint = false;
private String mCustomButtonName = "";
// **
private static StringBuilder createMwmUrl(Context context, String title, double zoomLevel, List<Point> points)
{
final StringBuilder urlBuilder = new StringBuilder("om://map?");
// version
urlBuilder.append("v=").append(Const.API_VERSION).append("&");
// back url, always not null
urlBuilder.append("backurl=").append(getCallbackAction(context)).append("&");
// title
appendIfNotNull(urlBuilder, "appname", title);
// zoom
appendIfNotNull(urlBuilder, "z", isValidZoomLevel(zoomLevel) ? String.valueOf(zoomLevel) : null);
// points
for (final Point point : points)
{
if (point != null)
{
urlBuilder.append("ll=").append(String.format(Locale.US, "%f,%f&", point.getLat(), point.getLon()));
appendIfNotNull(urlBuilder, "n", point.getName());
appendIfNotNull(urlBuilder, "id", point.getId());
appendIfNotNull(urlBuilder, "s", point.getStyleForUrl());
}
}
return urlBuilder;
}
private static String getCallbackAction(Context context)
{
return Const.CALLBACK_PREFIX + context.getPackageName();
}
private static Intent addCommonExtras(Context context, Intent intent)
{
intent.putExtra(Const.EXTRA_CALLER_APP_INFO, context.getApplicationInfo());
intent.putExtra(Const.EXTRA_API_VERSION, Const.API_VERSION);
return intent;
}
private static StringBuilder appendIfNotNull(StringBuilder builder, String key, String value)
{
if (value != null)
builder.append(key).append("=").append(Uri.encode(value)).append("&");
return builder;
}
private static boolean isValidZoomLevel(double zoom)
{
return zoom >= Api.ZOOM_MIN && zoom <= Api.ZOOM_MAX;
}
public Request setCustomButtonName(String buttonName)
{
mCustomButtonName = buttonName != null ? buttonName : "";
return this;
}
public Request setTitle(String title)
{
mTitle = title;
return this;
}
public Request setPickPointMode(boolean pickPoint)
{
mPickPoint = pickPoint;
return this;
}
public Request addPoint(Point point)
{
mPoints.add(point);
return this;
}
public Request addPoint(double lat, double lon, String name, String id)
{
return addPoint(new Point(lat, lon, name, id));
}
public Request setPoints(Collection<Point> points)
{
mPoints = new ArrayList<Point>(points);
return this;
}
// Below are utilities from OrganicMapsApi because we are not "Feature Envy"
public Request setReturnOnBalloonClick(boolean doReturn)
{
mReturnOnBalloonClick = doReturn;
return this;
}
public Request setZoomLevel(double zoomLevel)
{
mZoomLevel = zoomLevel;
return this;
}
public Request setPendingIntent(PendingIntent pi)
{
mPendingIntent = pi;
return this;
}
public Intent toIntent(Context context)
{
final Intent mwmIntent = new Intent(Const.ACTION_OM_REQUEST);
// url
final String mwmUrl = createMwmUrl(context, mTitle, mZoomLevel, mPoints).toString();
mwmIntent.putExtra(Const.EXTRA_URL, mwmUrl);
// title
mwmIntent.putExtra(Const.EXTRA_TITLE, mTitle);
// more
mwmIntent.putExtra(Const.EXTRA_RETURN_ON_BALLOON_CLICK, mReturnOnBalloonClick);
// pick point
mwmIntent.putExtra(Const.EXTRA_PICK_POINT, mPickPoint);
// custom button name
mwmIntent.putExtra(Const.EXTRA_CUSTOM_BUTTON_NAME, mCustomButtonName);
final boolean hasIntent = mPendingIntent != null;
mwmIntent.putExtra(Const.EXTRA_HAS_PENDING_INTENT, hasIntent);
if (hasIntent)
mwmIntent.putExtra(Const.EXTRA_CALLER_PENDING_INTENT, mPendingIntent);
addCommonExtras(context, mwmIntent);
return mwmIntent;
}
/**
* @Hidden This method is internal only.
* Used for compatibility.
*/
Request setPoints(Point[] points)
{
return setPoints(Arrays.asList(points));
}
}

View file

@ -3,16 +3,15 @@ plugins {
}
android {
compileSdk 32
namespace 'app.organicmaps.api.sample.capitals'
compileSdk project.targetSdkVersion
defaultConfig {
applicationId "app.organicmaps.api.sample.capitals"
minSdk 21
targetSdk 32
minSdk project.minSdkVersion
targetSdk project.targetSdkVersion
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
@ -22,14 +21,17 @@ android {
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility project.javaVersion
targetCompatibility project.javaVersion
}
}
dependencies {
tasks.withType(JavaCompile) {
options.compilerArgs << '-Xlint:unchecked' << '-Xlint:deprecation'
}
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'com.google.android.material:material:1.6.1'
dependencies {
implementation 'androidx.appcompat:appcompat:1.7.0'
implementation 'com.google.android.material:material:1.12.0'
implementation project(path: ':lib')
}

View file

@ -21,8 +21,7 @@
OF SUCH DAMAGE.
-->
<manifest package="app.organicmaps.api.sample.capitals"
xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"

View file

@ -1,4 +1,4 @@
/******************************************************************************
/*
Copyright (c) 2022, Organic Maps . All rights reserved.
Copyright (c) 2013, MapsWithMe GmbH. All rights reserved.
@ -20,24 +20,28 @@
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
******************************************************************************/
*/
package app.organicmaps.api.sample.capitals;
import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import app.organicmaps.api.Point;
import app.organicmaps.api.Api;
import app.organicmaps.api.MapRequest;
import java.util.ArrayList;
public class CapitalsListActivity extends ListActivity
{
private static final int REQ_CODE_CITY = 1;
CityAdapter mCityAdapter;
@Override
@ -61,12 +65,27 @@ public class CapitalsListActivity extends ListActivity
private void showCityOnOMMap(City ... cities)
{
Point[] points = new Point[cities.length];
for (int i = 0; i < cities.length; i++)
points[i] = cities[i].toPoint();
final ArrayList<Point> points = new ArrayList<>(cities.length);
for (City city : cities)
points.add(city.toPoint());
final String title = cities.length == 1 ? cities[0].getName() : "Capitals of the World";
Api.showPointsOnMap(this, title, CityDetailsActivity.getPendingIntent(this), points);
final Intent intent = new MapRequest()
.setPoints(points)
.setAppName(title)
.toIntent();
this.startActivityForResult(intent, REQ_CODE_CITY);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if (requestCode != REQ_CODE_CITY || resultCode != RESULT_OK)
return;
final Intent intent = new Intent(this, CityDetailsActivity.class);
intent.putExtra(CityDetailsActivity.EXTRA_POINT, data);
}
private static class CityAdapter extends ArrayAdapter<City>

View file

@ -1,4 +1,4 @@
/******************************************************************************
/*
Copyright (c) 2022, Organic Maps . All rights reserved.
Copyright (c) 2013, MapsWithMe GmbH. All rights reserved.
@ -20,7 +20,7 @@
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
******************************************************************************/
*/
package app.organicmaps.api.sample.capitals;
import app.organicmaps.api.Point;
@ -55,9 +55,8 @@ public class City
this.altNames = altNames;
}
@Override
public String toString() { return name; }
public Point toPoint() { return new Point(lat, lon, name, id); }
public String toString() { return name; }
public Point toPoint() { return new Point(lat, lon, name, id); }
public String getId() { return id; }
public String getName() { return name; }

View file

@ -1,5 +1,5 @@
/******************************************************************************
Copyright (c) 2022, Organic Maps . All rights reserved.
/*
Copyright (c) 2022-2023, Organic Maps . All rights reserved.
Copyright (c) 2013, MapsWithMe GmbH. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@ -20,25 +20,24 @@
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
******************************************************************************/
*/
package app.organicmaps.api.sample.capitals;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
import app.organicmaps.api.Response;
import app.organicmaps.api.Api;
import androidx.annotation.NonNull;
import app.organicmaps.api.PickPointResponse;
import app.organicmaps.api.Point;
import app.organicmaps.api.MapRequest;
public class CityDetailsActivity extends Activity
{
public static String EXTRA_FROM_ORGANICMAPS = "from-organicmaps";
private static final int REQ_CODE_CITY = 1;
public static String EXTRA_POINT = "point";
private TextView mName;
private TextView mAltNames;
private TextView mCountry;
@ -52,72 +51,65 @@ public class CityDetailsActivity extends Activity
private City mCity;
public static PendingIntent getPendingIntent(Context context)
{
final Intent i = new Intent(context, CityDetailsActivity.class);
i.putExtra(EXTRA_FROM_ORGANICMAPS, true);
return PendingIntent.getActivity(context, 0, i, PendingIntent.FLAG_IMMUTABLE);
}
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.city_details_activity);
mName = (TextView) findViewById(R.id.name);
mAltNames = (TextView) findViewById(R.id.altNames);
mCountry = (TextView) findViewById(R.id.cCode);
mName = findViewById(R.id.name);
mAltNames = findViewById(R.id.altNames);
mCountry = findViewById(R.id.cCode);
mLat = (TextView) findViewById(R.id.lat);
mLon = (TextView) findViewById(R.id.lon);
mElev = (TextView) findViewById(R.id.elevation);
mLat = findViewById(R.id.lat);
mLon = findViewById(R.id.lon);
mElev = findViewById(R.id.elevation);
mPopulation = (TextView) findViewById(R.id.population);
mTimeZone = (TextView) findViewById(R.id.timeZone);
mPopulation = findViewById(R.id.population);
mTimeZone = findViewById(R.id.timeZone);
findViewById(R.id.showOnMap).setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
Api.showPointsOnMap(CityDetailsActivity.this,mCity.getName(),
CityDetailsActivity.getPendingIntent(CityDetailsActivity.this),mCity.toPoint());
}
findViewById(R.id.showOnMap).setOnClickListener(v -> {
final Intent intent = new MapRequest()
.addPoint(mCity.toPoint())
.setAppName(getString(R.string.app_name))
.toIntent();
startActivityForResult(intent, REQ_CODE_CITY);
});
handleIntent(getIntent());
final Intent data = getIntent().getParcelableExtra(EXTRA_POINT);
handleResponse(data);
}
private void handleResponse(final @NonNull Intent data)
{
final PickPointResponse response = PickPointResponse.extractFromIntent(data);
final Point point = response.getPoint();
mCity = City.fromPoint(point);
if (mCity != null)
{
mName.setText(mCity.getName());
mAltNames.setText(mCity.getAltNames());
mCountry.setText(mCity.getCountryCode());
mLat.setText(String.valueOf(mCity.getLat()));
mLon.setText(String.valueOf(mCity.getLon()));
final String level = mCity.getElevation() != -9999 ? String.valueOf(mCity.getElevation()) : "No Data";
mElev.setText(level);
final String population = mCity.getPopulation() != -1 ? String.valueOf(mCity.getPopulation()) : "No Data";
mPopulation.setText(population);
mTimeZone.setText(mCity.getTimeZone());
}
}
@Override
protected void onNewIntent(Intent intent)
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onNewIntent(intent);
handleIntent(intent);
super.onActivityResult(requestCode, resultCode, data);
if (requestCode != REQ_CODE_CITY || resultCode != RESULT_OK)
return;
handleResponse(data);
}
private void handleIntent(Intent intent)
{
if (intent.getBooleanExtra(EXTRA_FROM_ORGANICMAPS, false))
{
final Response response = Response.extractFromIntent(this, intent);
mCity = City.fromPoint(response.getPoint());
if (mCity != null)
{
mName.setText(mCity.getName());
mAltNames.setText(mCity.getAltNames());
mCountry.setText(mCity.getCountryCode());
mLat.setText(mCity.getLat() + "");
mLon.setText(mCity.getLon() + "");
final String evel = mCity.getElevation() != -9999 ? String.valueOf(mCity.getElevation()) : "No Data";
mElev.setText(evel);
final String popul = mCity.getPopulation() != -1 ? String.valueOf(mCity.getPopulation()) : "No Data";
mPopulation.setText(popul);
mTimeZone.setText(mCity.getTimeZone());
}
}
}
}
}

View file

@ -12,5 +12,6 @@
<string name="population">Population:</string>
<string name="time_zone">Time Zone:</string>
<string name="elevation">Elevation:</string>
<string name="cancelled">Cancelled</string>
</resources>

1
sample-pick-point/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/build

View file

@ -0,0 +1,36 @@
plugins {
id 'com.android.application'
}
android {
namespace 'app.organicmaps.api.sample.pick_point'
compileSdk project.targetSdkVersion
defaultConfig {
applicationId "app.organicmaps.api.sample.pick_point"
minSdk project.minSdkVersion
targetSdk project.targetSdkVersion
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility project.javaVersion
targetCompatibility project.javaVersion
}
}
tasks.withType(JavaCompile) {
options.compilerArgs << '-Xlint:unchecked' << '-Xlint:deprecation'
}
dependencies {
implementation 'com.google.android.material:material:1.12.0'
implementation project(path: ':lib')
}

21
sample-pick-point/proguard-rules.pro vendored Normal file
View file

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:theme="@style/Theme.AppCompat"
android:supportsRtl="true">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View file

@ -0,0 +1,83 @@
/******************************************************************************
Copyright (c) 2022, Organic Maps . All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer. Redistributions in binary form must
reproduce the above copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided with the
distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
******************************************************************************/
package app.organicmaps.api.sample.pick_point;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;
import app.organicmaps.api.CrosshairRequest;
import app.organicmaps.api.DownloadDialog;
import app.organicmaps.api.PickPointResponse;
import app.organicmaps.api.Point;
public class MainActivity extends AppCompatActivity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ActivityResultLauncher<Intent> pickPoint = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> onPointSelected(result.getResultCode(), result.getData()));
findViewById(R.id.pick_point).setOnClickListener(v -> {
final Intent request = new CrosshairRequest().setAppName(getString(R.string.app_name))
.toIntent();
if (getApplicationContext().getPackageManager().resolveActivity(request, 0) == null)
{
new DownloadDialog(this).show();
return;
}
pickPoint.launch(request);
});
}
protected void onPointSelected(int resultCode, Intent data)
{
if (resultCode == RESULT_CANCELED)
{
Toast.makeText(this, getString(R.string.cancelled), Toast.LENGTH_LONG).show();
return;
}
else if (resultCode != RESULT_OK)
{
throw new AssertionError("Unsupported resultCode: " + resultCode);
}
final PickPointResponse response = PickPointResponse.extractFromIntent(data);
final Point point = response.getPoint();
final String message = getString(R.string.result, point.getLat(), point.getLon(), point.getId(), point.getName(), response.getZoomLevel());
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
}

View file

@ -0,0 +1,30 @@
<vector xmlns:aapt="http://schemas.android.com/aapt"
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeColor="#00000000"
android:strokeWidth="1" />
</vector>

View file

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
</vector>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
tools:context=".MainActivity">
<Button
android:id="@+id/pick_point"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/pick_point" />
</LinearLayout>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View file

@ -0,0 +1,6 @@
<resources>
<string name="app_name">Pick Point Sample</string>
<string name="pick_point">Pick Point</string>
<string name="result">Result: lat=%1$.4f lon=%2$.4f id=%3$s name=%4$s zoomLevel=%5$.2f</string>
<string name="cancelled">Cancelled</string>
</resources>

View file

@ -14,4 +14,5 @@ dependencyResolutionManagement {
}
rootProject.name = "Organic Maps API"
include ':sample-app-capitals'
include ':sample-pick-point'
include ':lib'