Compare commits

..

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
17 changed files with 199 additions and 76 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.
@ -73,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
@ -123,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)
@ -141,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:
@ -154,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/PickPointResponse.java "PickPointResponse.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,16 +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 = 31
buildToolsVersion = '32.0.0'
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,12 +3,12 @@ plugins {
}
android {
namespace 'app.organicmaps.api'
compileSdk project.targetSdkVersion
defaultConfig {
minSdk project.minSdkVersion
targetSdk project.targetSdkVersion
buildToolsVersion project.buildToolsVersion
consumerProguardFiles "consumer-rules.pro"
}
@ -25,8 +25,11 @@ android {
}
}
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

@ -24,17 +24,15 @@ package app.organicmaps.api;
public class Const
{
/* Common */
// Common
static final String API_SCHEME = "om://";
static final String AUTHORITY = "app.organicmaps.api";
static final String EXTRA_PREFIX = AUTHORITY + ".extra";
/* Request extras */
public static final String EXTRA_TITLE = EXTRA_PREFIX + ".TITLE";
// Request extras
public static final String EXTRA_PICK_POINT = EXTRA_PREFIX + ".PICK_POINT";
/* Response extras */
/* Point part-by-part*/
// 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";

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

@ -35,36 +35,40 @@ import java.util.Locale;
public class MapRequest
{
private List<Point> mPoints = new ArrayList<>();
private String mTitle;
private String mAppName;
private double mZoomLevel;
// pick point mode
private boolean mPickPointMode;
public MapRequest setTitle(String title)
public @NonNull MapRequest
setAppName(String appName)
{
mTitle = title;
mAppName = appName;
return this;
}
public MapRequest addPoint(Point point)
public @NonNull
MapRequest addPoint(Point point)
{
mPoints.add(point);
return this;
}
public MapRequest setPoints(Collection<Point> points)
public @NonNull
MapRequest setPoints(Collection<Point> points)
{
mPoints = new ArrayList<>(points);
return this;
}
public MapRequest setZoomLevel(double zoomLevel)
public @NonNull
MapRequest setZoomLevel(double zoomLevel)
{
mZoomLevel = zoomLevel;
return this;
}
public MapRequest setPickPointMode(boolean pickPointMode)
public @NonNull MapRequest setPickPointMode(boolean pickPointMode)
{
mPickPointMode = pickPointMode;
return this;
@ -77,8 +81,8 @@ public class MapRequest
builder.append("map?");
// title
if (mTitle != null)
builder.append("appname").append("=").append(Uri.encode(mTitle)).append("&");
if (mAppName != null)
builder.append("appname").append("=").append(Uri.encode(mAppName)).append("&");
// zoom
if (mZoomLevel != 0.0)
builder.append("z").append("=").append(mZoomLevel).append("&");
@ -100,8 +104,6 @@ public class MapRequest
final Uri uri = Uri.parse(builder.toString());
final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
if (mTitle != null)
intent.putExtra(Const.EXTRA_TITLE, mTitle);
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

@ -3,13 +3,13 @@ plugins {
}
android {
namespace 'app.organicmaps.api.sample.capitals'
compileSdk project.targetSdkVersion
defaultConfig {
applicationId "app.organicmaps.api.sample.capitals"
minSdk project.minSdkVersion
targetSdk project.targetSdkVersion
buildToolsVersion project.buildToolsVersion
versionCode 1
versionName "1.0"
}
@ -26,8 +26,12 @@ android {
}
}
tasks.withType(JavaCompile) {
options.compilerArgs << '-Xlint:unchecked' << '-Xlint:deprecation'
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'com.google.android.material:material:1.6.1'
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,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 android.app.ListActivity;
@ -72,7 +72,7 @@ public class CapitalsListActivity extends ListActivity
final String title = cities.length == 1 ? cities[0].getName() : "Capitals of the World";
final Intent intent = new MapRequest()
.setPoints(points)
.setTitle(title)
.setAppName(title)
.toIntent();
this.startActivityForResult(intent, REQ_CODE_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;

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,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 android.app.Activity;
@ -57,21 +57,21 @@ public class CityDetailsActivity extends Activity
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(v -> {
final Intent intent = new MapRequest()
.addPoint(mCity.toPoint())
.setTitle(getString(R.string.app_name))
.setAppName(getString(R.string.app_name))
.toIntent();
startActivityForResult(intent, REQ_CODE_CITY);
});

View file

@ -3,13 +3,13 @@ plugins {
}
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
buildToolsVersion project.buildToolsVersion
versionCode 1
versionName "1.0"
}
@ -26,7 +26,11 @@ android {
}
}
tasks.withType(JavaCompile) {
options.compilerArgs << '-Xlint:unchecked' << '-Xlint:deprecation'
}
dependencies {
implementation 'com.google.android.material:material:1.6.1'
implementation 'com.google.android.material:material:1.12.0'
implementation project(path: ':lib')
}

View file

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="app.organicmaps.api.sample.pick_point"
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

@ -31,8 +31,8 @@ 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.MapRequest;
import app.organicmaps.api.PickPointResponse;
import app.organicmaps.api.Point;
@ -48,12 +48,10 @@ public class MainActivity extends AppCompatActivity
new ActivityResultContracts.StartActivityForResult(),
result -> onPointSelected(result.getResultCode(), result.getData()));
findViewById(R.id.pick_point).setOnClickListener(v -> {
final Intent request = new MapRequest()
.setTitle(getString(R.string.app_name))
.setPickPointMode(true)
.toIntent();
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();