Skip to content

Commit

Permalink
Refactored
Browse files Browse the repository at this point in the history
Fixed openLogicalChannel issue with OMAPI < 3
  • Loading branch information
ocfmem committed Feb 3, 2020
1 parent 12791f5 commit bab209b
Show file tree
Hide file tree
Showing 10 changed files with 272 additions and 325 deletions.
2 changes: 1 addition & 1 deletion android/keyple-plugin/android-omapi/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ if(project.getProperties().containsKey("release") && release=="true"){

apply plugin: 'com.android.library'
apply plugin: 'maven'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

archivesBaseName = "keyple-android-plugin-omapi"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ import android.content.Context
import org.eclipse.keyple.core.seproxy.AbstractPluginFactory
import org.eclipse.keyple.core.seproxy.ReaderPlugin
import org.eclipse.keyple.plugin.android.omapi.se.AndroidSeOmapiPluginImpl
import org.eclipse.keyple.plugin.android.omapi.simalliance.AndroidSaOmapiPluginImpl
import timber.log.Timber
import org.eclipse.keyple.plugin.android.omapi.simalliance.AndroidOmapiPluginImpl

/**
* Build asynchronously the Android OMAPI plugin.
Expand All @@ -31,7 +30,7 @@ class AndroidOmapiPluginFactory(val context: Context) : AbstractPluginFactory()
//TODO throw error is Android is not compatible with OMAPI
override fun getPluginInstance(): ReaderPlugin {
return if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.P) {
AndroidSaOmapiPluginImpl.init(context)
AndroidOmapiPluginImpl.init(context)
} else {
AndroidSeOmapiPluginImpl.init(context)
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/********************************************************************************
* Copyright (c) 2019 Calypso Networks Association https://www.calypsonet-asso.org/
*
* See the NOTICE file(s) distributed with this work for additional information regarding copyright
* ownership.
*
* This program and the accompanying materials are made available under the terms of the Eclipse
* Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.keyple.plugin.android.omapi

import org.eclipse.keyple.core.seproxy.SeReader
import org.eclipse.keyple.core.seproxy.plugin.local.AbstractLocalReader
import org.eclipse.keyple.core.seproxy.plugin.local.SmartSelectionReader
import org.eclipse.keyple.core.seproxy.protocol.SeCommonProtocols
import org.eclipse.keyple.core.seproxy.protocol.SeProtocol
import org.eclipse.keyple.core.seproxy.protocol.TransmissionMode
import timber.log.Timber
import java.util.HashMap

/**
* Communicates with Android readers throught the Open Mobile API see org.simalliance.openmobileapi.Reader
*
* Instances of this class represent SE readers supported by this device. These readers can be physical devices
* or virtual devices. They can be removable or not. They can contain one SE that can or cannot be
* removed.
*/
abstract class AndroidOmapiReader(pluginName: String, readerName: String): AbstractLocalReader(pluginName, readerName), SmartSelectionReader{

private val parameters: MutableMap<String, String> = HashMap()

override fun getParameters(): Map<String, String> {
Timber.w("No parameters are supported by AndroidOmapiReaderImpl")
return parameters
}

override fun setParameter(key: String, value: String) {
Timber.w("No parameters are supported by AndroidOmapiReaderImpl")
parameters[key] = value
}

/**
* The transmission mode is always CONTACTS in an OMAPI reader
*
* @return the current transmission mode
*/
override fun getTransmissionMode(): TransmissionMode {
return TransmissionMode.CONTACTS
}

/**
* Check that protocolFlag is PROTOCOL_ISO7816_3
* @param protocolFlag
* @return true if match PROTOCOL_ISO7816_3
*/
override fun protocolFlagMatches(protocolFlag: SeProtocol?): Boolean {
return protocolFlag == SeCommonProtocols.PROTOCOL_ISO7816_3
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ object AndroidSeOmapiPluginImpl: AndroidOmapiPlugin<Reader, SEService>(), SEServ
return seService?.readers
}

override fun mapToSeReader(reader: Reader): SeReader{
Timber.d("Reader available name : %s", reader.name)
Timber.d("Reader available isSePresent : %S", reader.isSecureElementPresent)
return AndroidSeOmapiReaderImpl(PLUGIN_NAME, reader, reader.name)
override fun mapToSeReader(nativeReader: Reader): SeReader{
Timber.d("Reader available name : %s", nativeReader.name)
Timber.d("Reader available isSePresent : %S", nativeReader.isSecureElementPresent)
return AndroidSeOmapiReaderImpl(nativeReader, PLUGIN_NAME, nativeReader.name)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,16 @@ package org.eclipse.keyple.plugin.android.omapi.se
import android.se.omapi.Channel
import android.se.omapi.Reader
import android.se.omapi.Session
import android.util.Log
import androidx.annotation.RequiresApi
import org.eclipse.keyple.core.seproxy.SeSelector
import org.eclipse.keyple.core.seproxy.exception.KeypleApplicationSelectionException
import org.eclipse.keyple.core.seproxy.exception.KeypleChannelControlException
import org.eclipse.keyple.core.seproxy.exception.KeypleIOReaderException
import org.eclipse.keyple.core.seproxy.message.ApduResponse
import org.eclipse.keyple.core.seproxy.plugin.local.AbstractLocalReader
import org.eclipse.keyple.core.seproxy.plugin.local.SmartSelectionReader
import org.eclipse.keyple.core.seproxy.protocol.SeCommonProtocols
import org.eclipse.keyple.core.seproxy.protocol.SeProtocol
import org.eclipse.keyple.core.seproxy.protocol.TransmissionMode
import org.eclipse.keyple.core.util.ByteArrayUtil
import org.eclipse.keyple.plugin.android.omapi.AndroidOmapiReader
import org.slf4j.LoggerFactory
import timber.log.Timber
import java.io.IOException
import java.util.HashMap
import java.util.NoSuchElementException
import kotlin.experimental.or

Expand All @@ -28,42 +21,18 @@ import kotlin.experimental.or
* with android.se.omapi
*/
@RequiresApi(android.os.Build.VERSION_CODES.P)
class AndroidSeOmapiReaderImpl(pluginName: String, private val omapiReader: Reader, readerName: String)
: AbstractLocalReader(pluginName, readerName), AndroidOmapiReader, SmartSelectionReader{

private val logger = LoggerFactory.getLogger(AndroidSeOmapiReaderImpl::class.java)

private val TAG = AndroidSeOmapiReaderImpl::class.java.simpleName
internal class AndroidSeOmapiReaderImpl(private val nativeReader: Reader, pluginName: String, readerName: String)
: AndroidOmapiReader(pluginName, readerName){

private var session: Session? = null
private var openChannel: Channel? = null
private val parameters: MutableMap<String, String> = HashMap()

override fun getParameters(): Map<String, String> {
Log.w(TAG, "No parameters are supported by AndroidOmapiReaderImpl")
return parameters
}

override fun setParameter(key: String, value: String) {
Log.w(TAG, "No parameters are supported by AndroidOmapiReaderImpl")
parameters[key] = value
}

/**
* The transmission mode is always CONTACTS in an OMAPI reader
*
* @return the current transmission mode
*/
override fun getTransmissionMode(): TransmissionMode {
return TransmissionMode.CONTACTS
}

/**
* Check if a SE is present in this reader. see {@link Reader#isSecureElementPresent()}
* @return True if the SE is present, false otherwise
*/
override fun checkSePresence(): Boolean {
return omapiReader.isSecureElementPresent
return nativeReader.isSecureElementPresent
}

/**
Expand All @@ -72,7 +41,7 @@ class AndroidSeOmapiReaderImpl(pluginName: String, private val omapiReader: Read
*/
override fun getATR(): ByteArray? {
return session?.let {
Log.i(TAG, "Retrieving ATR from session...")
Timber.i("Retrieving ATR from session...")
it.atr
}
}
Expand All @@ -86,48 +55,46 @@ class AndroidSeOmapiReaderImpl(pluginName: String, private val omapiReader: Read
* @throws KeypleApplicationSelectionException
*/
@Throws(KeypleIOReaderException::class,KeypleChannelControlException::class,KeypleApplicationSelectionException::class)
override fun openChannelForAid(aidSelector: SeSelector.AidSelector?): ApduResponse {
if (aidSelector?.aidToSelect == null) {
override fun openChannelForAid(aidSelector: SeSelector.AidSelector): ApduResponse {
if (aidSelector.aidToSelect == null) {
try {
openChannel = session?.openBasicChannel(null)
} catch (e: IOException) {
Log.e(TAG, "IOException", e)
Timber.e(e, "IOException")
throw KeypleIOReaderException("IOException while opening basic channel.")
} catch (e: SecurityException) {
Log.e(TAG, "SecurityException", e)
Timber.e(e, "SecurityException")
throw KeypleChannelControlException("Error while opening basic channel, SE_SELECTOR = " + aidSelector.toString(), e.cause)
}

if (openChannel == null) {
throw KeypleIOReaderException("Failed to open a basic channel.")
}
} else {
if (logger.isTraceEnabled) {
logger.trace("[{}] openLogicalChannel => Select Application with AID = {}",
this.name, ByteArrayUtil.toHex(aidSelector.aidToSelect.value))
}
Timber.i("[%s] openLogicalChannel => Select Application with AID = %s",
this.name, ByteArrayUtil.toHex(aidSelector.aidToSelect.value))
try {
openChannel =
session?.openLogicalChannel(aidSelector.aidToSelect.value,
aidSelector.fileOccurrence.isoBitMask or aidSelector.fileControlInformation.isoBitMask)
} catch (e: IOException) {
Log.e(TAG, "IOException", e)
Timber.e(e, "IOException")
throw KeypleIOReaderException("IOException while opening logical channel.")
} catch (e: NoSuchElementException) {
Log.e(TAG, "NoSuchElementException", e)
Timber.e(e, "NoSuchElementException")
throw KeypleApplicationSelectionException(
"Error while selecting application : " + ByteArrayUtil.toHex(aidSelector.getAidToSelect().value), e)
"NoSuchElementException: " + ByteArrayUtil.toHex(aidSelector.getAidToSelect().value), e)
} catch (e: SecurityException) {
Log.e(TAG, "SecurityException", e)
throw KeypleChannelControlException("Error while opening logical channel, aid :" + ByteArrayUtil.toHex(aidSelector.getAidToSelect().value), e.cause)
Timber.e(e, "SecurityException")
throw KeypleChannelControlException("SecurityException while opening logical channel, aid :" + ByteArrayUtil.toHex(aidSelector.getAidToSelect().value), e.cause)
}

if (openChannel == null) {
throw KeypleIOReaderException("Failed to open a logical channel.")
}
}
/* get the FCI and build an ApduResponse */
return ApduResponse(openChannel?.selectResponse, aidSelector?.successfulSelectionStatusCodes)
return ApduResponse(openChannel?.selectResponse, aidSelector.successfulSelectionStatusCodes)
}

override fun isPhysicalChannelOpen(): Boolean {
Expand All @@ -137,9 +104,9 @@ class AndroidSeOmapiReaderImpl(pluginName: String, private val omapiReader: Read
@Throws(KeypleChannelControlException::class)
override fun openPhysicalChannel() {
try {
session = omapiReader.openSession()
session = nativeReader.openSession()
} catch (e: IOException) {
Log.e(TAG, "IOException", e)
Timber.e(e, "IOException")
throw KeypleChannelControlException("IOException while opening physical channel.", e)
}
}
Expand All @@ -160,8 +127,8 @@ class AndroidSeOmapiReaderImpl(pluginName: String, private val omapiReader: Read
*/
override fun transmitApdu(apduIn: ByteArray): ByteArray {
// Initialization
Log.d(TAG, "Data Length to be sent to tag : " + apduIn.size)
Log.d(TAG, "Data in : " + ByteArrayUtil.toHex(apduIn))
Timber.d("Data Length to be sent to tag : " + apduIn.size)
Timber.d("Data in : " + ByteArrayUtil.toHex(apduIn))
var dataOut = byteArrayOf(0)
try {
openChannel?.let {
Expand All @@ -171,17 +138,7 @@ class AndroidSeOmapiReaderImpl(pluginName: String, private val omapiReader: Read
throw KeypleIOReaderException("Error while transmitting APDU", e)
}

Log.d(TAG, "Data out : " + ByteArrayUtil.toHex(dataOut))
Timber.d("Data out : " + ByteArrayUtil.toHex(dataOut))
return dataOut
}

/**
* Check that protocolFlag is PROTOCOL_ISO7816_3
* @param protocolFlag
* @return true if match PROTOCOL_ISO7816_3
*/
override fun protocolFlagMatches(protocolFlag: SeProtocol?): Boolean {
return protocolFlag == SeCommonProtocols.PROTOCOL_ISO7816_3
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import org.simalliance.openmobileapi.Reader
import org.simalliance.openmobileapi.SEService
import timber.log.Timber

object AndroidSaOmapiPluginImpl: AndroidOmapiPlugin<Reader, SEService>(), SEService.CallBack {
object AndroidOmapiPluginImpl: AndroidOmapiPlugin<Reader, SEService>(), SEService.CallBack {

override fun connectToSe(context: Context) {
val seServiceFactory = SeServiceFactoryImpl()
Expand All @@ -19,10 +19,10 @@ object AndroidSaOmapiPluginImpl: AndroidOmapiPlugin<Reader, SEService>(), SEServ
return seService?.readers
}

override fun mapToSeReader(reader: Reader): SeReader {
Timber.d("Reader available name : %s", reader.name)
Timber.d("Reader available isSePresent : %S", reader.isSecureElementPresent)
return AndroidOmapiReaderImpl(PLUGIN_NAME, reader, reader.name)
override fun mapToSeReader(nativeReader: Reader): SeReader {
Timber.d("Reader available name : %s", nativeReader.name)
Timber.d("Reader available isSePresent : %S", nativeReader.isSecureElementPresent)
return AndroidOmapiReaderImpl(nativeReader, PLUGIN_NAME, nativeReader.name)
}

/**
Expand Down

0 comments on commit bab209b

Please sign in to comment.