• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
25 import org.mockito.MockitoAnnotations;
26 import org.mockito.invocation.InvocationOnMock;
27 import org.mockito.stubbing.Answer;
28 
29 import android.Manifest;
30 import android.app.AppOpsManager;
31 import android.app.NotificationManager;
32 import android.app.StatusBarManager;
33 import android.app.role.RoleManager;
34 import android.content.BroadcastReceiver;
35 import android.content.ComponentName;
36 import android.content.ContentResolver;
37 import android.content.Context;
38 import android.content.IContentProvider;
39 import android.content.Intent;
40 import android.content.IntentFilter;
41 import android.content.ServiceConnection;
42 import android.content.pm.ApplicationInfo;
43 import android.content.pm.PackageManager;
44 import android.content.pm.ResolveInfo;
45 import android.content.pm.ServiceInfo;
46 import android.content.res.Configuration;
47 import android.content.res.Resources;
48 import android.location.Country;
49 import android.location.CountryDetector;
50 import android.media.AudioManager;
51 import android.os.Bundle;
52 import android.os.Handler;
53 import android.os.IInterface;
54 import android.os.UserHandle;
55 import android.os.UserManager;
56 import android.telecom.CallAudioState;
57 import android.telecom.ConnectionService;
58 import android.telecom.Log;
59 import android.telecom.InCallService;
60 import android.telecom.PhoneAccount;
61 import android.telecom.TelecomManager;
62 import android.telephony.CarrierConfigManager;
63 import android.telephony.SubscriptionManager;
64 import android.telephony.TelephonyManager;
65 import android.test.mock.MockContext;
66 
67 import java.io.File;
68 import java.io.IOException;
69 import java.util.ArrayList;
70 import java.util.Arrays;
71 import java.util.HashMap;
72 import java.util.List;
73 import java.util.Locale;
74 import java.util.Map;
75 import java.util.concurrent.Executor;
76 
77 import static org.mockito.ArgumentMatchers.matches;
78 import static org.mockito.Matchers.anyString;
79 import static org.mockito.Mockito.any;
80 import static org.mockito.Mockito.anyInt;
81 import static org.mockito.Mockito.doAnswer;
82 import static org.mockito.Mockito.doReturn;
83 import static org.mockito.Mockito.eq;
84 import static org.mockito.Mockito.mock;
85 import static org.mockito.Mockito.spy;
86 import static org.mockito.Mockito.when;
87 
88 /**
89  * Controls a test {@link Context} as would be provided by the Android framework to an
90  * {@code Activity}, {@code Service} or other system-instantiated component.
91  *
92  * The {@link Context} created by this object is "hollow" but its {@code applicationContext}
93  * property points to an application context implementing all the nontrivial functionality.
94  */
95 public class ComponentContextFixture implements TestFixture<Context> {
96 
97     public class FakeApplicationContext extends MockContext {
98         @Override
getPackageManager()99         public PackageManager getPackageManager() {
100             return mPackageManager;
101         }
102 
103         @Override
getMainExecutor()104         public Executor getMainExecutor() {
105             // TODO: This doesn't actually execute anything as we don't need to do so for now, but
106             //  future users might need it.
107             return mMainExecutor;
108         }
109 
110         @Override
getPackageName()111         public String getPackageName() {
112             return "com.android.server.telecom.tests";
113         }
114 
115         @Override
getPackageResourcePath()116         public String getPackageResourcePath() {
117             return "/tmp/i/dont/know";
118         }
119 
120         @Override
getApplicationContext()121         public Context getApplicationContext() {
122             return mApplicationContextSpy;
123         }
124 
125         @Override
getFilesDir()126         public File getFilesDir() {
127             try {
128                 return File.createTempFile("temp", "temp").getParentFile();
129             } catch (IOException e) {
130                 throw new RuntimeException(e);
131             }
132         }
133 
134         @Override
bindServiceAsUser( Intent serviceIntent, ServiceConnection connection, int flags, UserHandle userHandle)135         public boolean bindServiceAsUser(
136                 Intent serviceIntent,
137                 ServiceConnection connection,
138                 int flags,
139                 UserHandle userHandle) {
140             // TODO: Implement "as user" functionality
141             return bindService(serviceIntent, connection, flags);
142         }
143 
144         @Override
bindService( Intent serviceIntent, ServiceConnection connection, int flags)145         public boolean bindService(
146                 Intent serviceIntent,
147                 ServiceConnection connection,
148                 int flags) {
149             if (mServiceByServiceConnection.containsKey(connection)) {
150                 throw new RuntimeException("ServiceConnection already bound: " + connection);
151             }
152             IInterface service = mServiceByComponentName.get(serviceIntent.getComponent());
153             if (service == null) {
154                 throw new RuntimeException("ServiceConnection not found: "
155                         + serviceIntent.getComponent());
156             }
157             mServiceByServiceConnection.put(connection, service);
158             connection.onServiceConnected(serviceIntent.getComponent(), service.asBinder());
159             return true;
160         }
161 
162         @Override
unbindService( ServiceConnection connection)163         public void unbindService(
164                 ServiceConnection connection) {
165             IInterface service = mServiceByServiceConnection.remove(connection);
166             if (service == null) {
167                 throw new RuntimeException("ServiceConnection not found: " + connection);
168             }
169             connection.onServiceDisconnected(mComponentNameByService.get(service));
170         }
171 
172         @Override
getSystemService(String name)173         public Object getSystemService(String name) {
174             switch (name) {
175                 case Context.AUDIO_SERVICE:
176                     return mAudioManager;
177                 case Context.TELEPHONY_SERVICE:
178                     return mTelephonyManager;
179                 case Context.APP_OPS_SERVICE:
180                     return mAppOpsManager;
181                 case Context.NOTIFICATION_SERVICE:
182                     return mNotificationManager;
183                 case Context.STATUS_BAR_SERVICE:
184                     return mStatusBarManager;
185                 case Context.USER_SERVICE:
186                     return mUserManager;
187                 case Context.TELEPHONY_SUBSCRIPTION_SERVICE:
188                     return mSubscriptionManager;
189                 case Context.TELECOM_SERVICE:
190                     return mTelecomManager;
191                 case Context.CARRIER_CONFIG_SERVICE:
192                     return mCarrierConfigManager;
193                 case Context.COUNTRY_DETECTOR:
194                     return mCountryDetector;
195                 case Context.ROLE_SERVICE:
196                     return mRoleManager;
197                 default:
198                     return null;
199             }
200         }
201 
202         @Override
getSystemServiceName(Class<?> svcClass)203         public String getSystemServiceName(Class<?> svcClass) {
204             if (svcClass == UserManager.class) {
205                 return Context.USER_SERVICE;
206             } else if (svcClass == RoleManager.class) {
207                 return Context.ROLE_SERVICE;
208             } else if (svcClass == AudioManager.class) {
209                 return Context.AUDIO_SERVICE;
210             } else if (svcClass == TelephonyManager.class) {
211                 return Context.TELEPHONY_SERVICE;
212             }
213             throw new UnsupportedOperationException();
214         }
215 
216         @Override
getUserId()217         public int getUserId() {
218             return 0;
219         }
220 
221         @Override
getResources()222         public Resources getResources() {
223             return mResources;
224         }
225 
226         @Override
getOpPackageName()227         public String getOpPackageName() {
228             return "com.android.server.telecom.tests";
229         }
230 
231         @Override
getApplicationInfo()232         public ApplicationInfo getApplicationInfo() {
233             return mTestApplicationInfo;
234         }
235 
236         @Override
getContentResolver()237         public ContentResolver getContentResolver() {
238             return new ContentResolver(mApplicationContextSpy) {
239                 @Override
240                 protected IContentProvider acquireProvider(Context c, String name) {
241                     Log.i(this, "acquireProvider %s", name);
242                     return getOrCreateProvider(name);
243                 }
244 
245                 @Override
246                 public boolean releaseProvider(IContentProvider icp) {
247                     return true;
248                 }
249 
250                 @Override
251                 protected IContentProvider acquireUnstableProvider(Context c, String name) {
252                     Log.i(this, "acquireUnstableProvider %s", name);
253                     return getOrCreateProvider(name);
254                 }
255 
256                 private IContentProvider getOrCreateProvider(String name) {
257                     if (!mIContentProviderByUri.containsKey(name)) {
258                         mIContentProviderByUri.put(name, mock(IContentProvider.class));
259                     }
260                     return mIContentProviderByUri.get(name);
261                 }
262 
263                 @Override
264                 public boolean releaseUnstableProvider(IContentProvider icp) {
265                     return false;
266                 }
267 
268                 @Override
269                 public void unstableProviderDied(IContentProvider icp) {
270                 }
271             };
272         }
273 
274         @Override
registerReceiver(BroadcastReceiver receiver, IntentFilter filter)275         public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
276             // TODO -- this is called by WiredHeadsetManager!!!
277             return null;
278         }
279 
280         @Override
registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler)281         public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
282                 String broadcastPermission, Handler scheduler) {
283             return null;
284         }
285 
286         @Override
registerReceiverAsUser(BroadcastReceiver receiver, UserHandle handle, IntentFilter filter, String broadcastPermission, Handler scheduler)287         public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle handle,
288                 IntentFilter filter, String broadcastPermission, Handler scheduler) {
289             return null;
290         }
291 
292         @Override
sendBroadcast(Intent intent)293         public void sendBroadcast(Intent intent) {
294             // TODO -- need to ensure this is captured
295         }
296 
297         @Override
sendBroadcast(Intent intent, String receiverPermission)298         public void sendBroadcast(Intent intent, String receiverPermission) {
299             // TODO -- need to ensure this is captured
300         }
301 
302         @Override
sendBroadcastAsUser(Intent intent, UserHandle userHandle)303         public void sendBroadcastAsUser(Intent intent, UserHandle userHandle) {
304             // TODO -- need to ensure this is captured
305         }
306 
307         @Override
sendOrderedBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)308         public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
309                 String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
310                 int initialCode, String initialData, Bundle initialExtras) {
311             // TODO -- need to ensure this is captured
312         }
313 
314         @Override
sendOrderedBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission, int appOp, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)315         public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
316                 String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
317                 Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
318         }
319 
320         @Override
sendOrderedBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission, int appOp, Bundle options, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)321         public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
322                 String receiverPermission, int appOp, Bundle options,
323                 BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
324                 String initialData, Bundle initialExtras) {
325         }
326 
327         @Override
createPackageContextAsUser(String packageName, int flags, UserHandle user)328         public Context createPackageContextAsUser(String packageName, int flags, UserHandle user)
329                 throws PackageManager.NameNotFoundException {
330             return this;
331         }
332 
333         @Override
checkCallingOrSelfPermission(String permission)334         public int checkCallingOrSelfPermission(String permission) {
335             return PackageManager.PERMISSION_GRANTED;
336         }
337 
338         @Override
enforceCallingOrSelfPermission(String permission, String message)339         public void enforceCallingOrSelfPermission(String permission, String message) {
340             // Don't bother enforcing anything in mock.
341         }
342 
343         @Override
enforcePermission( String permission, int pid, int uid, String message)344         public void enforcePermission(
345                 String permission, int pid, int uid, String message) {
346             // By default, don't enforce anything in mock.
347         }
348 
349         @Override
startActivityAsUser(Intent intent, UserHandle userHandle)350         public void startActivityAsUser(Intent intent, UserHandle userHandle) {
351             // For capturing
352         }
353     }
354 
355     public class FakeAudioManager extends AudioManager {
356 
357         private boolean mMute = false;
358         private boolean mSpeakerphoneOn = false;
359         private int mAudioStreamValue = 1;
360         private int mMode = AudioManager.MODE_NORMAL;
361         private int mRingerMode = AudioManager.RINGER_MODE_NORMAL;
362 
363         public FakeAudioManager(Context context) {
364             super(context);
365         }
366 
367         @Override
368         public void setMicrophoneMute(boolean value) {
369             mMute = value;
370         }
371 
372         @Override
373         public boolean isMicrophoneMute() {
374             return mMute;
375         }
376 
377         @Override
378         public void setSpeakerphoneOn(boolean value) {
379             mSpeakerphoneOn = value;
380         }
381 
382         @Override
383         public boolean isSpeakerphoneOn() {
384             return mSpeakerphoneOn;
385         }
386 
387         @Override
388         public void setMode(int mode) {
389             mMode = mode;
390         }
391 
392         @Override
393         public int getMode() {
394             return mMode;
395         }
396 
397         @Override
398         public void setRingerModeInternal(int ringerMode) {
399             mRingerMode = ringerMode;
400         }
401 
402         @Override
403         public int getRingerModeInternal() {
404             return mRingerMode;
405         }
406 
407         @Override
408         public void setStreamVolume(int streamTypeUnused, int index, int flagsUnused){
409             mAudioStreamValue = index;
410         }
411 
412         @Override
413         public int getStreamVolume(int streamValueUnused) {
414             return mAudioStreamValue;
415         }
416     }
417 
418     private final Multimap<String, ComponentName> mComponentNamesByAction =
419             ArrayListMultimap.create();
420     private final Map<ComponentName, IInterface> mServiceByComponentName = new HashMap<>();
421     private final Map<ComponentName, ServiceInfo> mServiceInfoByComponentName = new HashMap<>();
422     private final Map<IInterface, ComponentName> mComponentNameByService = new HashMap<>();
423     private final Map<ServiceConnection, IInterface> mServiceByServiceConnection = new HashMap<>();
424 
425     private final Context mContext = new MockContext() {
426         @Override
427         public Context getApplicationContext() {
428             return mApplicationContextSpy;
429         }
430 
431         @Override
432         public Resources getResources() {
433             return mResources;
434         }
435     };
436 
437     // The application context is the most important object this class provides to the system
438     // under test.
439     private final Context mApplicationContext = new FakeApplicationContext();
440 
441     // We then create a spy on the application context allowing standard Mockito-style
442     // when(...) logic to be used to add specific little responses where needed.
443 
444     private final Resources mResources = mock(Resources.class);
445     private final Context mApplicationContextSpy = spy(mApplicationContext);
446     private final PackageManager mPackageManager = mock(PackageManager.class);
447     private final Executor mMainExecutor = mock(Executor.class);
448     private final AudioManager mAudioManager = spy(new FakeAudioManager(mContext));
449     private final TelephonyManager mTelephonyManager = mock(TelephonyManager.class);
450     private final AppOpsManager mAppOpsManager = mock(AppOpsManager.class);
451     private final NotificationManager mNotificationManager = mock(NotificationManager.class);
452     private final UserManager mUserManager = mock(UserManager.class);
453     private final StatusBarManager mStatusBarManager = mock(StatusBarManager.class);
454     private final SubscriptionManager mSubscriptionManager = mock(SubscriptionManager.class);
455     private final CarrierConfigManager mCarrierConfigManager = mock(CarrierConfigManager.class);
456     private final CountryDetector mCountryDetector = mock(CountryDetector.class);
457     private final Map<String, IContentProvider> mIContentProviderByUri = new HashMap<>();
458     private final Configuration mResourceConfiguration = new Configuration();
459     private final ApplicationInfo mTestApplicationInfo = new ApplicationInfo();
460     private final RoleManager mRoleManager = mock(RoleManager.class);
461 
462     private TelecomManager mTelecomManager = mock(TelecomManager.class);
463 
464     public ComponentContextFixture() {
465         MockitoAnnotations.initMocks(this);
466         when(mResources.getConfiguration()).thenReturn(mResourceConfiguration);
467         when(mResources.getString(anyInt())).thenReturn("");
468         when(mResources.getStringArray(anyInt())).thenReturn(new String[0]);
469         mResourceConfiguration.setLocale(Locale.TAIWAN);
470 
471         // TODO: Move into actual tests
472         doReturn(false).when(mAudioManager).isWiredHeadsetOn();
473 
474         doAnswer(new Answer<List<ResolveInfo>>() {
475             @Override
476             public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable {
477                 return doQueryIntentServices(
478                         (Intent) invocation.getArguments()[0],
479                         (Integer) invocation.getArguments()[1]);
480             }
481         }).when(mPackageManager).queryIntentServices((Intent) any(), anyInt());
482 
483         doAnswer(new Answer<List<ResolveInfo>>() {
484             @Override
485             public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable {
486                 return doQueryIntentServices(
487                         (Intent) invocation.getArguments()[0],
488                         (Integer) invocation.getArguments()[1]);
489             }
490         }).when(mPackageManager).queryIntentServicesAsUser((Intent) any(), anyInt(), anyInt());
491 
492         // By default, tests use non-ui apps instead of 3rd party companion apps.
493         when(mPackageManager.checkPermission(
494                 matches(Manifest.permission.CALL_COMPANION_APP), anyString()))
495                 .thenReturn(PackageManager.PERMISSION_DENIED);
496 
497         // Used in CreateConnectionProcessor to rank emergency numbers by viability.
498         // For the test, make them all equal to INVALID so that the preferred PhoneAccount will be
499         // chosen.
500         when(mTelephonyManager.getSubIdForPhoneAccount((PhoneAccount) any())).thenReturn(
501                 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
502 
503         when(mTelephonyManager.getNetworkOperatorName()).thenReturn("label1");
504         when(mTelephonyManager.getMultiSimConfiguration()).thenReturn(
505                 TelephonyManager.MultiSimVariants.UNKNOWN);
506         when(mResources.getBoolean(eq(R.bool.grant_location_permission_enabled))).thenReturn(false);
507         doAnswer(new Answer<Void>(){
508             @Override
509             public Void answer(InvocationOnMock invocation) throws Throwable {
510                 return null;
511             }
512         }).when(mAppOpsManager).checkPackage(anyInt(), anyString());
513 
514         when(mNotificationManager.matchesCallFilter(any(Bundle.class))).thenReturn(true);
515 
516         when(mUserManager.getSerialNumberForUser(any(UserHandle.class))).thenReturn(-1L);
517 
518         doReturn(null).when(mApplicationContextSpy).registerReceiver(any(BroadcastReceiver.class),
519                 any(IntentFilter.class));
520 
521         // Make sure we do not hide PII during testing.
522         Log.setTag("TelecomTEST");
523         Log.setIsExtendedLoggingEnabled(true);
524         Log.VERBOSE = true;
525     }
526 
527     @Override
528     public Context getTestDouble() {
529         return mContext;
530     }
531 
532     public void addConnectionService(
533             ComponentName componentName,
534             IConnectionService service)
535             throws Exception {
536         addService(ConnectionService.SERVICE_INTERFACE, componentName, service);
537         ServiceInfo serviceInfo = new ServiceInfo();
538         serviceInfo.permission = android.Manifest.permission.BIND_CONNECTION_SERVICE;
539         serviceInfo.packageName = componentName.getPackageName();
540         serviceInfo.name = componentName.getClassName();
541         mServiceInfoByComponentName.put(componentName, serviceInfo);
542     }
543 
544     public void addInCallService(
545             ComponentName componentName,
546             IInCallService service)
547             throws Exception {
548         addService(InCallService.SERVICE_INTERFACE, componentName, service);
549         ServiceInfo serviceInfo = new ServiceInfo();
550         serviceInfo.permission = android.Manifest.permission.BIND_INCALL_SERVICE;
551         serviceInfo.packageName = componentName.getPackageName();
552         serviceInfo.name = componentName.getClassName();
553         mServiceInfoByComponentName.put(componentName, serviceInfo);
554     }
555 
556     public void putResource(int id, final String value) {
557         when(mResources.getText(eq(id))).thenReturn(value);
558         when(mResources.getString(eq(id))).thenReturn(value);
559         when(mResources.getString(eq(id), any())).thenAnswer(new Answer<String>() {
560             @Override
561             public String answer(InvocationOnMock invocation) {
562                 Object[] args = invocation.getArguments();
563                 return String.format(value, Arrays.copyOfRange(args, 1, args.length));
564             }
565         });
566     }
567 
568     public void putFloatResource(int id, final float value) {
569         when(mResources.getFloat(eq(id))).thenReturn(value);
570     }
571 
572     public void putBooleanResource(int id, boolean value) {
573         when(mResources.getBoolean(eq(id))).thenReturn(value);
574     }
575 
576     public void putStringArrayResource(int id, String[] value) {
577         when(mResources.getStringArray(eq(id))).thenReturn(value);
578     }
579 
580     public void setTelecomManager(TelecomManager telecomManager) {
581         mTelecomManager = telecomManager;
582     }
583 
584     public TelephonyManager getTelephonyManager() {
585         return mTelephonyManager;
586     }
587 
588     private void addService(String action, ComponentName name, IInterface service) {
589         mComponentNamesByAction.put(action, name);
590         mServiceByComponentName.put(name, service);
591         mComponentNameByService.put(service, name);
592     }
593 
594     private List<ResolveInfo> doQueryIntentServices(Intent intent, int flags) {
595         List<ResolveInfo> result = new ArrayList<>();
596         for (ComponentName componentName : mComponentNamesByAction.get(intent.getAction())) {
597             ResolveInfo resolveInfo = new ResolveInfo();
598             resolveInfo.serviceInfo = mServiceInfoByComponentName.get(componentName);
599             resolveInfo.serviceInfo.metaData = new Bundle();
600             resolveInfo.serviceInfo.metaData.putBoolean(
601                     TelecomManager.METADATA_INCLUDE_EXTERNAL_CALLS, true);
602             result.add(resolveInfo);
603         }
604         return result;
605     }
606 }
607