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