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