ComponentContextFixture.java revision 877267255abf10ed14ccc88bf5201e48ab867f81
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 mock(IContentProvider.class); 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 mock(IContentProvider.class); 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 Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, 229 String broadcastPermission, Handler scheduler) { 230 return null; 231 } 232 233 @Override 234 public void sendBroadcast(Intent intent) { 235 // TODO -- need to ensure this is captured 236 } 237 238 @Override 239 public void sendBroadcast(Intent intent, String receiverPermission) { 240 // TODO -- need to ensure this is captured 241 } 242 243 @Override 244 public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, 245 String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, 246 int initialCode, String initialData, Bundle initialExtras) { 247 // TODO -- need to ensure this is captured 248 } 249 250 @Override 251 public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, 252 String receiverPermission, int appOp, BroadcastReceiver resultReceiver, 253 Handler scheduler, int initialCode, String initialData, Bundle initialExtras) { 254 } 255 256 @Override 257 public Context createPackageContextAsUser(String packageName, int flags, UserHandle user) 258 throws PackageManager.NameNotFoundException { 259 return this; 260 } 261 }; 262 263 public class FakeAudioManager extends AudioManager { 264 265 private boolean mMute = false; 266 private boolean mSpeakerphoneOn = false; 267 private int mMode = AudioManager.MODE_NORMAL; 268 269 public FakeAudioManager(Context context) { 270 super(context); 271 } 272 273 @Override 274 public void setMicrophoneMute(boolean value) { 275 mMute = value; 276 } 277 278 @Override 279 public boolean isMicrophoneMute() { 280 return mMute; 281 } 282 283 @Override 284 public void setSpeakerphoneOn(boolean value) { 285 mSpeakerphoneOn = value; 286 } 287 288 @Override 289 public boolean isSpeakerphoneOn() { 290 return mSpeakerphoneOn; 291 } 292 293 @Override 294 public void setMode(int mode) { 295 mMode = mode; 296 } 297 298 @Override 299 public int getMode() { 300 return mMode; 301 } 302 } 303 304 private final Multimap<String, ComponentName> mComponentNamesByAction = 305 ArrayListMultimap.create(); 306 private final Map<ComponentName, IInterface> mServiceByComponentName = new HashMap<>(); 307 private final Map<ComponentName, ServiceInfo> mServiceInfoByComponentName = new HashMap<>(); 308 private final Map<IInterface, ComponentName> mComponentNameByService = new HashMap<>(); 309 private final Map<ServiceConnection, IInterface> mServiceByServiceConnection = new HashMap<>(); 310 311 private final Context mContext = new MockContext() { 312 @Override 313 public Context getApplicationContext() { 314 return mApplicationContextSpy; 315 } 316 317 @Override 318 public Resources getResources() { 319 return mResources; 320 } 321 }; 322 323 // The application context is the most important object this class provides to the system 324 // under test. 325 private final Context mApplicationContext = new FakeApplicationContext(); 326 327 // We then create a spy on the application context allowing standard Mockito-style 328 // when(...) logic to be used to add specific little responses where needed. 329 330 private final Resources mResources = mock(Resources.class); 331 private final Context mApplicationContextSpy = spy(mApplicationContext); 332 private final PackageManager mPackageManager = mock(PackageManager.class); 333 private final AudioManager mAudioManager = spy(new FakeAudioManager(mContext)); 334 private final TelephonyManager mTelephonyManager = mock(TelephonyManager.class); 335 private final AppOpsManager mAppOpsManager = mock(AppOpsManager.class); 336 private final NotificationManager mNotificationManager = mock(NotificationManager.class); 337 private final UserManager mUserManager = mock(UserManager.class); 338 private final StatusBarManager mStatusBarManager = mock(StatusBarManager.class); 339 private final SubscriptionManager mSubscriptionManager = mock(SubscriptionManager.class); 340 private final CarrierConfigManager mCarrierConfigManager = mock(CarrierConfigManager.class); 341 private final Configuration mResourceConfiguration = new Configuration(); 342 343 private TelecomManager mTelecomManager = null; 344 345 public ComponentContextFixture() { 346 MockitoAnnotations.initMocks(this); 347 when(mResources.getConfiguration()).thenReturn(mResourceConfiguration); 348 mResourceConfiguration.setLocale(Locale.TAIWAN); 349 350 // TODO: Move into actual tests 351 when(mAudioManager.isWiredHeadsetOn()).thenReturn(false); 352 353 doAnswer(new Answer<List<ResolveInfo>>() { 354 @Override 355 public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable { 356 return doQueryIntentServices( 357 (Intent) invocation.getArguments()[0], 358 (Integer) invocation.getArguments()[1]); 359 } 360 }).when(mPackageManager).queryIntentServices((Intent) any(), anyInt()); 361 362 doAnswer(new Answer<List<ResolveInfo>>() { 363 @Override 364 public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable { 365 return doQueryIntentServices( 366 (Intent) invocation.getArguments()[0], 367 (Integer) invocation.getArguments()[1]); 368 } 369 }).when(mPackageManager).queryIntentServicesAsUser((Intent) any(), anyInt(), anyInt()); 370 371 when(mTelephonyManager.getSubIdForPhoneAccount((PhoneAccount) any())).thenReturn(1); 372 373 doAnswer(new Answer<Void>(){ 374 @Override 375 public Void answer(InvocationOnMock invocation) throws Throwable { 376 return null; 377 } 378 }).when(mAppOpsManager).checkPackage(anyInt(), anyString()); 379 380 when(mNotificationManager.matchesCallFilter(any(Bundle.class))).thenReturn(true); 381 382 when(mUserManager.getSerialNumberForUser(any(UserHandle.class))).thenReturn(-1L); 383 384 doReturn(null).when(mApplicationContextSpy).registerReceiver(any(BroadcastReceiver.class), 385 any(IntentFilter.class)); 386 } 387 388 @Override 389 public Context getTestDouble() { 390 return mContext; 391 } 392 393 public void addConnectionService( 394 ComponentName componentName, 395 IConnectionService service) 396 throws Exception { 397 addService(ConnectionService.SERVICE_INTERFACE, componentName, service); 398 ServiceInfo serviceInfo = new ServiceInfo(); 399 serviceInfo.permission = android.Manifest.permission.BIND_CONNECTION_SERVICE; 400 serviceInfo.packageName = componentName.getPackageName(); 401 serviceInfo.name = componentName.getClassName(); 402 mServiceInfoByComponentName.put(componentName, serviceInfo); 403 } 404 405 public void addInCallService( 406 ComponentName componentName, 407 IInCallService service) 408 throws Exception { 409 addService(InCallService.SERVICE_INTERFACE, componentName, service); 410 ServiceInfo serviceInfo = new ServiceInfo(); 411 serviceInfo.permission = android.Manifest.permission.BIND_INCALL_SERVICE; 412 serviceInfo.packageName = componentName.getPackageName(); 413 serviceInfo.name = componentName.getClassName(); 414 mServiceInfoByComponentName.put(componentName, serviceInfo); 415 } 416 417 public void putResource(int id, final String value) { 418 when(mResources.getText(eq(id))).thenReturn(value); 419 when(mResources.getString(eq(id))).thenReturn(value); 420 when(mResources.getString(eq(id), any())).thenAnswer(new Answer<String>() { 421 @Override 422 public String answer(InvocationOnMock invocation) { 423 Object[] args = invocation.getArguments(); 424 return String.format(value, Arrays.copyOfRange(args, 1, args.length)); 425 } 426 }); 427 } 428 429 public void setTelecomManager(TelecomManager telecomManager) { 430 mTelecomManager = telecomManager; 431 } 432 433 private void addService(String action, ComponentName name, IInterface service) { 434 mComponentNamesByAction.put(action, name); 435 mServiceByComponentName.put(name, service); 436 mComponentNameByService.put(service, name); 437 } 438 439 private List<ResolveInfo> doQueryIntentServices(Intent intent, int flags) { 440 List<ResolveInfo> result = new ArrayList<>(); 441 for (ComponentName componentName : mComponentNamesByAction.get(intent.getAction())) { 442 ResolveInfo resolveInfo = new ResolveInfo(); 443 resolveInfo.serviceInfo = mServiceInfoByComponentName.get(componentName); 444 result.add(resolveInfo); 445 } 446 return result; 447 } 448} 449