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