Professional Documents
Culture Documents
APOS_Development_Best_Pratices_WL
APOS_Development_Best_Pratices_WL
Best Practices
APOS A8
1.1
Public
www.ingenico.com
28/32, boulevard de Grenelle, 75015 Paris - France / (T) +33 (0)1 58 01 80 00 / (F) +33 (0)1 58 01 91 35
Ingenico Group – S.A. au capital de 61 493 241 € / 317 218 758 RCS PARIS
1.1 Development Best Practices Public
Contents
1 Introduction........................................................................................ 4
1_1 Purpose and Scope............................................................................................. 4
2 APOS A8 ............................................................................................. 5
2_1 USDK .................................................................................................................. 5
2_2 BC ....................................................................................................................... 5
7 Development hints........................................................................... 27
7_1 Inserting test encryption keys............................................................................ 27
Mapping KAP ID to BC ............................................................................................................... 27
1 Introduction
This guide will help to understand what it should be considered in the application development to
prevent misusage of the equipment. Thus, all the tips found here will require someone to write code. It
is not the scope of this document teaching:
Android development
How to write a payment application
Either BC or EMV concepts
How to use the A8 Settings screen
Read this guide to understand and make best use of your terminal in order to create a reliable and
stable application.
2 APOS A8
Creating applications to run on an APOS A8 device will eventually use non-Android hardware
modules, and to access those modules it will require either the USDK library or the BC APOS library.
2_1 USDK
The USDK is a service which supports many APIs for using the terminal device functions. If any
application wants to use the terminal device functions, it needs to register on service.
To detailed guide on what is in the interface and how to use, please access the link
https://arke.landicorp.com/en/sdk-introduction.
2_2 BC
BC is an acronym to Biblioteca Compartilhada (“Shared Library” in English) and is a specification
currently maintained by Associção Brasileira das Empresas de Cartão e Serviços (as known as
ABECS) consortium. ABECS is compound by the main credit card issuers, card brands, acquirers and
processors in Brazil.
BC specification aims to simplify and normalize card transaction process. Ingenico delivers an Android
library that implements the BC specification version 1.08a. This library is intended to use on APOS
terminals, and it includes the USDK library internally.
BC APOS
USDK
3 Customizing terminal
This section will show how to customize an APOS to provide a better experience to users.
In order to prevent this, the application must enable or disable programmatically using UStatusBar.
NOTE: This is feature requires BC 4.15 or USDK version 2.3.5_20190805.
Code snippet
Code snippet
This feature is provided by Android default launcher. In order to disable this there is two ways:
Customer develops custom launcher to replace the default. This is a too heavy job.
If default launcher is used, customer can disable [uninstall] function on specific app. See the flow
below:
A strategy is to apply protection to second level of settings, in this case, the Apps settings.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cleaner);
Toast.makeText(this, "Cannot delete data!", Toast.LENGTH_LONG).show();
finish();
}
}
After installing the app in the device, the Clear data button will change to Manage space. By clicking
it, it will invoke the activity referenced in the android:manageSpaceActivity attribute. In this
example, it will prompt the message Cannot delete data!
Code snippet
Terminal requirements
The ‘disorder’ property is not available in all terminals. Only terminals with hardware number ending
with “3” allow sort the PIN input keys.
According to PCI and UnionPay security specifications, the virtual PIN entry numbers shall be random
to promote the security. So, setting the ‘disorder’ property to false is not recommended.
When there is no guarantee every terminal has a proper hardware ending number, it is recommended
the application checks it. See below the snippet of a code to check whether the terminal allows sorting
the virtual PIN keys.
Package name
This is the value in the Android manifest file inserted when the project was created. For example:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ingenico.lar.bcapp">
SHA256 value
Every Android application must be generated with a signature key store. This key store may be
created using a tool that has this purpose. The next example considers that the Android project uses a
key store file, called myapp.keystore, and shows how to get the value SHA256 to add in the Jira ticket
and get the API key.
C:\Users\jwick>keytool -list -v -keystore myapp.keystore
Enter keystore password:
Keystore type: jks
Keystore provider: SUN
API key
Based on the package name and the SHA256 value, Ingenico will generate the corresponding API-key
value to add in the Android manifest file, inside the application element, as seen in the following
example.
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
…
<meta-data
android:name="com.android.settings.API_KEY"
android:value="4332706C38432B756671767844336A54694A4E7356696957493437744E4A7870394
F76636B50414661486F6E6D74704F646F5338623256746E524D516F39744C324470647547632B32436
2490A6566396175574479632B7265666B664F75307475653846783434413659746B476E48713554556
C34746E7238334A695A7A6B557266545068652F384D4C6E432B626352544E6F5668327164580A51475
97157385649496E6C484A437673557464635A4D376E49535672735979336A394773564D575331464F6
E6E62513549346943453641792F3242704B783750676D4B642F514C4338656F330A5971677346366A6
F4D6F753159666D5757717948314D6444373432554149355A555659767467565852454953704930664
74E7A7A576D3643557A4B45693764657A55776B6E656955533552330A5746417838336262597773684
74B35593875526D695975777A63716A4F5771536A7673776D673D3D0A" />
…
</application>
AIDL files
The Android Interface Definition Language (AIDL) allows to define the programming interface that both
the client and service agree upon in order to communicate with each other using interprocess
communication (IPC).
According to Android documentation, you must define your AIDL interface in an .aidl file, then save it
in the source code (in the src/ directory) of both the application hosting the service and any other
application that binds to the service.
When you build each application that contains the .aidl file, the Android SDK tools generate an IBinder
interface based on the .aidl file and save it in the project's gen/ directory. The service must implement
the IBinder interface as appropriate. The client applications can then bind to the service and call
methods from the IBinder to perform IPC.
To create a bounded service using AIDL, follow these steps:
1. Create the .aidl file: this file defines the programming interface with method signatures.
2. Implement the interface: the Android SDK tools generate an interface in the Java
programming language, based on your .aidl file. This interface has an inner abstract class
named Stub that extends Binder and implements methods from your AIDL interface. You must
extend the Stub class and implement the methods.
3. Expose the interface to clients: implement a Service and override onBind() to return your
implementation of the Stub class.
NOTE: for further information of how AIDL file works consult the Android
documentation at https://developer.android.com/guide/components/aidl.
The application must implement the two AIDLs: IAuthorityCallback.aidl and IAuthorityRequest.aidl. In
both files the package name must be “com.android.settings.authority”.
interface IAuthorityRequest {
List<String> requestAuthScreen();
Intent requestAuthority();
void setAuthorityCallback(IAuthorityCallback callback);
}
This is the interface the service should implement.
To implement the interface generated from the .aidl, extend the generated Binder interface and
implement the methods inherited from the .aidl file. Here is an example implementation of the interface
called IAuthorityRequest (defined by the IAuthorityRequest.aidl) using an anonymous
instance:
private IAuthorityRequest mBinder = new IAuthorityRequest.Stub() {
@Override
public List<String> requestAuthScreen() throws RemoteException {
List<String> lists = new ArrayList<>();
lists.add("Main");
return lists;
// return null; // if you wants to not require any password
}
@Override
public Intent requestAuthority() throws RemoteException {
String packageName =
getApplicationContext().getPackageManager().getNameForUid(Binder.getCallingUid());
@Override
public void setAuthorityCallback(IAuthorityCallback callback) throws
RemoteException {
mAuthorityCallback = callback;
if (callback == null) {
mHandler.removeMessages(1);
}
}
};
Now the binder is an instance of the Stub class (a Binder), which defines the RPC interface for the
service.
@Override
public List<String> requestAuthScreen() throws RemoteException {
…
}
@Override
public Intent requestAuthority() throws RemoteException {
…
}
@Override
public void setAuthorityCallback(IAuthorityCallback callback) throws
RemoteException {
…
}
};
@Override
public IBinder onBind(Intent intent) {
return mBinder.asBinder();
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
}
Now you have a basic service structure to handle the authorization process.
Main Main
WLAN Wifi
Bluetooth Bluetooth
Ethernet Ethernet
Buttons Button
Display Display
Storage Memory
Battery PowerUsage
Apps ManageApplications
Profiles
Location Location
Security Security
Accessibility Accessibility
Printing Print
Example
Suppose the customer wants to request a password for WLAN and Apps settings only. The following
code snippet shows how to set this.
@Override
public List<String> requestAuthScreen() throws RemoteException {
List<String> lists = new ArrayList<>();
lists.add("Wifi");
lists.add("ManageApplications");
return lists;
}
The requestAuthority() method will return an intent object with the action that will invoke our
activity.
@Override
public Intent requestAuthority() throws RemoteException {
Intent intent = new Intent("com.android.settings.ACTION.CUST_AUTHORITY");
return intent;
}
The authority service will invoke our MainActivity.java. When it verifies the password, it will finish
setting a proper result of the authorization.
public class MainActivity extends AppCompatActivity {
…
private void setResult(boolean result, String errorMsg) {
Log.d(TAG, "setResult: result=" + result+ ";errorMsg=" + errorMsg);
Intent intent = new Intent();
intent.putExtra("auth_result", result);
intent.putExtra("auth_result_error_msg", errorMsg);
setResult(1000, intent);
finish();
}
…
}
The setAuthorityCallback() method will save the callback object that the device authority will
send:
@Override
public void setAuthorityCallback(IAuthorityCallback callback) throws
RemoteException {
mAuthorityCallback = callback;
}
Then, somewhere in the application structure, it will invoke the onAuthorityCallBack() method to
send the auth result.
try {
mAuthorityCallback.onAuthorityCallBack(false, "my error message...");
} catch (RemoteException e) {
}
Setting list
There are some extras settings the application may change to adjust the skin according to merchant
needs.
/ List of settings
Setting Type Description
String The skin that will be prompt. If this setting isn’t sent, the device
skin_name
default skin will be set.
gravity Integer The location of the virtual PIN PAD. If this setting isn’t sent, the
skin default will take effect.
skb_x Integer The X-pixel coordinate of the virtual PIN PAD. If this setting isn’t
sent, the skin default will take effect.
skb_y Integer The Y-pixel coordinate of the virtual PIN PAD. If this setting isn’t
sent, the skin default will take effect.
skb_width Integer The width of the virtual PIN PAD, ranging from -1 to MAX. The
value -1 means “match_parent”. If this setting isn’t sent, the
skin default will take effect.
skb_height Integer The height of the virtual PIN PAD, ranging from -1 to MAX. The
value -1 means “match_parent”. If this setting isn’t sent, the
skin default will take effect.
show_input Boolean Whether to show the text view or not. If it is true, then the text
view of the skin will be shown (as View.VISIBLE), otherwise it
will be hidden (as View.GONE). The text view is a view in the
skin layout, which shows the user PIN as character “*”.
custom_text String[] This extra can set the text of TextView on the skin layout. The
value is a list of String pairs, where the first String is the id of the
TextView, and the second is the text to show.
handle_back_key Boolean Whether to handle back key of the device. If true, then pressing
the back key on the device will be able to exit virtual PIN PAD,
otherwise you can only exit the virtual PIN PAD by press the
cancel button on virtual PIN PAD.
dim_amount Integer The alpha of virtual PIN PAD dim. The range goes from 0, that is
[0, 100] transparent setting, to 100 will be all black. The virtual PIN PAD
is a Dialog that when it is prompted, the screen will dim.
User cannot click outside the virtual PIN PAD Dialog. So, it’s
suggested not to set a too low dim value, because it may
confuse the user, by making him think clicking outside is allowed.
Example of settings:
intent = new Intent("com.landicorp.pinpad.pinentry.server.SET_SKIN");
intent.putExtra("skin_name", "DEMO");
intent.putExtra("gravity", Gravity.BOTTOM);
intent.putExtra("skb_x", 0);
intent.putExtra("skb_y", 0);
intent.putExtra("skb_width", 580);
intent.putExtra("skb_height", 600);
intent.putExtra("show_input", true);
intent.putExtra("custom_text", new String[]{"id_test", "this is a test"});
intent.putExtra("handle_back_key", true);
intent.putExtra("dim_amount amount", 30);
context.sendBroadcast(intent);
The activity here is just a search key for virtual PIN PAD to find the skin application.
3. The application needs a string resource whose id is skin_name. The value insert in this id will
be the name of the skin that will be used in the broadcast. For example, consider the following
skin_name:
<string name="skin_name">TRAINING_SKIN</string>
4. There must be a layout resource whose file name is softkeyboard.xml. This layout will
be loaded and assigned to the virtual PIN PAD, as the UI layout of skin.
Hints
User can set the virtual PIN PAD size programmatically by their will. Then, when you have your
softkeyboard.xml layout, please keep in mind to let it fit for different sizes. You can follow these rules
below to prevent display problems:
Avoid using specific sizes: using values like “300dp” or “wrap_content” is not
recommended. It’s suggested to use “match_parent” or “android:layout_weight” to set
the size of every widget.
Use stretchable drawable: nine patch is a good choice or consider to use color, shape or vector
instead if the picture is simple.
The text size of number buttons and text view: virtual PIN PAD will calculate a suitable text size
for number buttons and text view. You can trim the display effect by set the padding of these views.
All the other views will keep their text size as original set in layout.
Text view visibility: the text view can be set to View.VISIBLE or View.GONE programmatically
by user, so make sure the layout can be displayed well with or without text view.
disorder Boolean Whether the number keys will be randomly displayed. If true, the
number keys on PIN input will show in random order. If false, the
skin will request the virtual PIN PAD to show as the id order
(btn_digit0 will show 0, btn_digit1 will show 1, and so on). To be
PCI compliant, this setting should be set to true.
If this value does not exist, it will use the virtual PIN PAD default
settings instead that is true.
Content example
This is an example for config.xml file.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="version">1</integer>
<bool name="is_default">false</bool>
<integer name="gravity">80</integer><!-- 80 is the value of Gravity.BOTTOM -->
<integer name="skb_x">720</integer>
<integer name="skb_y">0</integer>
<integer name="skb_width">720</integer>
<integer name="skb_height">860</integer>
<bool name="show_input">true</bool>
<bool name="handle_back_key">false</bool>
<integer name="dim_amount">80</integer>
<string name="password_char">●</string>
<bool name="disorder">false</bool>
</resources>
A default VI PIN skin is available in OS version 6.4.84 or above. To change to the default VI PIN skin,
just send a broadcast like the snippet below:
intent = new Intent("com.landicorp.pinpad.pinentry.server.SET_SKIN");
intent.putExtra("skin_name", "VIPIN_DEFAULT");
context.sendBroadcast(intent);
The APOS A8 is delivered with a transparent plastic frame (Figure 3) with embossed numbers. This
frame is to attach to the touch screen to use along with the default VI PIN skin helping visual impaired
cardholder locate the numbers.
/ Extra settings
Name Type Description
PIN trigger mode, that is, the action the cardholder uses to
input a number. The possible values are:
0 – normal mode (default)
1 – long press
pin_trigger_mode Integer
2 – long press and release the key
4 – double tap
5 – double tap or long press
6 – double tap or long press and release the key
Long press timeout. Default value is 2000 ms, don't exceed
t_long_down_ms Integer
10000 ms.
Double click time release. Default value is 1000 ms, don't
t_up_ms Integer
exceed 10000.
The most important parameter is the trigger mode, and it should be set any value other than the
default.
7 Development hints
Here we will see some hints to help the development process.
Mapping KAP ID to BC
The previous code sample is inserting keys into KAP ID area, that is the logical area native to APOS
A8. However, when using BC, the index keys are different, and they are based on ABECS key map.
The BC APOS library maps a position in the KAP ID to a position in the BC map. The table below
shows the association between them in order to help developers where to insert a key to test in
mockup devices. Note that not all BC index are mapped to a KAP ID.
/ BC to KAP ID mapping
KAP ID (0,0) index
BC index
3DES DUKPT
1 - - 4 5
2 4 5 3 28
3 1 - 2 -
4 0 55 - -
8 24 7 8 7
9 26 54 - -
10 2 3 22 23
11 - - 24 27
12 32 33 - -
13 34 35 - -
14 36 37 11 12
15 38 39 25 26
16 - - 13 14
17 - 6 6 -
18 44 45 15 16
19 - 47 17 18
20 - - 0 1
21 - 51 19 -
22 52 53 20 21