Refactor AstridPurchaseObserver, restore transactions on startup

pull/14/head
Sam Bosley 12 years ago
parent 12cab2e912
commit 23e1eb476f

@ -0,0 +1,151 @@
package com.todoroo.astrid.billing;
import android.app.Activity;
import android.os.Handler;
import android.util.Log;
import android.widget.Toast;
import com.timsu.astrid.R;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.actfm.sync.ActFmSyncService;
import com.todoroo.astrid.billing.BillingConstants.PurchaseState;
import com.todoroo.astrid.billing.BillingConstants.ResponseCode;
import com.todoroo.astrid.billing.BillingService.RequestPurchase;
import com.todoroo.astrid.billing.BillingService.RestoreTransactions;
import com.todoroo.astrid.utility.Constants;
@SuppressWarnings("nls")
public abstract class AstridPurchaseObserver extends PurchaseObserver {
@Autowired
private ActFmSyncService actFmSyncService;
@Autowired
private ActFmPreferenceService actFmPreferenceService;
/**
* A {@link PurchaseObserver} is used to get callbacks when Android Market sends
* messages to this application so that we can update the UI.
*/
public AstridPurchaseObserver(Activity activity, Handler handler) {
super(activity, handler);
DependencyInjectionService.getInstance().inject(this);
}
@Override
public void onBillingSupported(boolean supported, String type) {
if (Constants.DEBUG) {
Log.i(TAG, "supported: " + supported);
}
if (type != null && type.equals(BillingConstants.ITEM_TYPE_SUBSCRIPTION)) {
if (supported) {
billingSupportedCallback();
} else {
billingNotSupportedCallback();
}
} else {
subscriptionsNotSupportedCallback();
}
}
protected abstract void billingSupportedCallback();
protected abstract void billingNotSupportedCallback();
protected abstract void subscriptionsNotSupportedCallback();
@Override
public void onPurchaseStateChange(PurchaseState purchaseState, final String itemId,
int quantity, long purchaseTime, String developerPayload, final String purchaseToken) {
if (Constants.DEBUG) {
Log.i(TAG, "onPurchaseStateChange() itemId: " + itemId + " " + purchaseState);
}
Preferences.setString(BillingConstants.PREF_PRODUCT_ID, itemId);
Preferences.setString(BillingConstants.PREF_PURCHASE_TOKEN, purchaseToken);
if (purchaseState == PurchaseState.PURCHASED) {
new Thread() {
@Override
public void run() {
Preferences.setBoolean(ActFmPreferenceService.PREF_LOCAL_PREMIUM, true);
if (actFmPreferenceService.isLoggedIn()) {
actFmSyncService.updateUserSubscriptionStatus(new Runnable() {
@Override
public void run() {
Preferences.setBoolean(ActFmPreferenceService.PREF_PREMIUM, true);
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(mActivity, R.string.premium_success, Toast.LENGTH_LONG).show();
}
});
}
}, new Runnable() {
@Override
public void run() {
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(mActivity, R.string.premium_success_with_server_error, Toast.LENGTH_LONG).show();
}
});
}
});
}
}
}.start();
} else if (purchaseState == PurchaseState.REFUNDED || purchaseState == PurchaseState.EXPIRED) {
new Thread() {
@Override
public void run() {
Preferences.setBoolean(ActFmPreferenceService.PREF_LOCAL_PREMIUM, false);
if (actFmPreferenceService.isLoggedIn())
actFmSyncService.updateUserSubscriptionStatus(null, null);
}
}.start();
}
}
@Override
public void onRequestPurchaseResponse(RequestPurchase request,
ResponseCode responseCode) {
if (Constants.DEBUG) {
Log.d(TAG, request.mProductId + ": " + responseCode);
}
if (responseCode == ResponseCode.RESULT_OK) {
if (Constants.DEBUG) {
Log.i(TAG, "purchase was successfully sent to server");
}
} else if (responseCode == ResponseCode.RESULT_USER_CANCELED) {
if (Constants.DEBUG) {
Log.i(TAG, "user canceled purchase");
}
} else {
if (Constants.DEBUG) {
Log.i(TAG, "purchase failed");
}
}
}
@Override
public void onRestoreTransactionsResponse(RestoreTransactions request,
ResponseCode responseCode) {
if (responseCode == ResponseCode.RESULT_OK) {
if (Constants.DEBUG) {
Log.d(TAG, "completed RestoreTransactions request");
}
// Update the shared preferences so that we don't perform
// a RestoreTransactions again.
Preferences.setBoolean(BillingConstants.PREF_TRANSACTIONS_INITIALIZED, true);
} else {
if (Constants.DEBUG) {
Log.d(TAG, "RestoreTransactions error: " + responseCode);
}
}
}
}

