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