diff --git a/android/res/drawable-hdpi/ic_rate_send.png b/android/res/drawable-hdpi/ic_rate_send.png
new file mode 100644
index 0000000000..bab7a524a7
Binary files /dev/null and b/android/res/drawable-hdpi/ic_rate_send.png differ
diff --git a/android/res/drawable-mdpi/ic_rate_send.png b/android/res/drawable-mdpi/ic_rate_send.png
new file mode 100644
index 0000000000..ea758b1d79
Binary files /dev/null and b/android/res/drawable-mdpi/ic_rate_send.png differ
diff --git a/android/res/drawable-xhdpi/ic_rate_send.png b/android/res/drawable-xhdpi/ic_rate_send.png
new file mode 100644
index 0000000000..1af2409b4a
Binary files /dev/null and b/android/res/drawable-xhdpi/ic_rate_send.png differ
diff --git a/android/res/drawable-xxhdpi/ic_rate_send.png b/android/res/drawable-xxhdpi/ic_rate_send.png
new file mode 100644
index 0000000000..4fc0439265
Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_rate_send.png differ
diff --git a/android/res/drawable/rating_bar.xml b/android/res/drawable/rating_bar.xml
new file mode 100644
index 0000000000..fea0271881
--- /dev/null
+++ b/android/res/drawable/rating_bar.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/layout/fragment_google_play_dialog.xml b/android/res/layout/fragment_google_play_dialog.xml
new file mode 100644
index 0000000000..07512f2003
--- /dev/null
+++ b/android/res/layout/fragment_google_play_dialog.xml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/values/colors.xml b/android/res/values/colors.xml
index 0de101f545..7a8bd22c05 100644
--- a/android/res/values/colors.xml
+++ b/android/res/values/colors.xml
@@ -65,4 +65,8 @@
#2291d1
+
+ #dd000000
+ #89000000
+
diff --git a/android/res/values/dimens.xml b/android/res/values/dimens.xml
index fdfebdd642..dee01598b4 100644
--- a/android/res/values/dimens.xml
+++ b/android/res/values/dimens.xml
@@ -14,6 +14,7 @@
8dp
12dp
16dp
+ 24dp
32dp
48dp
diff --git a/android/res/values/styles.xml b/android/res/values/styles.xml
index 875d37f11f..8bec8e3eea 100644
--- a/android/res/values/styles.xml
+++ b/android/res/values/styles.xml
@@ -150,4 +150,9 @@
- @drawable/ic_bg_light
+
+
\ No newline at end of file
diff --git a/android/src/com/mapswithme/country/BaseDownloadAdapter.java b/android/src/com/mapswithme/country/BaseDownloadAdapter.java
index 18e883de88..9d8c369b45 100644
--- a/android/src/com/mapswithme/country/BaseDownloadAdapter.java
+++ b/android/src/com/mapswithme/country/BaseDownloadAdapter.java
@@ -158,7 +158,7 @@ abstract class BaseDownloadAdapter extends BaseAdapter
});
}
- protected void confirmDownloadCancelation(final ViewHolder holder, final int position, final String name)
+ protected void confirmDownloadCancellation(final ViewHolder holder, final int position, final String name)
{
final Dialog dlg = new AlertDialog.Builder(mFragment.getActivity())
.setTitle(name)
@@ -376,7 +376,7 @@ abstract class BaseDownloadAdapter extends BaseAdapter
@Override
public void onClick(View v)
{
- confirmDownloadCancelation(holder, position, item.getName());
+ confirmDownloadCancellation(holder, position, item.getName());
}
});
@@ -462,7 +462,7 @@ abstract class BaseDownloadAdapter extends BaseAdapter
@Override
public void onClick(View v)
{
- confirmDownloadCancelation(holder, position, item.getName());
+ confirmDownloadCancellation(holder, position, item.getName());
}
});
holder.mInfoSlided.setVisibility(View.VISIBLE);
@@ -773,7 +773,7 @@ abstract class BaseDownloadAdapter extends BaseAdapter
processNotDownloaded(name, position, status, StorageOptions.MAP_OPTION_MAP_ONLY, holder);
break;
case MENU_CANCEL:
- confirmDownloadCancelation(holder, position, name);
+ confirmDownloadCancellation(holder, position, name);
break;
case MENU_SHOW:
showCountry(position);
diff --git a/android/src/com/mapswithme/maps/MWMActivity.java b/android/src/com/mapswithme/maps/MWMActivity.java
index 5000753d03..d7de2c0b78 100644
--- a/android/src/com/mapswithme/maps/MWMActivity.java
+++ b/android/src/com/mapswithme/maps/MWMActivity.java
@@ -49,6 +49,7 @@ import com.mapswithme.maps.Framework.OnBalloonListener;
import com.mapswithme.maps.Framework.RoutingListener;
import com.mapswithme.maps.MapStorage.Index;
import com.mapswithme.maps.ads.AdsManager;
+import com.mapswithme.maps.ads.LikesManager;
import com.mapswithme.maps.ads.MenuAd;
import com.mapswithme.maps.api.ParsedMmwRequest;
import com.mapswithme.maps.background.WorkerService;
@@ -72,7 +73,6 @@ import com.mapswithme.maps.settings.UnitLocale;
import com.mapswithme.maps.widget.MapInfoView;
import com.mapswithme.maps.widget.MapInfoView.OnVisibilityChangedListener;
import com.mapswithme.maps.widget.MapInfoView.State;
-import com.mapswithme.util.ConnectionState;
import com.mapswithme.util.Constants;
import com.mapswithme.util.InputUtils;
import com.mapswithme.util.LocationUtils;
@@ -159,6 +159,7 @@ public class MWMActivity extends NvEventQueueActivity
private boolean mIsFragmentContainer;
private LocationPredictor mLocationPredictor;
+ private LikesManager mLikesManager;
public static Intent createShowMapIntent(Context context, Index index, boolean doAutoDownload)
{
@@ -730,6 +731,7 @@ public class MWMActivity extends NvEventQueueActivity
LocalBroadcastManager.getInstance(this).registerReceiver(mUpdateAdsReceiver, new IntentFilter(WorkerService.ACTION_UPDATE_MENU_ADS));
mLocationPredictor = new LocationPredictor(new Handler(), this);
+ mLikesManager = new LikesManager(this);
}
private void initViews()
@@ -1127,16 +1129,6 @@ public class MWMActivity extends NvEventQueueActivity
LocationState.INSTANCE.removeLocationStateModeListener(mLocationStateModeListenerId);
}
- @Override
- protected void onPause()
- {
- pauseLocation();
- stopWatchingExternalStorage();
- stopWatchingCompassStatusUpdate();
- super.onPause();
- mLocationPredictor.pause();
- }
-
@Override
protected void onResume()
{
@@ -1155,6 +1147,18 @@ public class MWMActivity extends NvEventQueueActivity
tryResumeRouting();
MWMApplication.get().onMwmResume(this);
mLocationPredictor.resume();
+ mLikesManager.showLikeDialogs();
+ }
+
+ @Override
+ protected void onPause()
+ {
+ pauseLocation();
+ stopWatchingExternalStorage();
+ stopWatchingCompassStatusUpdate();
+ super.onPause();
+ mLocationPredictor.pause();
+ mLikesManager.cancelLikeDialogs();
}
private void tryResumeRouting()
diff --git a/android/src/com/mapswithme/maps/MWMApplication.java b/android/src/com/mapswithme/maps/MWMApplication.java
index c3772eb764..1a9ec9209f 100644
--- a/android/src/com/mapswithme/maps/MWMApplication.java
+++ b/android/src/com/mapswithme/maps/MWMApplication.java
@@ -284,7 +284,10 @@ public class MWMApplication extends android.app.Application implements ActiveCou
final int sessionNum = nativeGetInt(SESSION_NUMBER_SETTING, 0);
final long lastSessionTimestamp = nativeGetLong(LAST_SESSION_TIMESTAMP_SETTING, 0);
if (!DateUtils.isToday(lastSessionTimestamp))
+ {
nativeSetInt(SESSION_NUMBER_SETTING, sessionNum + 1);
+ nativeSetLong(LAST_SESSION_TIMESTAMP_SETTING, System.currentTimeMillis());
+ }
}
private void trackAppActivation()
diff --git a/android/src/com/mapswithme/maps/ads/GooglePlusDialogFragment.java b/android/src/com/mapswithme/maps/ads/GooglePlusDialogFragment.java
index fce107241e..47a047c9a0 100644
--- a/android/src/com/mapswithme/maps/ads/GooglePlusDialogFragment.java
+++ b/android/src/com/mapswithme/maps/ads/GooglePlusDialogFragment.java
@@ -2,6 +2,7 @@ package com.mapswithme.maps.ads;
import android.app.AlertDialog;
import android.app.Dialog;
+import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
@@ -11,10 +12,21 @@ import android.view.View;
import com.google.android.gms.plus.PlusOneButton;
import com.mapswithme.maps.R;
import com.mapswithme.util.Constants;
+import com.mapswithme.util.statistics.Statistics;
public class GooglePlusDialogFragment extends DialogFragment
{
+ @Override
+ public void onResume()
+ {
+ super.onResume();
+
+ PlusOneButton plusButton = (PlusOneButton) getDialog().findViewById(R.id.btn__gplus);
+ if (plusButton != null)
+ plusButton.initialize(Constants.Url.PLAY_MARKET_HTTPS_APP_PREFIX + Constants.Package.MWM_PRO_PACKAGE, 0);
+ }
+
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
@@ -23,10 +35,24 @@ public class GooglePlusDialogFragment extends DialogFragment
final LayoutInflater inflater = getActivity().getLayoutInflater();
final View root = inflater.inflate(R.layout.fragment_google_plus_dialog, null);
- builder.setView(root);
- PlusOneButton plusButton = (PlusOneButton) root.findViewById(R.id.btn__gplus);
- plusButton.initialize(Constants.Url.PLAY_MARKET_HTTPS_APP_PREFIX + Constants.Package.MWM_PRO_PACKAGE, 1);
+ builder.
+ setView(root).
+ setNegativeButton(getString(R.string.remind_me_later), new DialogInterface.OnClickListener()
+ {
+ @Override
+ public void onClick(DialogInterface dialog, int which)
+ {
+ Statistics.INSTANCE.trackSimpleNamedEvent(Statistics.EventName.PLUS_DIALOG_LATER);
+ }
+ });
return builder.create();
}
+
+ @Override
+ public void onCancel(DialogInterface dialog)
+ {
+ super.onCancel(dialog);
+ Statistics.INSTANCE.trackSimpleNamedEvent(Statistics.EventName.PLUS_DIALOG_LATER);
+ }
}
diff --git a/android/src/com/mapswithme/maps/ads/LikesManager.java b/android/src/com/mapswithme/maps/ads/LikesManager.java
new file mode 100644
index 0000000000..a516fd4529
--- /dev/null
+++ b/android/src/com/mapswithme/maps/ads/LikesManager.java
@@ -0,0 +1,102 @@
+package com.mapswithme.maps.ads;
+
+import android.os.Handler;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.app.FragmentActivity;
+
+import com.mapswithme.maps.MWMApplication;
+
+import java.lang.ref.WeakReference;
+import java.util.Arrays;
+
+public class LikesManager
+{
+ public static final Integer[] GPLAY_NEW_USERS = new Integer[]{3, 7, 10, 15, 21};
+ public static final Integer[] GPLUS_NEW_USERS = new Integer[]{11, 20, 30, 40, 50};
+ public static final Integer[] GPLAY_OLD_USERS = new Integer[]{1, 7, 10, 15, 21};
+ public static final Integer[] GPLUS_OLD_USERS = new Integer[]{4, 14, 24, 34, 44};
+
+ private final boolean mIsNewUser;
+ private final int mSessionNum;
+
+ private Handler mHandler;
+ private Runnable mLikeRunnable;
+ private WeakReference mActivityRef;
+
+ public static final String LAST_RATED_SESSION = "LastRatedSession";
+
+ public LikesManager(FragmentActivity activity)
+ {
+ mHandler = new Handler(activity.getMainLooper());
+ mActivityRef = new WeakReference<>(activity);
+
+ mIsNewUser = MWMApplication.get().getFirstInstallVersion() >= 430;
+ mSessionNum = MWMApplication.get().getSessionsNumber();
+ }
+
+ public void showLikeDialogs()
+ {
+ if (mIsNewUser)
+ {
+ if (Arrays.asList(GPLAY_NEW_USERS).contains(mSessionNum))
+ displayLikeDialog(RateStoreDialogFragment.class);
+ else if (Arrays.asList(GPLUS_NEW_USERS).contains(mSessionNum))
+ displayLikeDialog(GooglePlusDialogFragment.class);
+ }
+ else
+ {
+ if (Arrays.asList(GPLAY_OLD_USERS).contains(mSessionNum))
+ displayLikeDialog(RateStoreDialogFragment.class);
+ else if (Arrays.asList(GPLUS_OLD_USERS).contains(mSessionNum))
+ displayLikeDialog(GooglePlusDialogFragment.class);
+ }
+ }
+
+ private void displayLikeDialog(final Class extends DialogFragment> dialogFragmentClass)
+ {
+ if (isSessionRated())
+ return;
+ setSessionRated();
+
+ mHandler.removeCallbacks(mLikeRunnable);
+ mLikeRunnable = new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ final FragmentActivity activity = mActivityRef.get();
+ if (activity == null)
+ return;
+
+ final DialogFragment fragment;
+ try
+ {
+ fragment = dialogFragmentClass.newInstance();
+ fragment.show(activity.getSupportFragmentManager(), null);
+ } catch (InstantiationException e)
+ {
+ e.printStackTrace();
+ } catch (IllegalAccessException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ };
+ mHandler.postDelayed(mLikeRunnable, 1);
+ }
+
+ public void cancelLikeDialogs()
+ {
+ mHandler.removeCallbacks(mLikeRunnable);
+ }
+
+ public boolean isSessionRated()
+ {
+ return MWMApplication.get().nativeGetInt(LAST_RATED_SESSION, 0) >= mSessionNum;
+ }
+
+ public void setSessionRated()
+ {
+ MWMApplication.get().nativeSetInt(LAST_RATED_SESSION, mSessionNum);
+ }
+}
diff --git a/android/src/com/mapswithme/maps/ads/RateStoreDialogFragment.java b/android/src/com/mapswithme/maps/ads/RateStoreDialogFragment.java
new file mode 100644
index 0000000000..6773c4eb35
--- /dev/null
+++ b/android/src/com/mapswithme/maps/ads/RateStoreDialogFragment.java
@@ -0,0 +1,112 @@
+package com.mapswithme.maps.ads;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.DialogFragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.RatingBar;
+import android.widget.TextView;
+
+import com.mapswithme.maps.BuildConfig;
+import com.mapswithme.maps.R;
+import com.mapswithme.util.Constants;
+import com.mapswithme.util.UiUtils;
+import com.mapswithme.util.Utils;
+import com.mapswithme.util.statistics.Statistics;
+import com.nineoldandroids.animation.Animator;
+import com.nineoldandroids.animation.ObjectAnimator;
+
+public class RateStoreDialogFragment extends DialogFragment implements View.OnClickListener
+{
+ private float mRating;
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState)
+ {
+ final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ final LayoutInflater inflater = getActivity().getLayoutInflater();
+
+ final View root = inflater.inflate(R.layout.fragment_google_play_dialog, null);
+ builder.
+ setView(root).
+ setNegativeButton(getString(R.string.remind_me_later), new DialogInterface.OnClickListener()
+ {
+ @Override
+ public void onClick(DialogInterface dialog, int which)
+ {
+ Statistics.INSTANCE.trackSimpleNamedEvent(Statistics.EventName.RATE_DIALOG_LATER);
+ }
+ });
+
+ final RatingBar rateBar = (RatingBar) root.findViewById(R.id.rb__play_rate);
+
+ rateBar.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener()
+ {
+ @Override
+ public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser)
+ {
+ Statistics.INSTANCE.trackRatingDialog(rating);
+ mRating = rating;
+ if (rating == 5.0f)
+ Utils.openAppInMarket(getActivity(), BuildConfig.REVIEW_URL);
+ else
+ {
+ ObjectAnimator animator = ObjectAnimator.ofFloat(rateBar, "alpha", 1.0f, 0.0f);
+ animator.addListener(new UiUtils.SimpleNineoldAnimationListener()
+ {
+ @Override
+ public void onAnimationEnd(Animator animation)
+ {
+ final Button button = (Button) root.findViewById(R.id.btn__explain_bad_rating);
+ button.setVisibility(View.VISIBLE);
+ button.setOnClickListener(RateStoreDialogFragment.this);
+ ((TextView) root.findViewById(R.id.tv__title)).setText("Thank you!");
+ ((TextView) root.findViewById(R.id.tv__subtitle)).setText("Would you like to share any ideas or issues, so we can improve the app for you?");
+ root.findViewById(R.id.v__divider).setVisibility(View.VISIBLE);
+ rateBar.setVisibility(View.GONE);
+ super.onAnimationEnd(animation);
+ }
+ });
+ animator.start();
+ }
+ }
+ });
+
+ return builder.create();
+ }
+
+ @Override
+ public void onCancel(DialogInterface dialog)
+ {
+ super.onCancel(dialog);
+ Statistics.INSTANCE.trackSimpleNamedEvent(Statistics.EventName.RATE_DIALOG_LATER);
+ }
+
+ @Override
+ public void onClick(View v)
+ {
+ switch (v.getId())
+ {
+ case R.id.btn__explain_bad_rating:
+ final Intent intent = new Intent(Intent.ACTION_SENDTO);
+ intent.setData(Utils.buildMailUri(Constants.Url.MAIL_MAPSME_RATING, "Rating : " + mRating,
+ "Android version:" + Build.VERSION.SDK_INT + "\n" + "App version: " + BuildConfig.APPLICATION_ID + " " + BuildConfig.VERSION_CODE + "\n"));
+ try
+ {
+ startActivity(intent);
+ } catch (android.content.ActivityNotFoundException ex)
+ {
+ //
+ }
+ break;
+ }
+ }
+}
diff --git a/android/src/com/mapswithme/util/Constants.java b/android/src/com/mapswithme/util/Constants.java
index 3b92fb61e0..3ddbeb101b 100644
--- a/android/src/com/mapswithme/util/Constants.java
+++ b/android/src/com/mapswithme/util/Constants.java
@@ -30,6 +30,7 @@ public class Constants
public static final String MAIL_MAPSME_INFO = "android@maps.me";
public static final String MAIL_MAPSME_BUGS = "android@maps.me";
public static final String MAIL_MAPSME_SUBSCRIBE = "subscribe@maps.me";
+ public static final String MAIL_MAPSME_RATING = "rating@maps.me";
public static final String DATA_SCHEME_FILE = "file";
public static final String FEATURES_JSON = "http://application.server/android/features.json";
diff --git a/android/src/com/mapswithme/util/Utils.java b/android/src/com/mapswithme/util/Utils.java
index 395095c4bb..0c7234007b 100644
--- a/android/src/com/mapswithme/util/Utils.java
+++ b/android/src/com/mapswithme/util/Utils.java
@@ -287,7 +287,6 @@ public class Utils
}
/**
- *
* @param timestamp in currentTimeMillis() format
* @return
*/
@@ -304,4 +303,15 @@ public class Utils
return false;
}
+
+ public static void openAppInMarket(Activity activity, String url)
+ {
+ final Intent marketIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+ marketIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
+ marketIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+ else
+ marketIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ activity.startActivity(marketIntent);
+ }
}
diff --git a/android/src/com/mapswithme/util/statistics/Statistics.java b/android/src/com/mapswithme/util/statistics/Statistics.java
index e7da492c72..4e17d9d6de 100644
--- a/android/src/com/mapswithme/util/statistics/Statistics.java
+++ b/android/src/com/mapswithme/util/statistics/Statistics.java
@@ -66,6 +66,9 @@ public enum Statistics
public static final String STATISTICS_STATUS_CHANGED = "Statistics status changed";
public static final String NO_FREE_SPACE = "Downloader. Not enough free space.";
public static final String APP_ACTIVATED = "Application activated.";
+ public static final String PLUS_DIALOG_LATER = "GPlus dialog cancelled.";
+ public static final String RATE_DIALOG_LATER = "GPlay dialog cancelled.";
+ public static final String RATE_DIALOG_RATED = "GPlay dialog. Rating set";
}
public static class EventParam
@@ -85,6 +88,7 @@ public enum Statistics
public static final String ENABLED = "Enabled";
public static final String IS_PREINSTALLED = "IsPreinstalled";
public static final String APP_FLAVOR = "Flavor";
+ public static final String RATING = "Rating";
}
private Statistics()
@@ -261,6 +265,15 @@ public enum Statistics
trackIfEnabled(mEventBuilder.setName(EventName.DOWNLOAD_COUNTRY_NOTIFICATION_CLICKED).buildEvent());
}
+ public void trackRatingDialog(float rating)
+ {
+ final Event event = mEventBuilder.
+ setName(EventName.RATE_DIALOG_RATED).
+ addParam(EventParam.RATING, String.valueOf(rating)).
+ buildEvent();
+ trackIfEnabled(event);
+ }
+
public void trackSimpleNamedEvent(String eventName)
{
trackIfEnabled(mEventBuilder.setName(eventName).buildEvent());