From de7048167d5f411a867f3a728eb41d3ee48b8277 Mon Sep 17 00:00:00 2001 From: Marvin Ramin Date: Fri, 14 Oct 2016 09:40:25 +0200 Subject: [PATCH] remove usage of experimental rxjava emitter (#14) --- .../FingerprintAuthenticationObservable.java | 68 ++++---- .../FingerprintDecryptionObservable.java | 144 ++++++++-------- .../FingerprintEncryptionObservable.java | 154 +++++++++--------- .../rxfingerprint/FingerprintObservable.java | 83 +++++----- 4 files changed, 226 insertions(+), 223 deletions(-) diff --git a/rxfingerprint/src/main/java/com/mtramin/rxfingerprint/FingerprintAuthenticationObservable.java b/rxfingerprint/src/main/java/com/mtramin/rxfingerprint/FingerprintAuthenticationObservable.java index e0cb276..c95098a 100644 --- a/rxfingerprint/src/main/java/com/mtramin/rxfingerprint/FingerprintAuthenticationObservable.java +++ b/rxfingerprint/src/main/java/com/mtramin/rxfingerprint/FingerprintAuthenticationObservable.java @@ -23,51 +23,49 @@ import com.mtramin.rxfingerprint.data.FingerprintAuthenticationResult; import com.mtramin.rxfingerprint.data.FingerprintResult; -import rx.Emitter; import rx.Observable; - -import static rx.Emitter.BackpressureMode.LATEST; +import rx.Subscriber; /** * Authenticates the user with his fingerprint. */ class FingerprintAuthenticationObservable extends FingerprintObservable { - private FingerprintAuthenticationObservable(Context context) { - super(context); - } + /** + * Creates an Observable that will enable the fingerprint scanner of the device and listen for + * the users fingerprint for authentication + * + * @param context context to use + * @return Observable {@link FingerprintAuthenticationResult} + */ + static Observable create(Context context) { + return Observable.create(new FingerprintAuthenticationObservable(context)); + } - /** - * Creates an Observable that will enable the fingerprint scanner of the device and listen for - * the users fingerprint for authentication - * - * @param context context to use - * @return Observable {@link FingerprintAuthenticationResult} - */ - static Observable create(Context context) { - return Observable.fromEmitter(new FingerprintAuthenticationObservable(context), LATEST); - } + private FingerprintAuthenticationObservable(Context context) { + super(context); + } - @Nullable - @Override - protected FingerprintManagerCompat.CryptoObject initCryptoObject(Emitter subscriber) { - // Simple authentication does not need CryptoObject - return null; - } + @Nullable + @Override + protected FingerprintManagerCompat.CryptoObject initCryptoObject(Subscriber subscriber) { + // Simple authentication does not need CryptoObject + return null; + } - @Override - protected void onAuthenticationSucceeded(Emitter emitter, FingerprintManagerCompat.AuthenticationResult result) { - emitter.onNext(new FingerprintAuthenticationResult(FingerprintResult.AUTHENTICATED, null)); - emitter.onCompleted(); - } + @Override + protected void onAuthenticationSucceeded(Subscriber subscriber, FingerprintManagerCompat.AuthenticationResult result) { + subscriber.onNext(new FingerprintAuthenticationResult(FingerprintResult.AUTHENTICATED, null)); + subscriber.onCompleted(); + } - @Override - protected void onAuthenticationHelp(Emitter emitter, int helpMessageId, String helpString) { - emitter.onNext(new FingerprintAuthenticationResult(FingerprintResult.HELP, helpString)); - } + @Override + protected void onAuthenticationHelp(Subscriber subscriber, int helpMessageId, String helpString) { + subscriber.onNext(new FingerprintAuthenticationResult(FingerprintResult.HELP, helpString)); + } - @Override - protected void onAuthenticationFailed(Emitter emitter) { - emitter.onNext(new FingerprintAuthenticationResult(FingerprintResult.FAILED, null)); - } + @Override + protected void onAuthenticationFailed(Subscriber subscriber) { + subscriber.onNext(new FingerprintAuthenticationResult(FingerprintResult.FAILED, null)); + } } diff --git a/rxfingerprint/src/main/java/com/mtramin/rxfingerprint/FingerprintDecryptionObservable.java b/rxfingerprint/src/main/java/com/mtramin/rxfingerprint/FingerprintDecryptionObservable.java index d794997..df95779 100644 --- a/rxfingerprint/src/main/java/com/mtramin/rxfingerprint/FingerprintDecryptionObservable.java +++ b/rxfingerprint/src/main/java/com/mtramin/rxfingerprint/FingerprintDecryptionObservable.java @@ -37,10 +37,8 @@ import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; -import rx.Emitter; import rx.Observable; - -import static rx.Emitter.BackpressureMode.LATEST; +import rx.Subscriber; /** * Decrypts data with fingerprint authentication. Initializes a {@link Cipher} for decryption which @@ -51,74 +49,74 @@ */ class FingerprintDecryptionObservable extends FingerprintObservable { - private final String keyName; - private final CryptoData encryptedData; - - private FingerprintDecryptionObservable(Context context, String keyName, String encrypted) { - super(context); - this.keyName = keyName; - this.encryptedData = CryptoData.fromString(encrypted); - } - - /** - * Creates a new FingerprintEncryptionObservable that will listen to fingerprint authentication - * to encrypt the given data. - * - * @param context context to use - * @param keyName keyName to use for the decryption - * @param encrypted data to encrypt @return Observable {@link FingerprintEncryptionResult} - * @return Observable result of the decryption - */ - static Observable create(Context context, String keyName, String encrypted) { - return Observable.fromEmitter(new FingerprintDecryptionObservable(context, keyName, encrypted), LATEST); - } - - /** - * Creates a new FingerprintEncryptionObservable that will listen to fingerprint authentication - * to encrypt the given data. - * - * @param context context to use - * @param encrypted data to encrypt @return Observable {@link FingerprintEncryptionResult} - * @return Observable result of the decryption - */ - static Observable create(Context context, String encrypted) { - return Observable.fromEmitter(new FingerprintDecryptionObservable(context, null, encrypted), LATEST); - } - - @Nullable - @Override - protected FingerprintManagerCompat.CryptoObject initCryptoObject(Emitter subscriber) { - CryptoProvider cryptoProvider = new CryptoProvider(this.context, this.keyName); - try { - Cipher cipher = cryptoProvider.initDecryptionCipher(encryptedData.getIv()); - return new FingerprintManagerCompat.CryptoObject(cipher); - } catch (NoSuchAlgorithmException | CertificateException | InvalidKeyException | KeyStoreException | InvalidAlgorithmParameterException | NoSuchPaddingException | IOException | UnrecoverableKeyException e) { - subscriber.onError(e); - return null; - } - } - - @Override - protected void onAuthenticationSucceeded(Emitter emitter, FingerprintManagerCompat.AuthenticationResult result) { - try { - Cipher cipher = result.getCryptoObject().getCipher(); - String decrypted = new String(cipher.doFinal(encryptedData.getMessage())); - - emitter.onNext(new FingerprintDecryptionResult(FingerprintResult.AUTHENTICATED, null, decrypted)); - emitter.onCompleted(); - } catch (BadPaddingException | IllegalBlockSizeException e) { - emitter.onError(e); - } - - } - - @Override - protected void onAuthenticationHelp(Emitter emitter, int helpMessageId, String helpString) { - emitter.onNext(new FingerprintDecryptionResult(FingerprintResult.HELP, helpString, null)); - } - - @Override - protected void onAuthenticationFailed(Emitter emitter) { - emitter.onNext(new FingerprintDecryptionResult(FingerprintResult.FAILED, null, null)); - } + private final String keyName; + private final CryptoData encryptedData; + + /** + * Creates a new FingerprintEncryptionObservable that will listen to fingerprint authentication + * to encrypt the given data. + * + * @param context context to use + * @param keyName keyName to use for the decryption + * @param encrypted data to encrypt @return Observable {@link FingerprintEncryptionResult} + * @return Observable result of the decryption + */ + static Observable create(Context context, String keyName, String encrypted) { + return Observable.create(new FingerprintDecryptionObservable(context, keyName, encrypted)); + } + + /** + * Creates a new FingerprintEncryptionObservable that will listen to fingerprint authentication + * to encrypt the given data. + * + * @param context context to use + * @param encrypted data to encrypt @return Observable {@link FingerprintEncryptionResult} + * @return Observable result of the decryption + */ + static Observable create(Context context, String encrypted) { + return Observable.create(new FingerprintDecryptionObservable(context, null, encrypted)); + } + + private FingerprintDecryptionObservable(Context context, String keyName, String encrypted) { + super(context); + this.keyName = keyName; + encryptedData = CryptoData.fromString(encrypted); + } + + @Nullable + @Override + protected FingerprintManagerCompat.CryptoObject initCryptoObject(Subscriber subscriber) { + CryptoProvider cryptoProvider = new CryptoProvider(context, keyName); + try { + Cipher cipher = cryptoProvider.initDecryptionCipher(encryptedData.getIv()); + return new FingerprintManagerCompat.CryptoObject(cipher); + } catch (NoSuchAlgorithmException | CertificateException | InvalidKeyException | KeyStoreException | InvalidAlgorithmParameterException | NoSuchPaddingException | IOException | UnrecoverableKeyException e) { + subscriber.onError(e); + return null; + } + } + + @Override + protected void onAuthenticationSucceeded(Subscriber subscriber, FingerprintManagerCompat.AuthenticationResult result) { + try { + Cipher cipher = result.getCryptoObject().getCipher(); + String decrypted = new String(cipher.doFinal(encryptedData.getMessage())); + + subscriber.onNext(new FingerprintDecryptionResult(FingerprintResult.AUTHENTICATED, null, decrypted)); + subscriber.onCompleted(); + } catch (BadPaddingException | IllegalBlockSizeException e) { + subscriber.onError(e); + } + + } + + @Override + protected void onAuthenticationHelp(Subscriber subscriber, int helpMessageId, String helpString) { + subscriber.onNext(new FingerprintDecryptionResult(FingerprintResult.HELP, helpString, null)); + } + + @Override + protected void onAuthenticationFailed(Subscriber subscriber) { + subscriber.onNext(new FingerprintDecryptionResult(FingerprintResult.FAILED, null, null)); + } } diff --git a/rxfingerprint/src/main/java/com/mtramin/rxfingerprint/FingerprintEncryptionObservable.java b/rxfingerprint/src/main/java/com/mtramin/rxfingerprint/FingerprintEncryptionObservable.java index 47080b5..2a08578 100644 --- a/rxfingerprint/src/main/java/com/mtramin/rxfingerprint/FingerprintEncryptionObservable.java +++ b/rxfingerprint/src/main/java/com/mtramin/rxfingerprint/FingerprintEncryptionObservable.java @@ -40,10 +40,8 @@ import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.IvParameterSpec; -import rx.Emitter; import rx.Observable; - -import static rx.Emitter.BackpressureMode.LATEST; +import rx.Subscriber; /** * Encrypts data with fingerprint authentication. Initializes a {@link Cipher} for encryption which @@ -52,79 +50,79 @@ */ class FingerprintEncryptionObservable extends FingerprintObservable { - private final String keyName; - private final String toEncrypt; - - private FingerprintEncryptionObservable(Context context, String keyName, String toEncrypt) { - super(context); - this.keyName = keyName; - - if (toEncrypt == null) { - throw new NullPointerException("String to be encrypted is null. Can only encrypt valid strings"); - } - this.toEncrypt = toEncrypt; - } - - /** - * Creates a new FingerprintEncryptionObservable that will listen to fingerprint authentication - * to encrypt the given data. - * - * @param context context to use - * @param keyName name of the key in the keystore - * @param toEncrypt data to encrypt @return Observable {@link FingerprintEncryptionResult} - */ - static Observable create(Context context, String keyName, String toEncrypt) { - return Observable.fromEmitter(new FingerprintEncryptionObservable(context, keyName, toEncrypt), LATEST); - } - - /** - * Creates a new FingerprintEncryptionObservable that will listen to fingerprint authentication - * to encrypt the given data. - * - * @param context context to use - * @param toEncrypt data to encrypt @return Observable {@link FingerprintEncryptionResult} - */ - static Observable create(Context context, String toEncrypt) { - return Observable.fromEmitter(new FingerprintEncryptionObservable(context, null, toEncrypt), LATEST); - } - - @Nullable - @Override - protected FingerprintManagerCompat.CryptoObject initCryptoObject(Emitter emitter) { - CryptoProvider cryptoProvider = new CryptoProvider(this.context, this.keyName); - try { - Cipher cipher = cryptoProvider.initEncryptionCipher(); - return new FingerprintManagerCompat.CryptoObject(cipher); - } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException | InvalidAlgorithmParameterException | CertificateException | UnrecoverableKeyException | KeyStoreException | IOException e) { - emitter.onError(e); - return null; - } - - } - - @Override - protected void onAuthenticationSucceeded(Emitter emitter, FingerprintManagerCompat.AuthenticationResult result) { - try { - Cipher cipher = result.getCryptoObject().getCipher(); - byte[] encryptedBytes = cipher.doFinal(toEncrypt.getBytes("UTF-8")); - byte[] ivBytes = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV(); - - CryptoData cryptoData = CryptoData.fromBytes(encryptedBytes, ivBytes); - - emitter.onNext(new FingerprintEncryptionResult(FingerprintResult.AUTHENTICATED, null, cryptoData.toString())); - emitter.onCompleted(); - } catch (IllegalBlockSizeException | BadPaddingException | InvalidParameterSpecException | UnsupportedEncodingException e) { - emitter.onError(e); - } - } - - @Override - protected void onAuthenticationHelp(Emitter emitter, int helpMessageId, String helpString) { - emitter.onNext(new FingerprintEncryptionResult(FingerprintResult.HELP, helpString, null)); - } - - @Override - protected void onAuthenticationFailed(Emitter emitter) { - emitter.onNext(new FingerprintEncryptionResult(FingerprintResult.FAILED, null, null)); - } + private final String keyName; + private final String toEncrypt; + + /** + * Creates a new FingerprintEncryptionObservable that will listen to fingerprint authentication + * to encrypt the given data. + * + * @param context context to use + * @param keyName name of the key in the keystore + * @param toEncrypt data to encrypt @return Observable {@link FingerprintEncryptionResult} + */ + static Observable create(Context context, String keyName, String toEncrypt) { + return Observable.create(new FingerprintEncryptionObservable(context, keyName, toEncrypt)); + } + + /** + * Creates a new FingerprintEncryptionObservable that will listen to fingerprint authentication + * to encrypt the given data. + * + * @param context context to use + * @param toEncrypt data to encrypt @return Observable {@link FingerprintEncryptionResult} + */ + static Observable create(Context context, String toEncrypt) { + return Observable.create(new FingerprintEncryptionObservable(context, null, toEncrypt)); + } + + private FingerprintEncryptionObservable(Context context, String keyName, String toEncrypt) { + super(context); + this.keyName = keyName; + + if (toEncrypt == null) { + throw new NullPointerException("String to be encrypted is null. Can only encrypt valid strings"); + } + this.toEncrypt = toEncrypt; + } + + @Nullable + @Override + protected FingerprintManagerCompat.CryptoObject initCryptoObject(Subscriber subscriber) { + CryptoProvider cryptoProvider = new CryptoProvider(context, keyName); + try { + Cipher cipher = cryptoProvider.initEncryptionCipher(); + return new FingerprintManagerCompat.CryptoObject(cipher); + } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException | InvalidAlgorithmParameterException | CertificateException | UnrecoverableKeyException | KeyStoreException | IOException e) { + subscriber.onError(e); + return null; + } + + } + + @Override + protected void onAuthenticationSucceeded(Subscriber subscriber, FingerprintManagerCompat.AuthenticationResult result) { + try { + Cipher cipher = result.getCryptoObject().getCipher(); + byte[] encryptedBytes = cipher.doFinal(toEncrypt.getBytes("UTF-8")); + byte[] ivBytes = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV(); + + CryptoData cryptoData = CryptoData.fromBytes(encryptedBytes, ivBytes); + + subscriber.onNext(new FingerprintEncryptionResult(FingerprintResult.AUTHENTICATED, null, cryptoData.toString())); + subscriber.onCompleted(); + } catch (IllegalBlockSizeException | BadPaddingException | InvalidParameterSpecException | UnsupportedEncodingException e) { + subscriber.onError(e); + } + } + + @Override + protected void onAuthenticationHelp(Subscriber subscriber, int helpMessageId, String helpString) { + subscriber.onNext(new FingerprintEncryptionResult(FingerprintResult.HELP, helpString, null)); + } + + @Override + protected void onAuthenticationFailed(Subscriber subscriber) { + subscriber.onNext(new FingerprintEncryptionResult(FingerprintResult.FAILED, null, null)); + } } diff --git a/rxfingerprint/src/main/java/com/mtramin/rxfingerprint/FingerprintObservable.java b/rxfingerprint/src/main/java/com/mtramin/rxfingerprint/FingerprintObservable.java index 9288ba8..7bc7d48 100644 --- a/rxfingerprint/src/main/java/com/mtramin/rxfingerprint/FingerprintObservable.java +++ b/rxfingerprint/src/main/java/com/mtramin/rxfingerprint/FingerprintObservable.java @@ -27,48 +27,49 @@ import com.mtramin.rxfingerprint.data.FingerprintAuthenticationException; -import rx.Emitter; +import rx.Observable; import rx.Subscriber; -import rx.functions.Action1; import rx.subscriptions.Subscriptions; /** * Base observable for Fingerprint authentication. Provides abstract methods that allow * to alter the input and result of the authentication. */ -abstract class FingerprintObservable implements Action1> { +abstract class FingerprintObservable implements Observable.OnSubscribe { protected final Context context; private CancellationSignal cancellationSignal; - /** - * Default constructor for fingerprint authentication - * - * @param context Context to be used for the fingerprint authentication - */ - FingerprintObservable(Context context) { - // If this is an Application Context, it causes issues when rotating the device while - // the sensor is active. The 2nd callback will receive the cancellation error of the first - // authentication action which will immediately onError and unsubscribe the 2nd - // authentication action. - if (context instanceof Application) { - Log.w("RxFingerprint", "Passing an Application Context to RxFingerprint might cause issues when the authentication is active and the application changes orientation. Consider passing an Activity Context."); - } - this.context = context; - } + /** + * Default constructor for fingerprint authentication + * + * @param context Context to be used for the fingerprint authentication + */ + FingerprintObservable(Context context) { + // If this is an Application Context, it causes issues when rotating the device while + // the sensor is active. The 2nd callback will receive the cancellation error of the first + // authentication action which will immediately onError and unsubscribe the 2nd + // authentication action. + if (context instanceof Application) { + Log.w("RxFingerprint", "Passing an Application Context to RxFingerprint might cause issues when the authentication is active and the application changes orientation. Consider passing an Activity Context."); + } + this.context = context; + } @Override - public void call(Emitter emitter) { + public void call(Subscriber subscriber) { if (!RxFingerprint.isAvailable(context)) { - emitter.onError(new IllegalAccessException("Fingerprint authentication is not available on this device! Ensure that the device has a Fingerprint sensor and enrolled Fingerprints by calling RxFingerprint#isAvailable(Context) first")); + if (!subscriber.isUnsubscribed()) { + subscriber.onError(new IllegalAccessException("Fingerprint authentication is not available on this device! Ensure that the device has a Fingerprint sensor and enrolled Fingerprints by calling RxFingerprint#isAvailable(Context) first")); + } } - AuthenticationCallback callback = createAuthenticationCallback(emitter); + AuthenticationCallback callback = createAuthenticationCallback(subscriber); cancellationSignal = new CancellationSignal(); - FingerprintManagerCompat.CryptoObject cryptoObject = initCryptoObject(emitter); + FingerprintManagerCompat.CryptoObject cryptoObject = initCryptoObject(subscriber); FingerprintManagerCompat.from(context).authenticate(cryptoObject, 0, cancellationSignal, callback, null); - emitter.setSubscription(Subscriptions.create(() -> { + subscriber.add(Subscriptions.create(() -> { if (cancellationSignal != null && !cancellationSignal.isCanceled()) { cancellationSignal.cancel(); } @@ -77,30 +78,38 @@ public void call(Emitter emitter) { } @NonNull - private AuthenticationCallback createAuthenticationCallback(Emitter emitter) { + private AuthenticationCallback createAuthenticationCallback(Subscriber subscriber) { return new AuthenticationCallback() { @Override public void onAuthenticationError(int errMsgId, CharSequence errString) { super.onAuthenticationError(errMsgId, errString); - emitter.onError(new FingerprintAuthenticationException(errString)); + if (!subscriber.isUnsubscribed()) { + subscriber.onError(new FingerprintAuthenticationException(errString)); + } } @Override public void onAuthenticationFailed() { super.onAuthenticationFailed(); - FingerprintObservable.this.onAuthenticationFailed(emitter); + if (!subscriber.isUnsubscribed()) { + FingerprintObservable.this.onAuthenticationFailed(subscriber); + } } @Override public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) { super.onAuthenticationHelp(helpMsgId, helpString); - FingerprintObservable.this.onAuthenticationHelp(emitter, helpMsgId, helpString.toString()); + if (!subscriber.isUnsubscribed()) { + FingerprintObservable.this.onAuthenticationHelp(subscriber, helpMsgId, helpString.toString()); + } } @Override public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) { super.onAuthenticationSucceeded(result); - FingerprintObservable.this.onAuthenticationSucceeded(emitter, result); + if (!subscriber.isUnsubscribed()) { + FingerprintObservable.this.onAuthenticationSucceeded(subscriber, result); + } } }; } @@ -109,12 +118,12 @@ public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationRes * Method to initialize the {@link FingerprintManagerCompat.CryptoObject} * used for the fingerprint authentication. * - * @param emitter current emitter + * @param subscriber current subscriber * @return a {@link FingerprintManagerCompat.CryptoObject} * that is to be used in the authentication. May be {@code null}. */ @Nullable - protected abstract FingerprintManagerCompat.CryptoObject initCryptoObject(Emitter emitter); + protected abstract FingerprintManagerCompat.CryptoObject initCryptoObject(Subscriber subscriber); /** * Action to execute when fingerprint authentication was successful. @@ -122,10 +131,10 @@ public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationRes *

* Should call {@link Subscriber#onCompleted()}. * - * @param emitter current emitter - * @param result result of the successful fingerprint authentication + * @param subscriber current subscriber + * @param result result of the successful fingerprint authentication */ - protected abstract void onAuthenticationSucceeded(Emitter emitter, FingerprintManagerCompat.AuthenticationResult result); + protected abstract void onAuthenticationSucceeded(Subscriber subscriber, FingerprintManagerCompat.AuthenticationResult result); /** * Action to execute when the fingerprint authentication returned a help result. @@ -133,11 +142,11 @@ public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationRes *

* Should not {@link Subscriber#onCompleted()}. * - * @param emitter current emitter + * @param subscriber current subscriber * @param helpMessageId ID of the help message returned from the {@link FingerprintManagerCompat} * @param helpString Help message string returned by the {@link FingerprintManagerCompat} */ - protected abstract void onAuthenticationHelp(Emitter emitter, int helpMessageId, String helpString); + protected abstract void onAuthenticationHelp(Subscriber subscriber, int helpMessageId, String helpString); /** * Action to execute when the fingerprint authentication failed. @@ -146,7 +155,7 @@ public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationRes * Should only call {@link Subscriber#onCompleted()} when fingerprint authentication should be * canceled due to the failed event. * - * @param emitter current emitter + * @param subscriber current subscriber */ - protected abstract void onAuthenticationFailed(Emitter emitter); + protected abstract void onAuthenticationFailed(Subscriber subscriber); }