Skip to content

Commit

Permalink
feat: add the management of Basic and Light cards (#21)
Browse files Browse the repository at this point in the history
Co-authored-by: Andrei Cristea <andrei.cristea019@gmail.com>
  • Loading branch information
jeanpierrefortune and andrei-cristea committed Oct 4, 2022
1 parent ca2c7c1 commit 9768fe9
Show file tree
Hide file tree
Showing 54 changed files with 462 additions and 928 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Build process using flavours mechanism replaced by standard single build process.
- Major refactoring of the source code.
### Upgraded
- `keyple-demo-common-lib:1.0.0-SNAPSHOT`
- `calypsonet-terminal-calypso-java-api:1.2.+`
- `keyple-service-java-lib:2.1.0`
- `keyple-service-resource-java-lib:2.0.2`
Expand Down
151 changes: 50 additions & 101 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,105 +2,44 @@

This is the repository for the Keyple Android Validation Demo application.

This demo is an open source project provided by [Calypso Networks Association](https://calypsonet.org),
you can adapt the demo for your cards, terminals, projects, etc.
This demo is an open source project provided by the [Calypso Networks Association](https://calypsonet.org) implementing
the [Eclipse Keyple SDK](https://keyple.org) in a typical use case that can serve as a basis for building a ticketing
ecosystem based on contactless cards and/or NFC smartphones.

This demo shows how to easily validate a contract (Season Pass and/or Multi-trip ticket) written on a Calypso card
using the [Eclipse Keyple](https://keyple.org) components.
The source code and APK are available at [calypsonet/keyple-android-demo-validation/releases](https://github.com/calypsonet/keyple-android-demo-validation/releases)

The demo application runs on the following devices:
- `Bluebird` via the proprietary plugin [Bluebird](https://github.com/calypsonet/keyple-plugin-cna-bluebird-specific-nfc-java-lib).
- `Coppernic` via the open source plugin [Coppernic](https://github.com/calypsonet/keyple-android-plugin-coppernic).
- `Famoco` via the open source plugins [Famoco](https://github.com/calypsonet/keyple-famoco) (for SAM access) and [Android NFC](https://keyple.org/components-java/plugins/nfc/) (for card access).
- `Flowbird` via the proprietary plugin [Flowbird](https://github.com/calypsonet/keyple-android-plugin-flowbird).
The code can be easily adapted to other cards, terminals and business logic.

The source code and APK are available at [calypsonet/keyple-android-demo-validation/releases](https://github.com/calypsonet/keyple-android-demo-validation/releases)
It shows how to check if a card is authorized to enter a controlled area (entering the transport network with
a Season Pass and/or Multi-trip ticket), a validation event is added in the event log to be checked by the
[Keyple Demo Control](https://github.com/calypsonet/keyple-android-demo-control) application.
The contracts are loaded in the Calypso card with the Android application of the [Keyple Reload Demo package](https://github.com/calypsonet/keyple-java-demo-remote).

By default, proprietary plugins are deactivated.
If you want to activate them, then here is the procedure to follow:
1. make an explicit request to CNA to obtain the desired plugin,
2. copy the plugin into the `/app/libs/` directory,
3. delete in the `/app/libs/` directory the plugin with the same name but suffixed with `-mock` (e.g. xxx-mock.aar),
4. compile the project via the gradle `build` command,
5. deploy the new apk on the device.
The demo application was tested on the following terminals:
- `Famoco FX205` via the open source plugins [Famoco](https://github.com/calypsonet/keyple-famoco) (for SAM access) and [Android NFC](https://keyple.org/components-java/plugins/nfc/) (for card access).
- `Coppernic C-One 2` via the open source plugin [Coppernic](https://github.com/calypsonet/keyple-android-plugin-coppernic).

The following terminals have also been tested but as they require non-open source libraries, they are not active by default (see [Using proprietary plugins](#using-proprietary-plugins))
- `Bluebird EF501` via the proprietary plugin [Bluebird](https://github.com/calypsonet/keyple-plugin-cna-bluebird-specific-nfc-java-lib).
- `Flowbird Axio 2` via the proprietary plugin [Flowbird](https://github.com/calypsonet/keyple-android-plugin-flowbird).

As all the exchanges made with the card are cryptographically secured by a security module (SAM), it is mandatory to install it in the terminal for the application to work properly.

## Keyple Demos

This demo is part of a set of three demos:
* [Keyple Remote Demo](https://github.com/calypsonet/keyple-java-demo-remote)
* [Keyple Reload Demo](https://github.com/calypsonet/keyple-java-demo-remote)
* [Keyple Validation Demo](https://github.com/calypsonet/keyple-android-demo-validation)
* [Keyple Control Demo](https://github.com/calypsonet/keyple-android-demo-control)

## Calypso Card Applications
These demos are all based on a common library that defines elements such as constants and data structures implemented
for the logic of the ticketing application: [Keyple Demo Common Library](https://github.com/calypsonet/keyple-demo-common-lib).

The demo works with the cards provided in the [Test kit](https://calypsonet.org/technical-support-documentation/)

This demo can be used with Calypso cards with the following configurations:
* AID 315449432E49434131h - File Structure 05h (CD Light/GTML Compatibility)
* AID 315449432E49434131h - File Structure 02h (Revision 2 Minimum with MF files)
* AID 315449432E49434133h - File Structure 32h (Calypso Light Classic)
* AID A0000004040125090101h - File Structure 05h (CD Light/GTML Compatibility)
Please refer to the [README](https://github.com/calypsonet/keyple-demo-common-lib/blob/main/README.md)
file of this library to discover these data structures.

## Validation Procedure

### Data Structures

#### Environment/Holder structure
| Field Name | Bits | Description | Type | Status |
|:---------------------|-----:|:---------------------------------------------------|:-------------:|:---------:|
| EnvVersionNumber | 8 | Data structure version number | VersionNumber | Mandatory |
| EnvApplicationNumber | 32 | Card application number (unique system identifier) | Int | Mandatory |
| EnvIssuingDate | 16 | Card application issuing date | DateCompact | Mandatory |
| EnvEndDate | 16 | Card application expiration date | DateCompact | Mandatory |
| HolderCompany | 8 | Holder company | Int | Optional |
| HolderIdNumber | 32 | Holder Identifier within HolderCompany | Int | Optional |
| EnvPadding | 120 | Padding (bits to 0) | Binary | Optional |
#### Event structure

| Field Name | Bits | Description | Type | Status |
|:-------------------|-----:|:----------------------------------------------|:-------------:|:---------:|
| EventVersionNumber | 8 | Data structure version number | VersionNumber | Mandatory |
| EventDateStamp | 16 | Date of the event | DateCompact | Mandatory |
| EventTimeStamp | 16 | Time of the event | TimeCompact | Mandatory |
| EventLocation | 32 | Location identifier | Int | Mandatory |
| EventContractUsed | 8 | Index of the contract used for the validation | Int | Mandatory |
| ContractPriority1 | 8 | Priority for contract #1 | PriorityCode | Mandatory |
| ContractPriority2 | 8 | Priority for contract #2 | PriorityCode | Mandatory |
| ContractPriority3 | 8 | Priority for contract #3 | PriorityCode | Mandatory |
| ContractPriority4 | 8 | Priority for contract #4 | PriorityCode | Mandatory |
| EventPadding | 120 | Padding (bits to 0) | Binary | Optional |
#### Contract structure

| Field Name | Bits | Description | Type | Status |
|:------------------------|-----:|:-------------------------------------|:-------------------:|:---------:|
| ContractVersionNumber | 8 | Data structure version number | VersionNumber | Mandatory |
| ContractTariff | 8 | Contract Type | PriorityCode | Mandatory |
| ContractSaleDate | 16 | Sale date of the contract | DateCompact | Mandatory |
| ContractValidityEndDate | 16 | Last day of validity of the contract | DateCompact | Mandatory |
| ContractSaleSam | 32 | SAM which loaded the contract | Int | Optional |
| ContractSaleCounter | 24 | SAM auth key counter value | Int | Optional |
| ContractAuthKvc | 8 | SAM auth key KVC | Int | Optional |
| ContractAuthenticator | 24 | Security authenticator | Authenticator (Int) | Optional |
| ContractPadding | 96 | Padding (bits to 0) | Binary | Optional |
#### Counter structure

| Field Name | Bits | Description | Type | Status |
|:-------------|-----:|:----------------|:----:|:---------:|
| CounterValue | 24 | Number of trips | Int | Mandatory |

### Data Types

| Name | Bits | Description |
|:--------------|-----:|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| DateCompact | 16 | Number of days since January 1st, 2010 (being date 0). Maximum value is 16,383, last complete year being 2053. All dates are in legal local time. |
| PriorityCode | 8 | Types of contracts defined: <br>0 Forbidden (present in clean records only)<br>1 Season Pass<br>2 Multi-trip ticket<br>3 Stored Value<br>4 to 30 RFU<br>31 Expired |
| TimeCompact | 16 | Time in minutes, value = hour*60+minute (0 to 1,439) |
| VersionNumber | 8 | Data model version:<br>0 Forbidden (undefined)<br>1 Current version<br>2..254 RFU<br>255 Forbidden (reserved) |

### Validation Use Case

This use case searches for the best candidate for validation from the existing contracts in the card.
Expand All @@ -125,7 +64,7 @@ Steps:
### Process

For this validation demo application, a simple example validation procedure has been implemented.
This procedure is implemented in the `ValidationProcedure` class.
This procedure is implemented in the `CardRepository` class.

Opening a Calypso secure session is mandatory for this procedure since we need to write a new event in the event log.
If no Calypso SAM is present, then the procedure will not execute and display an error.
Expand Down Expand Up @@ -195,20 +134,20 @@ This procedure's main steps are as follows:
- Season Pass: End of validity.
- MultiTrip Ticket: number of tickets left.
- If the validation fails, display the reason.



## Ticketing implementation

Below are the classes useful for implementing the ticketing layer:
- `MainService`
- `ReaderService`
- `ReaderActivity.CardReaderObserver`
- `TicketingService`
- `ReaderRepository`
- `ReaderActivity.CardReaderObserver`
- `CardRepository`

### MainService
### TicketingService

This service is the orchestrator of the ticketing process.

Mainly used to manage the lifecycle of the Keyple plugin.
Mainly used to manage the lifecycle of the Keyple plugin.
This service is used to initialize the plugin and manage the card detection phase.
It is called on the different steps of the reader activity lifecycle:
- onResume:
Expand All @@ -219,8 +158,16 @@ It is called on the different steps of the reader activity lifecycle:
- Stop NFC detection
- onDestroy:
- Clear the Keyple plugin (remove observers and unregister plugin)

It prepares and scheduled the selection scenario that will be sent to the card when a card is detected by setting
the AID(s) and the reader protocol(s) of the cards we want to detect and read.

### ReaderService
Once a card is detected, the service processes the selection scenario by retrieving the current `CalypsoCard` object.
This object contains information about the card (serial number, card revision...)

Finally, this class is responsible for launching the validation procedure and returning its result.

### ReaderRepository

This service is the interface between the business layer and the reader.

Expand All @@ -231,15 +178,17 @@ This class is the reader observer and inherits from Keyple class `CardReaderObse
It is invoked each time a new `CardReaderEvent` (`CARD_INSERTED`, `CARD_MATCHED`...) is launched by the Keyple plugin.
This reader is registered when the reader is registered and removed when the reader is unregistered.

### TicketingService

This service is the orchestrator of the ticketing process.
### CardRepository

First it prepares and scheduled the selection scenario that will be sent to the card when a card is detected by setting
the AID(s) and the reader protocol(s) of the cards we want to detect and read.
This class contains the implementation of the "Validation" procedure.

Once a card is detected, the service processes the selection scenario by retrieving the current `CalypsoCard` object.
This object contains information about the card (serial number, card revision...)
## Using proprietary plugins

Finally, this class is responsible for launching the validation procedure and returning its result.
By default, proprietary plugins are deactivated.
If you want to activate them, then here is the procedure to follow:
1. make an explicit request to [CNA](https://calypsonet.org/contact-us/) to obtain the desired plugin,
2. copy the plugin into the `/app/libs/` directory,
3. delete in the `/app/libs/` directory the plugin with the same name but suffixed with `-mock` (e.g. xxx-mock.aar),
4. compile the project via the gradle `build` command,
5. deploy the new apk on the device.

2 changes: 1 addition & 1 deletion app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Keep demo app classes
-keep class org.calypsonet.keyple.demo.validation.service.ticketing.model.Location { *; }
-keep class org.calypsonet.keyple.demo.validation.data.model.Location { *; }
-keep class org.joda.time.** { *; }

# Keep Keyple library classes
Expand Down
18 changes: 6 additions & 12 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
android:theme="@style/AppTheme" >

<activity
android:name="org.calypsonet.keyple.demo.validation.android.activity.SplashScreenActivity"
android:name="org.calypsonet.keyple.demo.validation.ui.MainActivity"
android:theme="@style/AppTheme.NoActionBar"
android:screenOrientation="portrait"
android:launchMode="singleTop"
Expand All @@ -29,7 +29,7 @@
</activity>

<activity
android:name="org.calypsonet.keyple.demo.validation.android.activity.ReaderActivity"
android:name="org.calypsonet.keyple.demo.validation.ui.ReaderActivity"
android:theme="@style/AppTheme.NoActionBar"
android:launchMode="singleTop"
android:screenOrientation="portrait">
Expand All @@ -38,34 +38,28 @@
</intent-filter>
</activity>
<activity
android:name="org.calypsonet.keyple.demo.validation.android.activity.CardSummaryActivity"
android:name="org.calypsonet.keyple.demo.validation.ui.CardSummaryActivity"
android:theme="@style/AppTheme.NoActionBar"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:configChanges="orientation|keyboardHidden"/>
<activity
android:name="org.calypsonet.keyple.demo.validation.android.activity.HomeActivity"
android:name="org.calypsonet.keyple.demo.validation.ui.HomeActivity"
android:theme="@style/AppTheme.NoActionBar"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:configChanges="orientation|keyboardHidden"/>
<activity
android:name="org.calypsonet.keyple.demo.validation.android.activity.SettingsActivity"
android:name="org.calypsonet.keyple.demo.validation.ui.SettingsActivity"
android:theme="@style/AppTheme.NoActionBar"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:configChanges="orientation|keyboardHidden" />
<activity
android:name="org.calypsonet.keyple.demo.validation.android.activity.DeviceSelectionActivity"
android:name="org.calypsonet.keyple.demo.validation.ui.deviceselection.DeviceSelectionActivity"
android:theme="@style/Theme.AppCompat.NoActionBar"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:configChanges="orientation|keyboardHidden" />

<receiver android:name="org.calypsonet.keyple.demo.validation.android.receiver.StartUpReceiver">
<intent-filter android:priority="800">
<action android:name="com.parkeon.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ package org.calypsonet.keyple.demo.validation
import android.content.Context
import androidx.multidex.MultiDex
import dagger.android.DaggerApplication
import org.calypsonet.keyple.demo.validation.android.di.AppComponent
import org.calypsonet.keyple.demo.validation.android.di.DaggerAppComponent
import org.calypsonet.keyple.demo.validation.di.AppComponent
import org.calypsonet.keyple.demo.validation.di.DaggerAppComponent
import timber.log.Timber
import timber.log.Timber.DebugTree

Expand Down

This file was deleted.

This file was deleted.

Loading

0 comments on commit 9768fe9

Please sign in to comment.