├── projects ├── PcscLike │ ├── .gitignore │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ └── values │ │ │ │ │ └── strings.xml │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── springcard │ │ │ │ └── pcsclike │ │ │ │ ├── communication │ │ │ │ ├── LowLevelLayer.kt │ │ │ │ ├── UsbLayer.kt │ │ │ │ ├── BleLayer.kt │ │ │ │ └── GattAttributes.kt │ │ │ │ ├── ccid │ │ │ │ ├── CcidSecureParameters.kt │ │ │ │ └── CcidFrame.kt │ │ │ │ ├── SCardReaderListUsb.kt │ │ │ │ ├── SCardReaderListBle.kt │ │ │ │ ├── SCardChannel.kt │ │ │ │ ├── utils │ │ │ │ └── Utils.kt │ │ │ │ ├── SCardError.kt │ │ │ │ └── SCardReaderListCallback.kt │ │ ├── test │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── springcard │ │ │ │ └── pcsclike │ │ │ │ └── ExampleUnitTest.java │ │ └── androidTest │ │ │ └── java │ │ │ └── com │ │ │ └── springcard │ │ │ └── pcsclike │ │ │ └── ExampleInstrumentedTest.java │ ├── proguard-rules.pro │ └── build.gradle.kts ├── PcscLikeSample │ ├── .gitignore │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── values │ │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ │ ├── dimens.xml │ │ │ │ │ ├── colors.xml │ │ │ │ │ ├── styles.xml │ │ │ │ │ └── strings.xml │ │ │ │ ├── values-v21 │ │ │ │ │ └── styles.xml │ │ │ │ ├── color │ │ │ │ │ ├── switch_thumb_selector.xml │ │ │ │ │ └── switch_track_selector.xml │ │ │ │ ├── drawable-xxhdpi │ │ │ │ │ ├── ic_signal_cellular_4_bar.xml │ │ │ │ │ ├── ic_signal_cellular_0_bar.xml │ │ │ │ │ ├── send.xml │ │ │ │ │ ├── backward.xml │ │ │ │ │ ├── forward.xml │ │ │ │ │ ├── icon_app_background.xml │ │ │ │ │ ├── ic_signal_cellular_1_bar.xml │ │ │ │ │ ├── ic_signal_cellular_2_bar.xml │ │ │ │ │ ├── ic_signal_cellular_3_bar.xml │ │ │ │ │ ├── sync.xml │ │ │ │ │ ├── search.xml │ │ │ │ │ ├── logs.xml │ │ │ │ │ ├── about.xml │ │ │ │ │ ├── settings.xml │ │ │ │ │ └── ic_launcher_background.xml │ │ │ │ ├── menu │ │ │ │ │ ├── log_app_bar.xml │ │ │ │ │ ├── device_app_bar.xml │ │ │ │ │ └── activity_main_drawer.xml │ │ │ │ ├── values-night │ │ │ │ │ └── colors.xml │ │ │ │ ├── layout │ │ │ │ │ ├── fragment_log.xml │ │ │ │ │ ├── activity_main.xml │ │ │ │ │ ├── nav_header_main.xml │ │ │ │ │ ├── row_device.xml │ │ │ │ │ └── content_main.xml │ │ │ │ └── values-fr │ │ │ │ │ └── strings.xml │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── springcard │ │ │ │ └── pcsclike_sample │ │ │ │ ├── DeviceListElement.kt │ │ │ │ ├── ApduModel.kt │ │ │ │ ├── ScanFragment.kt │ │ │ │ ├── AboutFragment.kt │ │ │ │ ├── DeviceListAdapter.kt │ │ │ │ ├── LogFragment.kt │ │ │ │ └── AppPreferences.kt │ │ ├── test │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── springcard │ │ │ │ └── pcsclike_sample │ │ │ │ └── ExampleUnitTest.java │ │ └── androidTest │ │ │ └── kotlin │ │ │ └── com │ │ │ └── springcard │ │ │ └── pcscapp │ │ │ └── ExampleInstrumentedTest.java │ ├── proguard-rules.pro │ └── build.gradle.kts ├── PcscLikeSampleBle │ ├── .gitignore │ ├── src │ │ ├── main │ │ │ ├── ic_launcher-web.png │ │ │ ├── ic_launcher_app-web.png │ │ │ ├── res │ │ │ │ ├── values │ │ │ │ │ ├── strings.xml │ │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ │ ├── themes.xml │ │ │ │ │ └── colors.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_app.png │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ └── ic_launcher_app_round.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_app.png │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ └── ic_launcher_app_round.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_app.png │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ └── ic_launcher_app_round.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_app.png │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ └── ic_launcher_app_round.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_app.png │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ └── ic_launcher_app_round.png │ │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ │ ├── ic_launcher.xml │ │ │ │ │ ├── ic_launcher_round.xml │ │ │ │ │ ├── ic_launcher_app.xml │ │ │ │ │ └── ic_launcher_app_round.xml │ │ │ │ ├── menu │ │ │ │ │ └── scan_app_bar.xml │ │ │ │ ├── drawable-v24 │ │ │ │ │ └── ic_launcher_background_app.xml │ │ │ │ ├── layout │ │ │ │ │ └── fragment_scan.xml │ │ │ │ └── drawable │ │ │ │ │ ├── ic_launcher_foreground.xml │ │ │ │ │ ├── ic_launcher_foreground_app.xml │ │ │ │ │ └── ic_launcher_background.xml │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── springcard │ │ │ │ └── pcsclike_sample_ble │ │ │ │ ├── MainActivity.kt │ │ │ │ └── DeviceFragment.kt │ │ ├── test │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── springcard │ │ │ │ └── pcsclike_sample_ble │ │ │ │ └── ExampleUnitTest.kt │ │ └── androidTest │ │ │ └── java │ │ │ └── com │ │ │ └── springcard │ │ │ └── pcsclike_sample_ble │ │ │ └── ExampleInstrumentedTest.kt │ ├── proguard-rules.pro │ └── build.gradle.kts ├── PcscLikeSampleUsb │ ├── .gitignore │ ├── .idea │ │ ├── .gitignore │ │ ├── vcs.xml │ │ ├── modules.xml │ │ ├── misc.xml │ │ └── gradle.xml │ ├── src │ │ ├── main │ │ │ ├── ic_launcher-web.png │ │ │ ├── ic_launcher_app-web.png │ │ │ ├── ic_launcher_usb-web.png │ │ │ ├── res │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_app.png │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ └── ic_launcher_app_round.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_app.png │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ └── ic_launcher_app_round.png │ │ │ │ ├── values │ │ │ │ │ ├── strings.xml │ │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ │ ├── themes.xml │ │ │ │ │ └── colors.xml │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_app.png │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ └── ic_launcher_app_round.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_app.png │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ └── ic_launcher_app_round.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_app.png │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ └── ic_launcher_app_round.png │ │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ │ ├── ic_launcher.xml │ │ │ │ │ ├── ic_launcher_round.xml │ │ │ │ │ ├── ic_launcher_app.xml │ │ │ │ │ └── ic_launcher_app_round.xml │ │ │ │ ├── drawable-v24 │ │ │ │ │ └── ic_launcher_background_app.xml │ │ │ │ ├── xml │ │ │ │ │ └── device_filter.xml │ │ │ │ ├── layout │ │ │ │ │ └── fragment_scan.xml │ │ │ │ └── drawable │ │ │ │ │ ├── ic_launcher_foreground.xml │ │ │ │ │ ├── ic_launcher_foreground_app.xml │ │ │ │ │ └── ic_launcher_background.xml │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── springcard │ │ │ │ └── pcsclike_sample_usb │ │ │ │ ├── DeviceFragment.kt │ │ │ │ └── MainActivity.kt │ │ ├── test │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── springcard │ │ │ │ └── pcsclike_sample_usb │ │ │ │ └── ExampleUnitTest.kt │ │ └── androidTest │ │ │ └── java │ │ │ └── com │ │ │ └── springcard │ │ │ └── pcsclike_sample_usb │ │ │ └── ExampleInstrumentedTest.kt │ ├── proguard-rules.pro │ └── build.gradle.kts ├── .idea │ ├── encodings.xml │ ├── codeStyles │ │ ├── codeStyleConfig.xml │ │ └── Project.xml │ ├── vcs.xml │ ├── dictionaries │ │ └── corentin_r.xml │ └── jarRepositories.xml ├── .gitignore ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── build.gradle.kts ├── settings.gradle.kts ├── gradle.properties ├── gradlew.bat ├── AndroidPcscLikeBackground.svg ├── AndroidPcscLikeBle.icon.svg ├── AndroidPcscLikeUsb.icon.svg └── gradlew ├── .idea ├── .gitignore ├── vcs.xml └── modules.xml ├── README.md ├── LICENSE.txt └── .gitignore /projects/PcscLike/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /projects/PcscLike/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | PcscLib 3 | 4 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleBle/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleUsb/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /projects/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/ic_launcher_app-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleBle/src/main/ic_launcher_app-web.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/ic_launcher_app-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleUsb/src/main/ic_launcher_app-web.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/ic_launcher_usb-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleUsb/src/main/ic_launcher_usb-web.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | PC/SC BLE 3 | Scan 4 | 5 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleBle/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleBle/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleUsb/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleUsb/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | PC/SC USB 3 | Devices 4 | 5 | -------------------------------------------------------------------------------- /projects/.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleBle/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleBle/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleBle/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleUsb/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleUsb/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleUsb/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/mipmap-hdpi/ic_launcher_app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleBle/src/main/res/mipmap-hdpi/ic_launcher_app.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/mipmap-mdpi/ic_launcher_app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleBle/src/main/res/mipmap-mdpi/ic_launcher_app.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/mipmap-xhdpi/ic_launcher_app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleBle/src/main/res/mipmap-xhdpi/ic_launcher_app.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #D80A1D 4 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/mipmap-hdpi/ic_launcher_app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleUsb/src/main/res/mipmap-hdpi/ic_launcher_app.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/mipmap-mdpi/ic_launcher_app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleUsb/src/main/res/mipmap-mdpi/ic_launcher_app.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/mipmap-xhdpi/ic_launcher_app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleUsb/src/main/res/mipmap-xhdpi/ic_launcher_app.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #D80A1D 4 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleBle/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleBle/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleBle/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/mipmap-xxhdpi/ic_launcher_app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleBle/src/main/res/mipmap-xxhdpi/ic_launcher_app.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleBle/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/mipmap-xxxhdpi/ic_launcher_app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleBle/src/main/res/mipmap-xxxhdpi/ic_launcher_app.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleUsb/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleUsb/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleUsb/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/mipmap-xxhdpi/ic_launcher_app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleUsb/src/main/res/mipmap-xxhdpi/ic_launcher_app.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleUsb/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/mipmap-xxxhdpi/ic_launcher_app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleUsb/src/main/res/mipmap-xxxhdpi/ic_launcher_app.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/mipmap-hdpi/ic_launcher_app_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleBle/src/main/res/mipmap-hdpi/ic_launcher_app_round.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/mipmap-mdpi/ic_launcher_app_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleBle/src/main/res/mipmap-mdpi/ic_launcher_app_round.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleBle/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/mipmap-hdpi/ic_launcher_app_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleUsb/src/main/res/mipmap-hdpi/ic_launcher_app_round.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/mipmap-mdpi/ic_launcher_app_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleUsb/src/main/res/mipmap-mdpi/ic_launcher_app_round.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleUsb/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/mipmap-xhdpi/ic_launcher_app_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleBle/src/main/res/mipmap-xhdpi/ic_launcher_app_round.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/mipmap-xxhdpi/ic_launcher_app_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleBle/src/main/res/mipmap-xxhdpi/ic_launcher_app_round.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/mipmap-xxxhdpi/ic_launcher_app_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleBle/src/main/res/mipmap-xxxhdpi/ic_launcher_app_round.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/mipmap-xhdpi/ic_launcher_app_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleUsb/src/main/res/mipmap-xhdpi/ic_launcher_app_round.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/mipmap-xxhdpi/ic_launcher_app_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleUsb/src/main/res/mipmap-xxhdpi/ic_launcher_app_round.png -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/mipmap-xxxhdpi/ic_launcher_app_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springcard/android-pcsclike/HEAD/projects/PcscLikeSampleUsb/src/main/res/mipmap-xxxhdpi/ic_launcher_app_round.png -------------------------------------------------------------------------------- /projects/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /projects/PcscLike/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /projects/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Jul 28 11:03:56 CEST 2025 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/color/switch_thumb_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/color/switch_track_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /projects/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // build.gradle.kts 2 | plugins { 3 | id("com.android.application") version "8.9.3" apply false 4 | id("com.android.library") version "8.9.3" apply false 5 | id("org.jetbrains.kotlin.android") version "1.9.0" apply false 6 | id("org.jetbrains.kotlin.plugin.parcelize") version "1.9.0" apply false 7 | } -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/mipmap-anydpi-v26/ic_launcher_app.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/mipmap-anydpi-v26/ic_launcher_app.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/mipmap-anydpi-v26/ic_launcher_app_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/mipmap-anydpi-v26/ic_launcher_app_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 8dp 6 | 120dp 7 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/java/com/springcard/pcsclike_sample/DeviceListElement.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019 SpringCard - www.springcard.com 3 | * All right reserved 4 | * This software is covered by the SpringCard SDK License Agreement - see LICENSE.txt 5 | */ 6 | 7 | package com.springcard.pcsclike_sample 8 | 9 | data class DeviceListElement (val name: String = "", val info: String) 10 | 11 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/drawable-xxhdpi/ic_signal_cellular_4_bar.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/drawable-xxhdpi/ic_signal_cellular_0_bar.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/drawable-xxhdpi/send.xml: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/java/com/springcard/pcsclike_sample/ApduModel.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019 SpringCard - www.springcard.com 3 | * All right reserved 4 | * This software is covered by the SpringCard SDK License Agreement - see LICENSE.txt 5 | */ 6 | 7 | package com.springcard.pcsclike_sample 8 | 9 | data class ApduModel(val id: Int, val title: String, val apdu: String, val mode: Int, val created: String, val modified: String) -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/menu/log_app_bar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/drawable-xxhdpi/backward.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/drawable-xxhdpi/forward.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/menu/scan_app_bar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/drawable-xxhdpi/icon_app_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /projects/PcscLike/src/test/java/com/springcard/pcsclike/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.springcard.pcsclike; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/test/java/com/springcard/pcsclike_sample_ble/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.springcard.pcsclike_sample_ble 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/test/java/com/springcard/pcsclike_sample_usb/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.springcard.pcsclike_sample_usb 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/drawable-xxhdpi/ic_signal_cellular_1_bar.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/drawable-xxhdpi/ic_signal_cellular_2_bar.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/drawable-xxhdpi/ic_signal_cellular_3_bar.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/test/java/com/springcard/pcsclike_sample/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.springcard.pcsclike_sample; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /projects/PcscLike/src/main/java/com/springcard/pcsclike/communication/LowLevelLayer.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019 SpringCard - www.springcard.com 3 | * All right reserved 4 | * This software is covered by the SpringCard SDK License Agreement - see LICENSE.txt 5 | */ 6 | 7 | package com.springcard.pcsclike.communication 8 | 9 | import android.content.Context 10 | 11 | interface LowLevelLayer { 12 | 13 | fun connect(ctx: Context) 14 | 15 | fun disconnect() 16 | 17 | fun close() 18 | 19 | fun write(data: List) 20 | } -------------------------------------------------------------------------------- /projects/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | // settings.gradle.kts 2 | pluginManagement { 3 | repositories { 4 | google() 5 | mavenCentral() 6 | gradlePluginPortal() 7 | } 8 | } 9 | dependencyResolutionManagement { 10 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 11 | repositories { 12 | google() 13 | mavenCentral() 14 | } 15 | } 16 | 17 | rootProject.name = "PcscLike" 18 | include(":PcscLike") 19 | include(":PcscLikeSample") 20 | include(":PcscLikeSampleBle") 21 | include(":PcscLikeSampleUsb") 22 | -------------------------------------------------------------------------------- /projects/.idea/dictionaries/corentin_r.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | abcdef 5 | apdu 6 | apdus 7 | authentification 8 | ccid 9 | cmac 10 | gson 11 | pcsc 12 | pcsclike 13 | pcscoverble 14 | pcscoverusb 15 | recv 16 | scard 17 | springcard 18 | xxxxx 19 | 20 | 21 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/drawable-xxhdpi/sync.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/drawable-xxhdpi/search.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/values-night/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #d80a1d 4 | #f6e2e4 5 | #71050f 6 | 7 | #102C43 8 | #FFFFFF 9 | #000000 10 | #FFFFFF 11 | #D80A1D 12 | #333333 13 | #DDDDDD 14 | #959595 15 | 16 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #d80a1d 4 | #f6e2e4 5 | #71050f 6 | 7 | 8 | #FFFFFF 9 | #D80A1D 10 | #FFFFFF 11 | #000000 12 | #D80A1D 13 | #C1C1C1 14 | #DDDDDD 15 | #8A8A8A 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/drawable-xxhdpi/logs.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/java/com/springcard/pcsclike_sample/ScanFragment.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019 SpringCard - www.springcard.com 3 | * All right reserved 4 | * This software is covered by the SpringCard SDK License Agreement - see LICENSE.txt 5 | */ 6 | 7 | package com.springcard.pcsclike_sample 8 | 9 | 10 | import android.content.pm.PackageManager 11 | import androidx.fragment.app.Fragment 12 | 13 | 14 | abstract class ScanFragment : Fragment() { 15 | 16 | protected val TAG = this::class.java.simpleName 17 | 18 | /* System support feature ? */ 19 | protected fun PackageManager.missingSystemFeature(name: String): Boolean = !hasSystemFeature(name) 20 | 21 | protected lateinit var mainActivity: MainActivity 22 | } 23 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/drawable-xxhdpi/about.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /projects/PcscLike/src/main/java/com/springcard/pcsclike/communication/UsbLayer.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019 SpringCard - www.springcard.com 3 | * All right reserved 4 | * This software is covered by the SpringCard SDK License Agreement - see LICENSE.txt 5 | */ 6 | 7 | package com.springcard.pcsclike.communication 8 | 9 | import android.hardware.usb.* 10 | import com.springcard.pcsclike.* 11 | 12 | internal class UsbLayer(scardReaderList : SCardReaderList, usbDevice: UsbDevice): CommunicationLayer(scardReaderList) { 13 | 14 | private val TAG = this::class.java.simpleName 15 | 16 | override var lowLayer = UsbLowLevel(scardReaderList, usbDevice) as LowLevelLayer 17 | 18 | override fun wakeUp() { 19 | throw NotImplementedError("Error, wakeUp() method is not available in USB") 20 | } 21 | } -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/layout/fragment_log.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/androidTest/java/com/springcard/pcsclike_sample_ble/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.springcard.pcsclike_sample_ble 2 | 3 | import androidx.test.ext.junit.runners.AndroidJUnit4 4 | import androidx.test.platform.app.InstrumentationRegistry 5 | import org.junit.Assert.assertEquals 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | /** 10 | * Instrumented test, which will execute on an Android device. 11 | * 12 | * See [testing documentation](http://d.android.com/tools/testing). 13 | */ 14 | @RunWith(AndroidJUnit4::class) 15 | class ExampleInstrumentedTest { 16 | @Test 17 | fun useAppContext() { 18 | // Context of the app under test. 19 | val appContext = InstrumentationRegistry.getInstrumentation().context; 20 | assertEquals("com.springcard.pcsclike_sample_ble", appContext.packageName) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/androidTest/java/com/springcard/pcsclike_sample_usb/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.springcard.pcsclike_sample_usb 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().context 22 | assertEquals("com.springcard.pcsclike_sample_usb", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 14 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /projects/PcscLike/src/androidTest/java/com/springcard/pcsclike/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.springcard.pcsclike; 2 | 3 | import android.content.Context; 4 | import androidx.test.platform.app.InstrumentationRegistry; 5 | import androidx.test.ext.junit.runners.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getInstrumentation().getContext(); 23 | 24 | assertEquals("com.springcard.pcsclike.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /projects/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # Kotlin code style for this project: "official" or "obsolete": 15 | kotlin.code.style=official 16 | android.useAndroidX=true 17 | android.enableJetifier=true 18 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/androidTest/kotlin/com/springcard/pcscapp/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.springcard.pcsclike_sample; 2 | 3 | import android.content.Context; 4 | import androidx.test.platform.app.InstrumentationRegistry; 5 | import androidx.test.ext.junit.runners.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getInstrumentation().getContext(); 23 | 24 | assertEquals("com.springcard.pcsclike_sample.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/menu/device_app_bar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 15 | 20 | 21 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/drawable-xxhdpi/settings.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/drawable-v24/ic_launcher_background_app.xml: -------------------------------------------------------------------------------- 1 | 7 | 11 | 12 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/drawable-v24/ic_launcher_background_app.xml: -------------------------------------------------------------------------------- 1 | 7 | 11 | 12 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/menu/activity_main_drawer.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 13 | 17 | 21 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/xml/device_filter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /projects/PcscLike/src/main/java/com/springcard/pcsclike/communication/BleLayer.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019 SpringCard - www.springcard.com 3 | * All right reserved 4 | * This software is covered by the SpringCard SDK License Agreement - see LICENSE.txt 5 | */ 6 | 7 | package com.springcard.pcsclike.communication 8 | 9 | import android.bluetooth.BluetoothDevice 10 | import android.os.Build 11 | import androidx.annotation.RequiresApi 12 | import com.springcard.pcsclike.SCardReaderList 13 | import com.springcard.pcsclike.SCardReaderListCallback 14 | 15 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP) 16 | internal class BleLayer(scardReaderList : SCardReaderList, bluetoothDevice: BluetoothDevice ): CommunicationLayer(scardReaderList) { 17 | 18 | private val TAG = this::class.java.simpleName 19 | 20 | override var lowLayer = BleLowLevel(scardReaderList, bluetoothDevice) as LowLevelLayer 21 | 22 | override fun wakeUp() { 23 | scardReaderList.enterExclusive() 24 | scardReaderList.machineState.setNewState(State.WakingUp) 25 | /* Subscribe to Service changed to wake-up device */ 26 | (lowLayer as BleLowLevel).enableNotifOnCcidStatus() 27 | } 28 | } -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/layout/fragment_scan.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 18 | 19 | 27 | 28 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/layout/fragment_scan.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 18 | 19 | 27 | 28 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 18 | 19 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /projects/PcscLike/src/main/java/com/springcard/pcsclike/ccid/CcidSecureParameters.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019 SpringCard - www.springcard.com 3 | * All right reserved 4 | * This software is covered by the SpringCard SDK License Agreement - see LICENSE.txt 5 | */ 6 | 7 | package com.springcard.pcsclike.ccid 8 | 9 | /** 10 | * Class used to authenticate and ciphering CCID frames 11 | * 12 | * @property authMode Authentication version & mode (0x01 -> AES128) 13 | * @property keyIndex Index of the Key (0x00 -> User, 0x01 -> Admin) 14 | * @property keyValue The value of the key on 16 bytes for AES128 15 | * @property mode This field specify how the communication will be secured once the authentication is passed 16 | * @constructor 17 | */ 18 | class CcidSecureParameters (val authMode: AuthenticationMode, val keyIndex: AuthenticationKeyIndex, val keyValue: MutableList, val mode: CommunicationMode) { 19 | enum class AuthenticationMode(val value: Byte) { 20 | None(-1), 21 | Aes128(0x01) 22 | } 23 | enum class AuthenticationKeyIndex(val value: Byte) { 24 | None(-1), 25 | User(0x00), 26 | Admin(0x01) 27 | } 28 | enum class CommunicationMode(val value: Byte) { 29 | Plain(0x00), 30 | Mac(0x01), 31 | MacAndCipher(0x03) 32 | } 33 | } -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /projects/PcscLike/src/main/java/com/springcard/pcsclike/SCardReaderListUsb.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019 SpringCard - www.springcard.com 3 | * All right reserved 4 | * This software is covered by the SpringCard SDK License Agreement - see LICENSE.txt 5 | */ 6 | 7 | package com.springcard.pcsclike 8 | 9 | import android.hardware.usb.UsbDevice 10 | import android.content.Context 11 | import android.util.Log 12 | import com.springcard.pcsclike.ccid.* 13 | import com.springcard.pcsclike.communication.* 14 | 15 | class SCardReaderListUsb internal constructor(layerDevice: UsbDevice, callbacks: SCardReaderListCallback): SCardReaderList(layerDevice as Any, callbacks) { 16 | 17 | override fun create(ctx : Context) { 18 | //Log.i("PcscLikeLibrary", "Lib rev = ${BuildConfig.VERSION_NAME}") 19 | if(layerDevice is UsbDevice) { 20 | commLayer = UsbLayer(this, layerDevice) 21 | commLayer.connect(ctx) 22 | } 23 | } 24 | 25 | override fun create(ctx : Context, secureConnexionParameters: CcidSecureParameters) { 26 | //Log.i("PcscLikeLibrary", "Lib rev = ${BuildConfig.VERSION_NAME}") 27 | if(layerDevice is UsbDevice) { 28 | commLayer = UsbLayer(this, layerDevice) 29 | ccidHandler = CcidHandler(this, secureConnexionParameters) 30 | commLayer.connect(ctx) 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /projects/PcscLike/src/main/java/com/springcard/pcsclike/SCardReaderListBle.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019 SpringCard - www.springcard.com 3 | * All right reserved 4 | * This software is covered by the SpringCard SDK License Agreement - see LICENSE.txt 5 | */ 6 | 7 | package com.springcard.pcsclike 8 | 9 | import android.bluetooth.BluetoothDevice 10 | import android.content.Context 11 | import android.os.Build 12 | import androidx.annotation.RequiresApi 13 | import android.util.Log 14 | import com.springcard.pcsclike.ccid.* 15 | import com.springcard.pcsclike.communication.* 16 | 17 | 18 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP) 19 | class SCardReaderListBle internal constructor(layerDevice: BluetoothDevice, callbacks: SCardReaderListCallback): SCardReaderList(layerDevice as Any, callbacks) { 20 | 21 | override fun create(ctx : Context) { 22 | //Log.i("PcscLikeLibrary", "Lib rev = ${BuildConfig.VERSION_NAME}") 23 | if(layerDevice is BluetoothDevice) { 24 | commLayer = BleLayer(this, layerDevice) 25 | commLayer.connect(ctx) 26 | } 27 | } 28 | 29 | override fun create(ctx : Context, secureConnexionParameters: CcidSecureParameters) { 30 | //Log.i("PcscLikeLibrary", "Lib rev = ${BuildConfig.VERSION_NAME}") 31 | if(layerDevice is BluetoothDevice) { 32 | commLayer = BleLayer(this, layerDevice) 33 | ccidHandler = CcidHandler(this, secureConnexionParameters) 34 | commLayer.connect(ctx) 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/layout/nav_header_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 21 | 22 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PC/SC Like Android library 2 | 3 | The SpringCard PC/SC-like library and sample applciations for Android provides access to all the compliant SpringCard USB and BLE contact or contactless smartcard readers, including NFC/RFID @ 13.56MHz readers. 4 | 5 | The documentation of this library is avalaible online: https://docs.springcard.com/apis/Android/PCSC-Like/ 6 | 7 | This is the source code to the SpringCard PC/SC over BLE application for Android. If you are looking for the binaries, please download the application from the Play Store or from the release section. 8 | 9 | SpringCard PC/SC over BLE or USB are the reference applications to work with SpringCard smartcard and NFC/RFID readers over a Bluetooth Low Energy or USB connection. 10 | 11 | Use this application together with Puck, Prox'N'Roll, and a lot of other SpringCard smartcard readers. Connect to a contact or contactless smartcard, retrieve its ATR, exchange ISO 7816 APDUs; read/write NFC tags or RFID @ 13.56MHz labels; explore and validate your own use cases. 12 | 13 | Once ready, download the AAR in the release section and start developing your own Android application together with SpringCard products! 14 | 15 | NB: the above-mentionned PC/SC USB devices will work only on Android devices featuring a "real" USB host port. USB on-the-go is not supported. 16 | 17 | You can download and install these applications here: 18 | * https://play.google.com/store/apps/details?id=com.springcard.pcsclike_sample_ble 19 | * https://play.google.com/store/apps/details?id=com.springcard.pcsclike_sample_usb 20 | 21 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 21 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/layout/row_device.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 17 | 18 | 23 | 24 | 31 | 32 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/java/com/springcard/pcsclike_sample_usb/DeviceFragment.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019 SpringCard - www.springcard.com 3 | * All right reserved 4 | * This software is covered by the SpringCard SDK License Agreement - see LICENSE.txt 5 | */ 6 | 7 | package com.springcard.pcsclike_sample_usb 8 | 9 | import android.hardware.usb.UsbDevice 10 | import com.springcard.pcsclike.* 11 | import android.view.Menu 12 | import android.view.MenuInflater 13 | import com.springcard.pcsclike_sample.DeviceFragment 14 | import com.springcard.pcsclike_sample.R 15 | 16 | class DeviceFragment : DeviceFragment() { 17 | 18 | override fun connectToDevice() { 19 | 20 | if(device is UsbDevice) { 21 | val extraInfo =(mainActivity.scanFragment as ScanFragment).getDeviceExtraInfo(device as UsbDevice) 22 | deviceName = "${(device as UsbDevice).manufacturerName} ${(device as UsbDevice).productName} [$extraInfo]" 23 | SCardReaderList.create(mainActivity, device as UsbDevice, scardCallbacks) 24 | } 25 | else { 26 | mainActivity.logInfo("Device is not a USB device") 27 | } 28 | } 29 | 30 | override fun init(_device: Any) { 31 | 32 | if(_device is UsbDevice) { 33 | device = _device 34 | } 35 | else { 36 | mainActivity.logInfo("Device is not a USB device") 37 | } 38 | } 39 | 40 | override fun onCreateOptionsMenu( 41 | menu: Menu, inflater: MenuInflater 42 | ) { 43 | super.onCreateOptionsMenu(menu, inflater) 44 | 45 | /* Hide shutdown and wake-up buttons when we are on USB */ 46 | menu.findItem(R.id.action_shutdown).isVisible = false 47 | menu.findItem(R.id.action_wakeup).isVisible = false 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /projects/PcscLike/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | # cf https://support.brightcove.com/removing-android-log-messages 24 | # cf https://stackoverflow.com/questions/15571520/how-to-configure-proguard-to-only-remove-android-logging-calls/15593061#15593061 25 | # cf https://medium.com/@trionkidnapper/stripping-log-statements-using-proguard-73dedc68ee97 26 | 27 | -dontwarn ** 28 | -target 17 29 | -dontusemixedcaseclassnames 30 | -dontskipnonpubliclibraryclasses 31 | -dontpreverify 32 | -verbose 33 | 34 | -optimizations !code/simplification/arithmetic,!code/allocation/variable 35 | -keep class ** 36 | -keepclassmembers class *{*;} # Do not remove it, otherwise the library crash 37 | -keepattributes * 38 | -dontobfuscate 39 | 40 | -assumenosideeffects class android.util.Log { 41 | public static boolean isLoggable(java.lang.String, int); 42 | public static int v(...); 43 | public static int i(...); 44 | public static int w(...); 45 | public static int d(...); 46 | public static int e(...); 47 | } -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | # cf https://support.brightcove.com/removing-android-log-messages 24 | # cf https://stackoverflow.com/questions/15571520/how-to-configure-proguard-to-only-remove-android-logging-calls/15593061#15593061 25 | # cf https://medium.com/@trionkidnapper/stripping-log-statements-using-proguard-73dedc68ee97 26 | 27 | -dontwarn ** 28 | -target 17 29 | -dontusemixedcaseclassnames 30 | -dontskipnonpubliclibraryclasses 31 | -dontpreverify 32 | -verbose 33 | 34 | -optimizations !code/simplification/arithmetic,!code/allocation/variable 35 | -keep class ** 36 | -keepclassmembers class *{*;} # Do not remove it, otherwise the library crash 37 | -keepattributes * 38 | -dontobfuscate 39 | 40 | -assumenosideeffects class android.util.Log { 41 | public static boolean isLoggable(java.lang.String, int); 42 | public static int v(...); 43 | public static int i(...); 44 | public static int w(...); 45 | public static int d(...); 46 | public static int e(...); 47 | } -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | # cf https://support.brightcove.com/removing-android-log-messages 24 | # cf https://stackoverflow.com/questions/15571520/how-to-configure-proguard-to-only-remove-android-logging-calls/15593061#15593061 25 | # cf https://medium.com/@trionkidnapper/stripping-log-statements-using-proguard-73dedc68ee97 26 | 27 | -dontwarn ** 28 | -target 17 29 | -dontusemixedcaseclassnames 30 | -dontskipnonpubliclibraryclasses 31 | -dontpreverify 32 | -verbose 33 | 34 | -optimizations !code/simplification/arithmetic,!code/allocation/variable 35 | -keep class ** 36 | -keepclassmembers class *{*;} # Do not remove it, otherwise the library crash 37 | -keepattributes * 38 | -dontobfuscate 39 | 40 | -assumenosideeffects class android.util.Log { 41 | public static boolean isLoggable(java.lang.String, int); 42 | public static int v(...); 43 | public static int i(...); 44 | public static int w(...); 45 | public static int d(...); 46 | public static int e(...); 47 | } -------------------------------------------------------------------------------- /projects/PcscLike/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // PcscLike/build.gradle.kts 2 | plugins { 3 | id("com.android.library") 4 | id("org.jetbrains.kotlin.android") 5 | id("org.jetbrains.kotlin.plugin.parcelize") 6 | } 7 | 8 | android { 9 | namespace = "com.springcard.pcsclike" 10 | compileSdk = 36 11 | 12 | buildFeatures{ 13 | buildConfig = true 14 | } 15 | 16 | viewBinding { 17 | enable = true 18 | } 19 | 20 | defaultConfig { 21 | minSdk = 22 22 | 23 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 24 | consumerProguardFiles("consumer-rules.pro") 25 | 26 | buildConfigField("String", "libraryName", "\"PC/SC-Like Library\"") 27 | buildConfigField("String", "librarySpecial", "\"\"") 28 | buildConfigField("String", "libraryVersion", "\"\"") 29 | buildConfigField("int", "libraryVersionMajor", "1") 30 | buildConfigField("int", "libraryVersionMinor", "0") 31 | buildConfigField("int", "libraryVersionBuild", "0") 32 | } 33 | 34 | buildTypes { 35 | release { 36 | isMinifyEnabled = false 37 | proguardFiles( 38 | getDefaultProguardFile("proguard-android-optimize.txt"), 39 | "proguard-rules.pro" 40 | ) 41 | } 42 | } 43 | compileOptions { 44 | sourceCompatibility = JavaVersion.VERSION_17 45 | targetCompatibility = JavaVersion.VERSION_17 46 | } 47 | kotlinOptions { 48 | jvmTarget = "17" 49 | } 50 | } 51 | 52 | dependencies { 53 | 54 | implementation("androidx.core:core-ktx:1.12.0") 55 | implementation("androidx.appcompat:appcompat:1.6.1") 56 | implementation("com.google.android.material:material:1.11.0") 57 | testImplementation("junit:junit:4.13.2") 58 | androidTestImplementation("androidx.test.ext:junit:1.1.5") 59 | androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") 60 | } -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 6 | 8 | 11 | 17 | 23 | 29 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/drawable/ic_launcher_foreground_app.xml: -------------------------------------------------------------------------------- 1 | 6 | 8 | 11 | 17 | 23 | 29 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/java/com/springcard/pcsclike_sample_usb/MainActivity.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019 SpringCard - www.springcard.com 3 | * All right reserved 4 | * This software is covered by the SpringCard SDK License Agreement - see LICENSE.txt 5 | */ 6 | 7 | package com.springcard.pcsclike_sample_usb 8 | 9 | 10 | import android.os.Bundle 11 | import com.springcard.pcsclike_sample.MainActivity 12 | 13 | 14 | class MainActivity : MainActivity() { 15 | 16 | 17 | override val deviceFragment = DeviceFragment() 18 | override val scanFragment = ScanFragment() 19 | override var supportCrypto = false // USB does not support authentication 20 | 21 | override fun onCreate(savedInstanceState: Bundle?) { 22 | super.onCreate(savedInstanceState) 23 | 24 | setAboutInfo() 25 | } 26 | 27 | private fun setAboutInfo() { 28 | 29 | val appInfo = ApplicationInfo( 30 | BuildConfig.DEBUG, 31 | BuildConfig.APPLICATION_ID, 32 | BuildConfig.BUILD_TYPE, 33 | "NO", 34 | BuildConfig.VERSION_CODE, 35 | BuildConfig.VERSION_NAME, 36 | BuildConfig.DEBUG) 37 | 38 | val libInfo = LibraryInfo( 39 | BuildConfig.DEBUG, 40 | BuildConfig.APPLICATION_ID, 41 | BuildConfig.BUILD_TYPE, 42 | "NO", 43 | BuildConfig.VERSION_CODE, 44 | BuildConfig.VERSION_NAME, 45 | com.springcard.pcsclike.BuildConfig.DEBUG, 46 | com.springcard.pcsclike.BuildConfig.libraryName, 47 | com.springcard.pcsclike.BuildConfig.librarySpecial, 48 | com.springcard.pcsclike.BuildConfig.libraryVersion, 49 | com.springcard.pcsclike.BuildConfig.libraryVersionBuild, 50 | com.springcard.pcsclike.BuildConfig.libraryVersionMajor, 51 | com.springcard.pcsclike.BuildConfig.libraryVersionMinor) 52 | 53 | super.setAboutInfo(appInfo, libInfo) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/java/com/springcard/pcsclike_sample_ble/MainActivity.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019 SpringCard - www.springcard.com 3 | * All right reserved 4 | * This software is covered by the SpringCard SDK License Agreement - see LICENSE.txt 5 | */ 6 | 7 | package com.springcard.pcsclike_sample_ble 8 | 9 | import android.os.Bundle 10 | import com.android.volley.BuildConfig 11 | import com.springcard.pcsclike_sample.MainActivity 12 | import com.springcard.pcsclike_sample_ble.ScanFragment 13 | 14 | class MainActivity : MainActivity() { 15 | 16 | override val deviceFragment: DeviceFragment = DeviceFragment() 17 | override val scanFragment: ScanFragment = ScanFragment() 18 | override var supportCrypto = true // BLE support AES authentication 19 | 20 | override fun onCreate(savedInstanceState: Bundle?) { 21 | super.onCreate(savedInstanceState) 22 | 23 | setAboutInfo() 24 | } 25 | 26 | private fun setAboutInfo() { 27 | 28 | val appInfo = ApplicationInfo( 29 | BuildConfig.DEBUG, 30 | BuildConfig.APPLICATION_ID, 31 | BuildConfig.BUILD_TYPE, 32 | "NO", 33 | BuildConfig.VERSION_CODE, 34 | BuildConfig.VERSION_NAME, 35 | BuildConfig.DEBUG 36 | ) 37 | 38 | val libInfo = LibraryInfo( 39 | BuildConfig.DEBUG, 40 | BuildConfig.APPLICATION_ID, 41 | BuildConfig.BUILD_TYPE, 42 | "NO", 43 | BuildConfig.VERSION_CODE, 44 | BuildConfig.VERSION_NAME, 45 | com.springcard.pcsclike.BuildConfig.DEBUG, 46 | com.springcard.pcsclike.BuildConfig.libraryName, 47 | com.springcard.pcsclike.BuildConfig.librarySpecial, 48 | com.springcard.pcsclike.BuildConfig.libraryVersion, 49 | com.springcard.pcsclike.BuildConfig.libraryVersionBuild, 50 | com.springcard.pcsclike.BuildConfig.libraryVersionMajor, 51 | com.springcard.pcsclike.BuildConfig.libraryVersionMinor) 52 | 53 | super.setAboutInfo(appInfo, libInfo) 54 | } 55 | 56 | 57 | } -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 6 | 8 | 11 | 17 | 23 | 29 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/drawable/ic_launcher_foreground_app.xml: -------------------------------------------------------------------------------- 1 | 6 | 8 | 11 | 17 | 23 | 29 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/layout/content_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 21 | 22 | 26 | 27 | 28 | 29 | 35 | 36 | 37 | 38 | 39 | 40 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | PCSC 3 | BLE not supported 4 | USB HOST not supported 5 | Open navigation drawer 6 | Close navigation drawer 7 | 8 | Device Information 9 | Run 10 | scan_button 11 | Info 12 | 13 | Connected 14 | Disconnected 15 | ATR 16 | card mute 17 | Retrieving readerList information 18 | Loading… 19 | Absent 20 | Present 21 | Shutdown 22 | Send mail 23 | 24 | no C-APDU 25 | no card 26 | Wake-up 27 | 28 | Options 29 | About 30 | Logs 31 | Devices 32 | 33 | Enable Logs 34 | Stop on error 35 | Time measurement 36 | Use authentication 37 | Key index 38 | Authentication key 39 | The key must be 16 bytes long 40 | 41 | Connect 42 | Disconnect 43 | 44 | Logo 45 | Application Information 46 | Library Information 47 | www.springcard.com 48 | 49 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | SPRINGCARD SOFTWARE DEVELOPMENT KIT (SDK) LICENSE AGREEMENT 2 | ----------------------------------------------------------- 3 | 4 | This software is part of the SPRINGCARD SDK FOR PC/SC 5 | 6 | Redistribution and use in source (source code) and binary 7 | (object code) forms, with or without modification, are 8 | permitted provided that the following conditions are met : 9 | 10 | 1. Redistributed source code or object code shall be used 11 | only in conjunction with products (hardware devices) either 12 | manufactured, distributed or developed by SPRINGCARD, 13 | 14 | 2. Redistributed source code, either modified or 15 | un-modified, must retain the above copyright notice, 16 | this list of conditions and the disclaimer below, 17 | 18 | 3. Redistribution of any modified code must be clearly 19 | identified "Code derived from original SPRINGCARD 20 | copyrighted source code", with a description of the 21 | modification and the name of its author, 22 | 23 | 4. Redistributed object code must reproduce the above 24 | copyright notice, this list of conditions and the 25 | disclaimer below in the documentation and/or other 26 | materials provided with the distribution, 27 | 28 | 5. The name of SPRINGCARD may not be used to endorse 29 | or promote products derived from this software or in any 30 | other form without specific prior written permission from 31 | SPRINGCARD. 32 | 33 | THIS SOFTWARE IS PROVIDED BY SPRINGCARD "AS IS". 34 | SPRINGCARD SHALL NOT BE LIABLE FOR INFRINGEMENTS OF THIRD 35 | PARTIES RIGHTS BASED ON THIS SOFTWARE. 36 | 37 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 38 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 39 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 40 | 41 | SPRINGCARD DOES NOT WARRANT THAT THE FUNCTIONS CONTAINED IN 42 | THIS SOFTWARE WILL MEET THE USER'S REQUIREMENTS OR THAT THE 43 | OPERATION OF IT WILL BE UNINTERRUPTED OR ERROR-FREE. 44 | 45 | IN NO EVENT SHALL SPRINGCARD BE LIABLE FOR ANY DIRECT, 46 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 47 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 48 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 49 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 50 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 51 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 52 | THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 53 | OF SUCH DAMAGE. 54 | 55 | Contact: www.springcard.com 56 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/values-fr/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | PCSC 4 | BLE non supporté 5 | Hôte USB non supporté 6 | Ouvrir le tiroir de navigation 7 | Fermer le tiroir de navigation 8 | Informations du périphériques 9 | Lancer 10 | Scanner 11 | Informations 12 | 13 | Connecté 14 | Déconnecté 15 | ATR 16 | Carte muette 17 | Récupération des données 18 | Chargement… 19 | Absent 20 | Present 21 | Arréter 22 | Envoyer par mail 23 | 24 | Pas de C-APDU 25 | Pas de carte 26 | Réveiller 27 | 28 | Options 29 | À propos 30 | Journal 31 | Périphériques 32 | 33 | Activer les Logs 34 | Arrêt en cas d\'erreur 35 | Mesurer le temps d\'exécution 36 | Sécuriser la communication 37 | Index Clef 38 | Clef de sécurité 39 | La taille de la clé doit être de 16 octets 40 | 41 | Connecter 42 | Déconnecter 43 | 44 | Logo 45 | Informations sur l\'application 46 | Informations sur la librairie 47 | www.springcard.com 48 | -------------------------------------------------------------------------------- /projects/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /projects/.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | 39 | 40 | 44 | 45 | -------------------------------------------------------------------------------- /projects/PcscLike/src/main/java/com/springcard/pcsclike/SCardChannel.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019 SpringCard - www.springcard.com 3 | * All right reserved 4 | * This software is covered by the SpringCard SDK License Agreement - see LICENSE.txt 5 | */ 6 | 7 | package com.springcard.pcsclike 8 | 9 | import com.springcard.pcsclike.communication.* 10 | 11 | /** 12 | * Represents a channel 13 | * You can get this object with a call to reader.cardConnect() 14 | * 15 | * @property parent Points to an [SCardReader] object 16 | * @property atr Card’s ATR 17 | * 18 | */ 19 | class SCardChannel internal constructor(val parent: SCardReader) { 20 | 21 | var atr: ByteArray = ByteArray(0) 22 | internal set 23 | 24 | /** 25 | * Transmit a C-APDU to the card, receive the R-APDU in response (in the callback) 26 | * @param command The C-APDU to send to the card 27 | * 28 | * @throws Exception if the device is sleeping, there is a command already processing, the slot number exceed 255 29 | */ 30 | fun transmit(command: ByteArray) { 31 | 32 | if(parent.parent.isSleeping) { 33 | parent.parent.postCallback {parent.parent.callbacks.onReaderListError (parent.parent, SCardError(SCardError.ErrorCodes.BUSY, "Error: Device is sleeping"))} 34 | return 35 | } 36 | 37 | /* Update to new state and lock machine state if necessary */ 38 | parent.parent.enterExclusive() 39 | parent.parent.machineState.setNewState(State.WritingCmdAndWaitingResp) 40 | /* Build the frame */ 41 | val ccidCmd = parent.parent.ccidHandler.scardTransmit(parent.index.toByte(), command) 42 | 43 | /* Send the frame */ 44 | parent.parent.commLayer.writeCommand(ccidCmd) 45 | 46 | /* NB: The lock will be exited when the response will arrive */ 47 | } 48 | 49 | /** 50 | * Disconnect from the card (close the communication channel + power down) 51 | * 52 | * @throws Exception if the device is sleeping, there is a command already processing, the slot number exceed 255 53 | */ 54 | fun disconnect() { 55 | 56 | if(parent.parent.isSleeping) { 57 | parent.parent.postCallback {parent.parent.callbacks.onReaderListError (parent.parent, SCardError(SCardError.ErrorCodes.BUSY, "Error: Device is sleeping"))} 58 | return 59 | } 60 | 61 | parent.parent.enterExclusive() 62 | parent.parent.machineState.setNewState(State.WritingCmdAndWaitingResp) 63 | val ccidCmd = parent.parent.ccidHandler.scardDisconnect(parent.index.toByte()) 64 | parent.parent.commLayer.writeCommand(ccidCmd) 65 | } 66 | 67 | /** 68 | * Counterpart to PC/SC’s SCardReconnect, same as [SCardReader.cardConnect] 69 | * 70 | * @throws Exception the device is sleeping, there is a command already processing, the slot number exceed 255 71 | */ 72 | fun reconnect() { 73 | parent.cardConnect() 74 | } 75 | } -------------------------------------------------------------------------------- /projects/PcscLikeSample/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // PcscLikeSample/build.gradle.kts 2 | plugins { 3 | id("com.android.library") 4 | id("org.jetbrains.kotlin.android") 5 | id("org.jetbrains.kotlin.plugin.parcelize") 6 | } 7 | 8 | android { 9 | namespace = "com.springcard.pcsclike_sample" 10 | compileSdk = 36 11 | 12 | buildFeatures { 13 | compose = true 14 | viewBinding = true 15 | } 16 | 17 | defaultConfig { 18 | minSdk = 22 19 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 20 | vectorDrawables { 21 | useSupportLibrary = true 22 | } 23 | } 24 | 25 | buildTypes { 26 | release { 27 | isMinifyEnabled = false 28 | proguardFiles( 29 | getDefaultProguardFile("proguard-android.txt"), 30 | "proguard-rules.pro" 31 | ) 32 | //buildConfigField("Boolean", "libraryDebug", "false") 33 | } 34 | debug { 35 | //buildConfigField("Boolean", "libraryDebug", "true") 36 | } 37 | } 38 | 39 | compileOptions { 40 | sourceCompatibility = JavaVersion.VERSION_17 41 | targetCompatibility = JavaVersion.VERSION_17 42 | } 43 | 44 | kotlinOptions { 45 | jvmTarget = "17" 46 | } 47 | 48 | composeOptions { 49 | kotlinCompilerExtensionVersion = "1.5.1" 50 | } 51 | packaging { 52 | resources { 53 | excludes += "/META-INF/{AL2.0,LGPL2.1}" 54 | } 55 | } 56 | 57 | viewBinding { 58 | enable = true 59 | } 60 | } 61 | 62 | dependencies { 63 | implementation("androidx.core:core-ktx:1.12.0") 64 | implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0") 65 | implementation("androidx.activity:activity-compose:1.8.2") 66 | implementation("androidx.constraintlayout:constraintlayout:2.0.1") 67 | implementation(platform("androidx.compose:compose-bom:2024.04.00")) 68 | implementation("androidx.compose.ui:ui") 69 | implementation("androidx.compose.ui:ui-graphics") 70 | implementation("androidx.compose.ui:ui-tooling-preview") 71 | implementation("androidx.compose.material3:material3") 72 | implementation("androidx.fragment:fragment-ktx:1.6.2") 73 | implementation("com.google.android.material:material:1.11.0") 74 | implementation(project(":PcscLike")) 75 | testImplementation("junit:junit:4.13.2") 76 | androidTestImplementation("androidx.test.ext:junit:1.1.5") 77 | androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") 78 | androidTestImplementation(platform("androidx.compose:compose-bom:2024.04.00")) 79 | androidTestImplementation("androidx.compose.ui:ui-test-junit4") 80 | debugImplementation("androidx.compose.ui:ui-tooling") 81 | debugImplementation("androidx.compose.ui:ui-test-manifest") 82 | implementation("androidx.appcompat:appcompat:1.2.0") 83 | implementation("com.google.code.gson:gson:2.8.5") 84 | implementation("com.android.volley:volley:1.2.0") 85 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Output directories 2 | _*/ 3 | 4 | # Backups 5 | *.bak 6 | *.~* 7 | 8 | # Temporary files 9 | *.tmp 10 | *.tmp_proj 11 | 12 | # Compiled object files 13 | *.o 14 | *.kko 15 | *.obj 16 | *.elf 17 | *.slo 18 | *.slo 19 | *.obj 20 | *.dcu 21 | *.class 22 | 23 | # Precompiled headers and information files 24 | *.gch 25 | *.pch 26 | *.map 27 | *.bpl 28 | *.bpi 29 | *.dcp 30 | *.apk 31 | *.drc 32 | *.dres 33 | *.rsm 34 | *.tds 35 | 36 | # Libraries 37 | *.lib 38 | *.a 39 | *.la 40 | *.lo 41 | *.jar 42 | *.war 43 | *.ear 44 | *.dll 45 | *.so 46 | *.so.* 47 | *.dylib 48 | 49 | # Executables 50 | *.exe 51 | *.out 52 | *.app 53 | *.i*86 54 | *.x86_64 55 | *.hex 56 | *.a20 57 | *.x 58 | 59 | # Visual Studio 60 | *.ipch 61 | *.suo 62 | *.sdf 63 | *.user 64 | *.ncb 65 | *.sbr 66 | *.log 67 | *.tlog 68 | *.userosscache 69 | *.sln.docstates 70 | .vs/ 71 | ipch/ 72 | [Dd]ebug/ 73 | [Dd]ebugPublic/ 74 | [Rr]elease/ 75 | [Rr]eleases/ 76 | x64/ 77 | x86/ 78 | build/ 79 | bld/ 80 | [Bb]in/ 81 | [Oo]bj/ 82 | [Tt]est[Rr]esult*/ 83 | [Bb]uild[Ll]og.* 84 | *.VisualState.xml 85 | TestResult.xml 86 | [Dd]ebugPS/ 87 | [Rr]eleasePS/ 88 | _UpgradeReport_Files/ 89 | Backup*/ 90 | UpgradeLog*.XML 91 | UpgradeLog*.htm 92 | packages 93 | 94 | # Xamarin 95 | *.userprefs 96 | 97 | # External binaries 98 | !binaries/ 99 | !binaries/* 100 | !binaries/*/* 101 | !binaries/*/*/* 102 | !binaries/*/*/*/* 103 | 104 | 105 | # Android 106 | 107 | # Built application files 108 | *.apk 109 | *.ap_ 110 | *.aab 111 | 112 | # Files for the ART/Dalvik VM 113 | *.dex 114 | 115 | # Java class files 116 | *.class 117 | 118 | # Generated files 119 | bin/ 120 | gen/ 121 | out/ 122 | 123 | # Gradle files 124 | .gradle/ 125 | build/ 126 | 127 | # Local configuration file (sdk path, etc) 128 | local.properties 129 | 130 | # Proguard folder generated by Eclipse 131 | proguard/ 132 | 133 | # Log Files 134 | *.log 135 | 136 | # Android Studio Navigation editor temp files 137 | .navigation/ 138 | 139 | # Android Studio captures folder 140 | captures/ 141 | 142 | # IntelliJ 143 | *.iml 144 | .idea/workspace.xml 145 | .idea/tasks.xml 146 | .idea/gradle.xml 147 | .idea/assetWizardSettings.xml 148 | .idea/dictionaries 149 | .idea/libraries 150 | .idea/caches 151 | projects/.idea/misc.xml 152 | 153 | # Keystore files 154 | # Uncomment the following lines if you do not want to check your keystore files in. 155 | #*.jks 156 | #*.keystore 157 | 158 | # External native build folder generated in Android Studio 2.2 and later 159 | .externalNativeBuild 160 | 161 | # Google Services (e.g. APIs or Firebase) 162 | google-services.json 163 | 164 | # Freeline 165 | freeline.py 166 | freeline/ 167 | freeline_project_description.json 168 | 169 | # fastlane 170 | fastlane/report.xml 171 | fastlane/Preview.html 172 | fastlane/screenshots 173 | fastlane/test_output 174 | fastlane/readme.md 175 | 176 | #Copy to tests dirs 177 | copy_to_github.sh 178 | 179 | 180 | #AspcetJ class 181 | !projects/PcscLike/src/debug 182 | projects/.idea 183 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/java/com/springcard/pcsclike_sample/AboutFragment.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019 SpringCard - www.springcard.com 3 | * All right reserved 4 | * This software is covered by the SpringCard SDK License Agreement - see LICENSE.txt 5 | */ 6 | 7 | package com.springcard.pcsclike_sample 8 | 9 | import android.graphics.Typeface 10 | import android.os.Bundle 11 | import androidx.fragment.app.Fragment 12 | import android.view.* 13 | import android.widget.TextView 14 | import android.widget.TableLayout 15 | import android.widget.TableRow 16 | import androidx.core.content.ContextCompat 17 | import com.springcard.pcsclike_sample.databinding.FragmentAboutBinding 18 | 19 | class AboutFragment : Fragment() { 20 | 21 | private var _binding: FragmentAboutBinding? = null 22 | private val binding get() = _binding!! 23 | 24 | private lateinit var appInfo: MainActivity.ApplicationInfo 25 | private lateinit var libInfo: MainActivity.LibraryInfo 26 | 27 | override fun onCreateView( 28 | inflater: LayoutInflater, container: ViewGroup?, 29 | savedInstanceState: Bundle? 30 | ): View? { 31 | val mainActivity = activity as MainActivity 32 | mainActivity.setActionBarTitle(getString(R.string.menu_about)) 33 | 34 | _binding = FragmentAboutBinding.inflate(inflater, container, false) 35 | return binding.root 36 | } 37 | 38 | override fun onDestroyView() { 39 | super.onDestroyView() 40 | _binding = null 41 | } 42 | 43 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 44 | super.onViewCreated(view, savedInstanceState) 45 | 46 | addNewLine(binding.appInfoTable,"Version Code", appInfo.VERSION_CODE.toString()) 47 | addNewLine(binding.appInfoTable,"Version Name", appInfo.VERSION_NAME) 48 | addNewLine(binding.appInfoTable,"Debug", appInfo.DEBUG.toString()) 49 | 50 | addNewLine(binding.libInfoTable,"Library Name", libInfo.libraryName) 51 | addNewLine(binding.libInfoTable,"Version Name", libInfo.libraryVersion) 52 | addNewLine(binding.libInfoTable,"Debug", libInfo.libraryDebug.toString()) 53 | } 54 | 55 | private fun addNewLine(table: TableLayout, key: String, value: String) { 56 | val row = TableRow(activity) 57 | val tv1 = TextView(activity) 58 | val tv2 = TextView(activity) 59 | 60 | tv1.text = key 61 | tv1.typeface = Typeface.DEFAULT_BOLD 62 | tv1.setTextColor(ContextCompat.getColor(requireContext(), R.color.text_color)) 63 | val params1 = TableRow.LayoutParams(0, TableRow.LayoutParams.WRAP_CONTENT, 1f) 64 | tv1.layoutParams = params1 65 | 66 | tv2.text = value 67 | tv2.setTextColor(ContextCompat.getColor(requireContext(), R.color.text_color)) 68 | val params2 = TableRow.LayoutParams(0, TableRow.LayoutParams.WRAP_CONTENT, 1f) 69 | tv2.layoutParams = params2 70 | 71 | row.addView(tv1) 72 | row.addView(tv2) 73 | 74 | table.addView(row) 75 | } 76 | 77 | fun setAboutInfo(app: MainActivity.ApplicationInfo, lib: MainActivity.LibraryInfo) { 78 | appInfo = app 79 | libInfo = lib 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/java/com/springcard/pcsclike_sample/DeviceListAdapter.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019 SpringCard - www.springcard.com 3 | * All right reserved 4 | * This software is covered by the SpringCard SDK License Agreement - see LICENSE.txt 5 | */ 6 | 7 | package com.springcard.pcsclike_sample 8 | 9 | import android.content.Context 10 | import android.view.LayoutInflater 11 | import android.view.View 12 | import android.view.ViewGroup 13 | import android.widget.BaseAdapter 14 | import android.widget.ImageView 15 | import android.widget.TextView 16 | import com.springcard.pcsclike_sample.R 17 | 18 | class DeviceListAdapter(private val context: Context, 19 | private val dataSource: ArrayList) : BaseAdapter() { 20 | 21 | private val inflater: LayoutInflater 22 | = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater 23 | 24 | override fun getCount(): Int { 25 | return dataSource.size 26 | } 27 | 28 | override fun getItem(position: Int): Any { 29 | return dataSource[position] 30 | } 31 | 32 | override fun getItemId(position: Int): Long { 33 | return position.toLong() 34 | } 35 | 36 | override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { 37 | val viewHolder: ViewHolder 38 | val rowView: View 39 | 40 | if (convertView == null) { 41 | rowView = inflater.inflate(R.layout.row_device, parent, false) 42 | viewHolder = ViewHolder().apply { 43 | titleTextView = rowView.findViewById(R.id.name) 44 | subtitleTextView = rowView.findViewById(R.id.rssi) 45 | signalImageView = rowView.findViewById(R.id.signalIcon) 46 | } 47 | rowView.tag = viewHolder 48 | } else { 49 | rowView = convertView 50 | viewHolder = rowView.tag as ViewHolder 51 | } 52 | 53 | val device = getItem(position) as DeviceListElement 54 | viewHolder.titleTextView.text = device.name 55 | viewHolder.subtitleTextView.text = device.info.toString() 56 | 57 | try{ 58 | val rssi = device.info.toInt() 59 | when { 60 | rssi < -100 -> { 61 | viewHolder.signalImageView.setImageResource(R.drawable.ic_signal_cellular_0_bar) 62 | } 63 | rssi < -75 -> { 64 | viewHolder.signalImageView.setImageResource(R.drawable.ic_signal_cellular_1_bar) 65 | } 66 | rssi < -50 -> { 67 | viewHolder.signalImageView.setImageResource(R.drawable.ic_signal_cellular_2_bar) 68 | } 69 | rssi < -25 -> { 70 | viewHolder.signalImageView.setImageResource(R.drawable.ic_signal_cellular_3_bar) 71 | } 72 | else -> { 73 | viewHolder.signalImageView.setImageResource(R.drawable.ic_signal_cellular_4_bar) 74 | } 75 | } 76 | } 77 | catch (e: Exception){ 78 | viewHolder.signalImageView.setImageResource(R.drawable.ic_signal_cellular_4_bar) 79 | } 80 | 81 | 82 | return rowView 83 | } 84 | } 85 | 86 | private class ViewHolder { 87 | lateinit var titleTextView: TextView 88 | lateinit var subtitleTextView: TextView 89 | lateinit var signalImageView: ImageView 90 | } -------------------------------------------------------------------------------- /projects/AndroidPcscLikeBackground.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | image/svg+xml 46 | 49 | 54 | 59 | 60 | 62 | 69 | 73 | 77 | 81 | 85 | 86 | 95 | 96 | 97 | 100 | 103 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // PcscLikeSampleBle/build.gradle.kts 2 | import java.io.FileInputStream 3 | import java.util.* 4 | 5 | plugins { 6 | id("com.android.application") 7 | id("org.jetbrains.kotlin.android") 8 | id("org.jetbrains.kotlin.plugin.parcelize") 9 | } 10 | 11 | android { 12 | namespace = "com.springcard.pcsclike_sample_ble" 13 | compileSdk = 36 14 | 15 | buildFeatures{ 16 | buildConfig = true 17 | } 18 | 19 | defaultConfig { 20 | applicationId = "com.springcard.pcsclike_sample_ble" 21 | minSdk = 22 22 | targetSdk = 36 23 | versionCode = 13 24 | versionName = "1.3.1" 25 | 26 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 27 | vectorDrawables { 28 | useSupportLibrary = true 29 | } 30 | } 31 | 32 | signingConfigs { 33 | create("DefaultSigning") { 34 | val localPropertiesFile = rootProject.file("local.properties") 35 | val localProperties = Properties() 36 | localProperties.load(FileInputStream(localPropertiesFile)) 37 | 38 | /*keyAlias = localProperties.getProperty("key_alias", "") 39 | keyPassword = localProperties.getProperty("key_password", "") 40 | storeFile = file(localProperties.getProperty("key_file", "")) 41 | storePassword = localProperties.getProperty("key_password", "")*/ 42 | } 43 | } 44 | 45 | buildTypes { 46 | release { 47 | isMinifyEnabled = false 48 | proguardFiles( 49 | getDefaultProguardFile("proguard-android-optimize.txt"), 50 | "proguard-rules.pro" 51 | ) 52 | //buildConfigField("Boolean", "appDebug", "false") 53 | signingConfig = signingConfigs.getByName("DefaultSigning") 54 | } 55 | debug { 56 | buildConfigField("Boolean", "appDebug", "true") 57 | } 58 | } 59 | compileOptions { 60 | sourceCompatibility = JavaVersion.VERSION_17 61 | targetCompatibility = JavaVersion.VERSION_17 62 | } 63 | kotlinOptions { 64 | jvmTarget = "17" 65 | } 66 | buildFeatures { 67 | compose = true 68 | } 69 | composeOptions { 70 | kotlinCompilerExtensionVersion = "1.5.1" 71 | } 72 | packaging { 73 | resources { 74 | excludes += "/META-INF/{AL2.0,LGPL2.1}" 75 | } 76 | } 77 | viewBinding { 78 | enable = true 79 | } 80 | } 81 | 82 | dependencies { 83 | implementation("androidx.core:core-ktx:1.12.0") 84 | implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0") 85 | implementation("androidx.activity:activity-compose:1.8.2") 86 | implementation(platform("androidx.compose:compose-bom:2024.04.00")) 87 | implementation("androidx.compose.ui:ui") 88 | implementation("androidx.compose.ui:ui-graphics") 89 | implementation("androidx.compose.ui:ui-tooling-preview") 90 | implementation("androidx.compose.material3:material3") 91 | testImplementation("junit:junit:4.13.2") 92 | androidTestImplementation("androidx.test.ext:junit:1.1.5") 93 | androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") 94 | androidTestImplementation(platform("androidx.compose:compose-bom:2024.04.00")) 95 | androidTestImplementation("androidx.compose.ui:ui-test-junit4") 96 | debugImplementation("androidx.compose.ui:ui-tooling") 97 | debugImplementation("androidx.compose.ui:ui-test-manifest") 98 | implementation("androidx.appcompat:appcompat:1.2.0") 99 | implementation("com.google.code.gson:gson:2.8.5") 100 | implementation("com.android.volley:volley:1.2.0") 101 | implementation("com.google.android.material:material:1.11.0") 102 | implementation("androidx.legacy:legacy-support-v4:1.0.0") 103 | implementation(project(":PcscLike")) 104 | implementation(project(":PcscLikeSample")) 105 | } -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import java.io.FileInputStream 2 | import java.util.* 3 | 4 | // PcscLikeSampleUsb/build.gradle.kts 5 | plugins { 6 | id("com.android.application") 7 | id("org.jetbrains.kotlin.android") 8 | id("org.jetbrains.kotlin.plugin.parcelize") 9 | } 10 | 11 | android { 12 | namespace = "com.springcard.pcsclike_sample_usb" 13 | compileSdk = 36 14 | 15 | buildFeatures{ 16 | buildConfig = true 17 | } 18 | 19 | defaultConfig { 20 | applicationId = "com.springcard.pcsclike_sample_usb" 21 | minSdk = 22 22 | targetSdk = 36 23 | versionCode = 13 24 | versionName = "1.3.1" 25 | 26 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 27 | vectorDrawables { 28 | useSupportLibrary = true 29 | } 30 | } 31 | 32 | signingConfigs { 33 | create("DefaultSigning") { 34 | val localPropertiesFile = rootProject.file("local.properties") 35 | val localProperties = Properties().apply { 36 | load(FileInputStream(localPropertiesFile)) 37 | } 38 | 39 | /*keyAlias = localProperties.getProperty("key_alias", "") 40 | keyPassword = localProperties.getProperty("key_password", "") 41 | storeFile = file(localProperties.getProperty("key_file", "")) 42 | storePassword = localProperties.getProperty("key_password", "")*/ 43 | } 44 | } 45 | 46 | buildTypes { 47 | release { 48 | isMinifyEnabled = true 49 | proguardFiles( 50 | getDefaultProguardFile("proguard-android-optimize.txt"), 51 | "proguard-rules.pro" 52 | ) 53 | //buildConfigField("Boolean", "appDebug", "false") 54 | signingConfig = signingConfigs.getByName("DefaultSigning") 55 | } 56 | debug { 57 | buildConfigField("Boolean", "appDebug", "true") 58 | } 59 | } 60 | 61 | compileOptions { 62 | sourceCompatibility = JavaVersion.VERSION_17 63 | targetCompatibility = JavaVersion.VERSION_17 64 | } 65 | kotlinOptions { 66 | jvmTarget = "17" 67 | } 68 | buildFeatures { 69 | compose = true 70 | } 71 | composeOptions { 72 | kotlinCompilerExtensionVersion = "1.5.1" 73 | } 74 | packaging { 75 | resources { 76 | excludes += "/META-INF/{AL2.0,LGPL2.1}" 77 | } 78 | } 79 | viewBinding { 80 | enable = true 81 | } 82 | } 83 | 84 | dependencies { 85 | implementation("androidx.core:core-ktx:1.12.0") 86 | implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0") 87 | implementation("androidx.activity:activity-compose:1.8.2") 88 | implementation(platform("androidx.compose:compose-bom:2024.04.00")) 89 | implementation("androidx.compose.ui:ui") 90 | implementation("androidx.compose.ui:ui-graphics") 91 | implementation("androidx.compose.ui:ui-tooling-preview") 92 | implementation("androidx.compose.material3:material3") 93 | testImplementation("junit:junit:4.13.2") 94 | androidTestImplementation("androidx.test.ext:junit:1.1.5") 95 | androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") 96 | androidTestImplementation(platform("androidx.compose:compose-bom:2024.04.00")) 97 | androidTestImplementation("androidx.compose.ui:ui-test-junit4") 98 | debugImplementation("androidx.compose.ui:ui-tooling") 99 | debugImplementation("androidx.compose.ui:ui-test-manifest") 100 | implementation("androidx.appcompat:appcompat:1.2.0") 101 | implementation("com.google.code.gson:gson:2.8.5") 102 | implementation("com.android.volley:volley:1.2.0") 103 | implementation("com.google.android.material:material:1.11.0") 104 | implementation("androidx.legacy:legacy-support-v4:1.0.0") 105 | implementation(project(":PcscLikeSample")) 106 | implementation(project(":PcscLike")) 107 | } -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/java/com/springcard/pcsclike_sample/LogFragment.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019 SpringCard - www.springcard.com 3 | * All right reserved 4 | * This software is covered by the SpringCard SDK License Agreement - see LICENSE.txt 5 | */ 6 | 7 | package com.springcard.pcsclike_sample 8 | 9 | import android.annotation.SuppressLint 10 | import android.graphics.Typeface 11 | import android.os.Bundle 12 | import androidx.fragment.app.Fragment 13 | import android.util.TypedValue 14 | import android.view.* 15 | import android.widget.TableRow 16 | import android.widget.TextView 17 | import android.content.Intent 18 | import androidx.core.content.ContextCompat 19 | import androidx.core.view.MenuHost 20 | import androidx.core.view.MenuProvider 21 | import androidx.lifecycle.Lifecycle 22 | import com.springcard.pcsclike_sample.R 23 | import com.springcard.pcsclike_sample.databinding.FragmentLogBinding 24 | import java.text.DateFormat 25 | import java.text.SimpleDateFormat 26 | import java.util.* 27 | 28 | 29 | class LogFragment : Fragment() { 30 | 31 | private var _binding: FragmentLogBinding? = null 32 | private val binding get() = _binding!! 33 | 34 | private var logString = mutableListOf() 35 | private val mainActivity by lazy { 36 | activity as MainActivity 37 | } 38 | 39 | fun appendToLog(message: String) { 40 | logString.add(message) 41 | } 42 | 43 | override fun onCreate(savedInstanceState: Bundle?) { 44 | super.onCreate(savedInstanceState) 45 | 46 | } 47 | 48 | override fun onCreateView( 49 | inflater: LayoutInflater, container: ViewGroup?, 50 | savedInstanceState: Bundle? 51 | ): View { 52 | mainActivity.setActionBarTitle(getString(R.string.menu_logs)) 53 | _binding = FragmentLogBinding.inflate(inflater, container, false) 54 | return binding.root 55 | } 56 | 57 | override fun onDestroyView() { 58 | super.onDestroyView() 59 | _binding = null 60 | } 61 | 62 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 63 | super.onViewCreated(view, savedInstanceState) 64 | for(msg in logString) { 65 | addNewLine(msg) 66 | } 67 | val menuHost: MenuHost = requireActivity() 68 | menuHost.addMenuProvider(object : MenuProvider { 69 | override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { 70 | menuInflater.inflate(R.menu.log_app_bar, menu) 71 | } 72 | 73 | override fun onMenuItemSelected(menuItem: MenuItem): Boolean { 74 | return when (menuItem.itemId) { 75 | R.id.send_button -> { 76 | val now = Date() 77 | val formatter = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.getDefault()) 78 | val date = formatter.format(now) 79 | sendMail("${getString(R.string.local_app_name)} Log - $date", logString.joinToString("\n")) 80 | true 81 | } 82 | else -> false 83 | } 84 | } 85 | }, viewLifecycleOwner, Lifecycle.State.RESUMED) 86 | } 87 | 88 | private fun addNewLine(message: String) { 89 | val row = TableRow(activity) 90 | val tv1 = TextView(activity) 91 | 92 | tv1.text = message 93 | tv1.typeface = Typeface.MONOSPACE 94 | tv1.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 10F) 95 | tv1.setTextColor(ContextCompat.getColor(requireContext(), R.color.text_color)) 96 | row.addView(tv1) 97 | 98 | binding.logTable.addView(row) 99 | } 100 | 101 | 102 | private fun sendMail(subject: String, content: String) { 103 | val intent = Intent(Intent.ACTION_SEND) 104 | intent.type = "text/plain" 105 | intent.putExtra(Intent.EXTRA_EMAIL, arrayOf("support@springcard.com")) 106 | intent.putExtra(Intent.EXTRA_SUBJECT, subject) 107 | intent.putExtra(Intent.EXTRA_TEXT, content) 108 | startActivity(Intent.createChooser(intent, "Send Email")) 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /projects/.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | xmlns:android 21 | 22 | ^$ 23 | 24 | 25 | 26 |
27 |
28 | 29 | 30 | 31 | xmlns:.* 32 | 33 | ^$ 34 | 35 | 36 | BY_NAME 37 | 38 |
39 |
40 | 41 | 42 | 43 | .*:id 44 | 45 | http://schemas.android.com/apk/res/android 46 | 47 | 48 | 49 |
50 |
51 | 52 | 53 | 54 | .*:name 55 | 56 | http://schemas.android.com/apk/res/android 57 | 58 | 59 | 60 |
61 |
62 | 63 | 64 | 65 | name 66 | 67 | ^$ 68 | 69 | 70 | 71 |
72 |
73 | 74 | 75 | 76 | style 77 | 78 | ^$ 79 | 80 | 81 | 82 |
83 |
84 | 85 | 86 | 87 | .* 88 | 89 | ^$ 90 | 91 | 92 | BY_NAME 93 | 94 |
95 |
96 | 97 | 98 | 99 | .* 100 | 101 | http://schemas.android.com/apk/res/android 102 | 103 | 104 | ANDROID_ATTRIBUTE_ORDER 105 | 106 |
107 |
108 | 109 | 110 | 111 | .* 112 | 113 | .* 114 | 115 | 116 | BY_NAME 117 | 118 |
119 |
120 |
121 |
122 | 123 | 125 |
126 |
-------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/java/com/springcard/pcsclike_sample/AppPreferences.kt: -------------------------------------------------------------------------------- 1 | package com.springcard.pcsclike_sample 2 | 3 | import android.content.Context 4 | import com.google.gson.Gson 5 | 6 | class AppPreferences(private val ctx: Context) { 7 | 8 | private val options = "optionsPcscApp" 9 | private val enableLogName = "enableLog" 10 | private val stopOnErrorName = "stopOnError" 11 | private val enableTimeMeasurementName = "enableTimeMeasurement" 12 | private val useAuthentificationName = "useAuthentication" 13 | private val authenticationKeyName = "authenticationKey" 14 | private val authenticationKeyIndexName = "authenticationKeyIndex" 15 | private val apduModelsName = "apduModels" 16 | private val defaultApdusName = "defaultApdus" 17 | 18 | var enableLog: Boolean 19 | get() { 20 | 21 | val sp = ctx.getSharedPreferences(options, 0) 22 | return sp.getBoolean(enableLogName, true) 23 | } 24 | set(value) { 25 | val editor = ctx.getSharedPreferences(options, 0).edit() 26 | editor.putBoolean(enableLogName, value) 27 | editor.apply() 28 | } 29 | 30 | var stopOnError: Boolean 31 | get() { 32 | val sp = ctx.getSharedPreferences(options, 0) 33 | return sp.getBoolean(stopOnErrorName, false) 34 | } 35 | set(value) { 36 | val editor = ctx.getSharedPreferences(options, 0).edit() 37 | editor.putBoolean(stopOnErrorName, value) 38 | editor.apply() 39 | } 40 | 41 | var enableTimeMeasurement: Boolean 42 | get() { 43 | val sp = ctx.getSharedPreferences(options, 0) 44 | return sp.getBoolean(enableTimeMeasurementName, false) 45 | } 46 | set(value) { 47 | val editor = ctx.getSharedPreferences(options, 0).edit() 48 | editor.putBoolean(enableTimeMeasurementName, value) 49 | editor.apply() 50 | } 51 | 52 | 53 | 54 | var useAuthentication: Boolean 55 | get() { 56 | val sp = ctx.getSharedPreferences(options, 0) 57 | return sp.getBoolean(useAuthentificationName, false) 58 | } 59 | set(value) { 60 | val editor = ctx.getSharedPreferences(options, 0).edit() 61 | editor.putBoolean(useAuthentificationName, value) 62 | editor.apply() 63 | } 64 | 65 | var authenticationKey: String 66 | get() { 67 | val sp = ctx.getSharedPreferences(options, 0) 68 | return sp.getString(authenticationKeyName, "00000000000000000000000000000000")!! 69 | } 70 | set(value) { 71 | val editor = ctx.getSharedPreferences(options, 0).edit() 72 | editor.putString(authenticationKeyName, value) 73 | editor.apply() 74 | } 75 | 76 | var authenticationKeyIndex: Int 77 | get() { 78 | val sp = ctx.getSharedPreferences(options, 0) 79 | return sp.getInt(authenticationKeyIndexName, 0) 80 | } 81 | set(value) { 82 | val editor = ctx.getSharedPreferences(options, 0).edit() 83 | editor.putInt(authenticationKeyIndexName, value) 84 | editor.apply() 85 | } 86 | 87 | var modelsApdusJson: String 88 | get() { 89 | val sp = ctx.getSharedPreferences(options, 0) 90 | return sp.getString(apduModelsName, "[{\"id\":0,\"title\":\"Card\\u0027s ATR\",\"mode\":0,\"apdu\":\"ff:ca:fa:00\",\"created\":\"2017-03-28T09:31:40+00:00\",\"modified\":\"2017-03-28T09:31:40+00:00\",\"group_id\":null,\"group\":\"\"}]")!! 91 | } 92 | set(value) { 93 | val editor = ctx.getSharedPreferences(options, 0).edit() 94 | editor.putString(apduModelsName, value) 95 | editor.apply() 96 | } 97 | 98 | var defaultApdus: ApduModel? 99 | get() { 100 | val sp = ctx.getSharedPreferences(options, 0) 101 | val json = sp.getString(defaultApdusName, "") 102 | return Gson().fromJson(json, ApduModel::class.java) 103 | } 104 | set(value) { 105 | val editor = ctx.getSharedPreferences(options, 0).edit() 106 | editor.putString(defaultApdusName, Gson().toJson(value)) 107 | editor.apply() 108 | } 109 | } -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/java/com/springcard/pcsclike_sample_ble/DeviceFragment.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019 SpringCard - www.springcard.com 3 | * All right reserved 4 | * This software is covered by the SpringCard SDK License Agreement - see LICENSE.txt 5 | */ 6 | 7 | package com.springcard.pcsclike_sample_ble 8 | 9 | 10 | import android.Manifest 11 | import android.bluetooth.BluetoothDevice 12 | import android.content.pm.PackageManager 13 | import android.os.Build 14 | import android.widget.Toast 15 | import androidx.core.content.ContextCompat 16 | import com.springcard.pcsclike.* 17 | import com.springcard.pcsclike.ccid.* 18 | import com.springcard.pcsclike.utils.* 19 | import com.springcard.pcsclike_sample.DeviceFragment 20 | 21 | class DeviceFragment : DeviceFragment() { 22 | 23 | override fun connectToDevice() { 24 | 25 | if(device is BluetoothDevice) { 26 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { 27 | if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) { 28 | return 29 | } 30 | } 31 | else{ 32 | if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { 33 | return 34 | } 35 | } 36 | deviceName = (device as BluetoothDevice).name 37 | 38 | if(mainActivity.supportCrypto && mainActivity.preferences.useAuthentication) { 39 | mainActivity.logInfo("Create readerList with authentication") 40 | 41 | /* Add lock emoji to device name */ 42 | deviceName = "\uD83D\uDD12 $deviceName" 43 | 44 | val key: MutableList 45 | if(mainActivity.preferences.authenticationKey.isHex()) { 46 | key = mainActivity.preferences.authenticationKey.hexStringToByteArray().toMutableList() 47 | } 48 | else { 49 | progressDialog.dismiss() 50 | mainActivity.backToScanFragment() 51 | return 52 | } 53 | 54 | if(key.size != 16) { 55 | Toast.makeText(mainActivity.applicationContext, "Wrong key size, must be 16 bytes long", Toast.LENGTH_LONG) 56 | progressDialog.dismiss() 57 | mainActivity.backToScanFragment() 58 | return 59 | } 60 | 61 | val index: CcidSecureParameters.AuthenticationKeyIndex = when { 62 | mainActivity.preferences.authenticationKeyIndex == 0 -> CcidSecureParameters.AuthenticationKeyIndex.User 63 | mainActivity.preferences.authenticationKeyIndex == 1 -> CcidSecureParameters.AuthenticationKeyIndex.Admin 64 | else -> { 65 | Toast.makeText(mainActivity.applicationContext, "Wrong key index ${mainActivity.preferences.authenticationKeyIndex}", Toast.LENGTH_LONG) 66 | progressDialog.dismiss() 67 | mainActivity.backToScanFragment() 68 | return 69 | } 70 | } 71 | 72 | SCardReaderList.create( 73 | mainActivity.applicationContext, 74 | device as BluetoothDevice, 75 | scardCallbacks, 76 | CcidSecureParameters( 77 | CcidSecureParameters.AuthenticationMode.Aes128, 78 | index, 79 | key, 80 | CcidSecureParameters.CommunicationMode.MacAndCipher 81 | ) 82 | ) 83 | } 84 | else { 85 | SCardReaderList.create(mainActivity.applicationContext, device as BluetoothDevice, scardCallbacks) 86 | } 87 | } 88 | else { 89 | mainActivity.logInfo("Device is not a BLE device") 90 | } 91 | } 92 | 93 | override fun init(_device: Any) { 94 | 95 | if(_device is BluetoothDevice) { 96 | device = _device 97 | } 98 | else { 99 | mainActivity.logInfo("Device is not a BLE device") 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /projects/PcscLike/src/main/java/com/springcard/pcsclike/utils/Utils.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019 SpringCard - www.springcard.com 3 | * All right reserved 4 | * This software is covered by the SpringCard SDK License Agreement - see LICENSE.txt 5 | */ 6 | 7 | package com.springcard.pcsclike.utils 8 | 9 | import android.util.Log 10 | import kotlin.experimental.xor 11 | 12 | 13 | private val HEX_CHARS = "0123456789ABCDEF".toCharArray() 14 | 15 | /** 16 | * Convert a ByteArray to a String in hexadecimal format 17 | * ex: ```[ 0x1F, 0xAB, 0xCD ] -> 1FABCD```. 18 | * See [String.hexStringToByteArray] to do the inverse 19 | * 20 | * @receiver ByteArray to convert 21 | * @return Hexadecimal string 22 | */ 23 | fun ByteArray.toHexString(): String { 24 | val result = StringBuffer() 25 | 26 | forEach { 27 | val octet = it.toInt() 28 | val firstIndex = (octet and 0xF0).ushr(4) 29 | val secondIndex = octet and 0x0F 30 | result.append(HEX_CHARS[firstIndex]) 31 | result.append(HEX_CHARS[secondIndex]) 32 | } 33 | 34 | return result.toString() 35 | } 36 | 37 | 38 | 39 | fun Collection.toHexString(): String { 40 | return this.toByteArray().toHexString() 41 | } 42 | 43 | fun Byte.toHexString(): String { 44 | return "0x${this.toString(16).uppercase().padStart(2, '0')}" 45 | } 46 | 47 | fun UByte.toHexString(): String { 48 | return "0x${this.toString(16).uppercase().padStart(2, '0')}" 49 | } 50 | 51 | /* 52 | fun MutableCollection.toHexString(): String { 53 | return this.toByteArray().toHexString() 54 | }*/ 55 | 56 | 57 | /** 58 | * Rotate an array by one byte to the left 59 | */ 60 | fun ByteArray.RotateLeftOneByte(): ByteArray { 61 | val result = ByteArray(this.size) 62 | 63 | for (i in 1 until this.size) 64 | result[i - 1] = this[i] 65 | result[this.size - 1] = this[0] 66 | 67 | return result 68 | } 69 | 70 | 71 | /** 72 | * Rotate an array by one byte to the right 73 | */ 74 | fun ByteArray.RotateRightOneByte(): ByteArray { 75 | val result = ByteArray(size) 76 | 77 | for (i in size - 1 downTo 1) 78 | result[i] = this[i - 1] 79 | result[0] = this[size - 1] 80 | 81 | return result 82 | } 83 | 84 | /** 85 | * Logical XOR of two arrays: result = buffer1 XOR buffer2. The length of the resulting array is set to the shortest of both. 86 | */ 87 | fun XOR(buffer1: MutableList, buffer2: MutableList): MutableList { 88 | 89 | val result = mutableListOf() 90 | 91 | if(buffer1.size != buffer2.size) { 92 | Log.d("Utils", "XOR: Buffers don't have the same size") 93 | } 94 | 95 | for (i in buffer1.indices) { 96 | result.add(buffer1[i] xor buffer2[i]) 97 | } 98 | return result 99 | } 100 | 101 | /** 102 | * Convert an hexadecimal String to a ByteArray 103 | * ex: ```1FABCD -> [ 0x1F, 0xAB, 0xCD ]```. 104 | * See [ByteArray.toHexString] to do the inverse 105 | * 106 | * @receiver String to convert 107 | * @return ByteArray 108 | */ 109 | fun String.hexStringToByteArray(): ByteArray { 110 | 111 | val result = ByteArray(length / 2) 112 | 113 | for (i in 0 until length step 2) { 114 | val firstIndex = HEX_CHARS.indexOf(this[i]) 115 | val secondIndex = HEX_CHARS.indexOf(this[i + 1]) 116 | 117 | val octet = firstIndex.shl(4).or(secondIndex) 118 | result[i.shr(1)] = octet.toByte() 119 | } 120 | 121 | return result 122 | } 123 | 124 | internal val String.Empty: String 125 | get() = "" 126 | 127 | 128 | /** 129 | * Check is a string represent an hexadecimal value 130 | * (even length, digit and A-F chars) 131 | * 132 | * @receiver String to be checked 133 | * @return true if the string is an hexadecimal value 134 | */ 135 | fun String.isHex(): Boolean { 136 | 137 | if (this.isEmpty()) { 138 | return false 139 | } 140 | 141 | // length should be even number 142 | // otherwise its not a valid hex 143 | if (this.length % 2 == 0) { 144 | val var1 = "(?i)[0-9A-F]+" 145 | return this.matches(var1.toRegex()) 146 | } 147 | 148 | return false 149 | } 150 | 151 | // LSB first 5555555 = 0xE3 0xB5 0x4F 0x03 152 | internal fun Int.bytes(): ByteArray { 153 | val b = mutableListOf(0, 0, 0, 0) 154 | 155 | for (i in 0 until 4) { 156 | b[i] = (this shr (i*8)).toByte() 157 | } 158 | 159 | return b.toByteArray() 160 | } 161 | 162 | -------------------------------------------------------------------------------- /projects/PcscLike/src/main/java/com/springcard/pcsclike/ccid/CcidFrame.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019 SpringCard - www.springcard.com 3 | * All right reserved 4 | * This software is covered by the SpringCard SDK License Agreement - see LICENSE.txt 5 | */ 6 | 7 | package com.springcard.pcsclike.ccid 8 | 9 | import android.util.Log 10 | import com.springcard.pcsclike.utils.* 11 | import java.nio.ByteBuffer 12 | import java.nio.ByteOrder 13 | import kotlin.experimental.and 14 | import kotlin.experimental.inv 15 | import kotlin.experimental.or 16 | 17 | internal abstract class CcidFrame { 18 | 19 | private val TAG: String 20 | get() = this::class.java.simpleName 21 | 22 | /* Array containing the whole data */ 23 | /* initialize with header (10 first bytes) to zero */ 24 | var raw = mutableListOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 25 | internal set 26 | 27 | /* Two parts of the frame */ 28 | 29 | val header: ByteArray 30 | get() { 31 | return raw.slice(0 until HEADER_SIZE).toByteArray() 32 | } 33 | 34 | 35 | var payload: ByteArray 36 | get() { 37 | return raw.slice(HEADER_SIZE until raw.size).toByteArray() 38 | } 39 | protected set(newPayload) { 40 | // keep old header and append new payload 41 | val headerSaved = header.toList() 42 | raw = mutableListOf() 43 | raw.addAll(headerSaved) 44 | raw.addAll(newPayload.toList()) 45 | 46 | // Update length 47 | length = newPayload.size 48 | } 49 | 50 | /* Different fields of the header and the payload */ 51 | 52 | var code: Byte 53 | get() { 54 | return raw[0] 55 | } 56 | protected set(value) { 57 | raw[0] = value 58 | } 59 | 60 | var ciphered: Boolean 61 | get() { 62 | return raw[4] == CIPHERED_BIT 63 | } 64 | internal set(value) { 65 | if(value) 66 | raw[4] = raw[4] or CIPHERED_BIT 67 | else 68 | raw[4] = raw[4] and CIPHERED_BIT.inv() 69 | } 70 | 71 | var length: Int 72 | get() { 73 | val lengthArray = raw.slice(1 .. 4).toByteArray() 74 | lengthArray[3] = lengthArray[3] and CIPHERED_BIT.inv() 75 | val buffer = ByteBuffer.wrap(lengthArray) 76 | buffer.order(ByteOrder.LITTLE_ENDIAN) 77 | 78 | val expectedSize = buffer.int 79 | 80 | if(expectedSize != payload.size) { 81 | Log.w(TAG, "Warning, Size specified ($expectedSize) does not match size of payload (${payload.size})") 82 | return HEADER_SIZE 83 | } 84 | return expectedSize 85 | } 86 | set(value) { 87 | val lengthArray = value.bytes() 88 | raw[1] = lengthArray[0] 89 | raw[2] = lengthArray[1] 90 | raw[3] = lengthArray[2] 91 | raw[4] = (raw[4] and CIPHERED_BIT) or lengthArray[3] 92 | } 93 | 94 | var slotNumber: Byte 95 | get() { 96 | return raw[5] 97 | } 98 | protected set(value) { 99 | raw[5] = value 100 | } 101 | 102 | var sequenceNumber: Byte 103 | get() { 104 | return raw[6] 105 | } 106 | internal set(value) { 107 | raw[6] = value 108 | } 109 | 110 | 111 | companion object { 112 | const val CIPHERED_BIT: Byte = 0x80.toByte() 113 | const val HEADER_SIZE = 10 114 | } 115 | 116 | } 117 | 118 | internal class CcidCommand(cmdCode : CommandCode, slotNb: Byte, data: ByteArray) : CcidFrame() { 119 | 120 | enum class CommandCode(var value: Byte) { 121 | PC_To_RDR_IccPowerOn(0x62.toByte()), 122 | PC_To_RDR_IccPowerOff(0x63.toByte()), 123 | PC_To_RDR_GetSlotStatus(0x65.toByte()), 124 | PC_To_RDR_Escape(0x6B.toByte()), 125 | PC_To_RDR_XfrBlock(0x6F.toByte()), 126 | } 127 | 128 | init { 129 | code = cmdCode.value 130 | slotNumber = slotNb 131 | payload = data 132 | sequenceNumber = 0 133 | } 134 | 135 | val parameters: ByteArray 136 | get() { 137 | return raw.slice(7 until HEADER_SIZE).toByteArray() 138 | } 139 | } 140 | 141 | 142 | internal class CcidResponse(rawFrame: ByteArray) : CcidFrame() { 143 | 144 | enum class ResponseCode(var value: Byte) { 145 | RDR_To_PC_DataBlock(0x80.toByte()), 146 | RDR_To_PC_SlotStatus(0x81.toByte()), 147 | RDR_To_PC_Escape(0x83.toByte()) 148 | } 149 | 150 | init { 151 | raw = rawFrame.toMutableList() 152 | if(raw.size == 0) { 153 | raw = mutableListOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 154 | } 155 | } 156 | 157 | val slotStatus: Byte 158 | get() { 159 | return raw[7] 160 | } 161 | 162 | val slotError: Byte 163 | get() { 164 | return raw[8] 165 | } 166 | } -------------------------------------------------------------------------------- /projects/PcscLikeSampleBle/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 32 | 34 | 36 | 38 | 40 | 42 | 44 | 46 | 48 | 50 | 52 | 54 | 56 | 58 | 60 | 62 | 64 | 66 | 68 | 70 | 72 | 74 | 75 | -------------------------------------------------------------------------------- /projects/PcscLikeSampleUsb/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 32 | 34 | 36 | 38 | 40 | 42 | 44 | 46 | 48 | 50 | 52 | 54 | 56 | 58 | 60 | 62 | 64 | 66 | 68 | 70 | 72 | 74 | 75 | -------------------------------------------------------------------------------- /projects/AndroidPcscLikeBle.icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | image/svg+xml 46 | 49 | 54 | 59 | 60 | 61 | 63 | 65 | 69 | 70 | 78 | 86 | 94 | 95 | 97 | 99 | 103 | 104 | 105 | 108 | 111 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /projects/AndroidPcscLikeUsb.icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | image/svg+xml 46 | 49 | 54 | 59 | 60 | 61 | 63 | 65 | 69 | 70 | 78 | 86 | 94 | 95 | 98 | 101 | 105 | 106 | 107 | 109 | 111 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /projects/PcscLike/src/main/java/com/springcard/pcsclike/SCardError.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019 SpringCard - www.springcard.com 3 | * All right reserved 4 | * This software is covered by the SpringCard SDK License Agreement - see LICENSE.txt 5 | */ 6 | 7 | package com.springcard.pcsclike 8 | 9 | /** 10 | * Class used by the errors callbacks when an error occurred 11 | * It contains some information about how the error happened 12 | * 13 | * @property code The error code 14 | * @property detail Detailed information about the error 15 | * @property isFatal If the error was critical, the device was lost and disconnected 16 | * @property message Message corresponding to the ErrorCodes 17 | * 18 | */ 19 | class SCardError(val code: ErrorCodes, val detail : String = "", val isFatal: Boolean = false) { 20 | 21 | val message : String 22 | get() { 23 | return code.name 24 | } 25 | 26 | /** 27 | * List of error codes 28 | * 29 | * @property value Error code value (2 bytes) 30 | */ 31 | enum class ErrorCodes(val value: Int){ 32 | 33 | /** 34 | * No Error, everything is OK 35 | */ 36 | NO_ERROR(0x0000), 37 | /** 38 | * Invalid parameter 39 | */ 40 | INVALID_PARAMETER(0x1000), 41 | /** 42 | * Other error 43 | */ 44 | OTHER_ERROR(0xFFFF), 45 | /** 46 | * Device is Busy 47 | */ 48 | BUSY(0x1001), 49 | 50 | /** 51 | * The library has been called to instantiate a device (SCardReaderList object), 52 | * but the provided input parameter does not refer to a connected BLE device. 53 | * Or the underlying BLE device has been disconnected 54 | */ 55 | DEVICE_NOT_CONNECTED(0x1100), 56 | /** 57 | * The device's primary service is not supported by the library 58 | */ 59 | UNSUPPORTED_PRIMARY_SERVICE(0x1200), 60 | /** 61 | * One of the mandatory services is missing from the device's GATT 62 | */ 63 | MISSING_SERVICE(0x1300), 64 | /** 65 | * One of the mandatory characteristics is missing from the device's GATT 66 | */ 67 | MISSING_CHARACTERISTIC(0x1400), 68 | /** 69 | * One of the mandatory services has not the expected settings 70 | * (for instance, bonding flags not consistent with the implementation in the library) 71 | */ 72 | INVALID_SERVICE_SETTINGS(0x1500), 73 | /** 74 | * One of the mandatory characteristics has not the expected settings 75 | * (for instance, read/write/notify flags not consistent with the implementation in the library) 76 | */ 77 | INVALID_CHARACTERISTIC_SETTINGS(0x1600), 78 | /** 79 | * The library has failed to enable the notifications or indications on a given characteristic 80 | */ 81 | ENABLE_CHARACTERISTIC_EVENTS_FAILED(0x1700), 82 | /** 83 | * The library has failed to read a given characteristic 84 | */ 85 | READ_CHARACTERISTIC_FAILED(0x1800), 86 | /** 87 | * The library has failed to write a given characteristic 88 | */ 89 | WRITE_CHARACTERISTIC_FAILED(0x1900), 90 | /** 91 | * The underlying BLE device is still connected, but a CCID-level timeout has occurred 92 | * (no RDR_To_PC after a PC_To_RDR) 93 | */ 94 | COMMUNICATION_TIMEOUT(0x1A00), 95 | /** 96 | * The format of the RDR_To_PC or CCID_Status characteristic is invalid 97 | * (unsupported opcode, bad length etc) 98 | */ 99 | PROTOCOL_ERROR(0x1B00), 100 | /** 101 | * The device does not answer as expected 102 | * (ex: empty response to a SCardControl that is looking for the slot name) 103 | */ 104 | DIALOG_ERROR(0x1C00), 105 | /** 106 | * The number of slots in CCID_Status is 0 107 | */ 108 | DUMMY_DEVICE(0x1D00), 109 | 110 | /** 111 | * The authentication between the library and the device has failed 112 | */ 113 | AUTHENTICATION_ERROR(0x2100), 114 | /** 115 | * Wrong CMAC or frame decipher failed 116 | */ 117 | SECURE_COMMUNICATION_ERROR(0x2200), 118 | /** 119 | * The device has reported a secure communication on its side and is closing the communication 120 | */ 121 | SECURE_COMMUNICATION_ABORTED(0x2300), 122 | 123 | /** 124 | * getReader invoked with an invalid parameter 125 | */ 126 | NO_SUCH_SLOT(0x3100), 127 | /** 128 | * Connect invoked, but there's no card in the slot 129 | */ 130 | CARD_ABSENT(0x3200), 131 | /** 132 | * A card is present, but it is unresponsive 133 | */ 134 | CARD_MUTE(0x3300), 135 | /** 136 | * Transmit or Disconnect invoked, but the library is aware that the card has already been removed 137 | */ 138 | CARD_REMOVED(0x3400), 139 | /** 140 | * Transmit invoked, and no response from the card (the card is likely to have been removed during the exchange) 141 | */ 142 | CARD_COMMUNICATION_ERROR(0x3400), 143 | /** 144 | * Transmit invoked, but Disconnect has been called earlier 145 | */ 146 | CARD_POWERED_DOWN(0x3500) 147 | } 148 | } -------------------------------------------------------------------------------- /projects/PcscLike/src/main/java/com/springcard/pcsclike/communication/GattAttributes.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019 SpringCard - www.springcard.com 3 | * All right reserved 4 | * This software is covered by the SpringCard SDK License Agreement - see LICENSE.txt 5 | */ 6 | 7 | package com.springcard.pcsclike.communication 8 | 9 | import java.util.* 10 | 11 | 12 | open class GattAttributes { 13 | 14 | private val standardUuidPrefix = "0000" 15 | private val standardUuidSuffix = "-0000-1000-8000-00805F9B34FB" 16 | 17 | private fun getUuidFromShort(shortUuid: String) : UUID { 18 | return UUID.fromString("$standardUuidPrefix$shortUuid$standardUuidSuffix") 19 | } 20 | 21 | protected fun getUuid(longUuid: String) : UUID { 22 | return UUID.fromString(longUuid) 23 | } 24 | 25 | /* Generic Services */ 26 | 27 | val UUID_GENERIC_ACCESS_SERVICE = getUuidFromShort("1800") 28 | val UUID_DEVICE_NAME_CHAR = getUuidFromShort("2A00") 29 | val UUID_APPEARANCE_CHAR = getUuidFromShort("2A01") 30 | 31 | val UUID_DEVICE_INFORMATION_SERVICE = getUuidFromShort("180A") 32 | val UUID_MANUFACTURER_NAME_STRING_CHAR = getUuidFromShort("2A29") 33 | val UUID_MODEL_NUMBER_STRING_CHAR = getUuidFromShort("2A24") 34 | val UUID_SERIAL_NUMBER_STRING_CHAR = getUuidFromShort("2A25") 35 | val UUID_FIRMWARE_REVISION_STRING_CHAR = getUuidFromShort("2A26") 36 | val UUID_SOFTWARE_REVISION_STRING_CHAR = getUuidFromShort("2A28") 37 | val UUID_HARDWARE_REVISION_STRING_CHAR = getUuidFromShort("2A27") 38 | val UUID_PNP_ID_CHAR = getUuidFromShort("2A50") 39 | 40 | val UUID_BATTERY_SERVICE = getUuidFromShort("180F") 41 | val UUID_BATTERY_LEVEL_CHAR = getUuidFromShort("2A19") 42 | 43 | val UUID_GENERIC_ATTRIBUTE_SERVICE = getUuidFromShort("180F") 44 | val UUID_SERVICE_CHANGED_CHAR = getUuidFromShort("2A05") 45 | 46 | } 47 | 48 | object GattAttributesD600 : GattAttributes() { 49 | 50 | /* SpringCard Services */ 51 | 52 | val UUID_SPRINGCARD_RFID_SCAN_PCSC_LIKE_SERVICE = getUuid("6CB501B7-96F6-4EEF-ACB1-D7535F153CF0") // 53 | val UUID_SPRINGCARD_SCAN_DATA_CHAR = getUuid("CE3E81B8-D871-4613-BA78-5FFC0B1520A6") 54 | val UUID_SPRINGCARD_SCAN_CONTROL_CHAR = getUuid("833A2364-BCA0-4647-8113-478E1FC449BA") 55 | val UUID_SPRINGCARD_CCID_STATUS_CHAR = getUuid("7C334BC2-1812-4C7E-A81D-591F92933C37") 56 | val UUID_SPRINGCARD_CCID_TO_RDR_CHAR = getUuid("91ACE9FD-EDD6-40B1-BA77-050A78CF9BC0") 57 | val UUID_SPRINGCARD_CCID_TO_PC_CHAR = getUuid("B4CA2D75-B855-4C1A-BF40-4A72AE46BD5A") 58 | 59 | val UUID_SPRINGCARD_DEVICE_CONFIG_SERVICE = getUuid("7A4385C9-F7C7-4E22-9AFD-16D68FC588CA") 60 | val UUID_SPRINGCARD_CONFIG_IO_CHAR = getUuid("1254FC72-336E-4BB2-A0A8-71C7D28D73CE") 61 | 62 | val UUID_SPRINGCARD_OTA_DFU_SERVICE = getUuid("D7B82F8E-7D95-4143-8D97-B57FC21B025B") 63 | val UUID_SPRINGCARD_DFU_TO_RDR_CHAR = getUuid("AC38BCCD-D1D6-4DF6-AE84-AE6A951F9971") 64 | val UUID_SPRINGCARD_DFU_TO_PC_CHAR = getUuid("9110BC7E-124B-4D93-B29B-BC7BF74AE964") 65 | } 66 | 67 | 68 | object GattAttributesSpringCore : GattAttributes() { 69 | 70 | /* SpringCard Services */ 71 | 72 | val UUID_SPRINGCARD_CCID_PLAIN_SERVICE = getUuid("F91C914F-367C-4108-AC3E-3D30CFDD0A1A") // 73 | private val UUID_CCID_PC_TO_RDR_PLAIN_CHAR = getUuid("281EBED4-86C4-4253-84F1-57FB9AB2F72C") 74 | private val UUID_CCID_RDR_TO_PC_PLAIN_CHAR = getUuid("811DC7A6-A573-4E15-89CC-7EFACAE04E3C") 75 | private val UUID_CCID_STATUS_PLAIN_CHAR = getUuid("EAB75CAB-C7DC-4DB9-874C-4AD8EE0F180F") 76 | 77 | val UUID_SPRINGCARD_CCID_BONDED_SERVICE = getUuid("7F20CDC5-A9FC-4C70-9292-3ACF9DE71F73") // 78 | private val UUID_CCID_PC_TO_RDR_BONDED_CHAR = getUuid("CD5BCE75-65FC-4747-AB9A-FF82BFDFA7FB") 79 | private val UUID_CCID_RDR_TO_PC_BONDED_CHAR = getUuid("94EDE62E-0808-46F8-91EC-AC0272D67796") 80 | private val UUID_CCID_STATUS_BONDED_CHAR = getUuid("DC2AA4CA-76A9-43F9-9FE5-127652837EF5") 81 | 82 | val UUID_SPRINGCARD_S320_PLAIN_SERVICE = getUuid("F91C914F-367C-4108-AC3E-3D3030323353") 83 | val UUID_SPRINGCARD_S320_BONDED_SERVICE = getUuid("7F20CDC5-A9FC-4C70-9292-3ACF30323353") 84 | 85 | val UUID_SPRINGCARD_S370_PLAIN_SERVICE = getUuid("F91C914F-367C-4108-AC3E-3D3030373353") 86 | val UUID_SPRINGCARD_S370_BONDED_SERVICE = getUuid("7F20CDC5-A9FC-4C70-9292-3ACF30373353") 87 | 88 | /* Access to CCID characteristic transparently whereas it's bonded or not */ 89 | 90 | var isCcidServiceBonded = false 91 | 92 | val UUID_SPRINGCARD_CCID_SERVICE : UUID 93 | get() { 94 | return if( !isCcidServiceBonded) 95 | UUID_SPRINGCARD_CCID_PLAIN_SERVICE 96 | else 97 | UUID_SPRINGCARD_CCID_BONDED_SERVICE 98 | } 99 | 100 | val UUID_CCID_PC_TO_RDR_CHAR: UUID 101 | get() { 102 | return if( !isCcidServiceBonded) 103 | UUID_CCID_PC_TO_RDR_PLAIN_CHAR 104 | else 105 | UUID_CCID_PC_TO_RDR_BONDED_CHAR 106 | } 107 | 108 | val UUID_CCID_RDR_TO_PC_CHAR: UUID 109 | get() { 110 | return if( !isCcidServiceBonded) 111 | UUID_CCID_RDR_TO_PC_PLAIN_CHAR 112 | else 113 | UUID_CCID_RDR_TO_PC_BONDED_CHAR 114 | } 115 | 116 | val UUID_CCID_STATUS_CHAR: UUID 117 | get() { 118 | return if( !isCcidServiceBonded) 119 | UUID_CCID_STATUS_PLAIN_CHAR 120 | else 121 | UUID_CCID_STATUS_BONDED_CHAR 122 | } 123 | 124 | } 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /projects/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /projects/PcscLike/src/main/java/com/springcard/pcsclike/SCardReaderListCallback.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018-2019 SpringCard - www.springcard.com 3 | * All right reserved 4 | * This software is covered by the SpringCard SDK License Agreement - see LICENSE.txt 5 | */ 6 | 7 | package com.springcard.pcsclike 8 | 9 | import android.util.Log 10 | 11 | /* This class call the methods provided by SCardReaderListCallback and overwritten by the user */ 12 | internal class LoggedSCardReaderListCallback(private var callbacks: SCardReaderListCallback) : SCardReaderListCallback() { 13 | 14 | private val TAG = this::class.java.simpleName 15 | 16 | /* TODO CRA: use it in AOP class*/ 17 | private fun logMethodName(name: String?) { 18 | if(name != null) 19 | Log.d(TAG, "<-- $name()") 20 | else 21 | Log.d(TAG, "<-- callback()") 22 | } 23 | 24 | /* Methods overwritten */ 25 | 26 | override fun onReaderListCreated(readerList: SCardReaderList) { 27 | logMethodName(object{}.javaClass.enclosingMethod?.name) 28 | callbacks.onReaderListCreated(readerList) 29 | } 30 | 31 | override fun onReaderListClosed(readerList: SCardReaderList?) { 32 | logMethodName(object{}.javaClass.enclosingMethod?.name) 33 | callbacks.onReaderListClosed(readerList) 34 | } 35 | 36 | override fun onControlResponse(readerList: SCardReaderList, response: ByteArray) { 37 | logMethodName(object{}.javaClass.enclosingMethod?.name) 38 | callbacks.onControlResponse(readerList, response) 39 | } 40 | 41 | override fun onReaderStatus(slot: SCardReader, cardPresent: Boolean, cardConnected: Boolean) { 42 | logMethodName(object{}.javaClass.enclosingMethod?.name) 43 | callbacks.onReaderStatus(slot, cardPresent, cardConnected) 44 | } 45 | 46 | override fun onCardConnected(channel: SCardChannel) { 47 | logMethodName(object{}.javaClass.enclosingMethod?.name) 48 | callbacks.onCardConnected(channel) 49 | } 50 | 51 | override fun onCardDisconnected(channel: SCardChannel) { 52 | logMethodName(object{}.javaClass.enclosingMethod?.name) 53 | callbacks.onCardDisconnected(channel) 54 | } 55 | 56 | override fun onTransmitResponse(channel: SCardChannel, response: ByteArray) { 57 | logMethodName(object{}.javaClass.enclosingMethod?.name) 58 | callbacks.onTransmitResponse(channel, response) 59 | } 60 | 61 | override fun onReaderListError(readerList: SCardReaderList?, error: SCardError) { 62 | logMethodName(object{}.javaClass.enclosingMethod?.name) 63 | callbacks.onReaderListError(readerList, error) 64 | } 65 | 66 | override fun onReaderOrCardError(readerOrCard: Any, error: SCardError) { 67 | logMethodName(object{}.javaClass.enclosingMethod?.name) 68 | callbacks.onReaderOrCardError(readerOrCard, error) 69 | } 70 | 71 | override fun onReaderListState(readerList: SCardReaderList, isInLowPowerMode: Boolean) { 72 | logMethodName(object{}.javaClass.enclosingMethod?.name) 73 | callbacks.onReaderListState(readerList, isInLowPowerMode) 74 | } 75 | } 76 | 77 | 78 | /** 79 | * This abstract class is used to implement [SCardReaderList] callbacks. 80 | */ 81 | abstract class SCardReaderListCallback { 82 | 83 | /** 84 | * When the [SCardReaderList.create] methods finished its job, this method is called 85 | * @param readerList the readerList instantiated 86 | */ 87 | abstract fun onReaderListCreated(readerList: SCardReaderList) 88 | 89 | /** 90 | * When a disconnection from the current connected readerList is asked or when the readerList itself close 91 | * @param readerList SCardReaderList 92 | */ 93 | abstract fun onReaderListClosed(readerList: SCardReaderList?) 94 | 95 | /** 96 | * When a response is received after a call to [SCardReaderList.control] 97 | * @param readerList SCardReaderList 98 | * @param response a byte array if everything went well (empty in case of problem) 99 | */ 100 | abstract fun onControlResponse(readerList: SCardReaderList, response: ByteArray) 101 | 102 | 103 | /** 104 | * When a card is inserted into, or removed from an active reader 105 | * @param slot SCardReader 106 | * @param cardPresent Is the card present? 107 | * @param cardConnected Is the card connected? 108 | */ 109 | abstract fun onReaderStatus(slot: SCardReader, cardPresent: Boolean, cardConnected: Boolean) 110 | 111 | /** 112 | * Used to give the result of a [SCardReader.cardConnect] 113 | * @param channel SCardChannel 114 | */ 115 | abstract fun onCardConnected(channel: SCardChannel) 116 | 117 | /** 118 | * Used when the card is disconnected 119 | * @param channel SCardChannel 120 | */ 121 | abstract fun onCardDisconnected(channel: SCardChannel) 122 | 123 | /** 124 | * When a R-APDU is received after a call to [SCardChannel.transmit] 125 | * @param channel SCardChannel 126 | * @param response a byte array if everything went well (empty in case of problem) 127 | */ 128 | abstract fun onTransmitResponse(channel: SCardChannel, response: ByteArray) 129 | 130 | /* Error callbacks */ 131 | 132 | /** 133 | * Invoked for all readerList-level errors, e.g. BLE error, protocol error, etc. When this callback is invoked, the connection to the readerList is often closed. 134 | * @param readerList SCardReaderList (could be null if the ScardReaderList has not been created yet) 135 | * @param error SCardError 136 | */ 137 | abstract fun onReaderListError(readerList: SCardReaderList?, error: SCardError) 138 | 139 | /** 140 | * Invoked for all “recoverable” errors, e.g. invalid slot number, card absent, card removed or mute, etc. 141 | * @param readerOrCard Any 142 | * @param error SCardError 143 | */ 144 | abstract fun onReaderOrCardError(readerOrCard: Any, error: SCardError) 145 | 146 | /** 147 | * Invoked when the device is going to sleep or waking up 148 | * @param readerList SCardReaderList 149 | * @param isInLowPowerMode True = going to sleep, False = waking-up 150 | */ 151 | abstract fun onReaderListState(readerList: SCardReaderList, isInLowPowerMode: Boolean) 152 | } -------------------------------------------------------------------------------- /projects/PcscLikeSample/src/main/res/drawable-xxhdpi/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | --------------------------------------------------------------------------------