1/* 2 * Copyright (C) 2017 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 17package com.android.server.appwidget; 18 19import static org.mockito.ArgumentMatchers.any; 20import static org.mockito.ArgumentMatchers.anyInt; 21import static org.mockito.ArgumentMatchers.anyString; 22import static org.mockito.ArgumentMatchers.eq; 23import static org.mockito.Mockito.mock; 24import static org.mockito.Mockito.reset; 25import static org.mockito.Mockito.times; 26import static org.mockito.Mockito.verify; 27import static org.mockito.Mockito.when; 28 29import android.app.admin.DevicePolicyManagerInternal; 30import android.appwidget.AppWidgetManager; 31import android.appwidget.AppWidgetProviderInfo; 32import android.appwidget.PendingHostUpdate; 33import android.content.BroadcastReceiver; 34import android.content.ComponentName; 35import android.content.ContextWrapper; 36import android.content.Intent; 37import android.content.IntentFilter; 38import android.content.pm.LauncherApps; 39import android.content.pm.ShortcutServiceInternal; 40import android.os.Handler; 41import android.os.UserHandle; 42import android.test.InstrumentationTestCase; 43import android.test.suitebuilder.annotation.SmallTest; 44import android.widget.RemoteViews; 45 46import com.android.internal.appwidget.IAppWidgetHost; 47import com.android.server.LocalServices; 48 49import org.mockito.ArgumentCaptor; 50 51import java.util.Iterator; 52import java.util.List; 53import java.util.Random; 54import java.util.concurrent.CountDownLatch; 55 56 57/** 58 * Tests for {@link AppWidgetManager} and {@link AppWidgetServiceImpl}. 59 * 60 m FrameworksServicesTests && 61 adb install \ 62 -r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk && 63 adb shell am instrument -e class com.android.server.appwidget.AppWidgetServiceImplTest \ 64 -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner 65 */ 66@SmallTest 67public class AppWidgetServiceImplTest extends InstrumentationTestCase { 68 69 private static final int HOST_ID = 42; 70 71 private TestContext mTestContext; 72 private String mPkgName; 73 private AppWidgetServiceImpl mService; 74 private AppWidgetManager mManager; 75 76 private ShortcutServiceInternal mMockShortcutService; 77 private IAppWidgetHost mMockHost; 78 79 @Override 80 protected void setUp() throws Exception { 81 super.setUp(); 82 LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class); 83 LocalServices.removeServiceForTest(ShortcutServiceInternal.class); 84 85 mTestContext = new TestContext(); 86 mPkgName = mTestContext.getOpPackageName(); 87 mService = new AppWidgetServiceImpl(mTestContext); 88 mManager = new AppWidgetManager(mTestContext, mService); 89 90 mMockShortcutService = mock(ShortcutServiceInternal.class); 91 mMockHost = mock(IAppWidgetHost.class); 92 LocalServices.addService(ShortcutServiceInternal.class, mMockShortcutService); 93 mService.onStart(); 94 } 95 96 public void testRequestPinAppWidget_otherProvider() { 97 ComponentName otherProvider = null; 98 for (AppWidgetProviderInfo provider : mManager.getInstalledProviders()) { 99 if (!provider.provider.getPackageName().equals(mTestContext.getPackageName())) { 100 otherProvider = provider.provider; 101 break; 102 } 103 } 104 if (otherProvider == null) { 105 // No other provider found. Ignore this test. 106 } 107 assertFalse(mManager.requestPinAppWidget(otherProvider, null, null)); 108 } 109 110 public void testRequestPinAppWidget() { 111 ComponentName provider = new ComponentName(mTestContext, DummyAppWidget.class); 112 // Set up users. 113 when(mMockShortcutService.requestPinAppWidget(anyString(), 114 any(AppWidgetProviderInfo.class), eq(null), eq(null), anyInt())) 115 .thenReturn(true); 116 assertTrue(mManager.requestPinAppWidget(provider, null, null)); 117 118 final ArgumentCaptor<AppWidgetProviderInfo> providerCaptor = 119 ArgumentCaptor.forClass(AppWidgetProviderInfo.class); 120 verify(mMockShortcutService, times(1)).requestPinAppWidget(anyString(), 121 providerCaptor.capture(), eq(null), eq(null), anyInt()); 122 assertEquals(provider, providerCaptor.getValue().provider); 123 } 124 125 public void testIsRequestPinAppWidgetSupported() { 126 // Set up users. 127 when(mMockShortcutService.isRequestPinItemSupported(anyInt(), anyInt())) 128 .thenReturn(true, false); 129 assertTrue(mManager.isRequestPinAppWidgetSupported()); 130 assertFalse(mManager.isRequestPinAppWidgetSupported()); 131 132 verify(mMockShortcutService, times(2)).isRequestPinItemSupported(anyInt(), 133 eq(LauncherApps.PinItemRequest.REQUEST_TYPE_APPWIDGET)); 134 } 135 136 public void testProviderUpdatesReceived() throws Exception { 137 int widgetId = setupHostAndWidget(); 138 RemoteViews view = new RemoteViews(mPkgName, android.R.layout.simple_list_item_1); 139 mManager.updateAppWidget(widgetId, view); 140 mManager.updateAppWidget(widgetId, view); 141 mManager.updateAppWidget(widgetId, view); 142 mManager.updateAppWidget(widgetId, view); 143 144 flushMainThread(); 145 verify(mMockHost, times(4)).updateAppWidget(eq(widgetId), any(RemoteViews.class)); 146 147 reset(mMockHost); 148 mManager.notifyAppWidgetViewDataChanged(widgetId, 22); 149 flushMainThread(); 150 verify(mMockHost, times(1)).viewDataChanged(eq(widgetId), eq(22)); 151 } 152 153 public void testProviderUpdatesNotReceived() throws Exception { 154 int widgetId = setupHostAndWidget(); 155 mService.stopListening(mPkgName, HOST_ID); 156 RemoteViews view = new RemoteViews(mPkgName, android.R.layout.simple_list_item_1); 157 mManager.updateAppWidget(widgetId, view); 158 mManager.notifyAppWidgetViewDataChanged(widgetId, 22); 159 160 flushMainThread(); 161 verify(mMockHost, times(0)).updateAppWidget(anyInt(), any(RemoteViews.class)); 162 verify(mMockHost, times(0)).viewDataChanged(anyInt(), eq(22)); 163 } 164 165 public void testNoUpdatesReceived_queueEmpty() { 166 int widgetId = setupHostAndWidget(); 167 RemoteViews view = new RemoteViews(mPkgName, android.R.layout.simple_list_item_1); 168 mManager.updateAppWidget(widgetId, view); 169 mManager.notifyAppWidgetViewDataChanged(widgetId, 22); 170 mService.stopListening(mPkgName, HOST_ID); 171 172 List<PendingHostUpdate> updates = mService.startListening( 173 mMockHost, mPkgName, HOST_ID, new int[0]).getList(); 174 assertTrue(updates.isEmpty()); 175 } 176 177 /** 178 * Sends dummy widget updates to {@link #mManager}. 179 * @param widgetId widget to update 180 * @param viewIds a list of view ids for which 181 * {@link AppWidgetManager#notifyAppWidgetViewDataChanged} will be called 182 */ 183 private void sendDummyUpdates(int widgetId, int... viewIds) { 184 Random r = new Random(); 185 RemoteViews view = new RemoteViews(mPkgName, android.R.layout.simple_list_item_1); 186 for (int i = r.nextInt(10) + 2; i >= 0; i--) { 187 mManager.updateAppWidget(widgetId, view); 188 } 189 190 for (int viewId : viewIds) { 191 mManager.notifyAppWidgetViewDataChanged(widgetId, viewId); 192 for (int i = r.nextInt(3); i >= 0; i--) { 193 mManager.updateAppWidget(widgetId, view); 194 } 195 } 196 } 197 198 public void testNoUpdatesReceived_queueNonEmpty_noWidgetId() { 199 int widgetId = setupHostAndWidget(); 200 mService.stopListening(mPkgName, HOST_ID); 201 202 sendDummyUpdates(widgetId, 22, 23); 203 List<PendingHostUpdate> updates = mService.startListening( 204 mMockHost, mPkgName, HOST_ID, new int[0]).getList(); 205 assertTrue(updates.isEmpty()); 206 } 207 208 public void testUpdatesReceived_queueNotEmpty_widgetIdProvided() { 209 int widgetId = setupHostAndWidget(); 210 int widgetId2 = bindNewWidget(); 211 mService.stopListening(mPkgName, HOST_ID); 212 213 sendDummyUpdates(widgetId, 22, 23); 214 sendDummyUpdates(widgetId2, 100, 101, 102); 215 216 List<PendingHostUpdate> updates = mService.startListening( 217 mMockHost, mPkgName, HOST_ID, new int[]{widgetId}).getList(); 218 // 3 updates corresponding to the first widget 219 assertEquals(3, updates.size()); 220 } 221 222 public void testUpdatesReceived_queueNotEmpty_widgetIdProvided2() { 223 int widgetId = setupHostAndWidget(); 224 int widgetId2 = bindNewWidget(); 225 mService.stopListening(mPkgName, HOST_ID); 226 227 sendDummyUpdates(widgetId, 22, 23); 228 sendDummyUpdates(widgetId2, 100, 101, 102); 229 230 List<PendingHostUpdate> updates = mService.startListening( 231 mMockHost, mPkgName, HOST_ID, new int[]{widgetId2}).getList(); 232 // 4 updates corresponding to the second widget 233 assertEquals(4, updates.size()); 234 } 235 236 public void testUpdatesReceived_queueNotEmpty_multipleWidgetIdProvided() { 237 int widgetId = setupHostAndWidget(); 238 int widgetId2 = bindNewWidget(); 239 mService.stopListening(mPkgName, HOST_ID); 240 241 sendDummyUpdates(widgetId, 22, 23); 242 sendDummyUpdates(widgetId2, 100, 101, 102); 243 244 List<PendingHostUpdate> updates = mService.startListening( 245 mMockHost, mPkgName, HOST_ID, new int[]{widgetId, widgetId2}).getList(); 246 // 3 updates for first widget and 4 for second 247 assertEquals(7, updates.size()); 248 } 249 250 public void testUpdatesReceived_queueEmptyAfterStartListening() { 251 int widgetId = setupHostAndWidget(); 252 int widgetId2 = bindNewWidget(); 253 mService.stopListening(mPkgName, HOST_ID); 254 255 sendDummyUpdates(widgetId, 22, 23); 256 sendDummyUpdates(widgetId2, 100, 101, 102); 257 258 List<PendingHostUpdate> updates = mService.startListening( 259 mMockHost, mPkgName, HOST_ID, new int[]{widgetId, widgetId2}).getList(); 260 // 3 updates for first widget and 4 for second 261 assertEquals(7, updates.size()); 262 263 // Stop and start listening again 264 mService.stopListening(mPkgName, HOST_ID); 265 updates = mService.startListening( 266 mMockHost, mPkgName, HOST_ID, new int[]{widgetId, widgetId2}).getList(); 267 assertTrue(updates.isEmpty()); 268 } 269 270 public void testGetInstalledProvidersForPackage() { 271 List<AppWidgetProviderInfo> allProviders = mManager.getInstalledProviders(); 272 assertTrue(!allProviders.isEmpty()); 273 String packageName = allProviders.get(0).provider.getPackageName(); 274 List<AppWidgetProviderInfo> providersForPackage = mManager.getInstalledProvidersForPackage( 275 packageName, null); 276 // Remove providers from allProviders that don't have the given package name. 277 Iterator<AppWidgetProviderInfo> iter = allProviders.iterator(); 278 while (iter.hasNext()) { 279 if (!iter.next().provider.getPackageName().equals(packageName)) { 280 iter.remove(); 281 } 282 } 283 assertEquals(allProviders.size(), providersForPackage.size()); 284 for (int i = 0; i < allProviders.size(); i++) { 285 assertEquals(allProviders.get(i).provider, providersForPackage.get(i).provider); 286 } 287 } 288 289 private int setupHostAndWidget() { 290 List<PendingHostUpdate> updates = mService.startListening( 291 mMockHost, mPkgName, HOST_ID, new int[0]).getList(); 292 assertTrue(updates.isEmpty()); 293 return bindNewWidget(); 294 } 295 296 private int bindNewWidget() { 297 ComponentName provider = new ComponentName(mTestContext, DummyAppWidget.class); 298 int widgetId = mService.allocateAppWidgetId(mPkgName, HOST_ID); 299 assertTrue(mManager.bindAppWidgetIdIfAllowed(widgetId, provider)); 300 assertEquals(provider, mManager.getAppWidgetInfo(widgetId).provider); 301 302 return widgetId; 303 } 304 305 private void flushMainThread() throws Exception { 306 CountDownLatch latch = new CountDownLatch(1); 307 new Handler(mTestContext.getMainLooper()).post(latch::countDown); 308 latch.await(); 309 } 310 311 private class TestContext extends ContextWrapper { 312 313 public TestContext() { 314 super(getInstrumentation().getContext()); 315 } 316 317 @Override 318 public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user, 319 IntentFilter filter, String broadcastPermission, Handler scheduler) { 320 // ignore. 321 return null; 322 } 323 324 @Override 325 public void unregisterReceiver(BroadcastReceiver receiver) { 326 // ignore. 327 } 328 329 @Override 330 public void enforceCallingOrSelfPermission(String permission, String message) { 331 // ignore. 332 } 333 334 @Override 335 public void sendBroadcastAsUser(Intent intent, UserHandle user) { 336 // ignore. 337 } 338 } 339} 340