Fixed
Status Update
Comments
ad...@google.com <ad...@google.com>
ad...@google.com <ad...@google.com> #2
Project: platform/frameworks/support
Branch: androidx-master-dev
commit c60f33e229e31ab328ef6b59dab63b264954831c
Author: Alexandre Elias <aelias@google.com>
Date: Fri Jul 10 16:23:09 2020
Semantics no-op cleanups
Partly in response to lmr's broad code review, I did a pass of
superficial API/implementation cleanup. The main changes are:
- I changed each Boolean SemanticsProperty where false is equivalent to
not being present to take "Unit" instead. This is conceptually
clearer: it avoids questions like "can I cancel out a semantics from a
merged child by setting it to false?" Because "property = Unit" looks
weird, I also changed the style of these to "property()".
- I moved the Semantics id generator closer to where it's used, in
SemanticsModifierCore. I made it internal and an AtomicInt.
(Note that integer ids are heavily used in the Android
AccessibilityNodeInfo APIs so I can't simply remove them entirely.)
- I deleted dead code. Some examples include SemanticsHintOverrides,
a public API not connected to anything, and SemanticsPropertyKey
merge() open method which is never called. (In both cases I have
a different plan in mind for accessibility.)
Fixes: 145951226
Fixes: 145955412
Test: existing tests
Relnote: "Single-value semantics properties now use a calling style.
For example, 'semantics { hidden = true }' is now written as:
'semantics { hidden() }'."
Change-Id: Ic1afd12ea22c926babc9662f1804d80b33aa0cfc
M ui/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/LayoutNodeModifierBenchmark.kt
M ui/ui-core/api/0.1.0-dev15.txt
M ui/ui-core/api/current.txt
M ui/ui-core/api/public_plus_experimental_0.1.0-dev15.txt
M ui/ui-core/api/public_plus_experimental_current.txt
M ui/ui-core/api/restricted_0.1.0-dev15.txt
M ui/ui-core/api/restricted_current.txt
M ui/ui-core/src/androidAndroidTest/kotlin/androidx/ui/graphics/vector/VectorTest.kt
M ui/ui-core/src/androidAndroidTest/kotlin/androidx/ui/semantics/SemanticsTests.kt
M ui/ui-core/src/androidMain/kotlin/androidx/ui/core/AndroidActuals.kt
M ui/ui-core/src/androidMain/kotlin/androidx/ui/core/AndroidComposeView.kt
M ui/ui-core/src/androidMain/kotlin/androidx/ui/core/AndroidComposeViewAccessibilityDelegateCompat.kt
M ui/ui-core/src/androidMain/kotlin/androidx/ui/core/AndroidPopup.kt
M ui/ui-core/src/commonMain/kotlin/androidx/ui/core/Expect.kt
M ui/ui-core/src/commonMain/kotlin/androidx/ui/core/semantics/SemanticsConfiguration.kt
D ui/ui-core/src/commonMain/kotlin/androidx/ui/core/semantics/SemanticsHintOverrides.kt
M ui/ui-core/src/commonMain/kotlin/androidx/ui/core/semantics/SemanticsModifier.kt
M ui/ui-core/src/commonMain/kotlin/androidx/ui/core/semantics/SemanticsNode.kt
M ui/ui-core/src/commonMain/kotlin/androidx/ui/core/semantics/SemanticsOwner.kt
M ui/ui-core/src/commonMain/kotlin/androidx/ui/core/semantics/SemanticsWrapper.kt
M ui/ui-core/src/commonMain/kotlin/androidx/ui/semantics/SemanticsProperties.kt
M ui/ui-foundation/api/0.1.0-dev15.txt
M ui/ui-foundation/api/current.txt
M ui/ui-foundation/api/public_plus_experimental_0.1.0-dev15.txt
M ui/ui-foundation/api/public_plus_experimental_current.txt
M ui/ui-foundation/api/restricted_0.1.0-dev15.txt
M ui/ui-foundation/api/restricted_current.txt
M ui/ui-foundation/src/main/java/androidx/ui/foundation/Clickable.kt
M ui/ui-foundation/src/main/java/androidx/ui/foundation/Dialog.kt
M ui/ui-foundation/src/main/java/androidx/ui/foundation/Scroller.kt
M ui/ui-foundation/src/main/java/androidx/ui/foundation/selection/Selectable.kt
M ui/ui-foundation/src/main/java/androidx/ui/foundation/selection/Toggleable.kt
M ui/ui-foundation/src/main/java/androidx/ui/foundation/semantics/FoundationSemanticsProperties.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/ButtonTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/CardTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/CheckboxScreenshotTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/RadioButtonScreenshotTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/ScaffoldTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/SnackbarTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/SurfaceTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/ripple/RippleIndicationTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/textfield/TextFieldScreenshotTest.kt
M ui/ui-material/src/main/java/androidx/ui/material/AppBar.kt
M ui/ui-material/src/main/java/androidx/ui/material/TextFieldImpl.kt
M ui/ui-test/src/androidTest/java/androidx/ui/test/AssertsTest.kt
M ui/ui-test/src/androidTest/java/androidx/ui/test/CallSemanticsActionTest.kt
M ui/ui-test/src/androidTest/java/androidx/ui/test/ErrorMessagesTest.kt
M ui/ui-test/src/androidTest/java/androidx/ui/test/FindersTest.kt
M ui/ui-test/src/androidTest/java/androidx/ui/test/PrintToStringTest.kt
M ui/ui-test/src/androidTest/java/androidx/ui/test/ScrollToTest.kt
M ui/ui-test/src/androidTest/java/androidx/ui/test/TextActionsTest.kt
M ui/ui-test/src/main/java/androidx/ui/test/Actions.kt
M ui/ui-test/src/main/java/androidx/ui/test/Filters.kt
M ui/ui-text/api/0.1.0-dev15.txt
M ui/ui-text/api/current.txt
M ui/ui-text/api/public_plus_experimental_0.1.0-dev15.txt
M ui/ui-text/api/public_plus_experimental_current.txt
M ui/ui-text/api/restricted_0.1.0-dev15.txt
M ui/ui-text/api/restricted_current.txt
M ui/ui-text/src/commonMain/kotlin/androidx/ui/text/CoreTextField.kt
M ui/ui-text/src/commonMain/kotlin/androidx/ui/text/TextSemanticsProperties.kt
https://android-review.googlesource.com/1360099
Branch: androidx-master-dev
commit c60f33e229e31ab328ef6b59dab63b264954831c
Author: Alexandre Elias <aelias@google.com>
Date: Fri Jul 10 16:23:09 2020
Semantics no-op cleanups
Partly in response to lmr's broad code review, I did a pass of
superficial API/implementation cleanup. The main changes are:
- I changed each Boolean SemanticsProperty where false is equivalent to
not being present to take "Unit" instead. This is conceptually
clearer: it avoids questions like "can I cancel out a semantics from a
merged child by setting it to false?" Because "property = Unit" looks
weird, I also changed the style of these to "property()".
- I moved the Semantics id generator closer to where it's used, in
SemanticsModifierCore. I made it internal and an AtomicInt.
(Note that integer ids are heavily used in the Android
AccessibilityNodeInfo APIs so I can't simply remove them entirely.)
- I deleted dead code. Some examples include SemanticsHintOverrides,
a public API not connected to anything, and SemanticsPropertyKey
merge() open method which is never called. (In both cases I have
a different plan in mind for accessibility.)
Fixes: 145951226
Fixes: 145955412
Test: existing tests
Relnote: "Single-value semantics properties now use a calling style.
For example, 'semantics { hidden = true }' is now written as:
'semantics { hidden() }'."
Change-Id: Ic1afd12ea22c926babc9662f1804d80b33aa0cfc
M ui/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/LayoutNodeModifierBenchmark.kt
M ui/ui-core/api/0.1.0-dev15.txt
M ui/ui-core/api/current.txt
M ui/ui-core/api/public_plus_experimental_0.1.0-dev15.txt
M ui/ui-core/api/public_plus_experimental_current.txt
M ui/ui-core/api/restricted_0.1.0-dev15.txt
M ui/ui-core/api/restricted_current.txt
M ui/ui-core/src/androidAndroidTest/kotlin/androidx/ui/graphics/vector/VectorTest.kt
M ui/ui-core/src/androidAndroidTest/kotlin/androidx/ui/semantics/SemanticsTests.kt
M ui/ui-core/src/androidMain/kotlin/androidx/ui/core/AndroidActuals.kt
M ui/ui-core/src/androidMain/kotlin/androidx/ui/core/AndroidComposeView.kt
M ui/ui-core/src/androidMain/kotlin/androidx/ui/core/AndroidComposeViewAccessibilityDelegateCompat.kt
M ui/ui-core/src/androidMain/kotlin/androidx/ui/core/AndroidPopup.kt
M ui/ui-core/src/commonMain/kotlin/androidx/ui/core/Expect.kt
M ui/ui-core/src/commonMain/kotlin/androidx/ui/core/semantics/SemanticsConfiguration.kt
D ui/ui-core/src/commonMain/kotlin/androidx/ui/core/semantics/SemanticsHintOverrides.kt
M ui/ui-core/src/commonMain/kotlin/androidx/ui/core/semantics/SemanticsModifier.kt
M ui/ui-core/src/commonMain/kotlin/androidx/ui/core/semantics/SemanticsNode.kt
M ui/ui-core/src/commonMain/kotlin/androidx/ui/core/semantics/SemanticsOwner.kt
M ui/ui-core/src/commonMain/kotlin/androidx/ui/core/semantics/SemanticsWrapper.kt
M ui/ui-core/src/commonMain/kotlin/androidx/ui/semantics/SemanticsProperties.kt
M ui/ui-foundation/api/0.1.0-dev15.txt
M ui/ui-foundation/api/current.txt
M ui/ui-foundation/api/public_plus_experimental_0.1.0-dev15.txt
M ui/ui-foundation/api/public_plus_experimental_current.txt
M ui/ui-foundation/api/restricted_0.1.0-dev15.txt
M ui/ui-foundation/api/restricted_current.txt
M ui/ui-foundation/src/main/java/androidx/ui/foundation/Clickable.kt
M ui/ui-foundation/src/main/java/androidx/ui/foundation/Dialog.kt
M ui/ui-foundation/src/main/java/androidx/ui/foundation/Scroller.kt
M ui/ui-foundation/src/main/java/androidx/ui/foundation/selection/Selectable.kt
M ui/ui-foundation/src/main/java/androidx/ui/foundation/selection/Toggleable.kt
M ui/ui-foundation/src/main/java/androidx/ui/foundation/semantics/FoundationSemanticsProperties.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/ButtonTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/CardTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/CheckboxScreenshotTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/RadioButtonScreenshotTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/ScaffoldTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/SnackbarTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/SurfaceTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/ripple/RippleIndicationTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/textfield/TextFieldScreenshotTest.kt
M ui/ui-material/src/main/java/androidx/ui/material/AppBar.kt
M ui/ui-material/src/main/java/androidx/ui/material/TextFieldImpl.kt
M ui/ui-test/src/androidTest/java/androidx/ui/test/AssertsTest.kt
M ui/ui-test/src/androidTest/java/androidx/ui/test/CallSemanticsActionTest.kt
M ui/ui-test/src/androidTest/java/androidx/ui/test/ErrorMessagesTest.kt
M ui/ui-test/src/androidTest/java/androidx/ui/test/FindersTest.kt
M ui/ui-test/src/androidTest/java/androidx/ui/test/PrintToStringTest.kt
M ui/ui-test/src/androidTest/java/androidx/ui/test/ScrollToTest.kt
M ui/ui-test/src/androidTest/java/androidx/ui/test/TextActionsTest.kt
M ui/ui-test/src/main/java/androidx/ui/test/Actions.kt
M ui/ui-test/src/main/java/androidx/ui/test/Filters.kt
M ui/ui-text/api/0.1.0-dev15.txt
M ui/ui-text/api/current.txt
M ui/ui-text/api/public_plus_experimental_0.1.0-dev15.txt
M ui/ui-text/api/public_plus_experimental_current.txt
M ui/ui-text/api/restricted_0.1.0-dev15.txt
M ui/ui-text/api/restricted_current.txt
M ui/ui-text/src/commonMain/kotlin/androidx/ui/text/CoreTextField.kt
M ui/ui-text/src/commonMain/kotlin/androidx/ui/text/TextSemanticsProperties.kt
xe...@gmail.com <xe...@gmail.com> #3
ok, I did some more research, turns out that callback notification goes to the if we press "cancel" button but goes wrong when authentication succeeds
as you can see in the attached project
if you open the bio-prompt in the 1st Fragment and authenticate
and after that you go to the 2nd Fragment and authenticate in the bio-prompt
callback notifies the Fragment1 instead of the Fragment2 as you can see in the logs
expected result is that Fragment2 is notified instead of Fragment1
also if you first go to Fragment2 and after that you go to Fragment1 always opening the prompt and doing the authentication
Fragment2 is notified instead of Fragment1
funny thing is that doing cancel instead of authentication notification works ok
https://drive.google.com/open?id=1ZVhp9sFBJ6pa1bKzHg1AM5tF5XnmyFMM
as you can see in the attached project
if you open the bio-prompt in the 1st Fragment and authenticate
and after that you go to the 2nd Fragment and authenticate in the bio-prompt
callback notifies the Fragment1 instead of the Fragment2 as you can see in the logs
expected result is that Fragment2 is notified instead of Fragment1
also if you first go to Fragment2 and after that you go to Fragment1 always opening the prompt and doing the authentication
Fragment2 is notified instead of Fragment1
funny thing is that doing cancel instead of authentication notification works ok
xe...@gmail.com <xe...@gmail.com> #4
manually closing the FingerprintHelperFragment works as a workaround
```
override fun onPause() {
// WORKAROUND forhttps://issuetracker.google.com/issues/123857949
activity?.let { activity ->
activity.supportFragmentManager.findFragmentByTag("FingerprintHelperFragment")?.let {
activity.supportFragmentManager.beginTransaction().remove(it).commitAllowingStateLoss()
}
super.onPause()
}
}
```
```
override fun onPause() {
// WORKAROUND for
activity?.let { activity ->
activity.supportFragmentManager.findFragmentByTag("FingerprintHelperFragment")?.let {
activity.supportFragmentManager.beginTransaction().remove(it).commitAllowingStateLoss()
}
super.onPause()
}
}
```
ad...@google.com <ad...@google.com> #5
kc...@google.com <kc...@google.com> #6
There's might be something slightly different in the way lifecycle is being managed between O and lower, and P+
Looking at how mAuthenticationCallback is being passed around here should give us some ideas
https://cs.corp.google.com/aosp-androidx/biometric/src/main/java/androidx/biometric/BiometricPrompt.java?q=biometricprompt.java&dr
Josh can you take a look when convenient? I think the callback isn't getting to the FingerprintHelperFragment for some reason. We can also chat offline when you get to this.
Looking at how mAuthenticationCallback is being passed around here should give us some ideas
Josh can you take a look when convenient? I think the callback isn't getting to the FingerprintHelperFragment for some reason. We can also chat offline when you get to this.
ch...@gmail.com <ch...@gmail.com> #7
This bug is actually a duplicate of https://issuetracker.google.com/issues/121117380 . This issue happens because the new AuthenticationCallback is not being supplied to the biometric prompt fragments if they already exist in the FragmentManager.
Until this is fixed, users of this library MUST manually check for and remove any biometric prompt fragments from the FragmentManager before attempting to call BiometricPrompt#authenticate().
Until this is fixed, users of this library MUST manually check for and remove any biometric prompt fragments from the FragmentManager before attempting to call BiometricPrompt#authenticate().
ma...@zentity.com <ma...@zentity.com> #8
#7
I think that:
1. BiometricPrompt#authenticateInternal should call mFingerprintHelperFragment.setCallback method even if mFingerprintHelperFragment was existed before.
2. FingerprintHelperFragment#cleanup has to set mClientAuthenticationCallback and mExecutor to null to prevent leaking.
I think that:
1. BiometricPrompt#authenticateInternal should call mFingerprintHelperFragment.setCallback method even if mFingerprintHelperFragment was existed before.
2. FingerprintHelperFragment#cleanup has to set mClientAuthenticationCallback and mExecutor to null to prevent leaking.
ma...@zentity.com <ma...@zentity.com> #9
My mistake in point one:
1. Biometric#mLifecycleObserver#onResume should call mFingerprintHelperFragment.setCallback(...) even if mFingerprintDialogFragment is null.
Here is my temporary fix. Just place it in androidx.biometric package and use it like BiometricPrompt:
package androidx.biometric
import android.annotation.SuppressLint
import androidx.fragment.app.FragmentActivity
import java.util.concurrent.Executor
/**
* Fix for isssuehttps://issuetracker.google.com/issues/123857949
*/
@SuppressLint("RestrictedApi")
class FixedBiometricPrompt(
private val fragmentActivity: FragmentActivity,
executor: Executor,
callback: BiometricPrompt.AuthenticationCallback
) {
private val delegate: BiometricPrompt
init {
// set executor and callback to helper fragment
(fragmentActivity.supportFragmentManager.findFragmentByTag("FingerprintHelperFragment") as? FingerprintHelperFragment)?.setCallback(
executor,
callback
)
delegate = BiometricPrompt(fragmentActivity, executor, callback)
}
fun authenticate(info: BiometricPrompt.PromptInfo, crypto: BiometricPrompt.CryptoObject) {
delegate.authenticate(info, crypto)
}
fun authenticate(info: BiometricPrompt.PromptInfo) {
delegate.authenticate(info)
}
fun cancelAuthentication() {
delegate.cancelAuthentication()
}
fun cleanup() {
// remove executor and callback from helper fragment to prevent memory leak
(fragmentActivity.supportFragmentManager.findFragmentByTag("FingerprintHelperFragment") as? FingerprintHelperFragment)?.setCallback(
null,
null
)
}
}
1. Biometric#mLifecycleObserver#onResume should call mFingerprintHelperFragment.setCallback(...) even if mFingerprintDialogFragment is null.
Here is my temporary fix. Just place it in androidx.biometric package and use it like BiometricPrompt:
package androidx.biometric
import android.annotation.SuppressLint
import androidx.fragment.app.FragmentActivity
import java.util.concurrent.Executor
/**
* Fix for isssue
*/
@SuppressLint("RestrictedApi")
class FixedBiometricPrompt(
private val fragmentActivity: FragmentActivity,
executor: Executor,
callback: BiometricPrompt.AuthenticationCallback
) {
private val delegate: BiometricPrompt
init {
// set executor and callback to helper fragment
(fragmentActivity.supportFragmentManager.findFragmentByTag("FingerprintHelperFragment") as? FingerprintHelperFragment)?.setCallback(
executor,
callback
)
delegate = BiometricPrompt(fragmentActivity, executor, callback)
}
fun authenticate(info: BiometricPrompt.PromptInfo, crypto: BiometricPrompt.CryptoObject) {
delegate.authenticate(info, crypto)
}
fun authenticate(info: BiometricPrompt.PromptInfo) {
delegate.authenticate(info)
}
fun cancelAuthentication() {
delegate.cancelAuthentication()
}
fun cleanup() {
// remove executor and callback from helper fragment to prevent memory leak
(fragmentActivity.supportFragmentManager.findFragmentByTag("FingerprintHelperFragment") as? FingerprintHelperFragment)?.setCallback(
null,
null
)
}
}
ma...@zentity.com <ma...@zentity.com> #10
...
Then call function cleanup() in onDestroyView...
override fun onDestroyView() {
super.onDestroyView()
biometricPrompt.cleanup()
}
Then call function cleanup() in onDestroyView...
override fun onDestroyView() {
super.onDestroyView()
biometricPrompt.cleanup()
}
sb...@doximity.com <sb...@doximity.com> #11
the proper fix (on google's side) is pretty simple
on line 498
if (mFingerprintHelperFragment == null) {
mFingerprintHelperFragment = FingerprintHelperFragment.newInstance();
mFingerprintHelperFragment.setCallback(mExecutor, mAuthenticationCallback); // <-- this line should be moved out side the if statement
}
on line 498
if (mFingerprintHelperFragment == null) {
mFingerprintHelperFragment = FingerprintHelperFragment.newInstance();
mFingerprintHelperFragment.setCallback(mExecutor, mAuthenticationCallback); // <-- this line should be moved out side the if statement
}
kc...@google.com <kc...@google.com> #12
Hmm we already fixed this. Just need to cut a new build for alpha04 now.
The bug was referenced in this CL but somehow buganizer didn't close it
https://android-review.googlesource.com/c/platform/frameworks/support/+/917882/
The bug was referenced in this CL but somehow buganizer didn't close it
Description
Version used: 1.0.0-alpha03
Devices/Android versions reproduced on: Emulator API 24
if used in more than one Fragment inside the same activity, BiometricPrompt only listens for callbacks in the first BiometricPrompt.AuthenticationCallback provided
no matter if you create a new instance of the prompt in another fragment
This only happens in API level below P
In P works fine,
I tested in 24 and P