Slide 1

Slide 1 text

Streamlining Payments on Mobile Android Makers 2017

Slide 2

Slide 2 text

@Mathieu_Calba

Slide 3

Slide 3 text

@Mathieu_Calba

Slide 4

Slide 4 text

Payment is not Easy

Slide 5

Slide 5 text

Payment is not Easy Amazon

Slide 6

Slide 6 text

Payment is not Easy Amazon No Data Validation No Formatting No Limitation

Slide 7

Slide 7 text

Payment is not Easy Lydia

Slide 8

Slide 8 text

Payment is not Easy Lydia Pre-filling

Slide 9

Slide 9 text

Payment is not Easy Lydia No Formatting Simple data filling

Slide 10

Slide 10 text

Payment is not Easy Stripe

Slide 11

Slide 11 text

Payment is not Easy Stripe Format hints Card type recognition Formatting Error highlight

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

Compatible card types

Slide 14

Slide 14 text

Keep It Stupid and Simple

Slide 15

Slide 15 text

Keep It Stupid and Simple

Slide 16

Slide 16 text

Keep It Stupid and Simple Payment Account Number 4111 1111 1111 1111

Slide 17

Slide 17 text

Keep It Stupid and Simple Payment Account Number Expiration Date 4111 1111 1111 1111 04/17

Slide 18

Slide 18 text

Keep It Stupid and Simple Payment Account Number Expiration Date CVV 4111 1111 1111 1111 04/17 111

Slide 19

Slide 19 text

Keep It Stupid and Simple Payment Account Number Expiration Date CVV Holder Name 4111 1111 1111 1111 04/17 111 Bill Murray

Slide 20

Slide 20 text

Keep It Stupid and Simple Payment Account Number Expiration Date CVV Holder Name Terms of Sales 4111 1111 1111 1111 04/17 111 Bill Murray I agree with the Terms of Services of Android Makers

Slide 21

Slide 21 text

Keep It Stupid and Simple Payment Account Number Expiration Date CVV Holder Name Terms of Sales Pay Button 4111 1111 1111 1111 04/17 111 Bill Murray I agree with the Terms of Services of Android Makers PAY 123.00 €

Slide 22

Slide 22 text

Keep It Stupid and Simple Payment Account Number Expiration Date CVV Holder Name Terms of Sales Pay Button 4111 1111 1111 1111 04/17 111 Bill Murray I agree with the Terms of Services of Android Makers PAY 123.00 €

Slide 23

Slide 23 text

Testing it

Slide 24

Slide 24 text

Step 1 - Simplest Form ...

Slide 25

Slide 25 text

Step 1 - Simplest Form

Slide 26

Slide 26 text

Step 1 - Simplest Form Loose sense of what are we filling

Slide 27

Slide 27 text

Step 1 - Simplest Form Loose sense of what are we filling We can input whatever we want

Slide 28

Slide 28 text

Step 1 - Simplest Form Loose sense of what are we filling We can input whatever we want We have to manually select the next field

Slide 29

Slide 29 text

Step 1 - Simplest Form Loose sense of what are we filling We can input whatever we want We have to manually select the next field Keyboard not showing up automatically

Slide 30

Slide 30 text

Step 1 - Simplest Form Loose sense of what are we filling We can input whatever we want We have to manually select the next field Keyboard not showing up automatically

Slide 31

Slide 31 text

Taking care of these first form problems

Slide 32

Slide 32 text

Step 2 - Minimal Form Keep sense of what are we filling

Slide 33

Slide 33 text

Step 2 - Minimal Form Material Components for Android compile 'com.android.support:design:25.3.0' Keep sense of what are we filling

Slide 34

Slide 34 text

Step 2 - Minimal Form InputType Bit masking defining the basic content type of a text in an Editable object. Used by IME to determine which keyboard to display. Limit the input

Slide 35

Slide 35 text

Step 2 - Minimal Form 4 classes of InputType: TYPE_CLASS_DATETIME TYPE_CLASS_NUMBER TYPE_CLASS_PHONE TYPE_CLASS_TEXT Limit the input

