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.support.test.runner.AndroidJUnit4; 44 import android.test.suitebuilder.annotation.SmallTest; 45 46 import com.android.systemui.SysuiTestCase; 47 48 import org.junit.After; 49 import org.junit.Before; 50 import org.junit.Test; 51 import org.junit.runner.RunWith; 52 import org.mockito.Mockito; 53 54 @SmallTest 55 @RunWith(AndroidJUnit4.class) 56 public class TileLifecycleManagerTest extends SysuiTestCase { 57 private static final int TEST_FAIL_TIMEOUT = 5000; 58 59 private final PackageManagerAdapter mMockPackageManagerAdapter = 60 Mockito.mock(PackageManagerAdapter.class); 61 private final IQSTileService.Stub mMockTileService = Mockito.mock(IQSTileService.Stub.class); 62 private ComponentName mTileServiceComponentName; 63 private Intent mTileServiceIntent; 64 private UserHandle mUser; 65 private HandlerThread mThread; 66 private Handler mHandler; 67 private TileLifecycleManager mStateManager; 68 69 @Before 70 public void setUp() throws Exception { 71 setPackageEnabled(true); 72 mTileServiceComponentName = new ComponentName(mContext, "FakeTileService.class"); 73 74 // Stub.asInterface will just return itself. 75 when(mMockTileService.queryLocalInterface(anyString())).thenReturn(mMockTileService); 76 77 mContext.addMockService(mTileServiceComponentName, mMockTileService); 78 79 80 mTileServiceIntent = new Intent().setComponent(mTileServiceComponentName); 81 mUser = new UserHandle(UserHandle.myUserId()); 82 mThread = new HandlerThread("TestThread"); 83 mThread.start(); 84 mHandler = Handler.createAsync(mThread.getLooper()); 85 mStateManager = new TileLifecycleManager(mHandler, mContext, 86 Mockito.mock(IQSService.class), new Tile(), 87 mTileServiceIntent, 88 mUser, 89 mMockPackageManagerAdapter); 90 } 91 92 @After 93 public void tearDown() throws Exception { 94 mThread.quit(); 95 } 96 97 private void setPackageEnabled(boolean enabled) throws Exception { 98 ServiceInfo defaultServiceInfo = null; 99 if (enabled) { 100 defaultServiceInfo = new ServiceInfo(); 101 defaultServiceInfo.metaData = new Bundle(); 102 defaultServiceInfo.metaData.putBoolean(TileService.META_DATA_ACTIVE_TILE, true); 103 } 104 when(mMockPackageManagerAdapter.getServiceInfo(any(), anyInt(), anyInt())) 105 .thenReturn(defaultServiceInfo); 106 when(mMockPackageManagerAdapter.getServiceInfo(any(), anyInt())) 107 .thenReturn(defaultServiceInfo); 108 PackageInfo defaultPackageInfo = new PackageInfo(); 109 when(mMockPackageManagerAdapter.getPackageInfoAsUser(anyString(), anyInt(), anyInt())) 110 .thenReturn(defaultPackageInfo); 111 } 112 113 private void verifyBind(int times) { 114 assertEquals(times > 0, mContext.isBound(mTileServiceComponentName)); 115 } 116 117 @Test 118 public void testBind() { 119 mStateManager.setBindService(true); 120 verifyBind(1); 121 } 122 123 @Test 124 public void testUnbind() { 125 mStateManager.setBindService(true); 126 mStateManager.setBindService(false); 127 assertFalse(mContext.isBound(mTileServiceComponentName)); 128 } 129 130 @Test 131 public void testTileServiceCallbacks() throws Exception { 132 mStateManager.setBindService(true); 133 mStateManager.onTileAdded(); 134 verify(mMockTileService).onTileAdded(); 135 mStateManager.onStartListening(); 136 verify(mMockTileService).onStartListening(); 137 mStateManager.onClick(null); 138 verify(mMockTileService).onClick(null); 139 mStateManager.onStopListening(); 140 verify(mMockTileService).onStopListening(); 141 mStateManager.onTileRemoved(); 142 verify(mMockTileService).onTileRemoved(); 143 } 144 145 @Test 146 public void testAddedBeforeBind() throws Exception { 147 mStateManager.onTileAdded(); 148 mStateManager.setBindService(true); 149 150 verifyBind(1); 151 verify(mMockTileService).onTileAdded(); 152 } 153 154 @Test 155 public void testListeningBeforeBind() throws Exception { 156 mStateManager.onTileAdded(); 157 mStateManager.onStartListening(); 158 mStateManager.setBindService(true); 159 160 verifyBind(1); 161 verify(mMockTileService).onTileAdded(); 162 verify(mMockTileService).onStartListening(); 163 } 164 165 @Test 166 public void testClickBeforeBind() throws Exception { 167 mStateManager.onTileAdded(); 168 mStateManager.onStartListening(); 169 mStateManager.onClick(null); 170 mStateManager.setBindService(true); 171 172 verifyBind(1); 173 verify(mMockTileService).onTileAdded(); 174 verify(mMockTileService).onStartListening(); 175 verify(mMockTileService).onClick(null); 176 } 177 178 @Test 179 public void testListeningNotListeningBeforeBind() throws Exception { 180 mStateManager.onTileAdded(); 181 mStateManager.onStartListening(); 182 mStateManager.onStopListening(); 183 mStateManager.setBindService(true); 184 185 verifyBind(1); 186 mStateManager.setBindService(false); 187 assertFalse(mContext.isBound(mTileServiceComponentName)); 188 verify(mMockTileService, never()).onStartListening(); 189 } 190 191 @Test 192 public void testNoClickOfNotListeningAnymore() throws Exception { 193 mStateManager.onTileAdded(); 194 mStateManager.onStartListening(); 195 mStateManager.onClick(null); 196 mStateManager.onStopListening(); 197 mStateManager.setBindService(true); 198 199 verifyBind(1); 200 mStateManager.setBindService(false); 201 assertFalse(mContext.isBound(mTileServiceComponentName)); 202 verify(mMockTileService, never()).onClick(null); 203 } 204 205 @Test 206 public void testComponentEnabling() throws Exception { 207 mStateManager.onTileAdded(); 208 mStateManager.onStartListening(); 209 setPackageEnabled(false); 210 mStateManager.setBindService(true); 211 // Package not available, not yet created. 212 verifyBind(0); 213 214 // Package is re-enabled. 215 setPackageEnabled(true); 216 mStateManager.onReceive( 217 mContext, 218 new Intent( 219 Intent.ACTION_PACKAGE_CHANGED, 220 Uri.fromParts( 221 "package", mTileServiceComponentName.getPackageName(), null))); 222 verifyBind(1); 223 } 224 225 @Test 226 public void testKillProcess() throws Exception { 227 mStateManager.onStartListening(); 228 mStateManager.setBindService(true); 229 mStateManager.setBindRetryDelay(0); 230 mStateManager.onServiceDisconnected(mTileServiceComponentName); 231 232 // Guarantees mHandler has processed all messages. 233 assertTrue(mHandler.runWithScissors(()->{}, TEST_FAIL_TIMEOUT)); 234 235 // Two calls: one for the first bind, one for the restart. 236 verifyBind(2); 237 verify(mMockTileService, times(2)).onStartListening(); 238 } 239 } 240