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