Slide 36

Slide 36 text

Step 2 - Minimal Form Many flags & variations: TYPE_DATETIME_VARIATION_DATE TYPE_DATETIME_VARIATION_NORMAL TYPE_DATETIME_VARIATION_TIME TYPE_NUMBER_FLAG_DECIMAL TYPE_NUMBER_FLAG_SIGNED TYPE_NUMBER_VARIATION_NORMAL TYPE_TEXT_FLAG_AUTO_COMPLETE TYPE_TEXT_FLAG_AUTO_CORRECT TYPE_TEXT_FLAG_CAP_CHARACTERS Limit the input TYPE_TEXT_FLAG_CAP_SENTENCES TYPE_TEXT_FLAG_CAP_WORDS TYPE_TEXT_FLAG_MULTI_LINE TYPE_TEXT_FLAG_NO_SUGGESTIONS TYPE_TEXT_VARIATION_PASSWORD TYPE_TEXT_VARIATION_PERSON_NAME TYPE_TEXT_VARIATION_PHONETIC TYPE_TEXT_VARIATION_URI ...

Slide 37

Slide 37 text

Step 2 - Minimal Form TextView.setInputType(int type) Only change the input capabilities (keyboard, pasting, etc). Does NOT validate the input. Limit the input

Slide 38

Slide 38 text

Step 2 - Minimal Form android:inputType XML attribute Limit the input

Slide 39

Slide 39 text

Step 2 - Minimal Form Many flags & variations: date datetime none number numberDecimal numberSigned textAutoComplete textAutoCorrect textCapCharacters textCapSentences Limit the input textCapWords textImeMultiLine textMultiLine textNoSuggestions textPassword textPersonName textPhonetic textVisiblePassword time ...

Slide 40

Slide 40 text

Step 2 - Minimal Form Expiration Date TYPE_CLASS_DATETIME | TYPE_DATETIME_VARIATION_DATE or date Payment Account Number & CVV TYPE_CLASS_NUMBER | TYPE_NUMBER_VARIATION_NORMAL or number Card Holder TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PERSON_NAME or textPersonName Limit the input

Slide 41

Slide 41 text

Step 2 - Minimal Form Expiration Date TYPE_CLASS_DATETIME | TYPE_DATETIME_VARIATION_DATE or date Payment Account Number & CVV TYPE_CLASS_NUMBER | TYPE_NUMBER_VARIATION_NORMAL or number Card Holder TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PERSON_NAME or textPersonName Limit the input

Slide 42

Slide 42 text

Step 2 - Minimal Form Expiration Date TYPE_CLASS_DATETIME | TYPE_DATETIME_VARIATION_DATE or date Payment Account Number & CVV TYPE_CLASS_NUMBER | TYPE_NUMBER_VARIATION_NORMAL or number Card Holder TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PERSON_NAME or textPersonName Limit the input

Slide 43

Slide 43 text

Step 2 - Minimal Form Expiration Date TYPE_CLASS_DATETIME | TYPE_DATETIME_VARIATION_DATE or date Payment Account Number & CVV TYPE_CLASS_NUMBER | TYPE_NUMBER_VARIATION_NORMAL or number Card Holder TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PERSON_NAME or textPersonName Limit the input

Slide 44

Slide 44 text

Step 2 - Minimal Form TextView.setImeOptions (int imeOptions) Extend the type information for an Editor to improve IME integration with the application. Moving between inputs

Slide 45

Slide 45 text

Step 2 - Minimal Form Many actions & flags: IME_ACTION_DONE IME_ACTION_GO IME_ACTION_NEXT IME_ACTION_NONE IME_ACTION_PREVIOUS IME_ACTION_SEARCH IME_ACTION_SEND IME_ACTION_UNSPECIFIED Moving between inputs IME_FLAG_FORCE_ASCII IME_FLAG_NAVIGATE_NEXT IME_FLAG_NAVIGATE_PREVIOUS IME_FLAG_NO_ACCESSORY_ACTION IME_FLAG_NO_ENTER_ACTION IME_FLAG_NO_EXTRACT_UI IME_FLAG_NO_FULLSCREEN

