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 the SDK 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.11 from 5.10
SDK Additions and New Features
Device
UPDATE method "retrieveActionInfo" to add "InexplicitContainerException" exception
NEW method with a different signature "retrieveActionInfo(char[] actionId, char[] userId)"
What's New in Version 5.10 from 5.9
SDK Additions and New Features
SDKConstants
NEW constant "DEVICE_INFO_LOCALE"
NEW constant "DEVICE_INFO_ISROOTED"
NEW constant "PARAM_TX_MOBILE_CONTEXT"
NEW constant DEVICE_INFO_FPCAPABLE
NEW constant DEVICE_INFO_FPENROLLED
Transaction
UPDATE method "setStatus" supports "PARAM_TX_MOBILE_CONTEXT" parameter
Device
UPDATE method "getDeviceInfo" supports "DEVICE_INFO_ISROOTED"
UPDATE method "getDeviceInfo" supports "DEVICE_INFO_LOCALE"
UPDATE method "getDeviceInfo" supports "DEVICE_INFO_FPCAPABLE"
UPDATE method "getDeviceInfo" supports "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 enumeration value “INVALID_KEY”
BioPasswordPolicy
UPDATE method “setBiometricPrompt” to use FragmentActivity
NEW method accessor “getAuthorizedAuthenticator”
PasswordPolicy
NEW method accessor “isSequenceAllowed”
Container
NEW method accessor “getOriginalCreationDate”
ServerAction
NEW method accessor “getPayload”
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 event parameter constant CONTAINER_POLICY
NEW event parameter constant KEY_POLICY
NEW event parameter constant TYPE
ErrorCode
NEW enumeration value "UnsupportedVersion" (7)
NEW enumeration value "InvalidContainer" (8)
Others
REMOVED exception class "SerialNumberRequiredException"
NEW exception class “InvalidContainerException”
AsyncOTPGenerator
UPDATE New exception InvalidParameterException added to all methods
BioPasswordPolicy
REMOVED deprecated method “enableFingerPrintManager” (use setBiometricPrompt)
REMOVED deprecated method “getCancellationSignal”
PasswordPolicy
UPDATE New exception InvalidParameterException added to all methods
Container
UPDATE New exception InvalidParameterException added to all methods
NEW method “updateDeviceInfo” (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 property “initialPassword” (use EventListener)
Device
UPDATE New exception InvalidParameterException added to all methods
REMOVED deprecated method “retrieveTransaction”
NEW method “retrieveActionInfo”
ServerActionInfo retrieveActionInfo(char[] actionId) throws InternalException, ServerActionContainerInvalidException, InvalidContainerException, InvalidParameterException;
REMOVED deprecated method “createContainer” (use createContainer with sessionPassword)
REMOVED deprecated method “reset” (use DeviceFactory reset)
REMOVED deprecated method “getDefaultInitializationPolicy” (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 class ServerAction
Others
DEPRECATED class TransactionInfo (use retrieveActionInfo)
NEW class ServerAction
NEW class ServerActionInfo
DeviceFactory
UPDATE New exception InvalidParameterException added to all methods
REMOVED deprecated method “getDevice” with deviceSerialNumber
SDKConstants
NEW constant “ACTION_TRANSACTION”
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 method "getDevice"
public static Device getDevice(Context context, ConnectionConfiguration config) throws UnsupportedDeviceException, LostCredentialsException, UnsupportedDeviceException, InternalException;
DEPRECATED method "getDevice" (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 enumeration value InvalidArgument (3)
NEW enumeration value KeyGenerationFailure (4)
NEW enumeration value ProtectionPolicyFailure (5)
NEW enumeration value SecureDataFailure (6)
NEW enumeration value BiometricAuthenticationNotEnabled (207)
InternalException
NEW method "getErrorReason"
public ErrorCode getErrorReason()
NEW method "setErrorReason"
public void setErrorReason(ErrorCode errorReason)
NEW method "getParameter"
public Parameter getParameter()
NEW method "setParameter"
public void setParameter(Parameter param)
NEW class "InvalidParameterException"
LockPolicy.LockType
NEW enumeration value SILENT
NEW class "SilentLockPolicy"
Package com.hidglobal.ia.service.manager
NEW constant "KEY_PROPERTY_USAGE_OPPRO"
What's New in Version 5.1 from 4.0
SDK Updates
ContainerInitialization
DEPRECATED field "initialPassword" (use EventListener)
Device
NEW method "createContainer"
public Container createContainer(ContainerInitialization config, char[] sessionPassword, EventListener listener) throws UnsupportedDeviceException, InternalException, AuthenticationException, InvalidPasswordException, RemoteException, UnsafeDeviceException, ServerProtocolException, FingerprintAuthenticationRequiredException, FingerprintNotEnrolledException, GooglePlayServicesObsoleteException, PasswordCancelledException, ServerOperationFailedException;
DEPRECATED method "createContainer" (use new method)
public Container createContainer(ContainerInitialization config, EventListener listener) throws UnsupportedDeviceException, InternalException, AuthenticationException, InvalidPasswordException, RemoteException, UnsafeDeviceException, ServerProtocolException, FingerprintAuthenticationRequiredException, FingerprintNotEnrolledException, GooglePlayServicesObsoleteException, PasswordCancelledException, ServerOperationFailedException;
DEPRECATED method "retrieveTransaction" (use TransactionInfo.getTransaction)
public Transaction retrieveTransaction(char[] transactionId, char[] sessionPassword, Parameter[] params) throws AuthenticationException, RemoteException, UnsupportedDeviceException, PasswordExpiredException, LostCredentialsException, InternalException, InvalidPasswordException, TransactionContainerInvalidException, TransactionExpiredException, ServerOperationFailedException;
DEPRECATED method "reset" (use DeviceFactory.reset)
public boolean reset(Parameter[] params) throws InternalException;
DEPRECATED method "getDefaultInitializationPolicy" (use EventListener)
public ProtectionPolicy getDefaultInitializationPolicy() throws InternalException;
Transaction
UPDATE method "setStatus" throws new exception ServerOperationFailedException
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 method "getTransaction"
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 class "PasswordPromptResult"
NEW class "PasswordPromptEvent"
NEW class "EventResult"
NEW class "EventListener"
NEW class "Event"
DeviceFactory
NEW method "getDevice"
public static Device getDevice(Context context, ConnectionConfiguration config, char[] sessionPassword) throws UnsupportedDeviceException, LostCredentialsException, UnsupportedDeviceException, InternalException;
NEW method "reset"
public static boolean reset(Context ctx) throws InternalException
DEPRECATED method "getDevice" (use new method)
public static Device getDevice(Context context, ConnectionConfiguration config) throws UnsupportedDeviceException, LostCredentialsException, UnsupportedDeviceException, InternalException;
SDK Additions and New Features
Container
NEW method "getCreationDate"
public Date getCreationDate();
NEW method "getExpiryDate"
public Date getExpiryDate();
NEW method "getRenewalDate"
public Date getRenewalDate();
NEW method "isRenewable"
public Date isRenewable(char[] password);
NEW method "renew"
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 class "ContainerRenewal"
BioPasswordPolicy
DEPRECATED method "getCancellationSignal"
public Object getCancellationSignal() throws InternalException;
DEPRECATED method "enableFingerprintManager" (use setBiometricPrompt)
public void enableFingerprintManager(Object authenticationCallback, Object cancellationSignal) throws InternalException;
NEW method "setBiometricPrompt"
void setBiometricPrompt(Object object, Object authenticationCallback, Object promptInfo);
NEW method "resetBiometricPrompt"
void resetBiometricPrompt();
NEW method "disableBioAuthentication"
void disableBioAuthentication() throws UnsupportedDeviceException, FingerprintNotEnrolledException, FingerprintAuthenticationRequiredException, InternalException, LostCredentialsException, AuthenticationException, PasswordExpiredException;
ErrorCode
NEW enumeration value "PasswordCancelled"
NEW enumeration value "GooglePlayServicesObsolete"
NEW enumeration value "ServerUnsupportedOperation"
NEW enumeration value "ServerOperationFailed"
NEW exception class "ServerUnsupportedOperationException"
NEW exception class "ServerOperationFailedException"
NEW exception class "PasswordCancelledException"
NEW exception class "GooglePlayServicesObsoleteException"
What's New in Version 4.0 from 3.0
SDK Addition
Container
NEW method "IsFIPSModeEnabled" – 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);
}
}