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