ComponentContextFixture.java revision c6e42ef0465fe01b35bb3aa94fbcbc081e3b45ed
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 String getSystemServiceName(Class<?> svcClass) { 186 if (svcClass == UserManager.class) { 187 return Context.USER_SERVICE; 188 } 189 throw new UnsupportedOperationException(); 190 } 191 192 @Override 193 public int getUserId() { 194 return 0; 195 } 196 197 @Override 198 public Resources getResources() { 199 return mResources; 200 } 201 202 @Override 203 public String getOpPackageName() { 204 return "com.android.server.telecom.tests"; 205 } 206 207 @Override 208 public ContentResolver getContentResolver() { 209 return new ContentResolver(mApplicationContextSpy) { 210 @Override 211 protected IContentProvider acquireProvider(Context c, String name) { 212 Log.i(this, "acquireProvider %s", name); 213 return getOrCreateProvider(name); 214 } 215 216 @Override 217 public boolean releaseProvider(IContentProvider icp) { 218 return true; 219 } 220 221 @Override 222 protected IContentProvider acquireUnstableProvider(Context c, String name) { 223 Log.i(this, "acquireUnstableProvider %s", name); 224 return getOrCreateProvider(name); 225 } 226 227 private IContentProvider getOrCreateProvider(String name) { 228 if (!mIContentProviderByUri.containsKey(name)) { 229 mIContentProviderByUri.put(name, mock(IContentProvider.class)); 230 } 231 return mIContentProviderByUri.get(name); 232 } 233 234 @Override 235 public boolean releaseUnstableProvider(IContentProvider icp) { 236 return false; 237 } 238 239 @Override 240 public void unstableProviderDied(IContentProvider icp) { 241 } 242 }; 243 } 244 245 @Override 246 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { 247 // TODO -- this is called by WiredHeadsetManager!!! 248 return null; 249 } 250 251 @Override 252 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, 253 String broadcastPermission, Handler scheduler) { 254 return null; 255 } 256 257 @Override 258 public void sendBroadcast(Intent intent) { 259 // TODO -- need to ensure this is captured 260 } 261 262 @Override 263 public void sendBroadcast(Intent intent, String receiverPermission) { 264 // TODO -- need to ensure this is captured 265 } 266 267 @Override 268 public void sendBroadcastAsUser(Intent intent, UserHandle userHandle) { 269 // TODO -- need to ensure this is captured 270 } 271 272 @Override 273 public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, 274 String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, 275 int initialCode, String initialData, Bundle initialExtras) { 276 // TODO -- need to ensure this is captured 277 } 278 279 @Override 280 public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, 281 String receiverPermission, int appOp, BroadcastReceiver resultReceiver, 282 Handler scheduler, int initialCode, String initialData, Bundle initialExtras) { 283 } 284 285 @Override 286 public Context createPackageContextAsUser(String packageName, int flags, UserHandle user) 287 throws PackageManager.NameNotFoundException { 288 return this; 289 } 290 291 @Override 292 public int checkCallingOrSelfPermission(String permission) { 293 return PackageManager.PERMISSION_GRANTED; 294 } 295 296 @Override 297 public void enforceCallingOrSelfPermission(String permission, String message) { 298 // Don't bother enforcing anything in mock. 299 } 300 301 @Override 302 public void startActivityAsUser(Intent intent, UserHandle userHandle) { 303 // For capturing 304 } 305 } 306 307 public class FakeAudioManager extends AudioManager { 308 309 private boolean mMute = false; 310 private boolean mSpeakerphoneOn = false; 311 private int mAudioStreamValue = 1; 312 private int mMode = AudioManager.MODE_NORMAL; 313 private int mRingerMode = AudioManager.RINGER_MODE_NORMAL; 314 315 public FakeAudioManager(Context context) { 316 super(context); 317 } 318 319 @Override 320 public void setMicrophoneMute(boolean value) { 321 mMute = value; 322 } 323 324 @Override 325 public boolean isMicrophoneMute() { 326 return mMute; 327 } 328 329 @Override 330 public void setSpeakerphoneOn(boolean value) { 331 mSpeakerphoneOn = value; 332 } 333 334 @Override 335 public boolean isSpeakerphoneOn() { 336 return mSpeakerphoneOn; 337 } 338 339 @Override 340 public void setMode(int mode) { 341 mMode = mode; 342 } 343 344 @Override 345 public int getMode() { 346 return mMode; 347 } 348 349 @Override 350 public void setRingerModeInternal(int ringerMode) { 351 mRingerMode = ringerMode; 352 } 353 354 @Override 355 public int getRingerModeInternal() { 356 return mRingerMode; 357 } 358 359 @Override 360 public void setStreamVolume(int streamTypeUnused, int index, int flagsUnused){ 361 mAudioStreamValue = index; 362 } 363 364 @Override 365 public int getStreamVolume(int streamValueUnused) { 366 return mAudioStreamValue; 367 } 368 } 369 370 private final Multimap<String, ComponentName> mComponentNamesByAction = 371 ArrayListMultimap.create(); 372 private final Map<ComponentName, IInterface> mServiceByComponentName = new HashMap<>(); 373 private final Map<ComponentName, ServiceInfo> mServiceInfoByComponentName = new HashMap<>(); 374 private final Map<IInterface, ComponentName> mComponentNameByService = new HashMap<>(); 375 private final Map<ServiceConnection, IInterface> mServiceByServiceConnection = new HashMap<>(); 376 377 private final Context mContext = new MockContext() { 378 @Override 379 public Context getApplicationContext() { 380 return mApplicationContextSpy; 381 } 382 383 @Override 384 public Resources getResources() { 385 return mResources; 386 } 387 }; 388 389 // The application context is the most important object this class provides to the system 390 // under test. 391 private final Context mApplicationContext = new FakeApplicationContext(); 392 393 // We then create a spy on the application context allowing standard Mockito-style 394 // when(...) logic to be used to add specific little responses where needed. 395 396 private final Resources mResources = mock(Resources.class); 397 private final Context mApplicationContextSpy = spy(mApplicationContext); 398 private final PackageManager mPackageManager = mock(PackageManager.class); 399 private final AudioManager mAudioManager = spy(new FakeAudioManager(mContext)); 400 private final TelephonyManager mTelephonyManager = mock(TelephonyManager.class); 401 private final AppOpsManager mAppOpsManager = mock(AppOpsManager.class); 402 private final NotificationManager mNotificationManager = mock(NotificationManager.class); 403 private final UserManager mUserManager = mock(UserManager.class); 404 private final StatusBarManager mStatusBarManager = mock(StatusBarManager.class); 405 private final SubscriptionManager mSubscriptionManager = mock(SubscriptionManager.class); 406 private final CarrierConfigManager mCarrierConfigManager = mock(CarrierConfigManager.class); 407 private final Map<String, IContentProvider> mIContentProviderByUri = new HashMap<>(); 408 private final Configuration mResourceConfiguration = new Configuration(); 409 410 private TelecomManager mTelecomManager = null; 411 412 public ComponentContextFixture() { 413 MockitoAnnotations.initMocks(this); 414 when(mResources.getConfiguration()).thenReturn(mResourceConfiguration); 415 mResourceConfiguration.setLocale(Locale.TAIWAN); 416 417 // TODO: Move into actual tests 418 when(mAudioManager.isWiredHeadsetOn()).thenReturn(false); 419 420 doAnswer(new Answer<List<ResolveInfo>>() { 421 @Override 422 public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable { 423 return doQueryIntentServices( 424 (Intent) invocation.getArguments()[0], 425 (Integer) invocation.getArguments()[1]); 426 } 427 }).when(mPackageManager).queryIntentServices((Intent) any(), anyInt()); 428 429 doAnswer(new Answer<List<ResolveInfo>>() { 430 @Override 431 public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable { 432 return doQueryIntentServices( 433 (Intent) invocation.getArguments()[0], 434 (Integer) invocation.getArguments()[1]); 435 } 436 }).when(mPackageManager).queryIntentServicesAsUser((Intent) any(), anyInt(), anyInt()); 437 438 when(mTelephonyManager.getSubIdForPhoneAccount((PhoneAccount) any())).thenReturn(1); 439 440 when(mTelephonyManager.getNetworkOperatorName()).thenReturn("label1"); 441 442 doAnswer(new Answer<Void>(){ 443 @Override 444 public Void answer(InvocationOnMock invocation) throws Throwable { 445 return null; 446 } 447 }).when(mAppOpsManager).checkPackage(anyInt(), anyString()); 448 449 when(mNotificationManager.matchesCallFilter(any(Bundle.class))).thenReturn(true); 450 451 when(mUserManager.getSerialNumberForUser(any(UserHandle.class))).thenReturn(-1L); 452 453 doReturn(null).when(mApplicationContextSpy).registerReceiver(any(BroadcastReceiver.class), 454 any(IntentFilter.class)); 455 } 456 457 @Override 458 public Context getTestDouble() { 459 return mContext; 460 } 461 462 public void addConnectionService( 463 ComponentName componentName, 464 IConnectionService service) 465 throws Exception { 466 addService(ConnectionService.SERVICE_INTERFACE, componentName, service); 467 ServiceInfo serviceInfo = new ServiceInfo(); 468 serviceInfo.permission = android.Manifest.permission.BIND_CONNECTION_SERVICE; 469 serviceInfo.packageName = componentName.getPackageName(); 470 serviceInfo.name = componentName.getClassName(); 471 mServiceInfoByComponentName.put(componentName, serviceInfo); 472 } 473 474 public void addInCallService( 475 ComponentName componentName, 476 IInCallService service) 477 throws Exception { 478 addService(InCallService.SERVICE_INTERFACE, componentName, service); 479 ServiceInfo serviceInfo = new ServiceInfo(); 480 serviceInfo.permission = android.Manifest.permission.BIND_INCALL_SERVICE; 481 serviceInfo.packageName = componentName.getPackageName(); 482 serviceInfo.name = componentName.getClassName(); 483 mServiceInfoByComponentName.put(componentName, serviceInfo); 484 } 485 486 public void putResource(int id, final String value) { 487 when(mResources.getText(eq(id))).thenReturn(value); 488 when(mResources.getString(eq(id))).thenReturn(value); 489 when(mResources.getString(eq(id), any())).thenAnswer(new Answer<String>() { 490 @Override 491 public String answer(InvocationOnMock invocation) { 492 Object[] args = invocation.getArguments(); 493 return String.format(value, Arrays.copyOfRange(args, 1, args.length)); 494 } 495 }); 496 } 497 498 public void putBooleanResource(int id, boolean value) { 499 when(mResources.getBoolean(eq(id))).thenReturn(value); 500 } 501 502 public void setTelecomManager(TelecomManager telecomManager) { 503 mTelecomManager = telecomManager; 504 } 505 506 private void addService(String action, ComponentName name, IInterface service) { 507 mComponentNamesByAction.put(action, name); 508 mServiceByComponentName.put(name, service); 509 mComponentNameByService.put(service, name); 510 } 511 512 private List<ResolveInfo> doQueryIntentServices(Intent intent, int flags) { 513 List<ResolveInfo> result = new ArrayList<>(); 514 for (ComponentName componentName : mComponentNamesByAction.get(intent.getAction())) { 515 ResolveInfo resolveInfo = new ResolveInfo(); 516 resolveInfo.serviceInfo = mServiceInfoByComponentName.get(componentName); 517 result.add(resolveInfo); 518 } 519 return result; 520 } 521} 522