Slide 46

Slide 46 text

Step 2 - Minimal Form android:imeOptions XML attribute Moving between inputs

Slide 47

Slide 47 text

Step 2 - Minimal Form Many actions & flags: actionDone actionGo actionNext actionNone actionPrevious actionSearch actionSend actionUnspecified Moving between inputs flagForceAscii flagNavigateNext flagNavigatePrevious flagNoAccessoryAction flagNoEnterAction flagNoExtractUi flagNoFullscreen normal

Slide 48

Slide 48 text

Step 2 - Minimal Form TextView.setOnEditorActionListener (OnEditorActionListener l) Help you react on the Keyboard action key press Moving between inputs

Slide 49

Slide 49 text

Step 2 - Minimal Form Going Next (all except Card Holder) IME_ACTION_NEXT or actionNext Done (Card Holder) IME_ACTION_DONE or actionDone Moving between inputs

Slide 50

Slide 50 text

Step 2 - Minimal Form When Activity starts Showing/Hiding Keyboard

Slide 51

Slide 51 text

Step 2 - Minimal Form android:windowSoftInputMode Activity attribute defining how it interacts with the window containing the keyboard. Showing/Hiding Keyboard

Slide 52

Slide 52 text

Step 2 - Minimal Form Can be a state and/or adjust. state: state of the keyboard when Activity becomes visible stateUnspecified (default) stateUnchanged stateHidden stateAlwaysHidden stateVisible stateAlwaysVisible Showing/Hiding Keyboard adjust: adjustments made to the Activity’s main Window adjustUnspecified (default) adjustResize adjustPan

Slide 53

Slide 53 text

Step 2 - Minimal Form Can be a state and/or adjust. state: state of the keyboard when Activity becomes visible stateUnspecified (default) stateUnchanged stateHidden stateAlwaysHidden stateVisible stateAlwaysVisible Showing/Hiding Keyboard adjust: adjustments made to the Activity’s main Window adjustUnspecified (default) adjustResize adjustPan

Slide 54

Slide 54 text

Step 2 - Minimal Form Hide the keyboard if shown when the user tap the terms and conditions checkbox Showing/Hiding Keyboard

Slide 55

Slide 55 text

Step 2 - Minimal Form On demand InputMethodManager.showSoftInput(View view, int flags) InputMethodManager.hideSoftInputFromWindow (IBinder windowToken, int flags) Showing/Hiding Keyboard

Slide 56

Slide 56 text

Step 2 - Minimal Form On demand public static void hideSoftKeyboard(Context context, View view) { InputMethodManager imm = (InputMethodManager) context. getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(view.getWindowToken(), 0); } public static void showSoftKeyboard(Context context, View view) { InputMethodManager imm = (InputMethodManager) context. getSystemService(Context.INPUT_METHOD_SERVICE); imm.showSoftInput(view, 0); } Showing/Hiding Keyboard

Slide 57

Slide 57 text

Step 2 - Minimal Form On demand public static void hideSoftKeyboard(Context context, View view) { InputMethodManager imm = (InputMethodManager) context. getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(view.getWindowToken(), 0); } public static void showSoftKeyboard(Context context, View view) { InputMethodManager imm = (InputMethodManager) context. getSystemService(Context.INPUT_METHOD_SERVICE); imm.showSoftInput(view, 0); } Showing/Hiding Keyboard

Slide 58

Slide 58 text

Step 2 - Minimal Form On demand public static void hideSoftKeyboard(Context context, View view) { InputMethodManager imm = (InputMethodManager) context. getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(view.getWindowToken(), 0); } public static void showSoftKeyboard(Context context, View view) { InputMethodManager imm = (InputMethodManager) context. getSystemService(Context.INPUT_METHOD_SERVICE); imm.showSoftInput(view, 0); } Showing/Hiding Keyboard

Slide 59

