Merge branch 'master' into fix-alignment

# Conflicts:
#	OsmAnd/src/net/osmand/plus/widgets/FlowLayout.java
This commit is contained in:
androiddevkotlin 2021-03-06 22:42:38 +02:00
commit 802d063142
11 changed files with 105 additions and 84 deletions

View file

@ -186,32 +186,22 @@ public class RouteResultPreparation {
public RouteSegmentResult filterMinorStops(RouteSegmentResult seg) { public RouteSegmentResult filterMinorStops(RouteSegmentResult seg) {
List<Integer> stops = null; List<Integer> stops = null;
int startPoint = seg.getStartPointIndex(); boolean plus = seg.getStartPointIndex() < seg.getEndPointIndex();
int endPoint = seg.getEndPointIndex(); int next;
int start;
int end;
if (startPoint < endPoint) { for (int i = seg.getStartPointIndex(); i != seg.getEndPointIndex(); i = next) {
start = startPoint; next = plus ? i + 1 : i - 1;
end = endPoint; int[] pointTypes = seg.getObject().getPointTypes(i);
} else {
start = endPoint;
end = startPoint;
}
while (start <= end) {
int[] pointTypes = seg.getObject().getPointTypes(start);
if (pointTypes != null) { if (pointTypes != null) {
for (int j = 0; j < pointTypes.length; j++) { for (int j = 0; j < pointTypes.length; j++) {
if (pointTypes[j] == seg.getObject().region.stopMinor) { if (pointTypes[j] == seg.getObject().region.stopMinor) {
if (stops == null) { if (stops == null) {
stops = new ArrayList<>(); stops = new ArrayList<>();
} }
stops.add(start); stops.add(i);
} }
} }
} }
start++;
} }
if (stops != null) { if (stops != null) {

View file

@ -16,7 +16,6 @@
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="com.android.vending.BILLING" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

View file

@ -348,7 +348,7 @@ dependencies {
implementation 'org.immutables:gson:2.5.0' implementation 'org.immutables:gson:2.5.0'
implementation 'com.vividsolutions:jts-core:1.14.0' implementation 'com.vividsolutions:jts-core:1.14.0'
implementation 'com.google.openlocationcode:openlocationcode:1.0.4' implementation 'com.google.openlocationcode:openlocationcode:1.0.4'
implementation 'com.android.billingclient:billing:2.0.3' implementation 'com.android.billingclient:billing:3.0.2'
// turn off for now // turn off for now
//implementation 'com.atilika.kuromoji:kuromoji-ipadic:0.9.0' //implementation 'com.atilika.kuromoji:kuromoji-ipadic:0.9.0'
implementation 'com.squareup.picasso:picasso:2.71828' implementation 'com.squareup.picasso:picasso:2.71828'

View file

@ -6,9 +6,7 @@ import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull; import com.android.billingclient.api.AccountIdentifiers;
import androidx.annotation.Nullable;
import com.android.billingclient.api.BillingClient; import com.android.billingclient.api.BillingClient;
import com.android.billingclient.api.BillingResult; import com.android.billingclient.api.BillingResult;
import com.android.billingclient.api.Purchase; import com.android.billingclient.api.Purchase;
@ -25,7 +23,6 @@ import net.osmand.plus.inapp.InAppPurchases.InAppSubscription.SubscriptionState;
import net.osmand.plus.inapp.InAppPurchasesImpl.InAppPurchaseLiveUpdatesOldSubscription; import net.osmand.plus.inapp.InAppPurchasesImpl.InAppPurchaseLiveUpdatesOldSubscription;
import net.osmand.plus.inapp.util.BillingManager; import net.osmand.plus.inapp.util.BillingManager;
import net.osmand.plus.settings.backend.CommonPreference; import net.osmand.plus.settings.backend.CommonPreference;
import net.osmand.plus.settings.backend.OsmandPreference;
import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.srtmplugin.SRTMPlugin; import net.osmand.plus.srtmplugin.SRTMPlugin;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
@ -37,6 +34,9 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class InAppPurchaseHelperImpl extends InAppPurchaseHelper { public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
// The helper object // The helper object
@ -77,6 +77,7 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
return billingManager; return billingManager;
} }
@Override
protected void execImpl(@NonNull final InAppPurchaseTaskType taskType, @NonNull final InAppCommand runnable) { protected void execImpl(@NonNull final InAppPurchaseTaskType taskType, @NonNull final InAppCommand runnable) {
billingManager = new BillingManager(ctx, BASE64_ENCODED_PUBLIC_KEY, new BillingManager.BillingUpdatesListener() { billingManager = new BillingManager(ctx, BASE64_ENCODED_PUBLIC_KEY, new BillingManager.BillingUpdatesListener() {
@ -126,7 +127,7 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
} }
billingManager.querySkuDetailsAsync(BillingClient.SkuType.INAPP, skuInApps, new SkuDetailsResponseListener() { billingManager.querySkuDetailsAsync(BillingClient.SkuType.INAPP, skuInApps, new SkuDetailsResponseListener() {
@Override @Override
public void onSkuDetailsResponse(BillingResult billingResult, final List<SkuDetails> skuDetailsListInApps) { public void onSkuDetailsResponse(@NonNull BillingResult billingResult, final List<SkuDetails> skuDetailsListInApps) {
// Is it a failure? // Is it a failure?
if (billingResult.getResponseCode() != BillingClient.BillingResponseCode.OK) { if (billingResult.getResponseCode() != BillingClient.BillingResponseCode.OK) {
logError("Failed to query inapps sku details: " + billingResult.getResponseCode()); logError("Failed to query inapps sku details: " + billingResult.getResponseCode());
@ -153,7 +154,7 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
billingManager.querySkuDetailsAsync(BillingClient.SkuType.SUBS, skuSubscriptions, new SkuDetailsResponseListener() { billingManager.querySkuDetailsAsync(BillingClient.SkuType.SUBS, skuSubscriptions, new SkuDetailsResponseListener() {
@Override @Override
public void onSkuDetailsResponse(BillingResult billingResult, final List<SkuDetails> skuDetailsListSubscriptions) { public void onSkuDetailsResponse(@NonNull BillingResult billingResult, final List<SkuDetails> skuDetailsListSubscriptions) {
// Is it a failure? // Is it a failure?
if (billingResult.getResponseCode() != BillingClient.BillingResponseCode.OK) { if (billingResult.getResponseCode() != BillingClient.BillingResponseCode.OK) {
logError("Failed to query subscriptipons sku details: " + billingResult.getResponseCode()); logError("Failed to query subscriptipons sku details: " + billingResult.getResponseCode());
@ -197,6 +198,7 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
if (skuDetails == null) { if (skuDetails == null) {
throw new IllegalArgumentException("Cannot find sku details"); throw new IllegalArgumentException("Cannot find sku details");
} }
BillingManager billingManager = getBillingManager(); BillingManager billingManager = getBillingManager();
if (billingManager != null) { if (billingManager != null) {
billingManager.initiatePurchaseFlow(activity, skuDetails); billingManager.initiatePurchaseFlow(activity, skuDetails);
@ -321,7 +323,7 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
} }
@Override @Override
public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> skuDetailsList) { public void onSkuDetailsResponse(@NonNull BillingResult billingResult, List<SkuDetails> skuDetailsList) {
logDebug("Query sku details finished."); logDebug("Query sku details finished.");
@ -442,19 +444,8 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
if (liveUpdatesPurchases.size() > 0) { if (liveUpdatesPurchases.size() > 0) {
List<String> tokensSent = Arrays.asList(settings.BILLING_PURCHASE_TOKENS_SENT.get().split(";")); List<String> tokensSent = Arrays.asList(settings.BILLING_PURCHASE_TOKENS_SENT.get().split(";"));
for (Purchase purchase : liveUpdatesPurchases) { for (Purchase purchase : liveUpdatesPurchases) {
if ((Algorithms.isEmpty(settings.BILLING_USER_ID.get()) || Algorithms.isEmpty(settings.BILLING_USER_TOKEN.get())) if (needRestoreUserInfo()) {
&& !Algorithms.isEmpty(purchase.getDeveloperPayload())) { restoreUserInfo(purchase);
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())) { if (!tokensSent.contains(purchase.getSku())) {
tokensToSend.add(purchase); tokensToSend.add(purchase);
@ -469,6 +460,37 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
} }
}; };
private void restoreUserInfo(Purchase purchase) {
boolean restored = restoreUserInfoFromString(purchase.getDeveloperPayload());
if (!restored) {
AccountIdentifiers accountIdentifiers = purchase.getAccountIdentifiers();
if (accountIdentifiers != null) {
restoreUserInfoFromString(accountIdentifiers.getObfuscatedAccountId());
}
}
}
private boolean restoreUserInfoFromString(String userInfo) {
if (Algorithms.isEmpty(userInfo)) {
return false;
}
OsmandSettings settings = ctx.getSettings();
String[] arr = userInfo.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);
}
return needRestoreUserInfo();
}
private boolean needRestoreUserInfo() {
OsmandSettings settings = ctx.getSettings();
return Algorithms.isEmpty(settings.BILLING_USER_ID.get()) || Algorithms.isEmpty(settings.BILLING_USER_TOKEN.get());
}
private PurchaseInfo getPurchaseInfo(Purchase purchase) { private PurchaseInfo getPurchaseInfo(Purchase purchase) {
return new PurchaseInfo(purchase.getSku(), purchase.getOrderId(), purchase.getPurchaseToken()); return new PurchaseInfo(purchase.getSku(), purchase.getOrderId(), purchase.getPurchaseToken());
} }
@ -511,7 +533,7 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
String introductoryPrice = skuDetails.getIntroductoryPrice(); String introductoryPrice = skuDetails.getIntroductoryPrice();
String introductoryPricePeriod = skuDetails.getIntroductoryPricePeriod(); String introductoryPricePeriod = skuDetails.getIntroductoryPricePeriod();
String introductoryPriceCycles = skuDetails.getIntroductoryPriceCycles(); int introductoryPriceCycles = skuDetails.getIntroductoryPriceCycles();
long introductoryPriceAmountMicros = skuDetails.getIntroductoryPriceAmountMicros(); long introductoryPriceAmountMicros = skuDetails.getIntroductoryPriceAmountMicros();
if (!Algorithms.isEmpty(introductoryPrice)) { if (!Algorithms.isEmpty(introductoryPrice)) {
try { try {
@ -524,7 +546,8 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
} }
} }
protected InAppCommand getPurchaseLiveUpdatesCommand(final WeakReference<Activity> activity, final String sku, final String payload) { @Override
protected InAppCommand getPurchaseLiveUpdatesCommand(final WeakReference<Activity> activity, final String sku, final String userInfo) {
return new InAppCommand() { return new InAppCommand() {
@Override @Override
public void run(InAppPurchaseHelper helper) { public void run(InAppPurchaseHelper helper) {
@ -534,7 +557,7 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
if (AndroidUtils.isActivityNotDestroyed(a) && skuDetails != null) { if (AndroidUtils.isActivityNotDestroyed(a) && skuDetails != null) {
BillingManager billingManager = getBillingManager(); BillingManager billingManager = getBillingManager();
if (billingManager != null) { if (billingManager != null) {
billingManager.setPayload(payload); billingManager.setObfuscatedAccountId(userInfo);
billingManager.initiatePurchaseFlow(a, skuDetails); billingManager.initiatePurchaseFlow(a, skuDetails);
} else { } else {
throw new IllegalStateException("BillingManager disposed"); throw new IllegalStateException("BillingManager disposed");
@ -551,6 +574,7 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
}; };
} }
@Override
protected InAppCommand getRequestInventoryCommand() { protected InAppCommand getRequestInventoryCommand() {
return new InAppCommand() { return new InAppCommand() {
@Override @Override

View file

@ -276,7 +276,7 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
} }
} }
protected InAppCommand getPurchaseLiveUpdatesCommand(final WeakReference<Activity> activity, final String sku, final String payload) { protected InAppCommand getPurchaseLiveUpdatesCommand(final WeakReference<Activity> activity, final String sku, final String userInfo) {
return new InAppCommand() { return new InAppCommand() {
@Override @Override
public void run(InAppPurchaseHelper helper) { public void run(InAppPurchaseHelper helper) {
@ -285,7 +285,7 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
ProductInfo productInfo = getProductInfo(sku); ProductInfo productInfo = getProductInfo(sku);
if (AndroidUtils.isActivityNotDestroyed(a) && productInfo != null) { if (AndroidUtils.isActivityNotDestroyed(a) && productInfo != null) {
IapRequestHelper.createPurchaseIntent(getIapClient(), sku, IapRequestHelper.createPurchaseIntent(getIapClient(), sku,
IapClient.PriceType.IN_APP_SUBSCRIPTION, payload, new IapApiCallback<PurchaseIntentResult>() { IapClient.PriceType.IN_APP_SUBSCRIPTION, userInfo, new IapApiCallback<PurchaseIntentResult>() {
@Override @Override
public void onSuccess(PurchaseIntentResult result) { public void onSuccess(PurchaseIntentResult result) {
if (result == null) { if (result == null) {

View file

@ -364,8 +364,8 @@ public abstract class InAppPurchaseHelper {
notifyDismissProgress(InAppPurchaseTaskType.PURCHASE_LIVE_UPDATES); notifyDismissProgress(InAppPurchaseTaskType.PURCHASE_LIVE_UPDATES);
if (!Algorithms.isEmpty(userId) && !Algorithms.isEmpty(token)) { if (!Algorithms.isEmpty(userId) && !Algorithms.isEmpty(token)) {
logDebug("Launching purchase flow for live updates subscription for userId=" + userId); logDebug("Launching purchase flow for live updates subscription for userId=" + userId);
final String payload = userId + " " + token; final String userInfo = userId + " " + token;
exec(InAppPurchaseTaskType.PURCHASE_LIVE_UPDATES, getPurchaseLiveUpdatesCommand(activity, sku, payload)); exec(InAppPurchaseTaskType.PURCHASE_LIVE_UPDATES, getPurchaseLiveUpdatesCommand(activity, sku, userInfo));
} else { } else {
notifyError(InAppPurchaseTaskType.PURCHASE_LIVE_UPDATES, "Empty userId"); notifyError(InAppPurchaseTaskType.PURCHASE_LIVE_UPDATES, "Empty userId");
stop(true); stop(true);
@ -374,7 +374,7 @@ public abstract class InAppPurchaseHelper {
} }
protected abstract InAppCommand getPurchaseLiveUpdatesCommand(final WeakReference<Activity> activity, protected abstract InAppCommand getPurchaseLiveUpdatesCommand(final WeakReference<Activity> activity,
final String sku, final String payload) throws UnsupportedOperationException; final String sku, final String userInfo) throws UnsupportedOperationException;
@SuppressLint("StaticFieldLeak") @SuppressLint("StaticFieldLeak")
private class RequestInventoryTask extends AsyncTask<Void, Void, String[]> { private class RequestInventoryTask extends AsyncTask<Void, Void, String[]> {

View file

@ -405,16 +405,12 @@ public abstract class InAppPurchases {
String introductoryPrice, String introductoryPrice,
long introductoryPriceAmountMicros, long introductoryPriceAmountMicros,
String introductoryPeriodString, String introductoryPeriodString,
String introductoryCycles) throws ParseException { int introductoryCycles) throws ParseException {
this.subscription = subscription; this.subscription = subscription;
this.introductoryPrice = introductoryPrice; this.introductoryPrice = introductoryPrice;
this.introductoryPriceAmountMicros = introductoryPriceAmountMicros; this.introductoryPriceAmountMicros = introductoryPriceAmountMicros;
this.introductoryPeriodString = introductoryPeriodString; this.introductoryPeriodString = introductoryPeriodString;
try { this.introductoryCycles = introductoryCycles;
this.introductoryCycles = Integer.parseInt(introductoryCycles);
} catch (NumberFormatException e) {
throw new ParseException("Cannot parse introductoryCycles = " + introductoryCycles, 0);
}
introductoryPriceValue = introductoryPriceAmountMicros / 1000000d; introductoryPriceValue = introductoryPriceAmountMicros / 1000000d;
introductoryPeriod = Period.parse(introductoryPeriodString); introductoryPeriod = Period.parse(introductoryPeriodString);
} }

View file

@ -2,9 +2,7 @@ package net.osmand.plus.inapp.util;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.billingclient.api.AcknowledgePurchaseParams; import com.android.billingclient.api.AcknowledgePurchaseParams;
import com.android.billingclient.api.AcknowledgePurchaseResponseListener; import com.android.billingclient.api.AcknowledgePurchaseResponseListener;
@ -25,7 +23,6 @@ import com.android.billingclient.api.SkuDetailsParams;
import com.android.billingclient.api.SkuDetailsResponseListener; import com.android.billingclient.api.SkuDetailsResponseListener;
import net.osmand.PlatformUtil; import net.osmand.PlatformUtil;
import net.osmand.util.Algorithms;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -33,6 +30,9 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
/** /**
* Handles all the interactions with Play Store (via Billing library), maintains connection to * Handles all the interactions with Play Store (via Billing library), maintains connection to
* it through BillingClient and caches temporary states/data if needed * it through BillingClient and caches temporary states/data if needed
@ -58,7 +58,9 @@ public class BillingManager implements PurchasesUpdatedListener {
// Public key for verifying signature, in base64 encoding // Public key for verifying signature, in base64 encoding
private String mSignatureBase64; private String mSignatureBase64;
private String mPayload;
private String mObfuscatedAccountId;
private String mObfuscatedProfileId;
private final BillingUpdatesListener mBillingUpdatesListener; private final BillingUpdatesListener mBillingUpdatesListener;
private final List<Purchase> mPurchases = new ArrayList<>(); private final List<Purchase> mPurchases = new ArrayList<>();
@ -135,18 +137,29 @@ public class BillingManager implements PurchasesUpdatedListener {
* Start a purchase flow * Start a purchase flow
*/ */
public void initiatePurchaseFlow(final Activity activity, final SkuDetails skuDetails) { public void initiatePurchaseFlow(final Activity activity, final SkuDetails skuDetails) {
initiatePurchaseFlow(activity, skuDetails, null); initiatePurchaseFlow(activity, skuDetails, null, null);
} }
/** /**
* Start a purchase or subscription replace flow * Start a purchase or subscription replace flow
*/ */
public void initiatePurchaseFlow(final Activity activity, final SkuDetails skuDetails, final String oldSku) { public void initiatePurchaseFlow(final Activity activity, final SkuDetails skuDetails, final String oldSku, final String purchaseToken) {
Runnable purchaseFlowRequest = new Runnable() { Runnable purchaseFlowRequest = new Runnable() {
@Override @Override
public void run() { public void run() {
LOG.debug("Launching in-app purchase flow. Replace old SKU? " + (oldSku != null)); LOG.debug("Launching in-app purchase flow. Replace old SKU? " + (oldSku != null && purchaseToken != null));
BillingFlowParams purchaseParams = BillingFlowParams.newBuilder().setSkuDetails(skuDetails).setOldSku(oldSku).build(); BillingFlowParams.Builder paramsBuilder = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetails);
if (!TextUtils.isEmpty(mObfuscatedAccountId)) {
paramsBuilder.setObfuscatedAccountId(mObfuscatedAccountId);
}
if (!TextUtils.isEmpty(mObfuscatedProfileId)) {
paramsBuilder.setObfuscatedProfileId(mObfuscatedProfileId);
}
if (oldSku != null && purchaseToken != null) {
paramsBuilder.setOldSku(oldSku, purchaseToken);
}
BillingFlowParams purchaseParams = paramsBuilder.build();
mBillingClient.launchBillingFlow(activity, purchaseParams); mBillingClient.launchBillingFlow(activity, purchaseParams);
} }
}; };
@ -177,9 +190,11 @@ public class BillingManager implements PurchasesUpdatedListener {
@Override @Override
public void run() { public void run() {
// Query the purchase async // Query the purchase async
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder(); SkuDetailsParams params = SkuDetailsParams.newBuilder()
params.setSkusList(skuList).setType(itemType); .setSkusList(skuList)
mBillingClient.querySkuDetailsAsync(params.build(), .setType(itemType)
.build();
mBillingClient.querySkuDetailsAsync(params,
new SkuDetailsResponseListener() { new SkuDetailsResponseListener() {
@Override @Override
public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> skuDetailsList) { public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> skuDetailsList) {
@ -247,15 +262,6 @@ public class BillingManager implements PurchasesUpdatedListener {
return Collections.unmodifiableList(mPurchases); return Collections.unmodifiableList(mPurchases);
} }
public String getPayload() {
return mPayload;
}
public void setPayload(String payload) {
this.mPayload = payload;
}
/** /**
* Handles the purchase * Handles the purchase
* <p>Note: Notice that for each purchase, we check if signature is valid on the client. * <p>Note: Notice that for each purchase, we check if signature is valid on the client.
@ -274,13 +280,9 @@ public class BillingManager implements PurchasesUpdatedListener {
if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) { if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) {
// Acknowledge the purchase if it hasn't already been acknowledged. // Acknowledge the purchase if it hasn't already been acknowledged.
if (!purchase.isAcknowledged()) { if (!purchase.isAcknowledged()) {
AcknowledgePurchaseParams.Builder builder = AcknowledgePurchaseParams acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
AcknowledgePurchaseParams.newBuilder() .setPurchaseToken(purchase.getPurchaseToken())
.setPurchaseToken(purchase.getPurchaseToken()); .build();
if (!Algorithms.isEmpty(mPayload)) {
builder.setDeveloperPayload(mPayload);
}
AcknowledgePurchaseParams acknowledgePurchaseParams = builder.build();
mBillingClient.acknowledgePurchase(acknowledgePurchaseParams, new AcknowledgePurchaseResponseListener() { mBillingClient.acknowledgePurchase(acknowledgePurchaseParams, new AcknowledgePurchaseResponseListener() {
@Override @Override
public void onAcknowledgePurchaseResponse(BillingResult billingResult) { public void onAcknowledgePurchaseResponse(BillingResult billingResult) {
@ -404,6 +406,14 @@ public class BillingManager implements PurchasesUpdatedListener {
}); });
} }
public void setObfuscatedAccountId(String obfuscatedAccountId) {
mObfuscatedAccountId = obfuscatedAccountId;
}
public void setObfuscatedProfileId(String obfuscatedProfileId) {
mObfuscatedProfileId = obfuscatedProfileId;
}
private void executeServiceRequest(Runnable runnable) { private void executeServiceRequest(Runnable runnable) {
if (mIsServiceConnected) { if (mIsServiceConnected) {
runnable.run(); runnable.run();

View file

@ -41,6 +41,8 @@ public abstract class OnlineRoutingEngine implements Cloneable {
private final Set<EngineParameter> allowedParameters = new HashSet<>(); private final Set<EngineParameter> allowedParameters = new HashSet<>();
public OnlineRoutingEngine(@Nullable Map<String, String> params) { public OnlineRoutingEngine(@Nullable Map<String, String> params) {
// Params represents the entire state of an engine object.
// An engine object with null params used only to provide information about the engine type
if (!isEmpty(params)) { if (!isEmpty(params)) {
this.params.putAll(params); this.params.putAll(params);
} }

View file

@ -310,7 +310,7 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment implements O
outState.putString(PROFILE_STRINGKEY_KEY, changedProfile.stringKey); outState.putString(PROFILE_STRINGKEY_KEY, changedProfile.stringKey);
outState.putInt(PROFILE_ICON_RES_KEY, changedProfile.iconRes); outState.putInt(PROFILE_ICON_RES_KEY, changedProfile.iconRes);
outState.putSerializable(PROFILE_COLOR_KEY, changedProfile.color); outState.putSerializable(PROFILE_COLOR_KEY, changedProfile.color);
outState.putInt(PROFILE_CUSTOM_COLOR_KEY, changedProfile.customColor); outState.putSerializable(PROFILE_CUSTOM_COLOR_KEY, changedProfile.customColor);
if (changedProfile.parent != null) { if (changedProfile.parent != null) {
outState.putString(PROFILE_PARENT_KEY, changedProfile.parent.getStringKey()); outState.putString(PROFILE_PARENT_KEY, changedProfile.parent.getStringKey());
} }
@ -325,7 +325,7 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment implements O
changedProfile.stringKey = savedInstanceState.getString(PROFILE_STRINGKEY_KEY); changedProfile.stringKey = savedInstanceState.getString(PROFILE_STRINGKEY_KEY);
changedProfile.iconRes = savedInstanceState.getInt(PROFILE_ICON_RES_KEY); changedProfile.iconRes = savedInstanceState.getInt(PROFILE_ICON_RES_KEY);
changedProfile.color = (ProfileIconColors) savedInstanceState.getSerializable(PROFILE_COLOR_KEY); changedProfile.color = (ProfileIconColors) savedInstanceState.getSerializable(PROFILE_COLOR_KEY);
changedProfile.customColor = savedInstanceState.getInt(PROFILE_CUSTOM_COLOR_KEY); changedProfile.customColor = (Integer) savedInstanceState.getSerializable(PROFILE_CUSTOM_COLOR_KEY);
String parentStringKey = savedInstanceState.getString(PROFILE_PARENT_KEY); String parentStringKey = savedInstanceState.getString(PROFILE_PARENT_KEY);
changedProfile.parent = ApplicationMode.valueOfStringKey(parentStringKey, null); changedProfile.parent = ApplicationMode.valueOfStringKey(parentStringKey, null);
isBaseProfileImported = savedInstanceState.getBoolean(IS_BASE_PROFILE_IMPORTED); isBaseProfileImported = savedInstanceState.getBoolean(IS_BASE_PROFILE_IMPORTED);

View file

@ -114,7 +114,6 @@ public class FlowLayout extends ViewGroup {
} }
private int getFreeSizeSpacing(int width, LayoutParams lp, int childWidth) { private int getFreeSizeSpacing(int width, LayoutParams lp, int childWidth) {
int freeSizeSpacing;
int itemsCount = width / (childWidth + lp.horizontalSpacing); int itemsCount = width / (childWidth + lp.horizontalSpacing);
if (itemsCount > 1 && horizontalAutoSpacing) { if (itemsCount > 1 && horizontalAutoSpacing) {
freeSizeSpacing = (width - childWidth) / (itemsCount-1); freeSizeSpacing = (width - childWidth) / (itemsCount-1);
@ -122,8 +121,9 @@ public class FlowLayout extends ViewGroup {
freeSizeSpacing = childWidth + lp.horizontalSpacing; freeSizeSpacing = childWidth + lp.horizontalSpacing;
} else { } else {
freeSizeSpacing = (width % childWidth / itemsCount); freeSizeSpacing = (width % childWidth / itemsCount);
return (width % childWidth / (itemsCount - 1)) + lp.horizontalSpacing;
} }
return freeSizeSpacing; return lp.horizontalSpacing;
} }
public static class LayoutParams extends ViewGroup.LayoutParams { public static class LayoutParams extends ViewGroup.LayoutParams {