Loading Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -481,6 +481,7 @@ java_library { "android.hardware.vibrator-V1.1-java", "android.hardware.vibrator-V1.2-java", "android.hardware.vibrator-V1.3-java", "android.security.apc-java", "android.system.keystore2-java", "android.system.suspend.control.internal-java", "devicepolicyprotosnano", Loading core/java/android/security/ConfirmationPrompt.java +157 −36 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.content.ContentResolver; import android.content.Context; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.security.keystore.AndroidKeyStoreProvider; import android.text.TextUtils; import android.util.Log; Loading @@ -36,15 +37,15 @@ import java.util.concurrent.Executor; * compromised. Implementing confirmation prompts with these guarantees requires dedicated * hardware-support and may not always be available. * * <p>Confirmation prompts are typically used with an external entitity - the <i>Relying Party</i> - * <p>Confirmation prompts are typically used with an external entity - the <i>Relying Party</i> - * in the following way. The setup steps are as follows: * <ul> * <li> Before first use, the application generates a key-pair with the * {@link android.security.keystore.KeyGenParameterSpec.Builder#setUserConfirmationRequired * CONFIRMATION tag} set. Device attestation, * e.g. {@link java.security.KeyStore#getCertificateChain getCertificateChain()}, is used to * generate a certificate chain that includes the public key (<code>Kpub</code> in the following) * of the newly generated key. * CONFIRMATION tag} set. AndroidKeyStore key attestation, e.g., * {@link android.security.keystore.KeyGenParameterSpec.Builder#setAttestationChallenge(byte[])} * is used to generate a certificate chain that includes the public key (<code>Kpub</code> in the * following) of the newly generated key. * <li> The application sends <code>Kpub</code> and the certificate chain resulting from device * attestation to the <i>Relying Party</i>. * <li> The <i>Relying Party</i> validates the certificate chain which involves checking the root Loading Loading @@ -78,9 +79,10 @@ import java.util.concurrent.Executor; * previously created nonce. If all checks passes, the transaction is executed. * </ul> * * <p>A common way of implementing the "<code>promptText</code> is what is expected" check in the * last bullet, is to have the <i>Relying Party</i> generate <code>promptText</code> and store it * along the nonce in the <code>extraData</code> blob. * <p>Note: It is vital to check the <code>promptText</code> because this is the only part that * the user has approved. To avoid writing parsers for all of the possible locales, it is * recommended that the <i>Relying Party</i> uses the same string generator as used on the device * and performs a simple string comparison. */ public class ConfirmationPrompt { private static final String TAG = "ConfirmationPrompt"; Loading @@ -92,6 +94,14 @@ public class ConfirmationPrompt { private Context mContext; private final KeyStore mKeyStore = KeyStore.getInstance(); private AndroidProtectedConfirmation mProtectedConfirmation; private AndroidProtectedConfirmation getService() { if (mProtectedConfirmation == null) { mProtectedConfirmation = new AndroidProtectedConfirmation(); } return mProtectedConfirmation; } private void doCallback(int responseCode, byte[] dataThatWasConfirmed, ConfirmationCallback callback) { Loading Loading @@ -119,6 +129,32 @@ public class ConfirmationPrompt { } } private void doCallback2(int responseCode, byte[] dataThatWasConfirmed, ConfirmationCallback callback) { switch (responseCode) { case AndroidProtectedConfirmation.ERROR_OK: callback.onConfirmed(dataThatWasConfirmed); break; case AndroidProtectedConfirmation.ERROR_CANCELED: callback.onDismissed(); break; case AndroidProtectedConfirmation.ERROR_ABORTED: callback.onCanceled(); break; case AndroidProtectedConfirmation.ERROR_SYSTEM_ERROR: callback.onError(new Exception("System error returned by ConfirmationUI.")); break; default: callback.onError(new Exception("Unexpected responseCode=" + responseCode + " from onConfirmtionPromptCompleted() callback.")); break; } } private final android.os.IBinder mCallbackBinder = new android.security.IConfirmationPromptCallback.Stub() { @Override Loading @@ -144,6 +180,29 @@ public class ConfirmationPrompt { } }; private final android.security.apc.IConfirmationCallback mConfirmationCallback = new android.security.apc.IConfirmationCallback.Stub() { @Override public void onCompleted(int result, byte[] dataThatWasConfirmed) throws android.os.RemoteException { if (mCallback != null) { ConfirmationCallback callback = mCallback; Executor executor = mExecutor; mCallback = null; mExecutor = null; if (executor == null) { doCallback2(result, dataThatWasConfirmed, callback); } else { executor.execute(new Runnable() { @Override public void run() { doCallback2(result, dataThatWasConfirmed, callback); } }); } } } }; /** * A builder that collects arguments, to be shown on the system-provided confirmation prompt. */ Loading Loading @@ -211,6 +270,9 @@ public class ConfirmationPrompt { private static final int UI_OPTION_ACCESSIBILITY_MAGNIFIED_FLAG = 1 << 1; private int getUiOptionsAsFlags() { if (AndroidKeyStoreProvider.isKeystore2Enabled()) { return getUiOptionsAsFlags2(); } int uiOptionsAsFlags = 0; ContentResolver contentResolver = mContext.getContentResolver(); int inversionEnabled = Settings.Secure.getInt(contentResolver, Loading @@ -226,6 +288,22 @@ public class ConfirmationPrompt { return uiOptionsAsFlags; } private int getUiOptionsAsFlags2() { int uiOptionsAsFlags = 0; ContentResolver contentResolver = mContext.getContentResolver(); int inversionEnabled = Settings.Secure.getInt(contentResolver, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0); if (inversionEnabled == 1) { uiOptionsAsFlags |= AndroidProtectedConfirmation.FLAG_UI_OPTION_INVERTED; } float fontScale = Settings.System.getFloat(contentResolver, Settings.System.FONT_SCALE, (float) 1.0); if (fontScale > 1.0) { uiOptionsAsFlags |= AndroidProtectedConfirmation.FLAG_UI_OPTION_MAGNIFIED; } return uiOptionsAsFlags; } private static boolean isAccessibilityServiceRunning(Context context) { boolean serviceRunning = false; try { Loading Loading @@ -270,8 +348,31 @@ public class ConfirmationPrompt { mCallback = callback; mExecutor = executor; int uiOptionsAsFlags = getUiOptionsAsFlags(); String locale = Locale.getDefault().toLanguageTag(); if (AndroidKeyStoreProvider.isKeystore2Enabled()) { int uiOptionsAsFlags = getUiOptionsAsFlags2(); int responseCode = getService().presentConfirmationPrompt( mConfirmationCallback, mPromptText.toString(), mExtraData, locale, uiOptionsAsFlags); switch (responseCode) { case AndroidProtectedConfirmation.ERROR_OK: return; case AndroidProtectedConfirmation.ERROR_OPERATION_PENDING: throw new ConfirmationAlreadyPresentingException(); case AndroidProtectedConfirmation.ERROR_UNIMPLEMENTED: throw new ConfirmationNotAvailableException(); default: // Unexpected error code. Log.w(TAG, "Unexpected responseCode=" + responseCode + " from presentConfirmationPrompt() call."); throw new IllegalArgumentException(); } } else { int uiOptionsAsFlags = getUiOptionsAsFlags(); int responseCode = mKeyStore.presentConfirmationPrompt( mCallbackBinder, mPromptText.toString(), mExtraData, locale, uiOptionsAsFlags); switch (responseCode) { Loading @@ -295,6 +396,7 @@ public class ConfirmationPrompt { throw new IllegalArgumentException(); } } } /** * Cancels a prompt currently being displayed. Loading @@ -306,6 +408,21 @@ public class ConfirmationPrompt { * @throws IllegalStateException if no prompt is currently being presented. */ public void cancelPrompt() { if (AndroidKeyStoreProvider.isKeystore2Enabled()) { int responseCode = getService().cancelConfirmationPrompt(mConfirmationCallback); if (responseCode == AndroidProtectedConfirmation.ERROR_OK) { return; } else if (responseCode == AndroidProtectedConfirmation.ERROR_OPERATION_PENDING) { throw new IllegalStateException(); } else { // Unexpected error code. Log.w(TAG, "Unexpected responseCode=" + responseCode + " from cancelConfirmationPrompt() call."); throw new IllegalStateException(); } } else { int responseCode = mKeyStore.cancelConfirmationPrompt(mCallbackBinder); if (responseCode == KeyStore.CONFIRMATIONUI_OK) { return; Loading @@ -319,6 +436,7 @@ public class ConfirmationPrompt { throw new IllegalStateException(); } } } /** * Checks if the device supports confirmation prompts. Loading @@ -330,6 +448,9 @@ public class ConfirmationPrompt { if (isAccessibilityServiceRunning(context)) { return false; } if (AndroidKeyStoreProvider.isKeystore2Enabled()) { return new AndroidProtectedConfirmation().isConfirmationPromptSupported(); } return KeyStore.getInstance().isConfirmationPromptSupported(); } } keystore/java/android/security/AndroidProtectedConfirmation.java 0 → 100644 +118 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.security; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.security.apc.IConfirmationCallback; import android.security.apc.IProtectedConfirmation; import android.security.apc.ResponseCode; import android.util.Log; /** * @hide */ public class AndroidProtectedConfirmation { private static final String TAG = "AndroidProtectedConfirmation"; public static final int ERROR_OK = ResponseCode.OK; public static final int ERROR_CANCELED = ResponseCode.CANCELLED; public static final int ERROR_ABORTED = ResponseCode.ABORTED; public static final int ERROR_OPERATION_PENDING = ResponseCode.OPERATION_PENDING; public static final int ERROR_IGNORED = ResponseCode.IGNORED; public static final int ERROR_SYSTEM_ERROR = ResponseCode.SYSTEM_ERROR; public static final int ERROR_UNIMPLEMENTED = ResponseCode.UNIMPLEMENTED; public static final int FLAG_UI_OPTION_INVERTED = IProtectedConfirmation.FLAG_UI_OPTION_INVERTED; public static final int FLAG_UI_OPTION_MAGNIFIED = IProtectedConfirmation.FLAG_UI_OPTION_MAGNIFIED; private IProtectedConfirmation mProtectedConfirmation; public AndroidProtectedConfirmation() { mProtectedConfirmation = null; } private synchronized IProtectedConfirmation getService() { if (mProtectedConfirmation == null) { mProtectedConfirmation = IProtectedConfirmation.Stub.asInterface(ServiceManager .getService("android.security.apc")); } return mProtectedConfirmation; } /** * Requests keystore call into the confirmationui HAL to display a prompt. * * @param listener the binder to use for callbacks. * @param promptText the prompt to display. * @param extraData extra data / nonce from application. * @param locale the locale as a BCP 47 language tag. * @param uiOptionsAsFlags the UI options to use, as flags. * @return one of the {@code CONFIRMATIONUI_*} constants, for * example {@code KeyStore.CONFIRMATIONUI_OK}. */ public int presentConfirmationPrompt(IConfirmationCallback listener, String promptText, byte[] extraData, String locale, int uiOptionsAsFlags) { try { getService().presentPrompt(listener, promptText, extraData, locale, uiOptionsAsFlags); return ERROR_OK; } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return ERROR_SYSTEM_ERROR; } catch (ServiceSpecificException e) { return e.errorCode; } } /** * Requests keystore call into the confirmationui HAL to cancel displaying a prompt. * * @param listener the binder passed to the {@link #presentConfirmationPrompt} method. * @return one of the {@code CONFIRMATIONUI_*} constants, for * example {@code KeyStore.CONFIRMATIONUI_OK}. */ public int cancelConfirmationPrompt(IConfirmationCallback listener) { try { getService().cancelPrompt(listener); return ERROR_OK; } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return ERROR_SYSTEM_ERROR; } catch (ServiceSpecificException e) { return e.errorCode; } } /** * Requests keystore to check if the confirmationui HAL is available. * * @return whether the confirmationUI HAL is available. */ public boolean isConfirmationPromptSupported() { try { return getService().isSupported(); } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return false; } } } Loading
Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -481,6 +481,7 @@ java_library { "android.hardware.vibrator-V1.1-java", "android.hardware.vibrator-V1.2-java", "android.hardware.vibrator-V1.3-java", "android.security.apc-java", "android.system.keystore2-java", "android.system.suspend.control.internal-java", "devicepolicyprotosnano", Loading
core/java/android/security/ConfirmationPrompt.java +157 −36 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.content.ContentResolver; import android.content.Context; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.security.keystore.AndroidKeyStoreProvider; import android.text.TextUtils; import android.util.Log; Loading @@ -36,15 +37,15 @@ import java.util.concurrent.Executor; * compromised. Implementing confirmation prompts with these guarantees requires dedicated * hardware-support and may not always be available. * * <p>Confirmation prompts are typically used with an external entitity - the <i>Relying Party</i> - * <p>Confirmation prompts are typically used with an external entity - the <i>Relying Party</i> - * in the following way. The setup steps are as follows: * <ul> * <li> Before first use, the application generates a key-pair with the * {@link android.security.keystore.KeyGenParameterSpec.Builder#setUserConfirmationRequired * CONFIRMATION tag} set. Device attestation, * e.g. {@link java.security.KeyStore#getCertificateChain getCertificateChain()}, is used to * generate a certificate chain that includes the public key (<code>Kpub</code> in the following) * of the newly generated key. * CONFIRMATION tag} set. AndroidKeyStore key attestation, e.g., * {@link android.security.keystore.KeyGenParameterSpec.Builder#setAttestationChallenge(byte[])} * is used to generate a certificate chain that includes the public key (<code>Kpub</code> in the * following) of the newly generated key. * <li> The application sends <code>Kpub</code> and the certificate chain resulting from device * attestation to the <i>Relying Party</i>. * <li> The <i>Relying Party</i> validates the certificate chain which involves checking the root Loading Loading @@ -78,9 +79,10 @@ import java.util.concurrent.Executor; * previously created nonce. If all checks passes, the transaction is executed. * </ul> * * <p>A common way of implementing the "<code>promptText</code> is what is expected" check in the * last bullet, is to have the <i>Relying Party</i> generate <code>promptText</code> and store it * along the nonce in the <code>extraData</code> blob. * <p>Note: It is vital to check the <code>promptText</code> because this is the only part that * the user has approved. To avoid writing parsers for all of the possible locales, it is * recommended that the <i>Relying Party</i> uses the same string generator as used on the device * and performs a simple string comparison. */ public class ConfirmationPrompt { private static final String TAG = "ConfirmationPrompt"; Loading @@ -92,6 +94,14 @@ public class ConfirmationPrompt { private Context mContext; private final KeyStore mKeyStore = KeyStore.getInstance(); private AndroidProtectedConfirmation mProtectedConfirmation; private AndroidProtectedConfirmation getService() { if (mProtectedConfirmation == null) { mProtectedConfirmation = new AndroidProtectedConfirmation(); } return mProtectedConfirmation; } private void doCallback(int responseCode, byte[] dataThatWasConfirmed, ConfirmationCallback callback) { Loading Loading @@ -119,6 +129,32 @@ public class ConfirmationPrompt { } } private void doCallback2(int responseCode, byte[] dataThatWasConfirmed, ConfirmationCallback callback) { switch (responseCode) { case AndroidProtectedConfirmation.ERROR_OK: callback.onConfirmed(dataThatWasConfirmed); break; case AndroidProtectedConfirmation.ERROR_CANCELED: callback.onDismissed(); break; case AndroidProtectedConfirmation.ERROR_ABORTED: callback.onCanceled(); break; case AndroidProtectedConfirmation.ERROR_SYSTEM_ERROR: callback.onError(new Exception("System error returned by ConfirmationUI.")); break; default: callback.onError(new Exception("Unexpected responseCode=" + responseCode + " from onConfirmtionPromptCompleted() callback.")); break; } } private final android.os.IBinder mCallbackBinder = new android.security.IConfirmationPromptCallback.Stub() { @Override Loading @@ -144,6 +180,29 @@ public class ConfirmationPrompt { } }; private final android.security.apc.IConfirmationCallback mConfirmationCallback = new android.security.apc.IConfirmationCallback.Stub() { @Override public void onCompleted(int result, byte[] dataThatWasConfirmed) throws android.os.RemoteException { if (mCallback != null) { ConfirmationCallback callback = mCallback; Executor executor = mExecutor; mCallback = null; mExecutor = null; if (executor == null) { doCallback2(result, dataThatWasConfirmed, callback); } else { executor.execute(new Runnable() { @Override public void run() { doCallback2(result, dataThatWasConfirmed, callback); } }); } } } }; /** * A builder that collects arguments, to be shown on the system-provided confirmation prompt. */ Loading Loading @@ -211,6 +270,9 @@ public class ConfirmationPrompt { private static final int UI_OPTION_ACCESSIBILITY_MAGNIFIED_FLAG = 1 << 1; private int getUiOptionsAsFlags() { if (AndroidKeyStoreProvider.isKeystore2Enabled()) { return getUiOptionsAsFlags2(); } int uiOptionsAsFlags = 0; ContentResolver contentResolver = mContext.getContentResolver(); int inversionEnabled = Settings.Secure.getInt(contentResolver, Loading @@ -226,6 +288,22 @@ public class ConfirmationPrompt { return uiOptionsAsFlags; } private int getUiOptionsAsFlags2() { int uiOptionsAsFlags = 0; ContentResolver contentResolver = mContext.getContentResolver(); int inversionEnabled = Settings.Secure.getInt(contentResolver, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0); if (inversionEnabled == 1) { uiOptionsAsFlags |= AndroidProtectedConfirmation.FLAG_UI_OPTION_INVERTED; } float fontScale = Settings.System.getFloat(contentResolver, Settings.System.FONT_SCALE, (float) 1.0); if (fontScale > 1.0) { uiOptionsAsFlags |= AndroidProtectedConfirmation.FLAG_UI_OPTION_MAGNIFIED; } return uiOptionsAsFlags; } private static boolean isAccessibilityServiceRunning(Context context) { boolean serviceRunning = false; try { Loading Loading @@ -270,8 +348,31 @@ public class ConfirmationPrompt { mCallback = callback; mExecutor = executor; int uiOptionsAsFlags = getUiOptionsAsFlags(); String locale = Locale.getDefault().toLanguageTag(); if (AndroidKeyStoreProvider.isKeystore2Enabled()) { int uiOptionsAsFlags = getUiOptionsAsFlags2(); int responseCode = getService().presentConfirmationPrompt( mConfirmationCallback, mPromptText.toString(), mExtraData, locale, uiOptionsAsFlags); switch (responseCode) { case AndroidProtectedConfirmation.ERROR_OK: return; case AndroidProtectedConfirmation.ERROR_OPERATION_PENDING: throw new ConfirmationAlreadyPresentingException(); case AndroidProtectedConfirmation.ERROR_UNIMPLEMENTED: throw new ConfirmationNotAvailableException(); default: // Unexpected error code. Log.w(TAG, "Unexpected responseCode=" + responseCode + " from presentConfirmationPrompt() call."); throw new IllegalArgumentException(); } } else { int uiOptionsAsFlags = getUiOptionsAsFlags(); int responseCode = mKeyStore.presentConfirmationPrompt( mCallbackBinder, mPromptText.toString(), mExtraData, locale, uiOptionsAsFlags); switch (responseCode) { Loading @@ -295,6 +396,7 @@ public class ConfirmationPrompt { throw new IllegalArgumentException(); } } } /** * Cancels a prompt currently being displayed. Loading @@ -306,6 +408,21 @@ public class ConfirmationPrompt { * @throws IllegalStateException if no prompt is currently being presented. */ public void cancelPrompt() { if (AndroidKeyStoreProvider.isKeystore2Enabled()) { int responseCode = getService().cancelConfirmationPrompt(mConfirmationCallback); if (responseCode == AndroidProtectedConfirmation.ERROR_OK) { return; } else if (responseCode == AndroidProtectedConfirmation.ERROR_OPERATION_PENDING) { throw new IllegalStateException(); } else { // Unexpected error code. Log.w(TAG, "Unexpected responseCode=" + responseCode + " from cancelConfirmationPrompt() call."); throw new IllegalStateException(); } } else { int responseCode = mKeyStore.cancelConfirmationPrompt(mCallbackBinder); if (responseCode == KeyStore.CONFIRMATIONUI_OK) { return; Loading @@ -319,6 +436,7 @@ public class ConfirmationPrompt { throw new IllegalStateException(); } } } /** * Checks if the device supports confirmation prompts. Loading @@ -330,6 +448,9 @@ public class ConfirmationPrompt { if (isAccessibilityServiceRunning(context)) { return false; } if (AndroidKeyStoreProvider.isKeystore2Enabled()) { return new AndroidProtectedConfirmation().isConfirmationPromptSupported(); } return KeyStore.getInstance().isConfirmationPromptSupported(); } }
keystore/java/android/security/AndroidProtectedConfirmation.java 0 → 100644 +118 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.security; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.security.apc.IConfirmationCallback; import android.security.apc.IProtectedConfirmation; import android.security.apc.ResponseCode; import android.util.Log; /** * @hide */ public class AndroidProtectedConfirmation { private static final String TAG = "AndroidProtectedConfirmation"; public static final int ERROR_OK = ResponseCode.OK; public static final int ERROR_CANCELED = ResponseCode.CANCELLED; public static final int ERROR_ABORTED = ResponseCode.ABORTED; public static final int ERROR_OPERATION_PENDING = ResponseCode.OPERATION_PENDING; public static final int ERROR_IGNORED = ResponseCode.IGNORED; public static final int ERROR_SYSTEM_ERROR = ResponseCode.SYSTEM_ERROR; public static final int ERROR_UNIMPLEMENTED = ResponseCode.UNIMPLEMENTED; public static final int FLAG_UI_OPTION_INVERTED = IProtectedConfirmation.FLAG_UI_OPTION_INVERTED; public static final int FLAG_UI_OPTION_MAGNIFIED = IProtectedConfirmation.FLAG_UI_OPTION_MAGNIFIED; private IProtectedConfirmation mProtectedConfirmation; public AndroidProtectedConfirmation() { mProtectedConfirmation = null; } private synchronized IProtectedConfirmation getService() { if (mProtectedConfirmation == null) { mProtectedConfirmation = IProtectedConfirmation.Stub.asInterface(ServiceManager .getService("android.security.apc")); } return mProtectedConfirmation; } /** * Requests keystore call into the confirmationui HAL to display a prompt. * * @param listener the binder to use for callbacks. * @param promptText the prompt to display. * @param extraData extra data / nonce from application. * @param locale the locale as a BCP 47 language tag. * @param uiOptionsAsFlags the UI options to use, as flags. * @return one of the {@code CONFIRMATIONUI_*} constants, for * example {@code KeyStore.CONFIRMATIONUI_OK}. */ public int presentConfirmationPrompt(IConfirmationCallback listener, String promptText, byte[] extraData, String locale, int uiOptionsAsFlags) { try { getService().presentPrompt(listener, promptText, extraData, locale, uiOptionsAsFlags); return ERROR_OK; } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return ERROR_SYSTEM_ERROR; } catch (ServiceSpecificException e) { return e.errorCode; } } /** * Requests keystore call into the confirmationui HAL to cancel displaying a prompt. * * @param listener the binder passed to the {@link #presentConfirmationPrompt} method. * @return one of the {@code CONFIRMATIONUI_*} constants, for * example {@code KeyStore.CONFIRMATIONUI_OK}. */ public int cancelConfirmationPrompt(IConfirmationCallback listener) { try { getService().cancelPrompt(listener); return ERROR_OK; } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return ERROR_SYSTEM_ERROR; } catch (ServiceSpecificException e) { return e.errorCode; } } /** * Requests keystore to check if the confirmationui HAL is available. * * @return whether the confirmationUI HAL is available. */ public boolean isConfirmationPromptSupported() { try { return getService().isSupported(); } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return false; } } }