Skip to content

Commit

Permalink
Updating to APIv2
Browse files Browse the repository at this point in the history
  • Loading branch information
Nalini Sewak committed Aug 30, 2018
1 parent 6bee22c commit e5a17a0
Show file tree
Hide file tree
Showing 4 changed files with 379 additions and 192 deletions.
3 changes: 2 additions & 1 deletion app/build.gradle 100644 → 100755
Expand Up @@ -24,7 +24,8 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])

implementation 'com.google.android.gms:play-services:11.8.0'
implementation 'com.google.android.gms:play-services-wallet:16.0.0'
implementation 'com.android.support:appcompat-v7:24.1.1'

// "wallet" is the only module needed for the Google Payment API and this sample app.
// Apps that selectively compile Google Play service APIs need only this dependency.
Expand Down
200 changes: 147 additions & 53 deletions app/src/main/java/com/google/android/gms/samples/wallet/CheckoutActivity.java 100644 → 100755
Expand Up @@ -18,38 +18,55 @@

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.wallet.AutoResolveHelper;
import com.google.android.gms.wallet.IsReadyToPayRequest;
import com.google.android.gms.wallet.PaymentData;
import com.google.android.gms.wallet.PaymentDataRequest;
import com.google.android.gms.wallet.PaymentMethodToken;
import com.google.android.gms.wallet.PaymentsClient;
import com.google.android.gms.wallet.TransactionInfo;
import java.util.Optional;
import org.json.JSONException;
import org.json.JSONObject;

