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

Commit 152693da authored by Fabian Kozynski's avatar Fabian Kozynski
Browse files

Fix out of bounds in QuickQSPanelController

Make sure that we only select the correct number of tiles, therefore
there's no need to call subList. As we will always call setTiles if the
number of tiles in the resource changes. We'll always have enough tiles
to show.

Test: atest QuickQSControllerTest
Test: manual
Fixes: 173792244
Change-Id: I70a0e4903bb8e5a319dbbc8c321d8774f0dd3064
parent f48a5e3d
Loading
Loading
Loading
Loading
+4 −6
Original line number Diff line number Diff line
@@ -40,8 +40,6 @@ import javax.inject.Named;
@QSScope
public class QuickQSPanelController extends QSPanelControllerBase<QuickQSPanel> {

    private List<QSTile> mAllTiles = new ArrayList<>();

    private final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener =
            newConfig -> {
                int newMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
@@ -92,14 +90,14 @@ public class QuickQSPanelController extends QSPanelControllerBase<QuickQSPanel>

    @Override
    public void setTiles() {
        mAllTiles.clear();
        List<QSTile> tiles = new ArrayList();
        for (QSTile tile : mHost.getTiles()) {
            mAllTiles.add(tile);
            if (mAllTiles.size() == QuickQSPanel.DEFAULT_MAX_TILES) {
            tiles.add(tile);
            if (tiles.size() == mView.getNumQuickTiles()) {
                break;
            }
        }
        super.setTiles(mAllTiles.subList(0, mView.getNumQuickTiles()), true);
        super.setTiles(tiles, true);
    }

    /** */
+111 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.qs

import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.internal.logging.MetricsLogger
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.media.MediaHost
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.qs.customize.QSCustomizerController
import com.android.systemui.qs.logging.QSLogger
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.Mockito.any
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations

@SmallTest
@RunWith(AndroidTestingRunner::class)
class QuickQSPanelControllerTest : SysuiTestCase() {

    @Mock
    private lateinit var quickQSPanel: QuickQSPanel
    @Mock
    private lateinit var qsTileHost: QSTileHost
    @Mock
    private lateinit var qsCustomizerController: QSCustomizerController
    @Mock
    private lateinit var mediaHost: MediaHost
    @Mock
    private lateinit var metricsLogger: MetricsLogger
    private val uiEventLogger = UiEventLoggerFake()
    @Mock
    private lateinit var qsLogger: QSLogger
    private val dumpManager = DumpManager()
    @Mock
    private lateinit var tile: QSTile
    @Mock
    private lateinit var tileLayout: TileLayout

    private lateinit var controller: QuickQSPanelController

    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)

        `when`(quickQSPanel.tileLayout).thenReturn(tileLayout)
        `when`(quickQSPanel.dumpableTag).thenReturn("")

        controller = QuickQSPanelController(
                quickQSPanel,
                qsTileHost,
                qsCustomizerController,
                false,
                mediaHost,
                metricsLogger,
                uiEventLogger,
                qsLogger,
                dumpManager
        )

        controller.init()
    }

    @After
    fun tearDown() {
        controller.onViewDetached()
    }

    @Test
    fun testTileSublistWithFewerTiles_noCrash() {
        `when`(quickQSPanel.numQuickTiles).thenReturn(3)

        `when`(qsTileHost.tiles).thenReturn(listOf(tile, tile))

        controller.setTiles()
    }

    @Test
    fun testTileSublistWithTooManyTiles() {
        val limit = 3
        `when`(quickQSPanel.numQuickTiles).thenReturn(limit)
        `when`(qsTileHost.tiles).thenReturn(listOf(tile, tile, tile, tile))

        controller.setTiles()

        verify(quickQSPanel, times(limit)).addTile(any())
    }
}
 No newline at end of file