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