Postpone available check for CustomTile

In the case of custom tiles, we don't know if they are available until
after initialization. Because it runs async to tile creation, the check
in QSTileHost may fail and destroy the tile prematurely. Instead,
postpone it until after we've tried to retrieve the service icon.

Also, add TileService CTS tests to com.android.systemui.qs TEST_MAPPING.

Test: atest SystemUITests
Test: atest CtsAppTestCases
Fixes: 197970498
Change-Id: Id8d4090cfbfaa144b71d78ffd74da8fc1b9e6c6e
This commit is contained in:
Fabian Kozynski
2021-08-27 15:49:47 -04:00
parent 680d2625fd
commit f8ffbd327c
5 changed files with 59 additions and 4 deletions

View File

@@ -0,0 +1,21 @@
{
"presubmit": [
{
"name": "CtsAppTestCases",
"options": [
{
"include-filter": "android.app.cts.TileServiceTest"
},
{
"include-filter": "android.app.cts.BooleanTileServiceTest"
},
{
"exclude-annotation": "org.junit.Ignore"
},
{
"exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
}
]
}

View File

@@ -63,6 +63,7 @@ import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.inject.Inject;
@@ -98,6 +99,8 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
private final TileServiceKey mKey;
private final AtomicBoolean mInitialDefaultIconFetched = new AtomicBoolean(false);
private CustomTile(
QSHost host,
Looper backgroundLooper,
@@ -128,6 +131,12 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
@Override
protected void handleInitialize() {
updateDefaultTileAndIcon();
if (mInitialDefaultIconFetched.compareAndSet(false, true)) {
if (mDefaultIcon == null) {
mQSLogger.logTileDestroyed(getTileSpec(),
"Custom tile default icon not available");
}
}
if (mServiceManager.isToggleableTile()) {
// Replace states with BooleanState
resetStates();
@@ -213,9 +222,18 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
mHandler.post(this::updateDefaultTileAndIcon);
}
/**
* Custom tile is considered available if there is a default icon (obtained from PM).
*
* It will return {@code true} before initialization, so tiles are not destroyed prematurely.
*/
@Override
public boolean isAvailable() {
return mDefaultIcon != null;
if (mInitialDefaultIconFetched.get()) {
return mDefaultIcon != null;
} else {
return true;
}
}
public int getUser() {

View File

@@ -105,7 +105,7 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
protected final ActivityStarter mActivityStarter;
private final UiEventLogger mUiEventLogger;
private final FalsingManager mFalsingManager;
private final QSLogger mQSLogger;
protected final QSLogger mQSLogger;
private volatile int mReadyState;
private final ArrayList<Callback> mCallbacks = new ArrayList<>();

View File

@@ -20,8 +20,8 @@ package com.android.systemui.qs;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.mock;
@@ -424,7 +424,7 @@ public class QSTileHostTest extends SysuiTestCase {
mock(MetricsLogger.class),
mock(StatusBarStateController.class),
mock(ActivityStarter.class),
mQSLogger
QSTileHostTest.this.mQSLogger
);
}

View File

@@ -270,4 +270,20 @@ class CustomTileTest : SysuiTestCase() {
verify(customTileStatePersister)
.persistState(TileServiceKey(componentName, customTile.user), t)
}
@Test
fun testAvailableBeforeInitialization() {
`when`(packageManager.getApplicationInfo(anyString(), anyInt()))
.thenThrow(PackageManager.NameNotFoundException())
val tile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
assertTrue(tile.isAvailable)
}
@Test
fun testNotAvailableAfterInitializationWithoutIcon() {
val tile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
tile.initialize()
testableLooper.processAllMessages()
assertFalse(tile.isAvailable)
}
}