1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.systemui.qs.external; 17 18 import static junit.framework.Assert.assertFalse; 19 import static junit.framework.Assert.assertTrue; 20 21 import static org.junit.Assert.assertEquals; 22 import static org.mockito.Mockito.any; 23 import static org.mockito.Mockito.anyInt; 24 import static org.mockito.Mockito.anyString; 25 import static org.mockito.Mockito.never; 26 import static org.mockito.Mockito.times; 27 import static org.mockito.Mockito.verify; 28 import static org.mockito.Mockito.when; 29 30 import android.content.ComponentName; 31 import android.content.Intent; 32 import android.content.pm.PackageInfo; 33 import android.content.pm.ServiceInfo; 34 import android.net.Uri; 35 import android.os.Bundle; 36 import android.os.Handler; 37 import android.os.HandlerThread; 38 import android.os.UserHandle; 39 import android.service.quicksettings.IQSService; 40 import android.service.quicksettings.IQSTileService; 41 import android.service.quicksettings.Tile; 42 import android.service.quicksettings.TileService; 43 import android.test.suitebuilder.annotation.SmallTest; 44 45 import androidx.test.runner.AndroidJUnit4; 46 47 import com.android.systemui.SysuiTestCase; 48 import com.android.systemui.broadcast.BroadcastDispatcher; 49 50 import org.junit.After; 51 import org.junit.Before; 52 import org.junit.Test; 53 import org.junit.runner.RunWith; 54 import org.mockito.Mockito; 55 56 @SmallTest 57 @RunWith(AndroidJUnit4.class) 58 public class TileLifecycleManagerTest extends SysuiTestCase { 59 private static final int TEST_FAIL_TIMEOUT = 5000; 60 61 private final PackageManagerAdapter mMockPackageManagerAdapter = 62 Mockito.mock(PackageManagerAdapter.class); 63 private final BroadcastDispatcher mMockBroadcastDispatcher = 64 Mockito.mock(BroadcastDispatcher.class); 65 private final IQSTileService.Stub mMockTileService = Mockito.mock(IQSTileService.Stub.class); 66 private ComponentName mTileServiceComponentName; 67 private Intent mTileServiceIntent; 68 private UserHandle mUser; 69 private HandlerThread mThread; 70 private Handler mHandler; 71 private TileLifecycleManager mStateManager; 72 73 @Before setUp()74 public void setUp() throws Exception { 75 setPackageEnabled(true); 76 mTileServiceComponentName = new ComponentName(mContext, "FakeTileService.class"); 77 78 // Stub.asInterface will just return itself. 79 when(mMockTileService.queryLocalInterface(anyString())).thenReturn(mMockTileService); 80 when(mMockTileService.asBinder()).thenReturn(mMockTileService); 81 82 mContext.addMockService(mTileServiceComponentName, mMockTileService); 83 84 mTileServiceIntent = new Intent().setComponent(mTileServiceComponentName); 85 mUser = new UserHandle(UserHandle.myUserId()); 86 mThread = new HandlerThread("TestThread"); 87 mThread.start(); 88 mHandler = Handler.createAsync(mThread.getLooper()); 89 mStateManager = new TileLifecycleManager(mHandler, mContext, 90 Mockito.mock(IQSService.class), new Tile(), 91 mTileServiceIntent, 92 mUser, 93 mMockPackageManagerAdapter, 94 mMockBroadcastDispatcher); 95 } 96 97 @After tearDown()98 public void tearDown() throws Exception { 99 mThread.quit(); 100 } 101 setPackageEnabled(boolean enabled)102 private void setPackageEnabled(boolean enabled) throws Exception { 103 ServiceInfo defaultServiceInfo = null; 104 if (enabled) { 105 defaultServiceInfo = new ServiceInfo(); 106 defaultServiceInfo.metaData = new Bundle(); 107 defaultServiceInfo.metaData.putBoolean(TileService.META_DATA_ACTIVE_TILE, true); 108 defaultServiceInfo.metaData.putBoolean(TileService.META_DATA_TOGGLEABLE_TILE, true); 109 } 110 when(mMockPackageManagerAdapter.getServiceInfo(any(), anyInt(), anyInt())) 111 .thenReturn(defaultServiceInfo); 112 when(mMockPackageManagerAdapter.getServiceInfo(any(), anyInt())) 113 .thenReturn(defaultServiceInfo); 114 PackageInfo defaultPackageInfo = new PackageInfo(); 115 when(mMockPackageManagerAdapter.getPackageInfoAsUser(anyString(), anyInt(), anyInt())) 116 .thenReturn(defaultPackageInfo); 117 } 118 verifyBind(int times)119 private void verifyBind(int times) { 120 assertEquals(times > 0, mContext.isBound(mTileServiceComponentName)); 121 } 122 123 @Test testBind()124 public void testBind() { 125 mStateManager.setBindService(true); 126 verifyBind(1); 127 } 128 129 @Test testUnbind()130 public void testUnbind() { 131 mStateManager.setBindService(true); 132 mStateManager.setBindService(false); 133 assertFalse(mContext.isBound(mTileServiceComponentName)); 134 } 135 136 @Test testTileServiceCallbacks()137 public void testTileServiceCallbacks() throws Exception { 138 mStateManager.setBindService(true); 139 mStateManager.onTileAdded(); 140 verify(mMockTileService).onTileAdded(); 141 mStateManager.onStartListening(); 142 verify(mMockTileService).onStartListening(); 143 mStateManager.onClick(null); 144 verify(mMockTileService).onClick(null); 145 mStateManager.onStopListening(); 146 verify(mMockTileService).onStopListening(); 147 mStateManager.onTileRemoved(); 148 verify(mMockTileService).onTileRemoved(); 149 } 150 151 @Test testAddedBeforeBind()152 public void testAddedBeforeBind() throws Exception { 153 mStateManager.onTileAdded(); 154 mStateManager.setBindService(true); 155 156 verifyBind(1); 157 verify(mMockTileService).onTileAdded(); 158 } 159 160 @Test testListeningBeforeBind()161 public void testListeningBeforeBind() throws Exception { 162 mStateManager.onTileAdded(); 163 mStateManager.onStartListening(); 164 mStateManager.setBindService(true); 165 166 verifyBind(1); 167 verify(mMockTileService).onTileAdded(); 168 verify(mMockTileService).onStartListening(); 169 } 170 171 @Test testClickBeforeBind()172 public void testClickBeforeBind() throws Exception { 173 mStateManager.onTileAdded(); 174 mStateManager.onStartListening(); 175 mStateManager.onClick(null); 176 mStateManager.setBindService(true); 177 178 verifyBind(1); 179 verify(mMockTileService).onTileAdded(); 180 verify(mMockTileService).onStartListening(); 181 verify(mMockTileService).onClick(null); 182 } 183 184 @Test testListeningNotListeningBeforeBind()185 public void testListeningNotListeningBeforeBind() throws Exception { 186 mStateManager.onTileAdded(); 187 mStateManager.onStartListening(); 188 mStateManager.onStopListening(); 189 mStateManager.setBindService(true); 190 191 verifyBind(1); 192 mStateManager.setBindService(false); 193 assertFalse(mContext.isBound(mTileServiceComponentName)); 194 verify(mMockTileService, never()).onStartListening(); 195 } 196 197 @Test testNoClickOfNotListeningAnymore()198 public void testNoClickOfNotListeningAnymore() throws Exception { 199 mStateManager.onTileAdded(); 200 mStateManager.onStartListening(); 201 mStateManager.onClick(null); 202 mStateManager.onStopListening(); 203 mStateManager.setBindService(true); 204 205 verifyBind(1); 206 mStateManager.setBindService(false); 207 assertFalse(mContext.isBound(mTileServiceComponentName)); 208 verify(mMockTileService, never()).onClick(null); 209 } 210 211 @Test testComponentEnabling()212 public void testComponentEnabling() throws Exception { 213 mStateManager.onTileAdded(); 214 mStateManager.onStartListening(); 215 setPackageEnabled(false); 216 mStateManager.setBindService(true); 217 // Package not available, not yet created. 218 verifyBind(0); 219 220 // Package is re-enabled. 221 setPackageEnabled(true); 222 mStateManager.onReceive( 223 mContext, 224 new Intent( 225 Intent.ACTION_PACKAGE_CHANGED, 226 Uri.fromParts( 227 "package", mTileServiceComponentName.getPackageName(), null))); 228 verifyBind(1); 229 } 230 231 @Test testKillProcess()232 public void testKillProcess() throws Exception { 233 mStateManager.onStartListening(); 234 mStateManager.setBindService(true); 235 mStateManager.setBindRetryDelay(0); 236 mStateManager.onServiceDisconnected(mTileServiceComponentName); 237 238 // Guarantees mHandler has processed all messages. 239 assertTrue(mHandler.runWithScissors(()->{}, TEST_FAIL_TIMEOUT)); 240 241 // Two calls: one for the first bind, one for the restart. 242 verifyBind(2); 243 verify(mMockTileService, times(2)).onStartListening(); 244 } 245 246 @Test testToggleableTile()247 public void testToggleableTile() throws Exception { 248 assertTrue(mStateManager.isToggleableTile()); 249 } 250 } 251