From 2341d26298942aea56ca910ef5fbb6700638b4f9 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Sun, 10 Apr 2016 22:30:59 +0200 Subject: [PATCH 01/22] Use our logger in IabHelper --- .../android/ui/plans/util/IabHelper.java | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/util/IabHelper.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/util/IabHelper.java index 86bff92d00f8..530b2b689744 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/util/IabHelper.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/util/IabHelper.java @@ -32,6 +32,7 @@ import com.android.vending.billing.IInAppBillingService; import org.json.JSONException; +import org.wordpress.android.util.AppLog; import java.util.ArrayList; import java.util.List; @@ -68,9 +69,6 @@ * */ public class IabHelper { - // Is debug logging enabled? - boolean mDebugLog = false; - String mDebugTag = "IabHelper"; // Is setup done? boolean mSetupDone = false; @@ -169,18 +167,8 @@ public IabHelper(Context ctx, String base64PublicKey) { logDebug("IAB helper created."); } - /** - * Enables or disable debug logging through LogCat. - */ - public void enableDebugLogging(boolean enable, String tag) { - checkNotDisposed(); - mDebugLog = enable; - mDebugTag = tag; - } - public void enableDebugLogging(boolean enable) { checkNotDisposed(); - mDebugLog = enable; } /** @@ -1037,14 +1025,14 @@ public void run() { } void logDebug(String msg) { - if (mDebugLog) Log.d(mDebugTag, msg); + AppLog.d(AppLog.T.PLANS, msg); } void logError(String msg) { - Log.e(mDebugTag, "In-app billing error: " + msg); + AppLog.d(AppLog.T.PLANS, "In-app billing error: " + msg); } void logWarn(String msg) { - Log.w(mDebugTag, "In-app billing warning: " + msg); + AppLog.w(AppLog.T.PLANS, "In-app billing warning: " + msg); } } From 9cda45df745e759a1c4aedbc0a91535a0d4a4277 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Sun, 10 Apr 2016 22:31:17 +0200 Subject: [PATCH 02/22] Start integrating the store calls --- .../ui/plans/PlanPostPurchaseActivity.java | 2 + .../android/ui/plans/PlansActivity.java | 87 ++++++++++++++++--- 2 files changed, 77 insertions(+), 12 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlanPostPurchaseActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlanPostPurchaseActivity.java index 0264d113286f..a59357e151a4 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlanPostPurchaseActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlanPostPurchaseActivity.java @@ -37,6 +37,8 @@ public class PlanPostPurchaseActivity extends AppCompatActivity { static final int PAGE_NUMBER_THEMES = 3; // business only static final String ARG_IS_BUSINESS_PLAN = "is_business_plan"; + public static final String ARG_LOCAL_TABLE_BLOG_ID = "ARG_LOCAL_TABLE_BLOG_ID"; + public static final String ARG_PURCHASE_SKU = "ARG_PURCHASE_SKU"; private ViewPager mViewPager; private PageAdapter mPageAdapter; diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java index 40bdd43c167f..ffb35a187336 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java @@ -21,13 +21,20 @@ import android.widget.TextView; import android.widget.Toast; +import org.json.JSONException; +import org.json.JSONObject; import org.wordpress.android.BuildConfig; import org.wordpress.android.R; import org.wordpress.android.WordPress; +import org.wordpress.android.models.AccountHelper; +import org.wordpress.android.models.Blog; import org.wordpress.android.ui.plans.adapters.PlansPagerAdapter; import org.wordpress.android.ui.plans.models.Plan; +import org.wordpress.android.ui.plans.util.IabException; import org.wordpress.android.ui.plans.util.IabHelper; import org.wordpress.android.ui.plans.util.IabResult; +import org.wordpress.android.ui.plans.util.Inventory; +import org.wordpress.android.ui.plans.util.Purchase; import org.wordpress.android.ui.prefs.AppPrefs; import org.wordpress.android.util.AniUtils; import org.wordpress.android.util.AppLog; @@ -35,6 +42,7 @@ import org.wordpress.android.widgets.WPViewPager; import java.io.Serializable; +import java.util.ArrayList; import java.util.List; import de.greenrobot.event.EventBus; @@ -43,6 +51,7 @@ public class PlansActivity extends AppCompatActivity { public static final String ARG_LOCAL_TABLE_BLOG_ID = "ARG_LOCAL_TABLE_BLOG_ID"; private static final String ARG_LOCAL_AVAILABLE_PLANS = "ARG_LOCAL_AVAILABLE_PLANS"; + private static final int PURCHASE_PLAN_REQUEST = 0; private int mLocalBlogID = -1; private Plan[] mAvailablePlans; @@ -136,7 +145,7 @@ public void onPause() { } private void updatePurchaseUI(int position) { - Plan plan = getPageAdapter().getPlan(position); + final Plan plan = getPageAdapter().getPlan(position); boolean showPurchaseButton; if (plan.isCurrentPlan()) { showPurchaseButton = false; @@ -155,7 +164,7 @@ private void updatePurchaseUI(int position) { containerPurchase.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - startPurchaseProcess(); + startPurchaseProcess(plan); } }); } else { @@ -170,7 +179,7 @@ public void onClick(View v) { } private void setupPlansUI() { - if (mAvailablePlans == null || mAvailablePlans.length == 0) { + if (mAvailablePlans == null || mAvailablePlans.length == 0) { // This should never be called with empty plans. Toast.makeText(PlansActivity.this, R.string.plans_loading_error, Toast.LENGTH_LONG).show(); finish(); @@ -301,14 +310,69 @@ public boolean onOptionsItemSelected(MenuItem item) { return super.onOptionsItemSelected(item); } - private void startPurchaseProcess() { - // TODO: this should start the Google Play purchase process, for now it shows the - // post-purchase on-boarding + private void listPurchaseForTesting () { + ArrayList skuList = new ArrayList (); + skuList.add("test_plan_premium_001"); + skuList.add("danilo_test_plan_premium_sub_001"); + try { + Inventory inventory = mIabHelper.queryInventory(true, skuList, skuList); + for (String sku: skuList) { + if ( inventory.hasPurchase(sku) ) { + Purchase pur = inventory.getPurchase(sku); + AppLog.d(AppLog.T.PLANS, "Original purchase JSON " + pur.getOriginalJson()); + } + } + } catch (IabException e) { + AppLog.e(AppLog.T.PLANS, "Unable to load IAP details", e); + } + } + + private void startPurchaseProcess(Plan plan) { + //listPurchaseForTesting(); + + // TODO: remove when updated the rest api boolean isBusinessPlan = (mViewPager.getCurrentItem() == mViewPager.getAdapter().getCount() - 1); - Intent intent = new Intent(this, PlanPostPurchaseActivity.class); - intent.putExtra(PlanPostPurchaseActivity.ARG_IS_BUSINESS_PLAN, isBusinessPlan); - startActivity(intent); - finish(); + String sku = isBusinessPlan ? "sub_test_plan_business_001" : "sub_test_plan_premium_001"; + + Blog currentBlog = WordPress.getBlog(mLocalBlogID); + JSONObject extraData = new JSONObject(); + try { + extraData.put("blog_id", currentBlog.getDotComBlogId()); + extraData.put("user_id", AccountHelper.getDefaultAccount().getUserId()); + } catch (JSONException e) { + AppLog.e(AppLog.T.PLANS, "Can't add extra info to purchase data!", e); + } + + mIabHelper.launchSubscriptionPurchaseFlow(this, sku, PURCHASE_PLAN_REQUEST, + new IabHelper.OnIabPurchaseFinishedListener() { + public void onIabPurchaseFinished(IabResult result, Purchase info) { + if (result != null) { + AppLog.d(AppLog.T.PLANS, "IabResult: " + result.toString()); + if (result.isSuccess()) { + if (info != null) { + AppLog.d(AppLog.T.PLANS, "Purchase: " + info.toString()); + AppLog.d(AppLog.T.PLANS, "You have bought the " + info.getSku() + ". Excellent choice, adventurer!"); + boolean isBusinessPlan = (mViewPager.getCurrentItem() == mViewPager.getAdapter().getCount() - 1); + Intent intent = new Intent(PlansActivity.this, PlanPostPurchaseActivity.class); + intent.putExtra(PlanPostPurchaseActivity.ARG_IS_BUSINESS_PLAN, isBusinessPlan); + intent.putExtra(PlanPostPurchaseActivity.ARG_LOCAL_TABLE_BLOG_ID, mLocalBlogID); + intent.putExtra(PlanPostPurchaseActivity.ARG_PURCHASE_SKU, info.getSku()); + startActivity(intent); + } + } else { + // not a success. It seems that the buy activity already shows an error. + // or at least, it shows an error if you try to purchase a subscription you already own. + } + } + } + }, + extraData.toString()); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + boolean handled = mIabHelper.handleActivityResult(requestCode, resultCode, data); } /* @@ -319,8 +383,7 @@ private void startPurchaseProcess() { private void startInAppBillingHelper() { mIabHelper = new IabHelper(this, BuildConfig.APP_LICENSE_KEY); if (BuildConfig.DEBUG) { - String tag = AppLog.TAG + "-" + AppLog.T.PLANS.toString(); - mIabHelper.enableDebugLogging(true, tag); + mIabHelper.enableDebugLogging(true); } try { mIabHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() { From db846cf42c725bb99ef0a3c7f282035c55eabc41 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Mon, 11 Apr 2016 17:50:20 +0200 Subject: [PATCH 03/22] Re-synch purchases with wpcom server on startup and periodically. (The user could have cancelled them on the PlayStore). Re-synch purchases when the user buys a subscription from the store. --- .../java/org/wordpress/android/WordPress.java | 18 +++ .../ui/plans/PlanPostPurchaseActivity.java | 2 - .../android/ui/plans/PlansActivity.java | 27 +--- .../android/ui/plans/UpdateIAPTask.java | 133 ++++++++++++++++++ .../android/ui/plans/util/Inventory.java | 6 +- 5 files changed, 159 insertions(+), 27 deletions(-) create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java diff --git a/WordPress/src/main/java/org/wordpress/android/WordPress.java b/WordPress/src/main/java/org/wordpress/android/WordPress.java index 41fc5c1b98c3..47ff742a0f08 100644 --- a/WordPress/src/main/java/org/wordpress/android/WordPress.java +++ b/WordPress/src/main/java/org/wordpress/android/WordPress.java @@ -49,6 +49,8 @@ import org.wordpress.android.ui.accounts.helpers.UpdateBlogListTask.GenericUpdateBlogListTask; import org.wordpress.android.ui.notifications.utils.NotificationsUtils; import org.wordpress.android.ui.notifications.utils.SimperiumUtils; +import org.wordpress.android.ui.plans.PlansUtils; +import org.wordpress.android.ui.plans.UpdateIAPTask; import org.wordpress.android.ui.prefs.AppPrefs; import org.wordpress.android.ui.stats.StatsWidgetProvider; import org.wordpress.android.ui.stats.datasets.StatsDatabaseHelper; @@ -101,6 +103,7 @@ public class WordPress extends Application { private static final int SECONDS_BETWEEN_OPTIONS_UPDATE = 10 * 60; private static final int SECONDS_BETWEEN_BLOGLIST_UPDATE = 6 * 60 * 60; + private static final int SECONDS_BETWEEN_IAP_UPDATE = 5 * 60; private static final int SECONDS_BETWEEN_DELETE_STATS = 5 * 60; // 5 minutes private static Context mContext; @@ -134,6 +137,20 @@ protected boolean run() { } }; + /** + * Update IAPs. This need to be called to remove upgrades on wpcom side, those upgrades the user has already cancelled on mobile side + * (from the Google Store). + * + */ + public static RateLimitedTask sUpdateWordPressComIAP = new RateLimitedTask(SECONDS_BETWEEN_IAP_UPDATE) { + protected boolean run() { + if (AccountHelper.isSignedInWordPressDotCom()) { + new UpdateIAPTask(getContext()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + return true; + } + }; + /** * Delete stats cache that is already expired */ @@ -803,6 +820,7 @@ public void onAppComesFromBackground() { sUpdateCurrentBlogOption.runIfNotLimited(); } sDeleteExpiredStats.runIfNotLimited(); + sUpdateWordPressComIAP.forceRun(); // TODO: changes to run if not limited } @Override diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlanPostPurchaseActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlanPostPurchaseActivity.java index a59357e151a4..0264d113286f 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlanPostPurchaseActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlanPostPurchaseActivity.java @@ -37,8 +37,6 @@ public class PlanPostPurchaseActivity extends AppCompatActivity { static final int PAGE_NUMBER_THEMES = 3; // business only static final String ARG_IS_BUSINESS_PLAN = "is_business_plan"; - public static final String ARG_LOCAL_TABLE_BLOG_ID = "ARG_LOCAL_TABLE_BLOG_ID"; - public static final String ARG_PURCHASE_SKU = "ARG_PURCHASE_SKU"; private ViewPager mViewPager; private PageAdapter mPageAdapter; diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java index ffb35a187336..888bb5142c89 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java @@ -310,25 +310,7 @@ public boolean onOptionsItemSelected(MenuItem item) { return super.onOptionsItemSelected(item); } - private void listPurchaseForTesting () { - ArrayList skuList = new ArrayList (); - skuList.add("test_plan_premium_001"); - skuList.add("danilo_test_plan_premium_sub_001"); - try { - Inventory inventory = mIabHelper.queryInventory(true, skuList, skuList); - for (String sku: skuList) { - if ( inventory.hasPurchase(sku) ) { - Purchase pur = inventory.getPurchase(sku); - AppLog.d(AppLog.T.PLANS, "Original purchase JSON " + pur.getOriginalJson()); - } - } - } catch (IabException e) { - AppLog.e(AppLog.T.PLANS, "Unable to load IAP details", e); - } - } - private void startPurchaseProcess(Plan plan) { - //listPurchaseForTesting(); // TODO: remove when updated the rest api boolean isBusinessPlan = (mViewPager.getCurrentItem() == mViewPager.getAdapter().getCount() - 1); @@ -341,6 +323,7 @@ private void startPurchaseProcess(Plan plan) { extraData.put("user_id", AccountHelper.getDefaultAccount().getUserId()); } catch (JSONException e) { AppLog.e(AppLog.T.PLANS, "Can't add extra info to purchase data!", e); + return; } mIabHelper.launchSubscriptionPurchaseFlow(this, sku, PURCHASE_PLAN_REQUEST, @@ -350,18 +333,18 @@ public void onIabPurchaseFinished(IabResult result, Purchase info) { AppLog.d(AppLog.T.PLANS, "IabResult: " + result.toString()); if (result.isSuccess()) { if (info != null) { + WordPress.sUpdateWordPressComIAP.forceRun(); // refresh purchase on wpcom AppLog.d(AppLog.T.PLANS, "Purchase: " + info.toString()); AppLog.d(AppLog.T.PLANS, "You have bought the " + info.getSku() + ". Excellent choice, adventurer!"); boolean isBusinessPlan = (mViewPager.getCurrentItem() == mViewPager.getAdapter().getCount() - 1); Intent intent = new Intent(PlansActivity.this, PlanPostPurchaseActivity.class); intent.putExtra(PlanPostPurchaseActivity.ARG_IS_BUSINESS_PLAN, isBusinessPlan); - intent.putExtra(PlanPostPurchaseActivity.ARG_LOCAL_TABLE_BLOG_ID, mLocalBlogID); - intent.putExtra(PlanPostPurchaseActivity.ARG_PURCHASE_SKU, info.getSku()); startActivity(intent); } } else { - // not a success. It seems that the buy activity already shows an error. - // or at least, it shows an error if you try to purchase a subscription you already own. + AppLog.e(AppLog.T.PLANS, "Purchase failure " + result.getMessage()); + // Not a success. It seems that the buy activity already shows an error. + // Or at least, it shows an error if you try to purchase a subscription you already own. } } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java new file mode 100644 index 000000000000..e0a7ec1f3c88 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java @@ -0,0 +1,133 @@ +package org.wordpress.android.ui.plans; + +import android.content.Context; +import android.os.AsyncTask; + +import com.android.volley.VolleyError; +import com.wordpress.rest.RestRequest; + +import org.json.JSONException; +import org.json.JSONObject; +import org.wordpress.android.BuildConfig; +import org.wordpress.android.WordPress; +import org.wordpress.android.models.AccountHelper; +import org.wordpress.android.ui.plans.util.IabException; +import org.wordpress.android.ui.plans.util.IabHelper; +import org.wordpress.android.ui.plans.util.IabResult; +import org.wordpress.android.ui.plans.util.Inventory; +import org.wordpress.android.ui.plans.util.Purchase; +import org.wordpress.android.util.AppLog; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class UpdateIAPTask extends AsyncTask { + private static final int GET_IAP_BINDER_TIMEOUT = 30000; + private static final String IAP_ENDPOINT = "/iap/refresh"; + protected Context mContext; + private IabHelper mIabHelper; + + public UpdateIAPTask(Context context) { + mContext = context; + } + + @Override + protected Void doInBackground(Void... args) { + if (!AccountHelper.isSignedInWordPressDotCom()) { + return null; + } + + final CountDownLatch countDownLatch = new CountDownLatch(1); + + mIabHelper = new IabHelper(this.mContext, BuildConfig.APP_LICENSE_KEY); + if (BuildConfig.DEBUG) { + mIabHelper.enableDebugLogging(true); + } + try { + mIabHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() { + @Override + public void onIabSetupFinished(IabResult result) { + if (result.isSuccess()) { + AppLog.d(AppLog.T.PLANS, "IAB started successfully"); + } else { + AppLog.w(AppLog.T.PLANS, "IAB failed with " + result); + } + countDownLatch.countDown(); + } + }); + try { + countDownLatch.await(GET_IAP_BINDER_TIMEOUT, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + AppLog.e(AppLog.T.PLANS, "IAP setup took too long! > " + GET_IAP_BINDER_TIMEOUT + " msecs!", e); + return null; + } + } catch (NullPointerException e) { + // will happen when play store isn't available on device + //AppLog.e(AppLog.T.PLANS, e); + AppLog.w(AppLog.T.PLANS, "Unable to start IAB helper. Happen when Play Store isn't available on device."); + return null; + } + + listIAPs(); + stopInAppBillingHelper(); + return null; + } + + private void listIAPs() { + if (mIabHelper == null) { + return; + } + try { + Inventory inventory = mIabHelper.queryInventory(true, null, null); + List iaps = inventory.getAllPurchases(); + for (Purchase purchase : iaps) { + AppLog.d(AppLog.T.PLANS, "Original purchase JSON " + purchase.getOriginalJson()); + try { + JSONObject developerPayload = new JSONObject(purchase.getDeveloperPayload()); + Map params = new HashMap<>(); + params.put("blog_id", developerPayload.getString("blog_id")); + params.put("iap_sku", purchase.getSku()); + params.put("iap_token", purchase.getToken()); + params.put("iap_package_name", purchase.getPackageName()); + params.put("client_id", BuildConfig.OAUTH_APP_ID); + params.put("client_secret", BuildConfig.OAUTH_APP_SECRET); + WordPress.getRestClientUtilsV1_1().post(IAP_ENDPOINT, params, null, + new RestRequest.Listener() { + @Override + public void onResponse(JSONObject response) { + if (response != null) { + AppLog.d(AppLog.T.PLANS, "Response from the server: " + response.toString()); + } + } + }, + new RestRequest.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + AppLog.e(AppLog.T.PLANS, "Response from the server", error); + } + }); + } catch (JSONException e) { + AppLog.e(AppLog.T.PLANS, "Unable to parse IAP info - " + purchase.getOriginalJson(), e); + } + } + } catch (IabException e) { + AppLog.e(AppLog.T.PLANS, "Unable to refresh the inventory", e); + } + } + + private void stopInAppBillingHelper() { + if (mIabHelper != null) { + try { + mIabHelper.dispose(); + } catch (IllegalArgumentException e) { + // this can happen if the IAB helper was created but failed to bind to its service + // when started, which will occur on emulators + AppLog.w(AppLog.T.PLANS, "Unable to dispose IAB helper"); + } + mIabHelper = null; + } + } +} diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/util/Inventory.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/util/Inventory.java index b4508beecb99..9c8467e984f2 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/util/Inventory.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/util/Inventory.java @@ -63,12 +63,12 @@ public void erasePurchase(String sku) { } /** Returns a list of all owned product IDs. */ - List getAllOwnedSkus() { + public List getAllOwnedSkus() { return new ArrayList(mPurchaseMap.keySet()); } /** Returns a list of all owned product IDs of a given type */ - List getAllOwnedSkus(String itemType) { + public List getAllOwnedSkus(String itemType) { List result = new ArrayList(); for (Purchase p : mPurchaseMap.values()) { if (p.getItemType().equals(itemType)) result.add(p.getSku()); @@ -77,7 +77,7 @@ List getAllOwnedSkus(String itemType) { } /** Returns a list of all purchases. */ - List getAllPurchases() { + public List getAllPurchases() { return new ArrayList(mPurchaseMap.values()); } From 443d963254dec78249b53749d052411316c0e96d Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Mon, 11 Apr 2016 18:08:40 +0200 Subject: [PATCH 04/22] Remove unused imports. Add comments. --- .../src/main/java/org/wordpress/android/WordPress.java | 9 ++++----- .../org/wordpress/android/ui/plans/PlansActivity.java | 5 +---- .../org/wordpress/android/ui/plans/UpdateIAPTask.java | 4 ++++ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/WordPress.java b/WordPress/src/main/java/org/wordpress/android/WordPress.java index 47ff742a0f08..3618922d2404 100644 --- a/WordPress/src/main/java/org/wordpress/android/WordPress.java +++ b/WordPress/src/main/java/org/wordpress/android/WordPress.java @@ -49,7 +49,6 @@ import org.wordpress.android.ui.accounts.helpers.UpdateBlogListTask.GenericUpdateBlogListTask; import org.wordpress.android.ui.notifications.utils.NotificationsUtils; import org.wordpress.android.ui.notifications.utils.SimperiumUtils; -import org.wordpress.android.ui.plans.PlansUtils; import org.wordpress.android.ui.plans.UpdateIAPTask; import org.wordpress.android.ui.prefs.AppPrefs; import org.wordpress.android.ui.stats.StatsWidgetProvider; @@ -138,11 +137,11 @@ protected boolean run() { }; /** - * Update IAPs. This need to be called to remove upgrades on wpcom side, those upgrades the user has already cancelled on mobile side - * (from the Google Store). + * Synch IAPs with wpcom backend. This need to be called to add/remove upgrades on wpcom side. + * Those upgrades the user has already bought/cancelled on mobile side (from the Google Store). * */ - public static RateLimitedTask sUpdateWordPressComIAP = new RateLimitedTask(SECONDS_BETWEEN_IAP_UPDATE) { + public static RateLimitedTask sUpdateIAPsWordPressCom = new RateLimitedTask(SECONDS_BETWEEN_IAP_UPDATE) { protected boolean run() { if (AccountHelper.isSignedInWordPressDotCom()) { new UpdateIAPTask(getContext()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); @@ -820,7 +819,7 @@ public void onAppComesFromBackground() { sUpdateCurrentBlogOption.runIfNotLimited(); } sDeleteExpiredStats.runIfNotLimited(); - sUpdateWordPressComIAP.forceRun(); // TODO: changes to run if not limited + sUpdateIAPsWordPressCom.forceRun(); // TODO: changes to run if not limited } @Override diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java index 888bb5142c89..8028c53883b6 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java @@ -30,10 +30,8 @@ import org.wordpress.android.models.Blog; import org.wordpress.android.ui.plans.adapters.PlansPagerAdapter; import org.wordpress.android.ui.plans.models.Plan; -import org.wordpress.android.ui.plans.util.IabException; import org.wordpress.android.ui.plans.util.IabHelper; import org.wordpress.android.ui.plans.util.IabResult; -import org.wordpress.android.ui.plans.util.Inventory; import org.wordpress.android.ui.plans.util.Purchase; import org.wordpress.android.ui.prefs.AppPrefs; import org.wordpress.android.util.AniUtils; @@ -42,7 +40,6 @@ import org.wordpress.android.widgets.WPViewPager; import java.io.Serializable; -import java.util.ArrayList; import java.util.List; import de.greenrobot.event.EventBus; @@ -333,7 +330,7 @@ public void onIabPurchaseFinished(IabResult result, Purchase info) { AppLog.d(AppLog.T.PLANS, "IabResult: " + result.toString()); if (result.isSuccess()) { if (info != null) { - WordPress.sUpdateWordPressComIAP.forceRun(); // refresh purchase on wpcom + WordPress.sUpdateIAPsWordPressCom.forceRun(); // refresh purchase on wpcom AppLog.d(AppLog.T.PLANS, "Purchase: " + info.toString()); AppLog.d(AppLog.T.PLANS, "You have bought the " + info.getSku() + ". Excellent choice, adventurer!"); boolean isBusinessPlan = (mViewPager.getCurrentItem() == mViewPager.getAdapter().getCount() - 1); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java index e0a7ec1f3c88..5abe819afe1a 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java @@ -24,6 +24,10 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +/** + * Synch IAPs on the wpcom backend. This need to be called to add/remove upgrades on wpcom side. + * + */ public class UpdateIAPTask extends AsyncTask { private static final int GET_IAP_BINDER_TIMEOUT = 30000; private static final String IAP_ENDPOINT = "/iap/refresh"; From 8f553c9845d0ac872f2fc82d8afb383a7a74c9b0 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Tue, 12 Apr 2016 15:18:35 +0200 Subject: [PATCH 05/22] Remove custom hardcoded SKUs since REST Endpoint has been updated. --- .../java/org/wordpress/android/ui/plans/PlansActivity.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java index 8028c53883b6..c83221de17f0 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java @@ -308,11 +308,7 @@ public boolean onOptionsItemSelected(MenuItem item) { } private void startPurchaseProcess(Plan plan) { - - // TODO: remove when updated the rest api - boolean isBusinessPlan = (mViewPager.getCurrentItem() == mViewPager.getAdapter().getCount() - 1); - String sku = isBusinessPlan ? "sub_test_plan_business_001" : "sub_test_plan_premium_001"; - + String sku = plan.getAndroidSKU(); Blog currentBlog = WordPress.getBlog(mLocalBlogID); JSONObject extraData = new JSONObject(); try { From 2b9d5a6dcae412812047cbb9cec01c78dfc23cee Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Tue, 12 Apr 2016 16:00:26 +0200 Subject: [PATCH 06/22] Fix log message --- .../main/java/org/wordpress/android/ui/plans/PlansActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java index c83221de17f0..38aa8cd3e40b 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java @@ -335,7 +335,7 @@ public void onIabPurchaseFinished(IabResult result, Purchase info) { startActivity(intent); } } else { - AppLog.e(AppLog.T.PLANS, "Purchase failure " + result.getMessage()); + AppLog.e(AppLog.T.PLANS, "Purchase failure: " + result.getMessage()); // Not a success. It seems that the buy activity already shows an error. // Or at least, it shows an error if you try to purchase a subscription you already own. } From 691e6a801e0c540ab31ad3d225d9d2786cf92097 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Fri, 29 Apr 2016 15:16:03 +0200 Subject: [PATCH 07/22] Use the new endpoint name, and remove unused parameters. --- .../java/org/wordpress/android/ui/plans/UpdateIAPTask.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java index 5abe819afe1a..98ecf383a4f7 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java @@ -30,7 +30,7 @@ */ public class UpdateIAPTask extends AsyncTask { private static final int GET_IAP_BINDER_TIMEOUT = 30000; - private static final String IAP_ENDPOINT = "/iap/refresh"; + private static final String IAP_ENDPOINT = "/iap/validate"; protected Context mContext; private IabHelper mIabHelper; @@ -95,9 +95,6 @@ private void listIAPs() { params.put("blog_id", developerPayload.getString("blog_id")); params.put("iap_sku", purchase.getSku()); params.put("iap_token", purchase.getToken()); - params.put("iap_package_name", purchase.getPackageName()); - params.put("client_id", BuildConfig.OAUTH_APP_ID); - params.put("client_secret", BuildConfig.OAUTH_APP_SECRET); WordPress.getRestClientUtilsV1_1().post(IAP_ENDPOINT, params, null, new RestRequest.Listener() { @Override From 569e2b0e61ab32186509890de14182b1f1c6f98c Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Tue, 3 May 2016 16:41:26 +0200 Subject: [PATCH 08/22] Change the label to "upgrade" when the selected blog already has a plan subscription, and redirect the user to support. We're not going to enable upgrades whitin the apps. --- .../java/org/wordpress/android/WordPress.java | 4 +- .../android/ui/plans/PlansActivity.java | 82 ++++++++++++++++--- .../android/ui/plans/PlansUtils.java | 18 ++++ .../src/main/res/layout/plans_activity.xml | 1 + WordPress/src/main/res/values/strings.xml | 3 + 5 files changed, 95 insertions(+), 13 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/WordPress.java b/WordPress/src/main/java/org/wordpress/android/WordPress.java index 0bbb8c682342..bb7083fa7955 100644 --- a/WordPress/src/main/java/org/wordpress/android/WordPress.java +++ b/WordPress/src/main/java/org/wordpress/android/WordPress.java @@ -102,7 +102,7 @@ public class WordPress extends Application { private static final int SECONDS_BETWEEN_OPTIONS_UPDATE = 10 * 60; private static final int SECONDS_BETWEEN_BLOGLIST_UPDATE = 6 * 60 * 60; - private static final int SECONDS_BETWEEN_IAP_UPDATE = 5 * 60; + private static final int SECONDS_BETWEEN_IAP_UPDATE = 5 * 60; // 5 minutes private static final int SECONDS_BETWEEN_DELETE_STATS = 5 * 60; // 5 minutes private static Context mContext; @@ -829,7 +829,7 @@ public void onAppComesFromBackground() { sUpdateCurrentBlogOption.runIfNotLimited(); } sDeleteExpiredStats.runIfNotLimited(); - sUpdateIAPsWordPressCom.forceRun(); // TODO: changes to run if not limited + sUpdateIAPsWordPressCom.runIfNotLimited(); } @Override diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java index 38aa8cd3e40b..e8703f65a5e9 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java @@ -2,6 +2,8 @@ import android.animation.Animator; import android.annotation.TargetApi; +import android.app.AlertDialog; +import android.content.DialogInterface; import android.content.Intent; import android.graphics.Point; import android.os.Build; @@ -37,6 +39,7 @@ import org.wordpress.android.util.AniUtils; import org.wordpress.android.util.AppLog; import org.wordpress.android.util.DisplayUtils; +import org.wordpress.android.util.HelpshiftHelper; import org.wordpress.android.widgets.WPViewPager; import java.io.Serializable; @@ -141,27 +144,62 @@ public void onPause() { EventBus.getDefault().unregister(this); } - private void updatePurchaseUI(int position) { + /** + * The 'Buy' button should be available if the current plan is free, and the selected plan upgrade is available. + * @param position + * @return boolean - true if the current plan could be added to the blog. + */ + private boolean isBuyButtonAvailable(int position) { + long currentPlanProductId = WordPress.wpDB.getPlanIdForLocalTableBlogId(mLocalBlogID); + if (!PlansUtils.isFreePlan(currentPlanProductId)) { + return false; + } final Plan plan = getPageAdapter().getPlan(position); - boolean showPurchaseButton; - if (plan.isCurrentPlan()) { - showPurchaseButton = false; - } else { - // don't show the purchase button unless the plan at this position is "greater" than - // the current plan for this site - long currentPlanProductId = WordPress.wpDB.getPlanIdForLocalTableBlogId(mLocalBlogID); - showPurchaseButton = plan.isAvailable() && plan.getProductID() > currentPlanProductId; + return plan.isAvailable() && !plan.isCurrentPlan(); + } + + /** + * The 'Upgrade' button should be available if the current plan is NOT free, + * and the selected plan upgrade is available, and the current plan ID < new plan ID. + * @param position + * @return boolean - true if the current plan could be upgraded to the blog. + */ + private boolean isUpgradeButtonAvailable(int position) { + long currentPlanProductId = WordPress.wpDB.getPlanIdForLocalTableBlogId(mLocalBlogID); + if (isBuyButtonAvailable(position) || PlansUtils.isFreePlan(currentPlanProductId)) { + return false; } + final Plan plan = getPageAdapter().getPlan(position); + + // No downgrade! + if (PlansUtils.isFreePlan(plan) || currentPlanProductId > plan.getProductID()) { + return false; + } + + return plan.isAvailable() && !plan.isCurrentPlan(); + } + + private void updatePurchaseUI(final int position) { + final Plan plan = getPageAdapter().getPlan(position); + boolean showPurchaseButton = isBuyButtonAvailable(position) || isUpgradeButtonAvailable(position); + ViewGroup framePurchase = (ViewGroup) findViewById(R.id.frame_purchase); ViewGroup containerPurchase = (ViewGroup) findViewById(R.id.purchase_container); if (showPurchaseButton) { TextView txtPurchasePrice = (TextView) framePurchase.findViewById(R.id.text_purchase_price); txtPurchasePrice.setText(PlansUtils.getPlanDisplayPrice(plan)); + + TextView txtPurchaseLabel = (TextView) framePurchase.findViewById(R.id.text_purchase_label); + if (isBuyButtonAvailable(position)) { + txtPurchaseLabel.setText(getString(R.string.plan_purchase_now)); + } else if (isUpgradeButtonAvailable(position)) { + txtPurchaseLabel.setText(getString(R.string.plan_upgrade_now)); + } containerPurchase.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - startPurchaseProcess(plan); + startPurchaseProcess(position); } }); } else { @@ -307,7 +345,29 @@ public boolean onOptionsItemSelected(MenuItem item) { return super.onOptionsItemSelected(item); } - private void startPurchaseProcess(Plan plan) { + private void startPurchaseProcess(int position) { + final Plan plan = getPageAdapter().getPlan(position); + + // if it's an upgrade show the message and return. We don't handle upgrades in app. + if (isUpgradeButtonAvailable(position)) { + String upgradeText = getString(R.string.plan_upgrade_contact_support_text, plan.getProductName()); + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(upgradeText) + .setTitle(getString(R.string.plan_upgrade_not_available)); + builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + HelpshiftHelper.getInstance().showConversation(PlansActivity.this, HelpshiftHelper.Tag.ORIGIN_UNKNOWN); + } + }); + builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // User cancelled the dialog. Do nothing + } + }); + builder.create().show(); + return; + } + String sku = plan.getAndroidSKU(); Blog currentBlog = WordPress.getBlog(mLocalBlogID); JSONObject extraData = new JSONObject(); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansUtils.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansUtils.java index 10299596a95e..bf6939789ad3 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansUtils.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansUtils.java @@ -94,6 +94,24 @@ public static String getIconUrlForPlan(Plan plan, int iconSize) { return PhotonUtils.getPhotonImageUrl(plan.getIconUrl(), iconSize, iconSize); } + public static boolean isFreePlan(Plan plan) { + return plan.getProductSlug().equals("free_plan") || + plan.getProductSlug().equals("jetpack_free"); + } + + /** + * Weather the plan ID is a free plan. + * + * 2002 = Jetpack free + * 1 = WordPress.com free + * + * @param planID - The plan ID + * @return boolean - true if the current blog is on a free plan. + */ + public static boolean isFreePlan(long planID) { + return planID == 2002 || planID == 1; + } + /** * Removes stored plan data - for testing purposes */ diff --git a/WordPress/src/main/res/layout/plans_activity.xml b/WordPress/src/main/res/layout/plans_activity.xml index 2d679d4aa1b2..d8a718c048cf 100644 --- a/WordPress/src/main/res/layout/plans_activity.xml +++ b/WordPress/src/main/res/layout/plans_activity.xml @@ -84,6 +84,7 @@ android:textSize="@dimen/text_sz_large"/> Plans Unable to load plans Purchase Now + Upgrade Now + Upgrade not available + This blog already has a plan subscription. Please contact our support team to upgrade to %1$s. Do you want to contact support now? It\'s all yours, way to go! From 20c733578723f66f40ad069e1b09401a53d1e898 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Tue, 3 May 2016 17:44:09 +0200 Subject: [PATCH 09/22] Remove links to unused subprojects used during development --- settings.gradle | 4 ---- 1 file changed, 4 deletions(-) diff --git a/settings.gradle b/settings.gradle index c61872f05c87..d00ff04c5efe 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,9 +1,5 @@ include ':WordPress' include ':libs:utils:WordPressUtils' -include ':libs:android-wordpress-com-rest:WordPressComRest' include ':libs:networking:WordPressNetworking' include ':libs:analytics:WordPressAnalytics' include ':libs:editor:WordPressEditor' -include ':libs:automattictracks:AutomatticTracks' -include ':libs:Android-Passcodelock:library' - From 27765fb20f5449f9d5b2bb8103f0685625e27288 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Tue, 3 May 2016 17:47:42 +0200 Subject: [PATCH 10/22] Revert unwanted commits --- WordPress/build.gradle | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/WordPress/build.gradle b/WordPress/build.gradle index a6e86882267c..46d13e0de978 100644 --- a/WordPress/build.gradle +++ b/WordPress/build.gradle @@ -4,7 +4,7 @@ buildscript { maven { url 'https://maven.fabric.io/public' } } dependencies { - classpath 'com.android.tools.build:gradle:2.0.0' + classpath 'com.android.tools.build:gradle:2.1.0' classpath 'io.fabric.tools:gradle:1.+' } } @@ -13,6 +13,7 @@ repositories { jcenter() maven { url 'http://wordpress-mobile.github.io/WordPress-Android' } maven { url 'https://maven.fabric.io/public' } + maven { url 'http://dl.bintray.com/optimizely/optimizely' } } apply plugin: 'com.android.application' @@ -30,8 +31,8 @@ android { defaultConfig { applicationId "org.wordpress.android" - versionName "alpha-6" - versionCode 252 + versionName "alpha-7" + versionCode 253 minSdkVersion 14 targetSdkVersion 23 @@ -59,9 +60,8 @@ android { release { // Proguard is only used to fix an issue with some Samsung device // https://github.com/wordpress-mobile/WordPress-Android/issues/2151 - // minifyEnabled true - // proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.cfg' - debuggable true + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.cfg' } debug { @@ -76,6 +76,10 @@ dependencies { transitive = true; } + compile('com.optimizely:optimizely:+@aar') { + transitive = true + } + // Provided by maven central compile ('org.wordpress:mediapicker:1.2.4') { exclude group:'com.android.support' @@ -93,7 +97,7 @@ dependencies { compile 'com.github.chrisbanes.photoview:library:1.2.4' compile 'com.helpshift:android-helpshift-aar:4.4.0' compile 'de.greenrobot:eventbus:2.4.0' - // compile 'com.automattic:rest:1.0.3' + compile 'com.automattic:rest:1.0.3' compile 'org.wordpress:graphview:3.4.0' compile 'org.wordpress:persistentedittext:1.0.1' @@ -106,7 +110,7 @@ dependencies { // Provided by the WordPress-Android Repository compile 'org.wordpress:drag-sort-listview:0.6.1' // not found in maven central compile 'org.wordpress:slidinguppanel:1.0.0' // not found in maven central - // compile 'org.wordpress:passcodelock:1.1.0' + compile 'org.wordpress:passcodelock:1.1.0' compile 'org.wordpress:emailchecker:0.3' // Simperium @@ -120,12 +124,6 @@ dependencies { debugCompile project(path:':libs:analytics:WordPressAnalytics', configuration: 'debug') releaseCompile project(path:':libs:editor:WordPressEditor', configuration: 'release') debugCompile project(path:':libs:editor:WordPressEditor', configuration: 'debug') - - releaseCompile project(path:':libs:android-wordpress-com-rest:WordPressComRest', configuration: 'release') - debugCompile project(path:':libs:android-wordpress-com-rest:WordPressComRest', configuration: 'debug') - - releaseCompile project(path:':libs:Android-Passcodelock:library', configuration: 'release') - debugCompile project(path:':libs:Android-Passcodelock:library', configuration: 'debug') } configurations.all { From ef9b80da330e56d9c029e7e50b1e4006be4b63d9 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Tue, 3 May 2016 17:50:50 +0200 Subject: [PATCH 11/22] Fix merge conflicts --- WordPress/build.gradle | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/WordPress/build.gradle b/WordPress/build.gradle index 46d13e0de978..6fbbc1265fe0 100644 --- a/WordPress/build.gradle +++ b/WordPress/build.gradle @@ -14,6 +14,7 @@ repositories { maven { url 'http://wordpress-mobile.github.io/WordPress-Android' } maven { url 'https://maven.fabric.io/public' } maven { url 'http://dl.bintray.com/optimizely/optimizely' } + maven { url "https://jitpack.io" } } apply plugin: 'com.android.application' @@ -31,8 +32,8 @@ android { defaultConfig { applicationId "org.wordpress.android" - versionName "alpha-7" - versionCode 253 + versionName "alpha-8" + versionCode 259 minSdkVersion 14 targetSdkVersion 23 @@ -84,7 +85,7 @@ dependencies { compile ('org.wordpress:mediapicker:1.2.4') { exclude group:'com.android.support' } - compile 'com.google.code.gson:gson:2.2.2' + compile 'com.google.code.gson:gson:2.6.+' compile 'org.ccil.cowan.tagsoup:tagsoup:1.2.1' compile 'com.android.support:support-v13:23.1.1' compile 'com.android.support:appcompat-v7:23.1.1' @@ -97,10 +98,13 @@ dependencies { compile 'com.github.chrisbanes.photoview:library:1.2.4' compile 'com.helpshift:android-helpshift-aar:4.4.0' compile 'de.greenrobot:eventbus:2.4.0' - compile 'com.automattic:rest:1.0.3' + compile 'com.automattic:rest:1.0.5' compile 'org.wordpress:graphview:3.4.0' compile 'org.wordpress:persistentedittext:1.0.1' + compile 'com.yalantis:ucrop:1.2.4' + compile 'com.github.xizzhu:simple-tool-tip:0.5.0' + androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.0' androidTestCompile 'org.objenesis:objenesis:2.1' androidTestCompile 'org.mockito:mockito-core:+' From 97baa8c5dbbc353ee353af96426753df19df35a5 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Tue, 3 May 2016 17:52:25 +0200 Subject: [PATCH 12/22] Fix merge conflicts - tentative #2 --- libs/networking/WordPressNetworking/build.gradle | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/libs/networking/WordPressNetworking/build.gradle b/libs/networking/WordPressNetworking/build.gradle index a9f79dabc2a0..76a09ba62a60 100644 --- a/libs/networking/WordPressNetworking/build.gradle +++ b/libs/networking/WordPressNetworking/build.gradle @@ -30,10 +30,7 @@ android { dependencies { compile 'org.wordpress:utils:1.9.0' - //compile 'com.automattic:rest:1.0.3' - - releaseCompile project(path:':libs:android-wordpress-com-rest:WordPressComRest', configuration: 'release') - debugCompile project(path:':libs:android-wordpress-com-rest:WordPressComRest', configuration: 'debug') + compile 'com.automattic:rest:1.0.3' } uploadArchives { From 7c2824359ec495a4d960241609aa29c4ca492742 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Tue, 3 May 2016 17:53:08 +0200 Subject: [PATCH 13/22] New plans strings --- WordPress/src/main/res/values/strings.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index bd627876001b..009fda1c0d7f 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -1410,6 +1410,9 @@ Unable to load plans Purchase Now Enter your password instead + Upgrade Now + Upgrade not available + This blog already has a plan subscription. Please contact our support team to upgrade to %1$s. Do you want to contact support now? It\'s all yours, way to go! From 90e71a478a9115dac0025d812df050537e015f9e Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Wed, 4 May 2016 16:15:29 +0200 Subject: [PATCH 14/22] Do not show the Upgrade|Purchase button when the blog already has a plan attached to it. --- .../android/ui/plans/PlansActivity.java | 36 +++---------------- .../src/main/res/layout/plans_activity.xml | 1 - WordPress/src/main/res/values/strings.xml | 3 -- 3 files changed, 4 insertions(+), 36 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java index e8703f65a5e9..864e11f81051 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java @@ -2,8 +2,6 @@ import android.animation.Animator; import android.annotation.TargetApi; -import android.app.AlertDialog; -import android.content.DialogInterface; import android.content.Intent; import android.graphics.Point; import android.os.Build; @@ -39,7 +37,6 @@ import org.wordpress.android.util.AniUtils; import org.wordpress.android.util.AppLog; import org.wordpress.android.util.DisplayUtils; -import org.wordpress.android.util.HelpshiftHelper; import org.wordpress.android.widgets.WPViewPager; import java.io.Serializable; @@ -161,6 +158,9 @@ private boolean isBuyButtonAvailable(int position) { /** * The 'Upgrade' button should be available if the current plan is NOT free, * and the selected plan upgrade is available, and the current plan ID < new plan ID. + * + * Note: Not used now, but will be when we'll implement upgrade of plan within the app. + * * @param position * @return boolean - true if the current plan could be upgraded to the blog. */ @@ -182,20 +182,13 @@ private boolean isUpgradeButtonAvailable(int position) { private void updatePurchaseUI(final int position) { final Plan plan = getPageAdapter().getPlan(position); - boolean showPurchaseButton = isBuyButtonAvailable(position) || isUpgradeButtonAvailable(position); + boolean showPurchaseButton = isBuyButtonAvailable(position); ViewGroup framePurchase = (ViewGroup) findViewById(R.id.frame_purchase); ViewGroup containerPurchase = (ViewGroup) findViewById(R.id.purchase_container); if (showPurchaseButton) { TextView txtPurchasePrice = (TextView) framePurchase.findViewById(R.id.text_purchase_price); txtPurchasePrice.setText(PlansUtils.getPlanDisplayPrice(plan)); - - TextView txtPurchaseLabel = (TextView) framePurchase.findViewById(R.id.text_purchase_label); - if (isBuyButtonAvailable(position)) { - txtPurchaseLabel.setText(getString(R.string.plan_purchase_now)); - } else if (isUpgradeButtonAvailable(position)) { - txtPurchaseLabel.setText(getString(R.string.plan_upgrade_now)); - } containerPurchase.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -347,27 +340,6 @@ public boolean onOptionsItemSelected(MenuItem item) { private void startPurchaseProcess(int position) { final Plan plan = getPageAdapter().getPlan(position); - - // if it's an upgrade show the message and return. We don't handle upgrades in app. - if (isUpgradeButtonAvailable(position)) { - String upgradeText = getString(R.string.plan_upgrade_contact_support_text, plan.getProductName()); - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setMessage(upgradeText) - .setTitle(getString(R.string.plan_upgrade_not_available)); - builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - HelpshiftHelper.getInstance().showConversation(PlansActivity.this, HelpshiftHelper.Tag.ORIGIN_UNKNOWN); - } - }); - builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - // User cancelled the dialog. Do nothing - } - }); - builder.create().show(); - return; - } - String sku = plan.getAndroidSKU(); Blog currentBlog = WordPress.getBlog(mLocalBlogID); JSONObject extraData = new JSONObject(); diff --git a/WordPress/src/main/res/layout/plans_activity.xml b/WordPress/src/main/res/layout/plans_activity.xml index d8a718c048cf..2d679d4aa1b2 100644 --- a/WordPress/src/main/res/layout/plans_activity.xml +++ b/WordPress/src/main/res/layout/plans_activity.xml @@ -84,7 +84,6 @@ android:textSize="@dimen/text_sz_large"/> Unable to load plans Purchase Now Enter your password instead - Upgrade Now - Upgrade not available - This blog already has a plan subscription. Please contact our support team to upgrade to %1$s. Do you want to contact support now? It\'s all yours, way to go! From bdba660a2e8d9b74ba84379c0661884d735ed5bf Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Mon, 9 May 2016 15:25:08 +0200 Subject: [PATCH 15/22] Make sure `mIabHelper` has finished its setup before doing any calls on it. --- .../java/org/wordpress/android/ui/plans/PlansActivity.java | 7 ++++++- .../java/org/wordpress/android/ui/plans/UpdateIAPTask.java | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java index 864e11f81051..8d2e45d72604 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java @@ -58,6 +58,7 @@ public class PlansActivity extends AppCompatActivity { private TabLayout mTabLayout; private IabHelper mIabHelper; + private boolean mIABSetupDone = false; @Override public void onCreate(Bundle savedInstanceState) { @@ -147,6 +148,9 @@ public void onPause() { * @return boolean - true if the current plan could be added to the blog. */ private boolean isBuyButtonAvailable(int position) { + if (!mIABSetupDone) { + return false; + } long currentPlanProductId = WordPress.wpDB.getPlanIdForLocalTableBlogId(mLocalBlogID); if (!PlansUtils.isFreePlan(currentPlanProductId)) { return false; @@ -374,7 +378,7 @@ public void onIabPurchaseFinished(IabResult result, Purchase info) { } } }, - extraData.toString()); + extraData.toString()); } @Override @@ -399,6 +403,7 @@ private void startInAppBillingHelper() { public void onIabSetupFinished(IabResult result) { if (result.isSuccess()) { AppLog.d(AppLog.T.PLANS, "IAB started successfully"); + mIABSetupDone = true; } else { AppLog.w(AppLog.T.PLANS, "IAB failed with " + result); } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java index 98ecf383a4f7..6e01598b359e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java @@ -33,6 +33,7 @@ public class UpdateIAPTask extends AsyncTask { private static final String IAP_ENDPOINT = "/iap/validate"; protected Context mContext; private IabHelper mIabHelper; + private boolean mIABSetupDone = false; public UpdateIAPTask(Context context) { mContext = context; @@ -55,6 +56,7 @@ protected Void doInBackground(Void... args) { @Override public void onIabSetupFinished(IabResult result) { if (result.isSuccess()) { + mIABSetupDone = true; AppLog.d(AppLog.T.PLANS, "IAB started successfully"); } else { AppLog.w(AppLog.T.PLANS, "IAB failed with " + result); @@ -81,7 +83,7 @@ public void onIabSetupFinished(IabResult result) { } private void listIAPs() { - if (mIabHelper == null) { + if (mIabHelper == null || !mIABSetupDone) { return; } try { From 948c6bef9983005e2c38bc41ad24cbbf6ad61464 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Mon, 9 May 2016 15:58:27 +0200 Subject: [PATCH 16/22] Use constants defined in PlanConstants.java when checking for `planID` Introduce a utlity method that check if a plan is "greater" than another. --- .../android/ui/plans/PlansActivity.java | 13 ++++++-- .../android/ui/plans/PlansConstants.java | 4 +++ .../android/ui/plans/PlansUtils.java | 32 +++++++++++++++---- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java index 8d2e45d72604..f46e9d77e2a1 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java @@ -174,14 +174,21 @@ private boolean isUpgradeButtonAvailable(int position) { return false; } - final Plan plan = getPageAdapter().getPlan(position); + Plan currentPlan = PlansUtils.getPlan(mAvailablePlans, currentPlanProductId); + if (currentPlan == null) { + // Blog's current plan is not available anymore. Weird, it should be available, but not purchasable. + AppLog.w(AppLog.T.PLANS, "Blog's current plan with ID " + currentPlanProductId + "is not available anymore on wpcom!"); + return false; + } + + final Plan selectedPlan = getPageAdapter().getPlan(position); // No downgrade! - if (PlansUtils.isFreePlan(plan) || currentPlanProductId > plan.getProductID()) { + if (PlansUtils.isGreaterEquals(currentPlan, selectedPlan)) { return false; } - return plan.isAvailable() && !plan.isCurrentPlan(); + return selectedPlan.isAvailable() && !selectedPlan.isCurrentPlan(); } private void updatePurchaseUI(final int position) { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansConstants.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansConstants.java index 203bb6eba9b9..9027f436b4ca 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansConstants.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansConstants.java @@ -14,4 +14,8 @@ public class PlansConstants { public static final long JETPACK_FREE_PLAN_ID = 2002L; public static final long JETPACK_PREMIUM_PLAN_ID = 2000L; public static final long JETPACK_BUSINESS_PLAN_ID = 2001L; + + public static final String FREE_PLAN_SLUG = "free_plan"; + + public static final String JETPACK_FREE_PLAN_SLUG = "jetpack_free"; } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansUtils.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansUtils.java index bf6939789ad3..ce3d80b78e34 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansUtils.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansUtils.java @@ -95,21 +95,41 @@ public static String getIconUrlForPlan(Plan plan, int iconSize) { } public static boolean isFreePlan(Plan plan) { - return plan.getProductSlug().equals("free_plan") || - plan.getProductSlug().equals("jetpack_free"); + return plan.getProductSlug().equals(PlansConstants.FREE_PLAN_SLUG) || + plan.getProductSlug().equals(PlansConstants.JETPACK_FREE_PLAN_SLUG); } /** * Weather the plan ID is a free plan. * - * 2002 = Jetpack free - * 1 = WordPress.com free - * * @param planID - The plan ID * @return boolean - true if the current blog is on a free plan. */ public static boolean isFreePlan(long planID) { - return planID == 2002 || planID == 1; + return planID == PlansConstants.JETPACK_FREE_PLAN_ID || PlansConstants.FREE_PLAN_ID == 1; + } + + /* + * Weather the plan A is "greater" than or "equal" to the plan B + * + * TODO: Improve this, since we're assuming that a greater plan ID meant a more expensive plan. + */ + public static boolean isGreaterEquals(Plan planA, Plan planB) { + return planA.getProductID() >= planB.getProductID(); + } + + public static Plan getPlan(Plan[] plans, long planID) { + if (plans == null) { + AppLog.w(AppLog.T.PLANS, "The passed plans list is null!!"); + return null; + } + for (Plan currentPlan: plans) { + if (currentPlan.getProductID() == planID) { + return currentPlan; + } + } + AppLog.w(AppLog.T.PLANS, "Plan with ID " + planID + "not found in the plans list"); + return null; } /** From 795c213168a8858035b3571e0b03eb3200162c8e Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Mon, 9 May 2016 16:21:46 +0200 Subject: [PATCH 17/22] Remove unused constants. Fix a typo in the method that returns if a passed plan object is a free plan. --- .../wordpress/android/ui/plans/PlansConstants.java | 4 ---- .../org/wordpress/android/ui/plans/PlansUtils.java | 11 +++++------ 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansConstants.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansConstants.java index 9027f436b4ca..203bb6eba9b9 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansConstants.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansConstants.java @@ -14,8 +14,4 @@ public class PlansConstants { public static final long JETPACK_FREE_PLAN_ID = 2002L; public static final long JETPACK_PREMIUM_PLAN_ID = 2000L; public static final long JETPACK_BUSINESS_PLAN_ID = 2001L; - - public static final String FREE_PLAN_SLUG = "free_plan"; - - public static final String JETPACK_FREE_PLAN_SLUG = "jetpack_free"; } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansUtils.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansUtils.java index ce3d80b78e34..2063ed09c1fc 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansUtils.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansUtils.java @@ -95,8 +95,7 @@ public static String getIconUrlForPlan(Plan plan, int iconSize) { } public static boolean isFreePlan(Plan plan) { - return plan.getProductSlug().equals(PlansConstants.FREE_PLAN_SLUG) || - plan.getProductSlug().equals(PlansConstants.JETPACK_FREE_PLAN_SLUG); + return isFreePlan(plan.getProductID()); } /** @@ -106,11 +105,11 @@ public static boolean isFreePlan(Plan plan) { * @return boolean - true if the current blog is on a free plan. */ public static boolean isFreePlan(long planID) { - return planID == PlansConstants.JETPACK_FREE_PLAN_ID || PlansConstants.FREE_PLAN_ID == 1; + return planID == PlansConstants.JETPACK_FREE_PLAN_ID || planID == PlansConstants.FREE_PLAN_ID; } - /* - * Weather the plan A is "greater" than or "equal" to the plan B + /** + * Weather the plan A is "greater" than or "equal to" the plan B * * TODO: Improve this, since we're assuming that a greater plan ID meant a more expensive plan. */ @@ -128,7 +127,7 @@ public static Plan getPlan(Plan[] plans, long planID) { return currentPlan; } } - AppLog.w(AppLog.T.PLANS, "Plan with ID " + planID + "not found in the plans list"); + AppLog.w(AppLog.T.PLANS, "Plan with ID " + planID + " wasn't found in the plans list"); return null; } From f48f9f7f440c6043bac1b7c79c07278505648e79 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Wed, 11 May 2016 17:24:54 +0200 Subject: [PATCH 18/22] Synch IAPs with the backend when there is a pending request only. Do not use scheduled updates, since the backend already synchs the IAPs nightly. --- .../java/org/wordpress/android/WordPress.java | 19 ++----------------- .../android/ui/plans/PlansActivity.java | 3 ++- .../android/ui/plans/PlansUtils.java | 15 +++++++++++++++ .../android/ui/plans/UpdateIAPTask.java | 2 ++ .../wordpress/android/ui/prefs/AppPrefs.java | 10 ++++++++++ 5 files changed, 31 insertions(+), 18 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/WordPress.java b/WordPress/src/main/java/org/wordpress/android/WordPress.java index 237d7ee4c6c3..a8cb55dbea5b 100644 --- a/WordPress/src/main/java/org/wordpress/android/WordPress.java +++ b/WordPress/src/main/java/org/wordpress/android/WordPress.java @@ -49,7 +49,7 @@ import org.wordpress.android.ui.accounts.helpers.UpdateBlogListTask.GenericUpdateBlogListTask; import org.wordpress.android.ui.notifications.utils.NotificationsUtils; import org.wordpress.android.ui.notifications.utils.SimperiumUtils; -import org.wordpress.android.ui.plans.UpdateIAPTask; +import org.wordpress.android.ui.plans.PlansUtils; import org.wordpress.android.ui.prefs.AppPrefs; import org.wordpress.android.ui.stats.StatsWidgetProvider; import org.wordpress.android.ui.stats.datasets.StatsDatabaseHelper; @@ -103,7 +103,6 @@ public class WordPress extends Application { private static final int SECONDS_BETWEEN_OPTIONS_UPDATE = 10 * 60; private static final int SECONDS_BETWEEN_BLOGLIST_UPDATE = 6 * 60 * 60; - private static final int SECONDS_BETWEEN_IAP_UPDATE = 5 * 60; // 5 minutes private static final int SECONDS_BETWEEN_DELETE_STATS = 5 * 60; // 5 minutes private static Context mContext; @@ -137,20 +136,6 @@ protected boolean run() { } }; - /** - * Synch IAPs with wpcom backend. This need to be called to add/remove upgrades on wpcom side. - * Those upgrades the user has already bought/cancelled on mobile side (from the Google Store). - * - */ - public static RateLimitedTask sUpdateIAPsWordPressCom = new RateLimitedTask(SECONDS_BETWEEN_IAP_UPDATE) { - protected boolean run() { - if (AccountHelper.isSignedInWordPressDotCom()) { - new UpdateIAPTask(getContext()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } - return true; - } - }; - /** * Delete stats cache that is already expired */ @@ -838,7 +823,7 @@ public void onAppComesFromBackground() { sUpdateCurrentBlogOption.runIfNotLimited(); } sDeleteExpiredStats.runIfNotLimited(); - sUpdateIAPsWordPressCom.runIfNotLimited(); + PlansUtils.synchIAPsWordPressCom(); } @Override diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java index f46e9d77e2a1..9913db41e434 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java @@ -369,7 +369,8 @@ public void onIabPurchaseFinished(IabResult result, Purchase info) { AppLog.d(AppLog.T.PLANS, "IabResult: " + result.toString()); if (result.isSuccess()) { if (info != null) { - WordPress.sUpdateIAPsWordPressCom.forceRun(); // refresh purchase on wpcom + AppPrefs.setInAppPurchaseRefreshRequired(true); + PlansUtils.synchIAPsWordPressCom(); AppLog.d(AppLog.T.PLANS, "Purchase: " + info.toString()); AppLog.d(AppLog.T.PLANS, "You have bought the " + info.getSku() + ". Excellent choice, adventurer!"); boolean isBusinessPlan = (mViewPager.getCurrentItem() == mViewPager.getAdapter().getCount() - 1); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansUtils.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansUtils.java index 2063ed09c1fc..d50d11a35d58 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansUtils.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansUtils.java @@ -1,5 +1,6 @@ package org.wordpress.android.ui.plans; +import android.os.AsyncTask; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.TextUtils; @@ -7,6 +8,8 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import org.wordpress.android.WordPress; +import org.wordpress.android.models.AccountHelper; import org.wordpress.android.ui.plans.models.Feature; import org.wordpress.android.ui.plans.models.Plan; import org.wordpress.android.ui.prefs.AppPrefs; @@ -139,4 +142,16 @@ public static void clearPlanData() { AppPrefs.setGlobalPlansFeatures(null); } + + /** + * Synch IAPs with wpcom backend. This need to be called to add/remove upgrades on wpcom side. + * Those upgrades the user has already bought/cancelled on mobile side (from the Google Store). + */ + public static boolean synchIAPsWordPressCom() { + if (AccountHelper.isSignedInWordPressDotCom() && AppPrefs.isInAppPurchaseRefreshRequired()) { + new UpdateIAPTask(WordPress.getContext()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + return true; + } + return false; + } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java index 6e01598b359e..67a453761cce 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java @@ -16,6 +16,7 @@ import org.wordpress.android.ui.plans.util.IabResult; import org.wordpress.android.ui.plans.util.Inventory; import org.wordpress.android.ui.plans.util.Purchase; +import org.wordpress.android.ui.prefs.AppPrefs; import org.wordpress.android.util.AppLog; import java.util.HashMap; @@ -104,6 +105,7 @@ public void onResponse(JSONObject response) { if (response != null) { AppLog.d(AppLog.T.PLANS, "Response from the server: " + response.toString()); } + AppPrefs.setInAppPurchaseRefreshRequired(false); } }, new RestRequest.ErrorListener() { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/prefs/AppPrefs.java b/WordPress/src/main/java/org/wordpress/android/ui/prefs/AppPrefs.java index a7e5b172ad09..b52231f479fe 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/prefs/AppPrefs.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/prefs/AppPrefs.java @@ -82,6 +82,9 @@ public enum UndeletablePrefKey implements PrefKey { // Global plans features GLOBAL_PLANS_PLANS_FEATURES, + // When we need to sync IAP data with the wpcom backend + IAP_SYNC_REQUIRED, + // When we need to show the Gravatar Change Promo Tooltip GRAVATAR_CHANGE_PROMO_REQUIRED, } @@ -377,4 +380,11 @@ public static void setGlobalPlansFeatures(String jsonOfFeatures) { public static String getGlobalPlansFeatures() { return getString(UndeletablePrefKey.GLOBAL_PLANS_PLANS_FEATURES, ""); } + + public static boolean isInAppPurchaseRefreshRequired() { + return getBoolean(UndeletablePrefKey.IAP_SYNC_REQUIRED, false); + } + public static void setInAppPurchaseRefreshRequired(boolean required) { + setBoolean(UndeletablePrefKey.IAP_SYNC_REQUIRED, required); + } } From 858cfa8b40d288cc9ba0500da3c53eb99c31ab89 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Thu, 12 May 2016 15:41:23 +0200 Subject: [PATCH 19/22] Change the visibilty of `mContext` to private in UpdateIAPTask --- .../main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java index 67a453761cce..2e4ab2c200e5 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/UpdateIAPTask.java @@ -32,7 +32,7 @@ public class UpdateIAPTask extends AsyncTask { private static final int GET_IAP_BINDER_TIMEOUT = 30000; private static final String IAP_ENDPOINT = "/iap/validate"; - protected Context mContext; + private final Context mContext; private IabHelper mIabHelper; private boolean mIABSetupDone = false; From d0d361e81439a75423047d9409421befaf3a6ba6 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Thu, 12 May 2016 15:42:23 +0200 Subject: [PATCH 20/22] Drop unused variable --- .../main/java/org/wordpress/android/ui/plans/PlansActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java index 9913db41e434..a7f9649f4731 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java @@ -392,7 +392,7 @@ public void onIabPurchaseFinished(IabResult result, Purchase info) { @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); - boolean handled = mIabHelper.handleActivityResult(requestCode, resultCode, data); + mIabHelper.handleActivityResult(requestCode, resultCode, data); } /* From 70d4012518a70cc977896cb76af6d122dc801f84 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Thu, 12 May 2016 15:48:34 +0200 Subject: [PATCH 21/22] Added a comment that describe how the sync with wpcom works --- .../java/org/wordpress/android/ui/plans/PlansActivity.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java index a7f9649f4731..813b8195125e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/PlansActivity.java @@ -369,6 +369,13 @@ public void onIabPurchaseFinished(IabResult result, Purchase info) { AppLog.d(AppLog.T.PLANS, "IabResult: " + result.toString()); if (result.isSuccess()) { if (info != null) { + /* + Sync the purchase info with the wpcom backend, and enabled the product on the site. + We need to use an app setting here for security reasons. + If something bad happens during this sync, we need to re-sync it later (See onAppComesFromBackground in WordPress.java) + Without this initial sync the backend doesn't have any info about the purchase, and the product will NOT be enabled + without a manual action on backend side. + */ AppPrefs.setInAppPurchaseRefreshRequired(true); PlansUtils.synchIAPsWordPressCom(); AppLog.d(AppLog.T.PLANS, "Purchase: " + info.toString()); From 84932ae875a5c997a4d31148da4183134a5915b4 Mon Sep 17 00:00:00 2001 From: Danilo Ercoli Date: Thu, 12 May 2016 15:51:47 +0200 Subject: [PATCH 22/22] Revert changes made to IabHelper --- .../android/ui/plans/util/IabHelper.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/plans/util/IabHelper.java b/WordPress/src/main/java/org/wordpress/android/ui/plans/util/IabHelper.java index 530b2b689744..0b14aae8fc4e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/plans/util/IabHelper.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/plans/util/IabHelper.java @@ -69,6 +69,9 @@ * */ public class IabHelper { + // Is debug logging enabled? + boolean mDebugLog = false; + String mDebugTag = "IabHelper"; // Is setup done? boolean mSetupDone = false; @@ -167,8 +170,18 @@ public IabHelper(Context ctx, String base64PublicKey) { logDebug("IAB helper created."); } + /** + * Enables or disable debug logging through LogCat. + */ + public void enableDebugLogging(boolean enable, String tag) { + checkNotDisposed(); + mDebugLog = enable; + mDebugTag = tag; + } + public void enableDebugLogging(boolean enable) { checkNotDisposed(); + mDebugLog = enable; } /** @@ -1025,11 +1038,11 @@ public void run() { } void logDebug(String msg) { - AppLog.d(AppLog.T.PLANS, msg); + if (mDebugLog) AppLog.d(AppLog.T.PLANS, msg); } void logError(String msg) { - AppLog.d(AppLog.T.PLANS, "In-app billing error: " + msg); + AppLog.e(AppLog.T.PLANS, "In-app billing error: " + msg); } void logWarn(String msg) {