That depends on what version you actually want to find out: the version of the SmartcardService system component or the version of the Open Mobile API framework.
Finding the version of the SmartcardService system application
The most obvious way would be to check the version information of the SmartcardService application package:
final String SMARTCARD_SERVICE_PACKAGE = "org.simalliance.openmobileapi.service";
PackageInfo pi = getPackageManager().getPackageInfo(SMARTCARD_SERVICE_PACKAGE, 0);
String versionName = pi.versionName;
String versionCode = pi.versionCode;
Typical values for versionName
are "2.3.0" (versionCode = 1), "2.4.0" (versionCode = 3), "3.0.0" (versionCode = 4), "3.1.0" (versionCode = 5), and "4.0.0" (versionCode = 8). Thus, you can determine the exact version of SEEK that the SmartcardService was forked from.
Unfortunately, several OEMs (e.g. Samsung) decided to remove the version information from the application package. Consequently, this is not as reliable as one might expect.
Another method that allows you to distinguish between implementations based on SEEK versions < 4.0.0 and SEEK versions >= 4.0.0 is to check the intent filter of the SmartcardService component:
final String SMARTCARD_SERVICE_PACKAGE = "org.simalliance.openmobileapi.service";
final String SMARTCARD_SERVICE_CLASS = "org.simalliance.openmobileapi.service.SmartcardService";
final String SMARTCARD_SERVICE_ACTION_V4 = "org.simalliance.openmobileapi.BIND_SERVICE";
final String SMARTCARD_SERVICE_ACTION_PRE4 = "org.simalliance.openmobileapi.service.ISmartcardService";
Intent intent = new Intent();
intent.setClassName(SMARTCARD_SERVICE_PACKAGE, SMARTCARD_SERVICE_CLASS);
intent.setAction(SMARTCARD_SERVICE_ACTION_V4);
ResolveInfo ri = getPackageManager().resolveService(intent, 0);
if (ri != null) {
// is version >= 4.0.0
} else {
intent.setAction(SMARTCARD_SERVICE_ACTION_PRE4);
ResolveInfo ri = getPackageManager().resolveService(intent, 0);
if (ri != null) {
// is version < 4.0.0
} else {
// is unknown version
}
}
Yet another method that allows you to distinguish between SEEK < 4.0.0 and SEEK >= 4.0.0 is to check if the SmartcardService holds the permission BIND_TERMINAL, a permission introduced in SEEK 4.0.0:
final String SMARTCARD_SERVICE_PACKAGE = "org.simalliance.openmobileapi.service";
final String PERMISSION_BIND_TERMINAL = "org.simalliance.openmobileapi.BIND_TERMINAL";
if (PackageManager.PERMISSION_GRANTED == getPackageManager().checkPermission(PERMISSION_BIND_TERMINAL, SMARTCARD_SERVICE_PACKAGE)) {
// is version >= 4.0.0
} else {
// is version < 4.0.0
}
Finding the version of the Open Mobile API framework
Starting with SEEK version 4.0.0 the SEService
class of the Open Mobile API framework exposes a method getVersion()
that returns the version string of the implemented Open Mobile API specification ("3.0" for SEEK 4.0.0). Thus, you could query that method to find the implemented Open Mobile API version:
Class cls = org.simalliance.openmobileapi.SEService.class;
Method getVersion = null;
try {
getVersion = cls.getDeclaredMethod("getVersion");
} catch (NoSuchMethodException e) {}
if (getVersion != null) {
// probably SEEK >= 4.0.0
} else {
// probably SEEK < 4.0.0
}
Further, if you have an instance of the SEService
object, you could invoke the getVersion()
method to find the implemented Open Mobile API specification version:
If your application was compiled against SEEK < 4.0.0:
if (getVersion != null) {
String version = (String)getVersion.invoke(seService);
}
If your application was compiled against SEEK >= 4.0.0:
if (getVersion != null) {
String version = seService.getVersion();
}
Note that trying to obtain an instance of the SEService
class may result in exactly the undesired behavior that you found in the first place since the constructor of the SEService
class will automatically initiate the connection to the SmartcardService.
Similar to discovering the getVersion()
method, you could also try to discover methods in the API that are specific to a certain version of the Open Mobile API specification. For instance, you could test for the existence of the method
public Channel openBasicChannel(byte[] aid, byte p2);
in the Session
class (org.simalliance.openmobileapi.Session
). This method was introduced in version 3.0 of the specification.
However, you should be aware that detection based on the framework classes will only work if your app uses the Open Mobile API framework classes that are shipped with the target device and does not package its own version of the relevant framework classes. Else you would only detect what you packed into your app and not what's available on the system.
The Open Mobile API framework that is preinstalled on a device would usually be compatible with its backend (SMartcardService) on the same device. Since you seem to have version conflicts it is likely the case that your app packages its own version of the Open Mobile API framework that is incomatible with the target Android version and the Smartcard system service installed on the target device. This is something that you simply should not do.