Status Update
Comments
jb...@google.com <jb...@google.com>
il...@google.com <il...@google.com> #2
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
ed...@gmail.com <ed...@gmail.com> #3
il...@google.com <il...@google.com> #4
We'll fix this on our side and you'll be able to use savedStateHandle.toRoute<BookDetail>(mapOf(typeOf<Book> to bookType))
to properly extract your Book from the SavedStateHandle
.
cl...@google.com <cl...@google.com>
ap...@google.com <ap...@google.com> #5
Branch: androidx-main
commit 757c9fb13fa75779086fa3ac2f440d2f5dd5bc96
Author: Clara Fok <clarafok@google.com>
Date: Tue May 07 11:49:14 2024
Fix SavedStateHandle.toRoute
SavedStateHandle arguments are taken directly from a bundle, which is formatted by NavType#put. When we decode the arguments, we need to read it with NavType#get.
Test: ./gradlew navigation:navigation-common:cC
Test: ./gradlew navigation:navigation-compose:cC
Bug: 339026523
Relnote: "SavedStateHandle.toRoute() now takes in a typeMap parameter for custom argument types"
Change-Id: Ie39fb2afad346928a34bc309513fa17f16cefa8c
M navigation/navigation-common/api/2.8.0-beta01.txt
M navigation/navigation-common/api/current.txt
M navigation/navigation-common/api/restricted_2.8.0-beta01.txt
M navigation/navigation-common/api/restricted_current.txt
M navigation/navigation-common/src/androidTest/java/androidx/navigation/serialization/RouteDecoderTest.kt
M navigation/navigation-common/src/main/java/androidx/navigation/SavedStateHandle.kt
M navigation/navigation-common/src/main/java/androidx/navigation/serialization/RouteDecoder.kt
M navigation/navigation-common/src/main/java/androidx/navigation/serialization/RouteDeserializer.kt
M navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostControllerTest.kt
cl...@google.com <cl...@google.com> #6
Fixed internally and will be available in navigation 2.8.0-beta01
ed...@gmail.com <ed...@gmail.com> #7
pr...@google.com <pr...@google.com> #8
The following release(s) address this bug.It is possible this bug has only been partially addressed:
androidx.navigation:navigation-common:2.8.0-beta01
androidx.navigation:navigation-compose:2.8.0-beta01
je...@gmail.com <je...@gmail.com> #9
This seems to be still be busted (same error) if you change isNullableAllowed = true (I don't have any errors when changing the same code to isNullableAllowed = false AND <IndividualId>)
Example:
Custom Class
@JvmInline
@Serializable
value class IndividualId(val value: String)
NavType for nullable:
val IndividualIdNullableNavType = object : NavType<IndividualId?>(
isNullableAllowed = true
) {
override fun get(bundle: Bundle, key: String): IndividualId? = bundle.getString(key)?.let { IndividualId(it) }
override fun put(bundle: Bundle, key: String, value: IndividualId?) {
value?.let { bundle.putString(key, it.value) }
}
override fun parseValue(value: String): IndividualId? {
if (value == "null") return null
return Json.decodeFromString<IndividualId>(value)
}
override fun serializeAsValue(value: IndividualId?): String = value?.let { Json.encodeToString(IndividualId.serializer(), it) } ?: ""
}
NavHost code:
composable<IndividualEditRoute>(mapOf(
typeOf<IndividualId?>() to IndividualIdNullableNavType,
)) { backStackEntry ->
Log.w("TEST", "Before") // prints
val individualEditRoute = backStackEntry.toRoute<IndividualEditRoute>()
Log.w("TEST", "After: individualEditRoute == $individualEditRoute") // never gets here because: ClassCastException: IndividualId cannot be cast to java.lang.String
IndividualEditScreen(navController)
}
The following works (no error):
onClick = {
navController.navigate(IndividualEditRoute())
},
The following will cause a "ClassCastException: IndividualId cannot be cast to java.lang.String"
onClick = {
navController.navigate(IndividualEditRoute(IndividualId("123")))
},
cl...@google.com <cl...@google.com> #11
Re
ga...@gmail.com <ga...@gmail.com> #12
I'm also having this issue. I have created a repo for showcasing this:
In there you will find another case with a Parcelable object. In my case is quite strange since the logcat shows this error:
Process: com.bobbyesp.navigationbugreport, PID: 23169
kotlinx.serialization.SerializationException: Serializer for class 'Companion' is not found.
Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied.
at kotlinx.serialization.internal.Platform_commonKt.serializerNotRegistered(Platform.common.kt:91)
at kotlinx.serialization.SerializersKt__SerializersKt.serializer(Serializers.kt:278)
at kotlinx.serialization.SerializersKt.serializer(Unknown Source:1)
at androidx.navigation.NavGraph.setStartDestination(NavGraph.kt:404)
cl...@google.com <cl...@google.com> #13
Re
But based on your source code, it is your startDestination in song
arg for your SongInformationPage
.
With safe args, you can conveniently pass in starting arguments by passing in a class instance. The arguments will automatically be available within the starting composable.
This means your nested graph should be
navigation<UtilitiesNavigator>(
startDestination = SongInformationPage(song = ...),
)
If your startDestination does not contain arguments, then you can pass in either:
@Serializable
object MyDestination
startDestination = MyDestination
--- OR ---
@Serializable
class MyDestination
startDestination = MyDestination::class
If you have further questions, please file a separate bug so it is easier for other users with the same question to locate the answer.
ga...@gmail.com <ga...@gmail.com> #14
du...@matechmobile.com <du...@matechmobile.com> #15
here is my code for you guys to look around:
fun setNavController(mNavController: NavController) {
this.navController = mNavController
navController.graph = navController.createGraph(startDestination = nav_routes.manual_add_otp_data) {
fragment<AddOtpManualFragment, AddOtpData>(
typeMap = mapOf(typeOf<AddOtpData>() to getCustomParametersType<AddOtpData>())
) {
label = nav_routes.manual_add_otp_data
}
}
}
--------
private inline fun <reified T : Parcelable> getCustomParametersType(nullable: Boolean = false) =
object : NavType<T>(
isNullableAllowed = nullable
) {
override fun put(bundle: Bundle, key: String, value: T) {
// Handle null case if the type is nullable
bundle.putParcelable(key, value)
}
override fun get(bundle: Bundle, key: String): T? {
// Return null if the value is nullable and not present
return if (isNullableAllowed) {
bundle.getParcelable(key)
} else {
bundle.getParcelable(key)
?: throw IllegalArgumentException("No value present for non-nullable type")
}
}
override fun parseValue(value: String): T {
// Decode and deserialize the string into the object
return Json.decodeFromString(value)
}
override fun serializeAsValue(value: T): String {
// Encode the object into a JSON string and Uri encode it
return Uri.encode(Json.encodeToString(value))
}
}
---------
@Serializable
@Parcelize
data class AddOtpData(val otpAuthDB: OtpAuthDB) : Parcelable
that all, thanks
Description
Version used: 2.8.0-alpha08
Devices/Android versions reproduced on: Pixel 6a (Android 14)
Getting the custom arg in a ViewModel when using just serializables instead of parcelables with this NavType:
val bookType = object : NavType<Book>(isNullableAllowed = false) {
override fun get(bundle: Bundle, key: String): Book? {
return bundle.getString(key)?.let { Json.decodeFromString<Book>(it) }
}
override fun parseValue(value: String) = Json.decodeFromString<Book>(value)
override fun serializeAsValue(value: Book): String = Json.encodeToString(value)
override fun put(bundle: Bundle, key: String, value: Book) {
bundle.putString(key, Json.encodeToString(value))
}
}
It works well if I get the value from the NavBackStackEntry but if I do this in the ViewModel:
val bookDetail = savedStateHandle.toRoute<BookDetail>()
I get this error when navigating to the detail:
java.lang.ClassCastException: java.lang.String cannot be cast to com.example.composenavigation.typesafety.Book
You can see an example in:
The navigation is in the file: TypeSafetyNavigation.kt
Thanks in advance!