ComponentContextFixture.java revision ecda55454f4993003e71e09a63d20f94a216cc47
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 17package com.android.server.telecom.tests; 18 19import com.google.common.collect.ArrayListMultimap; 20import com.google.common.collect.Multimap; 21 22import com.android.internal.telecom.IConnectionService; 23import com.android.internal.telecom.IInCallService; 24import com.android.server.telecom.Log; 25 26import org.mockito.MockitoAnnotations; 27import org.mockito.invocation.InvocationOnMock; 28import org.mockito.stubbing.Answer; 29 30import android.app.AppOpsManager; 31import android.app.NotificationManager; 32import android.app.StatusBarManager; 33import android.content.BroadcastReceiver; 34import android.content.ComponentName; 35import android.content.ContentResolver; 36import android.content.Context; 37import android.content.IContentProvider; 38import android.content.Intent; 39import android.content.IntentFilter; 40import android.content.ServiceConnection; 41import android.content.pm.PackageManager; 42import android.content.pm.ResolveInfo; 43import android.content.pm.ServiceInfo; 44import android.content.res.Configuration; 45import android.content.res.Resources; 46import android.media.AudioManager; 47import android.os.Bundle; 48import android.os.Handler; 49import android.os.IInterface; 50import android.os.UserHandle; 51import android.os.UserManager; 52import android.telecom.CallAudioState; 53import android.telecom.ConnectionService; 54import android.telecom.InCallService; 55import android.telecom.PhoneAccount; 56import android.telecom.TelecomManager; 57import android.telephony.CarrierConfigManager; 58import android.telephony.SubscriptionManager; 59import android.telephony.TelephonyManager; 60import android.test.mock.MockContext; 61 62import java.io.File; 63import java.io.IOException; 64import java.util.ArrayList; 65import java.util.Arrays; 66import java.util.HashMap; 67import java.util.List; 68import java.util.Locale; 69import java.util.Map; 70 71import static org.mockito.Matchers.anyString; 72import static org.mockito.Mockito.any; 73import static org.mockito.Mockito.anyInt; 74import static org.mockito.Mockito.doAnswer; 75import static org.mockito.Mockito.doReturn; 76import static org.mockito.Mockito.eq; 77import static org.mockito.Mockito.mock; 78import static org.mockito.Mockito.spy; 79import static org.mockito.Mockito.when; 80 81/** 82 * Controls a test {@link Context} as would be provided by the Android framework to an 83 * {@code Activity}, {@code Service} or other system-instantiated component. 84 * 85 * The {@link Context} created by this object is "hollow" but its {@code applicationContext} 86 * property points to an application context implementing all the nontrivial functionality. 87 */ 88public class ComponentContextFixture implements TestFixture<Context> { 89 90 public class FakeApplicationContext extends MockContext { 91 @Override 92 public PackageManager getPackageManager() { 93 return mPackageManager; 94 } 95 96 @Override 97 public String getPackageName() { 98 return "com.android.server.telecom.tests"; 99 } 100 101 @Override 102 public String getPackageResourcePath() { 103 return "/tmp/i/dont/know"; 104 } 105 106 @Override 107 public Context getApplicationContext() { 108 return mApplicationContextSpy; 109 } 110 111 @Override 112 public File getFilesDir() { 113 try { 114 return File.createTempFile("temp", "temp").getParentFile(); 115 } catch (IOException e) { 116 throw new RuntimeException(e); 117 } 118 } 119 120 @Override 121 public boolean bindServiceAsUser( 122 Intent serviceIntent, 123 ServiceConnection connection, 124 int flags, 125 UserHandle userHandle) { 126 // TODO: Implement "as user" functionality 127 return bindService(serviceIntent, connection, flags); 128 } 129 130 @Override 131 public boolean bindService( 132 Intent serviceIntent, 133 ServiceConnection connection, 134 int flags) { 135 if (mServiceByServiceConnection.containsKey(connection)) { 136 throw new RuntimeException("ServiceConnection already bound: " + connection); 137 } 138 IInterface service = mServiceByComponentName.get(serviceIntent.getComponent()); 139 if (service == null) { 140 throw new RuntimeException("ServiceConnection not found: " 141 + serviceIntent.getComponent()); 142 } 143 mServiceByServiceConnection.put(connection, service); 144 connection.onServiceConnected(serviceIntent.getComponent(), service.asBinder()); 145 return true; 146 } 147 148 @Override 149 public void unbindService( 150 ServiceConnection connection) { 151 IInterface service = mServiceByServiceConnection.remove(connection); 152 if (service == null) { 153 throw new RuntimeException("ServiceConnection not found: " + connection); 154 } 155 connection.onServiceDisconnected(mComponentNameByService.get(service)); 156 } 157 158 @Override 159 public Object getSystemService(String name) { 160 switch (name) { 161 case Context.AUDIO_SERVICE: 162 return mAudioManager; 163 case Context.TELEPHONY_SERVICE: 164 return mTelephonyManager; 165 case Context.APP_OPS_SERVICE: 166 return mAppOpsManager; 167 case Context.NOTIFICATION_SERVICE: 168 return mNotificationManager; 169 case Context.STATUS_BAR_SERVICE: 170 return mStatusBarManager; 171 case Context.USER_SERVICE: 172 return mUserManager; 173 case Context.TELEPHONY_SUBSCRIPTION_SERVICE: 174 return mSubscriptionManager; 175 case Context.TELECOM_SERVICE: 176 return mTelecomManager; 177 case Context.CARRIER_CONFIG_SERVICE: 178 return mCarrierConfigManager; 179 default: 180 return null; 181 } 182 } 183 184 @Override 185 public int getUserId() { 186 return 0; 187 } 188 189 @Override 190 public Resources getResources() { 191 return mResources; 192 } 193 194 @Override 195 public String getOpPackageName() { 196 return "com.android.server.telecom.tests"; 197 } 198 199 @Override 200 public ContentResolver getContentResolver() { 201 return new ContentResolver(mApplicationContextSpy) { 202 @Override 203 protected IContentProvider acquireProvider(Context c, String name) { 204 Log.i(this, "acquireProvider %s", name); 205 return mContentProvider; 206 } 207 208 @Override 209 public boolean releaseProvider(IContentProvider icp) { 210 return true; 211 } 212 213 @Override 214 protected IContentProvider acquireUnstableProvider(Context c, String name) { 215 Log.i(this, "acquireUnstableProvider %s", name); 216 return mContentProvider; 217 } 218 219 @Override 220 public boolean releaseUnstableProvider(IContentProvider icp) { 221 return false; 222 } 223 224 @Override 225 public void unstableProviderDied(IContentProvider icp) { 226 } 227 }; 228 } 229 230 @Override 231 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { 232 // TODO -- this is called by WiredHeadsetManager!!! 233 return null; 234 } 235 236 @Override 237 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, 238 String broadcastPermission, Handler scheduler) { 239 return null; 240 } 241 242 @Override 243 public void sendBroadcast(Intent intent) { 244 // TODO -- need to ensure this is captured 245 } 246 247 @Override 248 public void sendBroadcast(Intent intent, String receiverPermission) { 249 // TODO -- need to ensure this is captured 250 } 251 252 @Override 253 public void sendBroadcastAsUser(Intent intent, UserHandle userHandle) { 254 // TODO -- need to ensure this is captured 255 } 256 257 @Override 258 public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, 259 String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, 260 int initialCode, String initialData, Bundle initialExtras) { 261 // TODO -- need to ensure this is captured 262 } 263 264 @Override 265 public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, 266 String receiverPermission, int appOp, BroadcastReceiver resultReceiver, 267 Handler scheduler, int initialCode, String initialData, Bundle initialExtras) { 268 } 269 270 @Override 271 public Context createPackageContextAsUser(String packageName, int flags, UserHandle user) 272 throws PackageManager.NameNotFoundException { 273 return this; 274 } 275 276 @Override 277 public int checkCallingOrSelfPermission(String permission) { 278 return PackageManager.PERMISSION_GRANTED; 279 } 280 281 @Override 282 public void enforceCallingOrSelfPermission(String permission, String message) { 283 // Don't bother enforcing anything in mock. 284 } 285 286 /** 287 * Used to work around a Mockito/ART bug. If you remove any of these, tests will fail. 288 */ 289 }; 290 291 public class FakeAudioManager extends AudioManager { 292 293 private boolean mMute = false; 294 private boolean mSpeakerphoneOn = false; 295 private int mAudioStreamValue = 1; 296 private int mMode = AudioManager.MODE_NORMAL; 297 private int mRingerMode = AudioManager.RINGER_MODE_NORMAL; 298 299 public FakeAudioManager(Context context) { 300 super(context); 301 } 302 303 @Override 304 public void setMicrophoneMute(boolean value) { 305 mMute = value; 306 } 307 308 @Override 309 public boolean isMicrophoneMute() { 310 return mMute; 311 } 312 313 @Override 314 public void setSpeakerphoneOn(boolean value) { 315 mSpeakerphoneOn = value; 316 } 317 318 @Override 319 public boolean isSpeakerphoneOn() { 320 return mSpeakerphoneOn; 321 } 322 323 @Override 324 public void setMode(int mode) { 325 mMode = mode; 326 } 327 328 @Override 329 public int getMode() { 330 return mMode; 331 } 332 333 @Override 334 public void setRingerModeInternal(int ringerMode) { 335 mRingerMode = ringerMode; 336 } 337 338 @Override 339 public int getRingerModeInternal() { 340 return mRingerMode; 341 } 342 343 @Override 344 public void setStreamVolume(int streamTypeUnused, int index, int flagsUnused){ 345 mAudioStreamValue = index; 346 } 347 348 @Override 349 public int getStreamVolume(int streamValueUnused) { 350 return mAudioStreamValue; 351 } 352 } 353 354 private final Multimap<String, ComponentName> mComponentNamesByAction = 355 ArrayListMultimap.create(); 356 private final Map<ComponentName, IInterface> mServiceByComponentName = new HashMap<>(); 357 private final Map<ComponentName, ServiceInfo> mServiceInfoByComponentName = new HashMap<>(); 358 private final Map<IInterface, ComponentName> mComponentNameByService = new HashMap<>(); 359 private final Map<ServiceConnection, IInterface> mServiceByServiceConnection = new HashMap<>(); 360 361 private final Context mContext = new MockContext() { 362 @Override 363 public Context getApplicationContext() { 364 return mApplicationContextSpy; 365 } 366 367 @Override 368 public Resources getResources() { 369 return mResources; 370 } 371 }; 372 373 // The application context is the most important object this class provides to the system 374 // under test. 375 private final Context mApplicationContext = new FakeApplicationContext(); 376 377 // We then create a spy on the application context allowing standard Mockito-style 378 // when(...) logic to be used to add specific little responses where needed. 379 380 private final Resources mResources = mock(Resources.class); 381 private final Context mApplicationContextSpy = spy(mApplicationContext); 382 private final PackageManager mPackageManager = mock(PackageManager.class); 383 private final AudioManager mAudioManager = spy(new FakeAudioManager(mContext)); 384 private final TelephonyManager mTelephonyManager = mock(TelephonyManager.class); 385 private final AppOpsManager mAppOpsManager = mock(AppOpsManager.class); 386 private final NotificationManager mNotificationManager = mock(NotificationManager.class); 387 private final UserManager mUserManager = mock(UserManager.class); 388 private final StatusBarManager mStatusBarManager = mock(StatusBarManager.class); 389 private final SubscriptionManager mSubscriptionManager = mock(SubscriptionManager.class); 390 private final CarrierConfigManager mCarrierConfigManager = mock(CarrierConfigManager.class); 391 private final IContentProvider mContentProvider = mock(IContentProvider.class); 392 private final Configuration mResourceConfiguration = new Configuration(); 393 394 private TelecomManager mTelecomManager = null; 395 396 public ComponentContextFixture() { 397 MockitoAnnotations.initMocks(this); 398 when(mResources.getConfiguration()).thenReturn(mResourceConfiguration); 399 mResourceConfiguration.setLocale(Locale.TAIWAN); 400 401 // TODO: Move into actual tests 402 when(mAudioManager.isWiredHeadsetOn()).thenReturn(false); 403 404 doAnswer(new Answer<List<ResolveInfo>>() { 405 @Override 406 public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable { 407 return doQueryIntentServices( 408 (Intent) invocation.getArguments()[0], 409 (Integer) invocation.getArguments()[1]); 410 } 411 }).when(mPackageManager).queryIntentServices((Intent) any(), anyInt()); 412 413 doAnswer(new Answer<List<ResolveInfo>>() { 414 @Override 415 public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable { 416 return doQueryIntentServices( 417 (Intent) invocation.getArguments()[0], 418 (Integer) invocation.getArguments()[1]); 419 } 420 }).when(mPackageManager).queryIntentServicesAsUser((Intent) any(), anyInt(), anyInt()); 421 422 when(mTelephonyManager.getSubIdForPhoneAccount((PhoneAccount) any())).thenReturn(1); 423 424 when(mTelephonyManager.getNetworkOperatorName()).thenReturn("label1"); 425 426 doAnswer(new Answer<Void>(){ 427 @Override 428 public Void answer(InvocationOnMock invocation) throws Throwable { 429 return null; 430 } 431 }).when(mAppOpsManager).checkPackage(anyInt(), anyString()); 432 433 when(mNotificationManager.matchesCallFilter(any(Bundle.class))).thenReturn(true); 434 435 when(mUserManager.getSerialNumberForUser(any(UserHandle.class))).thenReturn(-1L); 436 437 doReturn(null).when(mApplicationContextSpy).registerReceiver(any(BroadcastReceiver.class), 438 any(IntentFilter.class)); 439 } 440 441 @Override 442 public Context getTestDouble() { 443 return mContext; 444 } 445 446 public void addConnectionService( 447 ComponentName componentName, 448 IConnectionService service) 449 throws Exception { 450 addService(ConnectionService.SERVICE_INTERFACE, componentName, service); 451 ServiceInfo serviceInfo = new ServiceInfo(); 452 serviceInfo.permission = android.Manifest.permission.BIND_CONNECTION_SERVICE; 453 serviceInfo.packageName = componentName.getPackageName(); 454 serviceInfo.name = componentName.getClassName(); 455 mServiceInfoByComponentName.put(componentName, serviceInfo); 456 } 457 458 public void addInCallService( 459 ComponentName componentName, 460 IInCallService service) 461 throws Exception { 462 addService(InCallService.SERVICE_INTERFACE, componentName, service); 463 ServiceInfo serviceInfo = new ServiceInfo(); 464 serviceInfo.permission = android.Manifest.permission.BIND_INCALL_SERVICE; 465 serviceInfo.packageName = componentName.getPackageName(); 466 serviceInfo.name = componentName.getClassName(); 467 mServiceInfoByComponentName.put(componentName, serviceInfo); 468 } 469 470 public void putResource(int id, final String value) { 471 when(mResources.getText(eq(id))).thenReturn(value); 472 when(mResources.getString(eq(id))).thenReturn(value); 473 when(mResources.getString(eq(id), any())).thenAnswer(new Answer<String>() { 474 @Override 475 public String answer(InvocationOnMock invocation) { 476 Object[] args = invocation.getArguments(); 477 return String.format(value, Arrays.copyOfRange(args, 1, args.length)); 478 } 479 }); 480 } 481 482 public void putBooleanResource(int id, boolean value) { 483 when(mResources.getBoolean(eq(id))).thenReturn(value); 484 } 485 486 public void setTelecomManager(TelecomManager telecomManager) { 487 mTelecomManager = telecomManager; 488 } 489 490 private void addService(String action, ComponentName name, IInterface service) { 491 mComponentNamesByAction.put(action, name); 492 mServiceByComponentName.put(name, service); 493 mComponentNameByService.put(service, name); 494 } 495 496 private List<ResolveInfo> doQueryIntentServices(Intent intent, int flags) { 497 List<ResolveInfo> result = new ArrayList<>(); 498 for (ComponentName componentName : mComponentNamesByAction.get(intent.getAction())) { 499 ResolveInfo resolveInfo = new ResolveInfo(); 500 resolveInfo.serviceInfo = mServiceInfoByComponentName.get(componentName); 501 result.add(resolveInfo); 502 } 503 return result; 504 } 505} 506