Sample Applications

Sample apps, use cases, and UX strategies are included here to aid you in understanding the SDK and implementing it in your application. Sample source code and APKs can be downloaded from Download section.


Sample merchant app

Included with the Samsung Pay SDK to demonstrate its features, the sample merchant app shows you how to implement the payment sheet’s dynamic controls to leverage additional customer order and payment data and/or create a more custom UI look and feel.

The following payment sheet controls are available:

  • AddressControl
  • PlainTextControl
  • AmountBoxControl
  • SpinnerControl

Controls are applied to suit a particular purpose or need. For example, displaying a promotion notice in the payment sheet using the PlainTextControl.

Applying an AddressControl

This control is used to display the billing or shipping address on the payment sheet based on Samsung Pay’s My info user profile or addresses provided by your merchant app during the transaction request.

When creating the control, controlId and SheetItemType are needed to distinguish the billing address from the shipping address. Otherwise, your merchant app sets the following properties:

  • Address title – displays a merchant-defined title on the payment sheet. If empty, the default title (such as “Billing address”) is displayed.

  • Address – provides various methods to retrieve address details.
    The merchant app can retrieve the phone number using the 'getPhoneNumber'() method of 'CustomSheetPaymentInfo'.Address. Starting from API level 1.5, the addressee’s email address has also been added. Retrieve the email address using 'getEmail'(). You can also set a display option for the shipping address with 'setDisplayOption'(). For more information, see the Samsung Pay SDK-API reference Javadoc and the sample code included with the Samsung Pay SDK.

  • SheetUpdatedListener – used to capture the response from the Samsung Pay app; merchant app must deliver to the Samsung Pay app an AmountBoxControl to display payment information on a custom payment sheet. When the onResult() callback is called, the updateSheet() method must also be called to update the current payment sheet.

  • ErrorCode – used for containing error codes directly related to the address.

The workflows for BillingAddressControl and ShippingAddressControl are shown below.

BillingAddressControl


ShippingAddressControl

The following sample code demonstrates use of ddressControl on the payment sheet.

// For billing address
private AddressControl makeBillingAddressControl() {
    AddressControl billingAddressControl = new AddressControl(BILLING_ADDRESS_ID,SheetItemType.BILLING_ADDRESS);
    billingAddressControl.setAddressTitle("Billing Address [control]");
    //This callback is received when Controls are updated
    billingAddressControl.setSheetUpdatedListener(new SheetUpdatedListener() {
        @Override
        public void onResult(String updatedControlId, CustomSheet customSheet) {
            Log.d(TAG,"onResult billingAddressControl updatedControlId: " + updatedControlId);

            // Validate billing address and set errorCode, as needed
            AddressControl addressControl = AddressControl)customSheet.getSheetControl(updatedControlId);
            CustomSheetPaymentInfo.Address billAddress = addressControl.getAddress();
            int errorCode = validateBillingAddress(billAddress);
            Log.d(TAG, "onResult updateSheetBilling  errorCode: " + errorCode);
            addressControl.setErrorCode(errorCode);
            customSheet.updateControl(addressControl);
            // update transaction values
            AmountBoxControl amountBoxControl = (AmountBoxControl) 
            CustomSheet.getSheetControl(AMOUNT_CONTROL_ID);
            amountBoxControl.updateValue(PRODUCT_ITEM_ID, 1000);
            amountBoxControl.updateValue(PRODUCT_TAX_ID, 50);
            amountBoxControl.updateValue(PRODUCT_SHIPPING_ID, 10);
            amountBoxControl.updateValue(PRODUCT_FUEL_ID, 0, "Pending");
            amountBoxControl.setAmountTotal(1060, AmountConstants.FORMAT_TOTAL_PRICE_ONLY);
            customSheet.updateControl(amountBoxControl);
            // Call updateSheet for the full AmountBoxControl; mandatory
            try { 
                  paymentManager.updateSheet(customSheet);
            } catch (IllegalStateException | NullPointerException e) {
                  e.printStackTrace();
            }

        }
    });
    return billingAddressControl;
}

// For Shipping address
private AddressControl makeShippingAddressControl() {
    AddressControl shippingAddressControl = new AddressControl(SHIPPING_ADDRESS_ID, SheetItemType.SHIPPING_ADDRESS);
    shippingAddressControl.setAddressTitle("Shipping Address [control]");
    CustomSheetPaymentInfo.Address shippingAddress = new CustomSheetPaymentInfo.Address.Builder()
            .setAddressee("name")
            .setAddressLine1("addLine1")
            .setAddressLine2("addLine2")
            .setCity("city")
            .setState("state")
            .setCountryCode("USA")
            .setPostalCode("zip")
            .setPhoneNumber("555-123-1234")
            .setEmail("user@samsung.com")
            .build();
    shippingAddressControl.setAddress(shippingAddress);
    /*
     * Set address display option on custom payment sheet.
     * If displayOption is not set, then default addressControl is displayed on custom payment sheet.
     * The possible values are combination of below constants:
     *     {DISPLAY_OPTION_ADDRESSEE}
     *     {DISPLAY_OPTION_ADDRESS}
     *     {DISPLAY_OPTION_PHONE_NUMBER}
     *     {DISPLAY_OPTION_EMAIL}
     */
    int displayOption_val = AddressConstants.DISPLAY_OPTION_ADDRESSEE; // Addressee is mandatory
    displayOption_val += AddressConstants.DISPLAY_OPTION_ADDRESS;
    displayOption_val += AddressConstants.DISPLAY_OPTION_PHONE_NUMBER;
    displayOption_val += AddressConstants.DISPLAY_OPTION_EMAIL;
    shippingAddressControl.setDisplayOption(displayOption_val);
    return shippingAddressControl;
}

