Commit 3f87b8f7 authored by Arturo Mejia's avatar Arturo Mejia
Browse files

Closes #3211: Support endOfMenuAlwaysVisible for Android 6 and below.

parent 18f8b08a
......@@ -8,12 +8,15 @@ import android.annotation.SuppressLint
import android.graphics.Color
import android.graphics.Rect
import android.graphics.drawable.ColorDrawable
import android.os.Build
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewTreeObserver
import android.view.WindowManager
import android.widget.PopupWindow
import androidx.annotation.VisibleForTesting
import androidx.annotation.VisibleForTesting.PRIVATE
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.widget.PopupWindowCompat
import androidx.recyclerview.widget.LinearLayoutManager
......@@ -31,6 +34,9 @@ class BrowserMenu internal constructor(
private var currentPopup: PopupWindow? = null
private var menuList: RecyclerView? = null
@VisibleForTesting(otherwise = PRIVATE)
internal var scrollOnceToTheBottomWasCalled = false
/**
* @param anchor the view on which to pin the popup window.
* @param orientation the preferred orientation to show the popup window.
......@@ -50,7 +56,7 @@ class BrowserMenu internal constructor(
menuList = view.findViewById<RecyclerView>(R.id.mozac_browser_menu_recyclerView).apply {
layoutManager = LinearLayoutManager(anchor.context, RecyclerView.VERTICAL, false).also {
it.stackFromEnd = endOfMenuAlwaysVisible
setEndOfMenuAlwaysVisibleCompact(endOfMenuAlwaysVisible, it)
}
adapter = this@BrowserMenu.adapter
}
......@@ -76,6 +82,33 @@ class BrowserMenu internal constructor(
}
}
private fun RecyclerView.setEndOfMenuAlwaysVisibleCompact(
endOfMenuAlwaysVisible: Boolean,
layoutManager: LinearLayoutManager
) {
// In devices with Android 6 and below stackFromEnd is not working properly,
// as a result, we have to provided a backwards support.
// See: https://github.com/mozilla-mobile/android-components/issues/3211
if (endOfMenuAlwaysVisible && Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
scrollOnceToTheBottom()
} else {
layoutManager.stackFromEnd = endOfMenuAlwaysVisible
}
}
private fun RecyclerView.scrollOnceToTheBottom() {
var listener: ViewTreeObserver.OnGlobalLayoutListener? = null
listener = ViewTreeObserver.OnGlobalLayoutListener {
adapter?.let {
scrollToPosition(it.itemCount - 1)
// Unregister the listener to only call scrollToPosition once
viewTreeObserver.removeOnGlobalLayoutListener(listener)
}
}
viewTreeObserver.addOnGlobalLayoutListener(listener)
scrollOnceToTheBottomWasCalled = true
}
fun dismiss() {
currentPopup?.dismiss()
}
......
......@@ -4,6 +4,7 @@
package mozilla.components.browser.menu
import android.os.Build
import android.view.Gravity
import android.view.View
import android.widget.Button
......@@ -28,6 +29,7 @@ import org.mockito.Mockito.doReturn
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.robolectric.Shadows
import org.robolectric.annotation.Config
import org.robolectric.shadows.ShadowDisplay
@RunWith(AndroidJUnit4::class)
......@@ -89,6 +91,26 @@ class BrowserMenuTest {
assertTrue(layoutManager.stackFromEnd)
}
@Test
@Config(sdk = [Build.VERSION_CODES.M])
fun `endOfMenuAlwaysVisible will be forwarded to scrollOnceToTheBottom on devices with Android M and below`() {
val items = listOf(
SimpleBrowserMenuItem("Hello") {},
SimpleBrowserMenuItem("World") {})
val adapter = spy(BrowserMenuAdapter(testContext, items))
val menu = BrowserMenu(adapter)
val anchor = Button(testContext)
val popup = menu.show(anchor, endOfMenuAlwaysVisible = true)
val recyclerView: RecyclerView = popup.contentView.findViewById(R.id.mozac_browser_menu_recyclerView)
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
assertFalse(layoutManager.stackFromEnd)
assertNotNull(menu.scrollOnceToTheBottomWasCalled)
}
@Test
fun `invalidate will be forwarded to recyclerview adapter`() {
val items = listOf(
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment