Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
2341d26
Use our logger in IabHelper
daniloercoli Apr 10, 2016
9cda45d
Start integrating the store calls
daniloercoli Apr 10, 2016
db846cf
Re-synch purchases with wpcom server on startup and periodically. (Th…
daniloercoli Apr 11, 2016
eecf66f
Merge branch 'develop' of https://github.com/wordpress-mobile/WordPre…
daniloercoli Apr 11, 2016
443d963
Remove unused imports.
daniloercoli Apr 11, 2016
8f553c9
Remove custom hardcoded SKUs since REST Endpoint has been updated.
daniloercoli Apr 12, 2016
2b9d5a6
Fix log message
daniloercoli Apr 12, 2016
63ef93b
Merge branch 'develop' of https://github.com/wordpress-mobile/WordPre…
daniloercoli Apr 12, 2016
6be91fa
Merge branch 'develop' of https://github.com/wordpress-mobile/WordPre…
daniloercoli Apr 14, 2016
3835ec3
Merge branch 'develop' of https://github.com/wordpress-mobile/WordPre…
daniloercoli Apr 28, 2016
691e6a8
Use the new endpoint name, and remove unused parameters.
daniloercoli Apr 29, 2016
cc3c871
Merge branch 'develop' of https://github.com/wordpress-mobile/WordPre…
daniloercoli May 2, 2016
569e2b0
Change the label to "upgrade" when the selected blog already has a pl…
daniloercoli May 3, 2016
9cfa151
Merge branch 'develop' of https://github.com/wordpress-mobile/WordPre…
daniloercoli May 3, 2016
20c7335
Remove links to unused subprojects used during development
daniloercoli May 3, 2016
27765fb
Revert unwanted commits
daniloercoli May 3, 2016
ef9b80d
Fix merge conflicts
daniloercoli May 3, 2016
97baa8c
Fix merge conflicts - tentative #2
daniloercoli May 3, 2016
7c28243
New plans strings
daniloercoli May 3, 2016
90e71a4
Do not show the Upgrade|Purchase button when the blog already has a p…
daniloercoli May 4, 2016
e6ce503
Merge branch 'develop' of https://github.com/wordpress-mobile/WordPre…
daniloercoli May 6, 2016
877b460
Merge branch 'develop' of https://github.com/wordpress-mobile/WordPre…
daniloercoli May 9, 2016
bdba660
Make sure `mIabHelper` has finished its setup before doing any calls …
daniloercoli May 9, 2016
948c6be
Use constants defined in PlanConstants.java when checking for `planID`
daniloercoli May 9, 2016
795c213
Remove unused constants.
daniloercoli May 9, 2016
f48f9f7
Synch IAPs with the backend when there is a pending request only. Do …
daniloercoli May 11, 2016
858cfa8
Change the visibilty of `mContext` to private in UpdateIAPTask
daniloercoli May 12, 2016
d0d361e
Drop unused variable
daniloercoli May 12, 2016
70d4012
Added a comment that describe how the sync with wpcom works
daniloercoli May 12, 2016
84932ae
Revert changes made to IabHelper
daniloercoli May 12, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions WordPress/src/main/java/org/wordpress/android/WordPress.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +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.PlansUtils;
import org.wordpress.android.ui.prefs.AppPrefs;
import org.wordpress.android.ui.stats.StatsWidgetProvider;
import org.wordpress.android.ui.stats.datasets.StatsDatabaseHelper;
Expand Down Expand Up @@ -822,6 +823,7 @@ public void onAppComesFromBackground() {
sUpdateCurrentBlogOption.runIfNotLimited();
}
sDeleteExpiredStats.runIfNotLimited();
PlansUtils.synchIAPsWordPressCom();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,18 @@
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.IabHelper;
import org.wordpress.android.ui.plans.util.IabResult;
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;
Expand All @@ -43,6 +48,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;
Expand All @@ -52,6 +58,7 @@ public class PlansActivity extends AppCompatActivity {
private TabLayout mTabLayout;

private IabHelper mIabHelper;
private boolean mIABSetupDone = false;

@Override
public void onCreate(Bundle savedInstanceState) {
Expand Down Expand Up @@ -135,18 +142,59 @@ public void onPause() {
EventBus.getDefault().unregister(this);
}

private void updatePurchaseUI(int position) {
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;
/**
* 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) {
if (!mIABSetupDone) {
return false;
}
long currentPlanProductId = WordPress.wpDB.getPlanIdForLocalTableBlogId(mLocalBlogID);
if (!PlansUtils.isFreePlan(currentPlanProductId)) {
return false;
}
final Plan plan = getPageAdapter().getPlan(position);
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.
*
* 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.
*/
private boolean isUpgradeButtonAvailable(int position) {
long currentPlanProductId = WordPress.wpDB.getPlanIdForLocalTableBlogId(mLocalBlogID);
if (isBuyButtonAvailable(position) || PlansUtils.isFreePlan(currentPlanProductId)) {
return false;
}

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.isGreaterEquals(currentPlan, selectedPlan)) {
return false;
}

return selectedPlan.isAvailable() && !selectedPlan.isCurrentPlan();
}

private void updatePurchaseUI(final int position) {
final Plan plan = getPageAdapter().getPlan(position);
boolean showPurchaseButton = isBuyButtonAvailable(position);

ViewGroup framePurchase = (ViewGroup) findViewById(R.id.frame_purchase);
ViewGroup containerPurchase = (ViewGroup) findViewById(R.id.purchase_container);
if (showPurchaseButton) {
Expand All @@ -155,7 +203,7 @@ private void updatePurchaseUI(int position) {
containerPurchase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startPurchaseProcess();
startPurchaseProcess(position);
}
});
} else {
Expand All @@ -170,7 +218,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();
Expand Down Expand Up @@ -301,14 +349,57 @@ 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
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();
private void startPurchaseProcess(int position) {
final Plan plan = getPageAdapter().getPlan(position);
String sku = plan.getAndroidSKU();
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);
return;
}

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) {
/*
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);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this app setting necessary? Seems like we could drop it and remove the call to PlansUtils.synchIAPsWordPressCom() that's done here.

@daniloercoli daniloercoli May 12, 2016

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want to synch the purchase with the wpcom backend as soon as it's made on the Google Store. So the product is enabled on the site immediately after.

That app setting, and the call that happens when the app is brought in foreground, are there for security reasons. If something bad happens during the post purchase synch, we will re-synch it later. Without this initial synch the backend doesn't have any info about the purchase.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, that makes sense. It would a good idea to add a comment stating this purpose, though, since it's unclear otherwise.

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);
Intent intent = new Intent(PlansActivity.this, PlanPostPurchaseActivity.class);
intent.putExtra(PlanPostPurchaseActivity.ARG_IS_BUSINESS_PLAN, isBusinessPlan);
startActivity(intent);
}
} else {
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.
}
}
}
},
extraData.toString());
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
mIabHelper.handleActivityResult(requestCode, resultCode, data);
}

/*
Expand All @@ -319,15 +410,15 @@ 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() {
@Override
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);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package org.wordpress.android.ui.plans;

import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;

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;
Expand Down Expand Up @@ -94,6 +97,43 @@ public static String getIconUrlForPlan(Plan plan, int iconSize) {
return PhotonUtils.getPhotonImageUrl(plan.getIconUrl(), iconSize, iconSize);
}

public static boolean isFreePlan(Plan plan) {
return isFreePlan(plan.getProductID());
}

/**
* Weather the plan ID is a free plan.
*
* @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 == PlansConstants.JETPACK_FREE_PLAN_ID || planID == PlansConstants.FREE_PLAN_ID;
}

/**
* 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 + " wasn't found in the plans list");
return null;
}

/**
* Removes stored plan data - for testing purposes
*/
Expand All @@ -102,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;
}
}
Loading