From 0eb7259e4c1265bd9a8844f908c699dee917e7a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=97=D0=B0=D1=86=D0=B5=D0=BF=D0=B8=D0=BD?= Date: Thu, 23 Apr 2020 18:17:18 +0300 Subject: [PATCH] [android] Added JNI for guides gallery and code to activate guides gallery on tap --- android/jni/CMakeLists.txt | 22 +- android/jni/com/mapswithme/maps/Framework.cpp | 10 +- .../jni/com/mapswithme/maps/guides/Guides.cpp | 85 +++++ .../jni/com/mapswithme/maps/guides/Guides.hpp | 9 + .../mapswithme/maps/guides/GuidesGallery.java | 331 ++++++++++++++++++ 5 files changed, 446 insertions(+), 11 deletions(-) create mode 100644 android/jni/com/mapswithme/maps/guides/Guides.cpp create mode 100644 android/jni/com/mapswithme/maps/guides/Guides.hpp create mode 100644 android/src/com/mapswithme/maps/guides/GuidesGallery.java diff --git a/android/jni/CMakeLists.txt b/android/jni/CMakeLists.txt index 653ba7f56c..33f4372c3d 100644 --- a/android/jni/CMakeLists.txt +++ b/android/jni/CMakeLists.txt @@ -22,13 +22,13 @@ set( SRC # JNI headers ../../private.h - com/mapswithme/util/FeatureIdBuilder.hpp com/mapswithme/core/jni_helper.hpp com/mapswithme/core/logging.hpp com/mapswithme/core/ScopedEnv.hpp com/mapswithme/core/ScopedLocalRef.hpp com/mapswithme/maps/discovery/Locals.hpp com/mapswithme/maps/Framework.hpp + com/mapswithme/maps/guides/Guides.hpp com/mapswithme/maps/promo/Promo.hpp com/mapswithme/maps/SearchEngine.hpp com/mapswithme/opengl/android_gl_utils.hpp @@ -37,6 +37,8 @@ set( com/mapswithme/opengl/gl3stub.h com/mapswithme/platform/GuiThread.hpp com/mapswithme/platform/Platform.hpp + com/mapswithme/util/FeatureIdBuilder.hpp + com/mapswithme/vulkan/android_vulkan_context_factory.hpp # JNI sources com/mapswithme/core/jni_helper.cpp @@ -47,17 +49,19 @@ set( com/mapswithme/maps/discovery/Locals.cpp com/mapswithme/maps/DisplayedCategories.cpp com/mapswithme/maps/DownloadResourcesLegacyActivity.cpp - com/mapswithme/maps/editor/OpeningHours.cpp com/mapswithme/maps/editor/Editor.cpp + com/mapswithme/maps/editor/OpeningHours.cpp com/mapswithme/maps/editor/OsmOAuth.cpp com/mapswithme/maps/Framework.cpp + com/mapswithme/maps/guides/Guides.cpp + com/mapswithme/maps/isolines/IsolinesManager.cpp com/mapswithme/maps/LightFramework.cpp - com/mapswithme/maps/LocationState.cpp com/mapswithme/maps/LocationHelper.cpp + com/mapswithme/maps/LocationState.cpp com/mapswithme/maps/MapFragment.cpp com/mapswithme/maps/MapManager.cpp - com/mapswithme/maps/MwmApplication.cpp com/mapswithme/maps/metrics/UserActionsLogger.cpp + com/mapswithme/maps/MwmApplication.cpp com/mapswithme/maps/onboarding/Onboarding.cpp com/mapswithme/maps/PrivateVariables.cpp com/mapswithme/maps/promo/Promo.cpp @@ -67,20 +71,19 @@ set( com/mapswithme/maps/settings/UnitLocale.cpp com/mapswithme/maps/sound/tts.cpp com/mapswithme/maps/Sponsored.cpp + com/mapswithme/maps/subway/SubwayManager.cpp com/mapswithme/maps/taxi/TaxiManager.cpp com/mapswithme/maps/TrackRecorder.cpp com/mapswithme/maps/TrafficState.cpp - com/mapswithme/maps/isolines/IsolinesManager.cpp - com/mapswithme/maps/subway/SubwayManager.cpp com/mapswithme/maps/ugc/UGC.cpp com/mapswithme/maps/UserMarkHelper.cpp com/mapswithme/opengl/android_gl_utils.cpp com/mapswithme/opengl/androidoglcontext.cpp com/mapswithme/opengl/androidoglcontextfactory.cpp com/mapswithme/opengl/gl3stub.c + com/mapswithme/platform/GuiThread.cpp com/mapswithme/platform/HttpThread.cpp com/mapswithme/platform/HttpUserAgent.cpp - com/mapswithme/platform/GuiThread.cpp com/mapswithme/platform/Language.cpp com/mapswithme/platform/Localization.cpp com/mapswithme/platform/MarketingService.cpp @@ -90,17 +93,16 @@ set( com/mapswithme/platform/SocketImpl.cpp com/mapswithme/util/Config.cpp com/mapswithme/util/GeoUtils.cpp + com/mapswithme/util/HttpBackgroundUploader.cpp com/mapswithme/util/HttpClient.cpp com/mapswithme/util/HttpUploader.cpp - com/mapswithme/util/HttpBackgroundUploader.cpp com/mapswithme/util/HttpUploaderUtils.cpp com/mapswithme/util/Language.cpp com/mapswithme/util/LoggerFactory.cpp com/mapswithme/util/NetworkPolicy.cpp - com/mapswithme/util/StringUtils.cpp com/mapswithme/util/statistics/PushwooshHelper.cpp + com/mapswithme/util/StringUtils.cpp com/mapswithme/vulkan/android_vulkan_context_factory.cpp - com/mapswithme/vulkan/android_vulkan_context_factory.hpp ) omim_add_library(mapswithme SHARED ${SRC}) diff --git a/android/jni/com/mapswithme/maps/Framework.cpp b/android/jni/com/mapswithme/maps/Framework.cpp index 5020333123..9d0bfcd9a8 100644 --- a/android/jni/com/mapswithme/maps/Framework.cpp +++ b/android/jni/com/mapswithme/maps/Framework.cpp @@ -1,10 +1,12 @@ #include "com/mapswithme/maps/Framework.hpp" + #include "com/mapswithme/core/jni_helper.hpp" +#include "com/mapswithme/maps/guides/Guides.hpp" #include "com/mapswithme/maps/UserMarkHelper.hpp" #include "com/mapswithme/opengl/androidoglcontextfactory.hpp" #include "com/mapswithme/platform/Platform.hpp" -#include "com/mapswithme/util/NetworkPolicy.hpp" #include "com/mapswithme/util/FeatureIdBuilder.hpp" +#include "com/mapswithme/util/NetworkPolicy.hpp" #include "com/mapswithme/vulkan/android_vulkan_context_factory.hpp" #include "map/chart_generator.hpp" @@ -1039,6 +1041,12 @@ Java_com_mapswithme_maps_Framework_nativePlacePageActivationListener(JNIEnv *env auto const elevationInfo = frm()->GetBookmarkManager().MakeElevationInfo(info.GetTrackId()); placePageDataRef.reset(usermark_helper::CreateElevationInfo(env, serverId, elevationInfo)); } + else if (info.IsGuide()) + { + auto const & guidesManager = frm()->GetGuidesManager(); + auto const gallery = guidesManager.GetGallery(); + placePageDataRef.reset(guides::CreateGallery(env, gallery)); + } else { placePageDataRef.reset(usermark_helper::CreateMapObject(env, info)); diff --git a/android/jni/com/mapswithme/maps/guides/Guides.cpp b/android/jni/com/mapswithme/maps/guides/Guides.cpp new file mode 100644 index 0000000000..428f5ec892 --- /dev/null +++ b/android/jni/com/mapswithme/maps/guides/Guides.cpp @@ -0,0 +1,85 @@ +#include "com/mapswithme/maps/guides/Guides.hpp" + +namespace +{ +jclass g_galleryClass = nullptr; +jclass g_itemClass = nullptr; +jclass g_cityParamsClass = nullptr; +jclass g_outdoorParamsClass = nullptr; +jmethodID g_galleryConstructor = nullptr; +jmethodID g_itemConstructor = nullptr; +jmethodID g_cityParamsConstructor = nullptr; +jmethodID g_outdoorParamsConstructor = nullptr; + +void PrepareClassRefs(JNIEnv *env) +{ + if (g_galleryClass != nullptr) + return; + + g_galleryClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/guides/GuidesGallery"); + g_galleryConstructor = jni::GetConstructorID(env, g_galleryClass, + "([Lcom/mapswithme/maps/guides/GuidesGallery$Item;)V"); + g_itemClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/guides/GuidesGallery$Item"); + // public Item(@NonNull String guideId, @NonNull String url, @NonNull String imageUrl, + // @NonNull String title, @NonNull String subTitle, int type, + // boolean downloaded, @Nullable CityParams cityParams, + // @Nullable OutdoorParams outdoorParams) + g_itemConstructor + = jni::GetConstructorID(env, g_itemClass, "(Ljava/lang/String;Ljava/lang/String;" + "Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;" + "IZLcom/mapswithme/maps/guides/GuidesGallery$CityParams;" + "Lcom/mapswithme/maps/guides/GuidesGallery$OutdoorParams;)" + "V"); + g_cityParamsClass + = jni::GetGlobalClassRef(env, "com/mapswithme/maps/guides/GuidesGallery$CityParams"); + // public CityParams(int bookmarksCount, boolean isTrackAvailable) + g_cityParamsConstructor = jni::GetConstructorID(env, g_cityParamsClass, "(IZ)V"); + g_outdoorParamsClass + = jni::GetGlobalClassRef(env, "com/mapswithme/maps/guides/GuidesGallery$OutdoorParams"); + // public OutdoorParams(double distance, long duration, int ascent) + g_outdoorParamsConstructor + = jni::GetConstructorID(env, g_outdoorParamsClass, "(DJI)V"); + jni::HandleJavaException(env); +} +} // namespace + +namespace guides +{ +jobject CreateGallery(JNIEnv *env, GuidesManager::GuidesGallery const & gallery) +{ + PrepareClassRefs(env); + + auto const itemBuilder = [](JNIEnv *env, GuidesManager::GuidesGallery::Item const & item) + { + jni::TScopedLocalRef guideId(env, jni::ToJavaString(env, item.m_guideId)); + jni::TScopedLocalRef url(env, jni::ToJavaString(env, item.m_url)); + jni::TScopedLocalRef imageUrl(env, jni::ToJavaString(env, item.m_imageUrl)); + jni::TScopedLocalRef title(env, jni::ToJavaString(env, item.m_title)); + jni::TScopedLocalRef subtitle(env, jni::ToJavaString(env, item.m_subTitle)); + auto const type = static_cast(item.m_type); + auto const downloaded = static_cast(item.m_downloaded); + jni::TScopedLocalRef cityParams(env, nullptr); + jni::TScopedLocalRef outdoorParams(env, nullptr); + if (item.m_type == GuidesManager::GuidesGallery::Item::Type::City) + { + cityParams.reset(env->NewObject(g_cityParamsClass, g_cityParamsConstructor, + static_cast(item.m_cityParams.m_bookmarksCount), + static_cast(item.m_cityParams.m_trackIsAvailable))); + } else if (item.m_type == GuidesManager::GuidesGallery::Item::Type::Outdoor) + { + outdoorParams.reset(env->NewObject(g_outdoorParamsClass, g_outdoorParamsConstructor, + static_cast(item.m_outdoorsParams.m_distance), + static_cast(item.m_outdoorsParams.m_duration), + static_cast(item.m_outdoorsParams.m_ascent))); + } + + return env->NewObject(g_itemClass, g_itemConstructor, guideId.get(), url.get(), imageUrl.get(), + title.get(), subtitle.get(), type, downloaded, cityParams.get(), + outdoorParams.get()); + }; + + jni::TScopedLocalObjectArrayRef items(env, jni::ToJavaArray(env, g_itemClass, gallery.m_items, + itemBuilder)); + return env->NewObject(g_galleryClass, g_galleryConstructor, items.get()); +} +} // namespace guides diff --git a/android/jni/com/mapswithme/maps/guides/Guides.hpp b/android/jni/com/mapswithme/maps/guides/Guides.hpp new file mode 100644 index 0000000000..dfcb815d52 --- /dev/null +++ b/android/jni/com/mapswithme/maps/guides/Guides.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "com/mapswithme/core/jni_helper.hpp" +#include "map/guides_manager.hpp" + +namespace guides +{ +jobject CreateGallery(JNIEnv * env, GuidesManager::GuidesGallery const & gallery); +} // namespace diff --git a/android/src/com/mapswithme/maps/guides/GuidesGallery.java b/android/src/com/mapswithme/maps/guides/GuidesGallery.java new file mode 100644 index 0000000000..59fe476770 --- /dev/null +++ b/android/src/com/mapswithme/maps/guides/GuidesGallery.java @@ -0,0 +1,331 @@ +package com.mapswithme.maps.guides; + +import android.os.Parcel; +import android.os.Parcelable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.mapswithme.maps.widget.placepage.PlacePageData; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class GuidesGallery implements PlacePageData +{ + @NonNull + private final List mItems; + + public GuidesGallery(@NonNull Item[] items) + { + mItems = Arrays.asList(items); + } + + @NonNull + public List getItems() + { + return Collections.unmodifiableList(mItems); + } + + protected GuidesGallery(Parcel in) + { + List items = new ArrayList<>(); + in.readTypedList(items, Item.CREATOR); + mItems = items; + } + + @Override + public int describeContents() + { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) + { + // All collections are deserialized AFTER non-collection and primitive type objects, + // so collections must be always serialized at the end. + dest.writeTypedList(mItems); + } + + public static final Creator CREATOR = new Creator() + { + @Override + public GuidesGallery createFromParcel(Parcel in) + { + return new GuidesGallery(in); + } + + @Override + public GuidesGallery[] newArray(int size) + { + return new GuidesGallery[size]; + } + }; + + public static class Item implements Parcelable + { + @NonNull + private final String mGuideId; + @NonNull + private final String mUrl; + @NonNull + private final String mImageUrl; + @NonNull + private final String mTitle; + @NonNull + private final String mSubTitle; + @NonNull + private final Type mType; + private final boolean mDownloaded; + @Nullable + private final CityParams mCityParams; + @Nullable + private final OutdoorParams mOutdoorParams; + + public Item(@NonNull String guideId, @NonNull String url, @NonNull String imageUrl, + @NonNull String title, @NonNull String subTitle, int type, + boolean downloaded, @Nullable CityParams cityParams, + @Nullable OutdoorParams outdoorParams) + { + mGuideId = guideId; + mUrl = url; + mImageUrl = imageUrl; + mTitle = title; + mSubTitle = subTitle; + mType = Type.values()[type]; + mDownloaded = downloaded; + mCityParams = cityParams; + mOutdoorParams = outdoorParams; + } + + protected Item(Parcel in) + { + mGuideId = in.readString(); + mUrl = in.readString(); + mImageUrl = in.readString(); + mTitle = in.readString(); + mSubTitle = in.readString(); + mType = Type.values()[in.readInt()]; + mDownloaded = in.readByte() != 0; + mCityParams = in.readParcelable(CityParams.class.getClassLoader()); + mOutdoorParams = in.readParcelable(OutdoorParams.class.getClassLoader()); + } + + public static final Creator CREATOR = new Creator() + { + @Override + public Item createFromParcel(Parcel in) + { + return new Item(in); + } + + @Override + public Item[] newArray(int size) + { + return new Item[size]; + } + }; + + @NonNull + public String getGuideId() + { + return mGuideId; + } + + @NonNull + public String getUrl() + { + return mUrl; + } + + @NonNull + public String getImageUrl() + { + return mImageUrl; + } + + @NonNull + public String getTitle() + { + return mTitle; + } + + @NonNull + public String getSubTitle() + { + return mSubTitle; + } + + @NonNull + public Type getType() + { + return mType; + } + + public boolean isDownloaded() + { + return mDownloaded; + } + + @Nullable + public CityParams getCityParams() + { + return mCityParams; + } + + @Nullable + public OutdoorParams getOutdoorParams() + { + return mOutdoorParams; + } + + @Override + public int describeContents() + { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) + { + dest.writeString(mGuideId); + dest.writeString(mUrl); + dest.writeString(mImageUrl); + dest.writeString(mTitle); + dest.writeString(mSubTitle); + dest.writeInt(mType.ordinal()); + dest.writeByte((byte) (mDownloaded ? 1 : 0)); + dest.writeParcelable(mCityParams, flags); + dest.writeParcelable(mOutdoorParams, flags); + } + } + + public static class CityParams implements Parcelable + { + private final int mBookmarksCount; + private final boolean mIsTrackAvailable; + + public CityParams(int bookmarksCount, boolean isTrackAvailable) + { + mBookmarksCount = bookmarksCount; + mIsTrackAvailable = isTrackAvailable; + } + + protected CityParams(Parcel in) + { + mBookmarksCount = in.readInt(); + mIsTrackAvailable = in.readByte() != 0; + } + + public static final Creator CREATOR = new Creator() + { + @Override + public CityParams createFromParcel(Parcel in) + { + return new CityParams(in); + } + + @Override + public CityParams[] newArray(int size) + { + return new CityParams[size]; + } + }; + + public int getBookmarksCount() + { + return mBookmarksCount; + } + + public boolean isTrackAvailable() + { + return mIsTrackAvailable; + } + + @Override + public int describeContents() + { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) + { + dest.writeInt(mBookmarksCount); + dest.writeByte((byte) (mIsTrackAvailable ? 1 : 0)); + } + } + + public static class OutdoorParams implements Parcelable + { + private final double mDistance; + private final long mDuration; + private final int mAscent; + + public OutdoorParams(double distance, long duration, int ascent) + { + mDistance = distance; + mDuration = duration; + mAscent = ascent; + } + + protected OutdoorParams(Parcel in) + { + mDistance = in.readDouble(); + mDuration = in.readLong(); + mAscent = in.readInt(); + } + + public static final Creator CREATOR = new Creator() + { + @Override + public OutdoorParams createFromParcel(Parcel in) + { + return new OutdoorParams(in); + } + + @Override + public OutdoorParams[] newArray(int size) + { + return new OutdoorParams[size]; + } + }; + + public double getDistance() + { + return mDistance; + } + + public long getDuration() + { + return mDuration; + } + + public int getAscent() + { + return mAscent; + } + + @Override + public int describeContents() + { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) + { + dest.writeDouble(mDistance); + dest.writeLong(mDuration); + dest.writeInt(mAscent); + } + } + + enum Type + { + City, + Outdoor + } +}