Slide 59 text

Adapting each Fields to its Kind of Content

Slide 60

Slide 60 text

First up: Expiration Date fields

Slide 61

Slide 61 text

Step 3 - Improving Expiration Date No data validation No error display

Slide 62

Slide 62 text

Step 3 - Improving Expiration Date Spinner are not suitable for month/year selection on mobile due to the large amount of possibilities Data Validation

Slide 63

Slide 63 text

Step 3 - Improving Expiration Date TextView.addTextChangedListener (TextWatcher watcher) Listener on user inputs Data Validation

Slide 64

Slide 64 text

Step 3 - Improving Expiration Date public interface TextWatcher extends NoCopySpan { public void beforeTextChanged(CharSequence text, int start, int count, int after); public void onTextChanged(CharSequence text, int start, int before, int count); public void afterTextChanged(Editable text); } Data Validation

Slide 65

Slide 65 text

Step 3 - Improving Expiration Date public interface TextWatcher extends NoCopySpan { public void beforeTextChanged(CharSequence text, int start, int count, int after); public void onTextChanged(CharSequence text, int start, int before, int count); public void afterTextChanged(Editable text); } Data Validation

Slide 66

Slide 66 text

Step 3 - Improving Expiration Date public interface TextWatcher extends NoCopySpan { public void beforeTextChanged(CharSequence text, int start, int count, int after); public void onTextChanged(CharSequence text, int start, int before, int count); public void afterTextChanged(Editable text); } Data Validation

Slide 67

Slide 67 text

Step 3 - Improving Expiration Date public interface TextWatcher extends NoCopySpan { public void beforeTextChanged(CharSequence text, int start, int count, int after); public void onTextChanged(CharSequence text, int start, int before, int count); public void afterTextChanged(Editable text); } Data Validation

Slide 68

Slide 68 text

