diff options
author | Tiem Song <tiem@google.com> | 2017-11-14 18:17:15 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2017-11-14 18:17:15 +0000 |
commit | 78ec28ceaf0efaf9fdc6e8d74166123b153fd634 (patch) | |
tree | c891573fbdf05d8f5832495c3315e0cc530e9c23 | |
parent | 6f5c750676f0f6371b7f106c0b434825a82c6fa7 (diff) | |
parent | 6cb485a0c2cbe9be5f447c7d375725b7f087edfd (diff) | |
download | android-78ec28ceaf0efaf9fdc6e8d74166123b153fd634.tar.gz |
Merge "Create Kotlin version of FingerprintDialog sample" into oc-dev am: 44f2c83565
am: 6cb485a0c2
Change-Id: I2bec02b146fbba64f4934f4903acd6f7186793c8
45 files changed, 1762 insertions, 0 deletions
diff --git a/security/FingerprintDialog/kotlinApp/app/build.gradle b/security/FingerprintDialog/kotlinApp/app/build.gradle new file mode 100644 index 00000000..58bfe13a --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/build.gradle @@ -0,0 +1,25 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' + +android { + compileSdkVersion 27 + defaultConfig { + applicationId "com.example.android.fingerprintdialog" + minSdkVersion 24 + targetSdkVersion 27 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation "com.android.support:appcompat-v7:27.0.0" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" +}
\ No newline at end of file diff --git a/security/FingerprintDialog/kotlinApp/app/proguard-project.txt b/security/FingerprintDialog/kotlinApp/app/proguard-project.txt new file mode 100644 index 00000000..f2fe1559 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/AndroidManifest.xml b/security/FingerprintDialog/kotlinApp/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..9dffd1ce --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/AndroidManifest.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright (C) 2017 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 + --> +<manifest package="com.example.android.fingerprintdialog" + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:versionCode="1" + android:versionName="1.0"> + + <uses-permission android:name="android.permission.USE_FINGERPRINT" /> + + <application + android:allowBackup="true" + android:icon="@mipmap/ic_launcher" + android:label="@string/application_name" + android:supportsRtl="true" + android:theme="@style/Theme.AppCompat.Light" + tools:ignore="GoogleAppIndexingWarning"> + + <activity + android:name=".MainActivity" + android:label="@string/application_name" + android:theme="@style/Theme.AppCompat.Light.NoActionBar"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <activity + android:name=".SettingsActivity" + android:label="@string/action_settings" + android:parentActivityName=".MainActivity"/> + </application> +</manifest> diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/ActivityExtensions.kt b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/ActivityExtensions.kt new file mode 100644 index 00000000..108ca436 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/ActivityExtensions.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2017 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 com.example.android.fingerprintdialog + +import android.support.v7.app.AppCompatActivity +import android.widget.Toast + +fun AppCompatActivity.showToast(text: String) { + Toast.makeText(this, text, Toast.LENGTH_LONG).show() +}
\ No newline at end of file diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/Constants.kt b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/Constants.kt new file mode 100644 index 00000000..8f93fb11 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/Constants.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2017 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. + */ + +@file:JvmName("Constants") + +package com.example.android.fingerprintdialog + +@JvmField val DEFAULT_KEY_NAME = "default_key" + +/** + * Enumeration to indicate which authentication method the user is trying to authenticate with. + */ +enum class Stage { FINGERPRINT, NEW_FINGERPRINT_ENROLLED, PASSWORD } diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/FingerprintAuthenticationDialogFragment.kt b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/FingerprintAuthenticationDialogFragment.kt new file mode 100644 index 00000000..8e0fe0bd --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/FingerprintAuthenticationDialogFragment.kt @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2017 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 com.example.android.fingerprintdialog + +import android.app.DialogFragment +import android.content.Context +import android.content.SharedPreferences +import android.hardware.fingerprint.FingerprintManager +import android.os.Bundle +import android.preference.PreferenceManager +import android.view.KeyEvent +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.inputmethod.EditorInfo +import android.view.inputmethod.InputMethodManager +import android.widget.Button +import android.widget.CheckBox +import android.widget.EditText +import android.widget.TextView + +/** + * A dialog which uses fingerprint APIs to authenticate the user, and falls back to password + * authentication if fingerprint is not available. + */ +class FingerprintAuthenticationDialogFragment : DialogFragment(), + TextView.OnEditorActionListener, + FingerprintUiHelper.Callback { + + private lateinit var backupContent: View + private lateinit var cancelButton: Button + private lateinit var fingerprintContainer: View + private lateinit var fingerprintEnrolledTextView: TextView + private lateinit var passwordDescriptionTextView: TextView + private lateinit var passwordEditText: EditText + private lateinit var secondDialogButton: Button + private lateinit var useFingerprintFutureCheckBox: CheckBox + + internal lateinit var callback: Callback + internal lateinit var cryptoObject: FingerprintManager.CryptoObject + private lateinit var fingerprintUiHelper: FingerprintUiHelper + private lateinit var inputMethodManager: InputMethodManager + private lateinit var sharedPreferences: SharedPreferences + + internal var stage = Stage.FINGERPRINT + + private val showKeyboardRunnable = Runnable { + inputMethodManager.showSoftInput(passwordEditText, 0) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + // Do not create a new Fragment when the Activity is re-created such as orientation changes. + retainInstance = true + setStyle(DialogFragment.STYLE_NORMAL, android.R.style.Theme_Material_Light_Dialog) + } + + override fun onCreateView(inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + dialog.setTitle(getString(R.string.sign_in)) + return inflater.inflate(R.layout.fingerprint_dialog_container, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + backupContent = view.findViewById(R.id.backup_container) + cancelButton = view.findViewById(R.id.cancel_button) + fingerprintContainer = view.findViewById(R.id.fingerprint_container) + fingerprintEnrolledTextView = view.findViewById(R.id.new_fingerprint_enrolled_description) + passwordDescriptionTextView = view.findViewById(R.id.password_description) + passwordEditText = view.findViewById(R.id.password) + secondDialogButton = view.findViewById(R.id.second_dialog_button) + useFingerprintFutureCheckBox = view.findViewById(R.id.use_fingerprint_in_future_check) + + cancelButton.setOnClickListener { dismiss() } + passwordEditText.setOnEditorActionListener(this) + secondDialogButton.setOnClickListener { + if (stage == Stage.FINGERPRINT) goToBackup() else verifyPassword() + } + + fingerprintUiHelper = FingerprintUiHelper( + activity.getSystemService(FingerprintManager::class.java), + view.findViewById(R.id.fingerprint_icon), + view.findViewById(R.id.fingerprint_status), + this + ) + updateStage() + + // If fingerprint authentication is not available, switch immediately to the backup + // (password) screen. + if (!fingerprintUiHelper.isFingerprintAuthAvailable) { + goToBackup() + } + } + override fun onResume() { + super.onResume() + if (stage == Stage.FINGERPRINT) { + fingerprintUiHelper.startListening(cryptoObject) + } + } + + override fun onPause() { + super.onPause() + fingerprintUiHelper.stopListening() + } + + override fun onAttach(context: Context) { + super.onAttach(context) + inputMethodManager = context.getSystemService(InputMethodManager::class.java) + sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) + } + + /** + * Switches to backup (password) screen. This either can happen when fingerprint is not + * available or the user chooses to use the password authentication method by pressing the + * button. This can also happen when the user has too many invalid fingerprint attempts. + */ + private fun goToBackup() { + stage = Stage.PASSWORD + updateStage() + passwordEditText.run { + requestFocus() + + // Show the keyboard. + postDelayed(showKeyboardRunnable, 500) + } + + // Fingerprint is not used anymore. Stop listening for it. + fingerprintUiHelper.stopListening() + } + + /** + * Checks whether the current entered password is correct, and dismisses the dialog and + * informs the activity about the result. + */ + private fun verifyPassword() { + if (!checkPassword(passwordEditText.text.toString())) { + return + } + if (stage == Stage.NEW_FINGERPRINT_ENROLLED) { + sharedPreferences.edit() + .putBoolean(getString(R.string.use_fingerprint_to_authenticate_key), + useFingerprintFutureCheckBox.isChecked) + .apply() + + if (useFingerprintFutureCheckBox.isChecked) { + // Re-create the key so that fingerprints including new ones are validated. + callback.createKey(DEFAULT_KEY_NAME) + stage = Stage.FINGERPRINT + } + } + passwordEditText.setText("") + callback.onPurchased(withFingerprint = false) + dismiss() + } + + /** + * Checks if the given password is valid. Assume that the password is always correct. + * In a real world situation, the password needs to be verified via the server. + * + * @param password The password String + * + * @return true if `password` is correct, false otherwise + */ + private fun checkPassword(password: String) = password.isNotEmpty() + + private fun updateStage() { + when (stage) { + Stage.FINGERPRINT -> { + cancelButton.setText(R.string.cancel) + secondDialogButton.setText(R.string.use_password) + fingerprintContainer.visibility = View.VISIBLE + backupContent.visibility = View.GONE + } + Stage.NEW_FINGERPRINT_ENROLLED, // Intentional fall through + Stage.PASSWORD -> { + cancelButton.setText(R.string.cancel) + secondDialogButton.setText(R.string.ok) + fingerprintContainer.visibility = View.GONE + backupContent.visibility = View.VISIBLE + if (stage == Stage.NEW_FINGERPRINT_ENROLLED) { + passwordDescriptionTextView.visibility = View.GONE + fingerprintEnrolledTextView.visibility = View.VISIBLE + useFingerprintFutureCheckBox.visibility = View.VISIBLE + } + } + } + } + + override fun onEditorAction(v: TextView, actionId: Int, event: KeyEvent?): Boolean { + return if (actionId == EditorInfo.IME_ACTION_GO) { verifyPassword(); true } else false + } + + override fun onAuthenticated() { + // Callback from FingerprintUiHelper. Let the activity know that authentication succeeded. + callback.onPurchased(withFingerprint = true, crypto = cryptoObject) + dismiss() + } + + override fun onError() { + goToBackup() + } + + interface Callback { + fun onPurchased(withFingerprint: Boolean, crypto: FingerprintManager.CryptoObject? = null) + fun createKey(keyName: String, invalidatedByBiometricEnrollment: Boolean = true) + } +} diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/FingerprintUiHelper.kt b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/FingerprintUiHelper.kt new file mode 100644 index 00000000..ad38abc6 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/FingerprintUiHelper.kt @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2017 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 com.example.android.fingerprintdialog + +import android.hardware.fingerprint.FingerprintManager +import android.os.CancellationSignal +import android.widget.ImageView +import android.widget.TextView + +/** + * Small helper class to manage text/icon around fingerprint authentication UI. + */ +class FingerprintUiHelper + +/** + * Constructor for [FingerprintUiHelper]. + */ +internal constructor(private val fingerprintMgr: FingerprintManager, + private val icon: ImageView, + private val errorTextView: TextView, + private val callback: Callback +) : FingerprintManager.AuthenticationCallback() { + + private var cancellationSignal: CancellationSignal? = null + private var selfCancelled = false + + val isFingerprintAuthAvailable: Boolean + get() = fingerprintMgr.isHardwareDetected && fingerprintMgr.hasEnrolledFingerprints() + + private val resetErrorTextRunnable = Runnable { + icon.setImageResource(R.drawable.ic_fp_40px) + errorTextView.run { + setTextColor(errorTextView.resources.getColor(R.color.hint_color, null)) + text = errorTextView.resources.getString(R.string.fingerprint_hint) + } + } + + fun startListening(cryptoObject: FingerprintManager.CryptoObject) { + if (!isFingerprintAuthAvailable) return + cancellationSignal = CancellationSignal() + selfCancelled = false + fingerprintMgr.authenticate(cryptoObject, cancellationSignal, 0, this, null) + icon.setImageResource(R.drawable.ic_fp_40px) + } + + fun stopListening() { + cancellationSignal?.also { + selfCancelled = true + it.cancel() + } + cancellationSignal = null + } + + override fun onAuthenticationError(errMsgId: Int, errString: CharSequence) { + if (!selfCancelled) { + showError(errString) + icon.postDelayed({ callback.onError() }, ERROR_TIMEOUT_MILLIS) + } + } + + override fun onAuthenticationHelp(helpMsgId: Int, helpString: CharSequence) = + showError(helpString) + + override fun onAuthenticationFailed() = + showError(icon.resources.getString(R.string.fingerprint_not_recognized)) + + override fun onAuthenticationSucceeded(result: FingerprintManager.AuthenticationResult) { + errorTextView.run { + removeCallbacks(resetErrorTextRunnable) + setTextColor(errorTextView.resources.getColor(R.color.success_color, null)) + text = errorTextView.resources.getString(R.string.fingerprint_success) + } + icon.run { + setImageResource(R.drawable.ic_fingerprint_success) + postDelayed({ callback.onAuthenticated() }, SUCCESS_DELAY_MILLIS) + } + } + + private fun showError(error: CharSequence) { + icon.setImageResource(R.drawable.ic_fingerprint_error) + errorTextView.run { + text = error + setTextColor(errorTextView.resources.getColor(R.color.warning_color, null)) + removeCallbacks(resetErrorTextRunnable) + postDelayed(resetErrorTextRunnable, ERROR_TIMEOUT_MILLIS) + } + } + + interface Callback { + fun onAuthenticated() + fun onError() + } + + companion object { + val ERROR_TIMEOUT_MILLIS: Long = 1600 + val SUCCESS_DELAY_MILLIS: Long = 1300 + } +} diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/MainActivity.kt b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/MainActivity.kt new file mode 100644 index 00000000..27bcd250 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/MainActivity.kt @@ -0,0 +1,332 @@ +/* + * Copyright (C) 2017 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 com.example.android.fingerprintdialog + +import android.app.KeyguardManager +import android.content.Intent +import android.content.SharedPreferences +import android.hardware.fingerprint.FingerprintManager +import android.os.Bundle +import android.preference.PreferenceManager +import android.security.keystore.KeyGenParameterSpec +import android.security.keystore.KeyPermanentlyInvalidatedException +import android.security.keystore.KeyProperties +import android.security.keystore.KeyProperties.BLOCK_MODE_CBC +import android.security.keystore.KeyProperties.ENCRYPTION_PADDING_PKCS7 +import android.security.keystore.KeyProperties.KEY_ALGORITHM_AES +import android.support.v7.app.AppCompatActivity +import android.util.Base64 +import android.util.Log +import android.view.Menu +import android.view.MenuItem +import android.view.View +import android.widget.Button +import android.widget.TextView +import android.widget.Toast +import java.io.IOException +import java.security.InvalidAlgorithmParameterException +import java.security.InvalidKeyException +import java.security.KeyStore +import java.security.KeyStoreException +import java.security.NoSuchAlgorithmException +import java.security.NoSuchProviderException +import java.security.UnrecoverableKeyException +import java.security.cert.CertificateException +import javax.crypto.BadPaddingException +import javax.crypto.Cipher +import javax.crypto.IllegalBlockSizeException +import javax.crypto.KeyGenerator +import javax.crypto.NoSuchPaddingException +import javax.crypto.SecretKey + +/** + * Main entry point for the sample, showing a backpack and "Purchase" button. + */ +class MainActivity : AppCompatActivity(), + FingerprintAuthenticationDialogFragment.Callback { + + private lateinit var keyStore: KeyStore + private lateinit var keyGenerator: KeyGenerator + private lateinit var sharedPreferences: SharedPreferences + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + setSupportActionBar(findViewById(R.id.toolbar)) + setupKeyStoreAndKeyGenerator() + + val (defaultCipher: Cipher, cipherNotInvalidated: Cipher) = setupCiphers() + sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this) + setUpPurchaseButtons(cipherNotInvalidated, defaultCipher) + } + + /** + * Enables or disables purchase buttons and sets the appropriate click listeners. + * + * @param cipherNotInvalidated cipher for the not invalidated purchase button + * @param defaultCipher the default cipher, used for the purchase button + */ + private fun setUpPurchaseButtons(cipherNotInvalidated: Cipher, defaultCipher: Cipher) { + val purchaseButton = findViewById<Button>(R.id.purchase_button) + val purchaseButtonNotInvalidated = + findViewById<Button>(R.id.purchase_button_not_invalidated) + + purchaseButtonNotInvalidated.run { + isEnabled = true + setOnClickListener(PurchaseButtonClickListener( + cipherNotInvalidated, KEY_NAME_NOT_INVALIDATED)) + } + + val keyguardManager = getSystemService(KeyguardManager::class.java) + if (!keyguardManager.isKeyguardSecure) { + // Show a message that the user hasn't set up a fingerprint or lock screen. + showToast(getString(R.string.setup_lock_screen)) + purchaseButton.isEnabled = false + purchaseButtonNotInvalidated.isEnabled = false + return + } + + val fingerprintManager = getSystemService(FingerprintManager::class.java) + if (!fingerprintManager.hasEnrolledFingerprints()) { + purchaseButton.isEnabled = false + // This happens when no fingerprints are registered. + showToast(getString(R.string.register_fingerprint)) + return + } + + createKey(DEFAULT_KEY_NAME) + createKey(KEY_NAME_NOT_INVALIDATED, false) + purchaseButton.run { + isEnabled = true + setOnClickListener(PurchaseButtonClickListener(defaultCipher, DEFAULT_KEY_NAME)) + } + } + + /** + * Sets up KeyStore and KeyGenerator + */ + private fun setupKeyStoreAndKeyGenerator() { + try { + keyStore = KeyStore.getInstance(ANDROID_KEY_STORE) + } catch (e: KeyStoreException) { + throw RuntimeException("Failed to get an instance of KeyStore", e) + } + + try { + keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM_AES, ANDROID_KEY_STORE) + } catch (e: Exception) { + when (e) { + is NoSuchAlgorithmException, + is NoSuchProviderException -> + throw RuntimeException("Failed to get an instance of KeyGenerator", e) + else -> throw e + } + } + } + + /** + * Sets up default cipher and a non-invalidated cipher + */ + private fun setupCiphers(): Pair<Cipher, Cipher> { + val defaultCipher: Cipher + val cipherNotInvalidated: Cipher + try { + val cipherString = "$KEY_ALGORITHM_AES/$BLOCK_MODE_CBC/$ENCRYPTION_PADDING_PKCS7" + defaultCipher = Cipher.getInstance(cipherString) + cipherNotInvalidated = Cipher.getInstance(cipherString) + } catch (e: Exception) { + when (e) { + is NoSuchAlgorithmException, + is NoSuchPaddingException -> + throw RuntimeException("Failed to get an instance of Cipher", e) + else -> throw e + } + } + return Pair(defaultCipher, cipherNotInvalidated) + } + + /** + * Initialize the [Cipher] instance with the created key in the [createKey] method. + * + * @param keyName the key name to init the cipher + * @return `true` if initialization succeeded, `false` if the lock screen has been disabled or + * reset after key generation, or if a fingerprint was enrolled after key generation. + */ + private fun initCipher(cipher: Cipher, keyName: String): Boolean { + try { + keyStore.load(null) + cipher.init(Cipher.ENCRYPT_MODE, keyStore.getKey(keyName, null) as SecretKey) + return true + } catch (e: Exception) { + when (e) { + is KeyPermanentlyInvalidatedException -> return false + is KeyStoreException, + is CertificateException, + is UnrecoverableKeyException, + is IOException, + is NoSuchAlgorithmException, + is InvalidKeyException -> throw RuntimeException("Failed to init Cipher", e) + else -> throw e + } + } + } + + /** + * Proceed with the purchase operation + * + * @param withFingerprint `true` if the purchase was made by using a fingerprint + * @param crypto the Crypto object + */ + override fun onPurchased(withFingerprint: Boolean, crypto: FingerprintManager.CryptoObject?) { + if (withFingerprint) { + // If the user authenticated with fingerprint, verify using cryptography and then show + // the confirmation message. + if (crypto != null) { + tryEncrypt(crypto.cipher) + } + } else { + // Authentication happened with backup password. Just show the confirmation message. + showConfirmation() + } + } + + // Show confirmation message. Also show crypto information if fingerprint was used. + private fun showConfirmation(encrypted: ByteArray? = null) { + findViewById<View>(R.id.confirmation_message).visibility = View.VISIBLE + if (encrypted != null) { + findViewById<TextView>(R.id.encrypted_message).run { + visibility = View.VISIBLE + text = Base64.encodeToString(encrypted, 0 /* flags */) + } + } + } + + /** + * Tries to encrypt some data with the generated key from [createKey]. This only works if the + * user just authenticated via fingerprint. + */ + private fun tryEncrypt(cipher: Cipher) { + try { + showConfirmation(cipher.doFinal(SECRET_MESSAGE.toByteArray())) + } catch (e: Exception) { + when (e) { + is BadPaddingException, + is IllegalBlockSizeException -> { + Toast.makeText(this, "Failed to encrypt the data with the generated key. " + + "Retry the purchase", Toast.LENGTH_LONG).show() + Log.e(TAG, "Failed to encrypt the data with the generated key. ${e.message}") + } + else -> throw e + } + } + } + + /** + * Creates a symmetric key in the Android Key Store which can only be used after the user has + * authenticated with a fingerprint. + * + * @param keyName the name of the key to be created + * @param invalidatedByBiometricEnrollment if `false` is passed, the created key will not be + * invalidated even if a new fingerprint is enrolled. The default value is `true` - the key will + * be invalidated if a new fingerprint is enrolled. + */ + override fun createKey(keyName: String, invalidatedByBiometricEnrollment: Boolean) { + // The enrolling flow for fingerprint. This is where you ask the user to set up fingerprint + // for your flow. Use of keys is necessary if you need to know if the set of enrolled + // fingerprints has changed. + try { + keyStore.load(null) + + val keyProperties = KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT + val builder = KeyGenParameterSpec.Builder(keyName, keyProperties) + .setBlockModes(BLOCK_MODE_CBC) + .setUserAuthenticationRequired(true) + .setEncryptionPaddings(ENCRYPTION_PADDING_PKCS7) + .setInvalidatedByBiometricEnrollment(invalidatedByBiometricEnrollment) + + keyGenerator.run { + init(builder.build()) + generateKey() + } + } catch (e: Exception) { + when (e) { + is NoSuchAlgorithmException, + is InvalidAlgorithmParameterException, + is CertificateException, + is IOException -> throw RuntimeException(e) + else -> throw e + } + } + } + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.menu_main, menu) + return true + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + if (item.itemId == R.id.action_settings) { + val intent = Intent(this, SettingsActivity::class.java) + startActivity(intent) + return true + } + return super.onOptionsItemSelected(item) + } + + private inner class PurchaseButtonClickListener internal constructor( + internal var cipher: Cipher, + internal var keyName: String + ) : View.OnClickListener { + + override fun onClick(view: View) { + findViewById<View>(R.id.confirmation_message).visibility = View.GONE + findViewById<View>(R.id.encrypted_message).visibility = View.GONE + + val fragment = FingerprintAuthenticationDialogFragment() + fragment.cryptoObject = FingerprintManager.CryptoObject(cipher) + fragment.callback = this@MainActivity + + // Set up the crypto object for later, which will be authenticated by fingerprint usage. + if (initCipher(cipher, keyName)) { + + // Show the fingerprint dialog. The user has the option to use the fingerprint with + // crypto, or can fall back to using a server-side verified password. + val useFingerprintPreference = sharedPreferences + .getBoolean(getString(R.string.use_fingerprint_to_authenticate_key), true) + if (useFingerprintPreference) { + fragment.stage = Stage.FINGERPRINT + } else { + fragment.stage = Stage.PASSWORD + } + } else { + // This happens if the lock screen has been disabled or or a fingerprint was + // enrolled. Thus, show the dialog to authenticate with their password first and ask + // the user if they want to authenticate with a fingerprint in the future. + fragment.stage = Stage.NEW_FINGERPRINT_ENROLLED + } + fragment.show(fragmentManager, DIALOG_FRAGMENT_TAG) + } + } + + companion object { + private val ANDROID_KEY_STORE = "AndroidKeyStore" + private val DIALOG_FRAGMENT_TAG = "myFragment" + private val KEY_NAME_NOT_INVALIDATED = "key_not_invalidated" + private val SECRET_MESSAGE = "Very secret message" + private val TAG = MainActivity::class.java.simpleName + } +} diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/SettingsActivity.kt b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/SettingsActivity.kt new file mode 100644 index 00000000..6a8dc160 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/SettingsActivity.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2017 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 com.example.android.fingerprintdialog + +import android.os.Bundle +import android.support.v7.app.AppCompatActivity + +class SettingsActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + fragmentManager.beginTransaction() + .replace(android.R.id.content, SettingsFragment()) + .commit() + } + +} diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/SettingsFragment.kt b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/SettingsFragment.kt new file mode 100644 index 00000000..0681e6d3 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/java/com/example/android/fingerprintdialog/SettingsFragment.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2017 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 com.example.android.fingerprintdialog + +import android.os.Bundle +import android.preference.PreferenceFragment + +class SettingsFragment : PreferenceFragment() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addPreferencesFromResource(R.xml.preferences) + } + +} diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-hdpi/ic_fp_40px.png b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-hdpi/ic_fp_40px.png Binary files differnew file mode 100644 index 00000000..48ebd8ad --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-hdpi/ic_fp_40px.png diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-mdpi/ic_fp_40px.png b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-mdpi/ic_fp_40px.png Binary files differnew file mode 100644 index 00000000..122f4425 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-mdpi/ic_fp_40px.png diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-nodpi/android_robot.png b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-nodpi/android_robot.png Binary files differnew file mode 100644 index 00000000..40bf934b --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-nodpi/android_robot.png diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-xhdpi/ic_fp_40px.png b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-xhdpi/ic_fp_40px.png Binary files differnew file mode 100644 index 00000000..e1c9590b --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-xhdpi/ic_fp_40px.png diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-xxhdpi/ic_fp_40px.png b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-xxhdpi/ic_fp_40px.png Binary files differnew file mode 100644 index 00000000..f7e87240 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-xxhdpi/ic_fp_40px.png diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-xxxhdpi/ic_fp_40px.png b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-xxxhdpi/ic_fp_40px.png Binary files differnew file mode 100644 index 00000000..0fb85452 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable-xxxhdpi/ic_fp_40px.png diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable/card.xml b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable/card.xml new file mode 100644 index 00000000..cdd2907f --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable/card.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2017 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 + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + + <solid + android:color="@color/card_solid"/> + + <corners + android:radius="@dimen/card_corner" /> +</shape>
\ No newline at end of file diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable/ic_fingerprint_error.xml b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable/ic_fingerprint_error.xml new file mode 100644 index 00000000..b382543d --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable/ic_fingerprint_error.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2017 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 + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="@dimen/fingerprint_square_dimen" + android:height="@dimen/fingerprint_square_dimen" + android:viewportWidth="@dimen/fingerprint_square_dimen_viewport" + android:viewportHeight="@dimen/fingerprint_square_dimen_viewport"> + <path + android:pathData="M20.0,0.0C8.96,0.0 0.0,8.95 0.0,20.0s8.96,20.0 20.0,20.0c11.04,0.0 20.0,-8.95 20.0,-20.0S31.04,0.0 20.0,0.0z" + android:fillColor="@color/finerprint_error"/> + <path + android:pathData="M21.33,29.33l-2.67,0.0l0.0,-2.67l2.67,0.0L21.33,29.33zM21.33,22.67l-2.67,0.0l0.0,-12.0l2.67,0.0L21.33,22.67z" + android:fillColor="@color/fingerprint_fill"/> +</vector> diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable/ic_fingerprint_success.xml b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable/ic_fingerprint_success.xml new file mode 100644 index 00000000..0195cd79 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/drawable/ic_fingerprint_success.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2017 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 + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="@dimen/fingerprint_square_dimen" + android:height="@dimen/fingerprint_square_dimen" + android:viewportWidth="@dimen/fingerprint_square_dimen_viewport" + android:viewportHeight="@dimen/fingerprint_square_dimen_viewport"> + <path + android:pathData="M20.0,20.0m-20.0,0.0a20.0,20.0 0.0,1.0 1.0,40.0 0.0a20.0,20.0 0.0,1.0 1.0,-40.0 0.0" + android:fillColor="@color/fingerprint_success"/> + <path + android:pathData="M11.2,21.41l1.63,-1.619999 4.17,4.169998 10.59,-10.589999 1.619999,1.63 -12.209999,12.209999z" + android:fillColor="@color/fingerprint_fill"/> +</vector> diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/layout/activity_main.xml b/security/FingerprintDialog/kotlinApp/app/src/main/res/layout/activity_main.xml new file mode 100644 index 00000000..fedfde65 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,138 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2017 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 + --> +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <android.support.v7.widget.Toolbar + android:id="@+id/toolbar" + android:layout_width="match_parent" + android:layout_height="?attr/actionBarSize" + android:background="?attr/colorPrimary" + android:elevation="@dimen/default_elevation" + android:theme="@style/ThemeOverlay.AppCompat.ActionBar" + app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/> + + <ImageView + android:layout_width="@dimen/logo_square_dimen" + android:layout_height="@dimen/logo_square_dimen" + android:layout_marginTop="@dimen/logo_square_margin" + android:layout_marginBottom="@dimen/logo_square_margin" + android:layout_gravity="center_horizontal" + android:scaleType="fitCenter" + android:src="@drawable/android_robot" + android:contentDescription="@string/description_bugdroid_icon"/> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/default_margin_small" + android:layout_marginStart="@dimen/default_margin_small" + android:layout_marginEnd="@dimen/default_margin_small" + android:orientation="vertical" + android:background="@drawable/card" + android:elevation="@dimen/default_elevation" + android:paddingTop="@dimen/default_padding" + android:paddingBottom="@dimen/default_padding" + android:paddingStart="@dimen/default_padding" + android:paddingEnd="@dimen/default_padding"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@android:style/TextAppearance.Material.Headline" + android:text="@string/item_title"/> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@android:style/TextAppearance.Material.Body2" + android:textColor="?android:attr/colorAccent" + android:text="@string/item_price"/> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/default_margin" + android:textAppearance="@android:style/TextAppearance.Material.Body1" + android:textColor="?android:attr/textColorSecondary" + android:text="@string/item_description"/> + + </LinearLayout> + + <Button style="@android:style/Widget.Material.Button.Colored" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/default_margin_small" + android:layout_marginEnd="@dimen/default_margin_end" + android:layout_gravity="end" + android:textColor="?android:attr/textColorPrimaryInverse" + android:text="@string/purchase" + android:id="@+id/purchase_button" /> + + <Button style="@android:style/Widget.Material.Button.Colored" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/default_margin_small" + android:layout_marginEnd="@dimen/default_margin_end" + android:layout_gravity="end" + android:textColor="?android:attr/textColorPrimaryInverse" + android:text="@string/purchase_not_invalidated" + android:id="@+id/purchase_button_not_invalidated" /> + + <TextView + android:id="@+id/purchase_button_not_invalidated_description" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/default_margin_end" + android:gravity="end" + android:textAlignment="gravity" + android:text="@string/purchase_button_not_invalidated_description"/> + + <TextView + android:id="@+id/confirmation_message" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/default_margin" + android:paddingStart="@dimen/default_padding" + android:paddingEnd="@dimen/default_padding" + android:textAppearance="@android:style/TextAppearance.Material.Body2" + android:textColor="?android:attr/colorAccent" + android:text="@string/purchase_done" + android:visibility="gone"/> + + <TextView + android:id="@+id/encrypted_message" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/default_margin" + android:paddingStart="@dimen/default_padding" + android:paddingEnd="@dimen/default_padding" + android:textAppearance="@android:style/TextAppearance.Material.Body2" + android:textColor="?android:attr/colorAccent" + android:text="@string/purchase_done" + android:visibility="gone"/> + + </LinearLayout> + +</ScrollView>
\ No newline at end of file diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/layout/fingerprint_dialog_backup.xml b/security/FingerprintDialog/kotlinApp/app/src/main/res/layout/fingerprint_dialog_backup.xml new file mode 100644 index 00000000..9668f504 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/layout/fingerprint_dialog_backup.xml @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2017 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 + --> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/backup_container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingTop="@dimen/default_padding" + android:paddingBottom="@dimen/default_padding_small"> + + <FrameLayout + android:id="@+id/description" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentTop="true" + android:layout_alignParentStart="true" + android:layout_marginStart="@dimen/fingerprint_margin" + android:layout_marginEnd="@dimen/fingerprint_margin"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@android:style/TextAppearance.Material.Subhead" + android:text="@string/password_description" + android:id="@+id/password_description" + android:textColor="?android:attr/textColorSecondary" /> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@android:style/TextAppearance.Material.Subhead" + android:text="@string/new_fingerprint_enrolled_description" + android:id="@+id/new_fingerprint_enrolled_description" + android:visibility="gone" + android:textColor="?android:attr/textColorSecondary" /> + </FrameLayout> + + <EditText + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:inputType="textPassword" + android:ems="10" + android:hint="@string/password" + android:imeOptions="actionGo" + android:id="@+id/password" + android:layout_below="@+id/description" + android:layout_marginTop="@dimen/fingerprint_margin_vertical" + android:layout_marginStart="@dimen/fingerprint_margin_horizontal" + android:layout_marginEnd="@dimen/fingerprint_margin_horizontal" + android:layout_alignParentStart="true" /> + + <CheckBox + android:id="@+id/use_fingerprint_in_future_check" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/password" + android:layout_alignParentStart="true" + android:layout_marginTop="@dimen/fingerprint_margin_vertical" + android:layout_marginStart="@dimen/fingerprint_margin_horizontal" + android:layout_marginEnd="@dimen/fingerprint_margin_horizontal" + android:checked="true" + android:visibility="gone" + android:text="@string/use_fingerprint_in_future" /> + +</RelativeLayout>
\ No newline at end of file diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/layout/fingerprint_dialog_container.xml b/security/FingerprintDialog/kotlinApp/app/src/main/res/layout/fingerprint_dialog_container.xml new file mode 100644 index 00000000..c5881ff8 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/layout/fingerprint_dialog_container.xml @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2017 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 + --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <FrameLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content"> + + <include layout="@layout/fingerprint_dialog_content" /> + + <include + layout="@layout/fingerprint_dialog_backup" + android:visibility="gone" /> + + </FrameLayout> + + <LinearLayout + android:id="@+id/buttonPanel" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:paddingStart="@dimen/fingerprint_padding_horizontal" + android:paddingEnd="@dimen/fingerprint_padding_horizontal" + android:paddingTop="@dimen/fingerprint_padding_vertical" + android:paddingBottom="@dimen/fingerprint_padding_vertical" + android:gravity="bottom" + style="?android:attr/buttonBarStyle"> + + <Space + android:id="@+id/spacer" + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_weight="1" + android:visibility="invisible" /> + <Button + android:id="@+id/cancel_button" + style="?android:attr/buttonBarNegativeButtonStyle" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + + <Button + android:id="@+id/second_dialog_button" + style="?android:attr/buttonBarPositiveButtonStyle" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + </LinearLayout> + +</LinearLayout>
\ No newline at end of file diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/layout/fingerprint_dialog_content.xml b/security/FingerprintDialog/kotlinApp/app/src/main/res/layout/fingerprint_dialog_content.xml new file mode 100644 index 00000000..c68a178d --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/layout/fingerprint_dialog_content.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2017 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 + --> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/fingerprint_container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingBottom="@dimen/default_padding_small" + android:paddingStart="@dimen/default_padding_large" + android:paddingEnd="@dimen/default_padding_large" + android:paddingTop="@dimen/default_padding"> + + <TextView + android:id="@+id/fingerprint_description" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentStart="true" + android:layout_alignParentTop="true" + android:text="@string/fingerprint_description" + android:textAppearance="@android:style/TextAppearance.Material.Subhead" + android:textColor="?android:attr/textColorSecondary"/> + + <ImageView + android:id="@+id/fingerprint_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentStart="true" + android:layout_below="@+id/fingerprint_description" + android:layout_marginTop="@dimen/fingerprint_margin_horizontal" + android:src="@drawable/ic_fp_40px" + android:contentDescription="@string/description_fingerprint_icon"/> + + <TextView + android:id="@+id/fingerprint_status" + style="@android:style/TextAppearance.Material.Body1" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignBottom="@+id/fingerprint_icon" + android:layout_alignTop="@+id/fingerprint_icon" + android:layout_marginStart="@dimen/default_margin" + android:layout_toEndOf="@+id/fingerprint_icon" + android:gravity="center_vertical" + android:text="@string/fingerprint_hint" + android:textColor="@color/hint_color" /> + +</RelativeLayout>
\ No newline at end of file diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/menu/menu_main.xml b/security/FingerprintDialog/kotlinApp/app/src/main/res/menu/menu_main.xml new file mode 100644 index 00000000..2adf23cb --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/menu/menu_main.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2017 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 + --> +<menu xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + tools:context=".MainActivity"> + <item + android:id="@+id/action_settings" + android:orderInCategory="100" + android:title="@string/action_settings" + app:showAsAction="never" /> +</menu> diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-hdpi/ic_launcher.png b/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..68c473a1 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-mdpi/ic_launcher.png b/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..fd7e5f6a --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..106c0d32 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..b319bebe --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..4dc0ddf5 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/values/colors.xml b/security/FingerprintDialog/kotlinApp/app/src/main/res/values/colors.xml new file mode 100644 index 00000000..403534ef --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/values/colors.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2017 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 + --> +<resources> + <color name="warning_color">#f4511e</color> + <color name="hint_color">#42000000</color> + <color name="success_color">#009688</color> + <color name="fingerprint_success">#009688</color> + <color name="finerprint_error">#F4511E</color> + <color name="fingerprint_fill">#FFFFFF</color> + <color name="card_solid">#fefefe</color> +</resources> diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/values/dimens.xml b/security/FingerprintDialog/kotlinApp/app/src/main/res/values/dimens.xml new file mode 100644 index 00000000..e2d290b1 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/values/dimens.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2017 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 + --> +<resources> + <dimen name="fingerprint_square_dimen">40dp</dimen> + <dimen name="fingerprint_square_dimen_viewport" type="float">40.0</dimen> + <dimen name="card_corner">2dp</dimen> + <dimen name="default_elevation">4dp</dimen> + <dimen name="logo_square_dimen">150dp</dimen> + <dimen name="logo_square_margin">32dp</dimen> + <dimen name="default_padding">16dp</dimen> + <dimen name="default_margin">16dp</dimen> + <dimen name="default_margin_end">4dp</dimen> + <dimen name="default_margin_small">8dp</dimen> + <dimen name="fingerprint_padding_horizontal">12dp</dimen> + <dimen name="fingerprint_padding_vertical">4dp</dimen> + <dimen name="fingerprint_margin">24dp</dimen> + <dimen name="default_padding_small">8dp</dimen> + <dimen name="fingerprint_margin_horizontal">20dp</dimen> + <dimen name="fingerprint_margin_vertical">16dp</dimen> + <dimen name="default_padding_large">24dp</dimen> +</resources>
\ No newline at end of file diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/values/strings.xml b/security/FingerprintDialog/kotlinApp/app/src/main/res/values/strings.xml new file mode 100644 index 00000000..09f0376e --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/values/strings.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2017 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 + --> +<resources> + <!-- + The similar strings app_name is added in the Application/template directory, but depending + on the template directory makes it hard for the sample buildable with Android.mk. + Thus defining the application_name with different name from the template. + --> + <string name="application_name">FingerprintDialog</string> + <string name="action_settings">Settings</string> + <string name="cancel">Cancel</string> + <string name="use_password">Use password</string> + <string name="sign_in">Sign in</string> + <string name="ok">OK</string> + <string name="password">Password</string> + <string name="fingerprint_description">Confirm fingerprint to continue</string> + <string name="fingerprint_hint">Touch sensor</string> + <string name="password_description">Enter your store password to continue</string> + <string name="purchase">Purchase</string> + <string name="purchase_not_invalidated">Purchase not invalidated</string> + <string name="purchase_button_not_invalidated_description"> + You can proceed to purchase with this button \n even if a new fingerprint is enrolled + </string> + <string name="fingerprint_not_recognized">Fingerprint not recognized. Try again</string> + <string name="fingerprint_success">Fingerprint recognized</string> + <string name="item_title">White Mesh Pluto Backpack</string> + <string name="item_price">$62.68</string> + <string name="item_description">Mesh backpack in white. Black textile trim throughout.</string> + <string name="purchase_done">Purchase successful</string> + <string name="new_fingerprint_enrolled_description"> + A new fingerprint was added to this device, so your password is required. + </string> + <string name="use_fingerprint_in_future">Use fingerprint in the future</string> + <string name="use_fingerprint_to_authenticate_title">Use fingerprint to authenticate</string> + <string name="use_fingerprint_to_authenticate_key" >use_fingerprint_to_authenticate_key</string> + <string name="description_bugdroid_icon">Android bugdroid image</string> + <string name="description_fingerprint_icon">Fingerprint icon</string> + <string name="register_fingerprint"> + Go to \'Settings -> Security -> Fingerprint\' and register at least one fingerprint + </string> + <string name="setup_lock_screen"> + Secure lock screen hasn\'t set been up.\n + Go to \'Settings -> Security -> Fingerprint\' to set up a fingerprint + </string> +</resources> diff --git a/security/FingerprintDialog/kotlinApp/app/src/main/res/xml/preferences.xml b/security/FingerprintDialog/kotlinApp/app/src/main/res/xml/preferences.xml new file mode 100644 index 00000000..c9fd74b7 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/app/src/main/res/xml/preferences.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2017 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 + --> +<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> + <CheckBoxPreference + android:key="@string/use_fingerprint_to_authenticate_key" + android:title="@string/use_fingerprint_to_authenticate_title" + android:persistent="true" + android:defaultValue="true" /> +</PreferenceScreen>
\ No newline at end of file diff --git a/security/FingerprintDialog/kotlinApp/build.gradle b/security/FingerprintDialog/kotlinApp/build.gradle new file mode 100644 index 00000000..624b2312 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/build.gradle @@ -0,0 +1,22 @@ +buildscript { + ext.kotlin_version = '1.1.51' + repositories { + google() + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:3.0.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +}
\ No newline at end of file diff --git a/security/FingerprintDialog/kotlinApp/gradle.properties b/security/FingerprintDialog/kotlinApp/gradle.properties new file mode 100644 index 00000000..89196d13 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/gradle.properties @@ -0,0 +1,18 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + diff --git a/security/FingerprintDialog/kotlinApp/gradle/wrapper/gradle-wrapper.jar b/security/FingerprintDialog/kotlinApp/gradle/wrapper/gradle-wrapper.jar Binary files differnew file mode 100644 index 00000000..8c0fb64a --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/gradle/wrapper/gradle-wrapper.jar diff --git a/security/FingerprintDialog/kotlinApp/gradle/wrapper/gradle-wrapper.properties b/security/FingerprintDialog/kotlinApp/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..152529a1 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Oct 16 16:01:34 PDT 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip diff --git a/security/FingerprintDialog/kotlinApp/gradlew b/security/FingerprintDialog/kotlinApp/gradlew new file mode 100755 index 00000000..91a7e269 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/security/FingerprintDialog/kotlinApp/gradlew.bat b/security/FingerprintDialog/kotlinApp/gradlew.bat new file mode 100644 index 00000000..8a0b282a --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/security/FingerprintDialog/kotlinApp/screenshots/1-purchase-screen.png b/security/FingerprintDialog/kotlinApp/screenshots/1-purchase-screen.png Binary files differnew file mode 100644 index 00000000..0bf03bd0 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/screenshots/1-purchase-screen.png diff --git a/security/FingerprintDialog/kotlinApp/screenshots/2-fingerprint-dialog.png b/security/FingerprintDialog/kotlinApp/screenshots/2-fingerprint-dialog.png Binary files differnew file mode 100644 index 00000000..5e681f96 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/screenshots/2-fingerprint-dialog.png diff --git a/security/FingerprintDialog/kotlinApp/screenshots/3-fingerprint-authenticated.png b/security/FingerprintDialog/kotlinApp/screenshots/3-fingerprint-authenticated.png Binary files differnew file mode 100644 index 00000000..d485b1dd --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/screenshots/3-fingerprint-authenticated.png diff --git a/security/FingerprintDialog/kotlinApp/screenshots/4-new-fingerprint-enrolled.png b/security/FingerprintDialog/kotlinApp/screenshots/4-new-fingerprint-enrolled.png Binary files differnew file mode 100644 index 00000000..7dcf0800 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/screenshots/4-new-fingerprint-enrolled.png diff --git a/security/FingerprintDialog/kotlinApp/screenshots/big-icon.png b/security/FingerprintDialog/kotlinApp/screenshots/big-icon.png Binary files differnew file mode 100644 index 00000000..9e323342 --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/screenshots/big-icon.png diff --git a/security/FingerprintDialog/kotlinApp/settings.gradle b/security/FingerprintDialog/kotlinApp/settings.gradle new file mode 100644 index 00000000..4c90568a --- /dev/null +++ b/security/FingerprintDialog/kotlinApp/settings.gradle @@ -0,0 +1 @@ +include 'app' |