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