Updates to the HID Approve SDK for Google Android
This page details the design changes made in the new HID® Approve™ SDK for Google® Android®.
Please refer to the code examples provided below that illustrate the code changes, as well as Add Functions to your App.
When migrating from an SDK version earlier than 5.1, users might encounter an upgrade issue on some devices.
Impacted devices:
- Devices running on Android 9.0 or later while upgrading the app.
- Devices will be impacted regardless of the absence or presence of registered containers.
On affected devices, SDK initialization (DeviceFactory.getDevice(...)) can fail after app upgrade. This will provoke a new exception - SerialNumberRequiredException.
If this exception is thrown, two solutions are possible:
- The device serial number must be provided to HID Approve SDK through the appropriate parameter of the DeviceFactory.getDevice(…) in order to complete the upgrade successfully.
- If the device serial number cannot be provided, the SDK must be reset though the dedicated method DeviceFactory.reset() to complete the upgrade. All registered services will be lost. After this operation, the next SDK initialization will be successful.
What's New in Version 5.14 from 5.13
The new version is currently in development and will be available soon.
What's New in Version 5.13 from 5.12
UPDATE HIDDeviceFactory.reset method reviewed to be more robust
UPDATE HIDDeviceFactory.getDevice method reviewed to return a singleton instance of the device
Several deprecated APIs (from SDK 5.5 and SDK 5.7.1) have been removed
What's New in Version 5.12 from 5.11
None - this is release is to provide important security updates and third-party component updates.
What's New in Version 5.11 from 5.10
SDK Additions and New Features
Device
UPDATE retrieveActionInfo method to add InexplicitContainerException exception
NEW retrieveActionInfo(char[] actionId, char[] userId) method with a different signature
What's New in Version 5.10 from 5.9
SDK Additions and New Features
SDKConstants
NEW DEVICE_INFO_LOCALE constant
NEW DEVICE_INFO_ISROOTED constant
NEW PARAM_TX_MOBILE_CONTEXT constant
NEW DEVICE_INFO_FPCAPABLE constant
NEW DEVICE_INFO_FPENROLLED constant
Transaction
UPDATE setStatus method supports the PARAM_TX_MOBILE_CONTEXT parameter
Device
UPDATE getDeviceInfo method supports:
-
DEVICE_INFO_ISROOTED
-
DEVICE_INFO_LOCALE
-
DEVICE_INFO_FPCAPABLE
-
DEVICE_INFO_FPENROLLED
What's New in Version 5.9 from 5.7.1
SDK Updates
-
Support for Weak (Class 2) biometric authenticators
-
Sequential passwords are prohibited unless explicitly authorized with password policy parameters
SDK Additions and New Features
BioAuthenticationState
NEW INVALID_KEY enumeration value
BioPasswordPolicy
UPDATE setBiometricPrompt method to use FragmentActivity
NEW getAuthorizedAuthenticator method accessor
PasswordPolicy
NEW isSequenceAllowed method accessor
Container
NEW getOriginalCreationDate method accessor
ServerAction
NEW getPayload method accessor
What's New in Version 5.7.1 from 5.5.1
SDK Updates
Migration to 5.7.1 from versions 3.0 and 4.0 is no longer supported.
SDK Additions and New Features
PasswordPromptEvent
NEW CONTAINER_POLICY event parameter constant
NEW KEY_POLICY event parameter constant
NEW TYPE event parameter constant
ErrorCode
NEWUnsupportedVersion enumeration value (7)
NEWInvalidContainer enumeration value (8)
Others
REMOVEDSerialNumberRequiredException exception class
NEWInvalidContainerException exception class
AsyncOTPGenerator
UPDATE New exception InvalidParameterException added to all methods
BioPasswordPolicy
REMOVED deprecated enableFingerPrintManager method (use setBiometricPrompt)
REMOVED deprecated getCancelationSignal method
PasswordPolicy
UPDATE New exception InvalidParameterException added to all methods
Container
UPDATE New exception InvalidParameterException added to all methods
NEW updateDeviceInfo method (moved from Device)
void updateDeviceInfo(String name, char[] value, char[] password, Parameter[] params) throws RemoteException, AuthenticationException, UnsupportedDeviceException, InternalException, LostCredentialsException, com.hidglobal.ia.service.exception.FingerprintAuthenticationRequiredException, ServerOperationFailedException, InvalidParameterException;
ContainerInitialization
REMOVED deprecated initialPassword property (use EventListener)
Device
UPDATE New exception InvalidParameterException added to all methods
REMOVED deprecated retrieveTransaction method
NEW retrieveActionInfo method
ServerActionInfo retrieveActionInfo(char[] actionId) throws InternalException, ServerActionContainerInvalidException, InvalidContainerException, InvalidParameterException;
REMOVED deprecated createContainer method (use createContainer with sessionPassword)
REMOVED deprecated reset method (use DeviceFactory reset)
REMOVED deprecated getDefaultInitializationPolicy method (use EventListener)
Key
UPDATE New exception InvalidParameterException added to all methods
Transaction
UPDATE New exception InvalidParameterException added to all methods
UPDATE Class declaration inherits from ServerAction class
Others
DEPRECATED TransactionInfo class (use retrieveActionInfo)
NEW ServerAction class
NEW ServerActionInfo class
DeviceFactory
UPDATE New exception InvalidParameterException added to all methods
REMOVED deprecated getDevice method with deviceSerialNumber
SDKConstants
NEW ACTION_TRANSACTION constant
To ease integration, the unchecked runtime-exception IllegalArgumentException has been replaced with InvalidParameterException to indicate any provided parameters. This new exception has been added to all methods containing parameter as mentioned above.
To ease integration with Proguard/DexGuard/D8 obfuscation, a default rules file has been included in the AAR package.
What's New in Version 5.5.1 from 5.5
SDK Additions and New Features
To ease integration, successful biometric authentications via the BioPasswordPolicy no longer return the FingerprintAuthenticationRequiredException exception. This eliminates the need for a second call to the SDK within the AuthenticationCallback delegate to complete the required operation.
What's New in Version 5.5 from 5.4
SDK Additions and New Features
DeviceFactory
NEW getDevice method
public static Device getDevice(Context context, ConnectionConfiguration config) throws UnsupportedDeviceException, LostCredentialsException, UnsupportedDeviceException, InternalException;
DEPRECATED getDevice method (use new method)
public static Device getDevice(Context context, ConnectionConfiguration config, char[] sessionPassword) throws UnsupportedDeviceException, LostCredentialsException, UnsupportedDeviceException, InternalException;
Documentation has been updated to specify possible exceptions on some functions and methods.
To ease integration, InvalidPasswordException password-related exceptions have been declared as InvalidPasswordException, PasswordExpiredException, and PasswordNotYetUpdatableException.
What's New in Version 5.4 from 5.1
SDK Additions and New Features
ErrorCode
NEW InvalidArgument enumeration value (3)
NEW KeyGenerationFailure enumeration value (4)
NEW ProtectionPolicyFailure enumeration value (5)
NEW SecureDataFailure enumeration value (6)
NEW BiometricAuthenticationNotEnabled enumeration value (207)
InternalException
NEW getErrorReason method
public ErrorCode getErrorReason()
NEW setErrorReason method
public void setErrorReason(ErrorCode errorReason)
NEW getParameter method
public Parameter getParameter()
NEW setParameter method
public void setParameter(Parameter param)
NEW InvalidParameterException class
LockPolicy.LockType
NEW SILENT enumeration value
NEW SilentLockPolicy class
Package com.hidglobal.ia.service.manager
NEW KEY_PROPERTY_USAGE_OPPRO constant
What's New in Version 5.1 from 4.0
SDK Updates
ContainerInitialization
DEPRECATED initialPassword field (use EventListener)
Device
NEW createContainer method
public Container createContainer(ContainerInitialization config, char[] sessionPassword, EventListener listener) throws UnsupportedDeviceException, InternalException, AuthenticationException, InvalidPasswordException, RemoteException, UnsafeDeviceException, ServerProtocolException, FingerprintAuthenticationRequiredException, FingerprintNotEnrolledException, GooglePlayServicesObsoleteException, PasswordCancelledException, ServerOperationFailedException;
DEPRECATED createContainer method (use new method)
public Container createContainer(ContainerInitialization config, EventListener listener) throws UnsupportedDeviceException, InternalException, AuthenticationException, InvalidPasswordException, RemoteException, UnsafeDeviceException, ServerProtocolException, FingerprintAuthenticationRequiredException, FingerprintNotEnrolledException, GooglePlayServicesObsoleteException, PasswordCancelledException, ServerOperationFailedException;
DEPRECATED retrieveTransaction method (use TransactionInfo.getTransaction)
public Transaction retrieveTransaction(char[] transactionId, char[] sessionPassword, Parameter[] params) throws AuthenticationException, RemoteException, UnsupportedDeviceException, PasswordExpiredException, LostCredentialsException, InternalException, InvalidPasswordException, TransactionContainerInvalidException, TransactionExpiredException, ServerOperationFailedException;
DEPRECATED reset method (use DeviceFactory.reset)
public boolean reset(Parameter[] params) throws InternalException;
DEPRECATED getDefaultInitializationPolicy method (use EventListener)
public ProtectionPolicy getDefaultInitializationPolicy() throws InternalException;
Transaction
UPDATE setStatus method throws new ServerOperationFailedException exception
public boolean setStatus(String status, char[] signingPassword, char[] sessionPassword, Parameter[] param) throws AuthenticationException, PasswordExpiredException, TransactionExpiredException, ServerVersionException, RemoteException, LostCredentialsException, InternalException, PasswordRequiredException, FingerprintAuthenticationRequiredException, ServerAuthenticationException, ServerOperationFailedException;
TransactionInfo
UPDATE class declaration as interface
NEW getTransaction method
public Transaction getTransaction( char[] sessionPassword, Parameter[] params) throws AuthenticationException, RemoteException, UnsupportedDeviceException, PasswordExpiredException, LostCredentialsException, InternalException, InvalidPasswordException, TransactionContainerInvalidException, TransactionExpiredException, ServerOperationFailedException;
ProgressListener
REMOVED class and replaced with EventListener
NEW PasswordPromptResult class
NEW PasswordPromptEvent class
NEW EventResult class
NEW EventListener class
NEW Event class
DeviceFactory
NEW getDevice method
public static Device getDevice(Context context, ConnectionConfiguration config, char[] sessionPassword) throws UnsupportedDeviceException, LostCredentialsException, UnsupportedDeviceException, InternalException;
NEW reset method
public static boolean reset(Context ctx) throws InternalException
DEPRECATED getDevice method (use new method)
public static Device getDevice(Context context, ConnectionConfiguration config) throws UnsupportedDeviceException, LostCredentialsException, UnsupportedDeviceException, InternalException;
SDK Additions and New Features
Container
NEW getCreationDate method
public Date getCreationDate();
NEW getExpiryDate method
public Date getExpiryDate();
NEW getRenewalDate method
public Date getRenewalDate();
NEW isRenewable method
public Date isRenewable(char[] password);
NEW renew method
public void renew(ContainerRenewal config, char[] sessionPassword, EventListener eventListener) throws PasswordExpiredException , UnsupportedDeviceException, InternalException, AuthenticationException, InvalidPasswordException, RemoteException, UnsafeDeviceException, ServerProtocolException, FingerprintAuthenticationRequiredException, FingerprintNotEnrolledException, LostCredentialsException, PasswordRequiredException, CredentialsExpiredException, ServerUnsupportedOperationException, GooglePlayServicesObsoleteException, PasswordCancelledException, ServerOperationFailedException;
NEW ContainerRenewal class
BioPasswordPolicy
DEPRECATED getCancellationSignal method
public Object getCancellationSignal() throws InternalException;
DEPRECATED enableFingerprintManager method (use setBiometricPrompt)
public void enableFingerprintManager(Object authenticationCallback, Object cancellationSignal) throws InternalException;
NEW setBiometricPrompt method
void setBiometricPrompt(Object object, Object authenticationCallback, Object promptInfo);
NEW resetBiometricPrompt method
void resetBiometricPrompt();
NEW disableBioAuthentication method
void disableBioAuthentication() throws UnsupportedDeviceException, FingerprintNotEnrolledException, FingerprintAuthenticationRequiredException, InternalException, LostCredentialsException, AuthenticationException, PasswordExpiredException;
ErrorCode
NEW PasswordCancelled enumeration value
NEW GooglePlayServicesObsolete enumeration value
NEW ServerUnsupportedOperation enumeration value
NEWServerOperationFailed enumeration value
NEWServerUnsupportedOperationException exception class
NEWServerOperationFailedException exception class
NEW PasswordCancelledException exception class
NEWGooglePlayServicesObsoleteException exception class
What's New in Version 4.0 from 3.0
SDK Addition
Container
NEW IsFIPSModeEnabled method – Reserved for Future Use
Code Examples
Transaction Retrieval
Context ctx = this.getBaseContext();
// get device
ConnectionConfiguration connectionConfig = new ConnectionConfiguration();
Device device = DeviceFactory.getDevice(ctx, connectionConfig);
// get transaction
TransactionInfo txInfo = device.retrieveTransactionInfo(myTransactionId);
Transaction tx = device.retrieveTransaction(myTransactionId, mySessionPwd, new Parameter[0]);
Context ctx = this.getBaseContext();
// get device
ConnectionConfiguration connectionConfig = new ConnectionConfiguration();
Device device = DeviceFactory.getDevice(ctx, connectionConfig, mySessionPwd);
// get transaction
TransactionInfo txInfo = device.retrieveTransactionInfo(myTransactionId);
Transaction tx = txInfo.getTransaction(mySessionPwd, new Parameter[0]);
Context ctx = this.getBaseContext();
// get device
ConnectionConfiguration connectionConfig = new ConnectionConfiguration();
Device device = DeviceFactory.getDevice(ctx, connectionConfig);
// get transaction
TransactionInfo txInfo = device.retrieveTransactionInfo(myTransactionId);
Transaction tx = txInfo.getTransaction(mySessionPwd, new Parameter[0]);
Provisioning / Container Creation
// progress listener
@Override
public void onEventReceived(ProgressEvent event) {
Parameter[] params = event.getParameters();
char[] message = null; char[] percent = null;
for (int i = 0; i < params.length; i++) {
if (SDKConstants.PARAM_SYNCEVENT_MESSAGE.equalsIgnoreCase(params[i].getId()))
message = params[i].getValue();
if (SDKConstants.PARAM_SYNCEVENT_PERCENT.equalsIgnoreCase(params[i].getId()))
percent = params[i].getValue();
}
String text = new String(message) + " (" + new String(percent) + ")";
Log.d(LOG_TAG, "Event Received: " + text);
}
// provisioning
public void doProvisioning() {
// get device
ConnectionConfiguration connectionConfig = new ConnectionConfiguration();
Device device = DeviceFactory.getDevice(this.getBaseContext(), connectionConfig);
// new container
ContainerInitialization config = new ContainerInitialization();
config.activationCode = myActivationCode;
config.initialPassword = myInitialPassword;
config.pushId = myPushId;
config.containerFriendlyName = myContainerName;
Container container = device.createContainer(config, this);
}
// progress listener
@Override
public EventResult onEventReceived(Event event) {
if (event instanceof PasswordPromptEvent) {
// Continue: operation can continue
// Cancel: operation is cancelled by the user.
// Abort: operation is aborted by the app
PasswordPromptResult result = new PasswordPromptResult(EventResult.Code.Continue);
result.setPassword(myInitialPassword);
return result;
} else {// progress message
Parameter[] params = event.getParameters();
char[] message = null; char[] percent = null;
for (int i = 0; i < params.length; i++) {
if (SDKConstants.PARAM_SYNCEVENT_MESSAGE.equalsIgnoreCase(params[i].getId()))
message = params[i].getValue();
if (SDKConstants.PARAM_SYNCEVENT_PERCENT.equalsIgnoreCase(params[i].getId()))
percent = params[i].getValue();
}
String text = new String(message) + " (" + new String(percent) + ")";
Log.d(LOG_TAG, "Event Received: " + text);
}
return null;
}
// provisioning
public void doProvisioning() {
// get device
ConnectionConfiguration connectionConfig = new ConnectionConfiguration();
Device device = DeviceFactory.getDevice(this.getBaseContext(), connectionConfig, mySessionPwd);
// new container
ContainerInitialization config = new ContainerInitialization();
config.activationCode = myActivationCode;
// NOTE: “config.initialPassword” is not supported; use listener
config.pushId = myPushId;
config.containerFriendlyName = myContainerName;
Container container = device.createContainer(config, mySessionPwd, this);
}
// progress listener
@Override
public EventResult onEventReceived(Event event) {
if (event instanceof PasswordPromptEvent) {
// Continue: operation can continue
// Cancel: operation is cancelled by the user.
// Abort: operation is aborted by the app
PasswordPromptResult result = new PasswordPromptResult(EventResult.Code.Continue);
result.setPassword(myInitialPassword);
return result;
} else {// progress message
Parameter[] params = event.getParameters();
char[] message = null; char[] percent = null;
for (int i = 0; i < params.length; i++) {
if (SDKConstants.PARAM_SYNCEVENT_MESSAGE.equalsIgnoreCase(params[i].getId()))
message = params[i].getValue();
if (SDKConstants.PARAM_SYNCEVENT_PERCENT.equalsIgnoreCase(params[i].getId()))
percent = params[i].getValue();
}
String text = new String(message) + " (" + new String(percent) + ")";
Log.d(LOG_TAG, "Event Received: " + text);
}
return null;
}
// provisioning
public void doProvisioning() {
// get device
ConnectionConfiguration connectionConfig = new ConnectionConfiguration();
Device device = DeviceFactory.getDevice(this.getBaseContext(), connectionConfig);
// new container
ContainerInitialization config = new ContainerInitialization();
config.activationCode = myActivationCode;
// NOTE: “config.initialPassword” is not supported; use listener
config.pushId = myPushId;
config.containerFriendlyName = myContainerName;
Container container = device.createContainer(config, mySessionPwd, this);
}
Biometric Authentication
// Custom AuthenticationCallback implementation that receives sensor events
class CustomAuthenticationCallback extends FingerprintManager.AuthenticationCallback {
@Override
public void onAuthenticationError(int errorCode, CharSequence errString) {
// Display error
}
@Override
public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
// Give feedback to user
}
@Override
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
// Fingerprint matched, let’s proceed with the operation requested
otp = otpGenerator.getOTP(null);
// Display OTP
}
public void onAuthenticationFailed() {
// Dismiss UI / display user that fingerprint didn’t match
// A usual behavior is to prompt the user for his/her password
}
}
// Method invoked when button to generate OTP is clicked
public void onGenerateOTPClick(View v) {
// Pass an AuthenticationCallback instance and a CancellationSignal instance to the SDK
bioPasswordPolicy.enableFingerprintManager(customAuthenticationCallback, cancellationSignal);
// Perform the requested operation, for example getOTP
try {
otp = otpGenerator.getOTP(null);
// Display OTP
} catch (FingerprintAuthenticationRequiredException e) {
// Display UI to show user that he/she must put his/her finger on sensor
}
}
// Custom BiometricPrompt.AuthenticationCallback implementation that receives sensor events
class CustomAuthenticationCallback extends BiometricPrompt.AuthenticationCallback {
@Override
public void onAuthenticationError(int errorCode, CharSequence errString) {
// Display error
}
@Override
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
// Fingerprint matched, let’s proceed with the operation requested
otp = otpGenerator.getOTP(null);
// Display OTP
}
public void onAuthenticationFailed() {
// Dismiss UI / display user that fingerprint didn’t match
// A usual behavior is to prompt the user for his/her password
}
}
// Method invoked when button to generate OTP is clicked
public void onGenerateOTPClick(View v) {
// Construct PromptInfo dialog
BiometricPrompt.PromptInfo prompt =
new BiometricPrompt.PromptInfo.Builder()
.setTitle(activity.getString("Confirm fingerprint"))
.setNegativeButtonText(activity.getString("Cancel"))
.build();
// Pass Activity/Fragment, AuthenticationCallback and PromptInfo instances to the SDK
bioPasswordPolicy.setBiometricPrompt(getActivity(),customAuthenticationCallback,prompt);
// Perform the requested operation, for example getOTP
otp = otpGenerator.getOTP(null);
// Display OTP
}
ProtectionPolicy containerPolicy = pContainer.getProtectionPolicy();
if (containerPolicy.getType().equals(ProtectionPolicy.PolicyType.BIOPASSWORD.toString())
{
BioPasswordPolicy bioPasswordPolicy = (BioPasswordPolicy)containerPolicy;
if (bioPasswordPolicy.getBioAuthenticationState() == BioAuthenticationState.NOT_ENABLED)
{
// Prompt user for his/her password
// Then enable authentication with fingerprint
bioPasswordPolicy.enableBioAuthentication(password);
}
}