diff options
| author | 2023-03-28 15:30:34 -0400 | |
|---|---|---|
| committer | 2023-03-29 09:21:13 -0400 | |
| commit | c4ef08411d04159fc0bc472c2037fddd1360c81c (patch) | |
| tree | 9b353652751577458fe6289b68665b13cf5fa8b4 | |
| parent | 25be63a7bc27c53be1de2c67bf4bc9ea228e73f5 (diff) | |
Store tiles by component name and user
This way, when the user changes, the old tile is not just replaced in the
map, instead we keep it until it can be freed. This solves an issue of
active tiles not being able to be set into listening state after user
changing.
Test: atest TileServices
Test: manual, using sample tile service app
Fixes: 243902636
Change-Id: I57d08aec5c0b40f09f5bd763d63068aaea7ba450
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java | 18 | ||||
| -rw-r--r-- | packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java | 40 |
2 files changed, 51 insertions, 7 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java index 5e4f53181706..42536fef17aa 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java @@ -30,6 +30,7 @@ import android.service.quicksettings.IQSService; import android.service.quicksettings.Tile; import android.util.ArrayMap; import android.util.Log; +import android.util.SparseArrayMap; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -64,7 +65,7 @@ public class TileServices extends IQSService.Stub { private static final String TAG = "TileServices"; private final ArrayMap<CustomTile, TileServiceManager> mServices = new ArrayMap<>(); - private final ArrayMap<ComponentName, CustomTile> mTiles = new ArrayMap<>(); + private final SparseArrayMap<ComponentName, CustomTile> mTiles = new SparseArrayMap<>(); private final ArrayMap<IBinder, CustomTile> mTokenMap = new ArrayMap<>(); private final Context mContext; private final Handler mMainHandler; @@ -112,10 +113,11 @@ public class TileServices extends IQSService.Stub { public TileServiceManager getTileWrapper(CustomTile tile) { ComponentName component = tile.getComponent(); + int userId = tile.getUser(); TileServiceManager service = onCreateTileService(component, mBroadcastDispatcher); synchronized (mServices) { mServices.put(tile, service); - mTiles.put(component, tile); + mTiles.add(userId, component, tile); mTokenMap.put(service.getToken(), tile); } // Makes sure binding only happens after the maps have been populated @@ -135,7 +137,7 @@ public class TileServices extends IQSService.Stub { service.handleDestroy(); mServices.remove(tile); mTokenMap.remove(service.getToken()); - mTiles.remove(tile.getComponent()); + mTiles.delete(tile.getUser(), tile.getComponent()); final String slot = getStatusBarIconSlotName(tile.getComponent()); mMainHandler.post(() -> mStatusBarIconController.removeIconForTile(slot)); } @@ -188,9 +190,10 @@ public class TileServices extends IQSService.Stub { private void requestListening(ComponentName component) { synchronized (mServices) { - CustomTile customTile = getTileForComponent(component); + int userId = mUserTracker.getUserId(); + CustomTile customTile = getTileForUserAndComponent(userId, component); if (customTile == null) { - Log.d("TileServices", "Couldn't find tile for " + component); + Log.d(TAG, "Couldn't find tile for " + component + "(" + userId + ")"); return; } TileServiceManager service = mServices.get(customTile); @@ -362,9 +365,9 @@ public class TileServices extends IQSService.Stub { } @Nullable - private CustomTile getTileForComponent(ComponentName component) { + private CustomTile getTileForUserAndComponent(int userId, ComponentName component) { synchronized (mServices) { - return mTiles.get(component); + return mTiles.get(userId, component); } } @@ -395,4 +398,5 @@ public class TileServices extends IQSService.Stub { return -Integer.compare(left.getBindPriority(), right.getBindPriority()); } }; + } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java index 7e052bfa15d2..fb9336734d99 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java @@ -54,6 +54,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -95,6 +96,8 @@ public class TileServicesTest extends SysuiTestCase { private QSHost mQSHost; @Mock private PanelInteractor mPanelInteractor; + @Captor + private ArgumentCaptor<CommandQueue.Callbacks> mCallbacksArgumentCaptor; @Before public void setUp() throws Exception { @@ -251,6 +254,41 @@ public class TileServicesTest extends SysuiTestCase { verify(mPanelInteractor).forceCollapsePanels(); } + @Test + public void tileFreedForCorrectUser() throws RemoteException { + verify(mCommandQueue).addCallback(mCallbacksArgumentCaptor.capture()); + + ComponentName componentName = new ComponentName("pkg", "cls"); + CustomTile tileUser0 = mock(CustomTile.class); + CustomTile tileUser1 = mock(CustomTile.class); + + when(tileUser0.getComponent()).thenReturn(componentName); + when(tileUser1.getComponent()).thenReturn(componentName); + when(tileUser0.getUser()).thenReturn(0); + when(tileUser1.getUser()).thenReturn(1); + + // Create a tile for user 0 + TileServiceManager manager0 = mTileService.getTileWrapper(tileUser0); + when(manager0.isActiveTile()).thenReturn(true); + // Then create a tile for user 1 + TileServiceManager manager1 = mTileService.getTileWrapper(tileUser1); + when(manager1.isActiveTile()).thenReturn(true); + + // When the tile for user 0 gets freed + mTileService.freeService(tileUser0, manager0); + // and the user is 1 + when(mUserTracker.getUserId()).thenReturn(1); + + // a call to requestListeningState + mCallbacksArgumentCaptor.getValue().requestTileServiceListeningState(componentName); + mTestableLooper.processAllMessages(); + + // will call in the correct tile + verify(manager1).setBindRequested(true); + // and set it to listening + verify(manager1.getTileService()).onStartListening(); + } + private class TestTileServices extends TileServices { TestTileServices(QSHost host, Provider<Handler> handlerProvider, BroadcastDispatcher broadcastDispatcher, UserTracker userTracker, @@ -268,6 +306,8 @@ public class TileServicesTest extends SysuiTestCase { when(manager.isLifecycleStarted()).thenReturn(true); Binder b = new Binder(); when(manager.getToken()).thenReturn(b); + IQSTileService service = mock(IQSTileService.class); + when(manager.getTileService()).thenReturn(service); return manager; } } |