/* Copyright 2011 Robot Media SL (http://www.robotmedia.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.robotmedia.billing;
import android.app.PendingIntent;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
import com.android.vending.billing.IMarketBillingService;
public abstract class BillingRequest {
public static class CheckBillingSupported extends BillingRequest {
public CheckBillingSupported(String packageName, int startId) {
super(packageName, startId);
}
@Override
public String getRequestType() {
return REQUEST_TYPE_CHECK_BILLING_SUPPORTED;
}
@Override
protected void processOkResponse(Bundle response) {
final boolean supported = this.isSuccess();
BillingController.onBillingChecked(supported);
}
}
public static class CheckSubscriptionSupported extends BillingRequest {
public CheckSubscriptionSupported(String packageName, int startId) {
super(packageName, startId);
}
@Override
protected int getAPIVersion() {
return 2;
};
@Override
public String getRequestType() {
return REQUEST_TYPE_CHECK_BILLING_SUPPORTED;
}
@Override
protected void processOkResponse(Bundle response) {
final boolean supported = this.isSuccess();
BillingController.onSubscriptionChecked(supported);
}
@Override
protected void addParams(Bundle request) {
request.putString(KEY_ITEM_TYPE, ITEM_TYPE_SUBSCRIPTION);
}
}
public static class ConfirmNotifications extends BillingRequest {
private String[] notifyIds;
private static final String KEY_NOTIFY_IDS = "NOTIFY_IDS";
public ConfirmNotifications(String packageName, int startId, String[] notifyIds) {
super(packageName, startId);
this.notifyIds = notifyIds;
}
@Override
protected void addParams(Bundle request) {
request.putStringArray(KEY_NOTIFY_IDS, notifyIds);
}
@Override
public String getRequestType() {
return "CONFIRM_NOTIFICATIONS";
}
}
public static class GetPurchaseInformation extends BillingRequest {
private String[] notifyIds;
private static final String KEY_NOTIFY_IDS = "NOTIFY_IDS";
public GetPurchaseInformation(String packageName, int startId, String[] notifyIds) {
super(packageName,startId);
this.notifyIds = notifyIds;
}
@Override
protected void addParams(Bundle request) {
request.putStringArray(KEY_NOTIFY_IDS, notifyIds);
}
@Override
public String getRequestType() {
return "GET_PURCHASE_INFORMATION";
}
@Override public boolean hasNonce() { return true; }
}
public static class RequestPurchase extends BillingRequest {
private String itemId;
private String developerPayload;
private static final String KEY_ITEM_ID = "ITEM_ID";
private static final String KEY_DEVELOPER_PAYLOAD = "DEVELOPER_PAYLOAD";
private static final String KEY_PURCHASE_INTENT = "PURCHASE_INTENT";
public RequestPurchase(String packageName, int startId, String itemId, String developerPayload) {
super(packageName, startId);
this.itemId = itemId;
this.developerPayload = developerPayload;
}
@Override
protected void addParams(Bundle request) {
request.putString(KEY_ITEM_ID, itemId);
if (developerPayload != null) {
request.putString(KEY_DEVELOPER_PAYLOAD, developerPayload);
}
}
@Override
public String getRequestType() {
return "REQUEST_PURCHASE";
}
@Override
public void onResponseCode(ResponseCode response) {
super.onResponseCode(response);
BillingController.onRequestPurchaseResponse(itemId, response);
}
@Override
protected void processOkResponse(Bundle response) {
final PendingIntent purchaseIntent = response.getParcelable(KEY_PURCHASE_INTENT);
BillingController.onPurchaseIntent(itemId, purchaseIntent);
}
}
public static class RequestSubscription extends RequestPurchase {
public RequestSubscription(String packageName, int startId, String itemId, String developerPayload) {
super(packageName, startId, itemId, developerPayload);
}
@Override
protected void addParams(Bundle request) {
super.addParams(request);
request.putString(KEY_ITEM_TYPE, ITEM_TYPE_SUBSCRIPTION);
}
@Override
protected int getAPIVersion() {
return 2;
}
}
public static enum ResponseCode {
RESULT_OK, // 0
RESULT_USER_CANCELED, // 1
RESULT_SERVICE_UNAVAILABLE, // 2
RESULT_BILLING_UNAVAILABLE, // 3
RESULT_ITEM_UNAVAILABLE, // 4
RESULT_DEVELOPER_ERROR, // 5
RESULT_ERROR; // 6
public static boolean isResponseOk(int response) {
return ResponseCode.RESULT_OK.ordinal() == response;
}
// Converts from an ordinal value to the ResponseCode
public static ResponseCode valueOf(int index) {
ResponseCode[] values = ResponseCode.values();
if (index < 0 || index >= values.length) {
return RESULT_ERROR;
}
return values[index];
}
}
public static class RestoreTransactions extends BillingRequest {
public RestoreTransactions(String packageName, int startId) {
super(packageName, startId);
}
@Override
public String getRequestType() {
return "RESTORE_TRANSACTIONS";
}
@Override public boolean hasNonce() { return true; }
@Override
public void onResponseCode(ResponseCode response) {
super.onResponseCode(response);
if (response == ResponseCode.RESULT_OK) {
BillingController.onTransactionsRestored();
}
}
}
public static final String ITEM_TYPE_SUBSCRIPTION = "subs";
private static final String KEY_API_VERSION = "API_VERSION";
private static final String KEY_BILLING_REQUEST = "BILLING_REQUEST";
private static final String KEY_ITEM_TYPE = "ITEM_TYPE";
private static final String KEY_NONCE = "NONCE";
private static final String KEY_PACKAGE_NAME = "PACKAGE_NAME";
protected static final String KEY_REQUEST_ID = "REQUEST_ID";
private static final String KEY_RESPONSE_CODE = "RESPONSE_CODE";
private static final String REQUEST_TYPE_CHECK_BILLING_SUPPORTED = "CHECK_BILLING_SUPPORTED";
public static final long IGNORE_REQUEST_ID = -1;
private String packageName;
private int startId;
private boolean success;
private long nonce;
public BillingRequest(String packageName,int startId) {
this.packageName = packageName;
this.startId=startId;
}
protected void addParams(Bundle request) {
// Do nothing by default
}
protected int getAPIVersion() {
return 1;
}
public long getNonce() {
return nonce;
}
public abstract String getRequestType();
public boolean hasNonce() {
return false;
}
public boolean isSuccess() {
return success;
}
protected Bundle makeRequestBundle() {
final Bundle request = new Bundle();
request.putString(KEY_BILLING_REQUEST, getRequestType());
request.putInt(KEY_API_VERSION, getAPIVersion());
request.putString(KEY_PACKAGE_NAME, packageName);
if (hasNonce()) {
request.putLong(KEY_NONCE, nonce);
}
return request;
}
public void onResponseCode(ResponseCode responde) {
// Do nothing by default
}
protected void processOkResponse(Bundle response) {
// Do nothing by default
}
public long run(IMarketBillingService mService) throws RemoteException {
final Bundle request = makeRequestBundle();
addParams(request);
final Bundle response;
try {
response = mService.sendBillingRequest(request);
} catch (NullPointerException e) {
Log.e(this.getClass().getSimpleName(), "Known IAB bug. See: http://code.google.com/p/marketbilling/issues/detail?id=25", e);
return IGNORE_REQUEST_ID;
}
if (validateResponse(response)) {
processOkResponse(response);
return response.getLong(KEY_REQUEST_ID, IGNORE_REQUEST_ID);
} else {
return IGNORE_REQUEST_ID;
}
}
public void setNonce(long nonce) {
this.nonce = nonce;
}
protected boolean validateResponse(Bundle response) {
final int responseCode = response.getInt(KEY_RESPONSE_CODE);
success = ResponseCode.isResponseOk(responseCode);
if (!success) {
Log.w(this.getClass().getSimpleName(), "Error with response code " + ResponseCode.valueOf(responseCode));
}
return success;
}
public int getStartId() {
return startId;
}
}