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 import com.android.server.telecom.Log; 25 26 import org.mockito.MockitoAnnotations; 27 import org.mockito.invocation.InvocationOnMock; 28 import org.mockito.stubbing.Answer; 29 30 import android.app.AppOpsManager; 31 import android.app.NotificationManager; 32 import android.app.StatusBarManager; 33 import android.content.BroadcastReceiver; 34 import android.content.ComponentName; 35 import android.content.ContentResolver; 36 import android.content.Context; 37 import android.content.IContentProvider; 38 import android.content.Intent; 39 import android.content.IntentFilter; 40 import android.content.ServiceConnection; 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.InCallService; 57 import android.telecom.PhoneAccount; 58 import android.telecom.TelecomManager; 59 import android.telephony.CarrierConfigManager; 60 import android.telephony.SubscriptionManager; 61 import android.telephony.TelephonyManager; 62 import android.test.mock.MockContext; 63 64 import java.io.File; 65 import java.io.IOException; 66 import java.util.ArrayList; 67 import java.util.Arrays; 68 import java.util.HashMap; 69 import java.util.List; 70 import java.util.Locale; 71 import java.util.Map; 72 73 import static org.mockito.Matchers.anyString; 74 import static org.mockito.Mockito.any; 75 import static org.mockito.Mockito.anyInt; 76 import static org.mockito.Mockito.doAnswer; 77 import static org.mockito.Mockito.doReturn; 78 import static org.mockito.Mockito.eq; 79 import static org.mockito.Mockito.mock; 80 import static org.mockito.Mockito.spy; 81 import 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 */ 90 public 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 void sendBroadcast(Intent intent) { 263 // TODO -- need to ensure this is captured 264 } 265 266 @Override 267 public void sendBroadcast(Intent intent, String receiverPermission) { 268 // TODO -- need to ensure this is captured 269 } 270 271 @Override 272 public void sendBroadcastAsUser(Intent intent, UserHandle userHandle) { 273 // TODO -- need to ensure this is captured 274 } 275 276 @Override 277 public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, 278 String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, 279 int initialCode, String initialData, Bundle initialExtras) { 280 // TODO -- need to ensure this is captured 281 } 282 283 @Override 284 public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, 285 String receiverPermission, int appOp, BroadcastReceiver resultReceiver, 286 Handler scheduler, int initialCode, String initialData, Bundle initialExtras) { 287 } 288 289 @Override 290 public Context createPackageContextAsUser(String packageName, int flags, UserHandle user) 291 throws PackageManager.NameNotFoundException { 292 return this; 293 } 294 295 @Override 296 public int checkCallingOrSelfPermission(String permission) { 297 return PackageManager.PERMISSION_GRANTED; 298 } 299 300 @Override 301 public void enforceCallingOrSelfPermission(String permission, String message) { 302 // Don't bother enforcing anything in mock. 303 } 304 305 @Override 306 public void startActivityAsUser(Intent intent, UserHandle userHandle) { 307 // For capturing 308 } 309 } 310 311 public class FakeAudioManager extends AudioManager { 312 313 private boolean mMute = false; 314 private boolean mSpeakerphoneOn = false; 315 private int mAudioStreamValue = 1; 316 private int mMode = AudioManager.MODE_NORMAL; 317 private int mRingerMode = AudioManager.RINGER_MODE_NORMAL; 318 319 public FakeAudioManager(Context context) { 320 super(context); 321 } 322 323 @Override 324 public void setMicrophoneMute(boolean value) { 325 mMute = value; 326 } 327 328 @Override 329 public boolean isMicrophoneMute() { 330 return mMute; 331 } 332 333 @Override 334 public void setSpeakerphoneOn(boolean value) { 335 mSpeakerphoneOn = value; 336 } 337 338 @Override 339 public boolean isSpeakerphoneOn() { 340 return mSpeakerphoneOn; 341 } 342 343 @Override 344 public void setMode(int mode) { 345 mMode = mode; 346 } 347 348 @Override 349 public int getMode() { 350 return mMode; 351 } 352 353 @Override 354 public void setRingerModeInternal(int ringerMode) { 355 mRingerMode = ringerMode; 356 } 357 358 @Override 359 public int getRingerModeInternal() { 360 return mRingerMode; 361 } 362 363 @Override 364 public void setStreamVolume(int streamTypeUnused, int index, int flagsUnused){ 365 mAudioStreamValue = index; 366 } 367 368 @Override 369 public int getStreamVolume(int streamValueUnused) { 370 return mAudioStreamValue; 371 } 372 } 373 374 private final Multimap<String, ComponentName> mComponentNamesByAction = 375 ArrayListMultimap.create(); 376 private final Map<ComponentName, IInterface> mServiceByComponentName = new HashMap<>(); 377 private final Map<ComponentName, ServiceInfo> mServiceInfoByComponentName = new HashMap<>(); 378 private final Map<IInterface, ComponentName> mComponentNameByService = new HashMap<>(); 379 private final Map<ServiceConnection, IInterface> mServiceByServiceConnection = new HashMap<>(); 380 381 private final Context mContext = new MockContext() { 382 @Override 383 public Context getApplicationContext() { 384 return mApplicationContextSpy; 385 } 386 387 @Override 388 public Resources getResources() { 389 return mResources; 390 } 391 }; 392 393 // The application context is the most important object this class provides to the system 394 // under test. 395 private final Context mApplicationContext = new FakeApplicationContext(); 396 397 // We then create a spy on the application context allowing standard Mockito-style 398 // when(...) logic to be used to add specific little responses where needed. 399 400 private final Resources mResources = mock(Resources.class); 401 private final Context mApplicationContextSpy = spy(mApplicationContext); 402 private final PackageManager mPackageManager = mock(PackageManager.class); 403 private final AudioManager mAudioManager = spy(new FakeAudioManager(mContext)); 404 private final TelephonyManager mTelephonyManager = mock(TelephonyManager.class); 405 private final AppOpsManager mAppOpsManager = mock(AppOpsManager.class); 406 private final NotificationManager mNotificationManager = mock(NotificationManager.class); 407 private final UserManager mUserManager = mock(UserManager.class); 408 private final StatusBarManager mStatusBarManager = mock(StatusBarManager.class); 409 private final SubscriptionManager mSubscriptionManager = mock(SubscriptionManager.class); 410 private final CarrierConfigManager mCarrierConfigManager = mock(CarrierConfigManager.class); 411 private final CountryDetector mCountryDetector = mock(CountryDetector.class); 412 private final Map<String, IContentProvider> mIContentProviderByUri = new HashMap<>(); 413 private final Configuration mResourceConfiguration = new Configuration(); 414 415 private TelecomManager mTelecomManager = null; 416 417 public ComponentContextFixture() { 418 MockitoAnnotations.initMocks(this); 419 when(mResources.getConfiguration()).thenReturn(mResourceConfiguration); 420 mResourceConfiguration.setLocale(Locale.TAIWAN); 421 422 // TODO: Move into actual tests 423 when(mAudioManager.isWiredHeadsetOn()).thenReturn(false); 424 425 doAnswer(new Answer<List<ResolveInfo>>() { 426 @Override 427 public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable { 428 return doQueryIntentServices( 429 (Intent) invocation.getArguments()[0], 430 (Integer) invocation.getArguments()[1]); 431 } 432 }).when(mPackageManager).queryIntentServices((Intent) any(), anyInt()); 433 434 doAnswer(new Answer<List<ResolveInfo>>() { 435 @Override 436 public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable { 437 return doQueryIntentServices( 438 (Intent) invocation.getArguments()[0], 439 (Integer) invocation.getArguments()[1]); 440 } 441 }).when(mPackageManager).queryIntentServicesAsUser((Intent) any(), anyInt(), anyInt()); 442 443 when(mTelephonyManager.getSubIdForPhoneAccount((PhoneAccount) any())).thenReturn(1); 444 445 when(mTelephonyManager.getNetworkOperatorName()).thenReturn("label1"); 446 447 doAnswer(new Answer<Void>(){ 448 @Override 449 public Void answer(InvocationOnMock invocation) throws Throwable { 450 return null; 451 } 452 }).when(mAppOpsManager).checkPackage(anyInt(), anyString()); 453 454 when(mNotificationManager.matchesCallFilter(any(Bundle.class))).thenReturn(true); 455 456 when(mUserManager.getSerialNumberForUser(any(UserHandle.class))).thenReturn(-1L); 457 458 doReturn(null).when(mApplicationContextSpy).registerReceiver(any(BroadcastReceiver.class), 459 any(IntentFilter.class)); 460 } 461 462 @Override 463 public Context getTestDouble() { 464 return mContext; 465 } 466 467 public void addConnectionService( 468 ComponentName componentName, 469 IConnectionService service) 470 throws Exception { 471 addService(ConnectionService.SERVICE_INTERFACE, componentName, service); 472 ServiceInfo serviceInfo = new ServiceInfo(); 473 serviceInfo.permission = android.Manifest.permission.BIND_CONNECTION_SERVICE; 474 serviceInfo.packageName = componentName.getPackageName(); 475 serviceInfo.name = componentName.getClassName(); 476 mServiceInfoByComponentName.put(componentName, serviceInfo); 477 } 478 479 public void addInCallService( 480 ComponentName componentName, 481 IInCallService service) 482 throws Exception { 483 addService(InCallService.SERVICE_INTERFACE, componentName, service); 484 ServiceInfo serviceInfo = new ServiceInfo(); 485 serviceInfo.permission = android.Manifest.permission.BIND_INCALL_SERVICE; 486 serviceInfo.packageName = componentName.getPackageName(); 487 serviceInfo.name = componentName.getClassName(); 488 mServiceInfoByComponentName.put(componentName, serviceInfo); 489 } 490 491 public void putResource(int id, final String value) { 492 when(mResources.getText(eq(id))).thenReturn(value); 493 when(mResources.getString(eq(id))).thenReturn(value); 494 when(mResources.getString(eq(id), any())).thenAnswer(new Answer<String>() { 495 @Override 496 public String answer(InvocationOnMock invocation) { 497 Object[] args = invocation.getArguments(); 498 return String.format(value, Arrays.copyOfRange(args, 1, args.length)); 499 } 500 }); 501 } 502 503 public void putBooleanResource(int id, boolean value) { 504 when(mResources.getBoolean(eq(id))).thenReturn(value); 505 } 506 507 public void setTelecomManager(TelecomManager telecomManager) { 508 mTelecomManager = telecomManager; 509 } 510 511 private void addService(String action, ComponentName name, IInterface service) { 512 mComponentNamesByAction.put(action, name); 513 mServiceByComponentName.put(name, service); 514 mComponentNameByService.put(service, name); 515 } 516 517 private List<ResolveInfo> doQueryIntentServices(Intent intent, int flags) { 518 List<ResolveInfo> result = new ArrayList<>(); 519 for (ComponentName componentName : mComponentNamesByAction.get(intent.getAction())) { 520 ResolveInfo resolveInfo = new ResolveInfo(); 521 resolveInfo.serviceInfo = mServiceInfoByComponentName.get(componentName); 522 resolveInfo.serviceInfo.metaData = new Bundle(); 523 resolveInfo.serviceInfo.metaData.putBoolean( 524 TelecomManager.METADATA_INCLUDE_EXTERNAL_CALLS, true); 525 result.add(resolveInfo); 526 } 527 return result; 528 } 529 } 530