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

Commit bb3ff875 authored by Fabian Kozynski's avatar Fabian Kozynski
Browse files

Tiles added through adb stay during edit

If a tile that is not considered stock (currently nfc and user) are
added through adb, they will persist through edits of QSPanel until they
are removed.

Test: Manual using adb shell settings put secure sysui_qs_tiles wifi,bt,dnd,flashlight,inversion,nfc
Test: atest
Change-Id: I0c9c003b486ae93481810f19e26b849cc38adbc5
Fixes: 116614851
parent 82b6b06f
Loading
Loading
Loading
Loading
+19 −5
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
import android.provider.Settings;
import android.service.quicksettings.TileService;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -69,7 +70,8 @@ public class TileQueryHelper {
        mSpecs.clear();
        mFinished = false;
        // Enqueue jobs to fetch every system tile and then ever package tile.
        addStockTiles(host);
        addCurrentAndStockTiles(host);

        addPackageTiles(host);
    }

@@ -77,16 +79,28 @@ public class TileQueryHelper {
        return mFinished;
    }

    private void addStockTiles(QSTileHost host) {
        String possible = mContext.getString(R.string.quick_settings_tiles_stock);
    private void addCurrentAndStockTiles(QSTileHost host) {
        String stock = mContext.getString(R.string.quick_settings_tiles_stock);
        String current = Settings.Secure.getString(mContext.getContentResolver(),
                Settings.Secure.QS_TILES);
        final ArrayList<String> possibleTiles = new ArrayList<>();
        possibleTiles.addAll(Arrays.asList(possible.split(",")));
        if (Build.IS_DEBUGGABLE) {
        if (current != null) {
            // The setting QS_TILES is not populated immediately upon Factory Reset
            possibleTiles.addAll(Arrays.asList(current.split(",")));
        }
        String[] stockSplit =  stock.split(",");
        for (String spec : stockSplit) {
            if (!current.contains(spec)) {
                possibleTiles.add(spec);
            }
        }
        if (Build.IS_DEBUGGABLE && !current.contains(GarbageMonitor.MemoryTile.TILE_SPEC)) {
            possibleTiles.add(GarbageMonitor.MemoryTile.TILE_SPEC);
        }

        final ArrayList<QSTile> tilesToAdd = new ArrayList<>();
        for (String spec : possibleTiles) {
            // Only add current and stock tiles that can be created from QSFactoryImpl
            final QSTile tile = host.createTile(spec);
            if (tile == null) {
                continue;
+1 −1
Original line number Diff line number Diff line
@@ -114,7 +114,7 @@ public class QSFactoryImpl implements QSFactory {
        }

        // Broken tiles.
        Log.w(TAG, "Bad tile spec: " + tileSpec);
        Log.w(TAG, "No stock tile spec: " + tileSpec);
        return null;
    }

+124 −4
Original line number Diff line number Diff line
@@ -14,41 +14,76 @@

package com.android.systemui.qs.customize;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;

import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.pm.PackageManager;
import android.provider.Settings;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.text.TextUtils;
import android.util.ArraySet;

import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.QSTileHost;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
public class TileQueryHelperTest extends SysuiTestCase {
    @Mock private TileQueryHelper.TileStateListener mListener;
    @Mock private QSTileHost mQSTileHost;
    private static final String CURRENT_TILES = "wifi,dnd,nfc";
    private static final String ONLY_STOCK_TILES = "wifi,dnd";
    private static final String WITH_OTHER_TILES = "wifi,dnd,other";
    // Note no nfc in stock tiles
    private static final String STOCK_TILES = "wifi,dnd,cell,battery";
    private static final String ALL_TILES = "wifi,dnd,nfc,cell,battery";
    private static final Set<String> FACTORY_TILES = new ArraySet<>();

    static {
        FACTORY_TILES.addAll(Arrays.asList(
                new String[]{"wifi", "bt", "cell", "dnd", "inversion", "airplane", "work",
                        "rotation", "flashlight", "location", "cast", "hotspot", "user", "battery",
                        "saver", "night", "nfc"}));
    }

    private TestableLooper mBGLooper;
    @Mock
    private TileQueryHelper.TileStateListener mListener;
    @Mock
    private QSTileHost mQSTileHost;
    @Mock
    private PackageManager mPackageManager;

    private QSTile.State mState;
    private TestableLooper mBGLooper;
    private TileQueryHelper mTileQueryHelper;

    @Before
@@ -56,6 +91,23 @@ public class TileQueryHelperTest extends SysuiTestCase {
        MockitoAnnotations.initMocks(this);
        mBGLooper = TestableLooper.get(this);
        mDependency.injectTestDependency(Dependency.BG_LOOPER, mBGLooper.getLooper());
        mContext.setMockPackageManager(mPackageManager);

        mState = new QSTile.State();
        doAnswer(invocation -> {
                    String spec = (String) invocation.getArguments()[0];
                    if (FACTORY_TILES.contains(spec)) {
                        QSTile m = mock(QSTile.class);
                        when(m.isAvailable()).thenReturn(true);
                        when(m.getTileSpec()).thenReturn(spec);
                        when(m.getState()).thenReturn(mState);
                        return m;
                    } else {
                        return null;
                    }
                }
        ).when(mQSTileHost).createTile(anyString());

        mTileQueryHelper = new TileQueryHelper(mContext, mListener);
    }

@@ -98,4 +150,72 @@ public class TileQueryHelperTest extends SysuiTestCase {

        assertTrue(mTileQueryHelper.isFinished());
    }

    @Test
    public void testQueryTiles_correctTilesAndOrderOnlyStockTiles() {
        ArgumentCaptor<List<TileQueryHelper.TileInfo>> captor = ArgumentCaptor.forClass(List.class);

        Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.QS_TILES,
                ONLY_STOCK_TILES);
        mContext.getOrCreateTestableResources().addOverride(R.string.quick_settings_tiles_stock,
                STOCK_TILES);

        mTileQueryHelper.queryTiles(mQSTileHost);

        mBGLooper.processAllMessages();
        waitForIdleSync(Dependency.get(Dependency.MAIN_HANDLER));

        verify(mListener, atLeastOnce()).onTilesChanged(captor.capture());
        List<String> specs = new ArrayList<>();
        for (TileQueryHelper.TileInfo t : captor.getValue()) {
            specs.add(t.spec);
        }
        String tiles = TextUtils.join(",", specs);
        assertThat(tiles, is(equalTo(STOCK_TILES)));
    }

    @Test
    public void testQueryTiles_correctTilesAndOrderOtherFactoryTiles() {
        ArgumentCaptor<List<TileQueryHelper.TileInfo>> captor = ArgumentCaptor.forClass(List.class);

        Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.QS_TILES,
                CURRENT_TILES);
        mContext.getOrCreateTestableResources().addOverride(R.string.quick_settings_tiles_stock,
                STOCK_TILES);

        mTileQueryHelper.queryTiles(mQSTileHost);

        mBGLooper.processAllMessages();
        waitForIdleSync(Dependency.get(Dependency.MAIN_HANDLER));

        verify(mListener, atLeastOnce()).onTilesChanged(captor.capture());
        List<String> specs = new ArrayList<>();
        for (TileQueryHelper.TileInfo t : captor.getValue()) {
            specs.add(t.spec);
        }
        String tiles = TextUtils.join(",", specs);
        assertThat(tiles, is(equalTo(ALL_TILES)));
    }

    @Test
    public void testQueryTiles_otherTileNotIncluded() {
        ArgumentCaptor<List<TileQueryHelper.TileInfo>> captor = ArgumentCaptor.forClass(List.class);

        Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.QS_TILES,
                WITH_OTHER_TILES);
        mContext.getOrCreateTestableResources().addOverride(R.string.quick_settings_tiles_stock,
                STOCK_TILES);

        mTileQueryHelper.queryTiles(mQSTileHost);

        mBGLooper.processAllMessages();
        waitForIdleSync(Dependency.get(Dependency.MAIN_HANDLER));

        verify(mListener, atLeastOnce()).onTilesChanged(captor.capture());
        List<String> specs = new ArrayList<>();
        for (TileQueryHelper.TileInfo t : captor.getValue()) {
            specs.add(t.spec);
        }
        assertFalse(specs.contains("other"));
    }
}