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 getPackageManager()95 public PackageManager getPackageManager() { 96 return mPackageManager; 97 } 98 99 @Override getPackageName()100 public String getPackageName() { 101 return "com.android.server.telecom.tests"; 102 } 103 104 @Override getPackageResourcePath()105 public String getPackageResourcePath() { 106 return "/tmp/i/dont/know"; 107 } 108 109 @Override getApplicationContext()110 public Context getApplicationContext() { 111 return mApplicationContextSpy; 112 } 113 114 @Override getFilesDir()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 bindServiceAsUser( Intent serviceIntent, ServiceConnection connection, int flags, UserHandle userHandle)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 bindService( Intent serviceIntent, ServiceConnection connection, int flags)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 unbindService( ServiceConnection connection)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 getSystemService(String name)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 getSystemServiceName(Class<?> svcClass)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 getUserId()198 public int getUserId() { 199 return 0; 200 } 201 202 @Override getResources()203 public Resources getResources() { 204 return mResources; 205 } 206 207 @Override getOpPackageName()208 public String getOpPackageName() { 209 return "com.android.server.telecom.tests"; 210 } 211 212 @Override getApplicationInfo()213 public ApplicationInfo getApplicationInfo() { 214 return mTestApplicationInfo; 215 } 216 217 @Override getContentResolver()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 registerReceiver(BroadcastReceiver receiver, IntentFilter filter)256 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { 257 // TODO -- this is called by WiredHeadsetManager!!! 258 return null; 259 } 260 261 @Override registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler)262 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, 263 String broadcastPermission, Handler scheduler) { 264 return null; 265 } 266 267 @Override registerReceiverAsUser(BroadcastReceiver receiver, UserHandle handle, IntentFilter filter, String broadcastPermission, Handler scheduler)268 public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle handle, 269 IntentFilter filter, String broadcastPermission, Handler scheduler) { 270 return null; 271 } 272 273 @Override sendBroadcast(Intent intent)274 public void sendBroadcast(Intent intent) { 275 // TODO -- need to ensure this is captured 276 } 277 278 @Override sendBroadcast(Intent intent, String receiverPermission)279 public void sendBroadcast(Intent intent, String receiverPermission) { 280 // TODO -- need to ensure this is captured 281 } 282 283 @Override sendBroadcastAsUser(Intent intent, UserHandle userHandle)284 public void sendBroadcastAsUser(Intent intent, UserHandle userHandle) { 285 // TODO -- need to ensure this is captured 286 } 287 288 @Override sendOrderedBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)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 sendOrderedBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission, int appOp, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)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 createPackageContextAsUser(String packageName, int flags, UserHandle user)302 public Context createPackageContextAsUser(String packageName, int flags, UserHandle user) 303 throws PackageManager.NameNotFoundException { 304 return this; 305 } 306 307 @Override checkCallingOrSelfPermission(String permission)308 public int checkCallingOrSelfPermission(String permission) { 309 return PackageManager.PERMISSION_GRANTED; 310 } 311 312 @Override enforceCallingOrSelfPermission(String permission, String message)313 public void enforceCallingOrSelfPermission(String permission, String message) { 314 // Don't bother enforcing anything in mock. 315 } 316 317 @Override enforcePermission( String permission, int pid, int uid, String message)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 startActivityAsUser(Intent intent, UserHandle userHandle)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 mResourceConfiguration.setLocale(Locale.TAIWAN); 440 441 // TODO: Move into actual tests 442 when(mAudioManager.isWiredHeadsetOn()).thenReturn(false); 443 444 doAnswer(new Answer<List<ResolveInfo>>() { 445 @Override 446 public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable { 447 return doQueryIntentServices( 448 (Intent) invocation.getArguments()[0], 449 (Integer) invocation.getArguments()[1]); 450 } 451 }).when(mPackageManager).queryIntentServices((Intent) any(), anyInt()); 452 453 doAnswer(new Answer<List<ResolveInfo>>() { 454 @Override 455 public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable { 456 return doQueryIntentServices( 457 (Intent) invocation.getArguments()[0], 458 (Integer) invocation.getArguments()[1]); 459 } 460 }).when(mPackageManager).queryIntentServicesAsUser((Intent) any(), anyInt(), anyInt()); 461 462 when(mTelephonyManager.getSubIdForPhoneAccount((PhoneAccount) any())).thenReturn(1); 463 464 when(mTelephonyManager.getNetworkOperatorName()).thenReturn("label1"); 465 466 doAnswer(new Answer<Void>(){ 467 @Override 468 public Void answer(InvocationOnMock invocation) throws Throwable { 469 return null; 470 } 471 }).when(mAppOpsManager).checkPackage(anyInt(), anyString()); 472 473 when(mNotificationManager.matchesCallFilter(any(Bundle.class))).thenReturn(true); 474 475 when(mUserManager.getSerialNumberForUser(any(UserHandle.class))).thenReturn(-1L); 476 477 doReturn(null).when(mApplicationContextSpy).registerReceiver(any(BroadcastReceiver.class), 478 any(IntentFilter.class)); 479 } 480 481 @Override 482 public Context getTestDouble() { 483 return mContext; 484 } 485 486 public void addConnectionService( 487 ComponentName componentName, 488 IConnectionService service) 489 throws Exception { 490 addService(ConnectionService.SERVICE_INTERFACE, componentName, service); 491 ServiceInfo serviceInfo = new ServiceInfo(); 492 serviceInfo.permission = android.Manifest.permission.BIND_CONNECTION_SERVICE; 493 serviceInfo.packageName = componentName.getPackageName(); 494 serviceInfo.name = componentName.getClassName(); 495 mServiceInfoByComponentName.put(componentName, serviceInfo); 496 } 497 498 public void addInCallService( 499 ComponentName componentName, 500 IInCallService service) 501 throws Exception { 502 addService(InCallService.SERVICE_INTERFACE, componentName, service); 503 ServiceInfo serviceInfo = new ServiceInfo(); 504 serviceInfo.permission = android.Manifest.permission.BIND_INCALL_SERVICE; 505 serviceInfo.packageName = componentName.getPackageName(); 506 serviceInfo.name = componentName.getClassName(); 507 mServiceInfoByComponentName.put(componentName, serviceInfo); 508 } 509 510 public void putResource(int id, final String value) { 511 when(mResources.getText(eq(id))).thenReturn(value); 512 when(mResources.getString(eq(id))).thenReturn(value); 513 when(mResources.getString(eq(id), any())).thenAnswer(new Answer<String>() { 514 @Override 515 public String answer(InvocationOnMock invocation) { 516 Object[] args = invocation.getArguments(); 517 return String.format(value, Arrays.copyOfRange(args, 1, args.length)); 518 } 519 }); 520 } 521 522 public void putBooleanResource(int id, boolean value) { 523 when(mResources.getBoolean(eq(id))).thenReturn(value); 524 } 525 526 public void setTelecomManager(TelecomManager telecomManager) { 527 mTelecomManager = telecomManager; 528 } 529 530 private void addService(String action, ComponentName name, IInterface service) { 531 mComponentNamesByAction.put(action, name); 532 mServiceByComponentName.put(name, service); 533 mComponentNameByService.put(service, name); 534 } 535 536 private List<ResolveInfo> doQueryIntentServices(Intent intent, int flags) { 537 List<ResolveInfo> result = new ArrayList<>(); 538 for (ComponentName componentName : mComponentNamesByAction.get(intent.getAction())) { 539 ResolveInfo resolveInfo = new ResolveInfo(); 540 resolveInfo.serviceInfo = mServiceInfoByComponentName.get(componentName); 541 resolveInfo.serviceInfo.metaData = new Bundle(); 542 resolveInfo.serviceInfo.metaData.putBoolean( 543 TelecomManager.METADATA_INCLUDE_EXTERNAL_CALLS, true); 544 result.add(resolveInfo); 545 } 546 return result; 547 } 548 } 549