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 getPackageManager()94 public PackageManager getPackageManager() { 95 return mPackageManager; 96 } 97 98 @Override getPackageName()99 public String getPackageName() { 100 return "com.android.server.telecom.tests"; 101 } 102 103 @Override getPackageResourcePath()104 public String getPackageResourcePath() { 105 return "/tmp/i/dont/know"; 106 } 107 108 @Override getApplicationContext()109 public Context getApplicationContext() { 110 return mApplicationContextSpy; 111 } 112 113 @Override getFilesDir()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 bindServiceAsUser( Intent serviceIntent, ServiceConnection connection, int flags, UserHandle userHandle)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 bindService( Intent serviceIntent, ServiceConnection connection, int flags)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 unbindService( ServiceConnection connection)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 getSystemService(String name)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 getSystemServiceName(Class<?> svcClass)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 getUserId()197 public int getUserId() { 198 return 0; 199 } 200 201 @Override getResources()202 public Resources getResources() { 203 return mResources; 204 } 205 206 @Override getOpPackageName()207 public String getOpPackageName() { 208 return "com.android.server.telecom.tests"; 209 } 210 211 @Override getContentResolver()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 registerReceiver(BroadcastReceiver receiver, IntentFilter filter)250 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { 251 // TODO -- this is called by WiredHeadsetManager!!! 252 return null; 253 } 254 255 @Override registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler)256 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, 257 String broadcastPermission, Handler scheduler) { 258 return null; 259 } 260 261 @Override sendBroadcast(Intent intent)262 public void sendBroadcast(Intent intent) { 263 // TODO -- need to ensure this is captured 264 } 265 266 @Override sendBroadcast(Intent intent, String receiverPermission)267 public void sendBroadcast(Intent intent, String receiverPermission) { 268 // TODO -- need to ensure this is captured 269 } 270 271 @Override sendBroadcastAsUser(Intent intent, UserHandle userHandle)272 public void sendBroadcastAsUser(Intent intent, UserHandle userHandle) { 273 // TODO -- need to ensure this is captured 274 } 275 276 @Override sendOrderedBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)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 sendOrderedBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission, int appOp, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)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 createPackageContextAsUser(String packageName, int flags, UserHandle user)290 public Context createPackageContextAsUser(String packageName, int flags, UserHandle user) 291 throws PackageManager.NameNotFoundException { 292 return this; 293 } 294 295 @Override checkCallingOrSelfPermission(String permission)296 public int checkCallingOrSelfPermission(String permission) { 297 return PackageManager.PERMISSION_GRANTED; 298 } 299 300 @Override enforceCallingOrSelfPermission(String permission, String message)301 public void enforceCallingOrSelfPermission(String permission, String message) { 302 // Don't bother enforcing anything in mock. 303 } 304 305 @Override startActivityAsUser(Intent intent, UserHandle userHandle)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 result.add(resolveInfo); 523 } 524 return result; 525 } 526 } 527