Fix refresh tile when tile is already listening
Calling refreshTile externally on a tile that is already listening can have unexpected side effects, for example if the tile is tracking a user interaction (e.g. turning on bt). In particular, QSPanelController should not call it for tiles that are already listening. This is the case for tiles that are also in QQS. Test: manual, toggle bt ON in QQS and expand quickly. Test: atest com.android.systemui.qs Fixes: 225404999 Change-Id: Id0559ad95ecf6a28475abbdd8b989c745badd0b8
This commit is contained in:
@@ -39,7 +39,7 @@ import java.util.function.Supplier;
|
||||
@DependsOn(target = Icon.class)
|
||||
@DependsOn(target = State.class)
|
||||
public interface QSTile {
|
||||
int VERSION = 3;
|
||||
int VERSION = 4;
|
||||
|
||||
String getTileSpec();
|
||||
|
||||
@@ -114,6 +114,12 @@ public interface QSTile {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the tile is set to its listening state and therefore receiving updates and
|
||||
* refreshes from controllers
|
||||
*/
|
||||
boolean isListening();
|
||||
|
||||
@ProvidesInterface(version = Callback.VERSION)
|
||||
interface Callback {
|
||||
static final int VERSION = 2;
|
||||
|
||||
@@ -217,7 +217,12 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
|
||||
/** */
|
||||
public void refreshAllTiles() {
|
||||
for (QSPanelControllerBase.TileRecord r : mRecords) {
|
||||
r.tile.refreshState();
|
||||
if (!r.tile.isListening()) {
|
||||
// Only refresh tiles that were not already in the listening state. Tiles that are
|
||||
// already listening is as if they are already expanded (for example, tiles that
|
||||
// are both in QQS and QS).
|
||||
r.tile.refreshState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -331,6 +331,11 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
|
||||
refreshState(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isListening() {
|
||||
return getLifecycle().getCurrentState().isAtLeast(RESUMED);
|
||||
}
|
||||
|
||||
protected final void refreshState(@Nullable Object arg) {
|
||||
mHandler.obtainMessage(H.REFRESH_STATE, arg).sendToTarget();
|
||||
}
|
||||
@@ -416,7 +421,7 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
|
||||
@Nullable
|
||||
public abstract Intent getLongClickIntent();
|
||||
|
||||
protected void handleRefreshState(@Nullable Object arg) {
|
||||
protected final void handleRefreshState(@Nullable Object arg) {
|
||||
handleUpdateState(mTmpState, arg);
|
||||
boolean changed = mTmpState.copyTo(mState);
|
||||
if (mReadyState == READY_STATE_READYING) {
|
||||
|
||||
@@ -46,6 +46,7 @@ import com.android.systemui.R;
|
||||
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.plugins.qs.QSTileView;
|
||||
import com.android.systemui.qs.customize.QSCustomizerController;
|
||||
import com.android.systemui.qs.logging.QSLogger;
|
||||
@@ -62,6 +63,7 @@ import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@RunWithLooper
|
||||
@@ -89,6 +91,8 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {
|
||||
@Mock
|
||||
QSTileImpl mQSTile;
|
||||
@Mock
|
||||
QSTile mOtherTile;
|
||||
@Mock
|
||||
QSTileView mQSTileView;
|
||||
@Mock
|
||||
PagedTileLayout mPagedTileLayout;
|
||||
@@ -280,4 +284,17 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {
|
||||
assertThat(mController.shouldUseHorizontalLayout()).isFalse();
|
||||
verify(mHorizontalLayoutListener, times(2)).run();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshAllTilesDoesntRefreshListeningTiles() {
|
||||
when(mQSTileHost.getTiles()).thenReturn(List.of(mQSTile, mOtherTile));
|
||||
mController.setTiles();
|
||||
|
||||
when(mQSTile.isListening()).thenReturn(false);
|
||||
when(mOtherTile.isListening()).thenReturn(true);
|
||||
|
||||
mController.refreshAllTiles();
|
||||
verify(mQSTile).refreshState();
|
||||
verify(mOtherTile, never()).refreshState();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@ import android.test.suitebuilder.annotation.SmallTest
|
||||
import android.testing.AndroidTestingRunner
|
||||
import com.android.internal.logging.MetricsLogger
|
||||
import com.android.internal.logging.UiEventLogger
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.flags.FeatureFlags
|
||||
import com.android.systemui.media.MediaHost
|
||||
import com.android.systemui.media.MediaHostState
|
||||
import com.android.systemui.plugins.FalsingManager
|
||||
import com.android.systemui.plugins.qs.QSTile
|
||||
import com.android.systemui.qs.customize.QSCustomizerController
|
||||
import com.android.systemui.qs.logging.QSLogger
|
||||
import com.android.systemui.settings.brightness.BrightnessController
|
||||
@@ -21,11 +21,12 @@ import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.Mockito.any
|
||||
import org.mockito.Mockito.reset
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
import org.mockito.MockitoAnnotations
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@@ -49,6 +50,8 @@ class QSPanelControllerTest : SysuiTestCase() {
|
||||
@Mock private lateinit var falsingManager: FalsingManager
|
||||
@Mock private lateinit var featureFlags: FeatureFlags
|
||||
@Mock private lateinit var mediaHost: MediaHost
|
||||
@Mock private lateinit var tile: QSTile
|
||||
@Mock private lateinit var otherTile: QSTile
|
||||
|
||||
private lateinit var controller: QSPanelController
|
||||
|
||||
@@ -93,8 +96,17 @@ class QSPanelControllerTest : SysuiTestCase() {
|
||||
verify(mediaHost).expansion = MediaHostState.EXPANDED
|
||||
}
|
||||
|
||||
private fun setSplitShadeEnabled(enabled: Boolean) {
|
||||
mContext.orCreateTestableResources
|
||||
.addOverride(R.bool.config_use_split_notification_shade, enabled)
|
||||
@Test
|
||||
fun testSetListeningDoesntRefreshListeningTiles() {
|
||||
whenever(qsTileHost.getTiles()).thenReturn(listOf(tile, otherTile))
|
||||
controller.setTiles()
|
||||
whenever(tile.isListening()).thenReturn(false)
|
||||
whenever(otherTile.isListening()).thenReturn(true)
|
||||
whenever(qsPanel.isListening).thenReturn(true)
|
||||
|
||||
controller.setListening(true, true)
|
||||
|
||||
verify(tile).refreshState()
|
||||
verify(otherTile, Mockito.never()).refreshState()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,6 +372,11 @@ public class TileQueryHelperTest extends SysuiTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isListening() {
|
||||
return mListening;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTileLabel() {
|
||||
return mSpec;
|
||||
|
||||
@@ -361,6 +361,24 @@ public class QSTileImplTest extends SysuiTestCase {
|
||||
assertEquals(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS, captor.getValue().getAction());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsListening() {
|
||||
Object o = new Object();
|
||||
|
||||
mTile.setListening(o, true);
|
||||
mTestableLooper.processAllMessages();
|
||||
assertTrue(mTile.isListening());
|
||||
|
||||
mTile.setListening(o, false);
|
||||
mTestableLooper.processAllMessages();
|
||||
assertFalse(mTile.isListening());
|
||||
|
||||
mTile.setListening(o, true);
|
||||
mTile.destroy();
|
||||
mTestableLooper.processAllMessages();
|
||||
assertFalse(mTile.isListening());
|
||||
}
|
||||
|
||||
private void assertEvent(UiEventLogger.UiEventEnum eventType,
|
||||
UiEventLoggerFake.FakeUiEvent fakeEvent) {
|
||||
assertEquals(eventType.getId(), fakeEvent.eventId);
|
||||
|
||||
Reference in New Issue
Block a user