Merge "Fix: SlidingPaneLayout crash on certain devices" into androidx-main
diff --git a/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/SlidingPaneLayoutTest.kt b/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/SlidingPaneLayoutTest.kt
index 6093130..0d192d9 100644
--- a/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/SlidingPaneLayoutTest.kt
+++ b/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/SlidingPaneLayoutTest.kt
@@ -16,6 +16,7 @@
package androidx.slidingpanelayout.widget
+import android.content.Context
import android.graphics.Canvas
import android.graphics.ColorFilter
import android.graphics.PixelFormat
@@ -292,6 +293,45 @@
val view = inflater.inflate(R.layout.pane_spacing, null) as SlidingPaneLayout
assertWithMessage("paneSpacing is inflated").that(view.paneSpacing).isEqualTo(24)
}
+
+ @Test
+ fun testGenerateLayoutParams_fromViewGroupLayoutParams() {
+ val context = InstrumentationRegistry.getInstrumentation().context
+ val spl = TestSlidingPaneLayout(context)
+ val layoutParams = spl.getGeneratedLayoutParams(ViewGroup.LayoutParams(10, 20))
+ assertThat(layoutParams).isInstanceOf(SlidingPaneLayout.LayoutParams::class.java)
+ assertThat(layoutParams.width).isEqualTo(10)
+ assertThat(layoutParams.height).isEqualTo(20)
+ }
+
+ @Test
+ fun testGenerateLayoutParams_fromMarginLayoutParams() {
+ val context = InstrumentationRegistry.getInstrumentation().context
+ val spl = TestSlidingPaneLayout(context)
+ val layoutParams = spl.getGeneratedLayoutParams(ViewGroup.MarginLayoutParams(10, 20))
+ assertThat(layoutParams).isInstanceOf(SlidingPaneLayout.LayoutParams::class.java)
+ assertThat(layoutParams.width).isEqualTo(10)
+ assertThat(layoutParams.height).isEqualTo(20)
+ }
+
+ @Test
+ fun testGenerateLayoutParams_fromSlidingPaneLayoutLayoutParams() {
+ val context = InstrumentationRegistry.getInstrumentation().context
+ val spl = TestSlidingPaneLayout(context)
+ val layoutParams = spl.getGeneratedLayoutParams(SlidingPaneLayout.LayoutParams(10, 20))
+ assertThat(layoutParams).isInstanceOf(SlidingPaneLayout.LayoutParams::class.java)
+ assertThat(layoutParams.width).isEqualTo(10)
+ assertThat(layoutParams.height).isEqualTo(20)
+ }
+
+ @Test
+ fun testGenerateLayoutParams_fromNull() {
+ val context = InstrumentationRegistry.getInstrumentation().context
+ val spl = TestSlidingPaneLayout(context)
+ // Do not crash when input is null
+ val layoutParams = spl.getGeneratedLayoutParams(null)
+ assertThat(layoutParams).isInstanceOf(SlidingPaneLayout.LayoutParams::class.java)
+ }
}
private fun View.measureAndLayout(width: Int, height: Int) {
@@ -326,3 +366,10 @@
assertWithMessage("second child measure count").that(measureCount).isEqualTo(1)
}
}
+
+private class TestSlidingPaneLayout(context: Context) : SlidingPaneLayout(context) {
+ // ViewGroup.generateLayoutParams is protected.
+ fun getGeneratedLayoutParams(p: ViewGroup.LayoutParams?): ViewGroup.LayoutParams {
+ return generateLayoutParams(p)
+ }
+}
diff --git a/slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.kt b/slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.kt
index 9440cf4..2046ea5 100644
--- a/slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.kt
+++ b/slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.kt
@@ -27,6 +27,7 @@
import android.os.Parcelable
import android.os.Parcelable.ClassLoaderCreator
import android.util.AttributeSet
+import android.util.Log
import android.view.MotionEvent
import android.view.View
import android.view.View.MeasureSpec
@@ -202,17 +203,6 @@
}
/**
- * Pulls the string interpolation and exception throwing bytecode out of the inlined
- * [spLayoutParams] property at each call site
- */
-private fun layoutParamsError(childView: View, layoutParams: LayoutParams?): Nothing {
- error("SlidingPaneLayout child $childView had unexpected LayoutParams $layoutParams")
-}
-
-private inline val View.spLayoutParams: SlidingPaneLayout.LayoutParams
- get() = layoutParams as SlidingPaneLayout.LayoutParams
-
-/**
* SlidingPaneLayout provides a horizontal, multi-pane layout for use at the top level of a UI. A
* left (or start) pane is treated as a content list or browser, subordinate to a primary detail
* view for displaying content.
@@ -1853,7 +1843,13 @@
}
override fun generateLayoutParams(p: ViewGroup.LayoutParams?): ViewGroup.LayoutParams {
- return if (p is MarginLayoutParams) LayoutParams(p) else LayoutParams(p)
+ return if (p is MarginLayoutParams) {
+ SlidingPaneLayout.LayoutParams(p)
+ } else if (p == null) {
+ generateDefaultLayoutParams()
+ } else {
+ SlidingPaneLayout.LayoutParams(p)
+ }
}
override fun checkLayoutParams(p: ViewGroup.LayoutParams?): Boolean {
@@ -3081,4 +3077,16 @@
}
}
}
+
+ private inline val View.spLayoutParams: SlidingPaneLayout.LayoutParams
+ get() {
+ val layoutParams = this.layoutParams
+ return if (!checkLayoutParams(layoutParams)) {
+ Log.w(TAG, "Unexpected child: $this had unexpected LayoutParams: $layoutParams ")
+ generateLayoutParams(layoutParams)
+ } else {
+ layoutParams
+ }
+ as SlidingPaneLayout.LayoutParams
+ }
}