ComponentContextFixture.java revision f1dcfdb99763740e9fd1ab036f6c06a312f197ad
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;
24
25import org.mockito.MockitoAnnotations;
26import org.mockito.invocation.InvocationOnMock;
27import org.mockito.stubbing.Answer;
28
29import android.app.AppOpsManager;
30import android.app.NotificationManager;
31import android.app.StatusBarManager;
32import android.content.BroadcastReceiver;
33import android.content.ComponentName;
34import android.content.ContentResolver;
35import android.content.Context;
36import android.content.IContentProvider;
37import android.content.Intent;
38import android.content.IntentFilter;
39import android.content.ServiceConnection;
40import android.content.pm.PackageManager;
41import android.content.pm.ResolveInfo;
42import android.content.pm.ServiceInfo;
43import android.content.res.Configuration;
44import android.content.res.Resources;
45import android.location.Country;
46import android.location.CountryDetector;
47import android.media.AudioManager;
48import android.os.Bundle;
49import android.os.Handler;
50import android.os.IInterface;
51import android.os.UserHandle;
52import android.os.UserManager;
53import android.telecom.CallAudioState;
54import android.telecom.ConnectionService;
55import android.telecom.Log;
56import android.telecom.InCallService;
57import android.telecom.PhoneAccount;
58import android.telecom.TelecomManager;
59import android.telephony.CarrierConfigManager;
60import android.telephony.SubscriptionManager;
61import android.telephony.TelephonyManager;
62import android.test.mock.MockContext;
63
64import java.io.File;
65import java.io.IOException;
66import java.util.ArrayList;
67import java.util.Arrays;
68import java.util.HashMap;
69import java.util.List;
70import java.util.Locale;
71import java.util.Map;
72
73import static org.mockito.Matchers.anyString;
74import static org.mockito.Mockito.any;
75import static org.mockito.Mockito.anyInt;
76import static org.mockito.Mockito.doAnswer;
77import static org.mockito.Mockito.doReturn;
78import static org.mockito.Mockito.eq;
79import static org.mockito.Mockito.mock;
80import static org.mockito.Mockito.spy;
81import 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 */
90public class ComponentContextFixture implements TestFixture<Context> {
91
92    public class FakeApplicationContext extends MockContext {
93        @Override
94        public PackageManager getPackageManager() {
95            return mPackageManager;
96        }
97
98        @Override
99        public String getPackageName() {
100            return "com.android.server.telecom.tests";
101        }
102
103        @Override
104        public String getPackageResourcePath() {
105            return "/tmp/i/dont/know";
106        }
107
108        @Override
109        public Context getApplicationContext() {
110            return mApplicationContextSpy;
111        }
112
113        @Override
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
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
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
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
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
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
197        public int getUserId() {
198            return 0;
199        }
200
201        @Override
202        public Resources getResources() {
203            return mResources;
204        }
205
206        @Override
207        public String getOpPackageName() {
208            return "com.android.server.telecom.tests";
209        }
210
211        @Override
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
250        public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
251            // TODO -- this is called by WiredHeadsetManager!!!
252            return null;
253        }
254
255        @Override
256        public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
257                String broadcastPermission, Handler scheduler) {
258            return null;
259        }
260
261        @Override
262        public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle handle,
263                IntentFilter filter, String broadcastPermission, Handler scheduler) {
264            return null;
265        }
266
267        @Override
268        public void sendBroadcast(Intent intent) {
269            // TODO -- need to ensure this is captured
270        }
271
272        @Override
273        public void sendBroadcast(Intent intent, String receiverPermission) {
274            // TODO -- need to ensure this is captured
275        }
276
277        @Override
278        public void sendBroadcastAsUser(Intent intent, UserHandle userHandle) {
279            // TODO -- need to ensure this is captured
280        }
281
282        @Override
283        public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
284                String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
285                int initialCode, String initialData, Bundle initialExtras) {
286            // TODO -- need to ensure this is captured
287        }
288
289        @Override
290        public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
291                String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
292                Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
293        }
294
295        @Override
296        public Context createPackageContextAsUser(String packageName, int flags, UserHandle user)
297                throws PackageManager.NameNotFoundException {
298            return this;
299        }
300
301        @Override
302        public int checkCallingOrSelfPermission(String permission) {
303            return PackageManager.PERMISSION_GRANTED;
304        }
305
306        @Override
307        public void enforceCallingOrSelfPermission(String permission, String message) {
308            // Don't bother enforcing anything in mock.
309        }
310
311        @Override
312        public void enforcePermission(
313                String permission, int pid, int uid, String message) {
314            // By default, don't enforce anything in mock.
315        }
316
317        @Override
318        public void startActivityAsUser(Intent intent, UserHandle userHandle) {
319            // For capturing
320        }
321    }
322
323    public class FakeAudioManager extends AudioManager {
324
325        private boolean mMute = false;
326        private boolean mSpeakerphoneOn = false;
327        private int mAudioStreamValue = 1;
328        private int mMode = AudioManager.MODE_NORMAL;
329        private int mRingerMode = AudioManager.RINGER_MODE_NORMAL;
330
331        public FakeAudioManager(Context context) {
332            super(context);
333        }
334
335        @Override
336        public void setMicrophoneMute(boolean value) {
337            mMute = value;
338        }
339
340        @Override
341        public boolean isMicrophoneMute() {
342            return mMute;
343        }
344
345        @Override
346        public void setSpeakerphoneOn(boolean value) {
347            mSpeakerphoneOn = value;
348        }
349
350        @Override
351        public boolean isSpeakerphoneOn() {
352            return mSpeakerphoneOn;
353        }
354
355        @Override
356        public void setMode(int mode) {
357            mMode = mode;
358        }
359
360        @Override
361        public int getMode() {
362            return mMode;
363        }
364
365        @Override
366        public void setRingerModeInternal(int ringerMode) {
367            mRingerMode = ringerMode;
368        }
369
370        @Override
371        public int getRingerModeInternal() {
372            return mRingerMode;
373        }
374
375        @Override
376        public void setStreamVolume(int streamTypeUnused, int index, int flagsUnused){
377            mAudioStreamValue = index;
378        }
379
380        @Override
381        public int getStreamVolume(int streamValueUnused) {
382            return mAudioStreamValue;
383        }
384    }
385
386    private final Multimap<String, ComponentName> mComponentNamesByAction =
387            ArrayListMultimap.create();
388    private final Map<ComponentName, IInterface> mServiceByComponentName = new HashMap<>();
389    private final Map<ComponentName, ServiceInfo> mServiceInfoByComponentName = new HashMap<>();
390    private final Map<IInterface, ComponentName> mComponentNameByService = new HashMap<>();
391    private final Map<ServiceConnection, IInterface> mServiceByServiceConnection = new HashMap<>();
392
393    private final Context mContext = new MockContext() {
394        @Override
395        public Context getApplicationContext() {
396            return mApplicationContextSpy;
397        }
398
399        @Override
400        public Resources getResources() {
401            return mResources;
402        }
403    };
404
405    // The application context is the most important object this class provides to the system
406    // under test.
407    private final Context mApplicationContext = new FakeApplicationContext();
408
409    // We then create a spy on the application context allowing standard Mockito-style
410    // when(...) logic to be used to add specific little responses where needed.
411
412    private final Resources mResources = mock(Resources.class);
413    private final Context mApplicationContextSpy = spy(mApplicationContext);
414    private final PackageManager mPackageManager = mock(PackageManager.class);
415    private final AudioManager mAudioManager = spy(new FakeAudioManager(mContext));
416    private final TelephonyManager mTelephonyManager = mock(TelephonyManager.class);
417    private final AppOpsManager mAppOpsManager = mock(AppOpsManager.class);
418    private final NotificationManager mNotificationManager = mock(NotificationManager.class);
419    private final UserManager mUserManager = mock(UserManager.class);
420    private final StatusBarManager mStatusBarManager = mock(StatusBarManager.class);
421    private final SubscriptionManager mSubscriptionManager = mock(SubscriptionManager.class);
422    private final CarrierConfigManager mCarrierConfigManager = mock(CarrierConfigManager.class);
423    private final CountryDetector mCountryDetector = mock(CountryDetector.class);
424    private final Map<String, IContentProvider> mIContentProviderByUri = new HashMap<>();
425    private final Configuration mResourceConfiguration = new Configuration();
426
427    private TelecomManager mTelecomManager = null;
428
429    public ComponentContextFixture() {
430        MockitoAnnotations.initMocks(this);
431        when(mResources.getConfiguration()).thenReturn(mResourceConfiguration);
432        mResourceConfiguration.setLocale(Locale.TAIWAN);
433
434        // TODO: Move into actual tests
435        when(mAudioManager.isWiredHeadsetOn()).thenReturn(false);
436
437        doAnswer(new Answer<List<ResolveInfo>>() {
438            @Override
439            public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable {
440                return doQueryIntentServices(
441                        (Intent) invocation.getArguments()[0],
442                        (Integer) invocation.getArguments()[1]);
443            }
444        }).when(mPackageManager).queryIntentServices((Intent) any(), anyInt());
445
446        doAnswer(new Answer<List<ResolveInfo>>() {
447            @Override
448            public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable {
449                return doQueryIntentServices(
450                        (Intent) invocation.getArguments()[0],
451                        (Integer) invocation.getArguments()[1]);
452            }
453        }).when(mPackageManager).queryIntentServicesAsUser((Intent) any(), anyInt(), anyInt());
454
455        when(mTelephonyManager.getSubIdForPhoneAccount((PhoneAccount) any())).thenReturn(1);
456
457        when(mTelephonyManager.getNetworkOperatorName()).thenReturn("label1");
458
459        doAnswer(new Answer<Void>(){
460            @Override
461            public Void answer(InvocationOnMock invocation) throws Throwable {
462                return null;
463            }
464        }).when(mAppOpsManager).checkPackage(anyInt(), anyString());
465
466        when(mNotificationManager.matchesCallFilter(any(Bundle.class))).thenReturn(true);
467
468        when(mUserManager.getSerialNumberForUser(any(UserHandle.class))).thenReturn(-1L);
469
470        doReturn(null).when(mApplicationContextSpy).registerReceiver(any(BroadcastReceiver.class),
471                any(IntentFilter.class));
472    }
473
474    @Override
475    public Context getTestDouble() {
476        return mContext;
477    }
478
479    public void addConnectionService(
480            ComponentName componentName,
481            IConnectionService service)
482            throws Exception {
483        addService(ConnectionService.SERVICE_INTERFACE, componentName, service);
484        ServiceInfo serviceInfo = new ServiceInfo();
485        serviceInfo.permission = android.Manifest.permission.BIND_CONNECTION_SERVICE;
486        serviceInfo.packageName = componentName.getPackageName();
487        serviceInfo.name = componentName.getClassName();
488        mServiceInfoByComponentName.put(componentName, serviceInfo);
489    }
490
491    public void addInCallService(
492            ComponentName componentName,
493            IInCallService service)
494            throws Exception {
495        addService(InCallService.SERVICE_INTERFACE, componentName, service);
496        ServiceInfo serviceInfo = new ServiceInfo();
497        serviceInfo.permission = android.Manifest.permission.BIND_INCALL_SERVICE;
498        serviceInfo.packageName = componentName.getPackageName();
499        serviceInfo.name = componentName.getClassName();
500        mServiceInfoByComponentName.put(componentName, serviceInfo);
501    }
502
503    public void putResource(int id, final String value) {
504        when(mResources.getText(eq(id))).thenReturn(value);
505        when(mResources.getString(eq(id))).thenReturn(value);
506        when(mResources.getString(eq(id), any())).thenAnswer(new Answer<String>() {
507            @Override
508            public String answer(InvocationOnMock invocation) {
509                Object[] args = invocation.getArguments();
510                return String.format(value, Arrays.copyOfRange(args, 1, args.length));
511            }
512        });
513    }
514
515    public void putBooleanResource(int id, boolean value) {
516        when(mResources.getBoolean(eq(id))).thenReturn(value);
517    }
518
519    public void setTelecomManager(TelecomManager telecomManager) {
520        mTelecomManager = telecomManager;
521    }
522
523    private void addService(String action, ComponentName name, IInterface service) {
524        mComponentNamesByAction.put(action, name);
525        mServiceByComponentName.put(name, service);
526        mComponentNameByService.put(service, name);
527    }
528
529    private List<ResolveInfo> doQueryIntentServices(Intent intent, int flags) {
530        List<ResolveInfo> result = new ArrayList<>();
531        for (ComponentName componentName : mComponentNamesByAction.get(intent.getAction())) {
532            ResolveInfo resolveInfo = new ResolveInfo();
533            resolveInfo.serviceInfo = mServiceInfoByComponentName.get(componentName);
534            resolveInfo.serviceInfo.metaData = new Bundle();
535            resolveInfo.serviceInfo.metaData.putBoolean(
536                    TelecomManager.METADATA_INCLUDE_EXTERNAL_CALLS, true);
537            result.add(resolveInfo);
538        }
539        return result;
540    }
541}
542