Step 3 - Improving Expiration Date private ForegroundColorSpan mErrorSpan = new ForegroundColorSpan(Color.RED)); private boolean mIsEditing; @Override public void afterTextChanged(Editable text) { if (mIsEditing) { return; } mIsEditing = true; text.removeSpan(mErrorSpan); String expirationMonth = text.toString(); if (isExpirationMonthLengthValid(expirationMonth)) { if (!isExpirationMonthValid(expirationMonth)) { text.setSpan(mErrorSpan, 0, LENGTH_EXPIRATION_MONTH, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mEditView.setContentDescription("incorrect card expiration month"); mEditView.announceForAccessibility(mEditView.getContentDescription()); } } mIsEditing = false; } Data Validation

Slide 69

Slide 69 text

Step 3 - Improving Expiration Date private ForegroundColorSpan mErrorSpan = new ForegroundColorSpan(Color.RED)); private boolean mIsEditing; @Override public void afterTextChanged(Editable text) { if (mIsEditing) { return; } mIsEditing = true; text.removeSpan(mErrorSpan); String expirationMonth = text.toString(); if (isExpirationMonthLengthValid(expirationMonth)) { if (!isExpirationMonthValid(expirationMonth)) { text.setSpan(mErrorSpan, 0, LENGTH_EXPIRATION_MONTH, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mEditView.setContentDescription("incorrect card expiration month"); mEditView.announceForAccessibility(mEditView.getContentDescription()); } } mIsEditing = false; } Data Validation

Slide 70

Slide 70 text

Step 3 - Improving Expiration Date private ForegroundColorSpan mErrorSpan = new ForegroundColorSpan(Color.RED)); private boolean mIsEditing; @Override public void afterTextChanged(Editable text) { if (mIsEditing) { return; } mIsEditing = true; text.removeSpan(mErrorSpan); String expirationMonth = text.toString(); if (isExpirationMonthLengthValid(expirationMonth)) { if (!isExpirationMonthValid(expirationMonth)) { text.setSpan(mErrorSpan, 0, LENGTH_EXPIRATION_MONTH, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mEditView.setContentDescription("incorrect card expiration month"); mEditView.announceForAccessibility(mEditView.getContentDescription()); } } mIsEditing = false; } Data Validation

Slide 71

Slide 71 text

Step 3 - Improving Expiration Date private ForegroundColorSpan mErrorSpan = new ForegroundColorSpan(Color.RED)); private boolean mIsEditing; @Override public void afterTextChanged(Editable text) { if (mIsEditing) { return; } mIsEditing = true; text.removeSpan(mErrorSpan); String expirationMonth = text.toString(); if (isExpirationMonthLengthValid(expirationMonth)) { if (!isExpirationMonthValid(expirationMonth)) { text.setSpan(mErrorSpan, 0, LENGTH_EXPIRATION_MONTH, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mEditView.setContentDescription("incorrect card expiration month"); mEditView.announceForAccessibility(mEditView.getContentDescription()); } } mIsEditing = false; } Data Validation

Slide 72

Slide 72 text

Step 3 - Improving Expiration Date private ForegroundColorSpan mErrorSpan = new ForegroundColorSpan(Color.RED)); private boolean mIsEditing; @Override public void afterTextChanged(Editable text) { if (mIsEditing) { return; } mIsEditing = true; text.removeSpan(mErrorSpan); String expirationMonth = text.toString(); if (isExpirationMonthLengthValid(expirationMonth)) { if (!isExpirationMonthValid(expirationMonth)) { text.setSpan(mErrorSpan, 0, LENGTH_EXPIRATION_MONTH, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mEditView.setContentDescription("incorrect card expiration month"); mEditView.announceForAccessibility(mEditView.getContentDescription()); } } mIsEditing = false; } Data Validation

Slide 73

Slide 73 text

Step 3 - Improving Expiration Date Data Validation

Slide 74

Slide 74 text

Step 3 - Improving Expiration Date Lot of space wasted, maybe we could merge the expiration month and year fields into one ‣ Consolidate same kind of data together ‣ Allows us to validate the month with the year ‣ Make room for CVV on the right and Pay button moves up, making it always visible

Slide 75

Slide 75 text

Step 3 - Improving Expiration Date Lot of space wasted, maybe we could merge the expiration month and year fields into one ‣ Consolidate same kind of data together ‣ Allows us to validate the month with the year ‣ Make room for CVV on the right and Pay button moves up, making it always visible

Slide 76

Slide 76 text

Step 3 - Improving Expiration Date Lot of space wasted, maybe we could merge the expiration month and year fields into one ‣ Consolidate same kind of data together ‣ Allows us to validate the month with the year ‣ Make room for CVV on the right and Pay button moves up, making it always visible

Slide 77

Slide 77 text

Step 3 - Improving Expiration Date Lot of space wasted, maybe we could merge the expiration month and year fields into one ‣ Consolidate same kind of data together ‣ Allows us to validate the month with the year ‣ Make room for CVV on the right and Pay button moves up, making it always visible

Slide 78

Slide 78 text

Step 3 - Improving Expiration Date Using formatting pattern MM/YY Without letting the user enter / Optimising fields distribution

Slide 79

Slide 79 text

Step 3 - Improving Expiration Date private boolean mIsEditing; @Override public void afterTextChanged(Editable text) { if (mIsEditing) { return; } mIsEditing = true; // Remove filters because they prevent us from inserting // non-digit characters when inputType is set to "number" InputFilter[] inputFilters = text.getFilters(); text.setFilters(InputFilterUtils.EMPTY_FILTERS); [...] mIsEditing = false; } Optimising fields distribution

Slide 80

Slide 80 text

Step 3 - Improving Expiration Date @Override public void afterTextChanged(Editable text) { [...] // 1. We extract the expirationMonth and expirationYear String noSpaceText = getDigitOnlyText(text); int length = noSpaceText.length(); String expirationMonth = noSpaceText. substring(0, Math.min(length, LENGTH_EXPIRATION_PARTIAL)); String expirationYear = ""; if (noSpaceText.length() > LENGTH_EXPIRATION_PARTIAL) { expirationYear = noSpaceText.substring( LENGTH_EXPIRATION_PARTIAL, Math.min(length, LENGTH_EXPIRATION)); } [...] } Optimising fields distribution

Slide 81

Slide 81 text

Step 3 - Improving Expiration Date @Override public void afterTextChanged(Editable text) { [...] // 2. We try to format the newly entered text here CharSequence base = getFormattedExpirationDate( expirationMonth, expirationYear); text.removeSpan(mErrorSpan); text.replace(0, text.length(), base); // 3. We handle the error in this field like in previous slide // 4. Re-install filters text.setFilters(inputFilters); mIsEditing = false; } Optimising fields distribution

Slide 82

Slide 82 text

Step 3 - Improving Expiration Date @Override public void afterTextChanged(Editable text) { [...] // 2. We try to format the newly entered text here CharSequence base = getFormattedExpirationDate( expirationMonth, expirationYear); text.removeSpan(mErrorSpan); text.replace(0, text.length(), base); // 3. We handle the error in this field like in previous slide // 4. Re-install filters text.setFilters(inputFilters); mIsEditing = false; } Optimising fields distribution

Slide 83

Slide 83 text

Step 3 - Improving Expiration Date @Override public void afterTextChanged(Editable text) { [...] // 2. We try to format the newly entered text here CharSequence base = getFormattedExpirationDate( expirationMonth, expirationYear); text.removeSpan(mErrorSpan); text.replace(0, text.length(), base); // 3. We handle the error in this field like in previous slide // 4. Re-install filters text.setFilters(inputFilters); mIsEditing = false; } Optimising fields distribution

Slide 84

Slide 84 text

Step 3 - Improving Expiration Date Auto-advance to the next field!

Slide 85

Slide 85 text

Step 3 - Improving Expiration Date @Override public void afterTextChanged(Editable text) { [...] if (isMonthValid && isYearValid) { if (isExpirationDateValid(month, year)) { mCvvView.requestFocus(); CharSequence text = mCvvEditView.getText(); mCvvEditView.setSelection(text.length()); } } mIsEditing = false; } Auto-advance to the next field

Slide 86

Slide 86 text

Spreading these improvements

Slide 87

Slide 87 text

Step 4 - Improving PAN No formatting

Slide 88

Slide 88 text

Step 4 - Improving PAN No formatting No data validation

Slide 89

Slide 89 text

Step 4 - Improving PAN No formatting No data validation No error display

Slide 90

Slide 90 text

Step 4 - Improving PAN No formatting No data validation No error display

Slide 91

Slide 91 text

Step 4 - Improving PAN Many types of Cards, multiple formats Visa - 4xxx xxxx xxxx xxxx Formatting

Slide 92

Slide 92 text

Step 4 - Improving PAN Many types of Cards, multiple formats Visa - 4xxx xxxx xxxx xxxx Mastercard - 51xx xxxx xxxx xxxx -> 55xx xxxx xxxx xxxx Formatting

Slide 93

Slide 93 text

Step 4 - Improving PAN Many types of Cards, multiple formats Visa - 4xxx xxxx xxxx xxxx Mastercard - 51xx xxxx xxxx xxxx to 55xx xxxx xxxx xxxx American Express - 34xx xxxxx xxxxx and 37xx xxxxx xxxxx Formatting

Slide 94

Slide 94 text

Step 4 - Improving PAN Many types of Cards, multiple formats Visa - 4xxx xxxx xxxx xxxx Mastercard - 51xx xxxx xxxx xxxx to 55xx xxxx xxxx xxxx American Express - 34xx xxxxx xxxxx and 37xx xxxxx xxxxx and many others: https://en.wikipedia.org/wiki/Payment_card_number Formatting

Slide 95

Slide 95 text

Step 4 - Improving PAN Each type must validate the Luhn Algorithm: public static boolean checkLuhnValidity(String number) { int sum = 0; boolean isOdd = true; for (int i = number.length() - 1; i >= 0; i--) { String digitString = number.substring(i, i + 1); int digit = Integer.parseInt(digitString); sum += isOdd ? digit : digit / 5 + (digit << 1) % 10; isOdd = !isOdd; } return sum % 10 == 0; } Data Validation

Slide 96

Slide 96 text

Step 4 - Improving PAN Using same technics as with the Expiration Date field

Slide 97

Slide 97 text

Step 4 - Improving PAN Detect type of card

Slide 98

Slide 98 text

Step 4 - Improving PAN Detect type of card Validate it

Slide 99

Slide 99 text

Step 4 - Improving PAN Detect type of card Validate it Display type of card

Slide 100

Slide 100 text

Step 4 - Improving PAN Detect type of card Validate it Display type of card Handle CVV length

Slide 101

Slide 101 text

Step 4 - Improving PAN Detect type of card Validate it Display type of card Handle CVV length Display icon for each fields

Slide 102

Slide 102 text

Step 4 - Improving PAN Detect type of card Validate it Display type of card Handle CVV length Display icon for each fields

Slide 103

Slide 103 text

Keep it Safe for your Users (and for you)

Slide 104

Slide 104 text

Keep it Safe for your Users (and for you) WindowManager.LayoutParams.FLAG_SECURE Allows to configure a Window as secure Blocking screen capture

Slide 105

Slide 105 text

Keep it Safe for your Users (and for you) Before calling Activity.setContentView(), add: getWindow().setFlags( LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE) Blocking screen capture

Slide 106

Slide 106 text

Keep it Safe for your Users (and for you) Blocking screen capture

Slide 107

Slide 107 text

Keep it Safe for your Users (and for you) A webpage hosted by the bank to validate the identity of the person using the credit card Totally outside of our control and the control of your provider of payment 3D Secure

Slide 108

Slide 108 text

Keep it Safe for your Users (and for you) Webpage can take forever to load or can fail to load without any message Need to inform the user what’s happening Adding a permanent SnackBar or other in layout message indicating that the process is in progress, and what to do if nothing happens after some time 3D Secure

Slide 109

Slide 109 text

Keep it Contextual

Slide 110

Slide 110 text

Keep it Contextual Let the User know what he is paying Display the price directly on the Pay button

Slide 111

Slide 111 text

Adapt to your Users

Slide 112

Slide 112 text

Adapt to your Users Be frictionless on the payment Accept the most payment methods Adapt to your marketed countries (PayPal in Italy, SOFORT in Germany, etc) Use Android Pay if it’s available in your country (No France, thanks Google ) Remember their preferred payment method Multiple Payment Methods

Slide 113

Slide 113 text

Adapt to your Users How to adapt the UI with multiple payment methods and keeping it clean? No universal good way Depends on your business and what you want to optimise for Multiple Payment Methods

Slide 114

Slide 114 text

Adapt to your Users Expanding list with one entry per payment method Multiple Payment Methods

Slide 115

Slide 115 text

Adapt to your Users List with your preferred way of paying or the mostly used at the top promoted at the top Multiple Payment Methods

Slide 116

Slide 116 text

Adapt to your Users Directly select the preferred way of paying (or the mostly used) And add an access to other payment methods Multiple Payment Methods

Slide 117

Slide 117 text

No content

Slide 118

Slide 118 text

Remember for Them

Slide 119

Slide 119 text

–Me, right now “The better way to make a user fill in a form is to fill it for him”

Slide 120

Slide 120 text

Remember for Them Suggest saving payment cards on your server for recurring users, but do not force them to do so The perfect moment to suggest it is just after a payment succeed

Slide 121

Slide 121 text

Remember for Them Do it on the server, not locally, as some public organisations do not allow you to do so Server needs to be certified with PCI-DSS at a very high level, not an easy and quick thing to obtain

Slide 122

Slide 122 text

Remember for Them A saved payment card is probably the preferred way of paying, so make it the most accessible one

Slide 123

Slide 123 text

Remember for Them Autofill Framework Coming to Android O

Slide 124

Slide 124 text

Stay One Touch Away aka le Paiement Digital

Slide 125

Slide 125 text

Stay One Touch Away Do not force the user to use his fingerprint Fingerprint API

Slide 126

Slide 126 text

Stay One Touch Away Allow to use the CVV Fingerprint API

Slide 127

Slide 127 text

Stay One Touch Away API 23 min, but compatibility version available in support library Requires android.permission.USE_FINGERPRINT (not dangerous) Fingerprint API

Slide 128

Slide 128 text

Stay One Touch Away FingerprintManager Detect presence of Fingerprint hardware CTS enforce the presence of an hardware backed KeyStore for it to be compatible with the Android API Detect if any fingerprint is enrolled Authenticate a FingerprintManager.CryptoObject Fingerprint API

Slide 129

Slide 129 text

Stay One Touch Away FingerprintManager.CryptoObject Wrapper for using crypto objects with FingerprintManager Works on Cipher, Mac, and Signature objects Fingerprint API

Slide 130

Slide 130 text

Stay One Touch Away Mac Checks integrity of information transmitted over or stored in an unreliable medium, using a secret key known by each entities that want to read/write the information Fingerprint API

Slide 131

Slide 131 text

Stay One Touch Away Signature Provides digital signature algorithm Used for authentication and integrity assurance of digital data Fingerprint API

Slide 132

Slide 132 text

Stay One Touch Away Fingerprint API with Signature - enrolment My Application Server Payment Cards Fingerprint Manager create Signature for a PrivateKey 1 authenticate Signature 2 register Signature 3 save Signature 4 KeyStore

Slide 133

Slide 133 text

Stay One Touch Away Fingerprint API with Signature - payment My Application Server Payment Cards Fingerprint Manager create Signature for a PrivateKey 1 authenticate Signature 2 pay with Signature 3 validate Signature 4 5 access Payment Card KeyStore

Slide 134

Slide 134 text

Stay One Touch Away Cipher Cryptographic cipher for encryption and decryption Needs a transformation, aka the operations you want to apply to your input to get the output Fingerprint API

Slide 135

Slide 135 text

Stay One Touch Away Fingerprint API with Cipher - encryption My Application KeyStore Fingerprint Manager prepare Cipher with a SecretKey in encrypt mode 1 authenticate Cipher 2 Database save Cipher.getIV() and encrypted Data 4 encrypt Data with authenticated Cipher 3

Slide 136

Slide 136 text

Stay One Touch Away Fingerprint API with Cipher - encryption My Application KeyStore Server Payment Cards Fingerprint Manager prepare Cipher with a SecretKey and the IV in decrypt mode 2 authenticate Cipher 3 pay with decrypted Data 6 Database get the IV for this Data 1 decrypt Data with Cipher 5 get the encrypted Data 4

Slide 137

Slide 137 text

Stay One Touch Away Consult a security expert to know exactly what you can do with storing credit card data! Fingerprint API

Slide 138

Slide 138 text

Stay One Touch Away FingerprintManager.isHardwareDetected() Fingerprint API

Slide 139

Slide 139 text

Stay One Touch Away FingerprintManager.hasEnrolledFingerprints() Fingerprint API

Slide 140

Slide 140 text

Stay One Touch Away FingerprintManager.authenticate( CryptoObject crypto, int flags, CancellationSignal cancel, AuthenticationCallback callback, Handler handler) Fingerprint API

Slide 141

Slide 141 text

Stay One Touch Away public static abstract class AuthenticationCallback { public void onAuthenticationError(int errorCode, CharSequence errString) { } public void onAuthenticationHelp(int helpCode, CharSequence helpString) { } public void onAuthenticationSucceeded(AuthenticationResult result) { } public void onAuthenticationFailed() { } public void onAuthenticationAcquired(int acquireInfo) { } }; Fingerprint API

Slide 142

Slide 142 text

Questions?

Slide 143

Slide 143 text

Credits • Google Pixel device frames: Anjo Cerdeña https://material.uplabs.com/ posts/flat-google-pixel-svgs • Fonts: Yanone Kaffeesatz & Signika