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