Skip to content

Commit

Permalink
Backports BackStackContainer view persistence fix
Browse files Browse the repository at this point in the history
The fix in #730 should have been made on main.
  • Loading branch information
rjrjr committed Apr 22, 2022
1 parent 59c8ef1 commit 155ad6e
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 11 deletions.
4 changes: 2 additions & 2 deletions workflow-ui/container-android/api/container-android.api
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ public final class com/squareup/workflow1/ui/backstack/BackStackContainer$SavedS
}

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
xmlns:android="http://schemas.android.com/apk/res/android">

<application>
<activity android:name="androidx.activity.ComponentActivity"/>
<activity
android:name="com.squareup.workflow1.ui.modal.test.ModalViewContainerLifecycleActivity"
android:theme="@style/Theme.AppCompat.NoActionBar"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ import org.junit.rules.RuleChain

/**
* Uses a custom subclass, [NoTransitionBackStackContainer], to ensure transitions
* are synchronus.
* are synchronous.
*/
@OptIn(WorkflowUiExperimentalApi::class)
internal class BackStackContainerPersistenceTest {
internal class BackStackContainerPersistenceLifecycleTest {

private val scenarioRule =
ActivityScenarioRule(BackStackContainerLifecycleActivity::class.java)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package com.squareup.sample.container.overviewdetail
package com.squareup.workflow1.ui.backstack.test

import android.content.Context
import android.os.Parcel
import android.os.Parcelable
import android.text.Editable
import android.util.SparseArray
import android.view.View
import android.widget.EditText
import androidx.activity.ComponentActivity
import androidx.test.ext.junit.rules.ActivityScenarioRule
import com.google.common.truth.Truth.assertThat
Expand All @@ -28,10 +33,59 @@ internal class BackStackContainerTest {
override val compatibilityKey = name
override val viewFactory: ViewFactory<Rendering>
get() = BuilderViewFactory(Rendering::class) { r, e, ctx, _ ->
View(ctx).also { it.bindShowRendering(r, e) { _, _ -> /* Noop */ } }
EditText(ctx).apply {
// Must have an id to participate in view persistence.
id = 65
bindShowRendering(r, e) { _, _ -> /* Noop */ }
}
}
}

@Test fun savedStateParcelingWorks() {
scenario.onActivity { activity ->
val originalView = VisibleBackStackContainer(activity).apply {
// Must have an id to participate in view persistence.
id = 42
}

// Show "able".
originalView.show(BackStackScreen(Rendering("able")))
// Type "first" into the rendered EditText.
(originalView.getChildAt(0) as EditText).text = "first".toEditable()
// Push "baker" on top of "able".
originalView.show(BackStackScreen(Rendering("able"), Rendering("baker")))
// Type "second" into the replacement rendered EditText.
(originalView.getChildAt(0) as EditText).text = "second".toEditable()

// Save the view state to a ByteArray and read it out again, exercising all of
// the Parcel machinery.
val savedArray = SparseArray<Parcelable>()
originalView.saveHierarchyState(savedArray)
val bytes = Parcel.obtain().let { parcel ->
parcel.writeSparseArray(savedArray)
parcel.marshall().also { parcel.recycle() }
}
val restoredArray = Parcel.obtain().let { parcel ->
parcel.unmarshall(bytes, 0, bytes.size)
parcel.setDataPosition(0)
parcel.readSparseArray<Parcelable>(this::class.java.classLoader)!!.also { parcel.recycle() }
}

// Create a new BackStackContainer with the same id as the original
val restoredView = VisibleBackStackContainer(activity).apply { id = 42 }
// Have it render the same able > baker back stack that we last showed in the original.
restoredView.show(BackStackScreen(Rendering("able"), Rendering("baker")))
// Restore the view hierarchy.
restoredView.restoreHierarchyState(restoredArray)
// Android took care of restoring the text that was last shown.
assertThat((restoredView.getChildAt(0) as EditText).text.toString()).isEqualTo("second")
// Pop back to able.
restoredView.show(BackStackScreen(Rendering("able")))
// BackStackContainer restored the text we had typed on that.
assertThat((restoredView.getChildAt(0) as EditText).text.toString()).isEqualTo("first")
}
}

@Test fun firstScreenIsRendered() {
scenario.onActivity { activity ->
val c = VisibleBackStackContainer(activity)
Expand Down Expand Up @@ -100,3 +154,7 @@ internal class BackStackContainerTest {
}
}
}

private fun String.toEditable(): Editable {
return Editable.Factory.getInstance().newEditable(this)
}
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ public open class BackStackContainer @JvmOverloads constructor(
}

public constructor(source: Parcel) : super(source) {
this.savedViewState = source.readParcelable(ViewStateCache.Saved::class.java.classLoader)!!
savedViewState = source.readParcelable(ViewStateCache.Saved::class.java.classLoader)!!
}

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

public companion object CREATOR : Creator<ViewStateCache.Saved> {
override fun createFromParcel(source: Parcel): ViewStateCache.Saved =
ViewStateCache.Saved(source)
public companion object CREATOR : Creator<SavedState> {
override fun createFromParcel(source: Parcel): SavedState = SavedState(source)

override fun newArray(size: Int): Array<ViewStateCache.Saved?> = arrayOfNulls(size)
override fun newArray(size: Int): Array<SavedState?> = arrayOfNulls(size)
}
}

Expand Down

0 comments on commit 155ad6e

Please sign in to comment.