1/*
2 * Copyright (C) 2016 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.internal.telephony;
18
19import static org.junit.Assert.fail;
20import static org.mockito.Matchers.anyBoolean;
21import static org.mockito.Matchers.anyLong;
22import static org.mockito.Matchers.anyString;
23import static org.mockito.Mockito.any;
24import static org.mockito.Mockito.anyInt;
25import static org.mockito.Mockito.doAnswer;
26import static org.mockito.Mockito.doReturn;
27import static org.mockito.Mockito.eq;
28
29import android.app.ActivityManagerNative;
30import android.app.IActivityManager;
31import android.content.Context;
32import android.content.IIntentSender;
33import android.content.Intent;
34import android.content.SharedPreferences;
35import android.content.pm.PackageInfo;
36import android.content.pm.PackageManager;
37import android.database.Cursor;
38import android.os.Bundle;
39import android.os.Handler;
40import android.os.IBinder;
41import android.os.IDeviceIdleController;
42import android.os.RegistrantList;
43import android.os.ServiceManager;
44import android.provider.BlockedNumberContract;
45import android.telephony.ServiceState;
46import android.telephony.TelephonyManager;
47import android.test.mock.MockContentProvider;
48import android.test.mock.MockContentResolver;
49import android.util.Log;
50import android.util.Singleton;
51import android.util.SparseArray;
52
53import com.android.ims.ImsCall;
54import com.android.ims.ImsCallProfile;
55import com.android.ims.ImsEcbm;
56import com.android.ims.ImsManager;
57import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
58import com.android.internal.telephony.cdma.EriManager;
59import com.android.internal.telephony.dataconnection.DcTracker;
60import com.android.internal.telephony.imsphone.ImsPhone;
61import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
62import com.android.internal.telephony.mocks.TelephonyRegistryMock;
63import com.android.internal.telephony.test.SimulatedCommands;
64import com.android.internal.telephony.test.SimulatedCommandsVerifier;
65import com.android.internal.telephony.uicc.IccCardProxy;
66import com.android.internal.telephony.uicc.IccRecords;
67import com.android.internal.telephony.uicc.IsimUiccRecords;
68import com.android.internal.telephony.uicc.RuimRecords;
69import com.android.internal.telephony.uicc.SIMRecords;
70import com.android.internal.telephony.uicc.UiccCardApplication;
71import com.android.internal.telephony.uicc.UiccController;
72
73import org.mockito.Mock;
74import org.mockito.MockitoAnnotations;
75import org.mockito.invocation.InvocationOnMock;
76import org.mockito.stubbing.Answer;
77
78import java.lang.reflect.Field;
79import java.util.HashMap;
80import java.util.HashSet;
81import java.util.Iterator;
82import java.util.LinkedList;
83import java.util.Set;
84
85public abstract class TelephonyTest {
86    protected static String TAG;
87
88    @Mock
89    protected GsmCdmaPhone mPhone;
90    @Mock
91    protected ImsPhone mImsPhone;
92    @Mock
93    protected ServiceStateTracker mSST;
94    @Mock
95    protected GsmCdmaCallTracker mCT;
96    @Mock
97    protected ImsPhoneCallTracker mImsCT;
98    @Mock
99    protected UiccController mUiccController;
100    @Mock
101    protected IccCardProxy mIccCardProxy;
102    @Mock
103    protected CallManager mCallManager;
104    @Mock
105    protected PhoneNotifier mNotifier;
106    @Mock
107    protected TelephonyComponentFactory mTelephonyComponentFactory;
108    @Mock
109    protected CdmaSubscriptionSourceManager mCdmaSSM;
110    @Mock
111    protected RegistrantList mRegistrantList;
112    @Mock
113    protected IccPhoneBookInterfaceManager mIccPhoneBookIntManager;
114    @Mock
115    protected ImsManager mImsManager;
116    @Mock
117    protected DcTracker mDcTracker;
118    @Mock
119    protected GsmCdmaCall mGsmCdmaCall;
120    @Mock
121    protected ImsCall mImsCall;
122    @Mock
123    protected ImsCallProfile mImsCallProfile;
124    @Mock
125    protected ImsEcbm mImsEcbm;
126    @Mock
127    protected SubscriptionController mSubscriptionController;
128    @Mock
129    protected ServiceState mServiceState;
130    @Mock
131    protected SimulatedCommandsVerifier mSimulatedCommandsVerifier;
132    @Mock
133    protected IDeviceIdleController mIDeviceIdleController;
134    @Mock
135    protected InboundSmsHandler mInboundSmsHandler;
136    @Mock
137    protected WspTypeDecoder mWspTypeDecoder;
138    @Mock
139    protected UiccCardApplication mUiccCardApplication3gpp;
140    @Mock
141    protected UiccCardApplication mUiccCardApplication3gpp2;
142    @Mock
143    protected UiccCardApplication mUiccCardApplicationIms;
144    @Mock
145    protected SIMRecords mSimRecords;
146    @Mock
147    protected RuimRecords mRuimRecords;
148    @Mock
149    protected IsimUiccRecords mIsimUiccRecords;
150    @Mock
151    protected ProxyController mProxyController;
152    @Mock
153    protected Singleton<IActivityManager> mIActivityManagerSingleton;
154    @Mock
155    protected IActivityManager mIActivityManager;
156    @Mock
157    protected InboundSmsTracker mInboundSmsTracker;
158    @Mock
159    protected IIntentSender mIIntentSender;
160    @Mock
161    protected IBinder mIBinder;
162    @Mock
163    protected SmsStorageMonitor mSmsStorageMonitor;
164    @Mock
165    protected SmsUsageMonitor mSmsUsageMonitor;
166    @Mock
167    protected PackageInfo mPackageInfo;
168    @Mock
169    protected EriManager mEriManager;
170    @Mock
171    protected IBinder mConnMetLoggerBinder;
172
173    protected TelephonyManager mTelephonyManager;
174    protected SimulatedCommands mSimulatedCommands;
175    protected ContextFixture mContextFixture;
176    protected Context mContext;
177    protected FakeBlockedNumberContentProvider mFakeBlockedNumberContentProvider;
178    private Object mLock = new Object();
179    private boolean mReady;
180    protected HashMap<String, IBinder> mServiceManagerMockedServices = new HashMap<>();
181
182
183    protected HashMap<Integer, ImsManager> mImsManagerInstances = new HashMap<>();
184    private HashMap<InstanceKey, Object> mOldInstances = new HashMap<InstanceKey, Object>();
185
186    private LinkedList<InstanceKey> mInstanceKeys = new LinkedList<InstanceKey>();
187
188    private class InstanceKey {
189        public final Class mClass;
190        public final String mInstName;
191        public final Object mObj;
192        InstanceKey(final Class c, final String instName, final Object obj) {
193            mClass = c;
194            mInstName = instName;
195            mObj = obj;
196        }
197
198        @Override
199        public int hashCode() {
200            return (mClass.getName().hashCode() * 31 + mInstName.hashCode()) * 31;
201        }
202
203        @Override
204        public boolean equals(Object obj) {
205            if (obj == null || obj.getClass() != getClass()) {
206                return false;
207            }
208
209            InstanceKey other = (InstanceKey) obj;
210            return (other.mClass == mClass && other.mInstName.equals(mInstName)
211                    && other.mObj == mObj);
212        }
213    }
214
215    protected void waitUntilReady() {
216        while (true) {
217            synchronized (mLock) {
218                if (mReady) {
219                    break;
220                }
221            }
222        }
223    }
224
225    protected void setReady(boolean ready) {
226        synchronized (mLock) {
227            mReady = ready;
228        }
229    }
230
231    protected synchronized void replaceInstance(final Class c, final String instanceName,
232                                                final Object obj, final Object newValue)
233            throws Exception {
234        Field field = c.getDeclaredField(instanceName);
235        field.setAccessible(true);
236
237        InstanceKey key = new InstanceKey(c, instanceName, obj);
238        if (!mOldInstances.containsKey(key)) {
239            mOldInstances.put(key, field.get(obj));
240            mInstanceKeys.add(key);
241        }
242        field.set(obj, newValue);
243    }
244
245    protected synchronized void restoreInstance(final Class c, final String instanceName,
246                                                final Object obj) throws Exception {
247        InstanceKey key = new InstanceKey(c, instanceName, obj);
248        if (mOldInstances.containsKey(key)) {
249            Field field = c.getDeclaredField(instanceName);
250            field.setAccessible(true);
251            field.set(obj, mOldInstances.get(key));
252            mOldInstances.remove(key);
253            mInstanceKeys.remove(key);
254        }
255    }
256
257    protected synchronized void restoreInstances() throws Exception {
258        Iterator<InstanceKey> it = mInstanceKeys.descendingIterator();
259
260        while (it.hasNext()) {
261            InstanceKey key = it.next();
262            Field field = key.mClass.getDeclaredField(key.mInstName);
263            field.setAccessible(true);
264            field.set(key.mObj, mOldInstances.get(key));
265        }
266
267        mInstanceKeys.clear();
268        mOldInstances.clear();
269    }
270
271    protected void setUp(String tag) throws Exception {
272        TAG = tag;
273        MockitoAnnotations.initMocks(this);
274
275        //Use reflection to mock singletons
276        replaceInstance(CallManager.class, "INSTANCE", null, mCallManager);
277        replaceInstance(TelephonyComponentFactory.class, "sInstance", null,
278                mTelephonyComponentFactory);
279        replaceInstance(UiccController.class, "mInstance", null, mUiccController);
280        replaceInstance(CdmaSubscriptionSourceManager.class, "sInstance", null, mCdmaSSM);
281        replaceInstance(ImsManager.class, "sImsManagerInstances", null, mImsManagerInstances);
282        replaceInstance(SubscriptionController.class, "sInstance", null, mSubscriptionController);
283        replaceInstance(ProxyController.class, "sProxyController", null, mProxyController);
284        replaceInstance(ActivityManagerNative.class, "gDefault", null, mIActivityManagerSingleton);
285        replaceInstance(CdmaSubscriptionSourceManager.class,
286                "mCdmaSubscriptionSourceChangedRegistrants", mCdmaSSM, mRegistrantList);
287        replaceInstance(SimulatedCommandsVerifier.class, "sInstance", null,
288                mSimulatedCommandsVerifier);
289        replaceInstance(Singleton.class, "mInstance", mIActivityManagerSingleton,
290                mIActivityManager);
291        replaceInstance(ServiceManager.class, "sCache", null, mServiceManagerMockedServices);
292
293        mSimulatedCommands = new SimulatedCommands();
294        mContextFixture = new ContextFixture();
295        mContext = mContextFixture.getTestDouble();
296        mFakeBlockedNumberContentProvider = new FakeBlockedNumberContentProvider();
297        ((MockContentResolver)mContext.getContentResolver()).addProvider(
298                BlockedNumberContract.AUTHORITY, mFakeBlockedNumberContentProvider);
299        mPhone.mCi = mSimulatedCommands;
300        mCT.mCi = mSimulatedCommands;
301        mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
302
303        replaceInstance(TelephonyManager.class, "sInstance", null,
304                mContext.getSystemService(Context.TELEPHONY_SERVICE));
305
306        //mTelephonyComponentFactory
307        doReturn(mSST).when(mTelephonyComponentFactory)
308                .makeServiceStateTracker(any(GsmCdmaPhone.class), any(CommandsInterface.class));
309        doReturn(mIccCardProxy).when(mTelephonyComponentFactory)
310                .makeIccCardProxy(any(Context.class), any(CommandsInterface.class), anyInt());
311        doReturn(mCT).when(mTelephonyComponentFactory)
312                .makeGsmCdmaCallTracker(any(GsmCdmaPhone.class));
313        doReturn(mIccPhoneBookIntManager).when(mTelephonyComponentFactory)
314                .makeIccPhoneBookInterfaceManager(any(Phone.class));
315        doReturn(mDcTracker).when(mTelephonyComponentFactory)
316                .makeDcTracker(any(Phone.class));
317        doReturn(mWspTypeDecoder).when(mTelephonyComponentFactory)
318                .makeWspTypeDecoder(any(byte[].class));
319        doReturn(mInboundSmsTracker).when(mTelephonyComponentFactory)
320                .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(),
321                        anyBoolean(), anyString(), anyString());
322        doReturn(mInboundSmsTracker).when(mTelephonyComponentFactory)
323                .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(),
324                        anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyString());
325        doReturn(mInboundSmsTracker).when(mTelephonyComponentFactory)
326                .makeInboundSmsTracker(any(Cursor.class), anyBoolean());
327        doReturn(mImsCT).when(mTelephonyComponentFactory)
328                .makeImsPhoneCallTracker(any(ImsPhone.class));
329        doReturn(mCdmaSSM).when(mTelephonyComponentFactory)
330                .getCdmaSubscriptionSourceManagerInstance(any(Context.class),
331                        any(CommandsInterface.class), any(Handler.class),
332                        anyInt(), any(Object.class));
333        doReturn(mIDeviceIdleController).when(mTelephonyComponentFactory)
334                .getIDeviceIdleController();
335
336        //mPhone
337        doReturn(mContext).when(mPhone).getContext();
338        doReturn(mContext).when(mImsPhone).getContext();
339        doReturn(true).when(mPhone).getUnitTestMode();
340        doReturn(mIccCardProxy).when(mPhone).getIccCard();
341        doReturn(mServiceState).when(mPhone).getServiceState();
342        doReturn(mServiceState).when(mImsPhone).getServiceState();
343        doReturn(true).when(mPhone).isPhoneTypeGsm();
344        doReturn(PhoneConstants.PHONE_TYPE_GSM).when(mPhone).getPhoneType();
345        doReturn(mCT).when(mPhone).getCallTracker();
346        doReturn(mSST).when(mPhone).getServiceStateTracker();
347        mPhone.mEriManager = mEriManager;
348
349        //mUiccController
350        doReturn(mUiccCardApplication3gpp).when(mUiccController).getUiccCardApplication(anyInt(),
351                eq(UiccController.APP_FAM_3GPP));
352        doReturn(mUiccCardApplication3gpp2).when(mUiccController).getUiccCardApplication(anyInt(),
353                eq(UiccController.APP_FAM_3GPP2));
354        doReturn(mUiccCardApplicationIms).when(mUiccController).getUiccCardApplication(anyInt(),
355                eq(UiccController.APP_FAM_IMS));
356
357        doAnswer(new Answer<IccRecords>() {
358            public IccRecords answer(InvocationOnMock invocation) {
359                switch ((Integer) invocation.getArguments()[1]) {
360                    case UiccController.APP_FAM_3GPP:
361                        return mSimRecords;
362                    case UiccController.APP_FAM_3GPP2:
363                        return mRuimRecords;
364                    case UiccController.APP_FAM_IMS:
365                        return mIsimUiccRecords;
366                    default:
367                        logd("Unrecognized family " + invocation.getArguments()[1]);
368                        return null;
369                }
370            }
371        }).when(mUiccController).getIccRecords(anyInt(), anyInt());
372
373        //UiccCardApplication
374        doReturn(mSimRecords).when(mUiccCardApplication3gpp).getIccRecords();
375        doReturn(mRuimRecords).when(mUiccCardApplication3gpp2).getIccRecords();
376        doReturn(mIsimUiccRecords).when(mUiccCardApplicationIms).getIccRecords();
377
378        //mIccCardProxy
379        doReturn(mSimRecords).when(mIccCardProxy).getIccRecords();
380        doAnswer(new Answer<IccRecords>() {
381            public IccRecords answer(InvocationOnMock invocation) {
382                return (mPhone.isPhoneTypeGsm()) ? mSimRecords : mRuimRecords;
383            }
384        }).when(mIccCardProxy).getIccRecords();
385
386        //SMS
387        doReturn(true).when(mSmsStorageMonitor).isStorageAvailable();
388        doReturn(true).when(mSmsUsageMonitor).check(anyString(), anyInt());
389        doReturn(true).when(mTelephonyManager).getSmsReceiveCapableForPhone(anyInt(), anyBoolean());
390        doReturn(true).when(mTelephonyManager).getSmsSendCapableForPhone(
391                anyInt(), anyBoolean());
392
393        //Misc
394        doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS).when(mServiceState).
395                getRilDataRadioTechnology();
396        doReturn(mPhone).when(mCT).getPhone();
397        mImsManagerInstances.put(mPhone.getPhoneId(), null);
398        doReturn(mImsEcbm).when(mImsManager).getEcbmInterface(anyInt());
399        doReturn(mPhone).when(mInboundSmsHandler).getPhone();
400        doReturn(mImsCallProfile).when(mImsCall).getCallProfile();
401        doReturn(mIBinder).when(mIIntentSender).asBinder();
402        doReturn(mIIntentSender).when(mIActivityManager).getIntentSender(anyInt(),
403                anyString(), any(IBinder.class), anyString(), anyInt(), any(Intent[].class),
404                any(String[].class), anyInt(), any(Bundle.class), anyInt());
405        mSST.mSS = mServiceState;
406        mServiceManagerMockedServices.put("connectivity_metrics_logger", mConnMetLoggerBinder);
407
408        setReady(false);
409    }
410
411    protected void tearDown() throws Exception {
412
413        SharedPreferences sharedPreferences = mContext.getSharedPreferences((String) null, 0);
414        sharedPreferences.edit().clear().commit();
415
416        restoreInstances();
417    }
418
419    protected static void logd(String s) {
420        Log.d(TAG, s);
421    }
422
423    public static class FakeBlockedNumberContentProvider extends MockContentProvider {
424        public Set<String> mBlockedNumbers = new HashSet<>();
425        public int mNumEmergencyContactNotifications = 0;
426
427        @Override
428        public Bundle call(String method, String arg, Bundle extras) {
429            switch (method) {
430                case BlockedNumberContract.SystemContract.METHOD_SHOULD_SYSTEM_BLOCK_NUMBER:
431                    Bundle bundle = new Bundle();
432                    bundle.putBoolean(BlockedNumberContract.RES_NUMBER_IS_BLOCKED,
433                            mBlockedNumbers.contains(arg));
434                    return bundle;
435                case BlockedNumberContract.SystemContract.METHOD_NOTIFY_EMERGENCY_CONTACT:
436                    mNumEmergencyContactNotifications++;
437                    return new Bundle();
438                default:
439                    fail("Method not expected: " + method);
440            }
441            return null;
442        }
443    }
444
445    protected void setupMockPackagePermissionChecks() throws Exception {
446        PackageManager mockPackageManager = mContext.getPackageManager();
447        doReturn(new String[]{TAG}).when(mockPackageManager).getPackagesForUid(anyInt());
448        doReturn(mPackageInfo).when(mockPackageManager).getPackageInfo(eq(TAG), anyInt());
449    }
450}
451