Dynamic bottom ad items.

This commit is contained in:
Dmitry Yunitsky 2014-08-15 11:38:58 +03:00 committed by Alex Zolotarev
parent eb9abbe0c3
commit 83189d1d47
8 changed files with 418 additions and 0 deletions

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_toolbar_button_selector">
<ImageView
android:id="@+id/iv__bottom_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:paddingLeft="@dimen/margin_small"/>
<TextView
android:id="@+id/tv__bottom_item_text"
android:layout_width="wrap_content"
android:layout_height="@dimen/bottom_panel_height"
android:layout_toRightOf="@id/iv__bottom_icon"
android:gravity="center_vertical"
android:textColor="@android:color/white"/>
<View
style="@style/drawerSeparatorMediumPadded"
android:layout_below="@id/tv__bottom_item_text"/>
</RelativeLayout>

View file

@ -0,0 +1,178 @@
package com.mapswithme.maps.Ads;
import com.mapswithme.maps.MWMApplication;
import com.mapswithme.util.ConnectionState;
import com.mapswithme.util.Constants;
import com.mapswithme.util.UiUtils;
import com.mapswithme.util.Utils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class AdsManager
{
private static final String ROOT_MENU_ITEMS_KEY = "AppFeatureBottomMenuItems";
private static final String MENU_ITEMS_KEY = "Items";
private static final String DEFAULT_KEY = "*";
private static final String ID_KEY = "Id";
private static final String APP_URL_KEY = "AppURL";
private static final String ICON_KEY = "IconURLs";
private static final String TITLE_KEY = "Titles";
private static final String COLOR_KEY = "Color";
private static final String WEB_URL_KEY = "WebURLs";
private static final String CACHE_FILE = "menu_ads.json";
private static List<MenuAd> sMenuAds;
public static List<MenuAd> getMenuAds()
{
return sMenuAds;
}
public static void updateMenuAds()
{
String menuAdsString;
if (ConnectionState.isConnected(MWMApplication.get()))
{
menuAdsString = getJsonAdsFromServer();
cacheMenuAds(menuAdsString);
}
else
menuAdsString = getCachedJsonString();
if (menuAdsString == null)
return;
final JSONObject menuAdsJson;
try
{
menuAdsJson = new JSONObject(menuAdsString);
sMenuAds = parseMenuAds(menuAdsJson);
} catch (JSONException e)
{
e.printStackTrace();
}
}
private static void cacheMenuAds(String menuAdsString)
{
final File cacheFile = new File(MWMApplication.get().getDataStoragePath(), CACHE_FILE);
try (FileOutputStream fileOutputStream = new FileOutputStream(cacheFile))
{
fileOutputStream.write(menuAdsString.getBytes());
fileOutputStream.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
private static String getCachedJsonString()
{
String menuAdsString = null;
final File cacheFile = new File(MWMApplication.get().getDataStoragePath(), CACHE_FILE);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(cacheFile))))
{
final StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null)
stringBuilder.append(line);
menuAdsString = stringBuilder.toString();
} catch (IOException e)
{
e.printStackTrace();
}
return menuAdsString;
}
private static List<MenuAd> parseMenuAds(JSONObject adsJson) throws JSONException
{
final List<MenuAd> ads = new ArrayList<>();
final JSONArray menuItemsJson = adsJson.getJSONObject(ROOT_MENU_ITEMS_KEY).
getJSONObject(DEFAULT_KEY).
getJSONArray(MENU_ITEMS_KEY);
final String localeKey = Locale.getDefault().getLanguage();
final String density = UiUtils.getDisplayDensityString();
for (int i = 0; i < menuItemsJson.length(); i++)
{
final JSONObject menuItemJson = menuItemsJson.getJSONObject(i);
final String icon = getStringByKeyOrDefault(menuItemJson.getJSONObject(ICON_KEY), density);
final String webUrl = getStringByKeyOrDefault(menuItemJson.getJSONObject(WEB_URL_KEY), localeKey);
final String title = getStringByKeyOrDefault(menuItemJson.getJSONObject(TITLE_KEY), localeKey);
ads.add(new MenuAd(icon,
title,
menuItemJson.getString(COLOR_KEY),
menuItemJson.getString(ID_KEY),
menuItemJson.getString(APP_URL_KEY),
webUrl));
}
return ads;
}
private static String getStringByKeyOrDefault(JSONObject json, String key) throws JSONException
{
String res = json.optString(key);
if (res.isEmpty())
res = json.optString(DEFAULT_KEY);
return res;
}
private static String getJsonAdsFromServer()
{
BufferedReader reader = null;
HttpURLConnection connection = null;
try
{
final URL url = new URL(Constants.Url.MENU_ADS_JSON);
connection = (HttpURLConnection) url.openConnection();
final int timeout = 10000;
connection.setReadTimeout(timeout);
connection.setConnectTimeout(timeout);
connection.setRequestMethod("GET");
connection.setDoInput(true);
// Starts the query
connection.connect();
final int response = connection.getResponseCode();
if (response == HttpURLConnection.HTTP_OK)
{
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
final StringBuilder builder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null)
builder.append(line).append("\n");
return builder.toString();
}
} catch (java.io.IOException e)
{
e.printStackTrace();
} finally
{
Utils.closeStream(reader);
if (connection != null)
connection.disconnect();
}
return null;
}
}

