Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
8ecb5a66e9
4 changed files with 144 additions and 35 deletions
|
@ -43,6 +43,7 @@ import net.osmand.plus.dialogs.RateUsBottomSheetDialog;
|
|||
import net.osmand.plus.download.DownloadIndexesThread;
|
||||
import net.osmand.plus.helpers.AvoidSpecificRoads;
|
||||
import net.osmand.plus.helpers.WaypointHelper;
|
||||
import net.osmand.plus.inapp.InAppHelper;
|
||||
import net.osmand.plus.mapcontextmenu.other.RoutePreferencesMenu;
|
||||
import net.osmand.plus.monitoring.LiveMonitoringHelper;
|
||||
import net.osmand.plus.poi.PoiFiltersHelper;
|
||||
|
@ -157,6 +158,7 @@ public class OsmandApplication extends MultiDexApplication {
|
|||
// targetPointsHelper.clearPointToNavigate(false);
|
||||
// }
|
||||
|
||||
InAppHelper.initialize(this);
|
||||
initRemoteConfig();
|
||||
startApplication();
|
||||
System.out.println("Time to start application " + (System.currentTimeMillis() - timeToStart) + " ms. Should be less < 800 ms");
|
||||
|
|
|
@ -84,6 +84,7 @@ import net.osmand.plus.helpers.DiscountHelper;
|
|||
import net.osmand.plus.helpers.ExternalApiHelper;
|
||||
import net.osmand.plus.helpers.GpxImportHelper;
|
||||
import net.osmand.plus.helpers.WakeLockHelper;
|
||||
import net.osmand.plus.inapp.InAppHelper;
|
||||
import net.osmand.plus.mapcontextmenu.MapContextMenu;
|
||||
import net.osmand.plus.mapcontextmenu.MapContextMenuFragment;
|
||||
import net.osmand.plus.mapcontextmenu.other.DestinationReachedMenu;
|
||||
|
@ -180,6 +181,7 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
|
|||
private boolean permissionGranted;
|
||||
|
||||
private boolean mIsDestroyed = false;
|
||||
private InAppHelper inAppHelper;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
|
@ -929,6 +931,9 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
|
|||
if (atlasMapRendererView != null) {
|
||||
atlasMapRendererView.handleOnDestroy();
|
||||
}
|
||||
if (inAppHelper != null) {
|
||||
inAppHelper.stop();
|
||||
}
|
||||
mIsDestroyed = true;
|
||||
}
|
||||
|
||||
|
@ -1212,6 +1217,9 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
|
|||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (inAppHelper != null && inAppHelper.onActivityResultHandled(requestCode, resultCode, data)) {
|
||||
return;
|
||||
}
|
||||
for (ActivityResultListener listener : activityResultListeners) {
|
||||
if (listener.processResult(requestCode, resultCode, data)) {
|
||||
removeActivityResultListener(listener);
|
||||
|
@ -1538,4 +1546,39 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
|
|||
NEW_IF_EXPIRED,
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ import net.osmand.plus.OsmandSettings;
|
|||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.Version;
|
||||
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.TopToolbarControllerType;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
@ -124,10 +126,8 @@ public class DiscountHelper {
|
|||
settings.DISCOUNT_SHOW_DATETIME_MS.set(System.currentTimeMillis());
|
||||
showDiscountBanner(mapActivity, message, description, icon, url);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logError("JSON parsing error: ", e);
|
||||
}
|
||||
|
@ -154,7 +154,8 @@ public class DiscountHelper {
|
|||
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();
|
||||
toolbarController.setTitle(title);
|
||||
toolbarController.setDescription(description);
|
||||
|
@ -166,6 +167,7 @@ public class DiscountHelper {
|
|||
public void onClick(View v) {
|
||||
mapActivity.getMyApplication().logEvent(mapActivity, "motd_click");
|
||||
mBannerVisible = false;
|
||||
mapActivity.hideTopToolbar(toolbarController);
|
||||
openUrl(mapActivity, url);
|
||||
}
|
||||
});
|
||||
|
@ -174,6 +176,7 @@ public class DiscountHelper {
|
|||
public void onClick(View v) {
|
||||
mapActivity.getMyApplication().logEvent(mapActivity, "motd_click");
|
||||
mBannerVisible = false;
|
||||
mapActivity.hideTopToolbar(toolbarController);
|
||||
openUrl(mapActivity, url);
|
||||
}
|
||||
});
|
||||
|
@ -196,11 +199,27 @@ public class DiscountHelper {
|
|||
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.setData(Uri.parse(url));
|
||||
mapActivity.startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
||||
private static class DiscountBarController extends TopToolbarController {
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package net.osmand.plus.inapp;
|
|||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import net.osmand.AndroidNetworkUtils;
|
||||
|
@ -41,10 +42,10 @@ public class InAppHelper {
|
|||
private static long lastValidationCheckTime;
|
||||
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_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
|
||||
// (arbitrary) request code for the purchase flow
|
||||
|
@ -60,6 +61,24 @@ public class InAppHelper {
|
|||
private OsmandApplication ctx;
|
||||
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 {
|
||||
void onError(String error);
|
||||
|
||||
|
@ -72,6 +91,10 @@ public class InAppHelper {
|
|||
void dismissProgress();
|
||||
}
|
||||
|
||||
public interface InAppRunnable {
|
||||
void run(InAppHelper helper);
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
@ -100,9 +123,7 @@ public class InAppHelper {
|
|||
return !Algorithms.isEmpty(mLiveUpdatesPrice) && !Algorithms.isEmpty(mFullVersionPrice);
|
||||
}
|
||||
|
||||
public InAppHelper(OsmandApplication ctx, boolean forceRequestInventory) {
|
||||
this.ctx = ctx;
|
||||
this.forceRequestInventory = forceRequestInventory;
|
||||
public static void initialize(OsmandApplication ctx) {
|
||||
if (SKU_LIVE_UPDATES == null) {
|
||||
if (Version.isFreeVersion(ctx)) {
|
||||
SKU_LIVE_UPDATES = SKU_LIVE_UPDATES_FREE;
|
||||
|
@ -110,6 +131,12 @@ public class InAppHelper {
|
|||
SKU_LIVE_UPDATES = SKU_LIVE_UPDATES_FULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public InAppHelper(OsmandApplication ctx, boolean forceRequestInventory) {
|
||||
this.ctx = ctx;
|
||||
this.forceRequestInventory = forceRequestInventory;
|
||||
|
||||
isDeveloperVersion = Version.isDeveloperVersion(ctx);
|
||||
if (isDeveloperVersion) {
|
||||
mSubscribedToLiveUpdates = true;
|
||||
|
@ -119,29 +146,47 @@ public class InAppHelper {
|
|||
}
|
||||
}
|
||||
|
||||
public void start(final boolean stopAfterResult) {
|
||||
this.stopAfterResult = stopAfterResult;
|
||||
/* 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";
|
||||
public void exec(final @NonNull InAppRunnable runnable) {
|
||||
this.stopAfterResult = true;
|
||||
|
||||
// Create the helper, passing it our context and the public key to verify signatures with
|
||||
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).
|
||||
mHelper.enableDebugLogging(false);
|
||||
|
@ -601,15 +646,15 @@ public class InAppHelper {
|
|||
ctx.showToastMessage(message);
|
||||
}
|
||||
|
||||
void logDebug(String msg) {
|
||||
private void logDebug(String msg) {
|
||||
if (mDebugLog) Log.d(TAG, msg);
|
||||
}
|
||||
|
||||
void logError(String msg) {
|
||||
private void logError(String msg) {
|
||||
Log.e(TAG, msg);
|
||||
}
|
||||
|
||||
void logError(String msg, Throwable e) {
|
||||
private void logError(String msg, Throwable e) {
|
||||
Log.e(TAG, "Error: " + msg, e);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue