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.media.AudioManager; 47 import android.os.Bundle; 48 import android.os.Handler; 49 import android.os.IInterface; 50 import android.os.UserHandle; 51 import android.os.UserManager; 52 import android.telecom.CallAudioState; 53 import android.telecom.ConnectionService; 54 import android.telecom.InCallService; 55 import android.telecom.PhoneAccount; 56 import android.telephony.SubscriptionManager; 57 import android.telephony.TelephonyManager; 58 import android.test.mock.MockContext; 59 60 import java.io.File; 61 import java.io.IOException; 62 import java.util.ArrayList; 63 import java.util.HashMap; 64 import java.util.List; 65 import java.util.Locale; 66 import java.util.Map; 67 68 import static org.mockito.Matchers.anyString; 69 import static org.mockito.Mockito.any; 70 import static org.mockito.Mockito.anyInt; 71 import static org.mockito.Mockito.doAnswer; 72 import static org.mockito.Mockito.eq; 73 import static org.mockito.Mockito.mock; 74 import static org.mockito.Mockito.spy; 75 import 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 */ 84 public class ComponentContextFixture implements TestFixture<Context> { 85 86 public class FakeApplicationContext extends MockContext { 87 @Override getPackageManager()88 public PackageManager getPackageManager() { 89 return mPackageManager; 90 } 91 92 @Override getFilesDir()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 bindServiceAsUser( Intent serviceIntent, ServiceConnection connection, int flags, UserHandle userHandle)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 bindService( Intent serviceIntent, ServiceConnection connection, int flags)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 unbindService( ServiceConnection connection)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 getSystemService(String name)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 getUserId()162 public int getUserId() { 163 return 0; 164 } 165 166 @Override getResources()167 public Resources getResources() { 168 return mResources; 169 } 170 171 @Override getOpPackageName()172 public String getOpPackageName() { 173 return "test"; 174 } 175 176 @Override getContentResolver()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 registerReceiver(BroadcastReceiver receiver, IntentFilter filter)208 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { 209 // TODO -- this is called by WiredHeadsetManager!!! 210 return null; 211 } 212 213 @Override sendBroadcast(Intent intent)214 public void sendBroadcast(Intent intent) { 215 // TODO -- need to ensure this is captured 216 } 217 218 @Override sendBroadcast(Intent intent, String receiverPermission)219 public void sendBroadcast(Intent intent, String receiverPermission) { 220 // TODO -- need to ensure this is captured 221 } 222 223 @Override sendOrderedBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)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 sendOrderedBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission, int appOp, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)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 createPackageContextAsUser(String packageName, int flags, UserHandle user)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