View file

@ -0,0 +1,102 @@
package com.mapswithme.maps.Ads;
import android.os.Parcel;
import android.os.Parcelable;
public class MenuAd implements Parcelable
{
private String mIconUrl;
private String mTitle;
private String mHexColor;
private String mId;
private String mAppUrl;
private String mWebUrl;
public MenuAd(String iconUrl, String title, String hexColor, String id, String appUrl, String webUrl)
{
mIconUrl = iconUrl;
mTitle = title;
mHexColor = hexColor;
mId = id;
mAppUrl = appUrl;
mWebUrl = webUrl;
}
public MenuAd(Parcel source)
{
mIconUrl = source.readString();
mTitle = source.readString();
mHexColor = source.readString();
mId = source.readString();
mAppUrl = source.readString();
mWebUrl = source.readString();
}
@Override
public String toString()
{
return mIconUrl + " " + mTitle + " " + mHexColor + " " + mId + " " + mAppUrl + " " + mWebUrl;
}
public String getAppUrl()
{
return mAppUrl;
}
public String getHexColor()
{
return mHexColor;
}
public String getIconUrl()
{
return mIconUrl;
}
public String getId()
{
return mId;
}
public String getTitle()
{
return mTitle;
}
public String getWebUrl()
{
return mWebUrl;
}
@Override
public int describeContents()
{
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags)
{
dest.writeString(mIconUrl);
dest.writeString(mTitle);
dest.writeString(mHexColor);
dest.writeString(mId);
dest.writeString(mAppUrl);
dest.writeString(mWebUrl);
}
public static final Creator<MenuAd> CREATOR = new Creator<MenuAd>()
{
@Override
public MenuAd createFromParcel(Parcel source)
{
return new MenuAd(source);
}
@Override
public MenuAd[] newArray(int size)
{
return new MenuAd[size];
}
};
}

View file

@ -7,12 +7,16 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.Point;
import android.location.Location;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.content.LocalBroadcastManager;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.MotionEvent;
@ -21,16 +25,20 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.facebook.Session;
import com.facebook.SessionState;
import com.facebook.UiLifecycleHelper;
import com.mapswithme.country.DownloadActivity;
import com.mapswithme.maps.Ads.AdsManager;
import com.mapswithme.maps.Ads.MenuAd;
import com.mapswithme.maps.Framework.OnBalloonListener;
import com.mapswithme.maps.LocationButtonImageSetter.ButtonState;
import com.mapswithme.maps.MapStorage.Index;
import com.mapswithme.maps.api.ParsedMmwRequest;
import com.mapswithme.maps.background.WorkerService;
import com.mapswithme.maps.bookmarks.BookmarkActivity;
import com.mapswithme.maps.bookmarks.BookmarkCategoriesActivity;
import com.mapswithme.maps.bookmarks.data.Bookmark;
@ -59,6 +67,7 @@ import com.mapswithme.util.statistics.Statistics;
import com.nvidia.devtech.NvEventQueueActivity;
import java.io.Serializable;
import java.util.List;
import java.util.Locale;
import java.util.Stack;
@ -115,6 +124,17 @@ public class MWMActivity extends NvEventQueueActivity
}
};
// ads in vertical toolbar
private BroadcastReceiver mUpdateAdsReceiver = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
updateToolbarAds();
}
};
private boolean mAreToolbarAdsUpdated;
public static Intent createShowMapIntent(Context context, Index index, boolean doAutoDownload)
{
return new Intent(context, DownloadResourcesActivity.class)
@ -725,6 +745,43 @@ public class MWMActivity extends NvEventQueueActivity
mFbUiHelper = new UiLifecycleHelper(this, mFbStatusCallback);
mFbUiHelper.onCreate(savedInstanceState);
updateToolbarAds();
LocalBroadcastManager.getInstance(this).registerReceiver(mUpdateAdsReceiver, new IntentFilter(WorkerService.ACTION_UPDATE_MENU_ADS));
}
private void updateToolbarAds()
{
final List<MenuAd> ads = AdsManager.getMenuAds();
if (ads != null && !mAreToolbarAdsUpdated)
{
mAreToolbarAdsUpdated = true;
int startAdMenuPosition = 7;
for (final MenuAd ad : ads)
{
final View view = getLayoutInflater().inflate(R.layout.item_bottom_toolbar, mVerticalToolbar, false);
final TextView textView = (TextView) view.findViewById(R.id.tv__bottom_item_text);
textView.setText(ad.getTitle());
try
{
textView.setTextColor(Color.parseColor(ad.getHexColor()));
} catch (IllegalArgumentException e)
{
e.printStackTrace();
}
view.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
final Intent it = new Intent(Intent.ACTION_VIEW);
it.setData(Uri.parse(ad.getAppUrl()));
startActivity(it);
}
});
mVerticalToolbar.addView(view, startAdMenuPosition++);
}
}
}
private void setUpToolbars()

