diff options
author | Michael Keppler <michael.keppler@gmx.de> | 2014-04-21 18:33:07 +0200 |
---|---|---|
committer | Michael Keppler <michael.keppler@gmx.de> | 2014-04-21 18:33:07 +0200 |
commit | 7955c23b643ba127d002b07fac57790ca430ad88 (patch) | |
tree | 4f61c7f0c81bf8d85cb44034f097ff9b7c63e44b | |
parent | bcced1c4bfafcd0984f7c94abf53bc966359799e (diff) | |
download | cgeo-7955c23b643ba127d002b07fac57790ca430ad88.zip cgeo-7955c23b643ba127d002b07fac57790ca430ad88.tar.gz cgeo-7955c23b643ba127d002b07fac57790ca430ad88.tar.bz2 |
new: integrate mapswithme
39 files changed, 1359 insertions, 3 deletions
diff --git a/main/project.properties b/main/project.properties index 6d3329d..a761287 100644 --- a/main/project.properties +++ b/main/project.properties @@ -12,3 +12,4 @@ proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project. # Project target. target=Google Inc.:Google APIs:19 +android.library.reference.1=../mapswithme-api diff --git a/main/res/values/ids.xml b/main/res/values/ids.xml index 8539275..e8cb74b 100644 --- a/main/res/values/ids.xml +++ b/main/res/values/ids.xml @@ -24,5 +24,6 @@ <item name="cache_app_show_static_maps" type="id"/> <item name="cache_app_locus" type="id"/> <item name="cache_app_pebble" type="id"/> - + <item name="cache_app_mapswithme" type="id"/> + </resources>
\ No newline at end of file diff --git a/main/res/values/preference_keys.xml b/main/res/values/preference_keys.xml index 91b2c67..6036be3 100644 --- a/main/res/values/preference_keys.xml +++ b/main/res/values/preference_keys.xml @@ -137,6 +137,7 @@ <string name="pref_navigation_menu_gcc">navigationGcc</string> <string name="pref_navigation_menu_where_you_go">navigationWhereYouGo</string> <string name="pref_navigation_menu_pebble">navigationPebble</string> + <string name="pref_navigation_menu_mapswithme">navigationMapsWithMe</string> <string name="pref_ocpl_tokensecret">ocpl_tokensecret</string> <string name="pref_ocpl_tokenpublic">ocpl_tokenpublic</string> <string name="pref_temp_ocpl_token_secret">ocpl-temp-token-secret</string> diff --git a/main/res/values/strings.xml b/main/res/values/strings.xml index 62c3bbf..55d44b8 100644 --- a/main/res/values/strings.xml +++ b/main/res/values/strings.xml @@ -320,6 +320,7 @@ <string name="caches_move_all">Move all</string> <string name="caches_map_locus">Locus</string> <string name="caches_map_locus_export">Export to Locus</string> + <string name="caches_map_mapswithme">MapsWithMe</string> <string name="caches_recaptcha_title">reCAPTCHA</string> <string name="caches_recaptcha_explanation">Please enter the text you see in the image. This enables downloading of cache coordinates, which can be disabled in Settings.</string> <string name="caches_recaptcha_hint">Text from image</string> @@ -709,6 +710,7 @@ <string name="cache_menu_cachebeacon">Cache Beacon</string> <string name="cache_menu_navigon">Navigon</string> <string name="cache_menu_pebble">Pebble</string> + <string name="cache_menu_mapswithme">MapsWithMe</string> <string name="cache_status">Status</string> <string name="cache_status_offline_log">Saved Log</string> <string name="cache_status_found">Found</string> diff --git a/main/res/xml/preferences.xml b/main/res/xml/preferences.xml index fb17fb8..d550dc8 100644 --- a/main/res/xml/preferences.xml +++ b/main/res/xml/preferences.xml @@ -666,6 +666,11 @@ android:enabled="false" android:key="@string/pref_navigation_menu_pebble" android:title="@string/cache_menu_pebble" /> + <CheckBoxPreference + android:defaultValue="true" + android:enabled="false" + android:key="@string/pref_navigation_menu_mapswithme" + android:title="@string/cache_menu_mapswithme" /> </PreferenceScreen> </PreferenceCategory> </PreferenceScreen> diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java index b8f4703..e76a773 100644 --- a/main/src/cgeo/geocaching/CacheDetailActivity.java +++ b/main/src/cgeo/geocaching/CacheDetailActivity.java @@ -8,6 +8,7 @@ import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.activity.AbstractViewPagerActivity; import cgeo.geocaching.activity.Progress; import cgeo.geocaching.apps.cache.navi.NavigationAppFactory; +import cgeo.geocaching.apps.cachelist.MapsWithMeCacheListApp; import cgeo.geocaching.compatibility.Compatibility; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.connector.IConnector; @@ -55,6 +56,7 @@ import org.apache.commons.lang3.StringEscapeUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; + import rx.Observable; import rx.Observable.OnSubscribe; import rx.Observer; @@ -197,6 +199,11 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc guid = extras.getString(Intents.EXTRA_GUID); } + // integration with MapsWithMe + if (StringUtils.isEmpty(geocode)) { + geocode = MapsWithMeCacheListApp.getCacheFromMapsWithMe(this, getIntent()); + } + // try to get data from URI if (geocode == null && guid == null && uri != null) { final String uriHost = uri.getHost().toLowerCase(Locale.US); diff --git a/main/src/cgeo/geocaching/apps/cache/navi/MapsWithMeApp.java b/main/src/cgeo/geocaching/apps/cache/navi/MapsWithMeApp.java new file mode 100644 index 0000000..ea5aebb --- /dev/null +++ b/main/src/cgeo/geocaching/apps/cache/navi/MapsWithMeApp.java @@ -0,0 +1,43 @@ +package cgeo.geocaching.apps.cache.navi; + +import cgeo.geocaching.Geocache; +import cgeo.geocaching.R; +import cgeo.geocaching.Waypoint; +import cgeo.geocaching.geopoint.Geopoint; + +import com.mapswithme.maps.api.MapsWithMeApi; + +import android.app.Activity; + +public class MapsWithMeApp extends AbstractPointNavigationApp { + + protected MapsWithMeApp() { + super(getString(R.string.cache_menu_mapswithme), R.id.cache_app_mapswithme, null); + } + + @Override + public void navigate(Activity activity, Geopoint coords) { + navigate(activity, coords, getString(R.string.unknown)); + } + + @Override + public void navigate(Activity activity, Geocache cache) { + navigate(activity, cache.getCoords(), cache.getName()); + } + + private static void navigate(Activity activity, Geopoint coords, String label) { + MapsWithMeApi.showPointOnMap(activity, coords.getLatitude(), coords.getLongitude(), label); + } + + @Override + public void navigate(Activity activity, Waypoint waypoint) { + navigate(activity, waypoint.getCoords(), waypoint.getName()); + } + + @Override + public boolean isInstalled() { + // the library can handle the app not being installed + return true; + } + +} diff --git a/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java b/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java index bf0e776..3177a29 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java @@ -72,7 +72,8 @@ public final class NavigationAppFactory extends AbstractAppFactory { CACHE_BEACON(new CacheBeaconApp(), 14, R.string.pref_navigation_menu_cache_beacon), GCC(new GccApp(), 15, R.string.pref_navigation_menu_gcc), WHERE_YOU_GO(new WhereYouGoApp(), 16, R.string.pref_navigation_menu_where_you_go), - PEBBLE(new PebbleApp(), 17, R.string.pref_navigation_menu_pebble); + PEBBLE(new PebbleApp(), 17, R.string.pref_navigation_menu_pebble), + MAPSWITHME(new MapsWithMeApp(), 22, R.string.pref_navigation_menu_mapswithme); NavigationAppsEnum(final App app, final int id, final int preferenceKey) { this.app = app; diff --git a/main/src/cgeo/geocaching/apps/cachelist/CacheListAppFactory.java b/main/src/cgeo/geocaching/apps/cachelist/CacheListAppFactory.java index 4df9d26..8212111 100644 --- a/main/src/cgeo/geocaching/apps/cachelist/CacheListAppFactory.java +++ b/main/src/cgeo/geocaching/apps/cachelist/CacheListAppFactory.java @@ -21,7 +21,8 @@ public final class CacheListAppFactory extends AbstractAppFactory { public static final CacheListApp[] apps = { new InternalCacheListMap(), new LocusShowCacheListApp(), - new LocusExportCacheListApp() + new LocusExportCacheListApp(), + new MapsWithMeCacheListApp() }; } diff --git a/main/src/cgeo/geocaching/apps/cachelist/MapsWithMeCacheListApp.java b/main/src/cgeo/geocaching/apps/cachelist/MapsWithMeCacheListApp.java new file mode 100644 index 0000000..e22d358 --- /dev/null +++ b/main/src/cgeo/geocaching/apps/cachelist/MapsWithMeCacheListApp.java @@ -0,0 +1,65 @@ +package cgeo.geocaching.apps.cachelist; + +import cgeo.geocaching.CacheDetailActivity; +import cgeo.geocaching.Geocache; +import cgeo.geocaching.R; +import cgeo.geocaching.SearchResult; +import cgeo.geocaching.apps.AbstractApp; + +import com.mapswithme.maps.api.MWMPoint; +import com.mapswithme.maps.api.MWMResponse; +import com.mapswithme.maps.api.MapsWithMeApi; + +import org.eclipse.jdt.annotation.Nullable; + +import android.app.Activity; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; + +import java.util.List; + +public class MapsWithMeCacheListApp extends AbstractApp implements CacheListApp { + + protected MapsWithMeCacheListApp() { + super(getString(R.string.caches_map_mapswithme), R.id.cache_app_mapswithme, Intent.ACTION_VIEW); + } + + @Override + public boolean invoke(List<Geocache> caches, Activity activity, SearchResult search) { + final MWMPoint[] points = new MWMPoint[caches.size()]; + for (int i = 0; i < points.length; i++) { + Geocache geocache = caches.get(i); + points[i] = new MWMPoint(geocache.getCoords().getLatitude(), geocache.getCoords().getLongitude(), geocache.getName(), geocache.getGeocode()); + } + MapsWithMeApi.showPointsOnMap(activity, null, getPendingIntent(activity), points); + return true; + } + + @Override + public boolean isInstalled() { + // API can handle installing on the fly + return true; + } + + /** + * get cache code from an invocation of MapsWithMe + * + * @return + */ + @Nullable + public static String getCacheFromMapsWithMe(final Context context, final Intent intent) { + final MWMResponse mwmResponse = MWMResponse.extractFromIntent(context, intent); + if (mwmResponse != null) { + final MWMPoint point = mwmResponse.getPoint(); + return point.getId(); + } + return null; + } + + private static PendingIntent getPendingIntent(Context context) { + final Intent intent = new Intent(context, CacheDetailActivity.class); + return PendingIntent.getActivity(context, 0, intent, 0); + } + +} diff --git a/mapswithme-api/.classpath b/mapswithme-api/.classpath new file mode 100644 index 0000000..26bdfa6 --- /dev/null +++ b/mapswithme-api/.classpath @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="gen"/>
+ <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
+ <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
+ <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
+ <classpathentry kind="output" path="bin/classes"/>
+</classpath>
diff --git a/mapswithme-api/.project b/mapswithme-api/.project new file mode 100644 index 0000000..5d4fc1d --- /dev/null +++ b/mapswithme-api/.project @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>mapswithme-api</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.ApkBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>com.android.ide.eclipse.adt.AndroidNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/mapswithme-api/AndroidManifest.xml b/mapswithme-api/AndroidManifest.xml new file mode 100644 index 0000000..1bea627 --- /dev/null +++ b/mapswithme-api/AndroidManifest.xml @@ -0,0 +1,8 @@ +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.mapwithme.maps.api" + android:versionCode="1" + android:versionName="1.0" > + + <application /> + +</manifest>
\ No newline at end of file diff --git a/mapswithme-api/README.MD b/mapswithme-api/README.MD new file mode 100644 index 0000000..96c7b0d --- /dev/null +++ b/mapswithme-api/README.MD @@ -0,0 +1,169 @@ +# MapsWithMe Android API: Getting Started
+
+## Introduction
+MapsWithMe Android API (hereinafter referred to as *"API Library"* or just *"library"*)
+provides interface for client application to perform next tasks:
+
+* Show one or more points on offline map of [MapsWithMe Application][linkMwm]
+* Come back to the client application after selecting specific point on the map, by sending [PendingIntent][linkPIntent] with point data when user asks for more information by pressing "More Info" button in MapsWithMe Application
+* Map screen branding : your application's icon and name (or custom title) will be placed at the top.
+
+Thus, you can provide **two way communication between your application and MapsWithMe**,
+using MapsWithMe to show points of interest (POI) and providing more information in your app.
+
+Please refer to [sample application][linkSampleSource] for demo or see
+our [travel guide apps][linkTravelGuides] as an API integration example.
+
+## Prerequisites
+
+It is supposed that you are familiar with Android Development, and you have Android SDK and Eclipse (or another IDE of your choice) installed.
+You should be familiar with concept of [Intents][linkIntents], [library projects][linkLibProj], and [PendingIntents][linkPIntent] (recommended) as well.
+Your application must target at least *android sdk version 7*.
+
+## Integration
+First step is to clone [repository][linkRepo] or download it as an archive.
+
+When your are done you find two folders: *lib* and *sample-app-capitals*. First one is a library project that you should add to your project.
+You don't need any additional permissions in your AndroidManifest.xml to use API library, so you can write real code straight away, calling for different `MapsWithMeApi` methods (more details below).
+
+##Classes Overview and HOW TO
+Core classes you will work with are:
+
+* [com.mapswithme.maps.api.MapsWithMeApi][linkApiClass] - static class with methods such as `showPointOnMap(Activity, double, double, String)` etc.
+* [com.mapswithme.maps.api.MWMPoint][linkPointClass] - model of POI, includes lat, lon, name, and id data.
+* [com.mapswithme.maps.api.MWMResponse][linkRespClass] - helps you to extract response from MapsWithMe by applying `MWMResponse.extractFromIntent(Intent)` to Intent. Contains MWMPoint data.
+
+### Show Points on the Map
+
+The simplest usage:
+
+ public class MyPerfectActivity extends Activity {
+ ...
+
+ void showSomethingOnTheMap(SomeDomainObject arg)
+ {
+ // Do some work, create lat, lon, and name for point
+ final double lat = ...;
+ final double lon = ...;
+ final String name = ...;
+ // Ask MapsWithMe to show the point
+ MapsWithMeApi.showPointOnMap(this, lat, lon, name);
+ }
+ ...
+
+ }
+
+For multiple points use [MWMPoint][linkPointClass] class:
+
+ void showMultiplePoints(List<SomeDomainObject> list)
+ {
+ // Convert objects to MMWPoints
+ final MWMPoint[] points = new MWMPoint[list.length];
+ for (int i = 0; i < list.size; i++)
+ {
+ // Get lat, lon, and name from object and assign it to new MMWPoint
+ points[i] = new MWMPoint(lat, lon, name);
+ }
+ // Show all point on the map, you could also provide some title
+ MapsWithMeApi.showPointsOnMap(this, "Look at my points, my points are amazing!", points);
+ }
+
+
+### Ask MapsWithMe to Call my App
+
+We support PendingIntent interaction (just like Android native
+NotificationManager does). You should specify ID for each point to
+distinguish it later, and PentingIntent that MapsWithMe will send back to
+your application when user press "More Info" button :
+
+ // Here is how to pass points with ID ant PendingIntent
+ void showMultiplePointsWithPendingIntent(List<SomeDomainObject> list, PendingIntent pendingIntent)
+ {
+ // Convert objects to MWMPoints
+ final MWMPoint[] points = new MWMPoint[list.length];
+ for (int i = 0; i < list.size; i++)
+ {
+ // ||
+ // ||
+ // \/
+ // Now you should specify string ID for each point
+ points[i] = new MWMPoint(lat, lon, name, id);
+ }
+ // Show all points on the map, you could also provide some title
+ MapsWithMeApi.showPointsOnMap(this, "This title says that user should choose some point", pendingIntent, points);
+ }
+
+ //Code below shows general way to extract response data
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ // Handle intent you specified with PandingIntent
+ // Now it has additional information (MWMPoint).
+ handleIntent(getIntent());
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent)
+ {
+ super.onNewIntent(intent);
+ // if defined your activity as "SingleTop"- you should use onNewIntent callback
+ handleIntent(intent);
+ }
+
+ void handleIntent(Intent intent)
+ {
+ // Apply MWMResponse extraction method to intent
+ final MWMResponse mwmResponse = MWMResponse.extractFromIntent(this, intent);
+ // Here is your point that user selected
+ final MWMPoint point = mwmResponse.getPoint();
+ // Now, for instance you can do some work depending on point id
+ processUserInteraction(point.getId());
+ }
+
+## FAQ
+
+#### How should I detect if user has MapsWithMe installed?
+`MapsWithMeApi.isMapsWithMeInstalled(Context)` will return `true` if user has *Lite* or *Pro* version that supports API call installed.
+
+#### Which versions of MapsWithMe support API calls?
+Both *Lite* and *Pro* versions since 2.4.0 and above support API calls.
+
+#### What will happen if I call for `MapsWithMeApi.showPoint()` but MapsWithMe application is not installed?
+Nothing serious. API library will show simple dialog with gentle offer to download MapsWithMe. You can see how it looks like below. ![Please install us](site/images/dlg.png)
+
+#### If user has both *Lite* and *Pro* versions which one will be called?
+MapsWithMe Pro will serve your request in the case if both *Lite* and *Pro* versions installed.
+
+## Sample Code and Application
+
+* [Sample Application at Google Play][linkSampleGooglePlay]
+* [Sample Application Source Code][linkSampleSource]
+
+## Support
+If you have any questions please email to [api@mapswith.me][linkSupport].
+
+-------------------------------------------------------------------------------
+## API Code License
+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.
+
+[linkMwm]: http://mapswith.me/ "MapsWithMe"
+[linkPIntent]: http://developer.android.com/reference/android/app/PendingIntent.html "PendingIntent"
+[linkRepo]: https://github.com/mapswithme/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"
+[linkSupport]: mailto:api@mapswith.me "MapsWithMe Support Contact"
+[linkApiClass]: lib/src/com/mapswithme/maps/api/MapsWithMeApi.java "MapsWithMeApi.java"
+[linkPointClass]: lib/src/com/mapswithme/maps/api/MWMPoint.java "MWMPoint.java"
+[linkRespClass]: lib/src/com/mapswithme/maps/api/MWMResponse.java "MWMResponse.java"
+[linkSampleSource]: https://github.com/mapswithme/api-android/tree/master/sample-app-capitals "Api Source Code"
+[linkSampleGooglePlay]: http://play.google.com/store/apps/details?id=com.mapswithme.capitals "Api Demo .apk"
+[linkTravelGuides]: http://www.guidewithme.com
diff --git a/mapswithme-api/build.gradle b/mapswithme-api/build.gradle new file mode 100644 index 0000000..12dac15 --- /dev/null +++ b/mapswithme-api/build.gradle @@ -0,0 +1,34 @@ +apply plugin: 'android-library' + +dependencies { + compile fileTree(dir: 'libs', include: '*.jar') +} + +android { + compileSdkVersion 19 + buildToolsVersion "19" + + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + java.srcDirs = ['src'] + resources.srcDirs = ['src'] + aidl.srcDirs = ['src'] + renderscript.srcDirs = ['src'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + } + + // Move the tests to tests/java, tests/res, etc... + instrumentTest.setRoot('tests') + + // Move the build types to build-types/<type> + // For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ... + // This moves them out of them default location under src/<type>/... which would + // conflict with src/ being used by the main source set. + // Adding new build types or product flavors should be accompanied + // by a similar customization. + debug.setRoot('build-types/debug') + release.setRoot('build-types/release') + } +} diff --git a/mapswithme-api/build.xml b/mapswithme-api/build.xml new file mode 100644 index 0000000..dbb2595 --- /dev/null +++ b/mapswithme-api/build.xml @@ -0,0 +1,92 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project name="MwmApi" default="help"> + + <!-- The local.properties file is created and updated by the 'android' tool. + It contains the path to the SDK. It should *NOT* be checked into + Version Control Systems. --> + <property file="local.properties" /> + + <!-- The ant.properties file can be created by you. It is only edited by the + 'android' tool to add properties to it. + This is the place to change some Ant specific build properties. + Here are some properties you may want to change/update: + + source.dir + The name of the source directory. Default is 'src'. + out.dir + The name of the output directory. Default is 'bin'. + + For other overridable properties, look at the beginning of the rules + files in the SDK, at tools/ant/build.xml + + Properties related to the SDK location or the project target should + be updated using the 'android' tool with the 'update' action. + + This file is an integral part of the build system for your + application and should be checked into Version Control Systems. + + --> + <property file="ant.properties" /> + + <!-- if sdk.dir was not set from one of the property file, then + get it from the ANDROID_HOME env var. + This must be done before we load project.properties since + the proguard config can use sdk.dir --> + <property environment="env" /> + <condition property="sdk.dir" value="${env.ANDROID_HOME}"> + <isset property="env.ANDROID_HOME" /> + </condition> + + <!-- The project.properties file is created and updated by the 'android' + tool, as well as ADT. + + This contains project specific properties such as project target, and library + dependencies. Lower level build properties are stored in ant.properties + (or in .classpath for Eclipse projects). + + This file is an integral part of the build system for your + application and should be checked into Version Control Systems. --> + <loadproperties srcFile="project.properties" /> + + <!-- quick check on sdk.dir --> + <fail + message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable." + unless="sdk.dir" + /> + + <!-- + Import per project custom build rules if present at the root of the project. + This is the place to put custom intermediary targets such as: + -pre-build + -pre-compile + -post-compile (This is typically used for code obfuscation. + Compiled code location: ${out.classes.absolute.dir} + If this is not done in place, override ${out.dex.input.absolute.dir}) + -post-package + -post-build + -pre-clean + --> + <import file="custom_rules.xml" optional="true" /> + + <!-- Import the actual build file. + + To customize existing targets, there are two options: + - Customize only one target: + - copy/paste the target into this file, *before* the + <import> task. + - customize it to your needs. + - Customize the whole content of build.xml + - copy/paste the content of the rules files (minus the top node) + into this file, replacing the <import> task. + - customize to your needs. + + *********************** + ****** IMPORTANT ****** + *********************** + In all cases you must update the value of version-tag below to read 'custom' instead of an integer, + in order to avoid having your file be overridden by tools such as "android update project" + --> + <!-- version-tag: 1 --> + <import file="${sdk.dir}/tools/ant/build.xml" /> + +</project> diff --git a/mapswithme-api/proguard-project.txt b/mapswithme-api/proguard-project.txt new file mode 100644 index 0000000..f2fe155 --- /dev/null +++ b/mapswithme-api/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# 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 *; +#} diff --git a/mapswithme-api/project.properties b/mapswithme-api/project.properties new file mode 100644 index 0000000..91d2b02 --- /dev/null +++ b/mapswithme-api/project.properties @@ -0,0 +1,15 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-19 +android.library=true diff --git a/mapswithme-api/res/drawable/background_pattern.xml b/mapswithme-api/res/drawable/background_pattern.xml new file mode 100644 index 0000000..2293a51 --- /dev/null +++ b/mapswithme-api/res/drawable/background_pattern.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<bitmap xmlns:android="http://schemas.android.com/apk/res/android" + android:dither="true" + android:src="@drawable/pattern" + android:tileMode="repeat" /> diff --git a/mapswithme-api/res/drawable/btn_back_gray.xml b/mapswithme-api/res/drawable/btn_back_gray.xml new file mode 100644 index 0000000..445902c --- /dev/null +++ b/mapswithme-api/res/drawable/btn_back_gray.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android" > + + <!-- "background shadow" --> + <item android:drawable="@drawable/shadow"/> + <item + android:bottom="1dp" + android:left="1dp" + android:right="1dp" + android:top="1dp" + android:drawable="@drawable/gray"/> + +</layer-list>
\ No newline at end of file diff --git a/mapswithme-api/res/drawable/btn_back_gray_active.xml b/mapswithme-api/res/drawable/btn_back_gray_active.xml new file mode 100644 index 0000000..a4d6310 --- /dev/null +++ b/mapswithme-api/res/drawable/btn_back_gray_active.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + + <!-- "background shadow" --> + <item android:drawable="@drawable/shadow"/> + + <item + android:bottom="2dp" + android:left="1dp" + android:right="1dp" + android:top="1dp" + android:drawable="@drawable/gray"/> + + <item android:drawable="@drawable/overflow"/> + +</layer-list>
\ No newline at end of file diff --git a/mapswithme-api/res/drawable/btn_back_green.xml b/mapswithme-api/res/drawable/btn_back_green.xml new file mode 100644 index 0000000..b647551 --- /dev/null +++ b/mapswithme-api/res/drawable/btn_back_green.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android" > + + <!-- "background shadow" --> + <item android:drawable="@drawable/shadow"/> + + <item + android:bottom="1dp" + android:left="1dp" + android:right="1dp" + android:top="1dp" + android:drawable="@drawable/green"/> + +</layer-list>
\ No newline at end of file diff --git a/mapswithme-api/res/drawable/btn_back_green_active.xml b/mapswithme-api/res/drawable/btn_back_green_active.xml new file mode 100644 index 0000000..49e849f --- /dev/null +++ b/mapswithme-api/res/drawable/btn_back_green_active.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android" > + + <!-- "background shadow" --> + <item android:drawable="@drawable/shadow"/> + + <item + android:bottom="2dp" + android:left="1dp" + android:right="1dp" + android:top="1dp" + android:drawable="@drawable/green"/> + + <item android:drawable="@drawable/overflow"/> + +</layer-list>
\ No newline at end of file diff --git a/mapswithme-api/res/drawable/btn_gray_selector.xml b/mapswithme-api/res/drawable/btn_gray_selector.xml new file mode 100644 index 0000000..3876bb0 --- /dev/null +++ b/mapswithme-api/res/drawable/btn_gray_selector.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + + <item android:drawable="@drawable/btn_back_gray_active" android:state_pressed="true"/> + <item android:drawable="@drawable/btn_back_gray"/> + +</selector>
\ No newline at end of file diff --git a/mapswithme-api/res/drawable/btn_green_selector.xml b/mapswithme-api/res/drawable/btn_green_selector.xml new file mode 100644 index 0000000..61b78df --- /dev/null +++ b/mapswithme-api/res/drawable/btn_green_selector.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + + <item android:drawable="@drawable/btn_back_green_active" android:state_pressed="true"/> + <item android:drawable="@drawable/btn_back_green"/> + +</selector>
\ No newline at end of file diff --git a/mapswithme-api/res/drawable/gray.xml b/mapswithme-api/res/drawable/gray.xml new file mode 100644 index 0000000..f3fda93 --- /dev/null +++ b/mapswithme-api/res/drawable/gray.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle" > + + + <gradient android:type="linear" + android:angle="90" + android:startColor="#D00099CC" + android:centerColor="#D033B5E5" + android:endColor="#D00099CC"/> + + <corners android:radius="4dp" /> +</shape>
\ No newline at end of file diff --git a/mapswithme-api/res/drawable/green.xml b/mapswithme-api/res/drawable/green.xml new file mode 100644 index 0000000..c7afb64 --- /dev/null +++ b/mapswithme-api/res/drawable/green.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle" > + <!-- + <solid android:color="#66CC33" /> --> + + <gradient android:type="linear" + android:angle="90" + android:startColor="#D066CC33" + android:centerColor="#D099CC00" + android:endColor="#D066CC33"/> + + + <corners android:radius="4dp" /> +</shape>
\ No newline at end of file diff --git a/mapswithme-api/res/drawable/overflow.xml b/mapswithme-api/res/drawable/overflow.xml new file mode 100644 index 0000000..f507765 --- /dev/null +++ b/mapswithme-api/res/drawable/overflow.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle" > + <solid android:color="#80FFFFFF" /> + <corners android:radius="3dp" /> +</shape>
\ No newline at end of file diff --git a/mapswithme-api/res/drawable/pattern.png b/mapswithme-api/res/drawable/pattern.png Binary files differnew file mode 100644 index 0000000..33b8d96 --- /dev/null +++ b/mapswithme-api/res/drawable/pattern.png diff --git a/mapswithme-api/res/drawable/shadow.xml b/mapswithme-api/res/drawable/shadow.xml new file mode 100644 index 0000000..4c241c4 --- /dev/null +++ b/mapswithme-api/res/drawable/shadow.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle" > + <gradient + android:angle="-90" + android:centerX="50%" + android:centerY="50%" + android:gradientRadius="400" + android:startColor="#44000000" + android:endColor="#88000000" + android:type="linear" /> + <corners android:radius="4dp" /> +</shape>
\ No newline at end of file diff --git a/mapswithme-api/res/layout/dlg_install_mwm.xml b/mapswithme-api/res/layout/dlg_install_mwm.xml new file mode 100644 index 0000000..0d174a8 --- /dev/null +++ b/mapswithme-api/res/layout/dlg_install_mwm.xml @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> +<ScrollView 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" > + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@drawable/background_pattern" + android:gravity="center" + android:orientation="vertical" + android:paddingLeft="10dp" + android:paddingRight="10dp" > + + <TextView + style="@android:style/TextAppearance.Medium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:layout_weight="0" + android:gravity="center" + android:text="@string/mwm_should_be_installed" + android:textColor="@android:color/black" /> + + <Button + android:id="@+id/btn_pro" + style="@style/promoButton" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_weight="1" + android:background="@drawable/btn_green_selector" + android:text="@string/down_pro" /> + + <Button + android:id="@+id/btn_lite" + style="@style/promoButton" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_weight="1" + android:background="@drawable/btn_gray_selector" + android:padding="6dp" + android:text="@string/down_lite" /> + + </LinearLayout> + +</ScrollView>
\ No newline at end of file diff --git a/mapswithme-api/res/values/strings.xml b/mapswithme-api/res/values/strings.xml new file mode 100644 index 0000000..1955847 --- /dev/null +++ b/mapswithme-api/res/values/strings.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="mwm_should_be_installed">Offline maps are required to proceed. We have partnered with MapsWithMe to provide you with offline maps of the entire world.\nTo continue please download the app:</string> + <string name="down_lite">Download MapsWithMe Lite (free)</string> + <string name="down_pro">Download MapsWithMe Pro</string> + + <string name="url_pro">http://mapswith.me/get</string> + <string name="url_lite">http://mapswith.me/app</string> +</resources>
\ No newline at end of file diff --git a/mapswithme-api/res/values/styles.xml b/mapswithme-api/res/values/styles.xml new file mode 100644 index 0000000..e9c52fa --- /dev/null +++ b/mapswithme-api/res/values/styles.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources xmlns:android="http://schemas.android.com/apk/res/android"> + <style name="promoButton" parent="android:Widget.Button"> + <item name="android:layout_marginBottom">10dp</item> + <item name="android:layout_marginTop">10dp</item> + <item name="android:padding">6dp</item> + <item name="android:textColor">@android:color/white</item> + <item name="android:textStyle">bold</item> + </style> +</resources> diff --git a/mapswithme-api/src/com/mapswithme/maps/api/Const.java b/mapswithme-api/src/com/mapswithme/maps/api/Const.java new file mode 100644 index 0000000..8fbd196 --- /dev/null +++ b/mapswithme-api/src/com/mapswithme/maps/api/Const.java @@ -0,0 +1,55 @@ +/****************************************************************************** + 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 com.mapswithme.maps.api; + +public class Const +{ + + /* 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"; + + + /* Response extras */ + /* Point part-by-part*/ + public static final String EXTRA_MWM_RESPONSE_POINT_NAME = AUTHORITY + ".point_name"; + public static final String EXTRA_MWM_RESPONSE_POINT_LAT = AUTHORITY + ".point_lat"; + public static final String EXTRA_MWM_RESPONSE_POINT_LON = AUTHORITY + ".point_lon"; + public static final String EXTRA_MWM_RESPONSE_POINT_ID = AUTHORITY + ".point_id"; + public static final String EXTRA_MWM_RESPONSE_ZOOM = AUTHORITY + ".zoom_level"; + + + public static final String ACTION_MWM_REQUEST = AUTHORITY + ".request"; + static final int API_VERSION = 2; + static final String CALLBACK_PREFIX = "mapswithme.client."; + + private Const() {} +} diff --git a/mapswithme-api/src/com/mapswithme/maps/api/DownloadMapsWithMeDialog.java b/mapswithme-api/src/com/mapswithme/maps/api/DownloadMapsWithMeDialog.java new file mode 100644 index 0000000..5670a5f --- /dev/null +++ b/mapswithme-api/src/com/mapswithme/maps/api/DownloadMapsWithMeDialog.java @@ -0,0 +1,65 @@ +/****************************************************************************** + 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 com.mapswithme.maps.api; + +import android.app.Activity; +import android.app.Dialog; +import android.content.Intent; +import android.net.Uri; +import android.view.View; +import android.view.Window; + +import com.mapwithme.maps.api.R; + +public class DownloadMapsWithMeDialog extends Dialog implements android.view.View.OnClickListener +{ + + public DownloadMapsWithMeDialog(Activity activity) + { + super(activity); + + requestWindowFeature(Window.FEATURE_NO_TITLE); + setContentView(R.layout.dlg_install_mwm); + + findViewById(R.id.btn_lite).setOnClickListener(this); + findViewById(R.id.btn_pro).setOnClickListener(this); + + setOwnerActivity(activity); + } + + + public void onDownloadButtonClicked(String url) + { + Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + getContext().startActivity(i); + dismiss(); + } + + + @Override + public void onClick(View v) + { + String url = getContext().getString(v.getId() == R.id.btn_lite ? R.string.url_lite : R.string.url_pro); + onDownloadButtonClicked(url); + } +} diff --git a/mapswithme-api/src/com/mapswithme/maps/api/MWMPoint.java b/mapswithme-api/src/com/mapswithme/maps/api/MWMPoint.java new file mode 100644 index 0000000..86fa39a --- /dev/null +++ b/mapswithme-api/src/com/mapswithme/maps/api/MWMPoint.java @@ -0,0 +1,107 @@ +/****************************************************************************** + 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 com.mapswithme.maps.api; + +import java.io.Serializable; + +/** + * POI wrapper object. + * Has it's <code>equals()</code> and <code>hashCode()</code> methods overloaded + * so could be used in Hash(Map/Set/etc) classes. + */ +public final class MWMPoint implements Serializable +{ + private static final long serialVersionUID = 1L; + + final private double mLat; + final private double mLon; + final private String mName; + private String mId; + + public MWMPoint(double lat, double lon, String name) + { + this(lat, lon, name, null); + } + + public MWMPoint(double lat, double lon, String name, String id) + { + this.mLat = lat; + this.mLon = lon; + this.mName = name; + this.mId = id; + } + + public double getLat() { return mLat; } + public double getLon() { return mLon; } + public String getName() { return mName; } + public String getId() { return mId; } + + /** + * 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 + */ + public void setId(String id) { mId = id; } + + @Override + public String toString() + { + return "MWMPoint [lat=" + mLat + ", lon=" + mLon + ", name=" + mName + ", id=" + mId + "]"; + } + + @Override + public int hashCode() + { + final int prime = 31; + int result = 1; + long temp; + temp = Double.doubleToLongBits(mLat); + result = prime * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(mLon); + result = prime * result + (int) (temp ^ (temp >>> 32)); + result = prime * result + ((mName == null) ? 0 : mName.hashCode()); + return result; + } + + /** + * Two point are considered + * equal if they have they lat, lon, and name attributes equal. + */ + @Override + public boolean equals(Object obj) + { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final MWMPoint other = (MWMPoint) obj; + if (Double.doubleToLongBits(mLat) != Double.doubleToLongBits(other.mLat)) + return false; + if (Double.doubleToLongBits(mLon) != Double.doubleToLongBits(other.mLon)) + return false; + + return mName == null ? other.mName == null : mName.equals(other.mName); + } +} diff --git a/mapswithme-api/src/com/mapswithme/maps/api/MWMResponse.java b/mapswithme-api/src/com/mapswithme/maps/api/MWMResponse.java new file mode 100644 index 0000000..e2d865e --- /dev/null +++ b/mapswithme-api/src/com/mapswithme/maps/api/MWMResponse.java @@ -0,0 +1,77 @@ +/****************************************************************************** + 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 com.mapswithme.maps.api; + +import android.content.Context; +import android.content.Intent; + +public class MWMResponse +{ + private MWMPoint mPoint; + private double mZoomLevel; + + /** + * + * @return point, for which user requested more information in MapsWithMe application. + */ + public MWMPoint getPoint() { return mPoint; } + public boolean hasPoint() { return mPoint != null; } + public double getZoomLevel() { return mZoomLevel; } + + @Override + public String toString() + { + return "MWMResponse [SelectedPoint=" + mPoint + "]"; + } + + /** + * Factory method to extract response data from intent. + * + * @param context + * @param intent + * @return + */ + public static MWMResponse extractFromIntent(Context context, Intent intent) + { + final MWMResponse response = new MWMResponse(); + // parse point + final double lat = intent.getDoubleExtra(Const.EXTRA_MWM_RESPONSE_POINT_LAT, INVALID_LL); + final double lon = intent.getDoubleExtra(Const.EXTRA_MWM_RESPONSE_POINT_LON, INVALID_LL); + final String name = intent.getStringExtra(Const.EXTRA_MWM_RESPONSE_POINT_NAME); + final String id = intent.getStringExtra(Const.EXTRA_MWM_RESPONSE_POINT_ID); + + // parse additional info + response.mZoomLevel = intent.getDoubleExtra(Const.EXTRA_MWM_RESPONSE_ZOOM, 9); + + if (lat != INVALID_LL && lon != INVALID_LL) + response.mPoint = new MWMPoint(lat, lon, name, id); + else + response.mPoint = null; + + return response; + } + + private final static double INVALID_LL = Double.MIN_VALUE; + + private MWMResponse() {} +} diff --git a/mapswithme-api/src/com/mapswithme/maps/api/MapsWithMeApi.java b/mapswithme-api/src/com/mapswithme/maps/api/MapsWithMeApi.java new file mode 100644 index 0000000..e7fd9cd --- /dev/null +++ b/mapswithme-api/src/com/mapswithme/maps/api/MapsWithMeApi.java @@ -0,0 +1,159 @@ +/****************************************************************************** + 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 com.mapswithme.maps.api; + +import android.app.Activity; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.net.Uri; + + +public final class MapsWithMeApi +{ + + /** + * 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 showMapsWithMeUrl(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 MWMPoint(lat, lon, name, id)); + } + + public static void sendRequest(Activity caller, MwmRequest request) + { + final Intent mwmIntent = request.toIntent(caller); + + if (isMapsWithMeInstalled(caller)) + { + // Match activity for intent + final ActivityInfo aInfo = caller.getPackageManager().resolveActivity(mwmIntent, 0).activityInfo; + mwmIntent.setClassName(aInfo.packageName, aInfo.name); + caller.startActivity(mwmIntent); + } + else + (new DownloadMapsWithMeDialog(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, (String) null, (PendingIntent) null, new MWMPoint(lat, lon, name)); + } + + /** + * Shows single point on the map using specified zoom level in range from + * {@link MapsWithMeApi#ZOOM_MIN} to {@link MapsWithMeApi#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, (String) null, zoomLevel, (PendingIntent) null, new MWMPoint(lat, lon, name)); + } + + /** + * Shows set of points on the map. + * + * @param caller + * @param title + * @param points + */ + public static void showPointsOnMap(Activity caller, String title, MWMPoint... points) + { + showPointsOnMap(caller, title, null, points); + } + + /** + * Shows set of points on the maps and allows MapsWithMeApplication 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, MWMPoint... points) + { + showPointsOnMap(caller, title, -1, pendingIntent, points); + } + + private static void showPointsOnMap(Activity caller, String title, double zoomLevel, PendingIntent pendingIntent, + MWMPoint... points) + { + final MwmRequest request = new MwmRequest() + .setTitle(title) + .setZoomLevel(zoomLevel) + .setPendingIntent(pendingIntent) + .setPoints(points); + sendRequest(caller, request); + } + + public static void pickPoint(Activity caller, String title, PendingIntent pi) + { + final MwmRequest request = new MwmRequest() + .setTitle(title) + .setPickPointMode(true) + .setPendingIntent(pi); + sendRequest(caller, request); + } + + /** + * Detects if any version (Lite, Pro) of MapsWithMe, which supports API calls + * are installed on the device. + * + * @param context + * @return + */ + public static boolean isMapsWithMeInstalled(Context context) + { + final Intent intent = new Intent(Const.ACTION_MWM_REQUEST); + return context.getPackageManager().resolveActivity(intent, 0) != null; + } +} diff --git a/mapswithme-api/src/com/mapswithme/maps/api/MwmRequest.java b/mapswithme-api/src/com/mapswithme/maps/api/MwmRequest.java new file mode 100644 index 0000000..7a2335d --- /dev/null +++ b/mapswithme-api/src/com/mapswithme/maps/api/MwmRequest.java @@ -0,0 +1,173 @@ +package com.mapswithme.maps.api; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Locale; + +import android.annotation.SuppressLint; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; + +public class MwmRequest +{ + + // ** + private List<MWMPoint> mPoints = new ArrayList<MWMPoint>(); + private PendingIntent mPendingIntent; + private String mTitle; + private double mZoomLevel = 1; + private boolean mReturnOnBalloonClick; + private boolean mPickPoint = false; + private String mCustomButtonName = ""; + // ** + + public MwmRequest setCustomButtonName(String buttonName) + { + mCustomButtonName = buttonName != null ? buttonName : ""; + return this; + } + + public MwmRequest setTitle(String title) + { + mTitle = title; + return this; + } + + public MwmRequest setPickPointMode(boolean pickPoint) + { + mPickPoint = pickPoint; + return this; + } + + public MwmRequest addPoint(MWMPoint point) + { + mPoints.add(point); + return this; + } + + public MwmRequest addPoint(double lat, double lon, String name, String id) + { + return addPoint(new MWMPoint(lat, lon, name, id)); + } + + public MwmRequest setPoints(Collection<MWMPoint> points) + { + mPoints = new ArrayList<MWMPoint>(points); + return this; + } + + public MwmRequest setReturnOnBalloonClick(boolean doReturn) + { + mReturnOnBalloonClick = doReturn; + return this; + } + + public MwmRequest setZoomLevel(double zoomLevel) + { + mZoomLevel = zoomLevel; + return this; + } + + public MwmRequest setPendingIntent(PendingIntent pi) + { + mPendingIntent = pi; + return this; + } + + public Intent toIntent(Context context) + { + final Intent mwmIntent = new Intent(Const.ACTION_MWM_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. + */ + MwmRequest setPoints(MWMPoint[] points) + { + return setPoints(Arrays.asList(points)); + } + + // Below are utilities from MapsWithMeApi because we are not "Feature Envy" + + private static StringBuilder createMwmUrl(Context context, String title, double zoomLevel, List<MWMPoint> points) + { + final StringBuilder urlBuilder = new StringBuilder("mapswithme://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 MWMPoint 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()); + } + } + + return urlBuilder; + } + + private static String getCallbackAction(Context context) + { + return Const.CALLBACK_PREFIX + context.getPackageName(); + } + + @SuppressLint("NewApi") + 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 >= MapsWithMeApi.ZOOM_MIN && zoom <= MapsWithMeApi.ZOOM_MAX; + } + +} |