purchaseInfoList = new ArrayList<>();
+ for (InAppPurchaseData purchase : tokensToSend) {
+ purchaseInfoList.add(getPurchaseInfo(purchase));
+ }
+ onSkuDetailsResponseDone(purchaseInfoList);
+ }
+ };
+ }
+
+ private IapClient getIapClient() {
+ return Iap.getIapClient((Activity) uiActivity);
+ }
+
+ // Call when a purchase is finished
+ private void onPurchaseFinished(InAppPurchaseData purchase) {
+ logDebug("Purchase finished: " + purchase.getProductId());
+ onPurchaseDone(getPurchaseInfo(purchase));
+ }
+
+ @Override
+ protected boolean isBillingManagerExists() {
+ return false;
+ }
+
+ @Override
+ protected void destroyBillingManager() {
+ // non implemented
+ }
+
+ @Override
+ public boolean onActivityResult(@NonNull Activity activity, int requestCode, int resultCode, Intent data) {
+ if (requestCode == Constants.REQ_CODE_BUY_SUB) {
+ boolean succeed = false;
+ if (resultCode == Activity.RESULT_OK) {
+ PurchaseResultInfo result = SubscriptionUtils.getPurchaseResult(activity, data);
+ if (result != null) {
+ switch (result.getReturnCode()) {
+ case OrderStatusCode.ORDER_STATE_CANCEL:
+ logDebug("Purchase cancelled");
+ break;
+ case OrderStatusCode.ORDER_STATE_FAILED:
+ inventoryRequestPending = true;
+ logDebug("Purchase failed");
+ break;
+ case OrderStatusCode.ORDER_PRODUCT_OWNED:
+ inventoryRequestPending = true;
+ logDebug("Product already owned");
+ break;
+ case OrderStatusCode.ORDER_STATE_SUCCESS:
+ inventoryRequestPending = true;
+ InAppPurchaseData purchaseData = SubscriptionUtils.getInAppPurchaseData(null,
+ result.getInAppPurchaseData(), result.getInAppDataSignature());
+ if (purchaseData != null) {
+ onPurchaseFinished(purchaseData);
+ succeed = true;
+ } else {
+ logDebug("Purchase failed");
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ logDebug("Purchase failed");
+ }
+ } else {
+ logDebug("Purchase cancelled");
+ }
+ if (!succeed) {
+ stop(true);
+ }
+ return true;
+ } else if (requestCode == Constants.REQ_CODE_BUY_INAPP) {
+ boolean succeed = false;
+ if (data == null) {
+ logDebug("data is null");
+ } else {
+ PurchaseResultInfo buyResultInfo = Iap.getIapClient(activity).parsePurchaseResultInfoFromIntent(data);
+ switch (buyResultInfo.getReturnCode()) {
+ case OrderStatusCode.ORDER_STATE_CANCEL:
+ logDebug("Order has been canceled");
+ break;
+ case OrderStatusCode.ORDER_STATE_FAILED:
+ inventoryRequestPending = true;
+ logDebug("Order has been failed");
+ break;
+ case OrderStatusCode.ORDER_PRODUCT_OWNED:
+ inventoryRequestPending = true;
+ logDebug("Product already owned");
+ break;
+ case OrderStatusCode.ORDER_STATE_SUCCESS:
+ InAppPurchaseData purchaseData = InAppUtils.getInAppPurchaseData(null,
+ buyResultInfo.getInAppPurchaseData(), buyResultInfo.getInAppDataSignature());
+ if (purchaseData != null) {
+ onPurchaseFinished(purchaseData);
+ succeed = true;
+ } else {
+ logDebug("Purchase failed");
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if (!succeed) {
+ stop(true);
+ }
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/OsmAnd/src-huawei/net/osmand/plus/inapp/InAppPurchasesImpl.java b/OsmAnd/src-huawei/net/osmand/plus/inapp/InAppPurchasesImpl.java
new file mode 100644
index 0000000000..4ed0021b6f
--- /dev/null
+++ b/OsmAnd/src-huawei/net/osmand/plus/inapp/InAppPurchasesImpl.java
@@ -0,0 +1,196 @@
+package net.osmand.plus.inapp;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.huawei.hms.iap.entity.ProductInfo;
+
+import net.osmand.plus.OsmandApplication;
+import net.osmand.plus.R;
+
+public class InAppPurchasesImpl extends InAppPurchases {
+
+ private static final InAppPurchase FULL_VERSION = new InAppPurchaseFullVersion();
+ private static final InAppPurchaseDepthContoursFree DEPTH_CONTOURS_FREE = new InAppPurchaseDepthContoursFree();
+ private static final InAppPurchaseContourLinesFree CONTOUR_LINES_FREE = new InAppPurchaseContourLinesFree();
+
+
+ private static final InAppSubscription[] LIVE_UPDATES_FREE = new InAppSubscription[]{
+ new InAppPurchaseLiveUpdatesMonthlyFree(),
+ new InAppPurchaseLiveUpdates3MonthsFree(),
+ new InAppPurchaseLiveUpdatesAnnualFree()
+ };
+
+ public InAppPurchasesImpl(OsmandApplication ctx) {
+ super(ctx);
+ fullVersion = FULL_VERSION;
+ depthContours = DEPTH_CONTOURS_FREE;
+ contourLines = CONTOUR_LINES_FREE;
+ inAppPurchases = new InAppPurchase[] { fullVersion, depthContours, contourLines };
+
+ liveUpdates = new LiveUpdatesInAppPurchasesFree();
+ for (InAppSubscription s : liveUpdates.getAllSubscriptions()) {
+ if (s instanceof InAppPurchaseLiveUpdatesMonthly) {
+ if (s.isDiscounted()) {
+ discountedMonthlyLiveUpdates = s;
+ } else {
+ monthlyLiveUpdates = s;
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean isFullVersion(String sku) {
+ return FULL_VERSION.getSku().equals(sku);
+ }
+
+ @Override
+ public boolean isDepthContours(String sku) {
+ return DEPTH_CONTOURS_FREE.getSku().equals(sku);
+ }
+
+ @Override
+ public boolean isContourLines(String sku) {
+ return CONTOUR_LINES_FREE.getSku().equals(sku);
+ }
+
+ @Override
+ public boolean isLiveUpdates(String sku) {
+ for (InAppPurchase p : LIVE_UPDATES_FREE) {
+ if (p.getSku().equals(sku)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static class InAppPurchaseFullVersion extends InAppPurchase {
+
+ private static final String SKU_FULL_VERSION_PRICE = "net.osmand.huawei.full";
+
+ InAppPurchaseFullVersion() {
+ super(SKU_FULL_VERSION_PRICE);
+ }
+
+ @Override
+ public String getDefaultPrice(Context ctx) {
+ return ctx.getString(R.string.full_version_price);
+ }
+ }
+
+ private static class InAppPurchaseDepthContoursFree extends InAppPurchaseDepthContours {
+
+ private static final String SKU_DEPTH_CONTOURS_FREE = "net.osmand.huawei.seadepth";
+
+ InAppPurchaseDepthContoursFree() {
+ super(SKU_DEPTH_CONTOURS_FREE);
+ }
+ }
+
+ private static class InAppPurchaseContourLinesFree extends InAppPurchaseContourLines {
+
+ private static final String SKU_CONTOUR_LINES_FREE = "net.osmand.huawei.contourlines";
+
+ InAppPurchaseContourLinesFree() {
+ super(SKU_CONTOUR_LINES_FREE);
+ }
+ }
+
+ private static class InAppPurchaseLiveUpdatesMonthlyFree extends InAppPurchaseLiveUpdatesMonthly {
+
+ private static final String SKU_LIVE_UPDATES_MONTHLY_HW_FREE = "net.osmand.huawei.monthly";
+
+ InAppPurchaseLiveUpdatesMonthlyFree() {
+ super(SKU_LIVE_UPDATES_MONTHLY_HW_FREE, 1);
+ }
+
+ private InAppPurchaseLiveUpdatesMonthlyFree(@NonNull String sku) {
+ super(sku);
+ }
+
+ @Nullable
+ @Override
+ protected InAppSubscription newInstance(@NonNull String sku) {
+ return sku.startsWith(getSkuNoVersion()) ? new InAppPurchaseLiveUpdatesMonthlyFree(sku) : null;
+ }
+ }
+
+ private static class InAppPurchaseLiveUpdates3MonthsFree extends InAppPurchaseLiveUpdates3Months {
+
+ private static final String SKU_LIVE_UPDATES_3_MONTHS_HW_FREE = "net.osmand.huawei.3months";
+
+ InAppPurchaseLiveUpdates3MonthsFree() {
+ super(SKU_LIVE_UPDATES_3_MONTHS_HW_FREE, 1);
+ }
+
+ private InAppPurchaseLiveUpdates3MonthsFree(@NonNull String sku) {
+ super(sku);
+ }
+
+ @Nullable
+ @Override
+ protected InAppSubscription newInstance(@NonNull String sku) {
+ return sku.startsWith(getSkuNoVersion()) ? new InAppPurchaseLiveUpdates3MonthsFree(sku) : null;
+ }
+ }
+
+ private static class InAppPurchaseLiveUpdatesAnnualFree extends InAppPurchaseLiveUpdatesAnnual {
+
+ private static final String SKU_LIVE_UPDATES_ANNUAL_HW_FREE = "net.osmand.huawei.annual";
+
+ InAppPurchaseLiveUpdatesAnnualFree() {
+ super(SKU_LIVE_UPDATES_ANNUAL_HW_FREE, 1);
+ }
+
+ private InAppPurchaseLiveUpdatesAnnualFree(@NonNull String sku) {
+ super(sku);
+ }
+
+ @Nullable
+ @Override
+ protected InAppSubscription newInstance(@NonNull String sku) {
+ return sku.startsWith(getSkuNoVersion()) ? new InAppPurchaseLiveUpdatesAnnualFree(sku) : null;
+ }
+ }
+
+ public static class InAppPurchaseLiveUpdatesOldSubscription extends InAppSubscription {
+
+ private ProductInfo info;
+
+ InAppPurchaseLiveUpdatesOldSubscription(@NonNull ProductInfo info) {
+ super(info.getProductId(), true);
+ this.info = info;
+ }
+
+ @Override
+ public String getDefaultPrice(Context ctx) {
+ return "";
+ }
+
+ @Override
+ public CharSequence getTitle(Context ctx) {
+ return info.getProductName();
+ }
+
+ @Override
+ public CharSequence getDescription(@NonNull Context ctx) {
+ return info.getProductDesc();
+ }
+
+ @Nullable
+ @Override
+ protected InAppSubscription newInstance(@NonNull String sku) {
+ return null;
+ }
+ }
+
+ private static class LiveUpdatesInAppPurchasesFree extends InAppSubscriptionList {
+
+ public LiveUpdatesInAppPurchasesFree() {
+ super(LIVE_UPDATES_FREE);
+ }
+ }
+}
diff --git a/OsmAnd/src-huawei/net/osmand/plus/inapp/InAppUtils.java b/OsmAnd/src-huawei/net/osmand/plus/inapp/InAppUtils.java
new file mode 100644
index 0000000000..445727de96
--- /dev/null
+++ b/OsmAnd/src-huawei/net/osmand/plus/inapp/InAppUtils.java
@@ -0,0 +1,49 @@
+package net.osmand.plus.inapp;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.huawei.hms.iap.entity.InAppPurchaseData;
+import com.huawei.hms.iap.entity.OwnedPurchasesResult;
+
+import org.json.JSONException;
+
+public class InAppUtils {
+ private static final String TAG = "InAppUtils";
+
+ @Nullable
+ public static InAppPurchaseData getPurchaseData(OwnedPurchasesResult result, String productId) {
+ if (result == null || result.getInAppPurchaseDataList() == null) {
+ Log.i(TAG, "result is null");
+ return null;
+ }
+ int index = result.getItemList().indexOf(productId);
+ if (index != -1) {
+ String data = result.getInAppPurchaseDataList().get(index);
+ String signature = result.getInAppSignature().get(index);
+ return getInAppPurchaseData(productId, data, signature);
+ }
+ return null;
+ }
+
+ @Nullable
+ public static InAppPurchaseData getInAppPurchaseData(@Nullable String productId, @NonNull String data, @NonNull String signature) {
+ if (CipherUtil.doCheck(data, signature, CipherUtil.getPublicKey())) {
+ try {
+ InAppPurchaseData purchaseData = new InAppPurchaseData(data);
+ if (purchaseData.getPurchaseState() == InAppPurchaseData.PurchaseState.PURCHASED) {
+ if (productId == null || productId.equals(purchaseData.getProductId())) {
+ return purchaseData;
+ }
+ }
+ } catch (JSONException e) {
+ Log.e(TAG, "delivery: " + e.getMessage());
+ }
+ } else {
+ Log.e(TAG, "delivery: verify signature error");
+ }
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/OsmAnd/src-huawei/net/osmand/plus/inapp/SubscriptionUtils.java b/OsmAnd/src-huawei/net/osmand/plus/inapp/SubscriptionUtils.java
new file mode 100755
index 0000000000..3b249cb300
--- /dev/null
+++ b/OsmAnd/src-huawei/net/osmand/plus/inapp/SubscriptionUtils.java
@@ -0,0 +1,138 @@
+/**
+ * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.osmand.plus.inapp;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.huawei.hms.iap.Iap;
+import com.huawei.hms.iap.entity.InAppPurchaseData;
+import com.huawei.hms.iap.entity.OrderStatusCode;
+import com.huawei.hms.iap.entity.OwnedPurchasesResult;
+import com.huawei.hms.iap.entity.PurchaseResultInfo;
+
+import org.json.JSONException;
+
+import java.util.List;
+
+/**
+ * Util for Subscription function.
+ *
+ * @since 2019/12/9
+ */
+public class SubscriptionUtils {
+ private static final String TAG = "SubscriptionUtils";
+
+ /**
+ * Decide whether to offer subscription service
+ *
+ * @param result the OwnedPurchasesResult from IapClient.obtainOwnedPurchases
+ * @param productId subscription product id
+ * @return decision result
+ */
+ @Nullable
+ public static InAppPurchaseData getPurchaseData(OwnedPurchasesResult result, String productId) {
+ if (null == result) {
+ Log.e(TAG, "OwnedPurchasesResult is null");
+ return null;
+ }
+ List dataList = result.getInAppPurchaseDataList();
+ List signatureList = result.getInAppSignature();
+ for (int i = 0; i < dataList.size(); i++) {
+ String data = dataList.get(i);
+ String signature = signatureList.get(i);
+ InAppPurchaseData purchaseData = getInAppPurchaseData(productId, data, signature);
+ if (purchaseData != null) {
+ return purchaseData;
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ public static InAppPurchaseData getInAppPurchaseData(@Nullable String productId, @NonNull String data, @NonNull String signature) {
+ try {
+ InAppPurchaseData purchaseData = new InAppPurchaseData(data);
+ if (productId == null || productId.equals(purchaseData.getProductId())) {
+ boolean credible = CipherUtil.doCheck(data, signature, CipherUtil.getPublicKey());
+ if (credible) {
+ return purchaseData.isSubValid() ? purchaseData : null;
+ } else {
+ Log.e(TAG, "check the data signature fail");
+ return null;
+ }
+ }
+ } catch (JSONException e) {
+ Log.e(TAG, "parse InAppPurchaseData JSONException", e);
+ return null;
+ }
+ return null;
+ }
+
+ /**
+ * Parse PurchaseResult data from intent
+ *
+ * @param activity Activity
+ * @param data the intent from onActivityResult
+ * @return PurchaseResultInfo
+ */
+ public static PurchaseResultInfo getPurchaseResult(Activity activity, Intent data) {
+ PurchaseResultInfo purchaseResultInfo = Iap.getIapClient(activity).parsePurchaseResultInfoFromIntent(data);
+ if (null == purchaseResultInfo) {
+ Log.e(TAG, "PurchaseResultInfo is null");
+ } else {
+ int returnCode = purchaseResultInfo.getReturnCode();
+ String errMsg = purchaseResultInfo.getErrMsg();
+ switch (returnCode) {
+ case OrderStatusCode.ORDER_PRODUCT_OWNED:
+ Log.w(TAG, "you have owned this product");
+ break;
+ case OrderStatusCode.ORDER_STATE_SUCCESS:
+ boolean credible = CipherUtil.doCheck(purchaseResultInfo.getInAppPurchaseData(), purchaseResultInfo.getInAppDataSignature(), CipherUtil
+ .getPublicKey());
+ if (credible) {
+ try {
+ InAppPurchaseData inAppPurchaseData = new InAppPurchaseData(purchaseResultInfo.getInAppPurchaseData());
+ if (!inAppPurchaseData.isSubValid()) {
+ return getFailedPurchaseResultInfo();
+ }
+ } catch (JSONException e) {
+ Log.e(TAG, "parse InAppPurchaseData JSONException", e);
+ return getFailedPurchaseResultInfo();
+ }
+ } else {
+ Log.e(TAG, "check the data signature fail");
+ return getFailedPurchaseResultInfo();
+ }
+ default:
+ Log.e(TAG, "returnCode: " + returnCode + " , errMsg: " + errMsg);
+ break;
+ }
+ }
+ return purchaseResultInfo;
+ }
+
+ private static PurchaseResultInfo getFailedPurchaseResultInfo() {
+ PurchaseResultInfo info = new PurchaseResultInfo();
+ info.setReturnCode(OrderStatusCode.ORDER_STATE_FAILED);
+ return info;
+ }
+}
diff --git a/OsmAnd/src/net/osmand/plus/AppInitializer.java b/OsmAnd/src/net/osmand/plus/AppInitializer.java
index 2837bff6f8..0ae24b7c5f 100644
--- a/OsmAnd/src/net/osmand/plus/AppInitializer.java
+++ b/OsmAnd/src/net/osmand/plus/AppInitializer.java
@@ -38,7 +38,7 @@ import net.osmand.plus.download.ui.AbstractLoadLocalIndexTask;
import net.osmand.plus.helpers.AvoidSpecificRoads;
import net.osmand.plus.helpers.LockHelper;
import net.osmand.plus.helpers.WaypointHelper;
-import net.osmand.plus.inapp.InAppPurchaseHelper;
+import net.osmand.plus.inapp.InAppPurchaseHelperImpl;
import net.osmand.plus.liveupdates.LiveUpdatesHelper;
import net.osmand.plus.mapmarkers.MapMarkersDbHelper;
import net.osmand.plus.monitoring.LiveMonitoringHelper;
@@ -428,7 +428,7 @@ public class AppInitializer implements IProgress {
}
getLazyRoutingConfig();
app.applyTheme(app);
- app.inAppPurchaseHelper = startupInit(new InAppPurchaseHelper(app), InAppPurchaseHelper.class);
+ app.inAppPurchaseHelper = startupInit(new InAppPurchaseHelperImpl(app), InAppPurchaseHelperImpl.class);
app.poiTypes = startupInit(MapPoiTypes.getDefaultNoInit(), MapPoiTypes.class);
app.transportRoutingHelper = startupInit(new TransportRoutingHelper(app), TransportRoutingHelper.class);
app.routingHelper = startupInit(new RoutingHelper(app), RoutingHelper.class);
diff --git a/OsmAnd/src/net/osmand/plus/ContextMenuItem.java b/OsmAnd/src/net/osmand/plus/ContextMenuItem.java
index 3a5b391a67..3718169532 100644
--- a/OsmAnd/src/net/osmand/plus/ContextMenuItem.java
+++ b/OsmAnd/src/net/osmand/plus/ContextMenuItem.java
@@ -34,6 +34,7 @@ public class ContextMenuItem {
private boolean hidden;
private int order;
private String description;
+ private final OnUpdateCallback onUpdateCallback;
private final ContextMenuAdapter.ItemClickListener itemClickListener;
private final ContextMenuAdapter.OnIntegerValueChangedListener integerListener;
private final ContextMenuAdapter.ProgressListener progressListener;
@@ -58,6 +59,7 @@ public class ContextMenuItem {
boolean skipPaintingWithoutColor,
int order,
String description,
+ OnUpdateCallback onUpdateCallback,
ContextMenuAdapter.ItemClickListener itemClickListener,
ContextMenuAdapter.OnIntegerValueChangedListener integerListener,
ContextMenuAdapter.ProgressListener progressListener,
@@ -81,6 +83,7 @@ public class ContextMenuItem {
this.skipPaintingWithoutColor = skipPaintingWithoutColor;
this.order = order;
this.description = description;
+ this.onUpdateCallback = onUpdateCallback;
this.itemClickListener = itemClickListener;
this.integerListener = integerListener;
this.progressListener = progressListener;
@@ -245,6 +248,16 @@ public class ContextMenuItem {
return id;
}
+ public void update() {
+ if (onUpdateCallback != null) {
+ onUpdateCallback.onUpdateMenuItem(this);
+ }
+ }
+
+ public interface OnUpdateCallback {
+ void onUpdateMenuItem(ContextMenuItem item);
+ }
+
public static ItemBuilder createBuilder(String title) {
return new ItemBuilder().setTitle(title);
}
@@ -268,6 +281,7 @@ public class ContextMenuItem {
private boolean mIsClickable = true;
private int mOrder = 0;
private String mDescription = null;
+ private OnUpdateCallback mOnUpdateCallback = null;
private ContextMenuAdapter.ItemClickListener mItemClickListener = null;
private ContextMenuAdapter.OnIntegerValueChangedListener mIntegerListener = null;
private ContextMenuAdapter.ProgressListener mProgressListener = null;
@@ -348,6 +362,11 @@ public class ContextMenuItem {
return this;
}
+ public ItemBuilder setOnUpdateCallback(OnUpdateCallback onUpdateCallback) {
+ mOnUpdateCallback = onUpdateCallback;
+ return this;
+ }
+
public ItemBuilder setListener(ContextMenuAdapter.ItemClickListener checkBoxListener) {
mItemClickListener = checkBoxListener;
return this;
@@ -403,10 +422,12 @@ public class ContextMenuItem {
}
public ContextMenuItem createItem() {
- return new ContextMenuItem(mTitleId, mTitle, mIcon, mColorRes, mSecondaryIcon,
+ ContextMenuItem item = new ContextMenuItem(mTitleId, mTitle, mIcon, mColorRes, mSecondaryIcon,
mSelected, mProgress, mLayout, mLoading, mIsCategory, mIsClickable, mSkipPaintingWithoutColor,
- mOrder, mDescription, mItemClickListener, mIntegerListener, mProgressListener, mItemDeleteAction,
- mHideDivider, mHideCompoundButton, mMinHeight, mTag, mId);
+ mOrder, mDescription, mOnUpdateCallback, mItemClickListener, mIntegerListener, mProgressListener,
+ mItemDeleteAction, mHideDivider, mHideCompoundButton, mMinHeight, mTag, mId);
+ item.update();
+ return item;
}
}
}
diff --git a/OsmAnd/src/net/osmand/plus/HuaweiDrmHelper.java b/OsmAnd/src/net/osmand/plus/HuaweiDrmHelper.java
deleted file mode 100644
index 7cc2f2798e..0000000000
--- a/OsmAnd/src/net/osmand/plus/HuaweiDrmHelper.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package net.osmand.plus;
-
-import android.app.Activity;
-import android.util.Log;
-
-import java.lang.ref.WeakReference;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-public class HuaweiDrmHelper {
- private static final String TAG = HuaweiDrmHelper.class.getSimpleName();
-
- //Copyright protection id
- private static final String DRM_ID = "101117397";
- //Copyright protection public key
- private static final String DRM_PUBLIC_KEY = "9d6f861e7d46be167809a6a62302749a6753b3c1bd02c9729efb3973e268091d";
-
- public static void check(Activity activity) {
- boolean succeed = false;
- try {
- final WeakReference activityRef = new WeakReference<>(activity);
- Class> drmCheckCallbackClass = Class.forName("com.huawei.android.sdk.drm.DrmCheckCallback");
- Object callback = java.lang.reflect.Proxy.newProxyInstance(
- drmCheckCallbackClass.getClassLoader(),
- new java.lang.Class[]{drmCheckCallbackClass},
- new java.lang.reflect.InvocationHandler() {
-
- @Override
- public Object invoke(Object proxy, java.lang.reflect.Method method, Object[] args) {
- Activity a = activityRef.get();
- if (a != null && !a.isFinishing()) {
- String method_name = method.getName();
- if (method_name.equals("onCheckSuccess")) {
- // skip now
- } else if (method_name.equals("onCheckFailed")) {
- closeApplication(a);
- }
- }
- return null;
- }
- });
-
- Class> drmClass = Class.forName("com.huawei.android.sdk.drm.Drm");
- Class[] partypes = new Class[]{Activity.class, String.class, String.class, String.class, drmCheckCallbackClass};
- Method check = drmClass.getMethod("check", partypes);
- check.invoke(null, activity, activity.getPackageName(), DRM_ID, DRM_PUBLIC_KEY, callback);
- succeed = true;
-
- } catch (ClassNotFoundException e) {
- Log.e(TAG, "check: ", e);
- } catch (NoSuchMethodException e) {
- Log.e(TAG, "check: ", e);
- } catch (IllegalAccessException e) {
- Log.e(TAG, "check: ", e);
- } catch (InvocationTargetException e) {
- Log.e(TAG, "check: ", e);
- }
- if (!succeed) {
- closeApplication(activity);
- }
- }
-
- private static void closeApplication(Activity activity) {
- ((OsmandApplication) activity.getApplication()).closeApplicationAnywayImpl(activity, true);
- }
-}
diff --git a/OsmAnd/src/net/osmand/plus/Version.java b/OsmAnd/src/net/osmand/plus/Version.java
index 14ed68b100..86d26ec954 100644
--- a/OsmAnd/src/net/osmand/plus/Version.java
+++ b/OsmAnd/src/net/osmand/plus/Version.java
@@ -121,8 +121,8 @@ public class Version {
public static boolean isFreeVersion(OsmandApplication ctx){
return ctx.getPackageName().equals(FREE_VERSION_NAME) ||
ctx.getPackageName().equals(FREE_DEV_VERSION_NAME) ||
- ctx.getPackageName().equals(FREE_CUSTOM_VERSION_NAME)
- ;
+ ctx.getPackageName().equals(FREE_CUSTOM_VERSION_NAME) ||
+ isHuawei(ctx);
}
public static boolean isPaidVersion(OsmandApplication ctx) {
diff --git a/OsmAnd/src/net/osmand/plus/activities/MapActivity.java b/OsmAnd/src/net/osmand/plus/activities/MapActivity.java
index e23e596dcf..3baa33cb32 100644
--- a/OsmAnd/src/net/osmand/plus/activities/MapActivity.java
+++ b/OsmAnd/src/net/osmand/plus/activities/MapActivity.java
@@ -67,7 +67,6 @@ import net.osmand.plus.AppInitializer;
import net.osmand.plus.AppInitializer.AppInitializeListener;
import net.osmand.plus.AppInitializer.InitEvents;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
-import net.osmand.plus.HuaweiDrmHelper;
import net.osmand.plus.MapMarkersHelper.MapMarker;
import net.osmand.plus.MapMarkersHelper.MapMarkerChangedListener;
import net.osmand.plus.OnDismissDialogFragmentListener;
@@ -276,9 +275,6 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
super.onCreate(savedInstanceState);
- if (Version.isHuawei(getMyApplication())) {
- HuaweiDrmHelper.check(this);
- }
// Full screen is not used here
// getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.main);
@@ -1466,6 +1462,10 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
}
protected void onPostExecute(Void result) {
+ DashboardOnMap dashboard = getDashboard();
+ if (dashboard != null) {
+ dashboard.onMapSettingsUpdated();
+ }
}
}.executeOnExecutor(singleThreadExecutor, (Void) null);
diff --git a/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java b/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java
index dbd0f133fa..1d6e2c2dc7 100644
--- a/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java
+++ b/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java
@@ -899,7 +899,7 @@ public class MapActivityActions implements DialogProvider {
}
}).createItem());
- if (Version.isGooglePlayEnabled(app) || Version.isDeveloperVersion(app)) {
+ if (Version.isGooglePlayEnabled(app) || Version.isHuawei(app) || Version.isDeveloperVersion(app)) {
optionsMenuHelper.addItem(new ItemBuilder().setTitleId(R.string.osm_live, mapActivity)
.setId(DRAWER_OSMAND_LIVE_ID)
.setIcon(R.drawable.ic_action_osm_live)
diff --git a/OsmAnd/src/net/osmand/plus/activities/OsmandInAppPurchaseActivity.java b/OsmAnd/src/net/osmand/plus/activities/OsmandInAppPurchaseActivity.java
index cb91f7d167..47f7a17444 100644
--- a/OsmAnd/src/net/osmand/plus/activities/OsmandInAppPurchaseActivity.java
+++ b/OsmAnd/src/net/osmand/plus/activities/OsmandInAppPurchaseActivity.java
@@ -5,7 +5,6 @@ import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.net.Uri;
-import android.os.Bundle;
import android.widget.Toast;
import androidx.annotation.NonNull;
@@ -14,12 +13,15 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
+import net.osmand.AndroidUtils;
import net.osmand.PlatformUtil;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R;
import net.osmand.plus.Version;
+import net.osmand.plus.download.DownloadActivity;
import net.osmand.plus.inapp.InAppPurchaseHelper;
+import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseInitCallback;
import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseListener;
import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseTaskType;
import net.osmand.plus.liveupdates.OsmLiveRestartBottomSheetDialogFragment;
@@ -27,6 +29,7 @@ import net.osmand.plus.srtmplugin.SRTMPlugin;
import org.apache.commons.logging.Log;
+import java.lang.ref.WeakReference;
import java.util.List;
@SuppressLint("Registered")
@@ -34,14 +37,7 @@ public class OsmandInAppPurchaseActivity extends AppCompatActivity implements In
private static final Log LOG = PlatformUtil.getLog(OsmandInAppPurchaseActivity.class);
private InAppPurchaseHelper purchaseHelper;
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- if (isInAppPurchaseAllowed() && isInAppPurchaseSupported()) {
- purchaseHelper = getMyApplication().getInAppPurchaseHelper();
- }
- }
+ private boolean activityDestroyed;
@Override
protected void onResume() {
@@ -53,17 +49,39 @@ public class OsmandInAppPurchaseActivity extends AppCompatActivity implements In
protected void onDestroy() {
super.onDestroy();
deinitInAppPurchaseHelper();
+ activityDestroyed = true;
}
private void initInAppPurchaseHelper() {
deinitInAppPurchaseHelper();
-
- if (purchaseHelper != null) {
- purchaseHelper.setUiActivity(this);
- if (purchaseHelper.needRequestInventory()) {
- purchaseHelper.requestInventory();
+ if (purchaseHelper == null) {
+ OsmandApplication app = getMyApplication();
+ InAppPurchaseHelper purchaseHelper = app.getInAppPurchaseHelper();
+ if (app.getSettings().isInternetConnectionAvailable()
+ && isInAppPurchaseAllowed()
+ && isInAppPurchaseSupported(purchaseHelper)) {
+ this.purchaseHelper = purchaseHelper;
}
}
+ if (purchaseHelper != null) {
+ final WeakReference activityRef = new WeakReference<>(this);
+ purchaseHelper.isInAppPurchaseSupported(this, new InAppPurchaseInitCallback() {
+ @Override
+ public void onSuccess() {
+ OsmandInAppPurchaseActivity activity = activityRef.get();
+ if (!activityDestroyed && AndroidUtils.isActivityNotDestroyed(activity)) {
+ purchaseHelper.setUiActivity(activity);
+ if (purchaseHelper.needRequestInventory()) {
+ purchaseHelper.requestInventory();
+ }
+ }
+ }
+
+ @Override
+ public void onFail() {
+ }
+ });
+ }
}
private void deinitInAppPurchaseHelper() {
@@ -80,7 +98,11 @@ public class OsmandInAppPurchaseActivity extends AppCompatActivity implements In
InAppPurchaseHelper purchaseHelper = app.getInAppPurchaseHelper();
if (purchaseHelper != null) {
app.logEvent("in_app_purchase_redirect");
- purchaseHelper.purchaseFullVersion(activity);
+ try {
+ purchaseHelper.purchaseFullVersion(activity);
+ } catch (UnsupportedOperationException e) {
+ LOG.error("purchaseFullVersion is not supported", e);
+ }
}
} else {
app.logEvent("paid_version_redirect");
@@ -101,18 +123,27 @@ public class OsmandInAppPurchaseActivity extends AppCompatActivity implements In
InAppPurchaseHelper purchaseHelper = app.getInAppPurchaseHelper();
if (purchaseHelper != null) {
app.logEvent("depth_contours_purchase_redirect");
- purchaseHelper.purchaseDepthContours(activity);
+ try {
+ purchaseHelper.purchaseDepthContours(activity);
+ } catch (UnsupportedOperationException e) {
+ LOG.error("purchaseDepthContours is not supported", e);
+ }
}
}
}
- public static void purchaseSrtmPlugin(@NonNull final Activity activity) {
- OsmandPlugin plugin = OsmandPlugin.getPlugin(SRTMPlugin.class);
- if(plugin == null || plugin.getInstallURL() == null) {
- Toast.makeText(activity.getApplicationContext(),
- activity.getString(R.string.activate_srtm_plugin), Toast.LENGTH_LONG).show();
- } else {
- activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(plugin.getInstallURL())));
+ public static void purchaseContourLines(@NonNull final Activity activity) {
+ OsmandApplication app = (OsmandApplication) activity.getApplication();
+ if (app != null) {
+ InAppPurchaseHelper purchaseHelper = app.getInAppPurchaseHelper();
+ if (purchaseHelper != null) {
+ app.logEvent("contour_lines_purchase_redirect");
+ try {
+ purchaseHelper.purchaseContourLines(activity);
+ } catch (UnsupportedOperationException e) {
+ LOG.error("purchaseContourLines is not supported", e);
+ }
+ }
}
}
@@ -129,8 +160,9 @@ public class OsmandInAppPurchaseActivity extends AppCompatActivity implements In
return false;
}
- public boolean isInAppPurchaseSupported() {
- return Version.isGooglePlayEnabled(getMyApplication());
+ public boolean isInAppPurchaseSupported(InAppPurchaseHelper purchaseHelper) {
+ OsmandApplication app = getMyApplication();
+ return Version.isGooglePlayEnabled(app) || Version.isHuawei(app);
}
@Override
@@ -178,6 +210,11 @@ public class OsmandInAppPurchaseActivity extends AppCompatActivity implements In
}
onInAppPurchaseItemPurchased(sku);
fireInAppPurchaseItemPurchasedOnFragments(fragmentManager, sku, active);
+ if (purchaseHelper != null && purchaseHelper.getContourLines().getSku().equals(sku)) {
+ if (!(this instanceof MapActivity)) {
+ finish();
+ }
+ }
}
public void fireInAppPurchaseItemPurchasedOnFragments(@NonNull FragmentManager fragmentManager,
@@ -222,6 +259,17 @@ public class OsmandInAppPurchaseActivity extends AppCompatActivity implements In
}
}
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+ boolean handled = false;
+ if (purchaseHelper != null) {
+ handled = purchaseHelper.onActivityResult(this, requestCode, resultCode, data);
+ }
+ if (!handled) {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ }
+
public void onInAppPurchaseError(InAppPurchaseTaskType taskType, String error) {
// not implemented
}
diff --git a/OsmAnd/src/net/osmand/plus/chooseplan/ChoosePlanDialogFragment.java b/OsmAnd/src/net/osmand/plus/chooseplan/ChoosePlanDialogFragment.java
index 1e3b650a8f..c909d50845 100644
--- a/OsmAnd/src/net/osmand/plus/chooseplan/ChoosePlanDialogFragment.java
+++ b/OsmAnd/src/net/osmand/plus/chooseplan/ChoosePlanDialogFragment.java
@@ -428,7 +428,7 @@ public abstract class ChoosePlanDialogFragment extends BaseOsmAndDialogFragment
buttonCancelView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
- manageSubscription(ctx, s.getSku());
+ purchaseHelper.manageSubscription(ctx, s.getSku());
}
});
div.setVisibility(View.VISIBLE);
@@ -538,15 +538,6 @@ public abstract class ChoosePlanDialogFragment extends BaseOsmAndDialogFragment
}
}
- private void manageSubscription(@NonNull Context ctx, @Nullable String sku) {
- String url = "https://play.google.com/store/account/subscriptions?package=" + ctx.getPackageName();
- if (!Algorithms.isEmpty(sku)) {
- url += "&sku=" + sku;
- }
- Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
- startActivity(intent);
- }
-
private ViewGroup buildPlanTypeCard(@NonNull Context ctx, ViewGroup container) {
if (getPlanTypeFeatures().length == 0) {
return null;
diff --git a/OsmAnd/src/net/osmand/plus/chooseplan/ChoosePlanHillshadeSrtmDialogFragment.java b/OsmAnd/src/net/osmand/plus/chooseplan/ChoosePlanHillshadeSrtmDialogFragment.java
index b2858b53b8..d3a48a5a15 100644
--- a/OsmAnd/src/net/osmand/plus/chooseplan/ChoosePlanHillshadeSrtmDialogFragment.java
+++ b/OsmAnd/src/net/osmand/plus/chooseplan/ChoosePlanHillshadeSrtmDialogFragment.java
@@ -79,7 +79,7 @@ public class ChoosePlanHillshadeSrtmDialogFragment extends ChoosePlanDialogFragm
public void onClick(View v) {
Activity activity = getActivity();
if (activity != null) {
- OsmandInAppPurchaseActivity.purchaseSrtmPlugin(activity);
+ OsmandInAppPurchaseActivity.purchaseContourLines(activity);
dismiss();
}
}
diff --git a/OsmAnd/src/net/osmand/plus/dashboard/DashboardOnMap.java b/OsmAnd/src/net/osmand/plus/dashboard/DashboardOnMap.java
index 4c9b2a2c2b..bb2143c7eb 100644
--- a/OsmAnd/src/net/osmand/plus/dashboard/DashboardOnMap.java
+++ b/OsmAnd/src/net/osmand/plus/dashboard/DashboardOnMap.java
@@ -568,7 +568,7 @@ public class DashboardOnMap implements ObservableScrollViewCallbacks, IRouteInfo
boolean refresh = this.visibleType == type && !appModeChanged;
previousAppMode = currentAppMode;
- this.visibleType = type;
+ visibleType = type;
DashboardOnMap.staticVisible = visible;
DashboardOnMap.staticVisibleType = type;
mapActivity.enableDrawer();
@@ -1032,6 +1032,24 @@ public class DashboardOnMap implements ObservableScrollViewCallbacks, IRouteInfo
}
}
+ public void onMapSettingsUpdated() {
+ if (DashboardType.CONFIGURE_MAP.equals(visibleType)) {
+ updateMenuItems();
+ }
+ }
+
+ public void updateMenuItems() {
+ if (listAdapter != null) {
+ for (int i = 0; i < listAdapter.getCount(); i++) {
+ Object o = listAdapter.getItem(i);
+ if (o instanceof ContextMenuItem) {
+ ((ContextMenuItem) o).update();
+ }
+ }
+ listAdapter.notifyDataSetChanged();
+ }
+ }
+
public void updateLocation(final boolean centerChanged, final boolean locationChanged,
final boolean compassChanged) {
if (inLocationUpdate) {
diff --git a/OsmAnd/src/net/osmand/plus/dialogs/ConfigureMapMenu.java b/OsmAnd/src/net/osmand/plus/dialogs/ConfigureMapMenu.java
index 647eebeb4c..83c4e1942d 100644
--- a/OsmAnd/src/net/osmand/plus/dialogs/ConfigureMapMenu.java
+++ b/OsmAnd/src/net/osmand/plus/dialogs/ConfigureMapMenu.java
@@ -277,10 +277,12 @@ public class ConfigureMapMenu {
adapter.addItem(new ContextMenuItem.ItemBuilder().setTitleId(R.string.map_widget_map_rendering, activity)
.setId(MAP_RENDERING_CATEGORY_ID)
.setCategory(true).setLayout(R.layout.list_group_title_with_switch).createItem());
- adapter.addItem(new ContextMenuItem.ItemBuilder().setTitleId(R.string.map_widget_renderer, activity)
+ adapter.addItem(new ContextMenuItem.ItemBuilder()
.setId(MAP_STYLE_ID)
- .setDescription(getRenderDescr(activity)).setLayout(R.layout.list_item_single_line_descrition_narrow)
- .setIcon(R.drawable.ic_map).setListener(new ContextMenuAdapter.ItemClickListener() {
+ .setTitleId(R.string.map_widget_renderer, activity)
+ .setLayout(R.layout.list_item_single_line_descrition_narrow)
+ .setIcon(R.drawable.ic_map)
+ .setListener(new ContextMenuAdapter.ItemClickListener() {
@Override
public boolean onContextMenuClick(final ArrayAdapter ad, int itemId,
final int pos, boolean isChecked, int[] viewCoordinates) {
@@ -290,6 +292,13 @@ public class ConfigureMapMenu {
}
})
.setItemDeleteAction(makeDeleteAction(settings.RENDERER))
+ .setOnUpdateCallback(new ContextMenuItem.OnUpdateCallback() {
+ @Override
+ public void onUpdateMenuItem(ContextMenuItem item) {
+ String renderDescr = getRenderDescr(app);
+ item.setDescription(renderDescr);
+ }
+ })
.createItem());
String description = "";
@@ -942,13 +951,13 @@ public class ConfigureMapMenu {
dialog.show();
}
- protected String getRenderDescr(final MapActivity activity) {
- RendererRegistry rr = activity.getMyApplication().getRendererRegistry();
+ protected String getRenderDescr(OsmandApplication app) {
+ RendererRegistry rr = app.getRendererRegistry();
RenderingRulesStorage storage = rr.getCurrentSelectedRenderer();
if (storage == null) {
return "";
}
- String translation = RendererRegistry.getTranslatedRendererName(activity, storage.getName());
+ String translation = RendererRegistry.getTranslatedRendererName(app, storage.getName());
return translation == null ? storage.getName() : translation;
}
diff --git a/OsmAnd/src/net/osmand/plus/helpers/DiscountHelper.java b/OsmAnd/src/net/osmand/plus/helpers/DiscountHelper.java
index 61ae82399f..a4bb6ec74f 100644
--- a/OsmAnd/src/net/osmand/plus/helpers/DiscountHelper.java
+++ b/OsmAnd/src/net/osmand/plus/helpers/DiscountHelper.java
@@ -20,12 +20,14 @@ import androidx.annotation.NonNull;
import androidx.appcompat.content.res.AppCompatResources;
import net.osmand.AndroidNetworkUtils;
+import net.osmand.PlatformUtil;
import net.osmand.osm.AbstractPoiType;
import net.osmand.osm.MapPoiTypes;
import net.osmand.osm.PoiCategory;
import net.osmand.osm.PoiType;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin;
+import net.osmand.plus.activities.OsmandInAppPurchaseActivity;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.Version;
@@ -56,7 +58,7 @@ import java.util.Map;
public class DiscountHelper {
private static final String TAG = "DiscountHelper";
- //private static final String DISCOUNT_JSON = "discount.json";
+ private static final org.apache.commons.logging.Log LOG = PlatformUtil.getLog(DiscountHelper.class);
private static long mLastCheckTime;
private static ControllerData mData;
@@ -81,7 +83,7 @@ public class DiscountHelper {
public static void checkAndDisplay(final MapActivity mapActivity) {
OsmandApplication app = mapActivity.getMyApplication();
OsmandSettings settings = app.getSettings();
- if (settings.DO_NOT_SHOW_STARTUP_MESSAGES.get() || !settings.INAPPS_READ.get() || Version.isHuawei(app)) {
+ if (settings.DO_NOT_SHOW_STARTUP_MESSAGES.get() || !settings.INAPPS_READ.get()) {
return;
}
if (mBannerVisible) {
@@ -312,7 +314,11 @@ public class DiscountHelper {
if (purchaseHelper != null) {
if (url.contains(purchaseHelper.getFullVersion().getSku())) {
app.logEvent("in_app_purchase_redirect");
- purchaseHelper.purchaseFullVersion(mapActivity);
+ try {
+ purchaseHelper.purchaseFullVersion(mapActivity);
+ } catch (UnsupportedOperationException e) {
+ LOG.error("purchaseFullVersion is not supported", e);
+ }
} else {
for (InAppPurchase p : purchaseHelper.getLiveUpdates().getAllSubscriptions()) {
if (url.contains(p.getSku())) {
diff --git a/OsmAnd/src/net/osmand/plus/inapp/InAppPurchaseHelper.java b/OsmAnd/src/net/osmand/plus/inapp/InAppPurchaseHelper.java
index ac7e2c77fb..1364d7b154 100644
--- a/OsmAnd/src/net/osmand/plus/inapp/InAppPurchaseHelper.java
+++ b/OsmAnd/src/net/osmand/plus/inapp/InAppPurchaseHelper.java
@@ -2,6 +2,8 @@ package net.osmand.plus.inapp;
import android.annotation.SuppressLint;
import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
import android.os.AsyncTask;
import android.text.TextUtils;
import android.util.Log;
@@ -9,33 +11,21 @@ import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.billingclient.api.BillingClient.BillingResponseCode;
-import com.android.billingclient.api.BillingClient.SkuType;
-import com.android.billingclient.api.BillingResult;
-import com.android.billingclient.api.Purchase;
-import com.android.billingclient.api.SkuDetails;
-import com.android.billingclient.api.SkuDetailsResponseListener;
-
import net.osmand.AndroidNetworkUtils;
import net.osmand.AndroidNetworkUtils.OnRequestResultListener;
import net.osmand.AndroidNetworkUtils.OnRequestsResultListener;
import net.osmand.AndroidNetworkUtils.RequestResponse;
import net.osmand.PlatformUtil;
import net.osmand.plus.OsmandApplication;
-import net.osmand.plus.settings.backend.OsmandSettings;
-import net.osmand.plus.settings.backend.OsmandSettings.OsmandPreference;
import net.osmand.plus.R;
import net.osmand.plus.Version;
import net.osmand.plus.inapp.InAppPurchases.InAppPurchase;
import net.osmand.plus.inapp.InAppPurchases.InAppPurchase.PurchaseState;
-import net.osmand.plus.inapp.InAppPurchases.InAppPurchaseLiveUpdatesOldSubscription;
import net.osmand.plus.inapp.InAppPurchases.InAppSubscription;
-import net.osmand.plus.inapp.InAppPurchases.InAppSubscriptionIntroductoryInfo;
import net.osmand.plus.inapp.InAppPurchases.InAppSubscriptionList;
-import net.osmand.plus.inapp.util.BillingManager;
-import net.osmand.plus.inapp.util.BillingManager.BillingUpdatesListener;
import net.osmand.plus.liveupdates.CountrySelectionFragment;
import net.osmand.plus.liveupdates.CountrySelectionFragment.CountryItem;
+import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.util.Algorithms;
import org.json.JSONArray;
@@ -43,7 +33,6 @@ import org.json.JSONException;
import org.json.JSONObject;
import java.lang.ref.WeakReference;
-import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -53,54 +42,31 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
-public class InAppPurchaseHelper {
+public abstract class InAppPurchaseHelper {
// Debug tag, for logging
- private static final org.apache.commons.logging.Log LOG = PlatformUtil.getLog(InAppPurchaseHelper.class);
+ protected static final org.apache.commons.logging.Log LOG = PlatformUtil.getLog(InAppPurchaseHelper.class);
private static final String TAG = InAppPurchaseHelper.class.getSimpleName();
private boolean mDebugLog = false;
public static final long SUBSCRIPTION_HOLDING_TIME_MSEC = 1000 * 60 * 60 * 24 * 3; // 3 days
- private InAppPurchases purchases;
- private long lastValidationCheckTime;
- private boolean inventoryRequested;
+ protected InAppPurchases purchases;
+ protected long lastValidationCheckTime;
+ protected boolean inventoryRequested;
private static final long PURCHASE_VALIDATION_PERIOD_MSEC = 1000 * 60 * 60 * 24; // daily
- // (arbitrary) request code for the purchase flow
- private static final int RC_REQUEST = 10001;
- // The helper object
- private BillingManager billingManager;
- private List skuDetailsList;
+ protected boolean isDeveloperVersion;
+ protected String token = "";
+ protected InAppPurchaseTaskType activeTask;
+ protected boolean processingTask = false;
+ protected boolean inventoryRequestPending = false;
- private boolean isDeveloperVersion;
- private String token = "";
- private InAppPurchaseTaskType activeTask;
- private boolean processingTask = false;
- private boolean inventoryRequestPending = false;
-
- private OsmandApplication ctx;
- private InAppPurchaseListener uiActivity = null;
-
- /* 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";
+ protected OsmandApplication ctx;
+ protected InAppPurchaseListener uiActivity = null;
public interface InAppPurchaseListener {
+
void onError(InAppPurchaseTaskType taskType, String error);
void onGetItems();
@@ -112,16 +78,62 @@ public class InAppPurchaseHelper {
void dismissProgress(InAppPurchaseTaskType taskType);
}
+ public interface InAppPurchaseInitCallback {
+
+ void onSuccess();
+
+ void onFail();
+ }
+
public enum InAppPurchaseTaskType {
REQUEST_INVENTORY,
PURCHASE_FULL_VERSION,
PURCHASE_LIVE_UPDATES,
- PURCHASE_DEPTH_CONTOURS
+ PURCHASE_DEPTH_CONTOURS,
+ PURCHASE_CONTOUR_LINES
}
- public interface InAppRunnable {
+ public abstract class InAppCommand {
+
+ InAppCommandResultHandler resultHandler;
+
// return true if done and false if async task started
- boolean run(InAppPurchaseHelper helper);
+ abstract void run(InAppPurchaseHelper helper);
+
+ protected void commandDone() {
+ InAppCommandResultHandler resultHandler = this.resultHandler;
+ if (resultHandler != null) {
+ resultHandler.onCommandDone(this);
+ }
+ }
+ }
+
+ public interface InAppCommandResultHandler {
+ void onCommandDone(@NonNull InAppCommand command);
+ }
+
+ public static class PurchaseInfo {
+ private String sku;
+ private String orderId;
+ private String purchaseToken;
+
+ public PurchaseInfo(String sku, String orderId, String purchaseToken) {
+ this.sku = sku;
+ this.orderId = orderId;
+ this.purchaseToken = purchaseToken;
+ }
+
+ public String getSku() {
+ return sku;
+ }
+
+ public String getOrderId() {
+ return orderId;
+ }
+
+ public String getPurchaseToken() {
+ return purchaseToken;
+ }
}
public String getToken() {
@@ -144,6 +156,10 @@ public class InAppPurchaseHelper {
return Version.isDeveloperBuild(ctx) || ctx.getSettings().DEPTH_CONTOURS_PURCHASED.get();
}
+ public static boolean isContourLinesPurchased(@NonNull OsmandApplication ctx) {
+ return Version.isDeveloperBuild(ctx) || ctx.getSettings().CONTOUR_LINES_PURCHASED.get();
+ }
+
public InAppPurchases getInAppPurchases() {
return purchases;
}
@@ -176,9 +192,10 @@ public class InAppPurchaseHelper {
public InAppPurchaseHelper(OsmandApplication ctx) {
this.ctx = ctx;
isDeveloperVersion = Version.isDeveloperVersion(ctx);
- purchases = new InAppPurchases(ctx);
}
+ public abstract void isInAppPurchaseSupported(@NonNull final Activity activity, @Nullable final InAppPurchaseInitCallback callback);
+
public boolean hasInventory() {
return lastValidationCheckTime != 0;
}
@@ -194,12 +211,8 @@ public class InAppPurchaseHelper {
return false;
}
- private BillingManager getBillingManager() {
- return billingManager;
- }
-
- private void exec(final @NonNull InAppPurchaseTaskType taskType, final @NonNull InAppRunnable runnable) {
- if (isDeveloperVersion || !Version.isGooglePlayEnabled(ctx)) {
+ protected void exec(final @NonNull InAppPurchaseTaskType taskType, final @NonNull InAppCommand command) {
+ if (isDeveloperVersion || (!Version.isGooglePlayEnabled(ctx) && !Version.isHuawei(ctx))) {
notifyDismissProgress(taskType);
stop(true);
return;
@@ -222,117 +235,21 @@ public class InAppPurchaseHelper {
try {
processingTask = true;
activeTask = taskType;
- billingManager = new BillingManager(ctx, BASE64_ENCODED_PUBLIC_KEY, new BillingUpdatesListener() {
-
+ command.resultHandler = new InAppCommandResultHandler() {
@Override
- public void onBillingClientSetupFinished() {
- logDebug("Setup finished.");
-
- BillingManager billingManager = getBillingManager();
- // Have we been disposed of in the meantime? If so, quit.
- if (billingManager == null) {
- stop(true);
- return;
- }
-
- if (!billingManager.isServiceConnected()) {
- // Oh noes, there was a problem.
- //complain("Problem setting up in-app billing: " + result);
- notifyError(taskType, billingManager.getBillingClientResponseMessage());
- stop(true);
- return;
- }
-
- processingTask = !runnable.run(InAppPurchaseHelper.this);
+ public void onCommandDone(@NonNull InAppCommand command) {
+ processingTask = false;
}
-
- @Override
- public void onConsumeFinished(String token, BillingResult billingResult) {
- }
-
- @Override
- public void onPurchasesUpdated(final List purchases) {
-
- BillingManager billingManager = getBillingManager();
- // Have we been disposed of in the meantime? If so, quit.
- if (billingManager == null) {
- stop(true);
- return;
- }
-
- if (activeTask == InAppPurchaseTaskType.REQUEST_INVENTORY) {
- List skuInApps = new ArrayList<>();
- for (InAppPurchase purchase : getInAppPurchases().getAllInAppPurchases(false)) {
- skuInApps.add(purchase.getSku());
- }
- for (Purchase p : purchases) {
- skuInApps.add(p.getSku());
- }
- billingManager.querySkuDetailsAsync(SkuType.INAPP, skuInApps, new SkuDetailsResponseListener() {
- @Override
- public void onSkuDetailsResponse(BillingResult billingResult, final List skuDetailsListInApps) {
- // Is it a failure?
- if (billingResult.getResponseCode() != BillingResponseCode.OK) {
- logError("Failed to query inapps sku details: " + billingResult.getResponseCode());
- notifyError(InAppPurchaseTaskType.REQUEST_INVENTORY, billingResult.getDebugMessage());
- stop(true);
- return;
- }
-
- List skuSubscriptions = new ArrayList<>();
- for (InAppSubscription subscription : getInAppPurchases().getAllInAppSubscriptions()) {
- skuSubscriptions.add(subscription.getSku());
- }
- for (Purchase p : purchases) {
- skuSubscriptions.add(p.getSku());
- }
-
- BillingManager billingManager = getBillingManager();
- // Have we been disposed of in the meantime? If so, quit.
- if (billingManager == null) {
- stop(true);
- return;
- }
-
- billingManager.querySkuDetailsAsync(SkuType.SUBS, skuSubscriptions, new SkuDetailsResponseListener() {
- @Override
- public void onSkuDetailsResponse(BillingResult billingResult, final List skuDetailsListSubscriptions) {
- // Is it a failure?
- if (billingResult.getResponseCode() != BillingResponseCode.OK) {
- logError("Failed to query subscriptipons sku details: " + billingResult.getResponseCode());
- notifyError(InAppPurchaseTaskType.REQUEST_INVENTORY, billingResult.getDebugMessage());
- stop(true);
- return;
- }
-
- List skuDetailsList = new ArrayList<>(skuDetailsListInApps);
- skuDetailsList.addAll(skuDetailsListSubscriptions);
- InAppPurchaseHelper.this.skuDetailsList = skuDetailsList;
-
- mSkuDetailsResponseListener.onSkuDetailsResponse(billingResult, skuDetailsList);
- }
- });
- }
- });
- }
- for (Purchase purchase : purchases) {
- if (!purchase.isAcknowledged()) {
- onPurchaseFinished(purchase);
- }
- }
- }
-
- @Override
- public void onPurchaseCanceled() {
- stop(true);
- }
- });
+ };
+ execImpl(taskType, command);
} catch (Exception e) {
logError("exec Error", e);
stop(true);
}
}
+ protected abstract void execImpl(@NonNull final InAppPurchaseTaskType taskType, @NonNull final InAppCommand command);
+
public boolean needRequestInventory() {
return !inventoryRequested && ((isSubscribedToLiveUpdates(ctx) && Algorithms.isEmpty(ctx.getSettings().BILLING_PURCHASE_TOKENS_SENT.get()))
|| System.currentTimeMillis() - lastValidationCheckTime > PURCHASE_VALIDATION_PERIOD_MSEC);
@@ -343,322 +260,20 @@ public class InAppPurchaseHelper {
new RequestInventoryTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
}
- public void purchaseFullVersion(final Activity activity) {
- notifyShowProgress(InAppPurchaseTaskType.PURCHASE_FULL_VERSION);
- exec(InAppPurchaseTaskType.PURCHASE_FULL_VERSION, new InAppRunnable() {
- @Override
- public boolean run(InAppPurchaseHelper helper) {
- try {
- SkuDetails skuDetails = getSkuDetails(getFullVersion().getSku());
- if (skuDetails == null) {
- throw new IllegalArgumentException("Cannot find sku details");
- }
- BillingManager billingManager = getBillingManager();
- if (billingManager != null) {
- billingManager.initiatePurchaseFlow(activity, skuDetails);
- } else {
- throw new IllegalStateException("BillingManager disposed");
- }
- return false;
- } catch (Exception e) {
- complain("Cannot launch full version purchase!");
- logError("purchaseFullVersion Error", e);
- stop(true);
- }
- return true;
- }
- });
- }
+ public abstract void purchaseFullVersion(@NonNull final Activity activity) throws UnsupportedOperationException;
- public void purchaseLiveUpdates(Activity activity, String sku, String email, String userName,
+ public void purchaseLiveUpdates(@NonNull Activity activity, String sku, String email, String userName,
String countryDownloadName, boolean hideUserName) {
notifyShowProgress(InAppPurchaseTaskType.PURCHASE_LIVE_UPDATES);
new LiveUpdatesPurchaseTask(activity, sku, email, userName, countryDownloadName, hideUserName)
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
}
- public void purchaseDepthContours(final Activity activity) {
- notifyShowProgress(InAppPurchaseTaskType.PURCHASE_DEPTH_CONTOURS);
- exec(InAppPurchaseTaskType.PURCHASE_DEPTH_CONTOURS, new InAppRunnable() {
- @Override
- public boolean run(InAppPurchaseHelper helper) {
- try {
- SkuDetails skuDetails = getSkuDetails(getDepthContours().getSku());
- if (skuDetails == null) {
- throw new IllegalArgumentException("Cannot find sku details");
- }
- BillingManager billingManager = getBillingManager();
- if (billingManager != null) {
- billingManager.initiatePurchaseFlow(activity, skuDetails);
- } else {
- throw new IllegalStateException("BillingManager disposed");
- }
- return false;
- } catch (Exception e) {
- complain("Cannot launch depth contours purchase!");
- logError("purchaseDepthContours Error", e);
- stop(true);
- }
- return true;
- }
- });
- }
+ public abstract void purchaseDepthContours(@NonNull final Activity activity) throws UnsupportedOperationException;
- @Nullable
- private SkuDetails getSkuDetails(@NonNull String sku) {
- List skuDetailsList = this.skuDetailsList;
- if (skuDetailsList != null) {
- for (SkuDetails details : skuDetailsList) {
- if (details.getSku().equals(sku)) {
- return details;
- }
- }
- }
- return null;
- }
+ public abstract void purchaseContourLines(@NonNull final Activity activity) throws UnsupportedOperationException;
- private boolean hasDetails(@NonNull String sku) {
- return getSkuDetails(sku) != null;
- }
-
- @Nullable
- private Purchase getPurchase(@NonNull String sku) {
- BillingManager billingManager = getBillingManager();
- if (billingManager != null) {
- List purchases = billingManager.getPurchases();
- if (purchases != null) {
- for (Purchase p : purchases) {
- if (p.getSku().equals(sku)) {
- return p;
- }
- }
- }
- }
- return null;
- }
-
- // Listener that's called when we finish querying the items and subscriptions we own
- private SkuDetailsResponseListener mSkuDetailsResponseListener = new SkuDetailsResponseListener() {
-
- @NonNull
- private List getAllOwnedSubscriptionSkus() {
- List result = new ArrayList<>();
- BillingManager billingManager = getBillingManager();
- if (billingManager != null) {
- for (Purchase p : billingManager.getPurchases()) {
- if (getInAppPurchases().getInAppSubscriptionBySku(p.getSku()) != null) {
- result.add(p.getSku());
- }
- }
- }
- return result;
- }
-
- @Override
- public void onSkuDetailsResponse(BillingResult billingResult, List skuDetailsList) {
-
- logDebug("Query sku details finished.");
-
- // Have we been disposed of in the meantime? If so, quit.
- if (getBillingManager() == null) {
- stop(true);
- return;
- }
-
- // Is it a failure?
- if (billingResult.getResponseCode() != BillingResponseCode.OK) {
- logError("Failed to query inventory: " + billingResult.getResponseCode());
- notifyError(InAppPurchaseTaskType.REQUEST_INVENTORY, billingResult.getDebugMessage());
- stop(true);
- return;
- }
-
- logDebug("Query sku details was successful.");
-
- /*
- * Check for items we own. Notice that for each purchase, we check
- * the developer payload to see if it's correct! See
- * verifyDeveloperPayload().
- */
-
- List allOwnedSubscriptionSkus = getAllOwnedSubscriptionSkus();
- for (InAppSubscription s : getLiveUpdates().getAllSubscriptions()) {
- if (hasDetails(s.getSku())) {
- Purchase purchase = getPurchase(s.getSku());
- SkuDetails liveUpdatesDetails = getSkuDetails(s.getSku());
- if (liveUpdatesDetails != null) {
- fetchInAppPurchase(s, liveUpdatesDetails, purchase);
- }
- allOwnedSubscriptionSkus.remove(s.getSku());
- }
- }
- for (String sku : allOwnedSubscriptionSkus) {
- Purchase purchase = getPurchase(sku);
- SkuDetails liveUpdatesDetails = getSkuDetails(sku);
- if (liveUpdatesDetails != null) {
- InAppSubscription s = getLiveUpdates().upgradeSubscription(sku);
- if (s == null) {
- s = new InAppPurchaseLiveUpdatesOldSubscription(liveUpdatesDetails);
- }
- fetchInAppPurchase(s, liveUpdatesDetails, purchase);
- }
- }
-
- InAppPurchase fullVersion = getFullVersion();
- if (hasDetails(fullVersion.getSku())) {
- Purchase purchase = getPurchase(fullVersion.getSku());
- SkuDetails fullPriceDetails = getSkuDetails(fullVersion.getSku());
- if (fullPriceDetails != null) {
- fetchInAppPurchase(fullVersion, fullPriceDetails, purchase);
- }
- }
-
- InAppPurchase depthContours = getDepthContours();
- if (hasDetails(depthContours.getSku())) {
- Purchase purchase = getPurchase(depthContours.getSku());
- SkuDetails depthContoursDetails = getSkuDetails(depthContours.getSku());
- if (depthContoursDetails != null) {
- fetchInAppPurchase(depthContours, depthContoursDetails, purchase);
- }
- }
-
- InAppPurchase contourLines = getContourLines();
- if (hasDetails(contourLines.getSku())) {
- Purchase purchase = getPurchase(contourLines.getSku());
- SkuDetails contourLinesDetails = getSkuDetails(contourLines.getSku());
- if (contourLinesDetails != null) {
- fetchInAppPurchase(contourLines, contourLinesDetails, purchase);
- }
- }
-
- Purchase fullVersionPurchase = getPurchase(fullVersion.getSku());
- boolean fullVersionPurchased = fullVersionPurchase != null;
- if (fullVersionPurchased) {
- ctx.getSettings().FULL_VERSION_PURCHASED.set(true);
- }
-
- Purchase depthContoursPurchase = getPurchase(depthContours.getSku());
- boolean depthContoursPurchased = depthContoursPurchase != null;
- if (depthContoursPurchased) {
- ctx.getSettings().DEPTH_CONTOURS_PURCHASED.set(true);
- }
-
- // Do we have the live updates?
- boolean subscribedToLiveUpdates = false;
- List liveUpdatesPurchases = new ArrayList<>();
- for (InAppPurchase p : getLiveUpdates().getAllSubscriptions()) {
- Purchase purchase = getPurchase(p.getSku());
- if (purchase != null) {
- liveUpdatesPurchases.add(purchase);
- if (!subscribedToLiveUpdates) {
- subscribedToLiveUpdates = true;
- }
- }
- }
- OsmandPreference subscriptionCancelledTime = ctx.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_TIME;
- if (!subscribedToLiveUpdates && ctx.getSettings().LIVE_UPDATES_PURCHASED.get()) {
- if (subscriptionCancelledTime.get() == 0) {
- subscriptionCancelledTime.set(System.currentTimeMillis());
- ctx.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_FIRST_DLG_SHOWN.set(false);
- ctx.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_SECOND_DLG_SHOWN.set(false);
- } else if (System.currentTimeMillis() - subscriptionCancelledTime.get() > SUBSCRIPTION_HOLDING_TIME_MSEC) {
- ctx.getSettings().LIVE_UPDATES_PURCHASED.set(false);
- if (!isDepthContoursPurchased(ctx)) {
- ctx.getSettings().getCustomRenderBooleanProperty("depthContours").set(false);
- }
- }
- } else if (subscribedToLiveUpdates) {
- subscriptionCancelledTime.set(0L);
- ctx.getSettings().LIVE_UPDATES_PURCHASED.set(true);
- }
-
- lastValidationCheckTime = System.currentTimeMillis();
- logDebug("User " + (subscribedToLiveUpdates ? "HAS" : "DOES NOT HAVE")
- + " live updates purchased.");
-
- OsmandSettings settings = ctx.getSettings();
- settings.INAPPS_READ.set(true);
-
- List tokensToSend = new ArrayList<>();
- if (liveUpdatesPurchases.size() > 0) {
- List tokensSent = Arrays.asList(settings.BILLING_PURCHASE_TOKENS_SENT.get().split(";"));
- for (Purchase purchase : liveUpdatesPurchases) {
- if ((Algorithms.isEmpty(settings.BILLING_USER_ID.get()) || Algorithms.isEmpty(settings.BILLING_USER_TOKEN.get()))
- && !Algorithms.isEmpty(purchase.getDeveloperPayload())) {
- String payload = purchase.getDeveloperPayload();
- if (!Algorithms.isEmpty(payload)) {
- String[] arr = payload.split(" ");
- if (arr.length > 0) {
- settings.BILLING_USER_ID.set(arr[0]);
- }
- if (arr.length > 1) {
- token = arr[1];
- settings.BILLING_USER_TOKEN.set(token);
- }
- }
- }
- if (!tokensSent.contains(purchase.getSku())) {
- tokensToSend.add(purchase);
- }
- }
- }
-
- final OnRequestResultListener listener = new OnRequestResultListener() {
- @Override
- public void onResult(String result) {
- notifyDismissProgress(InAppPurchaseTaskType.REQUEST_INVENTORY);
- notifyGetItems();
- stop(true);
- logDebug("Initial inapp query finished");
- }
- };
-
- if (tokensToSend.size() > 0) {
- sendTokens(tokensToSend, listener);
- } else {
- listener.onResult("OK");
- }
- }
- };
-
- private void fetchInAppPurchase(@NonNull InAppPurchase inAppPurchase, @NonNull SkuDetails skuDetails, @Nullable Purchase purchase) {
- if (purchase != null) {
- inAppPurchase.setPurchaseState(PurchaseState.PURCHASED);
- inAppPurchase.setPurchaseTime(purchase.getPurchaseTime());
- } else {
- inAppPurchase.setPurchaseState(PurchaseState.NOT_PURCHASED);
- }
- inAppPurchase.setPrice(skuDetails.getPrice());
- inAppPurchase.setPriceCurrencyCode(skuDetails.getPriceCurrencyCode());
- if (skuDetails.getPriceAmountMicros() > 0) {
- inAppPurchase.setPriceValue(skuDetails.getPriceAmountMicros() / 1000000d);
- }
- String subscriptionPeriod = skuDetails.getSubscriptionPeriod();
- if (!Algorithms.isEmpty(subscriptionPeriod)) {
- if (inAppPurchase instanceof InAppSubscription) {
- try {
- ((InAppSubscription) inAppPurchase).setSubscriptionPeriodString(subscriptionPeriod);
- } catch (ParseException e) {
- LOG.error(e);
- }
- }
- }
- if (inAppPurchase instanceof InAppSubscription) {
- String introductoryPrice = skuDetails.getIntroductoryPrice();
- String introductoryPricePeriod = skuDetails.getIntroductoryPricePeriod();
- String introductoryPriceCycles = skuDetails.getIntroductoryPriceCycles();
- long introductoryPriceAmountMicros = skuDetails.getIntroductoryPriceAmountMicros();
- if (!Algorithms.isEmpty(introductoryPrice)) {
- InAppSubscription s = (InAppSubscription) inAppPurchase;
- try {
- s.setIntroductoryInfo(new InAppSubscriptionIntroductoryInfo(s, introductoryPrice,
- introductoryPriceAmountMicros, introductoryPricePeriod, introductoryPriceCycles));
- } catch (ParseException e) {
- LOG.error(e);
- }
- }
- }
- }
+ public abstract void manageSubscription(@NonNull Context ctx, @Nullable String sku);
@SuppressLint("StaticFieldLeak")
private class LiveUpdatesPurchaseTask extends AsyncTask {
@@ -746,31 +361,7 @@ public class InAppPurchaseHelper {
if (!Algorithms.isEmpty(userId) && !Algorithms.isEmpty(token)) {
logDebug("Launching purchase flow for live updates subscription for userId=" + userId);
final String payload = userId + " " + token;
- exec(InAppPurchaseTaskType.PURCHASE_LIVE_UPDATES, new InAppRunnable() {
- @Override
- public boolean run(InAppPurchaseHelper helper) {
- try {
- Activity a = activity.get();
- SkuDetails skuDetails = getSkuDetails(sku);
- if (a != null && skuDetails != null) {
- BillingManager billingManager = getBillingManager();
- if (billingManager != null) {
- billingManager.setPayload(payload);
- billingManager.initiatePurchaseFlow(a, skuDetails);
- } else {
- throw new IllegalStateException("BillingManager disposed");
- }
- return false;
- } else {
- stop(true);
- }
- } catch (Exception e) {
- logError("launchPurchaseFlow Error", e);
- stop(true);
- }
- return true;
- }
- });
+ exec(InAppPurchaseTaskType.PURCHASE_LIVE_UPDATES, getPurchaseLiveUpdatesCommand(activity, sku, payload));
} else {
notifyError(InAppPurchaseTaskType.PURCHASE_LIVE_UPDATES, "Empty userId");
stop(true);
@@ -778,6 +369,9 @@ public class InAppPurchaseHelper {
}
}
+ protected abstract InAppCommand getPurchaseLiveUpdatesCommand(final WeakReference activity,
+ final String sku, final String payload) throws UnsupportedOperationException;
+
@SuppressLint("StaticFieldLeak")
private class RequestInventoryTask extends AsyncTask {
@@ -808,38 +402,41 @@ public class InAppPurchaseHelper {
try {
JSONObject obj = new JSONObject(response);
JSONArray names = obj.names();
- for (int i = 0; i < names.length(); i++) {
- String skuType = names.getString(i);
- JSONObject subObj = obj.getJSONObject(skuType);
- String sku = subObj.getString("sku");
- if (!Algorithms.isEmpty(sku)) {
- getLiveUpdates().upgradeSubscription(sku);
+ if (names != null) {
+ for (int i = 0; i < names.length(); i++) {
+ String skuType = names.getString(i);
+ JSONObject subObj = obj.getJSONObject(skuType);
+ String sku = subObj.getString("sku");
+ if (!Algorithms.isEmpty(sku)) {
+ getLiveUpdates().upgradeSubscription(sku);
+ }
}
}
} catch (JSONException e) {
logError("Json parsing error", e);
}
}
- exec(InAppPurchaseTaskType.REQUEST_INVENTORY, new InAppRunnable() {
- @Override
- public boolean run(InAppPurchaseHelper helper) {
- logDebug("Setup successful. Querying inventory.");
- try {
- BillingManager billingManager = getBillingManager();
- if (billingManager != null) {
- billingManager.queryPurchases();
- } else {
- throw new IllegalStateException("BillingManager disposed");
- }
- return false;
- } catch (Exception e) {
- logError("queryInventoryAsync Error", e);
- notifyDismissProgress(InAppPurchaseTaskType.REQUEST_INVENTORY);
- stop(true);
- }
- return true;
- }
- });
+ exec(InAppPurchaseTaskType.REQUEST_INVENTORY, getRequestInventoryCommand());
+ }
+ }
+
+ protected abstract InAppCommand getRequestInventoryCommand() throws UnsupportedOperationException;
+
+ protected void onSkuDetailsResponseDone(List purchaseInfoList) {
+ final AndroidNetworkUtils.OnRequestResultListener listener = new AndroidNetworkUtils.OnRequestResultListener() {
+ @Override
+ public void onResult(String result) {
+ notifyDismissProgress(InAppPurchaseTaskType.REQUEST_INVENTORY);
+ notifyGetItems();
+ stop(true);
+ logDebug("Initial inapp query finished");
+ }
+ };
+
+ if (purchaseInfoList.size() > 0) {
+ sendTokens(purchaseInfoList, listener);
+ } else {
+ listener.onResult("OK");
}
}
@@ -852,25 +449,16 @@ public class InAppPurchaseHelper {
parameters.put("aid", ctx.getUserAndroidId());
}
- // Call when a purchase is finished
- private void onPurchaseFinished(Purchase purchase) {
- logDebug("Purchase finished: " + purchase);
-
- // if we were disposed of in the meantime, quit.
- if (getBillingManager() == null) {
- stop(true);
- return;
- }
-
+ protected void onPurchaseDone(PurchaseInfo info) {
logDebug("Purchase successful.");
- InAppPurchase liveUpdatesPurchase = getLiveUpdates().getSubscriptionBySku(purchase.getSku());
+ InAppPurchase liveUpdatesPurchase = getLiveUpdates().getSubscriptionBySku(info.getSku());
if (liveUpdatesPurchase != null) {
// bought live updates
logDebug("Live updates subscription purchased.");
final String sku = liveUpdatesPurchase.getSku();
liveUpdatesPurchase.setPurchaseState(PurchaseState.PURCHASED);
- sendTokens(Collections.singletonList(purchase), new OnRequestResultListener() {
+ sendTokens(Collections.singletonList(info), new OnRequestResultListener() {
@Override
public void onResult(String result) {
boolean active = ctx.getSettings().LIVE_UPDATES_PURCHASED.get();
@@ -887,7 +475,7 @@ public class InAppPurchaseHelper {
}
});
- } else if (purchase.getSku().equals(getFullVersion().getSku())) {
+ } else if (info.getSku().equals(getFullVersion().getSku())) {
// bought full version
getFullVersion().setPurchaseState(PurchaseState.PURCHASED);
logDebug("Full version purchased.");
@@ -898,7 +486,7 @@ public class InAppPurchaseHelper {
notifyItemPurchased(getFullVersion().getSku(), false);
stop(true);
- } else if (purchase.getSku().equals(getDepthContours().getSku())) {
+ } else if (info.getSku().equals(getDepthContours().getSku())) {
// bought sea depth contours
getDepthContours().setPurchaseState(PurchaseState.PURCHASED);
logDebug("Sea depth contours purchased.");
@@ -910,6 +498,17 @@ public class InAppPurchaseHelper {
notifyItemPurchased(getDepthContours().getSku(), false);
stop(true);
+ } else if (info.getSku().equals(getContourLines().getSku())) {
+ // bought contour lines
+ getContourLines().setPurchaseState(PurchaseState.PURCHASED);
+ logDebug("Contours lines purchased.");
+ showToast(ctx.getString(R.string.contour_lines_thanks));
+ ctx.getSettings().CONTOUR_LINES_PURCHASED.set(true);
+
+ notifyDismissProgress(InAppPurchaseTaskType.PURCHASE_CONTOUR_LINES);
+ notifyItemPurchased(getContourLines().getSku(), false);
+ stop(true);
+
} else {
notifyDismissProgress(activeTask);
stop(true);
@@ -921,17 +520,19 @@ public class InAppPurchaseHelper {
stop(false);
}
- private void stop(boolean taskDone) {
+ protected abstract boolean isBillingManagerExists();
+
+ protected abstract void destroyBillingManager();
+
+ protected void stop(boolean taskDone) {
logDebug("Destroying helper.");
- BillingManager billingManager = getBillingManager();
- if (billingManager != null) {
+ if (isBillingManagerExists()) {
if (taskDone) {
processingTask = false;
}
if (!processingTask) {
activeTask = null;
- billingManager.destroy();
- this.billingManager = null;
+ destroyBillingManager();
}
} else {
processingTask = false;
@@ -943,7 +544,7 @@ public class InAppPurchaseHelper {
}
}
- private void sendTokens(@NonNull final List purchases, final OnRequestResultListener listener) {
+ protected void sendTokens(@NonNull final List purchaseInfoList, final OnRequestResultListener listener) {
final String userId = ctx.getSettings().BILLING_USER_ID.get();
final String token = ctx.getSettings().BILLING_USER_TOKEN.get();
final String email = ctx.getSettings().BILLING_USER_EMAIL.get();
@@ -951,12 +552,12 @@ public class InAppPurchaseHelper {
String url = "https://osmand.net/subscription/purchased";
String userOperation = "Sending purchase info...";
final List requests = new ArrayList<>();
- for (Purchase purchase : purchases) {
+ for (PurchaseInfo info : purchaseInfoList) {
Map parameters = new HashMap<>();
parameters.put("userid", userId);
- parameters.put("sku", purchase.getSku());
- parameters.put("orderId", purchase.getOrderId());
- parameters.put("purchaseToken", purchase.getPurchaseToken());
+ parameters.put("sku", info.getSku());
+ parameters.put("orderId", info.getOrderId());
+ parameters.put("purchaseToken", info.getPurchaseToken());
parameters.put("email", email);
parameters.put("token", token);
addUserInfo(parameters);
@@ -967,9 +568,9 @@ public class InAppPurchaseHelper {
public void onResult(@NonNull List results) {
for (RequestResponse rr : results) {
String sku = rr.getRequest().getParameters().get("sku");
- Purchase purchase = getPurchase(sku);
- if (purchase != null) {
- updateSentTokens(purchase);
+ PurchaseInfo info = getPurchaseInfo(sku);
+ if (info != null) {
+ updateSentTokens(info);
String result = rr.getResponse();
if (result != null) {
try {
@@ -979,13 +580,13 @@ public class InAppPurchaseHelper {
} else {
complain("SendToken Error: "
+ obj.getString("error")
- + " (userId=" + userId + " token=" + token + " response=" + result + " google=" + purchase.toString() + ")");
+ + " (userId=" + userId + " token=" + token + " response=" + result + " google=" + info.toString() + ")");
}
} catch (JSONException e) {
logError("SendToken", e);
complain("SendToken Error: "
+ (e.getMessage() != null ? e.getMessage() : "JSONException")
- + " (userId=" + userId + " token=" + token + " response=" + result + " google=" + purchase.toString() + ")");
+ + " (userId=" + userId + " token=" + token + " response=" + result + " google=" + info.toString() + ")");
}
}
}
@@ -995,10 +596,10 @@ public class InAppPurchaseHelper {
}
}
- private void updateSentTokens(@NonNull Purchase purchase) {
+ private void updateSentTokens(@NonNull PurchaseInfo info) {
String tokensSentStr = ctx.getSettings().BILLING_PURCHASE_TOKENS_SENT.get();
Set tokensSent = new HashSet<>(Arrays.asList(tokensSentStr.split(";")));
- tokensSent.add(purchase.getSku());
+ tokensSent.add(info.getSku());
ctx.getSettings().BILLING_PURCHASE_TOKENS_SENT.set(TextUtils.join(";", tokensSent));
}
@@ -1032,10 +633,10 @@ public class InAppPurchaseHelper {
}
@Nullable
- private Purchase getPurchase(String sku) {
- for (Purchase purchase : purchases) {
- if (purchase.getSku().equals(sku)) {
- return purchase;
+ private PurchaseInfo getPurchaseInfo(String sku) {
+ for (PurchaseInfo info : purchaseInfoList) {
+ if (info.getSku().equals(sku)) {
+ return info;
}
}
return null;
@@ -1049,31 +650,35 @@ public class InAppPurchaseHelper {
}
}
- private void notifyError(InAppPurchaseTaskType taskType, String message) {
+ public boolean onActivityResult(@NonNull Activity activity, int requestCode, int resultCode, Intent data) {
+ return false;
+ }
+
+ protected void notifyError(InAppPurchaseTaskType taskType, String message) {
if (uiActivity != null) {
uiActivity.onError(taskType, message);
}
}
- private void notifyGetItems() {
+ protected void notifyGetItems() {
if (uiActivity != null) {
uiActivity.onGetItems();
}
}
- private void notifyItemPurchased(String sku, boolean active) {
+ protected void notifyItemPurchased(String sku, boolean active) {
if (uiActivity != null) {
uiActivity.onItemPurchased(sku, active);
}
}
- private void notifyShowProgress(InAppPurchaseTaskType taskType) {
+ protected void notifyShowProgress(InAppPurchaseTaskType taskType) {
if (uiActivity != null) {
uiActivity.showProgress(taskType);
}
}
- private void notifyDismissProgress(InAppPurchaseTaskType taskType) {
+ protected void notifyDismissProgress(InAppPurchaseTaskType taskType) {
if (uiActivity != null) {
uiActivity.dismissProgress(taskType);
}
@@ -1090,26 +695,26 @@ public class InAppPurchaseHelper {
}
}
- private void complain(String message) {
+ protected void complain(String message) {
logError("**** InAppPurchaseHelper Error: " + message);
showToast(message);
}
- private void showToast(final String message) {
+ protected void showToast(final String message) {
ctx.showToastMessage(message);
}
- private void logDebug(String msg) {
+ protected void logDebug(String msg) {
if (mDebugLog) {
Log.d(TAG, msg);
}
}
- private void logError(String msg) {
+ protected void logError(String msg) {
Log.e(TAG, msg);
}
- private void logError(String msg, Throwable e) {
+ protected void logError(String msg, Throwable e) {
Log.e(TAG, "Error: " + msg, e);
}
diff --git a/OsmAnd/src/net/osmand/plus/inapp/InAppPurchases.java b/OsmAnd/src/net/osmand/plus/inapp/InAppPurchases.java
index b42b57f045..5004e97165 100644
--- a/OsmAnd/src/net/osmand/plus/inapp/InAppPurchases.java
+++ b/OsmAnd/src/net/osmand/plus/inapp/InAppPurchases.java
@@ -11,14 +11,11 @@ import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.billingclient.api.SkuDetails;
-
import net.osmand.AndroidUtils;
import net.osmand.Period;
import net.osmand.Period.PeriodUnit;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
-import net.osmand.plus.Version;
import net.osmand.plus.helpers.FontCache;
import net.osmand.plus.widgets.style.CustomTypefaceSpan;
import net.osmand.util.Algorithms;
@@ -33,64 +30,17 @@ import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
-public class InAppPurchases {
+public abstract class InAppPurchases {
- private static final InAppPurchase FULL_VERSION = new InAppPurchaseFullVersion();
- private static final InAppPurchaseDepthContoursFull DEPTH_CONTOURS_FULL = new InAppPurchaseDepthContoursFull();
- private static final InAppPurchaseDepthContoursFree DEPTH_CONTOURS_FREE = new InAppPurchaseDepthContoursFree();
- private static final InAppPurchaseContourLinesFull CONTOUR_LINES_FULL = new InAppPurchaseContourLinesFull();
- private static final InAppPurchaseContourLinesFree CONTOUR_LINES_FREE = new InAppPurchaseContourLinesFree();
+ protected InAppPurchase fullVersion;
+ protected InAppPurchase depthContours;
+ protected InAppPurchase contourLines;
+ protected InAppSubscription monthlyLiveUpdates;
+ protected InAppSubscription discountedMonthlyLiveUpdates;
+ protected InAppSubscriptionList liveUpdates;
+ protected InAppPurchase[] inAppPurchases;
- private static final InAppSubscription[] LIVE_UPDATES_FULL = new InAppSubscription[]{
- new InAppPurchaseLiveUpdatesOldMonthlyFull(),
- new InAppPurchaseLiveUpdatesMonthlyFull(),
- new InAppPurchaseLiveUpdates3MonthsFull(),
- new InAppPurchaseLiveUpdatesAnnualFull()
- };
-
- private static final InAppSubscription[] LIVE_UPDATES_FREE = new InAppSubscription[]{
- new InAppPurchaseLiveUpdatesOldMonthlyFree(),
- new InAppPurchaseLiveUpdatesMonthlyFree(),
- new InAppPurchaseLiveUpdates3MonthsFree(),
- new InAppPurchaseLiveUpdatesAnnualFree()
- };
-
- private InAppPurchase fullVersion;
- private InAppPurchase depthContours;
- private InAppPurchase contourLines;
- private InAppSubscription monthlyLiveUpdates;
- private InAppSubscription discountedMonthlyLiveUpdates;
- private InAppSubscriptionList liveUpdates;
- private InAppPurchase[] inAppPurchases;
-
- InAppPurchases(OsmandApplication ctx) {
- fullVersion = FULL_VERSION;
- if (Version.isFreeVersion(ctx)) {
- liveUpdates = new LiveUpdatesInAppPurchasesFree();
- } else {
- liveUpdates = new LiveUpdatesInAppPurchasesFull();
- }
- for (InAppSubscription s : liveUpdates.getAllSubscriptions()) {
- if (s instanceof InAppPurchaseLiveUpdatesMonthly) {
- if (s.isDiscounted()) {
- discountedMonthlyLiveUpdates = s;
- } else {
- monthlyLiveUpdates = s;
- }
- }
- }
- if (Version.isFreeVersion(ctx)) {
- depthContours = DEPTH_CONTOURS_FREE;
- } else {
- depthContours = DEPTH_CONTOURS_FULL;
- }
- if (Version.isFreeVersion(ctx)) {
- contourLines = CONTOUR_LINES_FREE;
- } else {
- contourLines = CONTOUR_LINES_FULL;
- }
-
- inAppPurchases = new InAppPurchase[] { fullVersion, depthContours, contourLines };
+ protected InAppPurchases(OsmandApplication ctx) {
}
public InAppPurchase getFullVersion() {
@@ -123,7 +73,7 @@ public class InAppPurchases {
public InAppSubscription getPurchasedMonthlyLiveUpdates() {
if (monthlyLiveUpdates.isAnyPurchased()) {
return monthlyLiveUpdates;
- } else if (discountedMonthlyLiveUpdates.isAnyPurchased()) {
+ } else if (discountedMonthlyLiveUpdates != null && discountedMonthlyLiveUpdates.isAnyPurchased()) {
return discountedMonthlyLiveUpdates;
}
return null;
@@ -158,31 +108,13 @@ public class InAppPurchases {
return null;
}
- public boolean isFullVersion(String sku) {
- return FULL_VERSION.getSku().equals(sku);
- }
+ public abstract boolean isFullVersion(String sku);
- public boolean isDepthContours(String sku) {
- return DEPTH_CONTOURS_FULL.getSku().equals(sku) || DEPTH_CONTOURS_FREE.getSku().equals(sku);
- }
+ public abstract boolean isDepthContours(String sku);
- public boolean isContourLines(String sku) {
- return CONTOUR_LINES_FULL.getSku().equals(sku) || CONTOUR_LINES_FREE.getSku().equals(sku);
- }
+ public abstract boolean isContourLines(String sku);
- public boolean isLiveUpdates(String sku) {
- for (InAppPurchase p : LIVE_UPDATES_FULL) {
- if (p.getSku().equals(sku)) {
- return true;
- }
- }
- for (InAppPurchase p : LIVE_UPDATES_FREE) {
- if (p.getSku().equals(sku)) {
- return true;
- }
- }
- return false;
- }
+ public abstract boolean isLiveUpdates(String sku);
public abstract static class InAppSubscriptionList {
@@ -260,20 +192,6 @@ public class InAppPurchases {
}
}
- public static class LiveUpdatesInAppPurchasesFree extends InAppSubscriptionList {
-
- public LiveUpdatesInAppPurchasesFree() {
- super(LIVE_UPDATES_FREE);
- }
- }
-
- public static class LiveUpdatesInAppPurchasesFull extends InAppSubscriptionList {
-
- public LiveUpdatesInAppPurchasesFull() {
- super(LIVE_UPDATES_FULL);
- }
- }
-
public abstract static class InAppPurchase {
public enum PurchaseState {
@@ -295,11 +213,11 @@ public class InAppPurchases {
private NumberFormat currencyFormatter;
- private InAppPurchase(@NonNull String sku) {
+ protected InAppPurchase(@NonNull String sku) {
this.sku = sku;
}
- private InAppPurchase(@NonNull String sku, boolean discounted) {
+ protected InAppPurchase(@NonNull String sku, boolean discounted) {
this(sku);
this.discounted = discounted;
}
@@ -777,23 +695,9 @@ public class InAppPurchases {
}
}
- public static class InAppPurchaseFullVersion extends InAppPurchase {
-
- private static final String SKU_FULL_VERSION_PRICE = "osmand_full_version_price";
-
- InAppPurchaseFullVersion() {
- super(SKU_FULL_VERSION_PRICE);
- }
-
- @Override
- public String getDefaultPrice(Context ctx) {
- return ctx.getString(R.string.full_version_price);
- }
- }
-
public static class InAppPurchaseDepthContours extends InAppPurchase {
- private InAppPurchaseDepthContours(String sku) {
+ protected InAppPurchaseDepthContours(String sku) {
super(sku);
}
@@ -803,27 +707,9 @@ public class InAppPurchases {
}
}
- public static class InAppPurchaseDepthContoursFull extends InAppPurchaseDepthContours {
-
- private static final String SKU_DEPTH_CONTOURS_FULL = "net.osmand.seadepth_plus";
-
- InAppPurchaseDepthContoursFull() {
- super(SKU_DEPTH_CONTOURS_FULL);
- }
- }
-
- public static class InAppPurchaseDepthContoursFree extends InAppPurchaseDepthContours {
-
- private static final String SKU_DEPTH_CONTOURS_FREE = "net.osmand.seadepth";
-
- InAppPurchaseDepthContoursFree() {
- super(SKU_DEPTH_CONTOURS_FREE);
- }
- }
-
public static class InAppPurchaseContourLines extends InAppPurchase {
- private InAppPurchaseContourLines(String sku) {
+ protected InAppPurchaseContourLines(String sku) {
super(sku);
}
@@ -833,25 +719,7 @@ public class InAppPurchases {
}
}
- public static class InAppPurchaseContourLinesFull extends InAppPurchaseContourLines {
-
- private static final String SKU_CONTOUR_LINES_FULL = "net.osmand.contourlines_plus";
-
- InAppPurchaseContourLinesFull() {
- super(SKU_CONTOUR_LINES_FULL);
- }
- }
-
- public static class InAppPurchaseContourLinesFree extends InAppPurchaseContourLines {
-
- private static final String SKU_CONTOUR_LINES_FREE = "net.osmand.contourlines";
-
- InAppPurchaseContourLinesFree() {
- super(SKU_CONTOUR_LINES_FREE);
- }
- }
-
- public static abstract class InAppPurchaseLiveUpdatesMonthly extends InAppSubscription {
+ protected static abstract class InAppPurchaseLiveUpdatesMonthly extends InAppSubscription {
InAppPurchaseLiveUpdatesMonthly(String skuNoVersion, int version) {
super(skuNoVersion, version);
@@ -905,45 +773,7 @@ public class InAppPurchases {
}
}
- public static class InAppPurchaseLiveUpdatesMonthlyFull extends InAppPurchaseLiveUpdatesMonthly {
-
- private static final String SKU_LIVE_UPDATES_MONTHLY_FULL = "osm_live_subscription_monthly_full";
-
- InAppPurchaseLiveUpdatesMonthlyFull() {
- super(SKU_LIVE_UPDATES_MONTHLY_FULL, 1);
- }
-
- private InAppPurchaseLiveUpdatesMonthlyFull(@NonNull String sku) {
- super(sku);
- }
-
- @Nullable
- @Override
- protected InAppSubscription newInstance(@NonNull String sku) {
- return sku.startsWith(getSkuNoVersion()) ? new InAppPurchaseLiveUpdatesMonthlyFull(sku) : null;
- }
- }
-
- public static class InAppPurchaseLiveUpdatesMonthlyFree extends InAppPurchaseLiveUpdatesMonthly {
-
- private static final String SKU_LIVE_UPDATES_MONTHLY_FREE = "osm_live_subscription_monthly_free";
-
- InAppPurchaseLiveUpdatesMonthlyFree() {
- super(SKU_LIVE_UPDATES_MONTHLY_FREE, 1);
- }
-
- private InAppPurchaseLiveUpdatesMonthlyFree(@NonNull String sku) {
- super(sku);
- }
-
- @Nullable
- @Override
- protected InAppSubscription newInstance(@NonNull String sku) {
- return sku.startsWith(getSkuNoVersion()) ? new InAppPurchaseLiveUpdatesMonthlyFree(sku) : null;
- }
- }
-
- public static abstract class InAppPurchaseLiveUpdates3Months extends InAppSubscription {
+ protected static abstract class InAppPurchaseLiveUpdates3Months extends InAppSubscription {
InAppPurchaseLiveUpdates3Months(String skuNoVersion, int version) {
super(skuNoVersion, version);
@@ -986,45 +816,7 @@ public class InAppPurchases {
}
}
- public static class InAppPurchaseLiveUpdates3MonthsFull extends InAppPurchaseLiveUpdates3Months {
-
- private static final String SKU_LIVE_UPDATES_3_MONTHS_FULL = "osm_live_subscription_3_months_full";
-
- InAppPurchaseLiveUpdates3MonthsFull() {
- super(SKU_LIVE_UPDATES_3_MONTHS_FULL, 1);
- }
-
- private InAppPurchaseLiveUpdates3MonthsFull(@NonNull String sku) {
- super(sku);
- }
-
- @Nullable
- @Override
- protected InAppSubscription newInstance(@NonNull String sku) {
- return sku.startsWith(getSkuNoVersion()) ? new InAppPurchaseLiveUpdates3MonthsFull(sku) : null;
- }
- }
-
- public static class InAppPurchaseLiveUpdates3MonthsFree extends InAppPurchaseLiveUpdates3Months {
-
- private static final String SKU_LIVE_UPDATES_3_MONTHS_FREE = "osm_live_subscription_3_months_free";
-
- InAppPurchaseLiveUpdates3MonthsFree() {
- super(SKU_LIVE_UPDATES_3_MONTHS_FREE, 1);
- }
-
- private InAppPurchaseLiveUpdates3MonthsFree(@NonNull String sku) {
- super(sku);
- }
-
- @Nullable
- @Override
- protected InAppSubscription newInstance(@NonNull String sku) {
- return sku.startsWith(getSkuNoVersion()) ? new InAppPurchaseLiveUpdates3MonthsFree(sku) : null;
- }
- }
-
- public static abstract class InAppPurchaseLiveUpdatesAnnual extends InAppSubscription {
+ protected static abstract class InAppPurchaseLiveUpdatesAnnual extends InAppSubscription {
InAppPurchaseLiveUpdatesAnnual(String skuNoVersion, int version) {
super(skuNoVersion, version);
@@ -1067,44 +859,6 @@ public class InAppPurchases {
}
}
- public static class InAppPurchaseLiveUpdatesAnnualFull extends InAppPurchaseLiveUpdatesAnnual {
-
- private static final String SKU_LIVE_UPDATES_ANNUAL_FULL = "osm_live_subscription_annual_full";
-
- InAppPurchaseLiveUpdatesAnnualFull() {
- super(SKU_LIVE_UPDATES_ANNUAL_FULL, 1);
- }
-
- private InAppPurchaseLiveUpdatesAnnualFull(@NonNull String sku) {
- super(sku);
- }
-
- @Nullable
- @Override
- protected InAppSubscription newInstance(@NonNull String sku) {
- return sku.startsWith(getSkuNoVersion()) ? new InAppPurchaseLiveUpdatesAnnualFull(sku) : null;
- }
- }
-
- public static class InAppPurchaseLiveUpdatesAnnualFree extends InAppPurchaseLiveUpdatesAnnual {
-
- private static final String SKU_LIVE_UPDATES_ANNUAL_FREE = "osm_live_subscription_annual_free";
-
- InAppPurchaseLiveUpdatesAnnualFree() {
- super(SKU_LIVE_UPDATES_ANNUAL_FREE, 1);
- }
-
- private InAppPurchaseLiveUpdatesAnnualFree(@NonNull String sku) {
- super(sku);
- }
-
- @Nullable
- @Override
- protected InAppSubscription newInstance(@NonNull String sku) {
- return sku.startsWith(getSkuNoVersion()) ? new InAppPurchaseLiveUpdatesAnnualFree(sku) : null;
- }
- }
-
public static class InAppPurchaseLiveUpdatesOldMonthly extends InAppPurchaseLiveUpdatesMonthly {
InAppPurchaseLiveUpdatesOldMonthly(String sku) {
@@ -1127,54 +881,5 @@ public class InAppPurchases {
return null;
}
}
-
- public static class InAppPurchaseLiveUpdatesOldMonthlyFull extends InAppPurchaseLiveUpdatesOldMonthly {
-
- private static final String SKU_LIVE_UPDATES_OLD_MONTHLY_FULL = "osm_live_subscription_2";
-
- InAppPurchaseLiveUpdatesOldMonthlyFull() {
- super(SKU_LIVE_UPDATES_OLD_MONTHLY_FULL);
- }
- }
-
- public static class InAppPurchaseLiveUpdatesOldMonthlyFree extends InAppPurchaseLiveUpdatesOldMonthly {
-
- private static final String SKU_LIVE_UPDATES_OLD_MONTHLY_FREE = "osm_free_live_subscription_2";
-
- InAppPurchaseLiveUpdatesOldMonthlyFree() {
- super(SKU_LIVE_UPDATES_OLD_MONTHLY_FREE);
- }
- }
-
- public static class InAppPurchaseLiveUpdatesOldSubscription extends InAppSubscription {
-
- private SkuDetails details;
-
- InAppPurchaseLiveUpdatesOldSubscription(@NonNull SkuDetails details) {
- super(details.getSku(), true);
- this.details = details;
- }
-
- @Override
- public String getDefaultPrice(Context ctx) {
- return "";
- }
-
- @Override
- public CharSequence getTitle(Context ctx) {
- return details.getTitle();
- }
-
- @Override
- public CharSequence getDescription(@NonNull Context ctx) {
- return details.getDescription();
- }
-
- @Nullable
- @Override
- protected InAppSubscription newInstance(@NonNull String sku) {
- return null;
- }
- }
}
diff --git a/OsmAnd/src/net/osmand/plus/render/RendererRegistry.java b/OsmAnd/src/net/osmand/plus/render/RendererRegistry.java
index 17dc572bc4..3f8ed81ba7 100644
--- a/OsmAnd/src/net/osmand/plus/render/RendererRegistry.java
+++ b/OsmAnd/src/net/osmand/plus/render/RendererRegistry.java
@@ -49,7 +49,7 @@ public class RendererRegistry {
private RenderingRulesStorage defaultRender = null;
private RenderingRulesStorage currentSelectedRender = null;
-
+
private Map externalRenderers = new LinkedHashMap();
private Map internalRenderers = new LinkedHashMap();
diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java b/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java
index efa7147e6c..1619102c84 100644
--- a/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java
+++ b/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java
@@ -2008,6 +2008,7 @@ public class OsmandSettings {
public final OsmandPreference LIVE_UPDATES_PURCHASE_CANCELLED_SECOND_DLG_SHOWN = new BooleanPreference("live_updates_purchase_cancelled_second_dlg_shown", false).makeGlobal();
public final OsmandPreference FULL_VERSION_PURCHASED = new BooleanPreference("billing_full_version_purchased", false).makeGlobal();
public final OsmandPreference DEPTH_CONTOURS_PURCHASED = new BooleanPreference("billing_sea_depth_purchased", false).makeGlobal();
+ public final OsmandPreference CONTOUR_LINES_PURCHASED = new BooleanPreference("billing_srtm_purchased", false).makeGlobal();
public final OsmandPreference EMAIL_SUBSCRIBED = new BooleanPreference("email_subscribed", false).makeGlobal();
public final OsmandPreference DISCOUNT_ID = new IntPreference("discount_id", 0).makeGlobal();
diff --git a/OsmAnd/src/net/osmand/plus/srtmplugin/SRTMPlugin.java b/OsmAnd/src/net/osmand/plus/srtmplugin/SRTMPlugin.java
index 808c541523..3690afbc3d 100644
--- a/OsmAnd/src/net/osmand/plus/srtmplugin/SRTMPlugin.java
+++ b/OsmAnd/src/net/osmand/plus/srtmplugin/SRTMPlugin.java
@@ -95,7 +95,9 @@ public class SRTMPlugin extends OsmandPlugin {
@Override
protected boolean pluginAvailable(OsmandApplication app) {
- return super.pluginAvailable(app) || InAppPurchaseHelper.isSubscribedToLiveUpdates(app);
+ return super.pluginAvailable(app)
+ || InAppPurchaseHelper.isSubscribedToLiveUpdates(app)
+ || InAppPurchaseHelper.isContourLinesPurchased(app);
}
@Override
@@ -359,7 +361,7 @@ public class SRTMPlugin extends OsmandPlugin {
.setTitleId(R.string.shared_string_terrain, mapActivity)
.setDescription(app.getString(terrainMode == TerrainMode.HILLSHADE
? R.string.shared_string_hillshade
- : R.string.shared_string_slope))
+ : R.string.download_slope_maps))
.setSelected(terrainEnabled)
.setColor(terrainEnabled ? R.color.osmand_orange : ContextMenuItem.INVALID_ID)
.setIcon(R.drawable.ic_action_hillshade_dark)
diff --git a/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWayDrawer.java b/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWayDrawer.java
index db45a9b55c..0bfa86f43b 100644
--- a/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWayDrawer.java
+++ b/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWayDrawer.java
@@ -31,22 +31,28 @@ public class GeometryWayDrawer {
int h = tb.getPixHeight();
int w = tb.getPixWidth();
- int left = -w / 4;
+ int left = -w / 4;
int right = w + w / 4;
- int top = - h/4;
- int bottom = h + h/4;
+ int top = -h / 4;
+ int bottom = h + h / 4;
boolean hasStyles = styles != null && styles.size() == tx.size();
double zoomCoef = tb.getZoomAnimation() > 0 ? (Math.pow(2, tb.getZoomAnimation() + tb.getZoomFloatPart())) : 1f;
- Bitmap arrow = context.getArrowBitmap();
- int arrowHeight = arrow.getHeight();
- double pxStep = arrowHeight * 4f * zoomCoef;
- double pxStepRegular = arrowHeight * 4f * zoomCoef;
+
+ int startIndex = tx.size() - 2;
+ double defaultPxStep;
+ if (hasStyles && styles.get(startIndex) != null) {
+ defaultPxStep = styles.get(startIndex).getPointStepPx(zoomCoef);
+ } else {
+ Bitmap arrow = context.getArrowBitmap();
+ defaultPxStep = arrow.getHeight() * 4f * zoomCoef;
+ }
+ double pxStep = defaultPxStep;
double dist = 0;
if (distPixToFinish != 0) {
dist = distPixToFinish - pxStep * ((int) (distPixToFinish / pxStep)); // dist < 1
}
- for (int i = tx.size() - 2; i >= 0; i --) {
+ for (int i = startIndex; i >= 0; i--) {
GeometryWayStyle> style = hasStyles ? styles.get(i) : null;
float px = tx.get(i);
float py = ty.get(i);
@@ -57,7 +63,7 @@ public class GeometryWayDrawer {
if (distSegment == 0) {
continue;
}
- pxStep = style != null ? style.getPointStepPx(zoomCoef) : pxStepRegular;
+ pxStep = style != null ? style.getPointStepPx(zoomCoef) : defaultPxStep;
if (dist >= pxStep) {
dist = 0;
}
diff --git a/build.gradle b/build.gradle
index 1cd0b221b4..a64480346c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,6 +4,9 @@ buildscript {
google()
mavenCentral()
jcenter()
+ maven {
+ url 'https://developer.huawei.com/repo/'
+ }
}
dependencies {
//classpath 'com.android.tools.build:gradle:2.+'
@@ -11,6 +14,9 @@ buildscript {
classpath 'com.google.gms:google-services:3.0.0'
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ if (gradle.startParameter.taskNames.toString().contains("huawei")) {
+ classpath 'com.huawei.agconnect:agcp:1.4.1.300'
+ }
}
}
@@ -32,5 +38,8 @@ allprojects {
maven {
url "https://jitpack.io"
}
+ maven {
+ url 'https://developer.huawei.com/repo/'
+ }
}
}