public class CheckoutActivity extends Activity {
// Arbitrarily-picked result code.
private static final int LOAD_PAYMENT_DATA_REQUEST_CODE = 991;

/**
* A client for interacting with the Google Pay API.
*
* @see <a
* href="https://developers.google.com/android/reference/com/google/android/gms/wallet/PaymentsClient">PaymentsClient</a>
*/
private PaymentsClient mPaymentsClient;

/**
* A Google Pay payment button presented to the viewer for interaction.
*
* @see <a href="https://developers.google.com/pay/api/android/guides/brand-guidelines">Google Pay
* payment button brand guidelines</a>
*/
private View mGooglePayButton;

// Arbitrarily-picked constant integer you define to track a request for payment data activity */
private static final int LOAD_PAYMENT_DATA_REQUEST_CODE = 991;

private TextView mGooglePayStatusText;

private ItemInfo mBikeItem = new ItemInfo("Simple Bike", 300 * 1000000, R.drawable.bike);
private long mShippingCost = 90 * 1000000;

/**
* Initialize the Google Pay API on creation of the activity
*
* @see Activity#onCreate(android.os.Bundle)
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Expand All @@ -61,23 +78,43 @@ protected void onCreate(Bundle savedInstanceState) {
mGooglePayButton = findViewById(R.id.googlepay_button);
mGooglePayStatusText = findViewById(R.id.googlepay_status);

mGooglePayButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
requestPayment(view);
}
});

// Initialize a Google Pay API client for an environment suitable for testing.
// It's recommended to create the PaymentsClient object inside of the onCreate method.
mPaymentsClient = PaymentsUtil.createPaymentsClient(this);
checkIsReadyToPay();
possiblyShowGooglePayButton();

mGooglePayButton.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
requestPayment(view);
}
});
}

private void checkIsReadyToPay() {
/**
* Determine the viewer's ability to pay with a payment method supported by your app and display a
* Google Pay payment button.
*
* @see <a href=
* "https://developers.google.com/android/reference/com/google/android/gms/wallet/PaymentsClient.html#isReadyToPay(com.google.android.gms.wallet.IsReadyToPayRequest)">PaymentsClient#IsReadyToPay</a>
*/
private void possiblyShowGooglePayButton() {
final Optional<JSONObject> isReadyToPayJson = PaymentsUtil.getIsReadyToPayRequest();
if (!isReadyToPayJson.isPresent()) {
return;
}
IsReadyToPayRequest request = IsReadyToPayRequest.fromJson(isReadyToPayJson.get().toString());
if (request == null) {
return;
}

// The call to isReadyToPay is asynchronous and returns a Task. We need to provide an
// OnCompleteListener to be triggered when the result of the call is known.
PaymentsUtil.isReadyToPay(mPaymentsClient).addOnCompleteListener(
Task<Boolean> task = mPaymentsClient.isReadyToPay(request);
task.addOnCompleteListener(
new OnCompleteListener<Boolean>() {
@Override
public void onComplete(Task<Boolean> task) {
try {
boolean result = task.getResult(ApiException.class);
Expand All @@ -90,11 +127,14 @@ public void onComplete(Task<Boolean> task) {
});
}

/**
* If isReadyToPay returned true, show the button and hide the "checking" text. Otherwise, notify
* the user that Pay with Google is not available. Please adjust to fit in with your current user
* flow. You are not required to explicitly let the user know if isReadyToPay returns false.
*
* @param available IsReadyToPay or not.
*/
private void setGooglePayAvailable(boolean available) {
// If isReadyToPay returned true, show the button and hide the "checking" text. Otherwise,
// notify the user that Pay with Google is not available.
// Please adjust to fit in with your current user flow. You are not required to explicitly
// let the user know if isReadyToPay returns false.
if (available) {
mGooglePayStatusText.setVisibility(View.GONE);
mGooglePayButton.setVisibility(View.VISIBLE);
Expand All @@ -103,9 +143,19 @@ private void setGooglePayAvailable(boolean available) {
}
}

/**
* Handle a resolved activity from the Google Pay payment sheet.
*
* @param requestCode Request code originally supplied to AutoResolveHelper in requestPayment().
* @param resultCode Result code returned by the Google Pay API.
* @param data Intent from the Google Pay API containing payment or error data.
* @see <a href="https://developer.android.com/training/basics/intents/result">Getting a result
* from an Activity</a>
*/
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
// value passed in AutoResolveHelper
case LOAD_PAYMENT_DATA_REQUEST_CODE:
switch (resultCode) {
case Activity.RESULT_OK:
Expand All @@ -120,6 +170,8 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
Status status = AutoResolveHelper.getStatusFromIntent(data);
handleError(status.getStatusCode());
break;
default:
// Do nothing.
}

// Re-enables the Pay with Google button.
Expand All @@ -128,41 +180,76 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
}
}

/**
* PaymentData response object contains the payment information, as well as any additional
* requested information, such as billing and shipping address.
*
* @param paymentData A response object returned by Google after a payer approves payment.
* @see <a
* href="https://developers.google.com/pay/api/android/reference/object#PaymentData">Payment
* Data
*/
private void handlePaymentSuccess(PaymentData paymentData) {
// PaymentMethodToken contains the payment information, as well as any additional
// requested information, such as billing and shipping address.
//
// Refer to your processor's documentation on how to proceed from here.
PaymentMethodToken token = paymentData.getPaymentMethodToken();

// getPaymentMethodToken will only return null if PaymentMethodTokenizationParameters was
// not set in the PaymentRequest.
String token = paymentData.toJson();

// Token will be null if PaymentDataRequest was not constructed using fromJson(String).
if (token != null) {
// If the gateway is set to example, no payment information is returned - instead, the
// token will only consist of "examplePaymentMethodToken".
if (token.getToken().equals("examplePaymentMethodToken")) {
AlertDialog alertDialog = new AlertDialog.Builder(this)
.setTitle("Warning")
.setMessage("Gateway name set to \"example\" - please modify " +
"Constants.java and replace it with your own gateway.")
.setPositiveButton("OK", null)
.create();
alertDialog.show();
}
JSONObject tokenObject;
try {
tokenObject = new JSONObject(token);
// If the gateway is set to example, no payment information is returned - instead, the
// token will only consist of "examplePaymentMethodToken".
if (tokenObject
.getJSONObject("paymentMethodData")
.getJSONObject("tokenizationData")
.getString("token")
.equals("examplePaymentMethodToken")) {
AlertDialog alertDialog =
new AlertDialog.Builder(this)
.setTitle("Warning")
.setMessage(
"Gateway name set to \"example\" - please modify "
+ "Constants.java and replace it with your own gateway.")
.setPositiveButton("OK", null)
.create();
alertDialog.show();
}

String billingName = paymentData.getCardInfo().getBillingAddress().getName();
Toast.makeText(this, getString(R.string.payments_show_name, billingName), Toast.LENGTH_LONG).show();
String billingName =
tokenObject
.getJSONObject("paymentMethodData")
.getJSONObject("info")
.getJSONObject("billingAddress")
.getString("name");
Log.d("BillingName", billingName);
Toast.makeText(this, getString(R.string.payments_show_name, billingName), Toast.LENGTH_LONG)
.show();

// Use token.getToken() to get the token string.
Log.d("PaymentData", "PaymentMethodToken received");
// Logging token string.
Log.d(
"PaymentData",
tokenObject
.getJSONObject("paymentMethodData")
.getJSONObject("tokenizationData")
.getString("token"));
} catch (JSONException e) {
Log.e("handlePaymentSuccess failed", e.toString());
return;
}
}
}

/**
* At this stage, the user has already seen a popup informing them an error occurred. Normally,
* only logging is required.
*
* @param statusCode will hold the value of any constant from CommonStatusCode or one of the
* WalletConstants.ERROR_CODE_* constants.
* @see <a
* href="https://developers.google.com/android/reference/com/google/android/gms/wallet/WalletConstants#constant-summary">Wallet
* Constants Library</a>
*/
private void handleError(int statusCode) {
// At this stage, the user has already seen a popup informing them an error occurred.
// Normally, only logging is required.
// statusCode will hold the value of any constant from CommonStatusCode or one of the
// WalletConstants.ERROR_CODE_* constants.
Log.w("loadPaymentData failed", String.format("Error code: %d", statusCode));
}

Expand All @@ -175,14 +262,21 @@ public void requestPayment(View view) {
// This price is not displayed to the user.
String price = PaymentsUtil.microsToString(mBikeItem.getPriceMicros() + mShippingCost);

TransactionInfo transaction = PaymentsUtil.createTransaction(price);
PaymentDataRequest request = PaymentsUtil.createPaymentDataRequest(transaction);
Task<PaymentData> futurePaymentData = mPaymentsClient.loadPaymentData(request);
// TransactionInfo transaction = PaymentsUtil.createTransaction(price);
Optional<JSONObject> paymentDataRequestJson = PaymentsUtil.getPaymentDataRequest(price);
if (!paymentDataRequestJson.isPresent()) {
return;
}
PaymentDataRequest request =
PaymentDataRequest.fromJson(paymentDataRequestJson.get().toString());

// Since loadPaymentData may show the UI asking the user to select a payment method, we use
// AutoResolveHelper to wait for the user interacting with it. Once completed,
// onActivityResult will be called with the result.
AutoResolveHelper.resolveTask(futurePaymentData, this, LOAD_PAYMENT_DATA_REQUEST_CODE);
if (request != null) {
AutoResolveHelper.resolveTask(
mPaymentsClient.loadPaymentData(request), this, LOAD_PAYMENT_DATA_REQUEST_CODE);
}
}

private void initItemUI() {
Expand Down
56 changes: 24 additions & 32 deletions app/src/main/java/com/google/android/gms/samples/wallet/Constants.java 100644 → 100755
Expand Up @@ -16,11 +16,9 @@

package com.google.android.gms.samples.wallet;

import android.util.Pair;

import com.google.android.gms.wallet.WalletConstants;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

public class Constants {
Expand All @@ -47,33 +45,26 @@ public class Constants {

// The allowed networks to be requested from the API. If the user has cards from networks not
// specified here in their account, these will not be offered for them to choose in the popup.
public static final List<Integer> SUPPORTED_NETWORKS = Arrays.asList(
WalletConstants.CARD_NETWORK_AMEX,
WalletConstants.CARD_NETWORK_DISCOVER,
WalletConstants.CARD_NETWORK_VISA,
WalletConstants.CARD_NETWORK_MASTERCARD
);

public static final List<Integer> SUPPORTED_METHODS = Arrays.asList(
// PAYMENT_METHOD_CARD returns to any card the user has stored in their Google Account.
WalletConstants.PAYMENT_METHOD_CARD,

// PAYMENT_METHOD_TOKENIZED_CARD refers to EMV tokenized credentials stored in the
// Google Pay app, assuming it's installed.
// Please keep in mind tokenized cards may exist in the Google Pay app without being
// added to the user's Google Account.
WalletConstants.PAYMENT_METHOD_TOKENIZED_CARD
);
public static final List<String> SUPPORTED_NETWORKS =
Arrays.asList("AMEX", "DISCOVER", "JCB", "VISA", "MASTERCARD");

/*
* The Google Pay API may return cards on file on Google.com (PAN_ONLY) and/or a device token on
* an Android device authenticated with a 3-D Secure cryptogram (CRYPTOGRAM_3DS).
*/
public static final List<String> SUPPORTED_METHODS =
Arrays.asList(
// Google Pay API can return cards on file on Google.com (PAN_ONLY)
"PAN_ONLY",
// and/or a device token on an Android device authenticated with a 3-D Secure cryptogram
"CRYPTOGRAM_3DS");

// Required by the API, but not visible to the user.
public static final String CURRENCY_CODE = "USD";

// Supported countries for shipping (use ISO 3166-1 alpha-2 country codes).
// Relevant only when requesting a shipping address.
public static final List<String> SHIPPING_SUPPORTED_COUNTRIES = Arrays.asList(
"US",
"GB"
);
public static final List<String> SHIPPING_SUPPORTED_COUNTRIES = Arrays.asList("US", "GB");

// The name of your payment processor / gateway. Please refer to their documentation for
// more information.
Expand All @@ -83,16 +74,17 @@ public class Constants {
// In many cases, your processor / gateway will only require a gatewayMerchantId.
// Please refer to your processor's documentation for more information. The number of parameters
// required and their names vary depending on the processor.
public static final List<Pair<String, String>> GATEWAY_TOKENIZATION_PARAMETERS = Arrays.asList(
Pair.create("gatewayMerchantId", "exampleGatewayMerchantId")

// Your processor may require additional parameters.
);
public static final HashMap<String, String> GATEWAY_TOKENIZATION_PARAMETERS =
new HashMap<String, String>() {
{
put("gateway", GATEWAY_TOKENIZATION_NAME);
put("gatewayMerchantId", "exampleGatewayMerchantId");
// Your processor may require additional parameters.
}
};

// Only used for DIRECT tokenization. Can be removed when using GATEWAY tokenization.
public static final String DIRECT_TOKENIZATION_PUBLIC_KEY = "REPLACE_ME";

private Constants() {
}

private Constants() {}
}

0 comments on commit e5a17a0

Please sign in to comment.