[android] Fix cian jni crash.

Added cian cache.
Loading info error message.
This commit is contained in:
Roman Romanov 2017-07-24 10:38:08 +04:00 committed by Arsentiy Milchakov
parent ca4b9105b1
commit ea114dc7b0
15 changed files with 133 additions and 44 deletions

View file

@ -16,6 +16,7 @@ jmethodID g_cianCallback;
jmethodID g_cianSuccessCallback;
jmethodID g_cianErrorCallback;
uint64_t g_requestId;
std::string g_id;
void PrepareClassRefs(JNIEnv * env)
{
@ -32,11 +33,11 @@ void PrepareClassRefs(JNIEnv * env)
g_rentOfferConstructor =
jni::GetConstructorID(env, g_rentOfferClass,
"(Ljava/lang/String;IIIILjava/lang/String;Ljava/lang/String;)V");
"(Ljava/lang/String;IDIILjava/lang/String;Ljava/lang/String;)V");
g_cianSuccessCallback =
jni::GetStaticMethodID(env, g_cianClass, "onRentPlacesReceived",
"([Lcom/mapswithme/maps/cian/RentPlace;)V");
"([Lcom/mapswithme/maps/cian/RentPlace;Ljava/lang/String;)V");
g_cianErrorCallback =
jni::GetStaticMethodID(env, g_cianClass, "onErrorReceived",
"(I)V");
@ -68,8 +69,9 @@ void OnRentPlacesReceived(std::vector<cian::RentPlace> const & places, uint64_t
jni::TScopedLocalObjectArrayRef jPlaces(env, jni::ToJavaArray(env, g_rentPlaceClass, places,
placeBuilder));
jni::TScopedLocalRef jId(env, jni::ToJavaString(env, g_id));
env->CallStaticVoidMethod(g_cianClass, g_cianSuccessCallback, jPlaces.get());
env->CallStaticVoidMethod(g_cianClass, g_cianSuccessCallback, jPlaces.get(), jId.get());
}
void OnErrorReceived(int httpCode, uint64_t const requestId)
@ -86,10 +88,11 @@ void OnErrorReceived(int httpCode, uint64_t const requestId)
extern "C" {
JNIEXPORT void JNICALL Java_com_mapswithme_maps_cian_Cian_nativeGetRentNearby(
JNIEnv * env, jclass clazz, jobject policy, jdouble lat, jdouble lon)
JNIEnv * env, jclass clazz, jobject policy, jdouble lat, jdouble lon, jstring id)
{
PrepareClassRefs(env);
g_id = jni::ToNativeString(env, id);
ms::LatLon const pos(lat, lon);
g_requestId = g_framework->GetRentNearby(env, policy, pos, &OnRentPlacesReceived,
&OnErrorReceived);

View file

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="@dimen/cian_product_width"
android:layout_height="@dimen/cian_product_height"
android:padding="@dimen/margin_quarter"
android:clipToPadding="false"
android:foreground="?clickableBackground">
<ImageView
android:id="@+id/iv__image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="?attr/sponsoredGalleryMore"/>
<TextView
android:id="@+id/tv__title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_half_plus"
android:layout_below="@id/iv__image"
android:layout_centerHorizontal="true"
android:textAppearance="@style/MwmTextAppearance.Body2"
android:fontFamily="@string/robotoMedium"
android:textColor="?colorAccent"
android:textAllCaps="true"
tools:text="More"
tools:targetApi="jelly_bean"/>
</RelativeLayout>

View file

@ -4,13 +4,15 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="@dimen/viator_product_width"
android:layout_height="@dimen/viator_product_height"
android:padding="@dimen/margin_quarter"
android:clipToPadding="false"
android:foreground="?clickableBackground">
<ImageView
android:id="@+id/iv__image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="?viatorMore"/>
android:src="?attr/sponsoredGalleryMore"/>
<TextView
android:id="@+id/tv__title"
android:layout_width="wrap_content"

View file

@ -85,7 +85,7 @@
<attr name="tagBackground" format="reference"/>
<attr name="viatorMore" format="reference"/>
<attr name="sponsoredGalleryMore" format="reference"/>
</declare-styleable>
<declare-styleable name="ThemeAttrs.NavButtons">

View file

@ -102,7 +102,7 @@
<item name="tagBackground">@drawable/bg_tag</item>
<item name="viatorMore">@drawable/ic_viator_more</item>
<item name="sponsoredGalleryMore">@drawable/ic_sponsored_gallery_more</item>
</style>
<!-- Night theme -->
@ -207,6 +207,6 @@
<item name="tagBackground">@drawable/bg_tag_night</item>
<item name="viatorMore">@drawable/ic_viator_more_night</item>
<item name="sponsoredGalleryMore">@drawable/ic_sponsored_gallery_more_night</item>
</style>
</resources>

View file

@ -2,6 +2,7 @@ package com.mapswithme.maps.base;
import android.support.annotation.CallSuper;
import android.support.annotation.IntDef;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
@ -34,6 +35,8 @@ public abstract class BaseSponsoredAdapter extends RecyclerView.Adapter<BaseSpon
R.dimen.viator_product_width);
private static final int MARGING_QUARTER = UiUtils.dimen(MwmApplication.get(),
R.dimen.margin_quarter);
private static final String ERROR_SUBTITLE = MwmApplication
.get().getString(R.string.error_load_information);
@Retention(RetentionPolicy.SOURCE)
@IntDef({ TYPE_PRODUCT, TYPE_MORE, TYPE_LOADING })
@ -43,20 +46,25 @@ public abstract class BaseSponsoredAdapter extends RecyclerView.Adapter<BaseSpon
private final List<Item> mItems;
@Nullable
private final ItemSelectedListener mListener;
@Sponsored.SponsoredType
private final int mSponsoredType;
public BaseSponsoredAdapter(@Sponsored.SponsoredType int sponsoredType, @NonNull String url,
boolean hasError, @Nullable ItemSelectedListener listener)
{
mSponsoredType = sponsoredType;
mItems = new ArrayList<>();
mListener = listener;
mItems.add(new Item(TYPE_LOADING, sponsoredType, getLoadingTitle(), url, getLoadingSubtitle(),
hasError, false));
String subtitle = hasError ? ERROR_SUBTITLE : getLoadingSubtitle();
mItems.add(new Item(TYPE_LOADING, sponsoredType, getLoadingTitle(), url, subtitle, hasError,
false));
}
public BaseSponsoredAdapter(@Sponsored.SponsoredType int sponsoredType,
@NonNull List<? extends Item> items, @NonNull String url,
@Nullable ItemSelectedListener listener)
{
mSponsoredType = sponsoredType;
mItems = new ArrayList<>();
mListener = listener;
boolean showMoreItem = items.size() >= MAX_ITEMS;
@ -78,9 +86,13 @@ public abstract class BaseSponsoredAdapter extends RecyclerView.Adapter<BaseSpon
case TYPE_PRODUCT:
return createViewHolder(LayoutInflater.from(parent.getContext()), parent);
case TYPE_MORE:
@LayoutRes final int layout;
if (mSponsoredType == Sponsored.TYPE_VIATOR)
layout = R.layout.item_viator_more;
else
layout = R.layout.item_cian_more;
return new ViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_viator_more,
parent, false), this);
.inflate(layout, parent, false), this);
case TYPE_LOADING:
return createLoadingViewHolder(LayoutInflater.from(parent.getContext()), parent);
}
@ -114,7 +126,7 @@ public abstract class BaseSponsoredAdapter extends RecyclerView.Adapter<BaseSpon
public void setLoadingError(@Sponsored.SponsoredType int sponsoredType, @NonNull String url)
{
mItems.clear();
mItems.add(new Item(TYPE_LOADING, sponsoredType, getLoadingTitle(), url, getLoadingSubtitle(),
mItems.add(new Item(TYPE_LOADING, sponsoredType, getLoadingTitle(), url, ERROR_SUBTITLE,
true, false));
notifyItemChanged(0);
}
@ -206,7 +218,6 @@ public abstract class BaseSponsoredAdapter extends RecyclerView.Adapter<BaseSpon
{
super.bind(item);
UiUtils.setTextAndHideIfEmpty(mSubtitle, item.mSubtitle);
UiUtils.visibleIf(!item.mLoadingError, mProgressBar);
if (item.mFinished)
{
UiUtils.hide(mTitle, mSubtitle, mProgressBar);
@ -216,6 +227,8 @@ public abstract class BaseSponsoredAdapter extends RecyclerView.Adapter<BaseSpon
itemView.setPadding(itemView.getLeft(), itemView.getTop(),
MARGING_QUARTER, itemView.getBottom());
}
if (item.mLoadingError)
UiUtils.hide(mProgressBar);
}
@Override

View file

@ -296,6 +296,12 @@ public class MapObject implements Parcelable
return mFeatureIndex;
}
@NonNull
public String getFeatureId()
{
return mMwmName + ":" + mMwmVersion + ":" + mFeatureIndex;
}
private static MapObject readFromParcel(Parcel source)
{
@MapObjectType int type = source.readInt();

View file

@ -5,19 +5,24 @@ import android.support.annotation.NonNull;
import com.mapswithme.util.NetworkPolicy;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
public final class Cian
{
@NonNull
private static WeakReference<com.mapswithme.maps.cian.Cian.CianListener> sCianListener = new WeakReference<>(null);
@NonNull
private static final Map<String, RentPlace[]> sProductsCache = new HashMap<>();
public static void setCianListener(@NonNull com.mapswithme.maps.cian.Cian.CianListener listener)
{
sCianListener = new WeakReference<>(listener);
}
private static void onRentPlacesReceived(@NonNull RentPlace[] places)
private static void onRentPlacesReceived(@NonNull RentPlace[] places, @NonNull String id)
{
sProductsCache.put(id, places);
com.mapswithme.maps.cian.Cian.CianListener listener = sCianListener.get();
if (listener != null)
listener.onRentPlacesReceived(places);
@ -32,9 +37,19 @@ public final class Cian
private Cian() {}
public static void getRentNearby(@NonNull NetworkPolicy policy,double lat, double lon)
public static void getRentNearby(@NonNull NetworkPolicy policy,double lat, double lon,
@NonNull String id)
{
nativeGetRentNearby(policy, lat, lon);
RentPlace[] products = sProductsCache.get(id);
if (products != null && products.length > 0)
onRentPlacesReceived(products, id);
nativeGetRentNearby(policy, lat, lon, id);
}
public static boolean hasCache(String id)
{
return sProductsCache.containsKey(id);
}
public interface CianListener
@ -44,5 +59,5 @@ public final class Cian
}
private static native void nativeGetRentNearby(@NonNull NetworkPolicy policy, double lat,
double lon);
double lon, @NonNull String id);
}

View file

@ -41,10 +41,13 @@ public final class CianAdapter extends BaseSponsoredAdapter
List<Item> viewItems = new ArrayList<>();
for (RentPlace place : items)
{
if (place.getOffers().isEmpty())
continue;
RentOffer product = place.getOffers().get(0);
Context context = MwmApplication.get();
String title = context.getString(R.string.room, Integer.toString(product.getRoomsCount()));
String price = Integer.toString(product.getPrice()) + " "
String price = Integer.toString((int) product.getPrice()) + " "
+ context.getString(R.string.rub_month);
viewItems.add(new Item(title, product.getUrl(), price, product.getAddress()));
}

View file

@ -9,7 +9,7 @@ public final class RentOffer implements Parcelable
@NonNull
private final String mFlatType;
private final int mRoomsCount;
private final int mPrice;
private final double mPrice;
private final int mFloorNumber;
private final int mFloorsCount;
@NonNull
@ -32,7 +32,7 @@ public final class RentOffer implements Parcelable
}
};
public RentOffer(@NonNull String flatType, int roomsCount, int price, int floorNumber,
public RentOffer(@NonNull String flatType, int roomsCount, double price, int floorNumber,
int floorsCount, @NonNull String url, @NonNull String address)
{
mFlatType = flatType;
@ -66,7 +66,7 @@ public final class RentOffer implements Parcelable
{
dest.writeString(mFlatType);
dest.writeInt(mRoomsCount);
dest.writeInt(mPrice);
dest.writeDouble(mPrice);
dest.writeInt(mFloorNumber);
dest.writeInt(mFloorsCount);
dest.writeString(mUrl);
@ -84,7 +84,7 @@ public final class RentOffer implements Parcelable
return mRoomsCount;
}
public int getPrice()
public double getPrice()
{
return mPrice;
}
@ -120,7 +120,7 @@ public final class RentOffer implements Parcelable
RentOffer rentOffer = (RentOffer) o;
if (mRoomsCount != rentOffer.mRoomsCount) return false;
if (mPrice != rentOffer.mPrice) return false;
if (Double.compare(rentOffer.mPrice, mPrice) != 0) return false;
if (mFloorNumber != rentOffer.mFloorNumber) return false;
if (mFloorsCount != rentOffer.mFloorsCount) return false;
if (!mFlatType.equals(rentOffer.mFlatType)) return false;
@ -131,9 +131,12 @@ public final class RentOffer implements Parcelable
@Override
public int hashCode()
{
int result = mFlatType.hashCode();
int result;
long temp;
result = mFlatType.hashCode();
result = 31 * result + mRoomsCount;
result = 31 * result + mPrice;
temp = Double.doubleToLongBits(mPrice);
result = 31 * result + (int) (temp ^ (temp >>> 32));
result = 31 * result + mFloorNumber;
result = 31 * result + mFloorsCount;
result = 31 * result + mUrl.hashCode();

View file

@ -55,6 +55,7 @@ import com.mapswithme.maps.bookmarks.data.BookmarkManager;
import com.mapswithme.maps.bookmarks.data.DistanceAndAzimut;
import com.mapswithme.maps.bookmarks.data.MapObject;
import com.mapswithme.maps.bookmarks.data.Metadata;
import com.mapswithme.maps.cian.Cian;
import com.mapswithme.maps.cian.CianAdapter;
import com.mapswithme.maps.cian.RentPlace;
import com.mapswithme.maps.downloader.CountryItem;
@ -128,7 +129,8 @@ public class PlacePageView extends RelativeLayout
Viator.ViatorListener,
UGC.UGCListener,
UgcAverageRatingController.OnUgcRatingChangedListener,
BaseSponsoredAdapter.ItemSelectedListener
BaseSponsoredAdapter.ItemSelectedListener,
Cian.CianListener
{
private static final Logger LOGGER = LoggerFactory.INSTANCE.getLogger(LoggerFactory.Type.MISC);
private static final String TAG = PlacePageView.class.getSimpleName();
@ -656,6 +658,7 @@ public class PlacePageView extends RelativeLayout
Sponsored.setPriceListener(this);
Sponsored.setInfoListener(this);
Viator.setViatorListener(this);
Cian.setCianListener(this);
}
private void initUgcView()
@ -850,14 +853,15 @@ public class PlacePageView extends RelativeLayout
updateViatorView(products, mSponsored.getUrl());
}
//TODO override from Cian.CianListener
void onRentPlacesReceived(@NonNull RentPlace[] places)
@Override
public void onRentPlacesReceived(@NonNull RentPlace[] places)
{
updateCianView(places, "");
if (mSponsored != null)
updateCianView(places, mSponsored.getUrl());
}
//TODO override from Cian.CianListener
void onErrorReceived(int httpCode)
@Override
public void onErrorReceived(int httpCode)
{
if (mSponsoredAdapter == null || !mSponsoredAdapter.containsLoading())
{
@ -866,7 +870,8 @@ public class PlacePageView extends RelativeLayout
}
else
{
mSponsoredAdapter.setLoadingError(Sponsored.TYPE_CIAN, "");
mSponsoredAdapter.setLoadingError(Sponsored.TYPE_CIAN,
mSponsored != null ? mSponsored.getUrl() : "");
}
Statistics.INSTANCE.trackSponsoredGalleryError(Sponsored.TYPE_CIAN);
}
@ -972,11 +977,11 @@ public class PlacePageView extends RelativeLayout
}
}
private void showLoadingCianProducts(@NonNull String url)
private void showLoadingCianProducts(@NonNull String id, @NonNull String url)
{
UiUtils.show(mSponsoredGalleryView);
mTvSponsoredTitle.setText(R.string.subtitle_rent);
if (mRvSponsoredProducts.getAdapter().getItemCount() == 0)
if (!Cian.hasCache(id))
{
mSponsoredAdapter = new CianAdapter(url, false, this);
mRvSponsoredProducts.setAdapter(mSponsoredAdapter);
@ -1311,6 +1316,12 @@ public class PlacePageView extends RelativeLayout
Viator.requestViatorProducts(policy, mSponsored.getId(), currencyCode);
showLoadingViatorProducts(mSponsored.getId(), mSponsored.getUrl());
}
else if (mSponsored.getType() == Sponsored.TYPE_CIAN)
{
Cian.getRentNearby(policy, mMapObject.getLat(), mMapObject.getLon(),
mMapObject.getFeatureId());
showLoadingCianProducts(mMapObject.getFeatureId(), mSponsored.getUrl());
}
}
Sponsored.requestInfo(mSponsored, Locale.getDefault().toString(), policy);
}

