diff --git a/.travis.yml b/.travis.yml
index 3dff1018..a8b0dc5a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -17,7 +17,7 @@ before_script:
- adb shell input keyevent 82 &
script:
- - ./gradlew connectedCheck --project-prop sonatypeUsername=none --project-prop sonatypePassword=none --project-prop sonatypeRepo=none
+ - ./gradlew connectedCheck
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
diff --git a/library/build.gradle b/library/build.gradle
index c0b6158e..2439118d 100644
--- a/library/build.gradle
+++ b/library/build.gradle
@@ -35,6 +35,7 @@ android {
dependencies {
androidTestCompile 'com.android.support.test:runner:0.5'
androidTestCompile 'com.android.support.test:rules:0.5'
+ compile 'com.android.support:support-annotations:25.3.1'
}
configurations.archives.extendsFrom configurations.default
@@ -69,8 +70,10 @@ uploadArchives {
repositories.mavenDeployer {
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
- repository(url: sonatypeRepo) {
- authentication(userName: sonatypeUsername, password: sonatypePassword)
+ if (project.hasProperty('sonatypeRepo')) {
+ repository(url: sonatypeRepo) {
+ authentication(userName: sonatypeUsername, password: sonatypePassword)
+ }
}
pom.project {
diff --git a/library/src/androidTest/java/com/anjlab/android/iab/v3/PurchaseInfoParcelableTest.java b/library/src/androidTest/java/com/anjlab/android/iab/v3/PurchaseInfoParcelableTest.java
index c0bf8bdb..43b3dd97 100644
--- a/library/src/androidTest/java/com/anjlab/android/iab/v3/PurchaseInfoParcelableTest.java
+++ b/library/src/androidTest/java/com/anjlab/android/iab/v3/PurchaseInfoParcelableTest.java
@@ -36,7 +36,7 @@ public void testParcelable() throws Exception
@Test
public void testResponseDataParcelable() throws Exception
{
- PurchaseData responseData = purchaseInfo.parseResponseData();
+ PurchaseData responseData = purchaseInfo.parseResponseDataImpl();
Parcel parcel = Parcel.obtain();
responseData.writeToParcel(parcel, 0);
diff --git a/library/src/androidTest/java/com/anjlab/android/iab/v3/TransactionDetailsParcelableTest.java b/library/src/androidTest/java/com/anjlab/android/iab/v3/TransactionDetailsParcelableTest.java
index 79b92d9e..ea1dea5a 100644
--- a/library/src/androidTest/java/com/anjlab/android/iab/v3/TransactionDetailsParcelableTest.java
+++ b/library/src/androidTest/java/com/anjlab/android/iab/v3/TransactionDetailsParcelableTest.java
@@ -24,12 +24,9 @@ public void testParcelable() throws Exception
TransactionDetails result = TransactionDetails.CREATOR.createFromParcel(parcel);
- assertEquals(details.productId, result.productId);
- assertEquals(details.orderId, result.orderId);
- assertEquals(details.purchaseToken, result.purchaseToken);
- assertEquals(details.purchaseTime, result.purchaseTime);
+ assertEquals(details.purchaseInfo, result.purchaseInfo);
- // Only check that purchase info is not null, we check it's parcel implementationin it's own tests
+ // Only check that purchase info is not null, we check its parcel implementation in its own tests
assertNotNull(result.purchaseInfo);
}
}
diff --git a/library/src/main/java/com/anjlab/android/iab/v3/BillingProcessor.java b/library/src/main/java/com/anjlab/android/iab/v3/BillingProcessor.java
index f56f0d67..7f792958 100644
--- a/library/src/main/java/com/anjlab/android/iab/v3/BillingProcessor.java
+++ b/library/src/main/java/com/anjlab/android/iab/v3/BillingProcessor.java
@@ -27,6 +27,8 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
@@ -36,6 +38,7 @@
import org.json.JSONObject;
import java.util.ArrayList;
+import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
@@ -49,17 +52,26 @@ public class BillingProcessor extends BillingBase
*/
public interface IBillingHandler
{
- void onProductPurchased(String productId, TransactionDetails details);
+ void onProductPurchased(@NonNull String productId, @Nullable TransactionDetails details);
void onPurchaseHistoryRestored();
- void onBillingError(int errorCode, Throwable error);
+ void onBillingError(int errorCode, @Nullable Throwable error);
void onBillingInitialized();
}
- private static final Date DATE_MERCHANT_LIMIT_1 = new Date(2012, 12, 5); //5th December 2012
- private static final Date DATE_MERCHANT_LIMIT_2 = new Date(2015, 7, 20); //21st July 2015
+ private static final Date DATE_MERCHANT_LIMIT_1; //5th December 2012
+ private static final Date DATE_MERCHANT_LIMIT_2; //21st July 2015
+
+ static
+ {
+ Calendar calendar = Calendar.getInstance();
+ calendar.set(2012, Calendar.DECEMBER, 5);
+ DATE_MERCHANT_LIMIT_1 = calendar.getTime();
+ calendar.set(2015, Calendar.JULY, 21);
+ DATE_MERCHANT_LIMIT_2 = calendar.getTime();
+ }
private static final int PURCHASE_FLOW_REQUEST_CODE = 32459;
private static final String LOG_TAG = "iabv3";
@@ -285,8 +297,8 @@ private boolean loadPurchasesByType(String type, BillingCache cacheStorage)
}
}
}
+ return true;
}
- return true;
}
catch (Exception e)
{
@@ -296,10 +308,13 @@ private boolean loadPurchasesByType(String type, BillingCache cacheStorage)
return false;
}
+ /**
+ * Attempt to fetch purchases from the server and update our cache if successful
+ * @return {@code true} if all retrievals are successful, {@code false} otherwise
+ */
public boolean loadOwnedPurchasesFromGoogle()
{
- return isInitialized() &&
- loadPurchasesByType(Constants.PRODUCT_TYPE_MANAGED, cachedProducts) &&
+ return loadPurchasesByType(Constants.PRODUCT_TYPE_MANAGED, cachedProducts) &&
loadPurchasesByType(Constants.PRODUCT_TYPE_SUBSCRIPTION, cachedSubscriptions);
}
@@ -328,7 +343,7 @@ public boolean subscribe(Activity activity, String productId, String developerPa
*
* @param activity the activity calling this method
* @param productId the product id to purchase
- * @param extraParamsBundle A bundle object containing extra parameters to pass to
+ * @param extraParams A bundle object containing extra parameters to pass to
* getBuyIntentExtraParams()
* @see extra
* params documentation on developer.android.com
@@ -352,7 +367,7 @@ public boolean purchase(Activity activity, String productId, String developerPay
*
* @param activity the activity calling this method
* @param productId the product id to purchase
- * @param extraParamsBundle A bundle object containing extra parameters to pass to getBuyIntentExtraParams()
+ * @param extraParams A bundle object containing extra parameters to pass to getBuyIntentExtraParams()
* @see extra
* params documentation on developer.android.com
* @return {@code false} if the billing system is not initialized, {@code productId} is empty or if an exception occurs.
@@ -612,11 +627,6 @@ private boolean purchase(Activity activity, List oldProductIds, String p
}
else // API v7+ supported
{
- if (extraParamsBundle == null)
- {
- extraParamsBundle = new Bundle();
- }
-
if (!extraParamsBundle.containsKey(Constants.EXTRA_PARAMS_KEY_SKU_TO_REPLACE))
{
extraParamsBundle.putStringArrayList(Constants.EXTRA_PARAMS_KEY_SKU_TO_REPLACE,
@@ -713,41 +723,35 @@ private boolean checkMerchant(TransactionDetails details)
{
return true;
}
- if (details.purchaseTime.before(DATE_MERCHANT_LIMIT_1)) //new format [merchantId].[orderId] applied or not?
+ if (details.purchaseInfo.purchaseData.purchaseTime.before(DATE_MERCHANT_LIMIT_1)) //newest format applied
{
return true;
}
- if (details.purchaseTime.after(DATE_MERCHANT_LIMIT_2)) //newest format applied
+ if (details.purchaseInfo.purchaseData.purchaseTime.after(DATE_MERCHANT_LIMIT_2)) //newest format applied
{
return true;
}
- if (details.orderId == null || details.orderId.trim().length() == 0)
+ if (details.purchaseInfo.purchaseData.orderId == null || details.purchaseInfo.purchaseData.orderId.trim().length() == 0)
{
return false;
}
- int index = details.orderId.indexOf('.');
+ int index = details.purchaseInfo.purchaseData.orderId.indexOf('.');
if (index <= 0)
{
return false; //protect on missing merchant id
}
//extract merchant id
- String merchantId = details.orderId.substring(0, index);
+ String merchantId = details.purchaseInfo.purchaseData.orderId.substring(0, index);
return merchantId.compareTo(developerMerchantId) == 0;
}
+ @Nullable
private TransactionDetails getPurchaseTransactionDetails(String productId, BillingCache cache)
{
PurchaseInfo details = cache.getDetails(productId);
if (details != null && !TextUtils.isEmpty(details.responseData))
{
- try
- {
- return new TransactionDetails(details);
- }
- catch (JSONException e)
- {
- Log.e(LOG_TAG, "Failed to load saved purchase details for " + productId, e);
- }
+ return new TransactionDetails(details);
}
return null;
}
@@ -865,11 +869,13 @@ public List getSubscriptionListingDetails(ArrayList productI
return getSkuDetails(productIdList, Constants.PRODUCT_TYPE_SUBSCRIPTION);
}
+ @Nullable
public TransactionDetails getPurchaseTransactionDetails(String productId)
{
return getPurchaseTransactionDetails(productId, cachedProducts);
}
+ @Nullable
public TransactionDetails getSubscriptionTransactionDetails(String productId)
{
return getPurchaseTransactionDetails(productId, cachedSubscriptions);
diff --git a/library/src/main/java/com/anjlab/android/iab/v3/PurchaseInfo.java b/library/src/main/java/com/anjlab/android/iab/v3/PurchaseInfo.java
index ef1aa04e..56a06471 100644
--- a/library/src/main/java/com/anjlab/android/iab/v3/PurchaseInfo.java
+++ b/library/src/main/java/com/anjlab/android/iab/v3/PurchaseInfo.java
@@ -44,14 +44,19 @@ public PurchaseInfo(String responseData, String signature)
{
this.responseData = responseData;
this.signature = signature;
- this.purchaseData = parseResponseData();
+ this.purchaseData = parseResponseDataImpl();
}
/**
- * @deprecated dont call it directly, use {@see purchaseData}} instead.
+ * @deprecated don't call it directly, use {@see purchaseData} instead.
*/
@Deprecated
public PurchaseData parseResponseData()
+ {
+ return parseResponseDataImpl();
+ }
+
+ PurchaseData parseResponseDataImpl()
{
try
{
@@ -92,7 +97,7 @@ protected PurchaseInfo(Parcel in)
{
this.responseData = in.readString();
this.signature = in.readString();
- this.purchaseData = parseResponseData();
+ this.purchaseData = parseResponseDataImpl();
}
public static final Parcelable.Creator CREATOR =
@@ -108,4 +113,22 @@ public PurchaseInfo[] newArray(int size)
return new PurchaseInfo[size];
}
};
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o)
+ {
+ return true;
+ }
+ if (o == null || !(o instanceof PurchaseInfo))
+ {
+ return false;
+ }
+ PurchaseInfo other = (PurchaseInfo) o;
+ return responseData.equals(other.responseData)
+ && signature.equals(other.signature)
+ && purchaseData.purchaseToken.equals(other.purchaseData.purchaseToken)
+ && purchaseData.purchaseTime.equals(other.purchaseData.purchaseTime);
+ }
}
diff --git a/library/src/main/java/com/anjlab/android/iab/v3/SkuDetails.java b/library/src/main/java/com/anjlab/android/iab/v3/SkuDetails.java
index 11c10055..5d5d1a3b 100644
--- a/library/src/main/java/com/anjlab/android/iab/v3/SkuDetails.java
+++ b/library/src/main/java/com/anjlab/android/iab/v3/SkuDetails.java
@@ -18,6 +18,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+
import org.json.JSONException;
import org.json.JSONObject;
diff --git a/library/src/main/java/com/anjlab/android/iab/v3/TransactionDetails.java b/library/src/main/java/com/anjlab/android/iab/v3/TransactionDetails.java
index 98a35a53..8287e111 100644
--- a/library/src/main/java/com/anjlab/android/iab/v3/TransactionDetails.java
+++ b/library/src/main/java/com/anjlab/android/iab/v3/TransactionDetails.java
@@ -18,8 +18,6 @@
import android.os.Parcel;
import android.os.Parcelable;
-import org.json.JSONException;
-
import java.util.Date;
import java.util.Locale;
@@ -52,7 +50,7 @@ public class TransactionDetails implements Parcelable
public final PurchaseInfo purchaseInfo;
- public TransactionDetails(PurchaseInfo info) throws JSONException
+ public TransactionDetails(PurchaseInfo info)
{
purchaseInfo = info;
productId = purchaseInfo.purchaseData.productId;
diff --git a/sample/res/drawable/ic_launcher.png b/sample/res/drawable-anydpi/ic_launcher.png
similarity index 100%
rename from sample/res/drawable/ic_launcher.png
rename to sample/res/drawable-anydpi/ic_launcher.png
diff --git a/sample/res/values/strings.xml b/sample/res/values/strings.xml
index 5d084e81..a15dd893 100644
--- a/sample/res/values/strings.xml
+++ b/sample/res/values/strings.xml
@@ -2,7 +2,7 @@
In-app Billing v3 Sample
- wait...
+ wait…
Sample Activity #%d
diff --git a/sample/src/com/anjlab/android/iab/v3/sample2/MainActivity.java b/sample/src/com/anjlab/android/iab/v3/sample2/MainActivity.java
index 36ca2127..2054627a 100644
--- a/sample/src/com/anjlab/android/iab/v3/sample2/MainActivity.java
+++ b/sample/src/com/anjlab/android/iab/v3/sample2/MainActivity.java
@@ -18,6 +18,8 @@
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
@@ -58,12 +60,12 @@ protected void onCreate(Bundle savedInstanceState) {
bp = new BillingProcessor(this, LICENSE_KEY, MERCHANT_ID, new BillingProcessor.IBillingHandler() {
@Override
- public void onProductPurchased(String productId, TransactionDetails details) {
+ public void onProductPurchased(@NonNull String productId, @Nullable TransactionDetails details) {
showToast("onProductPurchased: " + productId);
updateTextViews();
}
@Override
- public void onBillingError(int errorCode, Throwable error) {
+ public void onBillingError(int errorCode, @Nullable Throwable error) {
showToast("onBillingError: " + Integer.toString(errorCode));
}
@Override