View file

@ -13,6 +13,7 @@ import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import com.google.android.gms.common.GooglePlayServicesRepairableException;
import com.mapswithme.maps.MapStorage.Index;
import com.mapswithme.maps.background.Notifier;
import com.mapswithme.maps.background.WorkerService;
import com.mapswithme.maps.bookmarks.data.BookmarkManager;
import com.mapswithme.maps.guides.GuideInfo;
import com.mapswithme.maps.guides.GuidesUtils;
@ -155,6 +156,8 @@ public class MWMApplication extends android.app.Application implements MapStorag
BookmarkManager.getBookmarkManager(getApplicationContext());
Notifier.schedulePromoNotification();
WorkerService.startActionUpdateAds(this);
}
public LocationService getLocationService()

View file

@ -7,8 +7,10 @@ import android.content.SharedPreferences;
import android.location.Location;
import android.location.LocationManager;
import android.net.Uri;
import android.support.v4.content.LocalBroadcastManager;
import android.text.TextUtils;
import com.mapswithme.maps.Ads.AdsManager;
import com.mapswithme.maps.Framework;
import com.mapswithme.maps.MWMApplication;
import com.mapswithme.maps.R;
@ -33,6 +35,7 @@ public class WorkerService extends IntentService
public static final String ACTION_DOWNLOAD_COUNTRY = "com.mapswithme.maps.action.download_country";
public static final String ACTION_PROMO_NOTIFICATION_SHOW = "com.mapswithme.maps.action.notification.show";
public static final String ACTION_PROMO_NOTIFICATION_CLICK = "com.mapswithme.maps.action.notification.click";
public static final String ACTION_UPDATE_MENU_ADS = "com.mapswithme.maps.action.ads.update";
private static final String PROMO_SHOW_EVENT_NAME = "PromoShowAndroid";
private static final String PROMO_CLICK_EVENT_NAME = "PromoClickAndroid";
@ -80,6 +83,16 @@ public class WorkerService extends IntentService
context.startService(intent);
}
/**
* Starts this service to perform advertisements update for bottom menu.
*/
public static void startActionUpdateAds(Context context)
{
final Intent intent = new Intent(context, WorkerService.class);
intent.setAction(WorkerService.ACTION_UPDATE_MENU_ADS);
context.startService(intent);
}
public WorkerService()
{
super("WorkerService");
@ -109,6 +122,9 @@ public class WorkerService extends IntentService
case ACTION_PROMO_NOTIFICATION_CLICK:
promoNotificationClicked();
break;
case ACTION_UPDATE_MENU_ADS:
updateMenuAds();
break;
}
}
}
@ -220,4 +236,12 @@ public class WorkerService extends IntentService
startActivity(intent);
Statistics.INSTANCE.trackSimpleNamedEvent(PROMO_CLICK_EVENT_NAME);
}
private void updateMenuAds()
{
AdsManager.updateMenuAds();
final Intent broadcast = new Intent(ACTION_UPDATE_MENU_ADS);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
}

View file

@ -28,6 +28,7 @@ public class Constants
public static final String MAIL_MAPSME_SUBSCRIBE = "subscribe@maps.me";
public static final String DATA_SCHEME_FILE = "file";
public static final String MENU_ADS_JSON = "http://application.server/android/features.json";
private Url() {}
}

View file

@ -3,6 +3,7 @@ package com.mapswithme.util;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
@ -14,8 +15,10 @@ import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.widget.ImageView;
@ -306,6 +309,29 @@ public final class UiUtils
activity.startActivity(intent);
}
public static String getDisplayDensityString()
{
final DisplayMetrics metrics = new DisplayMetrics();
((WindowManager) MWMApplication.get().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(metrics);
switch (metrics.densityDpi)
{
case DisplayMetrics.DENSITY_LOW:
return "ldpi";
case DisplayMetrics.DENSITY_MEDIUM:
return "mdpi";
case DisplayMetrics.DENSITY_HIGH:
return "hdpi";
case DisplayMetrics.DENSITY_XHIGH:
return "xhdpi";
case DisplayMetrics.DENSITY_XXHIGH:
return "xxhdpi";
case DisplayMetrics.DENSITY_XXXHIGH:
return "xxxhdpi";
}
return "hdpi";
}
// utility class
private UiUtils()