Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorКузнецова Ксения <x.kuznetsow@gmail.com>2017-08-22 11:49:12 +0300
committerRoman Kuznetsov <r.kuznetsow@gmail.com>2017-09-27 11:36:03 +0300
commitcf324e4bbba41daf816942b6a2a7fa6e6832fee6 (patch)
tree9478aef256a6c6efb695fe1dd36e75e5f7582612
parenta1859a6f48c0cdbd090b0af27e0e0d47a923180e (diff)
Added Google Ads
-rw-r--r--android/build.gradle1
-rw-r--r--android/res/values/attrs.xml25
-rw-r--r--android/res/values/styles-google-ads.xml52
-rw-r--r--android/src/com/mapswithme/maps/ads/GoogleSearchAd.java6
-rw-r--r--android/src/com/mapswithme/maps/search/GoogleAdsBanner.java28
-rw-r--r--android/src/com/mapswithme/maps/search/GoogleAdsLoader.java151
-rw-r--r--android/src/com/mapswithme/maps/search/SearchAdapter.java142
-rw-r--r--android/src/com/mapswithme/maps/search/SearchData.java6
-rw-r--r--android/src/com/mapswithme/maps/search/SearchFragment.java157
-rw-r--r--android/src/com/mapswithme/maps/search/SearchResult.java16
-rw-r--r--android/src/com/mapswithme/maps/search/SearchResultTypes.java9
11 files changed, 507 insertions, 86 deletions
diff --git a/android/build.gradle b/android/build.gradle
index c956cc4175..787d69fc0f 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -45,6 +45,7 @@ dependencies {
compile 'com.google.android.gms:play-services-analytics:10.0.1'
compile 'com.google.android.gms:play-services-plus:10.0.1'
compile 'com.google.android.gms:play-services-gcm:10.0.1'
+ compile 'com.google.android.gms:play-services-ads:10.0.1'
// statistics
compile 'com.flurry.android:analytics:6.7.0'
// crash reporting
diff --git a/android/res/values/attrs.xml b/android/res/values/attrs.xml
index f90b460c45..70de1715d2 100644
--- a/android/res/values/attrs.xml
+++ b/android/res/values/attrs.xml
@@ -39,6 +39,31 @@
<attr name="drawSmile" format="boolean"/>
</declare-styleable>
+ <declare-styleable name="GoogleAds" >
+ <attr name="colorLocation" format="string"/>
+ <attr name="fontSizeLocation" format="string"/>
+ <attr name="clickToCall" format="string"/>
+ <attr name="location" format="string"/>
+ <attr name="sellerRatings" format="string"/>
+ <attr name="siteLinks" format="string"/>
+ <attr name="number" format="string"/>
+ <attr name="fontSizeAnnotation" format="string"/>
+ <attr name="fontSizeAttribution" format="string"/>
+ <attr name="fontSizeDescription" format="string"/>
+ <attr name="fontSizeDomainLink" format="string"/>
+ <attr name="fontSizeTitle" format="string"/>
+ <attr name="colorAdBorder" format="string"/>
+ <attr name="colorAnnotation" format="string"/>
+ <attr name="colorAttribution" format="string"/>
+ <attr name="colorBackground" format="string"/>
+ <attr name="colorDomainLink" format="string"/>
+ <attr name="colorText" format="string"/>
+ <attr name="colorTitleLink" format="string"/>
+ <attr name="attributionSpacingBelow" format="string"/>
+ <attr name="noTitleUnderline" format="string"/>
+ <attr name="titleBold" format="string"/>
+ </declare-styleable>
+
<bool name="isTablet">false</bool>
<bool name="tabletLayout">false</bool>
</resources>
diff --git a/android/res/values/styles-google-ads.xml b/android/res/values/styles-google-ads.xml
new file mode 100644
index 0000000000..c3181d0178
--- /dev/null
+++ b/android/res/values/styles-google-ads.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <style name="GoogleAdsLight">
+ <item name="colorLocation">#FFF9EF</item>
+ <item name="fontSizeLocation">12</item>
+ <item name="clickToCall">true</item>
+ <item name="location">true</item>
+ <item name="sellerRatings">false</item>
+ <item name="siteLinks">false</item>
+ <item name="number">1</item>;
+ <item name="fontSizeAnnotation">12</item>
+ <item name="fontSizeAttribution">12</item>
+ <item name="fontSizeDescription">12</item>
+ <item name="fontSizeDomainLink">12</item>
+ <item name="fontSizeTitle">12</item>
+ <item name="colorAdBorder">#E0DAD1</item>
+ <item name="colorAnnotation">#75726D</item>
+ <item name="colorAttribution">#75726D</item>
+ <item name="colorBackground">#FFF9EF</item>
+ <item name="colorDomainLink">#1E96F0</item>
+ <item name="colorText">#75726D</item>
+ <item name="colorTitleLink">#21201E</item>
+ <item name="attributionSpacingBelow">4</item>
+ <item name="noTitleUnderline">true</item>
+ <item name="titleBold">true</item>
+ </style>
+
+ <style name="GoogleAdsDark">
+ <item name="colorLocation">#484B50</item>
+ <item name="fontSizeLocation">12</item>
+ <item name="clickToCall">true</item>
+ <item name="location">true</item>
+ <item name="sellerRatings">false</item>
+ <item name="siteLinks">false</item>
+ <item name="number">1</item>;
+ <item name="fontSizeAnnotation">12</item>
+ <item name="fontSizeAttribution">12</item>
+ <item name="fontSizeDescription">12</item>
+ <item name="fontSizeDomainLink">12</item>
+ <item name="fontSizeTitle">12</item>
+ <item name="colorAdBorder">#56595D</item>
+ <item name="colorAnnotation">#C8C9CA</item>
+ <item name="colorAttribution">#C8C9CA</item>
+ <item name="colorBackground">#484B50</item>
+ <item name="colorDomainLink">#51B5E6</item>
+ <item name="colorText">#C8C9CA</item>
+ <item name="colorTitleLink">#FFFFFF</item>
+ <item name="attributionSpacingBelow">4</item>
+ <item name="noTitleUnderline">true</item>
+ <item name="titleBold">true</item>
+ </style>
+</resources>
diff --git a/android/src/com/mapswithme/maps/ads/GoogleSearchAd.java b/android/src/com/mapswithme/maps/ads/GoogleSearchAd.java
index 10e7b2d4ad..1612acbdad 100644
--- a/android/src/com/mapswithme/maps/ads/GoogleSearchAd.java
+++ b/android/src/com/mapswithme/maps/ads/GoogleSearchAd.java
@@ -1,9 +1,12 @@
package com.mapswithme.maps.ads;
+import android.support.annotation.NonNull;
+
import com.mapswithme.maps.Framework;
public class GoogleSearchAd
{
+ @NonNull
private String mAdUnitId = "";
public GoogleSearchAd()
@@ -22,5 +25,6 @@ public class GoogleSearchAd
}
}
- String getAdUnitId() { return mAdUnitId; }
+ @NonNull
+ public String getAdUnitId() { return mAdUnitId; }
}
diff --git a/android/src/com/mapswithme/maps/search/GoogleAdsBanner.java b/android/src/com/mapswithme/maps/search/GoogleAdsBanner.java
new file mode 100644
index 0000000000..cd156ffd94
--- /dev/null
+++ b/android/src/com/mapswithme/maps/search/GoogleAdsBanner.java
@@ -0,0 +1,28 @@
+package com.mapswithme.maps.search;
+
+import android.support.annotation.NonNull;
+
+import com.google.android.gms.ads.search.SearchAdView;
+
+class GoogleAdsBanner implements SearchData
+{
+ @NonNull
+ private SearchAdView mAdView;
+
+ GoogleAdsBanner(@NonNull SearchAdView adView)
+ {
+ this.mAdView = adView;
+ }
+
+ @NonNull
+ SearchAdView getAdView()
+ {
+ return mAdView;
+ }
+
+ @Override
+ public int getItemViewType()
+ {
+ return SearchResultTypes.TYPE_GOOGLE_ADS;
+ }
+}
diff --git a/android/src/com/mapswithme/maps/search/GoogleAdsLoader.java b/android/src/com/mapswithme/maps/search/GoogleAdsLoader.java
new file mode 100644
index 0000000000..1e6b131c1a
--- /dev/null
+++ b/android/src/com/mapswithme/maps/search/GoogleAdsLoader.java
@@ -0,0 +1,151 @@
+package com.mapswithme.maps.search;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import com.google.ads.mediation.admob.AdMobAdapter;
+import com.google.android.gms.ads.AdListener;
+import com.google.android.gms.ads.AdSize;
+import com.google.android.gms.ads.search.SearchAdRequest;
+import com.google.android.gms.ads.search.SearchAdView;
+import com.mapswithme.maps.R;
+import com.mapswithme.maps.ads.GoogleSearchAd;
+import com.mapswithme.util.ThemeUtils;
+import com.mapswithme.util.concurrency.UiThread;
+
+class GoogleAdsLoader
+{
+ private long mLoadingDelay;
+ @NonNull
+ private final Bundle mStyleParams = new Bundle();
+ @Nullable
+ private GoogleSearchAd mGoogleSearchAd;
+ @Nullable
+ private Runnable mLoadingTask;
+ @NonNull
+ private String mQuery = "";
+ @Nullable
+ private AdvertLoadingListener mLoadingListener;
+
+ GoogleAdsLoader(@NonNull Context context, long loadingDelay)
+ {
+ this.mLoadingDelay = loadingDelay;
+ initStyle(context);
+ }
+
+ void scheduleAdsLoading(@NonNull final Context context, @NonNull final String query)
+ {
+ cancelAdsLoading();
+ mQuery = query;
+
+ mGoogleSearchAd = new GoogleSearchAd();
+ if (mGoogleSearchAd.getAdUnitId().isEmpty())
+ return;
+
+ mLoadingTask = new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ performLoading(context);
+ }
+ };
+ UiThread.runLater(mLoadingTask, mLoadingDelay);
+ }
+
+ void cancelAdsLoading()
+ {
+ if (mLoadingTask != null)
+ {
+ UiThread.cancelDelayedTasks(mLoadingTask);
+ mLoadingTask = null;
+ }
+ }
+
+ private void updateAdView(SearchAdView searchAdView)
+ {
+ SearchAdRequest.Builder builder = new SearchAdRequest.Builder()
+ .setQuery(mQuery)
+ .addNetworkExtrasBundle(AdMobAdapter.class, mStyleParams);
+
+ searchAdView.loadAd(builder.build());
+ }
+
+ void attach(@NonNull AdvertLoadingListener listener)
+ {
+ mLoadingListener = listener;
+ }
+
+ void detach()
+ {
+ mLoadingListener = null;
+ }
+
+ private void initStyle(@NonNull Context context)
+ {
+ TypedArray attrs = context.obtainStyledAttributes(ThemeUtils.isNightTheme() ?
+ R.style.GoogleAdsDark : R.style.GoogleAdsLight, R.styleable.GoogleAds);
+
+ mStyleParams.putString("csa_width", "auto");
+ mStyleParams.putString("csa_colorLocation", attrs.getString(R.styleable.GoogleAds_colorLocation));
+ mStyleParams.putString("csa_fontSizeLocation", attrs.getString(R.styleable.GoogleAds_fontSizeLocation));
+ mStyleParams.putString("csa_clickToCall", attrs.getString(R.styleable.GoogleAds_clickToCall));
+ mStyleParams.putString("csa_location", attrs.getString(R.styleable.GoogleAds_location));
+ mStyleParams.putString("csa_sellerRatings", attrs.getString(R.styleable.GoogleAds_sellerRatings));
+ mStyleParams.putString("csa_siteLinks", attrs.getString(R.styleable.GoogleAds_siteLinks));
+ mStyleParams.putString("csa_number", attrs.getString(R.styleable.GoogleAds_number));
+ mStyleParams.putString("csa_fontSizeAnnotation", attrs.getString(R.styleable.GoogleAds_fontSizeAnnotation));
+ mStyleParams.putString("csa_fontSizeAttribution", attrs.getString(R.styleable.GoogleAds_fontSizeAttribution));
+ mStyleParams.putString("csa_fontSizeDescription", attrs.getString(R.styleable.GoogleAds_fontSizeDescription));
+ mStyleParams.putString("csa_fontSizeDomainLink", attrs.getString(R.styleable.GoogleAds_fontSizeDomainLink));
+ mStyleParams.putString("csa_fontSizeTitle", attrs.getString(R.styleable.GoogleAds_fontSizeTitle));
+ mStyleParams.putString("csa_colorAdBorder", attrs.getString(R.styleable.GoogleAds_colorAdBorder));
+ mStyleParams.putString("csa_colorAnnotation", attrs.getString(R.styleable.GoogleAds_colorAnnotation));
+ mStyleParams.putString("csa_colorAttribution", attrs.getString(R.styleable.GoogleAds_colorAttribution));
+ mStyleParams.putString("csa_colorBackground", attrs.getString(R.styleable.GoogleAds_colorBackground));
+ mStyleParams.putString("csa_colorDomainLink", attrs.getString(R.styleable.GoogleAds_colorDomainLink));
+ mStyleParams.putString("csa_colorText", attrs.getString(R.styleable.GoogleAds_colorText));
+ mStyleParams.putString("csa_colorTitleLink", attrs.getString(R.styleable.GoogleAds_colorTitleLink));
+ mStyleParams.putString("csa_attributionSpacingBelow", attrs.getString(R.styleable.GoogleAds_attributionSpacingBelow));
+ mStyleParams.putString("csa_noTitleUnderline", attrs.getString(R.styleable.GoogleAds_noTitleUnderline));
+ mStyleParams.putString("csa_titleBold", attrs.getString(R.styleable.GoogleAds_titleBold));
+ attrs.recycle();
+ }
+
+ private void performLoading(@NonNull Context context)
+ {
+ if (mGoogleSearchAd == null)
+ throw new AssertionError("mGoogleSearchAd can't be null here");
+
+ final SearchAdView view = new SearchAdView(context);
+ view.setAdSize(AdSize.SEARCH);
+ view.setAdUnitId(mGoogleSearchAd.getAdUnitId());
+ updateAdView(view);
+ view.setAdListener(new AdListener()
+ {
+ @Override
+ public void onAdLoaded()
+ {
+ mLoadingTask = null;
+ if (mLoadingListener != null)
+ {
+ mLoadingListener.onLoadingFinished(view);
+ }
+ }
+
+ @Override
+ public void onAdFailedToLoad(int i)
+ {
+ mLoadingTask = null;
+ }
+ });
+ }
+
+ interface AdvertLoadingListener
+ {
+ void onLoadingFinished(@NonNull SearchAdView searchAdView);
+ }
+}
diff --git a/android/src/com/mapswithme/maps/search/SearchAdapter.java b/android/src/com/mapswithme/maps/search/SearchAdapter.java
index 5e0069bbc8..aa1300f871 100644
--- a/android/src/com/mapswithme/maps/search/SearchAdapter.java
+++ b/android/src/com/mapswithme/maps/search/SearchAdapter.java
@@ -13,6 +13,7 @@ import android.text.style.StyleSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.FrameLayout;
import android.widget.TextView;
import com.mapswithme.maps.R;
@@ -21,23 +22,29 @@ import com.mapswithme.util.Graphics;
import com.mapswithme.util.ThemeUtils;
import com.mapswithme.util.UiUtils;
-class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.BaseViewHolder>
+class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.SearchDataViewHolder>
{
- private static final int TYPE_SUGGEST = 0;
- private static final int TYPE_RESULT = 1;
- private static final int TYPE_LOCAL_ADS_CUSTOMER = 2;
-
private final SearchFragment mSearchFragment;
- private SearchResult[] mResults;
+ private SearchData[] mResults;
private final Drawable mClosedMarkerBackground;
- static abstract class BaseViewHolder extends RecyclerView.ViewHolder
+ static abstract class SearchDataViewHolder extends RecyclerView.ViewHolder
+ {
+ SearchDataViewHolder(@NonNull View itemView)
+ {
+ super(itemView);
+ }
+
+ abstract void bind(@NonNull SearchData searchData, int position);
+ }
+
+ private static abstract class BaseResultViewHolder extends SearchDataViewHolder
{
SearchResult mResult;
// Position within search results
int mOrder;
- BaseViewHolder(View view)
+ BaseResultViewHolder(@NonNull View view)
{
super(view);
if (view instanceof TextView)
@@ -46,25 +53,6 @@ class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.BaseViewHolder>
if (tintAttr != 0)
Graphics.tint((TextView)view, tintAttr);
}
- }
-
- @AttrRes int getTintAttr()
- {
- return R.attr.colorAccent;
- }
-
- void bind(@NonNull SearchResult result, int order)
- {
- mResult = result;
- mOrder = order;
- }
- }
-
- private static abstract class BaseResultViewHolder extends BaseViewHolder
- {
- BaseResultViewHolder(View view)
- {
- super(view);
view.setOnClickListener(new View.OnClickListener()
{
@Override
@@ -76,26 +64,33 @@ class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.BaseViewHolder>
}
@Override
- void bind(@NonNull SearchResult result, int order)
+ void bind(@NonNull SearchData result, int order)
{
- super.bind(result, order);
-
- SpannableStringBuilder builder = new SpannableStringBuilder(result.name);
- if (result.highlightRanges != null)
+ mResult = (SearchResult)result;
+ mOrder = order;
+ SpannableStringBuilder builder = new SpannableStringBuilder(mResult.name);
+ if (mResult.highlightRanges != null)
{
- final int size = result.highlightRanges.length / 2;
+ final int size = mResult.highlightRanges.length / 2;
int index = 0;
for (int i = 0; i < size; i++)
{
- final int start = result.highlightRanges[index++];
- final int len = result.highlightRanges[index++];
+ final int start = mResult.highlightRanges[index++];
+ final int len = mResult.highlightRanges[index++];
builder.setSpan(new StyleSpan(Typeface.BOLD), start, start + len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
- getTitleView().setText(builder);
+ TextView titleView = getTitleView();
+ if (titleView != null)
+ titleView.setText(builder);
+ }
+
+ @AttrRes int getTintAttr()
+ {
+ return R.attr.colorAccent;
}
abstract TextView getTitleView();
@@ -123,6 +118,25 @@ class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.BaseViewHolder>
}
}
+ private static class GoogleAdsViewHolder extends SearchDataViewHolder
+ {
+ @NonNull
+ private ViewGroup container;
+
+ GoogleAdsViewHolder(@NonNull View view)
+ {
+ super(view);
+ container = (FrameLayout)view;
+ }
+
+ @Override
+ void bind(@NonNull SearchData searchData, int position)
+ {
+ container.removeAllViews();
+ container.addView(((GoogleAdsBanner)searchData).getAdView());
+ }
+ }
+
private class ResultViewHolder extends BaseResultViewHolder
{
final TextView mName;
@@ -205,16 +219,16 @@ class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.BaseViewHolder>
}
@Override
- void bind(@NonNull SearchResult result, int order)
+ void bind(@NonNull SearchData result, int order)
{
super.bind(result, order);
// TODO: Support also "Open Now" mark.
- UiUtils.showIf(result.description.openNow == SearchResult.OPEN_NOW_NO, mClosedMarker);
- UiUtils.setTextAndHideIfEmpty(mDescription, formatDescription(result));
- UiUtils.setTextAndHideIfEmpty(mRegion, result.description.region);
- UiUtils.setTextAndHideIfEmpty(mDistance, result.description.distance);
- UiUtils.setTextAndHideIfEmpty(mPriceCategory, result.description.pricing);
+ UiUtils.showIf(mResult.description.openNow == SearchResult.OPEN_NOW_NO, mClosedMarker);
+ UiUtils.setTextAndHideIfEmpty(mDescription, formatDescription(mResult));
+ UiUtils.setTextAndHideIfEmpty(mRegion, mResult.description.region);
+ UiUtils.setTextAndHideIfEmpty(mDistance, mResult.description.distance);
+ UiUtils.setTextAndHideIfEmpty(mPriceCategory, mResult.description.pricing);
}
@Override
@@ -245,29 +259,31 @@ class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.BaseViewHolder>
}
@Override
- public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
+ public SearchDataViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
{
final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
switch (viewType)
{
- case TYPE_SUGGEST:
- return new SuggestViewHolder(inflater.inflate(R.layout.item_search_suggest, parent, false));
+ case SearchResultTypes.TYPE_SUGGEST:
+ return new SuggestViewHolder(inflater.inflate(R.layout.item_search_suggest, parent, false));
+
+ case SearchResultTypes.TYPE_RESULT:
+ return new ResultViewHolder(inflater.inflate(R.layout.item_search_result, parent, false));
- case TYPE_RESULT:
- return new ResultViewHolder(inflater.inflate(R.layout.item_search_result, parent, false));
+ case SearchResultTypes.TYPE_LOCAL_ADS_CUSTOMER:
+ return new LocalAdsCustomerViewHolder(inflater.inflate(R.layout.item_search_result, parent, false));
- case TYPE_LOCAL_ADS_CUSTOMER:
- return new LocalAdsCustomerViewHolder(inflater.inflate(R.layout.item_search_result, parent,
- false));
+ case SearchResultTypes.TYPE_GOOGLE_ADS:
+ return new GoogleAdsViewHolder(new FrameLayout(parent.getContext()));
- default:
- throw new IllegalArgumentException("Unhandled view type given");
+ default:
+ throw new IllegalArgumentException("Unhandled view type given");
}
}
@Override
- public void onBindViewHolder(BaseViewHolder holder, int position)
+ public void onBindViewHolder(@NonNull SearchDataViewHolder holder, int position)
{
holder.bind(mResults[position], position);
}
@@ -275,20 +291,7 @@ class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.BaseViewHolder>
@Override
public int getItemViewType(int position)
{
- switch (mResults[position].type)
- {
- case SearchResult.TYPE_SUGGEST:
- return TYPE_SUGGEST;
-
- case SearchResult.TYPE_RESULT:
- return TYPE_RESULT;
-
- case SearchResult.TYPE_LOCAL_ADS_CUSTOMER:
- return TYPE_LOCAL_ADS_CUSTOMER;
-
- default:
- throw new IllegalArgumentException("Unhandled SearchResult type");
- }
+ return mResults[position].getItemViewType();
}
boolean showPopulateButton()
@@ -296,7 +299,8 @@ class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.BaseViewHolder>
return (!RoutingController.get().isWaitingPoiPick() &&
mResults != null &&
mResults.length > 0 &&
- mResults[0].type != SearchResult.TYPE_SUGGEST);
+ SearchResult.class.isInstance(mResults[0]) &&
+ ((SearchResult) mResults[0]).type != SearchResultTypes.TYPE_SUGGEST);
}
@Override
@@ -321,7 +325,7 @@ class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.BaseViewHolder>
refreshData(null);
}
- void refreshData(SearchResult[] results)
+ void refreshData(SearchData[] results)
{
mResults = results;
notifyDataSetChanged();
diff --git a/android/src/com/mapswithme/maps/search/SearchData.java b/android/src/com/mapswithme/maps/search/SearchData.java
new file mode 100644
index 0000000000..5a6e488f57
--- /dev/null
+++ b/android/src/com/mapswithme/maps/search/SearchData.java
@@ -0,0 +1,6 @@
+package com.mapswithme.maps.search;
+
+interface SearchData
+{
+ int getItemViewType();
+}
diff --git a/android/src/com/mapswithme/maps/search/SearchFragment.java b/android/src/com/mapswithme/maps/search/SearchFragment.java
index ff443d599c..7ff548ecc7 100644
--- a/android/src/com/mapswithme/maps/search/SearchFragment.java
+++ b/android/src/com/mapswithme/maps/search/SearchFragment.java
@@ -20,6 +20,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import com.google.android.gms.ads.search.SearchAdView;
import com.mapswithme.maps.MwmActivity;
import com.mapswithme.maps.MwmApplication;
import com.mapswithme.maps.R;
@@ -35,12 +36,16 @@ import com.mapswithme.maps.routing.RoutingController;
import com.mapswithme.maps.widget.PlaceholderView;
import com.mapswithme.maps.widget.SearchToolbarController;
import com.mapswithme.maps.widget.placepage.Sponsored;
+import com.mapswithme.util.ConnectionState;
+import com.mapswithme.util.SharedPropertiesUtils;
import com.mapswithme.util.UiUtils;
import com.mapswithme.util.Utils;
+import com.mapswithme.util.concurrency.UiThread;
import com.mapswithme.util.log.LoggerFactory;
import com.mapswithme.util.statistics.Statistics;
import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.List;
public class SearchFragment extends BaseMwmFragment
@@ -51,9 +56,38 @@ public class SearchFragment extends BaseMwmFragment
HotelsFilterHolder
{
public static final String PREFS_SHOW_ENABLE_LOGGING_SETTING = "ShowEnableLoggingSetting";
+ private static final int MIN_QUERY_LENGTH_FOR_AD = 3;
+ private static final long ADS_DELAY_MS = 200;
+ private static final long RESULTS_DELAY_MS = 400;
+ private static final int AD_POSITION = 3;
private long mLastQueryTimestamp;
+ @Nullable
+ private GoogleAdsLoader mAdsLoader;
+ private boolean mAdsRequested = false;
+ private int mAdsOrientation = -1;
+ @Nullable
+ private SearchAdView mGoogleAdView;
+ @NonNull
+ private final Runnable mResultsShowingTask = new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ refreshSearchResults();
+ }
+ };
+ @NonNull
+ private final Runnable mSearchEndTask = new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ onSearchEnd();
+ }
+ };
+
private static class LastPosition
{
double lat;
@@ -87,6 +121,11 @@ public class SearchFragment extends BaseMwmFragment
if (!isAdded())
return;
+ UiThread.cancelDelayedTasks(mSearchEndTask);
+ UiThread.cancelDelayedTasks(mResultsShowingTask);
+ mGoogleAdView = null;
+ stopAdsLoading();
+
if (TextUtils.isEmpty(query))
{
mSearchAdapter.clear();
@@ -105,6 +144,12 @@ public class SearchFragment extends BaseMwmFragment
if (mCianCategorySelected)
return;
+ if (mAdsLoader != null && !isInteractiveSearch() && query.length() >= MIN_QUERY_LENGTH_FOR_AD)
+ {
+ mAdsRequested = true;
+ mAdsLoader.scheduleAdsLoading(getActivity().getApplicationContext(), query);
+ }
+
runSearch();
}
@@ -188,6 +233,10 @@ public class SearchFragment extends BaseMwmFragment
@Nullable
private HotelsFilter mInitialHotelsFilter;
+ private boolean mIsHotel;
+ @NonNull
+ private SearchResult[] mSearchResults = new SearchResult[0];
+
private final LocationListener mLocationListener = new LocationListener.Simple()
{
@Override
@@ -299,6 +348,20 @@ public class SearchFragment extends BaseMwmFragment
super.onViewCreated(view, savedInstanceState);
readArguments();
+ if (ConnectionState.isWifiConnected() && SharedPropertiesUtils.isShowcaseSwitchedOnLocal())
+ {
+ mAdsLoader = new GoogleAdsLoader(getContext(), ADS_DELAY_MS);
+ mAdsLoader.attach(new GoogleAdsLoader.AdvertLoadingListener()
+ {
+ @Override
+ public void onLoadingFinished(@NonNull SearchAdView searchAdView)
+ {
+ mGoogleAdView = searchAdView;
+ mAdsRequested = false;
+ }
+ });
+ }
+
ViewGroup root = (ViewGroup) view;
mAppBarLayout = (AppBarLayout) root.findViewById(R.id.app_bar);
mToolbarLayout = (CollapsingToolbarLayout) mAppBarLayout.findViewById(R.id.collapsing_toolbar);
@@ -398,7 +461,6 @@ public class SearchFragment extends BaseMwmFragment
mFilterController.onSaveState(outState);
}
-
public void onResume()
{
super.onResume();
@@ -425,6 +487,14 @@ public class SearchFragment extends BaseMwmFragment
super.onDestroy();
}
+ @Override
+ public void onDestroyView()
+ {
+ if (mAdsLoader != null)
+ mAdsLoader.detach();
+ super.onDestroyView();
+ }
+
private String getQuery()
{
return mToolbarController.getQuery();
@@ -525,6 +595,12 @@ public class SearchFragment extends BaseMwmFragment
private void onSearchEnd()
{
+ if (mSearchRunning && isAdded())
+ updateSearchView();
+ }
+
+ private void updateSearchView()
+ {
mSearchRunning = false;
mToolbarController.showProgress(false);
updateFrames();
@@ -535,7 +611,13 @@ public class SearchFragment extends BaseMwmFragment
{
SearchEngine.cancelApiCall();
SearchEngine.cancelAllSearches();
- onSearchEnd();
+ updateSearchView();
+ }
+
+ private boolean isInteractiveSearch()
+ {
+ // TODO @yunitsky Implement more elegant solution.
+ return getActivity() instanceof MwmActivity;
}
private void runSearch()
@@ -545,8 +627,7 @@ public class SearchFragment extends BaseMwmFragment
hotelsFilter = mFilterController.getFilter();
mLastQueryTimestamp = System.nanoTime();
- // TODO @yunitsky Implement more elegant solution.
- if (getActivity() instanceof MwmActivity)
+ if (isInteractiveSearch())
{
SearchEngine.searchInteractive(
getQuery(), mLastQueryTimestamp, true /* isMapAndTable */, hotelsFilter);
@@ -572,19 +653,32 @@ public class SearchFragment extends BaseMwmFragment
if (!isAdded() || !mToolbarController.hasQuery())
return;
- // Search is running hence results updated.
- mSearchRunning = true;
- updateFrames();
- mSearchAdapter.refreshData(results);
- mToolbarController.showProgress(true);
- updateFilterButton(isHotel);
+ mSearchResults = results;
+ mIsHotel = isHotel;
+
+ if (mAdsRequested)
+ {
+ UiThread.cancelDelayedTasks(mResultsShowingTask);
+ UiThread.runLater(mResultsShowingTask, RESULTS_DELAY_MS);
+ }
+ else
+ {
+ refreshSearchResults();
+ }
}
@Override
public void onResultsEnd(long timestamp)
{
- if (mSearchRunning && isAdded())
+ if (mAdsRequested)
+ {
+ UiThread.cancelDelayedTasks(mSearchEndTask);
+ UiThread.runLater(mSearchEndTask, RESULTS_DELAY_MS);
+ }
+ else
+ {
onSearchEnd();
+ }
}
@Override
@@ -606,6 +700,38 @@ public class SearchFragment extends BaseMwmFragment
}
}
+ private void refreshSearchResults()
+ {
+ // Search is running hence results updated.
+ stopAdsLoading();
+ mSearchRunning = true;
+ updateFrames();
+ mSearchAdapter.refreshData(combineResultsWithAds());
+ mToolbarController.showProgress(true);
+ updateFilterButton(mIsHotel);
+ }
+
+ @NonNull
+ private SearchData[] combineResultsWithAds()
+ {
+ if (mSearchResults.length < AD_POSITION || mGoogleAdView == null)
+ return mSearchResults;
+
+ List<SearchData> result = new LinkedList<>();
+ int counter = 0;
+ for (SearchResult r : mSearchResults)
+ {
+ if (r.type != SearchResultTypes.TYPE_SUGGEST && counter++ == AD_POSITION)
+ result.add(new GoogleAdsBanner(mGoogleAdView));
+ else
+ result.add(r);
+ }
+
+ SearchData[] resultArray = new SearchData[result.size()];
+ result.toArray(resultArray);
+ return resultArray;
+ }
+
private void updateFilterButton(boolean isHotel)
{
if (mFilterController != null)
@@ -666,4 +792,13 @@ public class SearchFragment extends BaseMwmFragment
{
return mToolbarController;
}
+
+ private void stopAdsLoading()
+ {
+ if (mAdsLoader == null)
+ return;
+
+ mAdsLoader.cancelAdsLoading();
+ mAdsRequested = false;
+ }
}
diff --git a/android/src/com/mapswithme/maps/search/SearchResult.java b/android/src/com/mapswithme/maps/search/SearchResult.java
index b1003af705..c087310a0f 100644
--- a/android/src/com/mapswithme/maps/search/SearchResult.java
+++ b/android/src/com/mapswithme/maps/search/SearchResult.java
@@ -1,15 +1,15 @@
package com.mapswithme.maps.search;
+import static com.mapswithme.maps.search.SearchResultTypes.TYPE_LOCAL_ADS_CUSTOMER;
+import static com.mapswithme.maps.search.SearchResultTypes.TYPE_RESULT;
+import static com.mapswithme.maps.search.SearchResultTypes.TYPE_SUGGEST;
+
/**
* Class instances are created from native code.
*/
@SuppressWarnings("unused")
-public class SearchResult
+public class SearchResult implements SearchData
{
- public static final int TYPE_SUGGEST = 0;
- public static final int TYPE_RESULT = 1;
- public static final int TYPE_LOCAL_ADS_CUSTOMER = 2;
-
// Values should match osm::YesNoUnknown enum.
public static final int OPEN_NOW_UNKNOWN = 0;
public static final int OPEN_NOW_YES = 1;
@@ -78,4 +78,10 @@ public class SearchResult
this.description = description;
this.highlightRanges = highlightRanges;
}
+
+ @Override
+ public int getItemViewType()
+ {
+ return type;
+ }
}
diff --git a/android/src/com/mapswithme/maps/search/SearchResultTypes.java b/android/src/com/mapswithme/maps/search/SearchResultTypes.java
new file mode 100644
index 0000000000..03a8c5463c
--- /dev/null
+++ b/android/src/com/mapswithme/maps/search/SearchResultTypes.java
@@ -0,0 +1,9 @@
+package com.mapswithme.maps.search;
+
+class SearchResultTypes
+{
+ static final int TYPE_SUGGEST = 0;
+ static final int TYPE_RESULT = 1;
+ static final int TYPE_LOCAL_ADS_CUSTOMER = 2;
+ static final int TYPE_GOOGLE_ADS = 3;
+}