Here’s how these controls display on a custom payment sheet:
Billing Address control
Shippling Address control

Applying a PlainTextControl

This control is used for displaying a title with a two lines of text or a single line of text without a title on the payment sheet. When allocating this control, a controlId is needed. The merchant app sets both the title, as applicable, and the text. Diagrammed below is the flow between your merchant app and Samsung Pay.

![PlainTextControl flow]](https://d3unf4s5rp9dfh.cloudfront.net/SamsungPay_doc/7_1_3_PlainTextControl.png)

The merchant app code invoking this class would look something like the following:

private PlainTextControl makePlainTextControl() {
    PlainTextControl plainTextControl = new PlainTextControl("ExamplePlainTextControlId");
    plainTextControl.setText("Plain Text [example]", "This is example of PlainTextControl");
    return plainTextControl;
}

And this is how it displays on the custom payment sheet.
PlainTextControl flow

Applying an AmountBoxControl

AmountBoxControl is used for displaying purchase amount information on the payment sheet. It requires a controlId and a currencyCode, and consists of Item(s) and AmountTotal, defined as follows and diagrammed on the next page:

  • Item – consists of id, title, price, and extraPrice. If there is an extraPrice in AmountBoxControl, its text is displayed on the payment sheet even though there is an actual (numerical) price value. If there is no extraPrice, then currencyCode with the price value is displayed.
  • AmountTotal – consists of price and displayOption. The displayOption allows predefined strings only. Your merchant app can set the text to “Estimated amount”, “Amount pending”, “Pending”, “Free”, and so forth. The UI format for the string is different for each option.

For details, see the Javadoc Samsung Pay SDK-API Reference, available in the Documentation folder of your downloaded SDK package.
AmountBoxControl flow

Here’s a coding example to demonstrate the use of AmountBoxControl in a payment sheet.

private AmountBoxControl makeAmountControl() {
    AmountBoxControl amountBoxControl = new AmountBoxControl(AMOUNT_CONTROL_ID, "USD");
    amountBoxControl.addItem(PRODUCT_ITEM_ID, "Items", 1000, "");
    amountBoxControl.addItem(PRODUCT_TAX_ID, "Tax", 50, "");
    amountBoxControl.addItem(PRODUCT_SHIPPING_ID, "Shipping", 10, "");
    amountBoxControl.setAmountTotal(1060, AmountConstants.FORMAT_TOTAL_PRICE_ONLY);
    amountBoxControl.addItem(3, PRODUCT_FUEL_ID, "FUEL", 0, "Pending");
    return amountBoxControl;
}

The merchant app can also add new items using the 'addItem'() method of 'AmountControlBox' during callback.

Sample Merchant

When the custom sheet is updated, the merchant can add new items to AmountBoxControl. For example, if the user selects a specific card in the payment sheet which the merchant offers, a discount item can be added via the updateSheet().

// Example for adding new item while updating values
AmountBoxControl amount = (AmountBoxControl) sheet.getSheetControll("id_amount");

amount.updateValue("itemId", 900);
amount.updateValue("taxId", 50);
amount.updateValue("shippingId", 10);
amount.updateValue("fuelId", 0);

// Add “Discount” item
amount.addItem(4, "discountId", "Discount", -60, "");

amount.setAmountTotal(1000, AmountConstants.FORMAT_TOTAL_PRICE_ONLY);
sheet.updateControl(amount);

// Call updateSheet with AmountBoxControl; mandatory
try {
    paymentManager.updateSheet(sheet);
} catch (IllegalStateException | NullPointerException e) {
    e.printStackTrace();
}

Applying the SpinnerControl

This control is used for displaying Spinner options on a payment sheet. When creating the control, controlId, title, and SheetItemType are needed to distinguish between the types of spinner to be displayed. Your merchant app sets the following properties with SpinnerControl.

  • title – the merchant-defined Spinner title to appear the payment sheet.
  • SheetItemType – provides various types of Spinner.

A SHIPPING_METHOD_SPINNER and an INSTALLMENT_SPINNER are the two types of spinner available as of API level 1.6.

Here’s an example of constructing a SpinnerControl within your merchant app:

// Construct SpinnerControl for shipping method
SpinnerControl spinnerControl = new SpinnerControl(SHIPPINGMETHOD_SPINNER_ID, "Shipping Method ", 
      SheetItemType.SHIPPING_METHOD_SPINNER);
// Let the user can select one shipping method option on the payment sheet
spinnerControl.addItem("shipping_method_1", getString(R.string.standard_shipping_free));
spinnerControl.addItem("shipping_method_2", getString(R.string.twoday_shipping) );
spinnerControl.addItem("shipping_method_3", getString(R.string.oneday_shipping));
spinnerControl.setSelectedItemId("shipping_method_1"); // Set default option

// Listen for SheetControl events
spinnerControl.setSheetUpdatedListener(new SheetUpdatedListener() {
    @Override
    public void onResult(String updatedControlId, CustomSheet customSheet) {
        AmountBoxControl amountBoxControl = (AmountBoxControl) CustomSheet.getSheetControl(AMOUNT_CONTROL_ID);
        SpinnerControl spinnerControl = (SpinnerControl) CustomSheet.getSheetControl(updatedControlId);
        switch (spinnerControl.getSelectedItemId()) {
            case "shipping_method_1":
                amountBoxControl.updateValue(PRODUCT_SHIPPING_ID, 10);
                break;
            case "shipping_method_2":
                amountBoxControl.updateValue(PRODUCT_SHIPPING_ID, 10 + 0.1);
                break;
             case "shipping_method_3":
                  amountBoxControl.updateValue(PRODUCT_SHIPPING_ID, 10 + 0.2);
                  break;
            default:
                amountBoxControl.updateValue(PRODUCT_SHIPPING_ID, 10);
                break;
        }
        amountBoxControl.setAmountTotal(1000 + amountBoxControl.getValue(PRODUCT_SHIPPING_ID), 
             AmountConstants.FORMAT_TOTAL_PRICE_ONLY);
        customSheet.updateControl(amountBoxControl);

        // Call updateSheet with AmountBoxControl; mandatory.
        try {
            paymentManager.updateSheet(customSheet);
        } catch (IllegalStateException | NullPointerException e) {
            e.printStackTrace();
        }
    }
});

// Construct SpinnerControl for installment plan
SpinnerControl spinnerControl = new SpinnerControl(INSTALLMENT_SPINNER_ID, "Installment",  
        SheetItemType.INSTALLMENT_SPINNER);
spinnerControl.addItem("installment_1", "1 month without interest");
spinnerControl.addItem("installment_2", "2 months with 2% monthly interest");
spinnerControl.addItem("installment_3", "3 months with 2.2% monthly interest");
spinnerControl.setSelectedItemId("installment_1"); // Set default option

// Listen for SheetControl events
spinnerControl.setSheetUpdatedListener(new SheetUpdatedListener() {
    @Override
    public void onResult(String updatedControlId, CustomSheet customSheet) {
        AmountBoxControl amountBoxControl = (AmountBoxControl);    
        CustomSheet.getSheetControl(AMOUNT_CONTROL_ID);
        SpinnerControl spinnerControl = (SpinnerControl) CustomSheet.getSheetControl(updatedControlId);
        double totalInterest = 0;
        switch (spinnerControl.getSelectedItemId()) {
            case "installment1":
                amountBoxControl.updateValue(PRODUCT_TOTAL_INTEREST_ID, totalInterest);
                break;
            case "installment2":
                // Calculate total interest again and updateValue
                amountBoxControl.updateValue(PRODUCT_TOTAL_INTEREST_ID, totalInterest);
                break;
            case "installment3":
                // Calculate total interest again and updateValue
                amountBoxControl.updateValue(PRODUCT_TOTAL_INTEREST_ID, totalInterest);
                break;
            default:
                amountBoxControl.updateValue(PRODUCT_TOTAL_INTEREST_ID, totalInterest);
                break;
        }
        amountBoxControl.setAmountTotal(1000 + amountBoxControl.getValue(PRODUCT_TOTAL_INTEREST_ID), 
               AmountConstants.FORMAT_TOTAL_PRICE_ONLY);
        customSheet.updateControl(amountBoxControl);

        // Call updateSheet with AmountBoxControl; mandatory.
        try {
            paymentManager.updateSheet(customSheet);
        } catch (IllegalStateException | NullPointerException e) {
            e.printStackTrace();
        }
     }
});

Update sheet with custom error message

To display a custom error message on the payment sheet, use updateSheet with customErrorMessage.

void updateSheet(final CustomSheet sheet, final int errorCode, final String customErrorMessage)

This API method is an extended version of the existing updateSheet(sheet) method which gives the merchant the ability to display a custom error message in the payment sheet’s authentication area. It can be used to inform the user of any foreseen error scenarios encountered.

// Update sheet with CUSTOM_MESSSAGE error code
paymentManager.updateSheet(customSheet, PaymentManager.CUSTOM_MESSAGE, 
       "Phone number entered is not valid. Please change your phone number.");

Sample issuer app

The Samsung Pay SDK also provides a sample issuer app to showcase Samsung Pay SDK features.

Sample Issuer application

For more information, refer to the Javadoc Samsung Pay SDK API reference and sample code.