diff --git a/.gitignore b/.gitignore index 02e6ae4ce7..38baa9e9eb 100644 --- a/.gitignore +++ b/.gitignore @@ -133,3 +133,7 @@ android/fabric.properties android/pushwoosh.properties android/res/values/google-service.xml server + +*.li + +*.autosave diff --git a/android/jni/com/mapswithme/maps/Framework.cpp b/android/jni/com/mapswithme/maps/Framework.cpp index 361dba42b5..7557f82d8a 100644 --- a/android/jni/com/mapswithme/maps/Framework.cpp +++ b/android/jni/com/mapswithme/maps/Framework.cpp @@ -513,6 +513,17 @@ void Framework::EnableDownloadOn3g() m_work.GetDownloadingPolicy().EnableCellularDownload(true); } +void Framework::RequestUberProducts(ms::LatLon const & from, ms::LatLon const & to, + uber::ProductsCallback const & callback) +{ + m_work.GetUberApi().GetAvailableProducts(from, to, callback); +} + +uber::RideRequestLinks Framework::GetUberLinks(string const & productId, ms::LatLon const & from, ms::LatLon const & to) +{ + return uber::Api::GetRideRequestLinks(productId, from, to); +} + } // namespace android @@ -1183,4 +1194,64 @@ Java_com_mapswithme_maps_Framework_nativeSetVisibleRect(JNIEnv * env, jclass, ji frm()->SetVisibleViewport(m2::RectD(left, top, right, bottom)); } -} // extern "C" +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_Framework_nativeRequestUberProducts(JNIEnv * env, jclass, jdouble srcLat, jdouble srcLon, + jdouble dstLat, jdouble dstLon) +{ + ms::LatLon const from(srcLat, srcLon); + ms::LatLon const to(dstLat, dstLon); + + g_framework->RequestUberProducts(from, to, [](vector const & products, size_t const requestId) + { + GetPlatform().RunOnGuiThread([=]() + { + JNIEnv * env = jni::GetEnv(); + jclass const productClass = env->FindClass("com/mapswithme/maps/api/uber/UberInfo$Product"); + jmethodID const productConstructor = jni::GetConstructorID(env, productClass, + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + + auto uberProducts = jni::ToJavaArray(env, productClass, products, + [productClass, productConstructor](JNIEnv * env, uber::Product const & item) + { + return env->NewObject(productClass, productConstructor, + jni::ToJavaString(env, item.m_productId), + jni::ToJavaString(env, item.m_name), + jni::ToJavaString(env, item.m_time), + jni::ToJavaString(env, item.m_price)); + }); + + jclass const routingControllerClass = env->FindClass("com/mapswithme/maps/routing/RoutingController"); + jmethodID const routingControllerGetMethod = jni::GetStaticMethodID(env, routingControllerClass, "get", + "()Lcom/mapswithme/maps/routing/RoutingController;"); + jobject const routingControllerInstance = env->CallStaticObjectMethod(routingControllerClass, routingControllerGetMethod); + + jmethodID const uberInfoCallbackMethod = jni::GetMethodID(env, routingControllerInstance, "onUberInfoReceived", + "(Lcom/mapswithme/maps/api/uber/UberInfo;)V"); + + jclass const uberInfoClass = env->FindClass("com/mapswithme/maps/api/uber/UberInfo"); + jmethodID const uberInfoConstructor = jni::GetConstructorID(env, uberInfoClass, + "([Lcom/mapswithme/maps/api/uber/UberInfo$Product;)V"); + + env->CallVoidMethod(routingControllerInstance, uberInfoCallbackMethod, env->NewObject(uberInfoClass, + uberInfoConstructor, uberProducts)); + }); + }); +} + +JNIEXPORT jobject JNICALL +Java_com_mapswithme_maps_Framework_nativeGetUberLinks(JNIEnv * env, jclass, jstring productId, jdouble srcLat, + jdouble srcLon, jdouble dstLat, jdouble dstLon) +{ + ms::LatLon const from(srcLat, srcLon); + ms::LatLon const to(dstLat, dstLon); + + uber::RideRequestLinks const links = android::Framework::GetUberLinks(jni::ToNativeString(env, productId), from, to); + + jclass const uberLinksClass = env->FindClass("com/mapswithme/maps/api/uber/UberLinks"); + jmethodID const uberLinksConstructor = jni::GetConstructorID(env, uberLinksClass, + "(Ljava/lang/String;Ljava/lang/String;)V"); + return env->NewObject(uberLinksClass, uberLinksConstructor, jni::ToJavaString(env, links.m_deepLink), + jni::ToJavaString(env, links.m_universalLink)); +} +}// extern "C" + diff --git a/android/jni/com/mapswithme/maps/Framework.hpp b/android/jni/com/mapswithme/maps/Framework.hpp index 12fcdcd85d..09f7d9ba8b 100644 --- a/android/jni/com/mapswithme/maps/Framework.hpp +++ b/android/jni/com/mapswithme/maps/Framework.hpp @@ -166,6 +166,9 @@ namespace android bool IsAutoRetryDownloadFailed(); bool IsDownloadOn3gEnabled(); void EnableDownloadOn3g(); + + void RequestUberProducts(ms::LatLon const & from, ms::LatLon const & to, uber::ProductsCallback const & callback); + static uber::RideRequestLinks GetUberLinks(string const & productId, ms::LatLon const & from, ms::LatLon const & to); }; } diff --git a/android/jni/com/mapswithme/maps/SponsoredHotel.cpp b/android/jni/com/mapswithme/maps/SponsoredHotel.cpp index c420bc4320..986709c2ec 100644 --- a/android/jni/com/mapswithme/maps/SponsoredHotel.cpp +++ b/android/jni/com/mapswithme/maps/SponsoredHotel.cpp @@ -2,9 +2,7 @@ #include "../core/jni_helper.hpp" #include "../platform/Platform.hpp" - #include "map/place_page_info.hpp" - #include "partners_api/booking_api.hpp" #include "std/bind.hpp" diff --git a/android/res/drawable-hdpi/ic_logo_uber.png b/android/res/drawable-hdpi/ic_logo_uber.png new file mode 100644 index 0000000000..157cd1659f Binary files /dev/null and b/android/res/drawable-hdpi/ic_logo_uber.png differ diff --git a/android/res/drawable-hdpi/ic_taxi.png b/android/res/drawable-hdpi/ic_taxi.png new file mode 100644 index 0000000000..3c5996a596 Binary files /dev/null and b/android/res/drawable-hdpi/ic_taxi.png differ diff --git a/android/res/drawable-mdpi/ic_logo_uber.png b/android/res/drawable-mdpi/ic_logo_uber.png new file mode 100644 index 0000000000..5d0eee863f Binary files /dev/null and b/android/res/drawable-mdpi/ic_logo_uber.png differ diff --git a/android/res/drawable-mdpi/ic_taxi.png b/android/res/drawable-mdpi/ic_taxi.png new file mode 100644 index 0000000000..aa8d167fba Binary files /dev/null and b/android/res/drawable-mdpi/ic_taxi.png differ diff --git a/android/res/drawable-xhdpi/ic_logo_uber.png b/android/res/drawable-xhdpi/ic_logo_uber.png new file mode 100644 index 0000000000..9f0ddb7ccd Binary files /dev/null and b/android/res/drawable-xhdpi/ic_logo_uber.png differ diff --git a/android/res/drawable-xhdpi/ic_taxi.png b/android/res/drawable-xhdpi/ic_taxi.png new file mode 100644 index 0000000000..0f7f9e0d66 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_taxi.png differ diff --git a/android/res/drawable-xxhdpi/ic_logo_uber.png b/android/res/drawable-xxhdpi/ic_logo_uber.png new file mode 100644 index 0000000000..32e0674db7 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_logo_uber.png differ diff --git a/android/res/drawable-xxhdpi/ic_taxi.png b/android/res/drawable-xxhdpi/ic_taxi.png new file mode 100644 index 0000000000..af67db7f08 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_taxi.png differ diff --git a/android/res/drawable-xxxhdpi/ic_logo_uber.png b/android/res/drawable-xxxhdpi/ic_logo_uber.png new file mode 100644 index 0000000000..5570496517 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_logo_uber.png differ diff --git a/android/res/drawable-xxxhdpi/ic_taxi.png b/android/res/drawable-xxxhdpi/ic_taxi.png new file mode 100644 index 0000000000..a809111fef Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_taxi.png differ diff --git a/android/res/layout/menu_route_plan_line.xml b/android/res/layout/menu_route_plan_line.xml index a778073571..8e632d8a79 100644 --- a/android/res/layout/menu_route_plan_line.xml +++ b/android/res/layout/menu_route_plan_line.xml @@ -6,7 +6,10 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> - + + + \ No newline at end of file diff --git a/android/res/layout/routing_plan.xml b/android/res/layout/routing_plan.xml index 118b4e9d96..3b9fc31da4 100644 --- a/android/res/layout/routing_plan.xml +++ b/android/res/layout/routing_plan.xml @@ -73,9 +73,17 @@ style="@style/MwmWidget.ProgressWheel.RoutingPlan" android:layout_marginTop="@dimen/routing_selector_wheel_margin" android:layout_marginBottom="@dimen/routing_selector_wheel_margin" - android:layout_marginRight="@dimen/routing_selector_wheel_margin" + android:layout_marginRight="12dp" tools:visibility="visible" /> + + + + + + + + + diff --git a/android/res/layout/uber_panel.xml b/android/res/layout/uber_panel.xml new file mode 100644 index 0000000000..05b9b6a6ea --- /dev/null +++ b/android/res/layout/uber_panel.xml @@ -0,0 +1,42 @@ + + + + + + + + diff --git a/android/src/com/mapswithme/maps/Framework.java b/android/src/com/mapswithme/maps/Framework.java index 016dcd5bd5..438b52ac02 100644 --- a/android/src/com/mapswithme/maps/Framework.java +++ b/android/src/com/mapswithme/maps/Framework.java @@ -12,6 +12,7 @@ import java.lang.annotation.RetentionPolicy; import com.mapswithme.maps.api.ParsedRoutingData; import com.mapswithme.maps.api.ParsedUrlMwmRequest; +import com.mapswithme.maps.api.uber.UberLinks; import com.mapswithme.maps.bookmarks.data.DistanceAndAzimut; import com.mapswithme.maps.bookmarks.data.MapObject; import com.mapswithme.maps.routing.RoutingInfo; @@ -28,12 +29,14 @@ public class Framework public static final int MAP_STYLE_CLEAR = 2; @Retention(RetentionPolicy.SOURCE) - @IntDef({ROUTER_TYPE_VEHICLE, ROUTER_TYPE_PEDESTRIAN, ROUTER_TYPE_BICYCLE}) + @IntDef({ROUTER_TYPE_VEHICLE, ROUTER_TYPE_PEDESTRIAN, ROUTER_TYPE_BICYCLE, ROUTER_TYPE_TAXI}) + public @interface RouterType {} public static final int ROUTER_TYPE_VEHICLE = 0; public static final int ROUTER_TYPE_PEDESTRIAN = 1; public static final int ROUTER_TYPE_BICYCLE = 2; + public static final int ROUTER_TYPE_TAXI = 3; @SuppressWarnings("unused") public interface MapObjectListener @@ -258,4 +261,10 @@ public class Framework public static native String nativeGetActiveObjectFormattedCuisine(); public static native void nativeSetVisibleRect(int left, int top, int right, int bottom); + + public static native void nativeRequestUberProducts(double srcLat, double srcLon, double dstLat, double dstLon); + + @NonNull + public static native UberLinks nativeGetUberLinks(@NonNull String productId, double srcLon, double srcLat, + double dstLat, double dstLon); } diff --git a/android/src/com/mapswithme/maps/MwmActivity.java b/android/src/com/mapswithme/maps/MwmActivity.java index 9313971013..ca87b27ed3 100644 --- a/android/src/com/mapswithme/maps/MwmActivity.java +++ b/android/src/com/mapswithme/maps/MwmActivity.java @@ -28,6 +28,7 @@ import com.mapswithme.maps.api.ParsedMwmRequest; import com.mapswithme.maps.api.ParsedRoutingData; import com.mapswithme.maps.api.ParsedUrlMwmRequest; import com.mapswithme.maps.api.RoutePoint; +import com.mapswithme.maps.api.uber.UberInfo; import com.mapswithme.maps.base.BaseMwmFragmentActivity; import com.mapswithme.maps.base.OnBackPressListener; import com.mapswithme.maps.bookmarks.BookmarkCategoriesActivity; @@ -904,8 +905,6 @@ public class MwmActivity extends BaseMwmFragmentActivity { super.onStart(); RoutingController.get().attach(this); - if (!mIsFragmentContainer) - mRoutingPlanInplaceController.setStartButton(); if (MapFragment.nativeIsEngineCreated()) LocationHelper.INSTANCE.attach(this); @@ -1406,17 +1405,21 @@ public class MwmActivity extends BaseMwmFragmentActivity } @Override - public void onRouteBuilt(@Framework.RouterType int router) + public void onRouteBuilt() { if (mIsFragmentContainer) { RoutingPlanFragment fragment = (RoutingPlanFragment) getFragment(RoutingPlanFragment.class); if (fragment != null) - fragment.showRouteAltitudeChart(router != Framework.ROUTER_TYPE_VEHICLE); + { + fragment.showRouteAltitudeChart(); + fragment.setStartButton(); + } } else { - mRoutingPlanInplaceController.showRouteAltitudeChart(router != Framework.ROUTER_TYPE_VEHICLE); + mRoutingPlanInplaceController.showRouteAltitudeChart(); + mRoutingPlanInplaceController.setStartButton(); } } @@ -1435,6 +1438,12 @@ public class MwmActivity extends BaseMwmFragmentActivity } } + @Override + public void onUberInfoReceived(@NonNull UberInfo info) + { + mRoutingPlanInplaceController.showUberInfo(info); + } + boolean isFirstStart() { boolean res = mFirstStart; diff --git a/android/src/com/mapswithme/maps/api/uber/UberInfo.java b/android/src/com/mapswithme/maps/api/uber/UberInfo.java new file mode 100644 index 0000000000..e5ed494740 --- /dev/null +++ b/android/src/com/mapswithme/maps/api/uber/UberInfo.java @@ -0,0 +1,87 @@ +package com.mapswithme.maps.api.uber; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import java.util.Arrays; + +public class UberInfo +{ + @Nullable + private final Product[] mProducts; + + public UberInfo(@Nullable Product[] products) + { + mProducts = products; + } + + @Nullable + public Product[] getProducts() + { + return mProducts; + } + + @Override + public String toString() + { + return "UberInfo{" + + "mProducts=" + Arrays.toString(mProducts) + + '}'; + } + + public static class Product + { + @NonNull + private final String mProductId; + @NonNull + private final String mName; + @NonNull + private final String mTime; + @NonNull + private final String mPrice; + + public Product(@NonNull String productId, @NonNull String name, @NonNull String time, @NonNull String price) + { + mProductId = productId; + mName = name; + mTime = time; + mPrice = price; + } + + @NonNull + public String getProductId() + { + return mProductId; + } + + @NonNull + public String getName() + { + return mName; + } + + @NonNull + public String getTime() + { + return mTime; + } + + @NonNull + public String getPrice() + { + return mPrice; + } + + @Override + public String toString() + { + return "Product{" + + "mProductId='" + mProductId + '\'' + + ", mName='" + mName + '\'' + + ", mTime='" + mTime + '\'' + + ", mPrice='" + mPrice + '\'' + + '}'; + } + } +} + diff --git a/android/src/com/mapswithme/maps/api/uber/UberLinks.java b/android/src/com/mapswithme/maps/api/uber/UberLinks.java new file mode 100644 index 0000000000..3b83b5ed84 --- /dev/null +++ b/android/src/com/mapswithme/maps/api/uber/UberLinks.java @@ -0,0 +1,29 @@ +package com.mapswithme.maps.api.uber; + +import android.support.annotation.NonNull; + +public class UberLinks +{ + @NonNull + private final String mDeepLink; + @NonNull + private final String mUniversalLink; + + public UberLinks(@NonNull String deepLink, @NonNull String universalLink) + { + mDeepLink = deepLink; + mUniversalLink = universalLink; + } + + @NonNull + public String getDeepLink() + { + return mDeepLink; + } + + @NonNull + public String getUniversalLink() + { + return mUniversalLink; + } +} diff --git a/android/src/com/mapswithme/maps/routing/RoutingController.java b/android/src/com/mapswithme/maps/routing/RoutingController.java index 4dc809cfd4..c4406dedaa 100644 --- a/android/src/com/mapswithme/maps/routing/RoutingController.java +++ b/android/src/com/mapswithme/maps/routing/RoutingController.java @@ -5,25 +5,26 @@ import android.content.Context; import android.content.DialogInterface; import android.support.annotation.DimenRes; import android.support.annotation.IntRange; +import android.support.annotation.MainThread; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.FragmentActivity; import android.support.v7.app.AlertDialog; import android.text.TextUtils; import android.view.View; -import android.widget.Button; import android.widget.TextView; import com.mapswithme.maps.Framework; import com.mapswithme.maps.MwmApplication; import com.mapswithme.maps.R; +import com.mapswithme.maps.api.uber.UberInfo; +import com.mapswithme.maps.api.uber.UberLinks; import com.mapswithme.maps.bookmarks.data.MapObject; import com.mapswithme.maps.downloader.MapManager; import com.mapswithme.maps.location.LocationHelper; import com.mapswithme.util.Config; import com.mapswithme.util.StringUtils; import com.mapswithme.util.ThemeSwitcher; -import com.mapswithme.util.UiUtils; import com.mapswithme.util.Utils; import com.mapswithme.util.concurrency.UiThread; import com.mapswithme.util.log.DebugLogger; @@ -63,7 +64,8 @@ public class RoutingController void showDownloader(boolean openDownloaded); void updateMenu(); void updatePoints(); - void onRouteBuilt(@Framework.RouterType int router); + void onRouteBuilt(); + void onUberInfoReceived(@NonNull UberInfo info); /** * @param progress progress to be displayed. @@ -72,10 +74,9 @@ public class RoutingController } private static final RoutingController sInstance = new RoutingController(); - private final Logger mLogger = new DebugLogger("RCSTATE"); - + private static final Logger mLogger = new DebugLogger("RCSTATE"); + @Nullable private Container mContainer; - private Button mStartButton; private BuildState mBuildState = BuildState.NONE; private State mState = State.NONE; @@ -118,7 +119,7 @@ public class RoutingController setBuildState(BuildState.BUILT); mLastBuildProgress = 100; if (mContainer != null) - mContainer.onRouteBuilt(mLastRouterType); + mContainer.onRouteBuilt(); } processRoutingEvent(); @@ -227,7 +228,6 @@ public class RoutingController public void detach() { mContainer = null; - mStartButton = null; } public void restore() @@ -400,25 +400,6 @@ public class RoutingController private void updatePlan() { updateProgress(); - updateStartButton(); - } - - private void updateStartButton() - { - mLogger.d("updateStartButton" + (mStartButton == null ? ": SKIP" : "")); - - if (mStartButton == null) - return; - - mStartButton.setEnabled(mState == State.PREPARE && mBuildState == BuildState.BUILT); - UiUtils.updateAccentButton(mStartButton); - } - - void setStartButton(@Nullable Button button) - { - mLogger.d("setStartButton"); - mStartButton = button; - updateStartButton(); } private void cancelInternal() @@ -767,4 +748,31 @@ public class RoutingController return true; } + + void requestUberInfo() + { + MapObject start = RoutingController.get().getStartPoint(); + MapObject end = RoutingController.get().getEndPoint(); + Framework.nativeRequestUberProducts(start.getLat(), start.getLon(), end.getLat(), end.getLon()); + } + + @NonNull + UberLinks getUberLink(@NonNull String productId) + { + MapObject start = RoutingController.get().getStartPoint(); + MapObject end = RoutingController.get().getEndPoint(); + return Framework.nativeGetUberLinks(productId, start.getLat(), start.getLon(), end.getLat(), end.getLon()); + } + + /** + * Called from the native code + * @param info this object contains information about Uber products + */ + @MainThread + private void onUberInfoReceived(@NonNull UberInfo info) + { + mLogger.d("onUberInfoReceived uberInfo = " + info); + if (mContainer != null) + mContainer.onUberInfoReceived(info); + } } diff --git a/android/src/com/mapswithme/maps/routing/RoutingPlanController.java b/android/src/com/mapswithme/maps/routing/RoutingPlanController.java index 46b354457a..79667a63aa 100644 --- a/android/src/com/mapswithme/maps/routing/RoutingPlanController.java +++ b/android/src/com/mapswithme/maps/routing/RoutingPlanController.java @@ -7,22 +7,32 @@ import android.os.Bundle; import android.support.annotation.DrawableRes; import android.support.annotation.IdRes; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.view.PagerAdapter; +import android.support.v4.view.ViewPager; import android.view.View; import android.view.ViewGroup; +import android.widget.Button; import android.widget.CompoundButton; import android.widget.ImageView; import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.TextView; +import android.widget.Toast; import com.mapswithme.maps.Framework; import com.mapswithme.maps.MwmApplication; import com.mapswithme.maps.R; +import com.mapswithme.maps.api.uber.UberInfo; +import com.mapswithme.maps.api.uber.UberLinks; +import com.mapswithme.maps.uber.UberAdapter; +import com.mapswithme.maps.widget.DotPager; import com.mapswithme.maps.widget.RotateDrawable; import com.mapswithme.maps.widget.ToolbarController; import com.mapswithme.maps.widget.WheelProgressView; import com.mapswithme.util.Graphics; import com.mapswithme.util.UiUtils; +import com.mapswithme.util.Utils; import com.mapswithme.util.statistics.AlohaHelper; import com.mapswithme.util.statistics.Statistics; @@ -38,7 +48,9 @@ public class RoutingPlanController extends ToolbarController private final WheelProgressView mProgressVehicle; private final WheelProgressView mProgressPedestrian; private final WheelProgressView mProgressBicycle; + private final WheelProgressView mProgressTaxi; private final View mAltitudeChartFrame; + private final View mUberFrame; private final RotateDrawable mToggleImage = new RotateDrawable(R.drawable.ic_down); private int mFrameHeight; @@ -46,6 +58,9 @@ public class RoutingPlanController extends ToolbarController private boolean mOpen; private boolean mAltitudeChartShown; + @Nullable + private UberInfo.Product mUberProduct; + private RadioButton setupRouterButton(@IdRes int buttonId, final @DrawableRes int iconRes, View.OnClickListener clickListener) { CompoundButton.OnCheckedChangeListener listener = new CompoundButton.OnCheckedChangeListener() @@ -66,7 +81,7 @@ public class RoutingPlanController extends ToolbarController return rb; } - public RoutingPlanController(View root, Activity activity) + RoutingPlanController(View root, Activity activity) { super(root, activity); mFrame = root; @@ -108,10 +123,23 @@ public class RoutingPlanController extends ToolbarController } }); + setupRouterButton(R.id.taxi, R.drawable.ic_taxi, new View.OnClickListener() + { + @Override + public void onClick(View v) + { + RoutingController.get().requestUberInfo(); + AlohaHelper.logClick(AlohaHelper.ROUTING_TAXI_SET); + Statistics.INSTANCE.trackEvent(Statistics.EventName.ROUTING_TAXI_SET); + RoutingController.get().setRouterType(Framework.ROUTER_TYPE_TAXI); + } + }); + View progressFrame = mToolbar.findViewById(R.id.progress_frame); mProgressVehicle = (WheelProgressView) progressFrame.findViewById(R.id.progress_vehicle); mProgressPedestrian = (WheelProgressView) progressFrame.findViewById(R.id.progress_pedestrian); mProgressBicycle = (WheelProgressView) progressFrame.findViewById(R.id.progress_bicycle); + mProgressTaxi = (WheelProgressView) progressFrame.findViewById(R.id.progress_taxi); View altitudeChartFrame = mFrame.findViewById(R.id.altitude_chart_panel); if (altitudeChartFrame == null) @@ -120,6 +148,13 @@ public class RoutingPlanController extends ToolbarController mAltitudeChartFrame = altitudeChartFrame; UiUtils.hide(mAltitudeChartFrame); + View uberFrame = mFrame.findViewById(R.id.uber_panel); + if (uberFrame == null) + uberFrame = mActivity.findViewById(R.id.uber_panel); + + mUberFrame = uberFrame; + UiUtils.hide(mUberFrame); + mToggle.setImageDrawable(mToggleImage); mToggle.setOnClickListener(new View.OnClickListener() { @@ -178,6 +213,10 @@ public class RoutingPlanController extends ToolbarController private void showAltitudeChartAndRoutingDetails() { + if (isTaxiRouteChecked()) + return; + + UiUtils.hide(mUberFrame); UiUtils.show(mAltitudeChartFrame); mAltitudeChartShown = true; showRoutingDetails(); @@ -219,7 +258,7 @@ public class RoutingPlanController extends ToolbarController public void updateBuildProgress(int progress, @Framework.RouterType int router) { updateProgressLabels(); - UiUtils.invisible(mProgressVehicle, mProgressPedestrian, mProgressBicycle); + UiUtils.invisible(mProgressVehicle, mProgressPedestrian, mProgressBicycle, mProgressTaxi); WheelProgressView progressView; if (router == Framework.ROUTER_TYPE_VEHICLE) { @@ -231,6 +270,11 @@ public class RoutingPlanController extends ToolbarController mRouterTypes.check(R.id.pedestrian); progressView = mProgressPedestrian; } + else if (router == Framework.ROUTER_TYPE_TAXI) + { + mRouterTypes.check(R.id.taxi); + progressView = mProgressTaxi; + } else { mRouterTypes.check(R.id.bicycle); @@ -253,7 +297,7 @@ public class RoutingPlanController extends ToolbarController showSlots(!mOpen, true); } - protected void showSlots(final boolean show, final boolean animate) + void showSlots(final boolean show, final boolean animate) { if (!checkFrameHeight()) { @@ -296,12 +340,17 @@ public class RoutingPlanController extends ToolbarController } } - protected boolean isVehicleRouteChecked() + private boolean isVehicleRouteChecked() { return mRouterTypes.getCheckedRadioButtonId() == R.id.vehicle; } - public void disableToggle() + private boolean isTaxiRouteChecked() + { + return mRouterTypes.getCheckedRadioButtonId() == R.id.taxi; + } + + void disableToggle() { UiUtils.hide(mToggle); showSlots(true, false); @@ -312,15 +361,15 @@ public class RoutingPlanController extends ToolbarController return mOpen; } - public void showRouteAltitudeChart(boolean show) + public void showRouteAltitudeChart() { ImageView altitudeChart = (ImageView) mFrame.findViewById(R.id.altitude_chart); - showRouteAltitudeChartInternal(show, altitudeChart); + showRouteAltitudeChartInternal(altitudeChart); } - protected void showRouteAltitudeChartInternal(boolean show, ImageView altitudeChart) + void showRouteAltitudeChartInternal(@NonNull ImageView altitudeChart) { - if (!show) + if (isVehicleRouteChecked()) { UiUtils.hide(altitudeChart); return; @@ -336,14 +385,80 @@ public class RoutingPlanController extends ToolbarController } } - public void saveAltitudeChartState(@NonNull Bundle outState) + public void showUberInfo(@NonNull UberInfo info) + { + final UberInfo.Product[] products = info.getProducts(); + if (products == null || info.getProducts().length == 0) + { + //TOOD: show the panel "There is no taxi here" + return; + } + + mUberProduct = products[0]; + final PagerAdapter adapter = new UberAdapter(mActivity, products); + DotPager pager = new DotPager.Builder(mActivity, (ViewPager) mUberFrame.findViewById(R.id.pager), adapter) + .setIndicatorContainer((ViewGroup) mUberFrame.findViewById(R.id.indicator)) + .setPageChangedListener(new DotPager.OnPageChangedListener() + { + @Override + public void onPageChanged(int position) + { + mUberProduct = products[position]; + } + }).build(); + pager.show(); + UiUtils.hide(mAltitudeChartFrame); + setStartButton(); + UiUtils.show(mUberFrame); + } + + void saveAltitudeChartState(@NonNull Bundle outState) { outState.putBoolean(STATE_ALTITUDE_CHART_SHOWN, mAltitudeChartShown); } - public void restoreAltitudeChartState(@NonNull Bundle state) + void restoreAltitudeChartState(@NonNull Bundle state) { if (state.getBoolean(STATE_ALTITUDE_CHART_SHOWN)) - showRouteAltitudeChart(!isVehicleRouteChecked()); + showRouteAltitudeChart(); } + + public void setStartButton() + { + Button start = (Button) mFrame.findViewById(R.id.start); + if (start == null) + start = (Button) mActivity.findViewById(R.id.start); + + if (isTaxiRouteChecked()) + { + //TODO: use localized string!!! + start.setText("Заказать"); + start.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View v) + { + if (mUberProduct != null) + { + UberLinks links = RoutingController.get().getUberLink(mUberProduct.getProductId()); + Utils.launchUber(mActivity, links); + } + } + }); + } else + { + start.setText(mActivity.getText(R.string.p2p_start)); + start.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View v) + { + RoutingController.get().start(); + } + }); + } + + UiUtils.updateAccentButton(start); + } + } diff --git a/android/src/com/mapswithme/maps/routing/RoutingPlanFragment.java b/android/src/com/mapswithme/maps/routing/RoutingPlanFragment.java index 3903cf0f80..5693156563 100644 --- a/android/src/com/mapswithme/maps/routing/RoutingPlanFragment.java +++ b/android/src/com/mapswithme/maps/routing/RoutingPlanFragment.java @@ -16,6 +16,7 @@ import com.mapswithme.maps.base.OnBackPressListener; public class RoutingPlanFragment extends BaseMwmFragment implements OnBackPressListener { + private RoutingPlanController mPlanController; @Override @@ -26,17 +27,6 @@ public class RoutingPlanFragment extends BaseMwmFragment mPlanController = new RoutingPlanController(res, getActivity()); updatePoints(); - Button start = (Button) res.findViewById(R.id.start); - RoutingController.get().setStartButton(start); - start.setOnClickListener(new View.OnClickListener() - { - @Override - public void onClick(View v) - { - RoutingController.get().start(); - } - }); - Bundle activityState = getMwmActivity().getSavedInstanceState(); if (activityState != null) restoreAltitudeChartState(activityState); @@ -50,13 +40,6 @@ public class RoutingPlanFragment extends BaseMwmFragment mPlanController.disableToggle(); } - @Override - public void onDestroyView() - { - super.onDestroyView(); - RoutingController.get().setStartButton(null); - } - public void updatePoints() { mPlanController.updatePoints(); @@ -73,9 +56,14 @@ public class RoutingPlanFragment extends BaseMwmFragment return RoutingController.get().cancelPlanning(); } - public void showRouteAltitudeChart(boolean show) + public void showRouteAltitudeChart() { - mPlanController.showRouteAltitudeChart(show); + mPlanController.showRouteAltitudeChart(); + } + + public void setStartButton() + { + mPlanController.setStartButton(); } public void restoreAltitudeChartState(@NonNull Bundle state) diff --git a/android/src/com/mapswithme/maps/routing/RoutingPlanInplaceController.java b/android/src/com/mapswithme/maps/routing/RoutingPlanInplaceController.java index 9027f85698..a6320fc85c 100644 --- a/android/src/com/mapswithme/maps/routing/RoutingPlanInplaceController.java +++ b/android/src/com/mapswithme/maps/routing/RoutingPlanInplaceController.java @@ -3,8 +3,6 @@ package com.mapswithme.maps.routing; import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; -import android.view.View; -import android.widget.Button; import android.widget.ImageView; import com.mapswithme.maps.MwmActivity; @@ -12,8 +10,6 @@ import com.mapswithme.maps.R; import com.mapswithme.maps.bookmarks.data.MapObject; import com.mapswithme.util.ThemeUtils; import com.mapswithme.util.UiUtils; -import com.mapswithme.util.statistics.AlohaHelper; -import com.mapswithme.util.statistics.Statistics; public class RoutingPlanInplaceController extends RoutingPlanController { @@ -56,29 +52,6 @@ public class RoutingPlanInplaceController extends RoutingPlanController updatePoints(); } - public void setStartButton() - { - final MwmActivity activity = (MwmActivity) mActivity; - - Button start = activity.getMainMenu().getRouteStartButton(); - RoutingController.get().setStartButton(start); - start.setOnClickListener(new View.OnClickListener() - { - @Override - public void onClick(View v) - { - activity.closeMenu(Statistics.EventName.ROUTING_START, AlohaHelper.ROUTING_START, new Runnable() - { - @Override - public void run() - { - RoutingController.get().start(); - } - }); - } - }); - } - public void onSaveState(@NonNull Bundle outState) { outState.putBoolean(STATE_OPEN, isOpen()); @@ -94,9 +67,9 @@ public class RoutingPlanInplaceController extends RoutingPlanController } @Override - public void showRouteAltitudeChart(boolean show) + public void showRouteAltitudeChart() { ImageView altitudeChart = (ImageView) mActivity.findViewById(R.id.altitude_chart); - showRouteAltitudeChartInternal(show, altitudeChart); + showRouteAltitudeChartInternal(altitudeChart); } } diff --git a/android/src/com/mapswithme/maps/uber/UberAdapter.java b/android/src/com/mapswithme/maps/uber/UberAdapter.java new file mode 100644 index 0000000000..b44dd03976 --- /dev/null +++ b/android/src/com/mapswithme/maps/uber/UberAdapter.java @@ -0,0 +1,59 @@ +package com.mapswithme.maps.uber; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.v4.view.PagerAdapter; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.mapswithme.maps.R; +import com.mapswithme.maps.api.uber.UberInfo; + +public class UberAdapter extends PagerAdapter +{ + + @NonNull + private final Context mContext; + @NonNull + private final UberInfo.Product[] mProducts; + + public UberAdapter(@NonNull Context context, @NonNull UberInfo.Product[] products) + { + mContext = context; + mProducts = products; + } + + @Override + public int getCount() + { + return mProducts.length; + } + + @Override + public boolean isViewFromObject(View view, Object object) + { + return view == object; + } + + @Override + public Object instantiateItem(ViewGroup container, int position) + { + UberInfo.Product product = mProducts[position]; + + View v = LayoutInflater.from(mContext).inflate(R.layout.uber_pager_item, null); + TextView name = (TextView) v.findViewById(R.id.product_name); + name.setText(product.getName()); + TextView timeAndPrice = (TextView) v.findViewById(R.id.arrival_time_price); + timeAndPrice.setText(product.getTime() + " • " + product.getPrice()); + container.addView(v, 0); + return v; + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) + { + container.removeView((View) object); + } +} diff --git a/android/src/com/mapswithme/maps/widget/DotPager.java b/android/src/com/mapswithme/maps/widget/DotPager.java new file mode 100644 index 0000000000..959e57a88d --- /dev/null +++ b/android/src/com/mapswithme/maps/widget/DotPager.java @@ -0,0 +1,159 @@ +package com.mapswithme.maps.widget; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.view.PagerAdapter; +import android.support.v4.view.ViewPager; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import com.mapswithme.maps.R; +import com.mapswithme.util.ThemeUtils; +import com.mapswithme.util.UiUtils; + +public class DotPager implements ViewPager.OnPageChangeListener +{ + @NonNull + private final ViewPager mPager; + @NonNull + private final PagerAdapter mAdapter; + @Nullable + private final ViewGroup mIndicator; + @NonNull + private final ImageView[] mDots; + @NonNull + private final Context mContext; + @Nullable + private final OnPageChangedListener mListener; + + private DotPager(@NonNull Builder builder) + { + mContext = builder.mContext; + mPager = builder.mPager; + mAdapter = builder.mAdapter; + mIndicator = builder.mIndicatorContainer; + mListener = builder.mListener; + mDots = new ImageView[mAdapter.getCount()]; + } + + public void show() + { + configure(); + updateIndicator(); + } + + + private void configure() + { + configurePager(); + configureIndicator(); + } + + private void configurePager() + { + mPager.setAdapter(mAdapter); + mPager.addOnPageChangeListener(this); + } + + private void configureIndicator() + { + if (mIndicator == null) + return; + + mIndicator.removeAllViews(); + + if (mAdapter.getCount() == 1) + return; + + for (int i = 0; i < mDots.length; i++) + { + mDots[i] = new ImageView(mContext); + LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + layoutParams.setMargins(0, 0, UiUtils.dimen(mContext, R.dimen.margin_half), 0); + mIndicator.addView(mDots[i], i, layoutParams); + } + } + + @Override + public void onPageSelected(int position) + { + if (mIndicator != null) + updateIndicator(); + + if (mListener != null) + mListener.onPageChanged(position); + } + + private void updateIndicator() + { + int currentPage = mPager.getCurrentItem(); + for (int i = 0; i < mAdapter.getCount(); i++) + { + mDots[i].setImageResource(ThemeUtils.isNightTheme() ? i == currentPage ? R.drawable.news_marker_active_night + : R.drawable.news_marker_inactive_night + : i == currentPage ? R.drawable.news_marker_active + : R.drawable.news_marker_inactive); + } + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) + { + //no op + } + + @Override + public void onPageScrollStateChanged(int state) + { + //no op + } + + public static class Builder + { + @NonNull + private final ViewPager mPager; + @NonNull + private final PagerAdapter mAdapter; + @Nullable + private ViewGroup mIndicatorContainer; + @NonNull + private final ImageView[] mDots; + @NonNull + private final Context mContext; + @Nullable + private OnPageChangedListener mListener; + + public Builder(@NonNull Context context, @NonNull ViewPager pager, @NonNull PagerAdapter adapter) + { + mContext = context; + mPager = pager; + mAdapter = adapter; + mDots = new ImageView[mAdapter.getCount()]; + } + + public Builder setIndicatorContainer(@NonNull ViewGroup indicatorContainer) + { + mIndicatorContainer = indicatorContainer; + return this; + } + + public Builder setPageChangedListener(@Nullable OnPageChangedListener listener) + { + mListener = listener; + return this; + } + + public DotPager build() + { + return new DotPager(this); + } + } + + public interface OnPageChangedListener + { + void onPageChanged(int position); + } +} diff --git a/android/src/com/mapswithme/maps/widget/menu/MainMenu.java b/android/src/com/mapswithme/maps/widget/menu/MainMenu.java index 1c62360eca..fff888657f 100644 --- a/android/src/com/mapswithme/maps/widget/menu/MainMenu.java +++ b/android/src/com/mapswithme/maps/widget/menu/MainMenu.java @@ -57,7 +57,6 @@ public class MainMenu extends BaseMenu private final List mCollapseViews = new ArrayList<>(); private final MenuToggle mToggle; - private Button mRouteStartButton; // Maps Item into button view placed on mContentFrame private final Map mItemViews = new HashMap<>(); @@ -234,9 +233,6 @@ public class MainMenu extends BaseMenu mNewsMarker = mButtonsFrame.findViewById(R.id.marker); mNewsCounter = (TextView) mContentFrame.findViewById(R.id.counter); - if (mRoutePlanFrame != null) - mRouteStartButton = (Button) mRoutePlanFrame.findViewById(R.id.start); - init(); } @@ -306,11 +302,6 @@ public class MainMenu extends BaseMenu return mAnimationTrackListener; } - public Button getRouteStartButton() - { - return mRouteStartButton; - } - public void showLineFrame(boolean show) { UiUtils.showIf(show, mLineFrame); diff --git a/android/src/com/mapswithme/util/Utils.java b/android/src/com/mapswithme/util/Utils.java index 120c675fcf..c5df86b759 100644 --- a/android/src/com/mapswithme/util/Utils.java +++ b/android/src/com/mapswithme/util/Utils.java @@ -31,6 +31,7 @@ import com.mapswithme.maps.BuildConfig; import com.mapswithme.maps.MwmApplication; import com.mapswithme.maps.R; import com.mapswithme.maps.activity.CustomNavigateUpListener; +import com.mapswithme.maps.api.uber.UberLinks; import com.mapswithme.util.statistics.AlohaHelper; import java.io.Closeable; @@ -399,4 +400,22 @@ public class Utils return installationId; } + + public static void launchUber(@NonNull Activity context, @NonNull UberLinks links) + { + try + { + PackageManager pm = context.getPackageManager(); + pm.getPackageInfo("com.ubercab", PackageManager.GET_ACTIVITIES); + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse(links.getDeepLink())); + context.startActivity(intent); + } catch (PackageManager.NameNotFoundException e) + { + // No Uber app! Open mobile website. + Intent i = new Intent(Intent.ACTION_VIEW); + i.setData(Uri.parse(links.getUniversalLink())); + context.startActivity(i); + } + } } diff --git a/android/src/com/mapswithme/util/statistics/AlohaHelper.java b/android/src/com/mapswithme/util/statistics/AlohaHelper.java index 09efd5bd8f..30d914d366 100644 --- a/android/src/com/mapswithme/util/statistics/AlohaHelper.java +++ b/android/src/com/mapswithme/util/statistics/AlohaHelper.java @@ -74,6 +74,7 @@ public class AlohaHelper public static final String ROUTING_VEHICLE_SET = "routerSetVehicle"; public static final String ROUTING_PEDESTRIAN_SET = "routerSetPedestrian"; public static final String ROUTING_BICYCLE_SET = "routerSetBicycle"; + public static final String ROUTING_TAXI_SET = "routerSetTaxi"; public static final String ROUTING_SWAP_POINTS = "routeSwapPoints"; public static final String ROUTING_TOGGLE = "routeToggle"; public static final String ROUTING_SEARCH_POINT = "routSearchPoint"; diff --git a/android/src/com/mapswithme/util/statistics/Statistics.java b/android/src/com/mapswithme/util/statistics/Statistics.java index 4be6ba2f42..0b77c7be9d 100644 --- a/android/src/com/mapswithme/util/statistics/Statistics.java +++ b/android/src/com/mapswithme/util/statistics/Statistics.java @@ -110,6 +110,7 @@ public enum Statistics public static final String ROUTING_VEHICLE_SET = "Routing. Set vehicle"; public static final String ROUTING_PEDESTRIAN_SET = "Routing. Set pedestrian"; public static final String ROUTING_BICYCLE_SET = "Routing. Set bicycle"; + public static final String ROUTING_TAXI_SET = "Routing. Set taxi"; public static final String ROUTING_SWAP_POINTS = "Routing. Swap points"; public static final String ROUTING_TOGGLE = "Routing. Toggle"; public static final String ROUTING_SEARCH_POINT = "Routing. Search point";