View file

@ -16,7 +16,7 @@ import java.util.List;
public class PlacePageTracker
{
private static final float VISIBILITY_RATIO_VIATOR = 0.3f;
private static final float VISIBILITY_RATIO_SPONSORED_GALLERY = 0.3f;
private static final float VISIBILITY_RATIO_TAXI = 1f;
@NonNull
private final PlacePageView mPlacePageView;
@ -25,19 +25,19 @@ public class PlacePageTracker
@NonNull
private final View mTaxi;
@NonNull
private final View mViator;
private final View mSponsoredGallery;
@Nullable
private MapObject mMapObject;
private boolean mTaxiTracked;
private boolean mViatorTracked;
private boolean mSponsoredTracked;
public PlacePageTracker(@NonNull PlacePageView placePageView)
{
mPlacePageView = placePageView;
mBottomButtons = mPlacePageView.findViewById(R.id.pp__buttons);
mTaxi = mPlacePageView.findViewById(R.id.ll__place_page_taxi);
mViator = mPlacePageView.findViewById(R.id.ll__place_sponsored_gallery);
mSponsoredGallery = mPlacePageView.findViewById(R.id.ll__place_sponsored_gallery);
}
public void setMapObject(@Nullable MapObject mapObject)
@ -48,13 +48,13 @@ public class PlacePageTracker
public void onMove()
{
trackTaxiVisibility();
trackViatorVisibility();
trackSponsoredGalleryVisibility();
}
public void onHidden()
{
mTaxiTracked = false;
mViatorTracked = false;
mSponsoredTracked = false;
}
public void onOpened()
@ -82,14 +82,14 @@ public class PlacePageTracker
}
}
private void trackViatorVisibility()
private void trackSponsoredGalleryVisibility()
{
if (!mViatorTracked && isViewOnScreen(mViator, VISIBILITY_RATIO_VIATOR)
if (!mSponsoredTracked && isViewOnScreen(mSponsoredGallery, VISIBILITY_RATIO_SPONSORED_GALLERY)
&& mPlacePageView.getSponsored() != null)
{
Sponsored sponsored = mPlacePageView.getSponsored();
Statistics.INSTANCE.trackSponsoredGalleryShown(sponsored.getType());
mViatorTracked = true;
mSponsoredTracked = true;
}
}

View file

@ -81,6 +81,7 @@ import static com.mapswithme.util.statistics.Statistics.EventParam.RESTAURANT_LO
import static com.mapswithme.util.statistics.Statistics.EventParam.TYPE;
import static com.mapswithme.util.statistics.Statistics.EventParam.VALUE;
import static com.mapswithme.util.statistics.Statistics.ParamValue.BOOKING_COM;
import static com.mapswithme.util.statistics.Statistics.ParamValue.CIAN;
import static com.mapswithme.util.statistics.Statistics.ParamValue.GEOCHAT;
import static com.mapswithme.util.statistics.Statistics.ParamValue.OPENTABLE;
import static com.mapswithme.util.statistics.Statistics.ParamValue.SEARCH_BOOKING_COM;
@ -340,6 +341,7 @@ public enum Statistics
public static final String OPENTABLE = "OpenTable";
public static final String VIATOR = "Viator.Com";
public static final String GEOCHAT = "Geochat";
public static final String CIAN = "Cian";
}
// Initialized once in constructor and does not change until the process restarts.
@ -769,6 +771,8 @@ public enum Statistics
return GEOCHAT;
case Sponsored.TYPE_OPENTABLE:
return OPENTABLE;
case Sponsored.TYPE_CIAN:
return CIAN;
case Sponsored.TYPE_NONE:
return "N/A";
default: