Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 84ffe9f5 authored by Fabian Kozynski's avatar Fabian Kozynski
Browse files

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
parent 2d3b1c27
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -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);
    }
+99 −20
Original line number Diff line number Diff line
@@ -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)

        testableLooper.runWithLooper {
            qsPanel = QSPanel(context, null)
            qsPanel.mUsingMediaPlayer = true

        mTestableLooper.runWithLooper {
            mQsPanel = QSPanel(mContext, null)
            mQsPanel.initialize()
            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
    }
}