From d9baad56441eac7ae0217e69bee128f90a720231 Mon Sep 17 00:00:00 2001 From: max-klaus Date: Wed, 14 Apr 2021 19:38:46 +0300 Subject: [PATCH] Fix subscriptions new UI --- .../plus/inapp/InAppPurchaseHelperImpl.java | 32 ++- .../plus/inapp/InAppPurchaseHelperImpl.java | 8 +- .../plus/inapp/InAppPurchaseHelper.java | 58 ++-- .../net/osmand/plus/inapp/InAppPurchases.java | 271 +++++++++++++++--- .../fragments/SubscriptionsListCard.java | 43 +-- 5 files changed, 309 insertions(+), 103 deletions(-) diff --git a/OsmAnd/src-google/net/osmand/plus/inapp/InAppPurchaseHelperImpl.java b/OsmAnd/src-google/net/osmand/plus/inapp/InAppPurchaseHelperImpl.java index df05570f57..f1a07a1d3d 100644 --- a/OsmAnd/src-google/net/osmand/plus/inapp/InAppPurchaseHelperImpl.java +++ b/OsmAnd/src-google/net/osmand/plus/inapp/InAppPurchaseHelperImpl.java @@ -18,11 +18,12 @@ import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandPlugin; import net.osmand.plus.R; import net.osmand.plus.inapp.InAppPurchases.InAppPurchase; +import net.osmand.plus.inapp.InAppPurchases.InAppPurchase.PurchaseState; import net.osmand.plus.inapp.InAppPurchases.InAppSubscription; import net.osmand.plus.inapp.InAppPurchases.InAppSubscription.SubscriptionState; +import net.osmand.plus.inapp.InAppPurchases.PurchaseInfo; import net.osmand.plus.inapp.InAppPurchasesImpl.InAppPurchaseLiveUpdatesOldSubscription; import net.osmand.plus.inapp.util.BillingManager; -import net.osmand.plus.settings.backend.CommonPreference; import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.srtmplugin.SRTMPlugin; import net.osmand.util.Algorithms; @@ -310,8 +311,8 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper { } } } - for (Entry entry : subscriptionStateMap.entrySet()) { - SubscriptionState state = entry.getValue(); + for (Entry entry : subscriptionStateMap.entrySet()) { + SubscriptionState state = entry.getValue().state; if (state == SubscriptionState.PAUSED || state == SubscriptionState.ON_HOLD) { String sku = entry.getKey(); if (!result.contains(sku)) { @@ -492,15 +493,17 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper { } private PurchaseInfo getPurchaseInfo(Purchase purchase) { - return new PurchaseInfo(purchase.getSku(), purchase.getOrderId(), purchase.getPurchaseToken()); + return new PurchaseInfo(purchase.getSku(), purchase.getOrderId(), purchase.getPurchaseToken(), + purchase.getPurchaseTime(), purchase.getPurchaseState(), purchase.isAcknowledged(), purchase.isAutoRenewing()); } private void fetchInAppPurchase(@NonNull InAppPurchase inAppPurchase, @NonNull SkuDetails skuDetails, @Nullable Purchase purchase) { if (purchase != null) { - inAppPurchase.setPurchaseState(InAppPurchase.PurchaseState.PURCHASED); - inAppPurchase.setPurchaseTime(purchase.getPurchaseTime()); + inAppPurchase.setPurchaseState(PurchaseState.PURCHASED); + inAppPurchase.setPurchaseInfo(ctx, getPurchaseInfo(purchase)); } else { - inAppPurchase.setPurchaseState(InAppPurchase.PurchaseState.NOT_PURCHASED); + inAppPurchase.setPurchaseState(PurchaseState.NOT_PURCHASED); + inAppPurchase.restorePurchaseInfo(ctx); } inAppPurchase.setPrice(skuDetails.getPrice()); inAppPurchase.setPriceCurrencyCode(skuDetails.getPriceCurrencyCode()); @@ -519,18 +522,17 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper { } if (inAppPurchase instanceof InAppSubscription) { InAppSubscription s = (InAppSubscription) inAppPurchase; - - SubscriptionState state = subscriptionStateMap.get(inAppPurchase.getSku()); - s.setState(state == null ? SubscriptionState.UNDEFINED : state); - CommonPreference statePref = ctx.getSettings().registerStringPreference( - s.getSku() + "_state", SubscriptionState.UNDEFINED.getStateStr()).makeGlobal(); - s.setPrevState(SubscriptionState.getByStateStr(statePref.get())); - statePref.set(s.getState().getStateStr()); + s.restoreState(ctx); + s.restoreExpireTime(ctx); + SubscriptionStateHolder stateHolder = subscriptionStateMap.get(s.getSku()); + if (stateHolder != null) { + s.setState(ctx, stateHolder.state); + s.setExpireTime(ctx, stateHolder.expireTime); + } if (s.getState().isGone() && s.hasStateChanged()) { ctx.getSettings().LIVE_UPDATES_EXPIRED_FIRST_DLG_SHOWN_TIME.set(0L); ctx.getSettings().LIVE_UPDATES_EXPIRED_SECOND_DLG_SHOWN_TIME.set(0L); } - String introductoryPrice = skuDetails.getIntroductoryPrice(); String introductoryPricePeriod = skuDetails.getIntroductoryPricePeriod(); int introductoryPriceCycles = skuDetails.getIntroductoryPriceCycles(); diff --git a/OsmAnd/src-huawei/net/osmand/plus/inapp/InAppPurchaseHelperImpl.java b/OsmAnd/src-huawei/net/osmand/plus/inapp/InAppPurchaseHelperImpl.java index 6f930fec1d..704c086f47 100644 --- a/OsmAnd/src-huawei/net/osmand/plus/inapp/InAppPurchaseHelperImpl.java +++ b/OsmAnd/src-huawei/net/osmand/plus/inapp/InAppPurchaseHelperImpl.java @@ -29,6 +29,7 @@ import net.osmand.plus.OsmandApplication; import net.osmand.plus.inapp.InAppPurchases.InAppPurchase; import net.osmand.plus.inapp.InAppPurchases.InAppSubscription; import net.osmand.plus.inapp.InAppPurchases.InAppSubscriptionIntroductoryInfo; +import net.osmand.plus.inapp.InAppPurchases.PurchaseInfo; import net.osmand.plus.inapp.InAppPurchasesImpl.InAppPurchaseLiveUpdatesOldSubscription; import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.util.Algorithms; @@ -48,7 +49,7 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper { private List productInfos; private OwnedPurchasesResult ownedSubscriptions; - private List ownedInApps = new ArrayList<>(); + private final List ownedInApps = new ArrayList<>(); public InAppPurchaseHelperImpl(OsmandApplication ctx) { super(ctx); @@ -233,15 +234,18 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper { } private PurchaseInfo getPurchaseInfo(InAppPurchaseData purchase) { - return new PurchaseInfo(purchase.getProductId(), purchase.getSubscriptionId(), purchase.getPurchaseToken()); + return new PurchaseInfo(purchase.getProductId(), purchase.getSubscriptionId(), purchase.getPurchaseToken(), + purchase.getPurchaseTime(), purchase.getPurchaseState(), true, purchase.isAutoRenewing()); } private void fetchInAppPurchase(@NonNull InAppPurchase inAppPurchase, @NonNull ProductInfo productInfo, @Nullable InAppPurchaseData purchaseData) { if (purchaseData != null) { inAppPurchase.setPurchaseState(InAppPurchase.PurchaseState.PURCHASED); inAppPurchase.setPurchaseTime(purchaseData.getPurchaseTime()); + inAppPurchase.setPurchaseInfo(ctx, getPurchaseInfo(purchaseData)); } else { inAppPurchase.setPurchaseState(InAppPurchase.PurchaseState.NOT_PURCHASED); + inAppPurchase.restorePurchaseInfo(ctx); } inAppPurchase.setPrice(productInfo.getPrice()); inAppPurchase.setPriceCurrencyCode(productInfo.getCurrency()); diff --git a/OsmAnd/src/net/osmand/plus/inapp/InAppPurchaseHelper.java b/OsmAnd/src/net/osmand/plus/inapp/InAppPurchaseHelper.java index 5136cd1f73..1a36558b87 100644 --- a/OsmAnd/src/net/osmand/plus/inapp/InAppPurchaseHelper.java +++ b/OsmAnd/src/net/osmand/plus/inapp/InAppPurchaseHelper.java @@ -21,6 +21,7 @@ import net.osmand.plus.inapp.InAppPurchases.InAppPurchase.PurchaseState; import net.osmand.plus.inapp.InAppPurchases.InAppSubscription; import net.osmand.plus.inapp.InAppPurchases.InAppSubscription.SubscriptionState; import net.osmand.plus.inapp.InAppPurchases.InAppSubscriptionList; +import net.osmand.plus.inapp.InAppPurchases.PurchaseInfo; import net.osmand.plus.liveupdates.CountrySelectionFragment; import net.osmand.plus.liveupdates.CountrySelectionFragment.CountryItem; import net.osmand.plus.settings.backend.OsmandSettings; @@ -52,7 +53,7 @@ public abstract class InAppPurchaseHelper { protected InAppPurchases purchases; protected long lastValidationCheckTime; protected boolean inventoryRequested; - protected Map subscriptionStateMap = new HashMap<>(); + protected Map subscriptionStateMap = new HashMap<>(); private static final long PURCHASE_VALIDATION_PERIOD_MSEC = 1000 * 60 * 60 * 24; // daily @@ -85,6 +86,11 @@ public abstract class InAppPurchaseHelper { void onFail(); } + static class SubscriptionStateHolder { + SubscriptionState state = SubscriptionState.UNDEFINED; + long expireTime = 0; + } + public enum InAppPurchaseTaskType { REQUEST_INVENTORY, PURCHASE_FULL_VERSION, @@ -112,30 +118,6 @@ public abstract class InAppPurchaseHelper { 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() { return token; } @@ -193,6 +175,11 @@ public abstract class InAppPurchaseHelper { return purchases.getPurchasedMonthlyLiveUpdates(); } + @Nullable + public InAppSubscription getAnyPurchasedSubscription() { + return purchases.getAnyPurchasedSubscription(); + } + public InAppPurchaseHelper(OsmandApplication ctx) { this.ctx = ctx; isDeveloperVersion = Version.isDeveloperVersion(ctx); @@ -202,8 +189,7 @@ public abstract class InAppPurchaseHelper { public List getEverMadeSubscriptions() { List subscriptions = new ArrayList<>(); for (InAppSubscription subscription : getLiveUpdates().getVisibleSubscriptions()) { - SubscriptionState state = subscription.getState(); - if (state != SubscriptionState.UNDEFINED) { + if (subscription.isPurchased() || subscription.getState() != SubscriptionState.UNDEFINED) { subscriptions.add(subscription); } } @@ -448,15 +434,22 @@ public abstract class InAppPurchaseHelper { } if (subscriptionsStateJson != null) { inventoryRequested = true; - Map subscriptionStateMap = new HashMap<>(); + Map subscriptionStateMap = new HashMap<>(); try { JSONArray subArrJson = new JSONArray(subscriptionsStateJson); for (int i = 0; i < subArrJson.length(); i++) { JSONObject subObj = subArrJson.getJSONObject(i); String sku = subObj.getString("sku"); String state = subObj.getString("state"); + long expireTime = 0; + if (subObj.has("expire_time")) { + expireTime = subObj.getLong("expire_time"); + } if (!Algorithms.isEmpty(sku) && !Algorithms.isEmpty(state)) { - subscriptionStateMap.put(sku, SubscriptionState.getByStateStr(state)); + SubscriptionStateHolder stateHolder = new SubscriptionStateHolder(); + stateHolder.state = SubscriptionState.getByStateStr(state); + stateHolder.expireTime = expireTime; + subscriptionStateMap.put(sku, stateHolder); } } } catch (JSONException e) { @@ -500,12 +493,14 @@ public abstract class InAppPurchaseHelper { protected void onPurchaseDone(PurchaseInfo info) { logDebug("Purchase successful."); - InAppPurchase liveUpdatesPurchase = getLiveUpdates().getSubscriptionBySku(info.getSku()); + InAppSubscription 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); + liveUpdatesPurchase.setPurchaseInfo(ctx, info); + liveUpdatesPurchase.setState(ctx, SubscriptionState.UNDEFINED); sendTokens(Collections.singletonList(info), new OnRequestResultListener() { @Override public void onResult(String result) { @@ -525,6 +520,7 @@ public abstract class InAppPurchaseHelper { } else if (info.getSku().equals(getFullVersion().getSku())) { // bought full version getFullVersion().setPurchaseState(PurchaseState.PURCHASED); + getFullVersion().setPurchaseInfo(ctx, info); logDebug("Full version purchased."); showToast(ctx.getString(R.string.full_version_thanks)); ctx.getSettings().FULL_VERSION_PURCHASED.set(true); @@ -536,6 +532,7 @@ public abstract class InAppPurchaseHelper { } else if (info.getSku().equals(getDepthContours().getSku())) { // bought sea depth contours getDepthContours().setPurchaseState(PurchaseState.PURCHASED); + getDepthContours().setPurchaseInfo(ctx, info); logDebug("Sea depth contours purchased."); showToast(ctx.getString(R.string.sea_depth_thanks)); ctx.getSettings().DEPTH_CONTOURS_PURCHASED.set(true); @@ -548,6 +545,7 @@ public abstract class InAppPurchaseHelper { } else if (info.getSku().equals(getContourLines().getSku())) { // bought contour lines getContourLines().setPurchaseState(PurchaseState.PURCHASED); + getContourLines().setPurchaseInfo(ctx, info); logDebug("Contours lines purchased."); showToast(ctx.getString(R.string.contour_lines_thanks)); ctx.getSettings().CONTOUR_LINES_PURCHASED.set(true); diff --git a/OsmAnd/src/net/osmand/plus/inapp/InAppPurchases.java b/OsmAnd/src/net/osmand/plus/inapp/InAppPurchases.java index 27d359630e..61dae8f0e8 100644 --- a/OsmAnd/src/net/osmand/plus/inapp/InAppPurchases.java +++ b/OsmAnd/src/net/osmand/plus/inapp/InAppPurchases.java @@ -7,33 +7,41 @@ import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.style.ForegroundColorSpan; +import androidx.annotation.ColorInt; +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; + 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.helpers.FontCache; +import net.osmand.plus.settings.backend.CommonPreference; +import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.widgets.style.CustomTypefaceSpan; import net.osmand.util.Algorithms; +import org.json.JSONException; +import org.json.JSONObject; + import java.text.NumberFormat; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Calendar; import java.util.Collections; import java.util.Comparator; import java.util.Currency; +import java.util.Date; +import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import androidx.annotation.ColorInt; -import androidx.annotation.DrawableRes; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.StringRes; - public abstract class InAppPurchases { protected InAppPurchase fullVersion; @@ -47,6 +55,10 @@ public abstract class InAppPurchases { protected InAppPurchases(OsmandApplication ctx) { } + private static OsmandSettings getSettings(@NonNull Context ctx) { + return ((OsmandApplication) ctx.getApplicationContext()).getSettings(); + } + public InAppPurchase getFullVersion() { return fullVersion; } @@ -83,6 +95,17 @@ public abstract class InAppPurchases { return null; } + @Nullable + public InAppSubscription getAnyPurchasedSubscription() { + List allSubscriptions = liveUpdates.getAllSubscriptions(); + for (InAppSubscription subscription : allSubscriptions) { + if (subscription.isAnyPurchased()) { + return subscription; + } + } + return null; + } + public InAppSubscriptionList getLiveUpdates() { return liveUpdates; } @@ -231,7 +254,7 @@ public abstract class InAppPurchases { private double priceValue; private String priceCurrencyCode; private PurchaseState purchaseState = PurchaseState.UNKNOWN; - private long purchaseTime; + private PurchaseInfo purchaseInfo; double monthlyPriceValue; boolean donationSupported = false; @@ -253,6 +276,37 @@ public abstract class InAppPurchases { return sku; } + @Nullable + public String getOrderId() { + return purchaseInfo != null ? purchaseInfo.getOrderId() : null; + } + + private CommonPreference getPurchaseInfoPref(@NonNull Context ctx) { + return getSettings(ctx).registerStringPreference(sku + "_purchase_info", "").makeGlobal(); + } + + public boolean storePurchaseInfo(@NonNull Context ctx) { + PurchaseInfo purchaseInfo = this.purchaseInfo; + if (purchaseInfo != null) { + getPurchaseInfoPref(ctx).set(purchaseInfo.toJson()); + return true; + } + return false; + } + + public boolean restorePurchaseInfo(@NonNull Context ctx) { + String json = getPurchaseInfoPref(ctx).get(); + if (!Algorithms.isEmpty(json)) { + try { + purchaseInfo = new PurchaseInfo(json); + } catch (JSONException e) { + // ignore + } + return true; + } + return false; + } + public String getPrice(Context ctx) { if (!Algorithms.isEmpty(price)) { return price; @@ -266,11 +320,16 @@ public abstract class InAppPurchases { } public long getPurchaseTime() { - return purchaseTime; + return purchaseInfo != null ? purchaseInfo.getPurchaseTime() : 0; } - public void setPurchaseTime(long purchaseTime) { - this.purchaseTime = purchaseTime; + public PurchaseInfo getPurchaseInfo() { + return purchaseInfo; + } + + void setPurchaseInfo(@NonNull Context ctx, PurchaseInfo purchaseInfo) { + this.purchaseInfo = purchaseInfo; + storePurchaseInfo(ctx); } public String getDefaultPrice(Context ctx) { @@ -571,35 +630,33 @@ public abstract class InAppPurchases { public static abstract class InAppSubscription extends InAppPurchase { - private Map upgrades = new ConcurrentHashMap<>(); - private String skuNoVersion; + private final Map upgrades = new ConcurrentHashMap<>(); + private final String skuNoVersion; private String subscriptionPeriodString; private Period subscriptionPeriod; private boolean upgrade = false; private SubscriptionState state = SubscriptionState.UNDEFINED; - private SubscriptionState prevState = SubscriptionState.UNDEFINED; + private SubscriptionState previousState = SubscriptionState.UNDEFINED; + private long expireTime = 0; private InAppSubscriptionIntroductoryInfo introductoryInfo; public enum SubscriptionState { - UNDEFINED("undefined", 0, 0), - ACTIVE("active", R.string.osm_live_active, R.drawable.bg_osmand_live_active), - CANCELLED("cancelled", R.string.osmand_live_cancelled, R.drawable.bg_osmand_live_cancelled), - IN_GRACE_PERIOD("in_grace_period", R.string.in_grace_period, R.drawable.bg_osmand_live_active), - ON_HOLD("on_hold", R.string.on_hold, R.drawable.bg_osmand_live_cancelled), - PAUSED("paused", R.string.shared_string_paused, R.drawable.bg_osmand_live_cancelled), - EXPIRED("expired", R.string.expired, R.drawable.bg_osmand_live_cancelled); + UNDEFINED("undefined", R.string.shared_string_undefined), + ACTIVE("active", R.string.osm_live_active), + CANCELLED("cancelled", R.string.osmand_live_cancelled), + IN_GRACE_PERIOD("in_grace_period", R.string.in_grace_period), + ON_HOLD("on_hold", R.string.on_hold), + PAUSED("paused", R.string.shared_string_paused), + EXPIRED("expired", R.string.expired); private final String stateStr; @StringRes private final int stringRes; - @DrawableRes - private final int backgroundRes; - SubscriptionState(@NonNull String stateStr, @StringRes int stringRes, @DrawableRes int backgroundRes) { + SubscriptionState(@NonNull String stateStr, @StringRes int stringRes) { this.stateStr = stateStr; this.stringRes = stringRes; - this.backgroundRes = backgroundRes; } public String getStateStr() { @@ -611,11 +668,6 @@ public abstract class InAppPurchases { return stringRes; } - @DrawableRes - public int getBackgroundRes() { - return backgroundRes; - } - @NonNull public static SubscriptionState getByStateStr(@NonNull String stateStr) { for (SubscriptionState state : SubscriptionState.values()) { @@ -678,21 +730,76 @@ public abstract class InAppPurchases { return state; } - public void setState(@NonNull SubscriptionState state) { + public void setState(@NonNull Context ctx, @NonNull SubscriptionState state) { this.state = state; + storeState(ctx, state); } @NonNull - public SubscriptionState getPrevState() { - return prevState; - } - - public void setPrevState(@NonNull SubscriptionState prevState) { - this.prevState = prevState; + public SubscriptionState getPreviousState() { + return previousState; } public boolean hasStateChanged() { - return state != prevState; + return state != previousState; + } + + private CommonPreference getStatePref(@NonNull Context ctx) { + return getSettings(ctx).registerStringPreference(getSku() + "_state", "").makeGlobal(); + } + + void storeState(@NonNull Context ctx, @NonNull SubscriptionState state) { + getStatePref(ctx).set(state.getStateStr()); + } + + boolean restoreState(@NonNull Context ctx) { + String stateStr = getStatePref(ctx).get(); + if (!Algorithms.isEmpty(stateStr)) { + SubscriptionState state = SubscriptionState.getByStateStr(stateStr); + this.previousState = state; + this.state = state; + return true; + } + return false; + } + + public long getCalculatedExpiredTime() { + long purchaseTime = getPurchaseTime(); + Period period = getSubscriptionPeriod(); + if (purchaseTime == 0 || period == null || period.getUnit() == null) { + return 0; + } + Date date = new Date(purchaseTime); + Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); + calendar.add(period.getUnit().getCalendarIdx(), period.getNumberOfUnits()); + return calendar.getTimeInMillis(); + } + + public long getExpireTime() { + return expireTime; + } + + public void setExpireTime(@NonNull Context ctx, long expireTime) { + this.expireTime = expireTime; + storeExpireTime(ctx, expireTime); + } + + private CommonPreference getExpireTimePref(@NonNull Context ctx) { + return getSettings(ctx).registerLongPreference(getSku() + "_expire_time", 0L).makeGlobal(); + } + + boolean restoreExpireTime(@NonNull Context ctx) { + Long expireTime = getExpireTimePref(ctx).get(); + if (expireTime != null) { + this.expireTime = expireTime; + return true; + } + return false; + } + + void storeExpireTime(@NonNull Context ctx, long expireTime) { + getExpireTimePref(ctx).set(expireTime); } public boolean isAnyPurchased() { @@ -999,5 +1106,95 @@ public abstract class InAppPurchases { return null; } } + + public static class PurchaseInfo { + private String sku; + private String orderId; + private String purchaseToken; + private long purchaseTime; + private int purchaseState; + private boolean acknowledged; + private boolean autoRenewing; + + PurchaseInfo(String sku, String orderId, String purchaseToken, long purchaseTime, + int purchaseState, boolean acknowledged, boolean autoRenewing) { + this.sku = sku; + this.orderId = orderId; + this.purchaseToken = purchaseToken; + this.purchaseTime = purchaseTime; + this.purchaseState = purchaseState; + this.acknowledged = acknowledged; + this.autoRenewing = autoRenewing; + } + + PurchaseInfo(@NonNull String json) throws JSONException { + parseJson(json); + } + + public String getSku() { + return sku; + } + + public String getOrderId() { + return orderId; + } + + public String getPurchaseToken() { + return purchaseToken; + } + + public long getPurchaseTime() { + return purchaseTime; + } + + public int getPurchaseState() { + return purchaseState; + } + + public boolean isAcknowledged() { + return acknowledged; + } + + public boolean isAutoRenewing() { + return autoRenewing; + } + + public String toJson() { + Map jsonMap = new HashMap<>(); + jsonMap.put("sku", sku); + jsonMap.put("orderId", orderId); + jsonMap.put("purchaseToken", purchaseToken); + jsonMap.put("purchaseTime", purchaseTime); + jsonMap.put("purchaseState", purchaseState); + jsonMap.put("acknowledged", acknowledged); + jsonMap.put("autoRenewing", autoRenewing); + return new JSONObject(jsonMap).toString(); + } + + public void parseJson(@NonNull String json) throws JSONException { + JSONObject jsonObj = new JSONObject(json); + if (jsonObj.has("sku")) { + this.sku = jsonObj.getString("sku"); + } + if (jsonObj.has("orderId")) { + this.orderId = jsonObj.getString("orderId"); + } + if (jsonObj.has("purchaseToken")) { + this.purchaseToken = jsonObj.getString("purchaseToken"); + } + if (jsonObj.has("purchaseTime")) { + this.purchaseTime = jsonObj.getLong("purchaseTime"); + } + if (jsonObj.has("purchaseState")) { + this.purchaseState = jsonObj.getInt("purchaseState"); + } + if (jsonObj.has("acknowledged")) { + this.acknowledged = jsonObj.getBoolean("acknowledged"); + } + if (jsonObj.has("autoRenewing")) { + this.autoRenewing = jsonObj.getBoolean("autoRenewing"); + } + } + } } diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/SubscriptionsListCard.java b/OsmAnd/src/net/osmand/plus/settings/fragments/SubscriptionsListCard.java index 645a68b037..d4f56cdc76 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/SubscriptionsListCard.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/SubscriptionsListCard.java @@ -7,7 +7,6 @@ import android.view.ViewGroup; import android.widget.TextView; import net.osmand.AndroidUtils; -import net.osmand.Period; import net.osmand.plus.R; import net.osmand.plus.UiUtilities; import net.osmand.plus.activities.MapActivity; @@ -20,11 +19,10 @@ import net.osmand.plus.routepreparationmenu.cards.BaseCard; import net.osmand.util.Algorithms; import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; import java.util.List; import java.util.Locale; +import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; public class SubscriptionsListCard extends BaseCard { @@ -60,7 +58,13 @@ public class SubscriptionsListCard extends BaseCard { for (int i = 0; i < subscriptions.size(); i++) { InAppSubscription subscription = subscriptions.get(i); SubscriptionState state = subscription.getState(); - boolean autoRenewed = state == SubscriptionState.ACTIVE || state == SubscriptionState.IN_GRACE_PERIOD; + boolean autoRenewing = false; + if (subscription.isPurchased() && subscription.getPurchaseInfo() != null) { + autoRenewing = subscription.getPurchaseInfo().isAutoRenewing(); + state = SubscriptionState.ACTIVE; + } else if (state != SubscriptionState.UNDEFINED) { + autoRenewing = state == SubscriptionState.ACTIVE || state == SubscriptionState.IN_GRACE_PERIOD; + } View card = inflater.inflate(R.layout.subscription_layout, null, false); ((ViewGroup) view).addView(card); @@ -72,11 +76,18 @@ public class SubscriptionsListCard extends BaseCard { AndroidUiHelper.updateVisibility(subscriptionPeriod, true); } - if (autoRenewed) { + if (autoRenewing) { TextView nextBillingDate = card.findViewById(R.id.next_billing_date); - String date = getHumanDate(subscription.getPurchaseTime(), subscription.getSubscriptionPeriod()); - if (!Algorithms.isEmpty(date)) { - nextBillingDate.setText(app.getString(R.string.next_billing_date, date)); + String expiredTimeStr = null; + long expiredTime = subscription.getExpireTime(); + if (expiredTime == 0) { + expiredTime = subscription.getCalculatedExpiredTime(); + } + if (expiredTime > 0) { + expiredTimeStr = dateFormat.format(expiredTime); + } + if (!Algorithms.isEmpty(expiredTimeStr)) { + nextBillingDate.setText(app.getString(R.string.next_billing_date, expiredTimeStr)); AndroidUiHelper.updateVisibility(nextBillingDate, true); } } else { @@ -102,7 +113,7 @@ public class SubscriptionsListCard extends BaseCard { TextView status = card.findViewById(R.id.status); status.setText(app.getString(state.getStringRes())); - AndroidUtils.setBackground(status, app.getUIUtilities().getIcon(state.getBackgroundRes())); + AndroidUtils.setBackground(status, app.getUIUtilities().getIcon(getBackgroundRes(state))); int dividerLayout = i + 1 == subscriptions.size() ? R.layout.simple_divider_item : R.layout.divider_half_item; View divider = inflater.inflate(dividerLayout, (ViewGroup) view, false); @@ -110,15 +121,9 @@ public class SubscriptionsListCard extends BaseCard { } } - private String getHumanDate(long time, Period period) { - if (period == null || period.getUnit() == null) { - return ""; - } - Date date = new Date(time); - Calendar calendar = Calendar.getInstance(); - calendar.setTime(date); - calendar.add(period.getUnit().getCalendarIdx(), period.getNumberOfUnits()); - date = calendar.getTime(); - return dateFormat.format(date); + @DrawableRes + private int getBackgroundRes(@NonNull SubscriptionState state) { + return state == SubscriptionState.ACTIVE || state == SubscriptionState.IN_GRACE_PERIOD + ? R.drawable.bg_osmand_live_active : R.drawable.bg_osmand_live_cancelled; } } \ No newline at end of file