1 /*
2  * Copyright (C) 2009 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 android.telephony.cts;
18 
19 import android.bluetooth.BluetoothAdapter;
20 import android.content.Context;
21 import android.content.pm.PackageManager;
22 import android.cts.util.TestThread;
23 import android.net.ConnectivityManager;
24 import android.net.wifi.WifiInfo;
25 import android.net.wifi.WifiManager;
26 import android.os.Build;
27 import android.os.Looper;
28 import android.telecom.PhoneAccount;
29 import android.telecom.PhoneAccountHandle;
30 import android.telecom.TelecomManager;
31 import android.telephony.CellLocation;
32 import android.telephony.PhoneStateListener;
33 import android.telephony.TelephonyManager;
34 import android.test.AndroidTestCase;
35 import android.util.Log;
36 
37 import com.android.internal.telephony.PhoneConstants;
38 
39 import java.util.regex.Pattern;
40 
41 public class TelephonyManagerTest extends AndroidTestCase {
42     private TelephonyManager mTelephonyManager;
43     private boolean mOnCellLocationChangedCalled = false;
44     private final Object mLock = new Object();
45     private static final int TOLERANCE = 1000;
46     private PhoneStateListener mListener;
47     private static ConnectivityManager mCm;
48     private static final String TAG = "android.telephony.cts.TelephonyManagerTest";
49 
50     @Override
setUp()51     protected void setUp() throws Exception {
52         super.setUp();
53         mTelephonyManager =
54                 (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
55         mCm = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
56     }
57 
58     @Override
tearDown()59     protected void tearDown() throws Exception {
60         if (mListener != null) {
61             // unregister the listener
62             mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_NONE);
63         }
64         super.tearDown();
65     }
66 
testListen()67     public void testListen() throws Throwable {
68         if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
69             Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
70             return;
71         }
72 
73         if (mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
74             // TODO: temp workaround, need to adjust test to for CDMA
75             return;
76         }
77 
78         // Test register
79         TestThread t = new TestThread(new Runnable() {
80             public void run() {
81                 Looper.prepare();
82 
83                 mListener = new PhoneStateListener() {
84                     @Override
85                     public void onCellLocationChanged(CellLocation location) {
86                         if(!mOnCellLocationChangedCalled) {
87                             synchronized (mLock) {
88                                 mOnCellLocationChangedCalled = true;
89                                 mLock.notify();
90                             }
91                         }
92                     }
93                 };
94                 mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_CELL_LOCATION);
95                 CellLocation.requestLocationUpdate();
96                 Looper.loop();
97             }
98         });
99         t.start();
100         synchronized (mLock) {
101             mLock.wait(TOLERANCE);
102         }
103         assertTrue(mOnCellLocationChangedCalled);
104 
105         // Test unregister
106         t = new TestThread(new Runnable() {
107             public void run() {
108                 Looper.prepare();
109                 // unregister the listener
110                 mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_NONE);
111                 mOnCellLocationChangedCalled = false;
112                 // unregister again, to make sure doing so does not call the listener
113                 mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_NONE);
114                 CellLocation.requestLocationUpdate();
115                 Looper.loop();
116             }
117         });
118 
119         t.start();
120         synchronized (mLock) {
121             mLock.wait(TOLERANCE);
122         }
123         assertFalse(mOnCellLocationChangedCalled);
124     }
125 
126     /**
127      * The getter methods here are all related to the information about the telephony.
128      * These getters are related to concrete location, phone, service provider company, so
129      * it's no need to get details of these information, just make sure they are in right
130      * condition(>0 or not null).
131      */
testTelephonyManager()132     public void testTelephonyManager() {
133         assertTrue(mTelephonyManager.getNetworkType() >= TelephonyManager.NETWORK_TYPE_UNKNOWN);
134         assertTrue(mTelephonyManager.getPhoneType() >= TelephonyManager.PHONE_TYPE_NONE);
135         assertTrue(mTelephonyManager.getSimState() >= TelephonyManager.SIM_STATE_UNKNOWN);
136         assertTrue(mTelephonyManager.getDataActivity() >= TelephonyManager.DATA_ACTIVITY_NONE);
137         assertTrue(mTelephonyManager.getDataState() >= TelephonyManager.DATA_DISCONNECTED);
138         assertTrue(mTelephonyManager.getCallState() >= TelephonyManager.CALL_STATE_IDLE);
139 
140         // Make sure devices without MMS service won't fail on this
141         if (mTelephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE) {
142             assertFalse(mTelephonyManager.getMmsUserAgent().isEmpty());
143             assertFalse(mTelephonyManager.getMmsUAProfUrl().isEmpty());
144         }
145 
146         // The following methods may return null. Simply call them to make sure they do not
147         // throw any exceptions.
148         mTelephonyManager.getVoiceMailNumber();
149         mTelephonyManager.getSimOperatorName();
150         mTelephonyManager.getNetworkCountryIso();
151         mTelephonyManager.getCellLocation();
152         mTelephonyManager.getSimSerialNumber();
153         mTelephonyManager.getSimOperator();
154         mTelephonyManager.getNetworkOperatorName();
155         mTelephonyManager.getSubscriberId();
156         mTelephonyManager.getLine1Number();
157         mTelephonyManager.getNetworkOperator();
158         mTelephonyManager.getSimCountryIso();
159         mTelephonyManager.getVoiceMailAlphaTag();
160         mTelephonyManager.getNeighboringCellInfo();
161         mTelephonyManager.isNetworkRoaming();
162         mTelephonyManager.getDeviceId();
163         mTelephonyManager.getDeviceId(mTelephonyManager.getDefaultSim());
164         mTelephonyManager.getDeviceSoftwareVersion();
165         mTelephonyManager.getPhoneCount();
166 
167         TelecomManager telecomManager = (TelecomManager) getContext()
168             .getSystemService(Context.TELECOM_SERVICE);
169         PhoneAccountHandle defaultAccount = telecomManager
170             .getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL);
171         mTelephonyManager.getVoicemailRingtoneUri(defaultAccount);
172         mTelephonyManager.isVoicemailVibrationEnabled(defaultAccount);
173     }
174 
175     /**
176      * Tests that the phone count returned is valid.
177      */
testGetPhoneCount()178     public void testGetPhoneCount() {
179         int phoneCount = mTelephonyManager.getPhoneCount();
180         int phoneType = mTelephonyManager.getPhoneType();
181         switch (phoneType) {
182             case TelephonyManager.PHONE_TYPE_GSM:
183             case TelephonyManager.PHONE_TYPE_CDMA:
184                 assertTrue("Phone count should be > 0", phoneCount > 0);
185                 break;
186             case TelephonyManager.PHONE_TYPE_NONE:
187                 assertTrue("Phone count should be 0", phoneCount == 0 || phoneCount == 1);
188                 break;
189             default:
190                 throw new IllegalArgumentException("Did you add a new phone type? " + phoneType);
191         }
192     }
193 
194     /**
195      * Tests that the device properly reports either a valid IMEI if
196      * GSM, a valid MEID or ESN if CDMA, or a valid MAC address if
197      * only a WiFi device.
198      */
testGetDeviceId()199     public void testGetDeviceId() {
200         String deviceId = mTelephonyManager.getDeviceId();
201         verifyDeviceId(deviceId);
202     }
203 
204     /**
205      * Tests that the device properly reports either a valid IMEI if
206      * GSM, a valid MEID or ESN if CDMA, or a valid MAC address if
207      * only a WiFi device.
208      */
testGetDeviceIdForSlotId()209     public void testGetDeviceIdForSlotId() {
210         String deviceId = mTelephonyManager.getDeviceId(mTelephonyManager.getDefaultSim());
211         verifyDeviceId(deviceId);
212         // Also verify that no exception is thrown for any slot id (including invalid ones)
213         for (int i = -1; i <= mTelephonyManager.getPhoneCount(); i++) {
214             mTelephonyManager.getDeviceId(i);
215         }
216     }
217 
verifyDeviceId(String deviceId)218     private void verifyDeviceId(String deviceId) {
219         int phoneType = mTelephonyManager.getPhoneType();
220         switch (phoneType) {
221             case TelephonyManager.PHONE_TYPE_GSM:
222                 assertGsmDeviceId(deviceId);
223                 break;
224 
225             case TelephonyManager.PHONE_TYPE_CDMA:
226                 // LTE device is using IMEI as device id
227                 if (mTelephonyManager.getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE) {
228                     assertGsmDeviceId(deviceId);
229                 } else {
230                     assertCdmaDeviceId(deviceId);
231                 }
232                 break;
233 
234             case TelephonyManager.PHONE_TYPE_NONE:
235                 boolean nwSupported = mCm.isNetworkSupported(mCm.TYPE_WIFI);
236                 PackageManager packageManager = getContext().getPackageManager();
237                 // only check serial number & MAC address if device report wifi feature
238                 if (packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
239                     assertSerialNumber();
240                     assertMacAddress(getWifiMacAddress());
241                 } else if (mCm.getNetworkInfo(ConnectivityManager.TYPE_BLUETOOTH) != null) {
242                     assertSerialNumber();
243                     assertMacAddress(getBluetoothMacAddress());
244                 } else {
245                     assertTrue(mCm.getNetworkInfo(ConnectivityManager.TYPE_ETHERNET) != null);
246                 }
247                 break;
248 
249             default:
250                 throw new IllegalArgumentException("Did you add a new phone type? " + phoneType);
251         }
252     }
253 
assertGsmDeviceId(String deviceId)254     private static void assertGsmDeviceId(String deviceId) {
255         // IMEI may include the check digit
256         String imeiPattern = "[0-9]{14,15}";
257         assertTrue("IMEI device id " + deviceId + " does not match pattern " + imeiPattern,
258                 Pattern.matches(imeiPattern, deviceId));
259         if (deviceId.length() == 15) {
260             // if the ID is 15 digits, the 15th must be a check digit.
261             assertImeiCheckDigit(deviceId);
262         }
263     }
264 
assertImeiCheckDigit(String deviceId)265     private static void assertImeiCheckDigit(String deviceId) {
266         int expectedCheckDigit = getLuhnCheckDigit(deviceId.substring(0, 14));
267         int actualCheckDigit = Character.digit(deviceId.charAt(14), 10);
268         assertEquals("Incorrect check digit for " + deviceId, expectedCheckDigit, actualCheckDigit);
269     }
270 
271     /**
272      * Use decimal value (0-9) to index into array to get sum of its digits
273      * needed by Lunh check.
274      *
275      * Example: DOUBLE_DIGIT_SUM[6] = 3 because 6 * 2 = 12 => 1 + 2 = 3
276      */
277     private static final int[] DOUBLE_DIGIT_SUM = {0, 2, 4, 6, 8, 1, 3, 5, 7, 9};
278 
279     /**
280      * Calculate the check digit by starting from the right, doubling every
281      * each digit, summing all the digits including the doubled ones, and
282      * finding a number to make the sum divisible by 10.
283      *
284      * @param deviceId not including the check digit
285      * @return the check digit
286      */
getLuhnCheckDigit(String deviceId)287     private static int getLuhnCheckDigit(String deviceId) {
288         int sum = 0;
289         int dontDoubleModulus = deviceId.length() % 2;
290         for (int i = deviceId.length() - 1; i >= 0; --i) {
291             int digit = Character.digit(deviceId.charAt(i), 10);
292             if (i % 2 == dontDoubleModulus) {
293                 sum += digit;
294             } else {
295                 sum += DOUBLE_DIGIT_SUM[digit];
296             }
297         }
298         sum %= 10;
299         return sum == 0 ? 0 : 10 - sum;
300     }
301 
assertCdmaDeviceId(String deviceId)302     private static void assertCdmaDeviceId(String deviceId) {
303         // CDMA device IDs may either be a 14-hex-digit MEID or an
304         // 8-hex-digit ESN.  If it's an ESN, it may not be a
305         // pseudo-ESN.
306         if (deviceId.length() == 14) {
307             assertMeidFormat(deviceId);
308         } else if (deviceId.length() == 8) {
309             assertHexadecimalEsnFormat(deviceId);
310         } else {
311             fail("device id on CDMA must be 14-digit hex MEID or 8-digit hex ESN.");
312         }
313     }
314 
assertHexadecimalEsnFormat(String deviceId)315     private static void assertHexadecimalEsnFormat(String deviceId) {
316         String esnPattern = "[0-9a-fA-F]{8}";
317         assertTrue("ESN hex device id " + deviceId + " does not match pattern " + esnPattern,
318                    Pattern.matches(esnPattern, deviceId));
319         assertFalse("ESN hex device id " + deviceId + " must not be a pseudo-ESN",
320                     "80".equals(deviceId.substring(0, 2)));
321     }
322 
assertMeidFormat(String deviceId)323     private static void assertMeidFormat(String deviceId) {
324         // MEID must NOT include the check digit.
325         String meidPattern = "[0-9a-fA-F]{14}";
326         assertTrue("MEID device id " + deviceId + " does not match pattern " + meidPattern,
327                    Pattern.matches(meidPattern, deviceId));
328     }
329 
assertSerialNumber()330     private void assertSerialNumber() {
331         assertNotNull("Non-telephony devices must have a Build.SERIAL number.",
332                 Build.SERIAL);
333         assertTrue("Hardware id must be no longer than 20 characters.",
334                 Build.SERIAL.length() <= 20);
335         assertTrue("Hardware id must be alphanumeric.",
336                 Pattern.matches("[0-9A-Za-z]+", Build.SERIAL));
337     }
338 
assertMacAddress(String macAddress)339     private void assertMacAddress(String macAddress) {
340         String macPattern = "([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}";
341         assertTrue("MAC Address " + macAddress + " does not match pattern " + macPattern,
342                 Pattern.matches(macPattern, macAddress));
343     }
344 
345     /** @return mac address which requires the WiFi system to be enabled */
getWifiMacAddress()346     private String getWifiMacAddress() {
347         WifiManager wifiManager = (WifiManager) getContext()
348                 .getSystemService(Context.WIFI_SERVICE);
349 
350         boolean enabled = wifiManager.isWifiEnabled();
351 
352         try {
353             if (!enabled) {
354                 wifiManager.setWifiEnabled(true);
355             }
356 
357             WifiInfo wifiInfo = wifiManager.getConnectionInfo();
358             return wifiInfo.getMacAddress();
359 
360         } finally {
361             if (!enabled) {
362                 wifiManager.setWifiEnabled(false);
363             }
364         }
365     }
366 
getBluetoothMacAddress()367     private String getBluetoothMacAddress() {
368         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
369         if (adapter == null) {
370             return "";
371         }
372 
373         return adapter.getAddress();
374     }
375 
376     private static final String ISO_COUNTRY_CODE_PATTERN = "[a-z]{2}";
377 
testGetNetworkCountryIso()378     public void testGetNetworkCountryIso() {
379         PackageManager packageManager = getContext().getPackageManager();
380         String countryCode = mTelephonyManager.getNetworkCountryIso();
381         if (packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
382             assertTrue("Country code '" + countryCode + "' did not match "
383                     + ISO_COUNTRY_CODE_PATTERN,
384                     Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode));
385         } else {
386             // Non-telephony may still have the property defined if it has a SIM.
387         }
388     }
389 
testGetSimCountryIso()390     public void testGetSimCountryIso() {
391         PackageManager packageManager = getContext().getPackageManager();
392         String countryCode = mTelephonyManager.getSimCountryIso();
393         if (packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
394             assertTrue("Country code '" + countryCode + "' did not match "
395                     + ISO_COUNTRY_CODE_PATTERN,
396                     Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode));
397         } else {
398             // Non-telephony may still have the property defined if it has a SIM.
399         }
400     }
401 }
402