ComponentContextFixture.java revision 1b5490ac8643a5969adaba6f68d872acd251d666
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.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.media.AudioManager;
46import android.os.Bundle;
47import android.os.Handler;
48import android.os.IInterface;
49import android.os.UserHandle;
50import android.os.UserManager;
51import android.telecom.ConnectionService;
52import android.telecom.InCallService;
53import android.telecom.PhoneAccount;
54import android.telephony.SubscriptionManager;
55import android.telephony.TelephonyManager;
56import android.test.mock.MockContext;
57
58import java.io.File;
59import java.io.IOException;
60import java.util.ArrayList;
61import java.util.HashMap;
62import java.util.List;
63import java.util.Locale;
64import java.util.Map;
65
66import static org.mockito.Matchers.anyString;
67import static org.mockito.Mockito.any;
68import static org.mockito.Mockito.anyInt;
69import static org.mockito.Mockito.doAnswer;
70import static org.mockito.Mockito.eq;
71import static org.mockito.Mockito.mock;
72import static org.mockito.Mockito.spy;
73import static org.mockito.Mockito.when;
74
75/**
76 * Controls a test {@link Context} as would be provided by the Android framework to an
77 * {@code Activity}, {@code Service} or other system-instantiated component.
78 *
79 * The {@link Context} created by this object is "hollow" but its {@code applicationContext}
80 * property points to an application context implementing all the nontrivial functionality.
81 */
82public class ComponentContextFixture implements TestFixture<Context> {
83
84    public class TestApplicationContext extends MockContext {
85        @Override
86        public PackageManager getPackageManager() {
87            return mPackageManager;
88        }
89
90        @Override
91        public File getFilesDir() {
92            try {
93                return File.createTempFile("temp", "temp").getParentFile();
94            } catch (IOException e) {
95                throw new RuntimeException(e);
96            }
97        }
98
99        @Override
100        public boolean bindServiceAsUser(
101                Intent serviceIntent,
102                ServiceConnection connection,
103                int flags,
104                UserHandle userHandle) {
105            // TODO: Implement "as user" functionality
106            return bindService(serviceIntent, connection, flags);
107        }
108
109        @Override
110        public boolean bindService(
111                Intent serviceIntent,
112                ServiceConnection connection,
113                int flags) {
114            if (mServiceByServiceConnection.containsKey(connection)) {
115                throw new RuntimeException("ServiceConnection already bound: " + connection);
116            }
117            IInterface service = mServiceByComponentName.get(serviceIntent.getComponent());
118            if (service == null) {
119                throw new RuntimeException("ServiceConnection not found: "
120                        + serviceIntent.getComponent());
121            }
122            mServiceByServiceConnection.put(connection, service);
123            connection.onServiceConnected(serviceIntent.getComponent(), service.asBinder());
124            return true;
125        }
126
127        @Override
128        public void unbindService(
129                ServiceConnection connection) {
130            IInterface service = mServiceByServiceConnection.remove(connection);
131            if (service == null) {
132                throw new RuntimeException("ServiceConnection not found: " + connection);
133            }
134            connection.onServiceDisconnected(mComponentNameByService.get(service));
135        }
136
137        @Override
138        public Object getSystemService(String name) {
139            switch (name) {
140                case Context.AUDIO_SERVICE:
141                    return mAudioManager;
142                case Context.TELEPHONY_SERVICE:
143                    return mTelephonyManager;
144                case Context.APP_OPS_SERVICE:
145                    return mAppOpsManager;
146                case Context.NOTIFICATION_SERVICE:
147                    return mNotificationManager;
148                case Context.USER_SERVICE:
149                    return mUserManager;
150                case Context.TELEPHONY_SUBSCRIPTION_SERVICE:
151                    return mSubscriptionManager;
152                default:
153                    return null;
154            }
155        }
156
157        @Override
158        public int getUserId() {
159            return 0;
160        }
161
162        @Override
163        public Resources getResources() {
164            return mResources;
165        }
166
167        @Override
168        public String getOpPackageName() {
169            return "test";
170        }
171
172        @Override
173        public ContentResolver getContentResolver() {
174            return new ContentResolver(mApplicationContextSpy) {
175                @Override
176                protected IContentProvider acquireProvider(Context c, String name) {
177                    Log.i(this, "acquireProvider %s", name);
178                    return mock(IContentProvider.class);
179                }
180
181                @Override
182                public boolean releaseProvider(IContentProvider icp) {
183                    return true;
184                }
185
186                @Override
187                protected IContentProvider acquireUnstableProvider(Context c, String name) {
188                    Log.i(this, "acquireUnstableProvider %s", name);
189                    return mock(IContentProvider.class);
190                }
191
192                @Override
193                public boolean releaseUnstableProvider(IContentProvider icp) {
194                    return false;
195                }
196
197                @Override
198                public void unstableProviderDied(IContentProvider icp) {
199                }
200            };
201        }
202
203        @Override
204        public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
205            // TODO -- this is called by WiredHeadsetManager!!!
206            return null;
207        }
208
209        @Override
210        public void sendBroadcast(Intent intent) {
211            // TODO -- need to ensure this is captured
212        }
213
214        @Override
215        public void sendBroadcast(Intent intent, String receiverPermission) {
216            // TODO -- need to ensure this is captured
217        }
218
219        @Override
220        public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
221                String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
222                int initialCode, String initialData, Bundle initialExtras) {
223            // TODO -- need to ensure this is captured
224        }
225
226        @Override
227        public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
228                String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
229                Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
230        }
231
232        @Override
233        public Context createPackageContextAsUser(String packageName, int flags, UserHandle user)
234                throws PackageManager.NameNotFoundException {
235            return this;
236        }
237    };
238
239    private final Multimap<String, ComponentName> mComponentNamesByAction =
240            ArrayListMultimap.create();
241    private final Map<ComponentName, IInterface> mServiceByComponentName = new HashMap<>();
242    private final Map<ComponentName, ServiceInfo> mServiceInfoByComponentName = new HashMap<>();
243    private final Map<IInterface, ComponentName> mComponentNameByService = new HashMap<>();
244    private final Map<ServiceConnection, IInterface> mServiceByServiceConnection = new HashMap<>();
245
246    private final Context mContext = new MockContext() {
247        @Override
248        public Context getApplicationContext() {
249            return mApplicationContextSpy;
250        }
251    };
252
253    // The application context is the most important object this class provides to the system
254    // under test.
255    private final Context mApplicationContext = new TestApplicationContext();
256
257    // We then create a spy on the application context allowing standard Mockito-style
258    // when(...) logic to be used to add specific little responses where needed.
259
260    private final Context mApplicationContextSpy = spy(mApplicationContext);
261    private final PackageManager mPackageManager = mock(PackageManager.class);
262    private final AudioManager mAudioManager = mock(AudioManager.class);
263    private final TelephonyManager mTelephonyManager = mock(TelephonyManager.class);
264    private final AppOpsManager mAppOpsManager = mock(AppOpsManager.class);
265    private final NotificationManager mNotificationManager = mock(NotificationManager.class);
266    private final UserManager mUserManager = mock(UserManager.class);
267    private final SubscriptionManager mSubscriptionManager = mock(SubscriptionManager.class);
268    private final Resources mResources = mock(Resources.class);
269    private final Configuration mResourceConfiguration = new Configuration();
270
271    public ComponentContextFixture() {
272        MockitoAnnotations.initMocks(this);
273        when(mResources.getConfiguration()).thenReturn(mResourceConfiguration);
274        mResourceConfiguration.setLocale(Locale.TAIWAN);
275
276        // TODO: Move into actual tests
277        when(mAudioManager.isWiredHeadsetOn()).thenReturn(false);
278
279        doAnswer(new Answer<List<ResolveInfo>>() {
280            @Override
281            public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable {
282                return doQueryIntentServices(
283                        (Intent) invocation.getArguments()[0],
284                        (Integer) invocation.getArguments()[1]);
285            }
286        }).when(mPackageManager).queryIntentServices((Intent) any(), anyInt());
287
288        doAnswer(new Answer<List<ResolveInfo>>() {
289            @Override
290            public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable {
291                return doQueryIntentServices(
292                        (Intent) invocation.getArguments()[0],
293                        (Integer) invocation.getArguments()[1]);
294            }
295        }).when(mPackageManager).queryIntentServicesAsUser((Intent) any(), anyInt(), anyInt());
296
297        when(mTelephonyManager.getSubIdForPhoneAccount((PhoneAccount) any())).thenReturn(1);
298
299        doAnswer(new Answer<Void>(){
300            @Override
301            public Void answer(InvocationOnMock invocation) throws Throwable {
302                return null;
303            }
304        }).when(mAppOpsManager).checkPackage(anyInt(), anyString());
305
306        when(mNotificationManager.matchesCallFilter(any(Bundle.class))).thenReturn(true);
307
308        when(mUserManager.getSerialNumberForUser(any(UserHandle.class))).thenReturn(-1L);
309    }
310
311    @Override
312    public Context getTestDouble() {
313        return mContext;
314    }
315
316    public void addConnectionService(
317            ComponentName componentName,
318            IConnectionService service)
319            throws Exception {
320        addService(ConnectionService.SERVICE_INTERFACE, componentName, service);
321        ServiceInfo serviceInfo = new ServiceInfo();
322        serviceInfo.permission = android.Manifest.permission.BIND_CONNECTION_SERVICE;
323        serviceInfo.packageName = componentName.getPackageName();
324        serviceInfo.name = componentName.getClassName();
325        mServiceInfoByComponentName.put(componentName, serviceInfo);
326    }
327
328    public void addInCallService(
329            ComponentName componentName,
330            IInCallService service)
331            throws Exception {
332        addService(InCallService.SERVICE_INTERFACE, componentName, service);
333        ServiceInfo serviceInfo = new ServiceInfo();
334        serviceInfo.permission = android.Manifest.permission.BIND_INCALL_SERVICE;
335        serviceInfo.packageName = componentName.getPackageName();
336        serviceInfo.name = componentName.getClassName();
337        mServiceInfoByComponentName.put(componentName, serviceInfo);
338    }
339
340    public void putResource(int id, String value) {
341        when(mResources.getString(eq(id))).thenReturn(value);
342    }
343
344    private void addService(String action, ComponentName name, IInterface service) {
345        mComponentNamesByAction.put(action, name);
346        mServiceByComponentName.put(name, service);
347        mComponentNameByService.put(service, name);
348    }
349
350    private List<ResolveInfo> doQueryIntentServices(Intent intent, int flags) {
351        List<ResolveInfo> result = new ArrayList<>();
352        for (ComponentName componentName : mComponentNamesByAction.get(intent.getAction())) {
353            ResolveInfo resolveInfo = new ResolveInfo();
354            resolveInfo.serviceInfo = mServiceInfoByComponentName.get(componentName);
355            result.add(resolveInfo);
356        }
357        return result;
358    }
359}
360