Merge remote-tracking branch 'origin/master'

This commit is contained in:
Weblate 2017-03-15 19:23:44 +01:00
commit 8ecb5a66e9
4 changed files with 144 additions and 35 deletions

View file

@ -43,6 +43,7 @@ import net.osmand.plus.dialogs.RateUsBottomSheetDialog;
import net.osmand.plus.download.DownloadIndexesThread; import net.osmand.plus.download.DownloadIndexesThread;
import net.osmand.plus.helpers.AvoidSpecificRoads; import net.osmand.plus.helpers.AvoidSpecificRoads;
import net.osmand.plus.helpers.WaypointHelper; import net.osmand.plus.helpers.WaypointHelper;
import net.osmand.plus.inapp.InAppHelper;
import net.osmand.plus.mapcontextmenu.other.RoutePreferencesMenu; import net.osmand.plus.mapcontextmenu.other.RoutePreferencesMenu;
import net.osmand.plus.monitoring.LiveMonitoringHelper; import net.osmand.plus.monitoring.LiveMonitoringHelper;
import net.osmand.plus.poi.PoiFiltersHelper; import net.osmand.plus.poi.PoiFiltersHelper;
@ -157,6 +158,7 @@ public class OsmandApplication extends MultiDexApplication {
// targetPointsHelper.clearPointToNavigate(false); // targetPointsHelper.clearPointToNavigate(false);
// } // }
InAppHelper.initialize(this);
initRemoteConfig(); initRemoteConfig();
startApplication(); startApplication();
System.out.println("Time to start application " + (System.currentTimeMillis() - timeToStart) + " ms. Should be less < 800 ms"); System.out.println("Time to start application " + (System.currentTimeMillis() - timeToStart) + " ms. Should be less < 800 ms");

View file

@ -84,6 +84,7 @@ import net.osmand.plus.helpers.DiscountHelper;
import net.osmand.plus.helpers.ExternalApiHelper; import net.osmand.plus.helpers.ExternalApiHelper;
import net.osmand.plus.helpers.GpxImportHelper; import net.osmand.plus.helpers.GpxImportHelper;
import net.osmand.plus.helpers.WakeLockHelper; import net.osmand.plus.helpers.WakeLockHelper;
import net.osmand.plus.inapp.InAppHelper;
import net.osmand.plus.mapcontextmenu.MapContextMenu; import net.osmand.plus.mapcontextmenu.MapContextMenu;
import net.osmand.plus.mapcontextmenu.MapContextMenuFragment; import net.osmand.plus.mapcontextmenu.MapContextMenuFragment;
import net.osmand.plus.mapcontextmenu.other.DestinationReachedMenu; import net.osmand.plus.mapcontextmenu.other.DestinationReachedMenu;
@ -180,6 +181,7 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
private boolean permissionGranted; private boolean permissionGranted;
private boolean mIsDestroyed = false; private boolean mIsDestroyed = false;
private InAppHelper inAppHelper;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
@ -929,6 +931,9 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
if (atlasMapRendererView != null) { if (atlasMapRendererView != null) {
atlasMapRendererView.handleOnDestroy(); atlasMapRendererView.handleOnDestroy();
} }
if (inAppHelper != null) {
inAppHelper.stop();
}
mIsDestroyed = true; mIsDestroyed = true;
} }
@ -1212,6 +1217,9 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) { protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (inAppHelper != null && inAppHelper.onActivityResultHandled(requestCode, resultCode, data)) {
return;
}
for (ActivityResultListener listener : activityResultListeners) { for (ActivityResultListener listener : activityResultListeners) {
if (listener.processResult(requestCode, resultCode, data)) { if (listener.processResult(requestCode, resultCode, data)) {
removeActivityResultListener(listener); removeActivityResultListener(listener);
@ -1538,4 +1546,39 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
NEW_IF_EXPIRED, NEW_IF_EXPIRED,
CURRENT, CURRENT,
} }
public InAppHelper execInAppTask(@NonNull InAppHelper.InAppRunnable runnable) {
if (inAppHelper != null) {
inAppHelper.stop();
}
inAppHelper = new InAppHelper(getMyApplication(), false);
inAppHelper.addListener(new InAppHelper.InAppListener() {
@Override
public void onError(String error) {
inAppHelper = null;
}
@Override
public void onGetItems() {
inAppHelper = null;
}
@Override
public void onItemPurchased(String sku) {
inAppHelper = null;
}
@Override
public void showProgress() {
}
@Override
public void dismissProgress() {
}
});
inAppHelper.exec(runnable);
return inAppHelper;
}
} }

View file

@ -11,6 +11,8 @@ import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.Version; import net.osmand.plus.Version;
import net.osmand.plus.activities.MapActivity; import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.inapp.InAppHelper;
import net.osmand.plus.liveupdates.OsmLiveActivity;
import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarController; import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarController;
import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarControllerType; import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarControllerType;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
@ -124,10 +126,8 @@ public class DiscountHelper {
settings.DISCOUNT_SHOW_DATETIME_MS.set(System.currentTimeMillis()); settings.DISCOUNT_SHOW_DATETIME_MS.set(System.currentTimeMillis());
showDiscountBanner(mapActivity, message, description, icon, url); showDiscountBanner(mapActivity, message, description, icon, url);
} }
} }
} }
} catch (Exception e) { } catch (Exception e) {
logError("JSON parsing error: ", e); logError("JSON parsing error: ", e);
} }
@ -154,7 +154,8 @@ public class DiscountHelper {
return result; return result;
} }
private static void showDiscountBanner(final MapActivity mapActivity, final String title, final String description, final String icon, final String url) { private static void showDiscountBanner(final MapActivity mapActivity, final String title,
final String description, final String icon, final String url) {
final DiscountBarController toolbarController = new DiscountBarController(); final DiscountBarController toolbarController = new DiscountBarController();
toolbarController.setTitle(title); toolbarController.setTitle(title);
toolbarController.setDescription(description); toolbarController.setDescription(description);
@ -166,6 +167,7 @@ public class DiscountHelper {
public void onClick(View v) { public void onClick(View v) {
mapActivity.getMyApplication().logEvent(mapActivity, "motd_click"); mapActivity.getMyApplication().logEvent(mapActivity, "motd_click");
mBannerVisible = false; mBannerVisible = false;
mapActivity.hideTopToolbar(toolbarController);
openUrl(mapActivity, url); openUrl(mapActivity, url);
} }
}); });
@ -174,6 +176,7 @@ public class DiscountHelper {
public void onClick(View v) { public void onClick(View v) {
mapActivity.getMyApplication().logEvent(mapActivity, "motd_click"); mapActivity.getMyApplication().logEvent(mapActivity, "motd_click");
mBannerVisible = false; mBannerVisible = false;
mapActivity.hideTopToolbar(toolbarController);
openUrl(mapActivity, url); openUrl(mapActivity, url);
} }
}); });
@ -196,11 +199,27 @@ public class DiscountHelper {
mapActivity.showTopToolbar(toolbarController); mapActivity.showTopToolbar(toolbarController);
} }
private static void openUrl(MapActivity mapActivity, String url) { private static void openUrl(final MapActivity mapActivity, String url) {
if (url.startsWith("osmand-in-app:")) {
if (url.contains(InAppHelper.SKU_FULL_VERSION_PRICE)) {
mapActivity.execInAppTask(new InAppHelper.InAppRunnable() {
@Override
public void run(InAppHelper helper) {
helper.purchaseFullVersion(mapActivity);
}
});
} else if (url.contains(InAppHelper.SKU_LIVE_UPDATES)){
Intent intent = new Intent(mapActivity, OsmLiveActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
intent.putExtra(OsmLiveActivity.OPEN_SUBSCRIPTION_INTENT_PARAM, true);
mapActivity.startActivity(intent);
}
} else {
Intent intent = new Intent(Intent.ACTION_VIEW); Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url)); intent.setData(Uri.parse(url));
mapActivity.startActivity(intent); mapActivity.startActivity(intent);
} }
}
private static class DiscountBarController extends TopToolbarController { private static class DiscountBarController extends TopToolbarController {

View file

@ -3,6 +3,7 @@ package net.osmand.plus.inapp;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.util.Log; import android.util.Log;
import net.osmand.AndroidNetworkUtils; import net.osmand.AndroidNetworkUtils;
@ -41,10 +42,10 @@ public class InAppHelper {
private static long lastValidationCheckTime; private static long lastValidationCheckTime;
private static String mFullVersionPrice; private static String mFullVersionPrice;
private static final String SKU_FULL_VERSION_PRICE = "osmand_full_version_price"; public static final String SKU_FULL_VERSION_PRICE = "osmand_full_version_price";
private static final String SKU_LIVE_UPDATES_FULL = "osm_live_subscription_2"; private static final String SKU_LIVE_UPDATES_FULL = "osm_live_subscription_2";
private static final String SKU_LIVE_UPDATES_FREE = "osm_free_live_subscription_2"; private static final String SKU_LIVE_UPDATES_FREE = "osm_free_live_subscription_2";
private static String SKU_LIVE_UPDATES; public static String SKU_LIVE_UPDATES;
private static final long PURCHASE_VALIDATION_PERIOD_MSEC = 1000 * 60 * 60 * 24; // daily private static final long PURCHASE_VALIDATION_PERIOD_MSEC = 1000 * 60 * 60 * 24; // daily
// (arbitrary) request code for the purchase flow // (arbitrary) request code for the purchase flow
@ -60,6 +61,24 @@ public class InAppHelper {
private OsmandApplication ctx; private OsmandApplication ctx;
private List<InAppListener> listeners = new ArrayList<>(); private List<InAppListener> listeners = new ArrayList<>();
/* base64EncodedPublicKey should be YOUR APPLICATION'S PUBLIC KEY
* (that you got from the Google Play developer console). This is not your
* developer public key, it's the *app-specific* public key.
*
* Instead of just storing the entire literal string here embedded in the
* program, construct the key at runtime from pieces or
* use bit manipulation (for example, XOR with some other string) to hide
* the actual key. The key itself is not secret information, but we don't
* want to make it easy for an attacker to replace the public key with one
* of their own and then fake messages from the server.
*/
private static final String BASE64_ENCODED_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgk8cEx" +
"UO4mfEwWFLkQnX1Tkzehr4SnXLXcm2Osxs5FTJPEgyTckTh0POKVMrxeGLn0KoTY2NTgp1U/inp" +
"wccWisPhVPEmw9bAVvWsOkzlyg1kv03fJdnAXRBSqDDPV6X8Z3MtkPVqZkupBsxyIllEILKHK06" +
"OCw49JLTsMR3oTRifGzma79I71X0spw0fM+cIRlkS2tsXN8GPbdkJwHofZKPOXS51pgC1zU8uWX" +
"I+ftJO46a1XkNh1dO2anUiQ8P/H4yOTqnMsXF7biyYuiwjXPOcy0OMhEHi54Dq6Mr3u5ZALOAkc" +
"YTjh1H/ZgqIHy5ZluahINuDE76qdLYMXrDMQIDAQAB";
public interface InAppListener { public interface InAppListener {
void onError(String error); void onError(String error);
@ -72,6 +91,10 @@ public class InAppHelper {
void dismissProgress(); void dismissProgress();
} }
public interface InAppRunnable {
void run(InAppHelper helper);
}
public String getToken() { public String getToken() {
return token; return token;
} }
@ -100,9 +123,7 @@ public class InAppHelper {
return !Algorithms.isEmpty(mLiveUpdatesPrice) && !Algorithms.isEmpty(mFullVersionPrice); return !Algorithms.isEmpty(mLiveUpdatesPrice) && !Algorithms.isEmpty(mFullVersionPrice);
} }
public InAppHelper(OsmandApplication ctx, boolean forceRequestInventory) { public static void initialize(OsmandApplication ctx) {
this.ctx = ctx;
this.forceRequestInventory = forceRequestInventory;
if (SKU_LIVE_UPDATES == null) { if (SKU_LIVE_UPDATES == null) {
if (Version.isFreeVersion(ctx)) { if (Version.isFreeVersion(ctx)) {
SKU_LIVE_UPDATES = SKU_LIVE_UPDATES_FREE; SKU_LIVE_UPDATES = SKU_LIVE_UPDATES_FREE;
@ -110,6 +131,12 @@ public class InAppHelper {
SKU_LIVE_UPDATES = SKU_LIVE_UPDATES_FULL; SKU_LIVE_UPDATES = SKU_LIVE_UPDATES_FULL;
} }
} }
}
public InAppHelper(OsmandApplication ctx, boolean forceRequestInventory) {
this.ctx = ctx;
this.forceRequestInventory = forceRequestInventory;
isDeveloperVersion = Version.isDeveloperVersion(ctx); isDeveloperVersion = Version.isDeveloperVersion(ctx);
if (isDeveloperVersion) { if (isDeveloperVersion) {
mSubscribedToLiveUpdates = true; mSubscribedToLiveUpdates = true;
@ -119,29 +146,47 @@ public class InAppHelper {
} }
} }
public void start(final boolean stopAfterResult) { public void exec(final @NonNull InAppRunnable runnable) {
this.stopAfterResult = stopAfterResult; this.stopAfterResult = true;
/* base64EncodedPublicKey should be YOUR APPLICATION'S PUBLIC KEY
* (that you got from the Google Play developer console). This is not your
* developer public key, it's the *app-specific* public key.
*
* Instead of just storing the entire literal string here embedded in the
* program, construct the key at runtime from pieces or
* use bit manipulation (for example, XOR with some other string) to hide
* the actual key. The key itself is not secret information, but we don't
* want to make it easy for an attacker to replace the public key with one
* of their own and then fake messages from the server.
*/
String base64EncodedPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgk8cEx" +
"UO4mfEwWFLkQnX1Tkzehr4SnXLXcm2Osxs5FTJPEgyTckTh0POKVMrxeGLn0KoTY2NTgp1U/inp" +
"wccWisPhVPEmw9bAVvWsOkzlyg1kv03fJdnAXRBSqDDPV6X8Z3MtkPVqZkupBsxyIllEILKHK06" +
"OCw49JLTsMR3oTRifGzma79I71X0spw0fM+cIRlkS2tsXN8GPbdkJwHofZKPOXS51pgC1zU8uWX" +
"I+ftJO46a1XkNh1dO2anUiQ8P/H4yOTqnMsXF7biyYuiwjXPOcy0OMhEHi54Dq6Mr3u5ZALOAkc" +
"YTjh1H/ZgqIHy5ZluahINuDE76qdLYMXrDMQIDAQAB";
// Create the helper, passing it our context and the public key to verify signatures with // Create the helper, passing it our context and the public key to verify signatures with
logDebug("Creating InAppHelper."); logDebug("Creating InAppHelper.");
mHelper = new IabHelper(ctx, base64EncodedPublicKey); mHelper = new IabHelper(ctx, BASE64_ENCODED_PUBLIC_KEY);
// enable debug logging (for a production application, you should set this to false).
mHelper.enableDebugLogging(false);
// Start setup. This is asynchronous and the specified listener
// will be called once setup completes.
logDebug("Starting setup.");
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
logDebug("Setup finished.");
if (!result.isSuccess()) {
// Oh noes, there was a problem.
complain("Problem setting up in-app billing: " + result);
notifyError(result.getMessage());
if (stopAfterResult) {
stop();
}
return;
}
// Have we been disposed of in the meantime? If so, quit.
if (mHelper == null) return;
runnable.run(InAppHelper.this);
}
});
}
public void start(final boolean stopAfterResult) {
this.stopAfterResult = stopAfterResult;
// Create the helper, passing it our context and the public key to verify signatures with
logDebug("Creating InAppHelper.");
mHelper = new IabHelper(ctx, BASE64_ENCODED_PUBLIC_KEY);
// enable debug logging (for a production application, you should set this to false). // enable debug logging (for a production application, you should set this to false).
mHelper.enableDebugLogging(false); mHelper.enableDebugLogging(false);
@ -601,15 +646,15 @@ public class InAppHelper {
ctx.showToastMessage(message); ctx.showToastMessage(message);
} }
void logDebug(String msg) { private void logDebug(String msg) {
if (mDebugLog) Log.d(TAG, msg); if (mDebugLog) Log.d(TAG, msg);
} }
void logError(String msg) { private void logError(String msg) {
Log.e(TAG, msg); Log.e(TAG, msg);
} }
void logError(String msg, Throwable e) { private void logError(String msg, Throwable e) {
Log.e(TAG, "Error: " + msg, e); Log.e(TAG, "Error: " + msg, e);
} }