Fix clipping coordinates on RTL
In RTL in landscape, the container for QS and footer was clipping incorrectly, as it should use its coordinates (not its parent's) for clipping its children. Test: manual Test: atest QSPanelTest, test that views are visible to user Fixes: 235422445 Change-Id: Idf29a3f17128591eaa3405058ae16d5b09a51f43
This commit is contained in:
@@ -151,15 +151,17 @@ public class QSPanel extends LinearLayout implements Tunable {
|
||||
mHorizontalContentContainer.setClipChildren(true);
|
||||
mHorizontalContentContainer.setClipToPadding(false);
|
||||
// Don't clip on the top, that way, secondary pages tiles can animate up
|
||||
// Clipping coordinates should be relative to this view, not absolute (parent coordinates)
|
||||
mHorizontalContentContainer.addOnLayoutChangeListener(
|
||||
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
|
||||
if (left != oldLeft || right != oldRight || bottom != oldBottom) {
|
||||
mClippingRect.left = left;
|
||||
mClippingRect.right = right;
|
||||
mClippingRect.bottom = bottom;
|
||||
if ((right - left) != (oldRight - oldLeft)
|
||||
|| ((bottom - top) != (oldBottom - oldTop))) {
|
||||
mClippingRect.right = right - left;
|
||||
mClippingRect.bottom = bottom - top;
|
||||
mHorizontalContentContainer.setClipBounds(mClippingRect);
|
||||
}
|
||||
});
|
||||
mClippingRect.left = 0;
|
||||
mClippingRect.top = -1000;
|
||||
mHorizontalContentContainer.setClipBounds(mClippingRect);
|
||||
}
|
||||
|
||||
@@ -13,18 +13,24 @@
|
||||
*/
|
||||
package com.android.systemui.qs
|
||||
|
||||
import android.graphics.Rect
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper
|
||||
import android.testing.TestableLooper.RunWithLooper
|
||||
import android.testing.ViewUtils
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
||||
import android.view.accessibility.AccessibilityNodeInfo
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.LinearLayout
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.plugins.qs.QSTile
|
||||
import com.android.systemui.qs.tileimpl.QSIconViewImpl
|
||||
import com.android.systemui.qs.tileimpl.QSTileViewImpl
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
@@ -36,37 +42,40 @@ import org.mockito.MockitoAnnotations
|
||||
@RunWithLooper
|
||||
@SmallTest
|
||||
class QSPanelTest : SysuiTestCase() {
|
||||
private lateinit var mTestableLooper: TestableLooper
|
||||
private lateinit var mQsPanel: QSPanel
|
||||
private lateinit var testableLooper: TestableLooper
|
||||
private lateinit var qsPanel: QSPanel
|
||||
|
||||
private lateinit var mParentView: ViewGroup
|
||||
|
||||
private lateinit var mFooter: View
|
||||
private lateinit var footer: View
|
||||
|
||||
@Before
|
||||
@Throws(Exception::class)
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
mTestableLooper = TestableLooper.get(this)
|
||||
testableLooper = TestableLooper.get(this)
|
||||
|
||||
mTestableLooper.runWithLooper {
|
||||
mQsPanel = QSPanel(mContext, null)
|
||||
mQsPanel.initialize()
|
||||
testableLooper.runWithLooper {
|
||||
qsPanel = QSPanel(context, null)
|
||||
qsPanel.mUsingMediaPlayer = true
|
||||
|
||||
qsPanel.initialize()
|
||||
// QSPanel inflates a footer inside of it, mocking it here
|
||||
mFooter = LinearLayout(mContext).apply { id = R.id.qs_footer }
|
||||
mQsPanel.addView(mFooter)
|
||||
mQsPanel.onFinishInflate()
|
||||
footer = LinearLayout(context).apply { id = R.id.qs_footer }
|
||||
qsPanel.addView(footer, MATCH_PARENT, 100)
|
||||
qsPanel.onFinishInflate()
|
||||
// Provides a parent with non-zero size for QSPanel
|
||||
mParentView = FrameLayout(mContext).apply {
|
||||
addView(mQsPanel)
|
||||
}
|
||||
ViewUtils.attachView(qsPanel)
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
ViewUtils.detachView(qsPanel)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHasCollapseAccessibilityAction() {
|
||||
val info = AccessibilityNodeInfo(mQsPanel)
|
||||
mQsPanel.onInitializeAccessibilityNodeInfo(info)
|
||||
val info = AccessibilityNodeInfo(qsPanel)
|
||||
qsPanel.onInitializeAccessibilityNodeInfo(info)
|
||||
|
||||
assertThat(info.actions and AccessibilityNodeInfo.ACTION_COLLAPSE).isNotEqualTo(0)
|
||||
assertThat(info.actions and AccessibilityNodeInfo.ACTION_EXPAND).isEqualTo(0)
|
||||
@@ -75,9 +84,79 @@ class QSPanelTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun testCollapseActionCallsRunnable() {
|
||||
val mockRunnable = mock(Runnable::class.java)
|
||||
mQsPanel.setCollapseExpandAction(mockRunnable)
|
||||
qsPanel.setCollapseExpandAction(mockRunnable)
|
||||
|
||||
mQsPanel.performAccessibilityAction(AccessibilityNodeInfo.ACTION_COLLAPSE, null)
|
||||
qsPanel.performAccessibilityAction(AccessibilityNodeInfo.ACTION_COLLAPSE, null)
|
||||
verify(mockRunnable).run()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTilesFooterVisibleRTLLandscapeMedia() {
|
||||
qsPanel.layoutDirection = View.LAYOUT_DIRECTION_RTL
|
||||
// We need at least a tile so the layout has a height
|
||||
qsPanel.tileLayout?.addTile(
|
||||
QSPanelControllerBase.TileRecord(
|
||||
mock(QSTile::class.java),
|
||||
QSTileViewImpl(context, QSIconViewImpl(context))
|
||||
)
|
||||
)
|
||||
|
||||
val mediaView = FrameLayout(context)
|
||||
mediaView.addView(View(context), MATCH_PARENT, 800)
|
||||
|
||||
qsPanel.setUsingHorizontalLayout(/* horizontal */ true, mediaView, /* force */ true)
|
||||
qsPanel.measure(
|
||||
/* width */ View.MeasureSpec.makeMeasureSpec(3000, View.MeasureSpec.EXACTLY),
|
||||
/* height */ View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY)
|
||||
)
|
||||
qsPanel.layout(0, 0, qsPanel.measuredWidth, qsPanel.measuredHeight)
|
||||
|
||||
val tiles = qsPanel.tileLayout as View
|
||||
// Tiles are effectively to the right of media
|
||||
assertThat(mediaView isLeftOf tiles)
|
||||
assertThat(tiles.isVisibleToUser).isTrue()
|
||||
|
||||
assertThat(mediaView isLeftOf footer)
|
||||
assertThat(footer.isVisibleToUser).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTilesFooterVisibleLandscapeMedia() {
|
||||
qsPanel.layoutDirection = View.LAYOUT_DIRECTION_LTR
|
||||
// We need at least a tile so the layout has a height
|
||||
qsPanel.tileLayout?.addTile(
|
||||
QSPanelControllerBase.TileRecord(
|
||||
mock(QSTile::class.java),
|
||||
QSTileViewImpl(context, QSIconViewImpl(context))
|
||||
)
|
||||
)
|
||||
|
||||
val mediaView = FrameLayout(context)
|
||||
mediaView.addView(View(context), MATCH_PARENT, 800)
|
||||
|
||||
qsPanel.setUsingHorizontalLayout(/* horizontal */ true, mediaView, /* force */ true)
|
||||
qsPanel.measure(
|
||||
/* width */ View.MeasureSpec.makeMeasureSpec(3000, View.MeasureSpec.EXACTLY),
|
||||
/* height */ View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY)
|
||||
)
|
||||
qsPanel.layout(0, 0, qsPanel.measuredWidth, qsPanel.measuredHeight)
|
||||
|
||||
val tiles = qsPanel.tileLayout as View
|
||||
// Tiles are effectively to the left of media
|
||||
assertThat(tiles isLeftOf mediaView)
|
||||
assertThat(tiles.isVisibleToUser).isTrue()
|
||||
|
||||
assertThat(footer isLeftOf mediaView)
|
||||
assertThat(footer.isVisibleToUser).isTrue()
|
||||
}
|
||||
|
||||
private infix fun View.isLeftOf(other: View): Boolean {
|
||||
val rect = Rect()
|
||||
getBoundsOnScreen(rect)
|
||||
val thisRight = rect.right
|
||||
|
||||
other.getBoundsOnScreen(rect)
|
||||
|
||||
return thisRight <= rect.left
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user