@ -14,7 +14,6 @@ import android.util.Log;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.widget.Button; import android.widget.Button;
import android.widget.Toast;
import com.timsu.astrid.R; import com.timsu.astrid.R;
import com.todoroo.andlib.service.Autowired; import com.todoroo.andlib.service.Autowired;
@ -23,11 +22,6 @@ import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.andlib.utility.Preferences; import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.actfm.ActFmLoginActivity; import com.todoroo.astrid.actfm.ActFmLoginActivity;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService; import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.actfm.sync.ActFmSyncService;
import com.todoroo.astrid.billing.BillingConstants.PurchaseState;
import com.todoroo.astrid.billing.BillingConstants.ResponseCode;
import com.todoroo.astrid.billing.BillingService.RequestPurchase;
import com.todoroo.astrid.billing.BillingService.RestoreTransactions;
import com.todoroo.astrid.utility.Constants; import com.todoroo.astrid.utility.Constants;
public class BillingActivity extends Activity { public class BillingActivity extends Activity {
@ -36,15 +30,12 @@ public class BillingActivity extends Activity {
private static final int DIALOG_BILLING_NOT_SUPPORTED_ID = 2; private static final int DIALOG_BILLING_NOT_SUPPORTED_ID = 2;
private static final int DIALOG_SUBSCRIPTIONS_NOT_SUPPORTED_ID = 3; private static final int DIALOG_SUBSCRIPTIONS_NOT_SUPPORTED_ID = 3;
private static final String TRANSACTIONS_INITIALIZED = "premium_transactions_initialized"; //$NON-NLS-1$
private Handler handler; private Handler handler;
private BillingService billingService; private BillingService billingService;
private AstridPurchaseObserver purchaseObserver; private AstridPurchaseObserver purchaseObserver;
private Button buyMonth; private Button buyMonth;
private Button buyYear; private Button buyYear;
@Autowired private ActFmSyncService actFmSyncService;
@Autowired private ActFmPreferenceService actFmPreferenceService; @Autowired private ActFmPreferenceService actFmPreferenceService;
@ -59,7 +50,24 @@ public class BillingActivity extends Activity {
handler = new Handler(); handler = new Handler();
billingService = new BillingService(); billingService = new BillingService();
billingService.setContext(this); billingService.setContext(this);
purchaseObserver = new AstridPurchaseObserver(handler); purchaseObserver = new AstridPurchaseObserver(this, handler) {
@Override
protected void billingSupportedCallback() {
restoreTransactions();
buyMonth.setEnabled(true);
buyYear.setEnabled(true);
}
@Override
protected void billingNotSupportedCallback() {
showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
}
@Override
protected void subscriptionsNotSupportedCallback() {
showDialog(DIALOG_SUBSCRIPTIONS_NOT_SUPPORTED_ID);
}
};
ResponseHandler.register(purchaseObserver); ResponseHandler.register(purchaseObserver);
} }
@ -182,126 +190,9 @@ public class BillingActivity extends Activity {
} }
private void restoreTransactions() { private void restoreTransactions() {
boolean initialized = Preferences.getBoolean(TRANSACTIONS_INITIALIZED, false); boolean initialized = Preferences.getBoolean(BillingConstants.PREF_TRANSACTIONS_INITIALIZED, false);
if (!initialized) { if (!initialized) {
billingService.restoreTransactions(); billingService.restoreTransactions();
} }
} }
/**
* A {@link PurchaseObserver} is used to get callbacks when Android Market sends
* messages to this application so that we can update the UI.
*/
@SuppressWarnings("nls")
private class AstridPurchaseObserver extends PurchaseObserver {
public AstridPurchaseObserver(Handler handler) {
super(BillingActivity.this, handler);
}
@Override
public void onBillingSupported(boolean supported, String type) {
if (Constants.DEBUG) {
Log.i(TAG, "supported: " + supported);
}
if (type != null && type.equals(BillingConstants.ITEM_TYPE_SUBSCRIPTION)) {
if (supported) {
restoreTransactions();
buyMonth.setEnabled(true);
buyYear.setEnabled(true);
} else {
showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
}
} else {
showDialog(DIALOG_SUBSCRIPTIONS_NOT_SUPPORTED_ID);
}
}
@Override
public void onPurchaseStateChange(PurchaseState purchaseState, final String itemId,
int quantity, long purchaseTime, String developerPayload, final String purchaseToken) {
if (Constants.DEBUG) {
Log.i(TAG, "onPurchaseStateChange() itemId: " + itemId + " " + purchaseState);
}
Preferences.setString(BillingConstants.PREF_PRODUCT_ID, itemId);
Preferences.setString(BillingConstants.PREF_PURCHASE_TOKEN, purchaseToken);
if (purchaseState == PurchaseState.PURCHASED) {
new Thread() {
@Override
public void run() {
Preferences.setBoolean(ActFmPreferenceService.PREF_LOCAL_PREMIUM, true);
actFmSyncService.updateUserSubscriptionStatus(new Runnable() {
@Override
public void run() {
Preferences.setBoolean(ActFmPreferenceService.PREF_PREMIUM, true);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(BillingActivity.this, R.string.premium_success, Toast.LENGTH_LONG).show();
}
});
}
}, new Runnable() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(BillingActivity.this, R.string.premium_success_with_server_error, Toast.LENGTH_LONG).show();
}
});
}
});
}
}.start();
} else if (purchaseState == PurchaseState.REFUNDED || purchaseState == PurchaseState.EXPIRED) {
new Thread() {
@Override
public void run() {
Preferences.setBoolean(ActFmPreferenceService.PREF_LOCAL_PREMIUM, false);
actFmSyncService.updateUserSubscriptionStatus(null, null);
}
}.start();
}
}
@Override
public void onRequestPurchaseResponse(RequestPurchase request,
ResponseCode responseCode) {
if (Constants.DEBUG) {
Log.d(TAG, request.mProductId + ": " + responseCode);
}
if (responseCode == ResponseCode.RESULT_OK) {
if (Constants.DEBUG) {
Log.i(TAG, "purchase was successfully sent to server");
}
} else if (responseCode == ResponseCode.RESULT_USER_CANCELED) {
if (Constants.DEBUG) {
Log.i(TAG, "user canceled purchase");
}
} else {
if (Constants.DEBUG) {
Log.i(TAG, "purchase failed");
}
}
}
@Override
public void onRestoreTransactionsResponse(RestoreTransactions request,
ResponseCode responseCode) {
if (responseCode == ResponseCode.RESULT_OK) {
if (Constants.DEBUG) {
Log.d(TAG, "completed RestoreTransactions request");
}
// Update the shared preferences so that we don't perform
// a RestoreTransactions again.
Preferences.setBoolean(TRANSACTIONS_INITIALIZED, true);
} else {
if (Constants.DEBUG) {
Log.d(TAG, "RestoreTransactions error: " + responseCode);
}
}
}
}
} }

@ -55,6 +55,7 @@ public class BillingConstants {
public static final String PREF_PRODUCT_ID = ActFmPreferenceService.IDENTIFIER + "_inapp_product_id"; public static final String PREF_PRODUCT_ID = ActFmPreferenceService.IDENTIFIER + "_inapp_product_id";
public static final String PREF_PURCHASE_TOKEN = ActFmPreferenceService.IDENTIFIER + "_inapp_purchase_token"; public static final String PREF_PURCHASE_TOKEN = ActFmPreferenceService.IDENTIFIER + "_inapp_purchase_token";
public static final String PREF_NEEDS_SERVER_UPDATE = ActFmPreferenceService.IDENTIFIER + "_inapp_needs_server_update"; public static final String PREF_NEEDS_SERVER_UPDATE = ActFmPreferenceService.IDENTIFIER + "_inapp_needs_server_update";
public static final String PREF_TRANSACTIONS_INITIALIZED = "premium_transactions_initialized"; //$NON-NLS-1$
public static final char PUB_KEY_OBFUSCATION_CHAR = '!'; public static final char PUB_KEY_OBFUSCATION_CHAR = '!';
public static final char PUB_KEY_REPLACE_CHAR = 'B'; public static final char PUB_KEY_REPLACE_CHAR = 'B';

@ -28,7 +28,7 @@ import com.todoroo.astrid.billing.BillingService.RestoreTransactions;
*/ */
public abstract class PurchaseObserver { public abstract class PurchaseObserver {
protected static final String TAG = "purchase-observer"; //$NON-NLS-1$ protected static final String TAG = "purchase-observer"; //$NON-NLS-1$
private final Activity mActivity; protected final Activity mActivity;
private final Handler mHandler; private final Handler mHandler;
private Method mStartIntentSender; private Method mStartIntentSender;
private final Object[] mStartIntentSenderArgs = new Object[5]; private final Object[] mStartIntentSenderArgs = new Object[5];

@ -23,6 +23,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.database.sqlite.SQLiteException; import android.database.sqlite.SQLiteException;
import android.media.AudioManager; import android.media.AudioManager;
import android.os.Handler;
import android.util.Log; import android.util.Log;
import android.widget.Toast; import android.widget.Toast;
@ -41,6 +42,11 @@ import com.todoroo.astrid.activity.BeastModePreferences;
import com.todoroo.astrid.backup.BackupConstants; import com.todoroo.astrid.backup.BackupConstants;
import com.todoroo.astrid.backup.BackupService; import com.todoroo.astrid.backup.BackupService;
import com.todoroo.astrid.backup.TasksXmlImporter; import com.todoroo.astrid.backup.TasksXmlImporter;
import com.todoroo.astrid.billing.AstridPurchaseObserver;
import com.todoroo.astrid.billing.BillingConstants;
import com.todoroo.astrid.billing.BillingService;
import com.todoroo.astrid.billing.PurchaseObserver;
import com.todoroo.astrid.billing.ResponseHandler;
import com.todoroo.astrid.dao.Database; import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.gtasks.GtasksPreferenceService; import com.todoroo.astrid.gtasks.GtasksPreferenceService;
import com.todoroo.astrid.gtasks.sync.GtasksSyncService; import com.todoroo.astrid.gtasks.sync.GtasksSyncService;
@ -108,7 +114,7 @@ public class StartupService {
} }
/** Called when this application is started up */ /** Called when this application is started up */
public synchronized void onStartupApplication(final Context context) { public synchronized void onStartupApplication(final Activity context) {
if(hasStartedUp || context == null) if(hasStartedUp || context == null)
return; return;
@ -192,9 +198,30 @@ public class StartupService {
abTestInvoker.reportAcquisition(); abTestInvoker.reportAcquisition();
final Handler purchaseHandler = new Handler();
// perform startup activities in a background thread // perform startup activities in a background thread
new Thread(new Runnable() { new Thread(new Runnable() {
public void run() { public void run() {
final BillingService billingService = new BillingService();
billingService.setContext(context);
PurchaseObserver purchaseObserver = new AstridPurchaseObserver(context, purchaseHandler) {
@Override
protected void billingSupportedCallback() {
billingService.restoreTransactions();
}
@Override
protected void subscriptionsNotSupportedCallback() {/**/}
@Override
protected void billingNotSupportedCallback() {/**/}
};
ResponseHandler.register(purchaseObserver);
billingService.checkBillingSupported(BillingConstants.ITEM_TYPE_SUBSCRIPTION);
// start widget updating alarm // start widget updating alarm
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, WidgetUpdateService.class); Intent intent = new Intent(context, WidgetUpdateService.class);

Loading…
Cancel
Save