From c1c839a308b37e149a9b72a2f9b6d2ce2fdfccd6 Mon Sep 17 00:00:00 2001 From: alexzatsepin Date: Fri, 7 Oct 2016 17:28:28 +0300 Subject: [PATCH] [android] Implemented Uber feature 1. Made a Uber panel layout 2. Implemented the 'Order' button allowing to order the Uber by launching the Uber app or directing to the Google Play --- .gitignore | 4 + android/jni/com/mapswithme/maps/Framework.cpp | 73 +++++++- android/jni/com/mapswithme/maps/Framework.hpp | 3 + .../com/mapswithme/maps/SponsoredHotel.cpp | 2 - android/res/drawable-hdpi/ic_logo_uber.png | Bin 0 -> 2431 bytes android/res/drawable-hdpi/ic_taxi.png | Bin 0 -> 475 bytes android/res/drawable-mdpi/ic_logo_uber.png | Bin 0 -> 1487 bytes android/res/drawable-mdpi/ic_taxi.png | Bin 0 -> 496 bytes android/res/drawable-xhdpi/ic_logo_uber.png | Bin 0 -> 3644 bytes android/res/drawable-xhdpi/ic_taxi.png | Bin 0 -> 520 bytes android/res/drawable-xxhdpi/ic_logo_uber.png | Bin 0 -> 6267 bytes android/res/drawable-xxhdpi/ic_taxi.png | Bin 0 -> 787 bytes android/res/drawable-xxxhdpi/ic_logo_uber.png | Bin 0 -> 9682 bytes android/res/drawable-xxxhdpi/ic_taxi.png | Bin 0 -> 1121 bytes android/res/layout/menu_route_plan_line.xml | 5 +- android/res/layout/routing_plan.xml | 18 +- android/res/layout/uber_pager_item.xml | 22 +++ android/res/layout/uber_panel.xml | 42 +++++ .../src/com/mapswithme/maps/Framework.java | 11 +- .../src/com/mapswithme/maps/MwmActivity.java | 19 ++- .../mapswithme/maps/api/uber/UberInfo.java | 87 ++++++++++ .../mapswithme/maps/api/uber/UberLinks.java | 29 ++++ .../maps/routing/RoutingController.java | 62 ++++--- .../maps/routing/RoutingPlanController.java | 139 +++++++++++++-- .../maps/routing/RoutingPlanFragment.java | 28 +-- .../routing/RoutingPlanInplaceController.java | 31 +--- .../com/mapswithme/maps/uber/UberAdapter.java | 59 +++++++ .../com/mapswithme/maps/widget/DotPager.java | 159 ++++++++++++++++++ .../mapswithme/maps/widget/menu/MainMenu.java | 9 - android/src/com/mapswithme/util/Utils.java | 19 +++ .../util/statistics/AlohaHelper.java | 1 + .../util/statistics/Statistics.java | 1 + 32 files changed, 715 insertions(+), 108 deletions(-) create mode 100644 android/res/drawable-hdpi/ic_logo_uber.png create mode 100644 android/res/drawable-hdpi/ic_taxi.png create mode 100644 android/res/drawable-mdpi/ic_logo_uber.png create mode 100644 android/res/drawable-mdpi/ic_taxi.png create mode 100644 android/res/drawable-xhdpi/ic_logo_uber.png create mode 100644 android/res/drawable-xhdpi/ic_taxi.png create mode 100644 android/res/drawable-xxhdpi/ic_logo_uber.png create mode 100644 android/res/drawable-xxhdpi/ic_taxi.png create mode 100644 android/res/drawable-xxxhdpi/ic_logo_uber.png create mode 100644 android/res/drawable-xxxhdpi/ic_taxi.png create mode 100644 android/res/layout/uber_pager_item.xml create mode 100644 android/res/layout/uber_panel.xml create mode 100644 android/src/com/mapswithme/maps/api/uber/UberInfo.java create mode 100644 android/src/com/mapswithme/maps/api/uber/UberLinks.java create mode 100644 android/src/com/mapswithme/maps/uber/UberAdapter.java create mode 100644 android/src/com/mapswithme/maps/widget/DotPager.java 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 0000000000000000000000000000000000000000..157cd1659fa004d0ec0af8e1a65f97467de1aee0 GIT binary patch literal 2431 zcmV-_34r#AP)j+qP}nwr$%wh?AKNy1Vw@)3qkKv;LgxcdhCHVg)wQa?r!M?SlI57aK3fAIJ>p@FpC|5uQ%>`tt)}GG5zC;fII-3XTSl z?AOei0Sg8)I8?DY9{{ODAcCSWa~e9oAF(>Q1QrEE6;xmF^5Ky~_uhCikbslW(9eDr z6#T+5($&45tyIydMnjsxkS%Un^JrV%0U6_fLLUUA5(vKAQ1%=wEzOX z!Q^u!L!;;Clfm^GZW-qgQt-NtQa?yxD&Tvd+6<$PUb?$rcr1faRX1%y>gF4PkujvB zjfTsr4#vqMzCkNh#P?UMc!kry*wPZD15#KEY#TpAq%n?Rw*<(pXNP8d3-H2ioTNx6nrYukH_ zbxQBg|N6@$2=73;I!1YQ8H3EHg z7(U_^xK*f0i|bWIyD-4J>%OsbRz23dQ##X0-HJsiwO)a)5EIA#Cc*=ntosSFLG z7BqDV0aJg6wG##51`epv^h6b=_d?*i#+QYu#{W`h4%=cwa$(5FmGM0G-E4hU{`cRr zwGe|24x$RuTL4_QSDXxqb(Msj4@e9moP^()Q?|p@k9w(r5Q5;qpB3T+F1U-e`jhr;5bP@a8mF* zLu*S5Q)#LH{G9_&Ih%p8V%Dz^aXC9Uih2fHE@C8#8>CI$x8C%=_qDI`^)G&&DU^Y% zw(~yxdgb-`{c0O$<2S2pz%pCyLaAJ4D$SWWgP(oxo5XQMCaYvJ;tY!|KJVX$CV+%E z1^vM{zUn&e6!JZfx99co+Pm)&`2GZ>s>NE%LX@ugHLkw>Uc?WZdY|In?`!DeD$g<@ zh0x1$-!sp%_U;E{uuT%Om(J}U$STi>G$k+y3)A#zy+{}!IUkfv+Gxg+hmTG=Bs8Gi z-@_oFyR*Fk)TG3!%LBKO@=@g?VVff2WI!#xL^VhRX*4JYL{zEp({!IYbn8u6m>ziY zS>EgGYYJHuC$Mm(`&}Q@64Z;EQUpoRS|f*~`IIUuS&lsU;wvOc;=(XRQh)2qU%*r^R%6RO58&+ugLuY6H9-nph$m>8Z>u<8cCR=mz1(%X9xV5M|6US~NHy$9U z+R5`!=m(WXwyO%6jG!YUS%RA{ej&Tgv;-lyKJ*0tSYso0I_OBANy|4$k|`VCi?6)K zo`)UFUsqa-tM7aub*2?tDk8II0ybM4F-_ToK)^Y6dEvMvlx@hA;ul1+(Ald z$pwszS2*aj^Z3(B>+$E6)@H+<_hgSFk7LiHj%TA?_TsNAuEp<{Ta&$yJB_~LcnXt8 z)w&Dj*chS~sfSLPfN7|^r{`Rmm0p9!txR5nJcTeMXm2AK9(7lhu1-u#i0vCdkw%rc zYfuz{?;`?KBaH9kr(tpE|SzStyaNWT$>Sm)xS#pPTyfW?n)tk zExw?}Ab`XPwp<4BTq1V1XRf7CP3Ip}G45`Utwhb?a|sMK%EBb#fs$>m>U)T4HitNY zIC{QwIQhAmGnXiA4-fQ0A0msEO4&r4HArtFr|jq$TC3r8bs$zj$>xbN+2mB4V94%u z7Dh%L41%KATGhRyQiddf6wu_t{fjg6<0gI3fA>vS+R@R&G>$QTh$ael!h%Ly$Sl_| zfI9sDyGql%Db^jxhv={?ZNTLw4qTH2@q_G_V)3NW$L~2e9hmw{-pISC$XSF&O;DvH3An)Om7d`KhRX#PJ*aal*dgN915HV zlkz)I1#8f6RS9CXY5^o@$V!&t@jD#^T6DtwZxqug#MDPS^WT0Z=0R{te6G4#Q z22;!GsxysRJqGXVq@n*se^k9!ys8RZf@Zxxw@-kckM)Jp#>GAjl_5ClOG1VIpdia+_E^{zt| RYs&xt002ovPDHLkV1gmi*C+r0 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..5d0eee863f6d0ad43024144eea6b8e140bce3608 GIT binary patch literal 1487 zcmV;=1u*)FP)Px)iAh93R7eelR$FXTRTN$4KIYD=?MN+!Rxnlc%MXeX1OZE8uwcN)hZ-N>{s`hn z4Hy$8NFoG9|NJsh!Kl$_6OF}yq#uHiS_~CM+ej&;y!)8NE|N zY65cksu7wFZF(RaDv%8MFe3>doKEwd*}4wkFlPEk5KM%Aq0@oqJV=in61k*oC5dgo z9sESGfS^!7iP1)QI2q?0ePpMz@EN&VvEfJ{O-Ylb)G8#Dy3CA}YI7n^x08&=AIbPN zSOlJ#3{-0i^z;l0Q)#sG`_t+ivCX3x@ui-A$u_kG%_;qUcaGnakpUpJbbuo zJ04%X90g`Bkg}ej)oP6lQ5@Ict|W36w8E#gr5Ss-Zbl+X{@-MHkqGu~dl?Jo&qX<3 zgwExlSU(ky!IB;VHz24$Gisrn&w@VLy#^iaZT~S{AY@q|UupheyqciWJm_I8Y2-md!J}Q1@94Qk=69W!|Kr2~ofX z3wXHZs8}vx<>GtLwe;S)q^6wZYWivBbST+%<8P`ETh!X5V z={y!s!VB2Ny$AcRbMVp5*ZzS;vXRcNAAS8lqDX?o#erlIjgUcc_7>S82UJr7c#6L^ zKJPn(;nA`B^Ke-!fli+P8y`DAf&IPTnKh$NjijkXRHzUZgjN{}8U;(mJ=pO$u1rp0 z)0=yc&QgkRGIG?a&2PMg^Ovu|j(Jcq(mum(Hkwo-l$w%lFe5Xj*o~fpSgH{}44%YO zFKxwXvgt-+0 z++H*7D5e=hm?1R0$-vGIn5sy#LrfEim`Ntj^)ds9xUPXkY6nV$ML7=%nHFZUu2I{4 zUd>swtTAYA9N=AWm$@lKHh3ipY^s3_D^OqPz=UPjs3|fa2~!FbaYtG%98Sn(BiE>` z1;LnInd!79M~KsK1QETx7kf`IVeEcqqh z3iX!ssZ*22U2$S`*lWN21k+lgLfxX7UUetEu%VQ2oA`qnn2shq!gCWf|HGKYTq$#l z4=V&OWPUyNwb-axs@fB{!UnI4oL{3V!5yMFf~DmVh8z`?H4+KZ>~@=SEEEsLu?j6a p;$Fz-N_|$Y&_6RaG*z_-{0(W5#ZfaZI-~#q002ovPDHLkV1f}6x9$J{ literal 0 HcmV?d00001 diff --git a/android/res/drawable-mdpi/ic_taxi.png b/android/res/drawable-mdpi/ic_taxi.png new file mode 100644 index 0000000000000000000000000000000000000000..aa8d167fbaf7b38b3ff2c80bcda0ff173e594d54 GIT binary patch literal 496 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^Txt_Q2HW2$wHFqhl#h#yLwCMM+wZRzS14XHJaF}aep_S5 zPL7`ktJcc8=uDD17IRv=?eK-I(zSmMt4|bJuutY?-gdt%g$G*gM+zX4yXZ%z>G>`Hr&l=L ziadOn^?hRd-dnCo6QAsOQM5T|{sFP|4u9vc?0&0sr+9bVgGi~pzuP!hKmQ@e8PYrp g9+t2mWn}-h@2*seFiThnFbWwwUHx3vIVCg!08%U6yZ`_I literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..9f0ddb7ccd45733fdb061f136d2ca87d7b66fcea GIT binary patch literal 3644 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 O0000I?%XhAOd;P(P2W zs#6S{DXPR3dGi8YRc5D^+No66yukhbKhjE#?(@KO{epW_ENkV;ZmwWfV4!Lo^cDw* z;h>TO6SeDb{yLPNhM$A_`vjb)san%MM(ybs&ie%Z2?}Veeky2V99r`++Nc;<8Aa}& z_Y^pz4;wc6I0tV0kTEOJcR%$53p`}Z3fS%^JFvh*h5})qLcSNhs8h(}BK8#!brE|} z@L9Qvx{Z3VL<#Y4d&W_^zq5;iK%@p41t<`Tzy(RIWD*xy0vqk@MwY-#J3Esl(9_QL zBnW&x+*h@;RRa(6FJ7-?wX<0RuTuyigb+dqA%qY@2qA=!Q1}Eb*{(Om0p=C}0000< KMNUMnLSTZJ-{4^Y literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..32e0674db740a5c8d7f3377fe7a2992173c4b916 GIT binary patch literal 6267 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 literal 0 HcmV?d00001 diff --git a/android/res/drawable-xxhdpi/ic_taxi.png b/android/res/drawable-xxhdpi/ic_taxi.png new file mode 100644 index 0000000000000000000000000000000000000000..af67db7f08b8fe9eb8d7a1c91a7d079041aadba9 GIT binary patch literal 787 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 literal 0 HcmV?d00001 diff --git a/android/res/drawable-xxxhdpi/ic_taxi.png b/android/res/drawable-xxxhdpi/ic_taxi.png new file mode 100644 index 0000000000000000000000000000000000000000..a809111fef81d20ef0579333a8d43932306118ce GIT binary patch literal 1121 zcmeAS@N?(olHy`uVBq!ia0vp^2SAvE1xWt5x}=AJfkng9#WAGf*4w)qy`>Xnj(uF6 zU@fsUU~Pc*Kh|lFCN1oac=6ytR%xcVuEvd(-4_n7l=V`(?I@#qVQF)Bcaqq`l7bge z?wlbaE=z^3*vMwB-S@t7=aYNiH|%_$uI0HmzD91R@%y_+6@d2P0tGIzRsk{WuM`Zg zv+fDAjhj5<_K)Z-q2Y|tS&F99S$kH*DKB}psbOn({oKv}+CTo-zuw`~kKg*N(%TtU z&VLdky5U9uW4Fq4wSRuH<{<|*T6vy#W!yZye{I@>iT&p%#eMn_z4dMZebv4%V-j=GpAWlD*T)yVo&M~q@2;(n z<*%-*xp`HC)BU);`u%4fKY#tWug&}3!^-Ag;nLJOTi*WIy=8tBD^Y(|Q%djtEiZXi?S#Fnjcg6;v zSN{*~T;274wbYu`T3WljKh+C6J?H$3&1rj7e(ry`M&e>l)yz$qK9Pz)?GN6$ z+$nfATEF<7RIp!3|CeTk3oToVKNQ(E|5|G)yhNU*G3@N>TYG$s)~}0J{p;|(H0#Kx zgSXf4A6pW9cX@+m_VEu#Zm&_lwnmdnLvrGuFXfSIqrP085q7HT5C0m~Cf4$*kYr#rt_SHwLQof3NG@Ux!!_0K9-b^V|H`by&3J-5Ei+Q1~5JV(PPwen2V zFYe%+eN3ke_q`2Yxo1+iVVvjApIkrA2QaXLP{U!ST_!6uYePJ(&CR~bPW=)XES2*~ z`}vin2c^aTB^=WWPnqt_C{mE=nB!RabV_g>_cf-u)`G>GVjLp<*V}wHxwiY+FV}M? z^BAwL-Z;lS`0Izu@|NnmSzG2cZSj*;3s3ed<37=DH@iH}q1W=Ju7dcloO6|orq6(O zZ{U8UAX6yd_s6ZjxnNVgv#|Jq^$P{_kF>3`F&6pecIIG^`xBXIN?AIt7LnOWno0+g zVq(jCTki-SONu$fwCwe*UnZ652hH3gQg+nk8yCm#7ft3Xed>gb zcFx$#bjWVc<4CQ^^COGD&-(N^FexOVuEtlZ{;9{^V^5=w`W)lOl{w+!r}J$~giqYQ R@@y7J$kWx&Wt~$(6990*1K0on literal 0 HcmV?d00001 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";