Skip to content

Commit f9c8725

Browse files
committed
Backports BackStackContainer view persistence fix
The fix in #730 should have been made on main.
1 parent 70cc79b commit f9c8725

File tree

3 files changed

+64
-8
lines changed

3 files changed

+64
-8
lines changed

samples/containers/android/src/androidTest/java/com/squareup/sample/container/overviewdetail/BackStackContainerTest.kt

+58-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
package com.squareup.sample.container.overviewdetail
22

33
import android.content.Context
4+
import android.os.Parcel
5+
import android.os.Parcelable
6+
import android.text.Editable
7+
import android.util.SparseArray
48
import android.view.View
9+
import android.widget.EditText
510
import androidx.activity.ComponentActivity
611
import androidx.test.ext.junit.rules.ActivityScenarioRule
712
import com.google.common.truth.Truth.assertThat
@@ -28,10 +33,58 @@ internal class BackStackContainerTest {
2833
override val compatibilityKey = name
2934
override val viewFactory: ViewFactory<Rendering>
3035
get() = BuilderViewFactory(Rendering::class) { r, e, ctx, _ ->
31-
View(ctx).also { it.bindShowRendering(r, e) { _, _ -> /* Noop */ } }
36+
EditText(ctx).apply {
37+
// Must have an id to participate in view persistence.
38+
id = 65
39+
bindShowRendering(r, e) { _, _ -> /* Noop */ } }
3240
}
3341
}
3442

43+
@Test fun savedStateParcelingWorks() {
44+
scenario.onActivity { activity ->
45+
val originalView = VisibleBackStackContainer(activity).apply {
46+
// Must have an id to participate in view persistence.
47+
id = 42
48+
}
49+
50+
// Show "able".
51+
originalView.show(BackStackScreen(Rendering("able")))
52+
// Type "first" into the rendered EditText.
53+
(originalView.getChildAt(0) as EditText).text = "first".toEditable()
54+
// Push "baker" on top of "able".
55+
originalView.show(BackStackScreen(Rendering("able"), Rendering("baker")))
56+
// Type "second" into the replacement rendered EditText.
57+
(originalView.getChildAt(0) as EditText).text = "second".toEditable()
58+
59+
// Save the view state to a ByteArray and read it out again, exercising all of
60+
// the Parcel machinery.
61+
val savedArray = SparseArray<Parcelable>()
62+
originalView.saveHierarchyState(savedArray)
63+
val bytes = Parcel.obtain().let { parcel ->
64+
parcel.writeSparseArray(savedArray)
65+
parcel.marshall().also { parcel.recycle() }
66+
}
67+
val restoredArray = Parcel.obtain().let { parcel ->
68+
parcel.unmarshall(bytes, 0, bytes.size)
69+
parcel.setDataPosition(0)
70+
parcel.readSparseArray<Parcelable>(this::class.java.classLoader)!!.also { parcel.recycle() }
71+
}
72+
73+
// Create a new BackStackContainer with the same id as the original
74+
val restoredView = VisibleBackStackContainer(activity).apply { id = 42 }
75+
// Have it render the same able > baker back stack that we last showed in the original.
76+
restoredView.show(BackStackScreen(Rendering("able"), Rendering("baker")))
77+
// Restore the view hierarchy.
78+
restoredView.restoreHierarchyState(restoredArray)
79+
// Android took care of restoring the text that was last shown.
80+
assertThat((restoredView.getChildAt(0) as EditText).text.toString()).isEqualTo("second")
81+
// Pop back to able.
82+
restoredView.show(BackStackScreen(Rendering("able")))
83+
// BackStackContainer restored the text we had typed on that.
84+
assertThat((restoredView.getChildAt(0) as EditText).text.toString()).isEqualTo("first")
85+
}
86+
}
87+
3588
@Test fun firstScreenIsRendered() {
3689
scenario.onActivity { activity ->
3790
val c = VisibleBackStackContainer(activity)
@@ -100,3 +153,7 @@ internal class BackStackContainerTest {
100153
}
101154
}
102155
}
156+
157+
private fun String.toEditable(): Editable {
158+
return Editable.Factory.getInstance().newEditable(this)
159+
}

workflow-ui/container-android/api/container-android.api

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ public final class com/squareup/workflow1/ui/backstack/BackStackContainer$SavedS
4242
}
4343

4444
public final class com/squareup/workflow1/ui/backstack/BackStackContainer$SavedState$CREATOR : android/os/Parcelable$Creator {
45-
public fun createFromParcel (Landroid/os/Parcel;)Lcom/squareup/workflow1/ui/backstack/ViewStateCache$Saved;
45+
public fun createFromParcel (Landroid/os/Parcel;)Lcom/squareup/workflow1/ui/backstack/BackStackContainer$SavedState;
4646
public synthetic fun createFromParcel (Landroid/os/Parcel;)Ljava/lang/Object;
47-
public fun newArray (I)[Lcom/squareup/workflow1/ui/backstack/ViewStateCache$Saved;
47+
public fun newArray (I)[Lcom/squareup/workflow1/ui/backstack/BackStackContainer$SavedState;
4848
public synthetic fun newArray (I)[Ljava/lang/Object;
4949
}
5050

workflow-ui/container-android/src/main/java/com/squareup/workflow1/ui/backstack/BackStackContainer.kt

+4-5
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ public open class BackStackContainer @JvmOverloads constructor(
187187
}
188188

189189
public constructor(source: Parcel) : super(source) {
190-
this.savedViewState = source.readParcelable(ViewStateCache.Saved::class.java.classLoader)!!
190+
savedViewState = source.readParcelable(ViewStateCache.Saved::class.java.classLoader)!!
191191
}
192192

193193
public val savedViewState: ViewStateCache.Saved
@@ -200,11 +200,10 @@ public open class BackStackContainer @JvmOverloads constructor(
200200
out.writeParcelable(savedViewState, flags)
201201
}
202202

203-
public companion object CREATOR : Creator<ViewStateCache.Saved> {
204-
override fun createFromParcel(source: Parcel): ViewStateCache.Saved =
205-
ViewStateCache.Saved(source)
203+
public companion object CREATOR : Creator<SavedState> {
204+
override fun createFromParcel(source: Parcel): SavedState = SavedState(source)
206205

207-
override fun newArray(size: Int): Array<ViewStateCache.Saved?> = arrayOfNulls(size)
206+
override fun newArray(size: Int): Array<SavedState?> = arrayOfNulls(size)
208207
}
209208
}
210209

0 commit comments

Comments
 (0)