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.ReadElf; 23 import android.cts.util.TestThread; 24 import android.net.ConnectivityManager; 25 import android.net.wifi.WifiInfo; 26 import android.net.wifi.WifiManager; 27 import android.os.Build; 28 import android.os.Looper; 29 import android.telephony.CellLocation; 30 import android.telephony.PhoneStateListener; 31 import android.telephony.TelephonyManager; 32 import android.test.AndroidTestCase; 33 import android.util.Log; 34 35 import com.android.internal.telephony.PhoneConstants; 36 37 import java.util.regex.Pattern; 38 39 public class TelephonyManagerTest extends AndroidTestCase { 40 private TelephonyManager mTelephonyManager; 41 private boolean mOnCellLocationChangedCalled = false; 42 private final Object mLock = new Object(); 43 private static final int TOLERANCE = 1000; 44 private PhoneStateListener mListener; 45 private static ConnectivityManager mCm; 46 private static final String TAG = "android.telephony.cts.TelephonyManagerTest"; 47 48 @Override setUp()49 protected void setUp() throws Exception { 50 super.setUp(); 51 mTelephonyManager = 52 (TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE); 53 mCm = (ConnectivityManager)getContext().getSystemService(Context.CONNECTIVITY_SERVICE); 54 } 55 56 @Override tearDown()57 protected void tearDown() throws Exception { 58 if (mListener != null) { 59 // unregister the listener 60 mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_NONE); 61 } 62 super.tearDown(); 63 } 64 testListen()65 public void testListen() throws Throwable { 66 if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) { 67 Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE"); 68 return; 69 } 70 71 if (mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) { 72 // TODO: temp workaround, need to adjust test to for CDMA 73 return; 74 } 75 76 // Test register 77 TestThread t = new TestThread(new Runnable() { 78 public void run() { 79 Looper.prepare(); 80 81 mListener = new PhoneStateListener() { 82 @Override 83 public void onCellLocationChanged(CellLocation location) { 84 if(!mOnCellLocationChangedCalled) { 85 synchronized (mLock) { 86 mOnCellLocationChangedCalled = true; 87 mLock.notify(); 88 } 89 } 90 } 91 }; 92 mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_CELL_LOCATION); 93 CellLocation.requestLocationUpdate(); 94 Looper.loop(); 95 } 96 }); 97 t.start(); 98 synchronized (mLock) { 99 while (!mOnCellLocationChangedCalled) { 100 mLock.wait(); 101 } 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 168 /** 169 * Tests that the phone count returned is valid. 170 */ testGetPhoneCount()171 public void testGetPhoneCount() { 172 int phoneCount = mTelephonyManager.getPhoneCount(); 173 int phoneType = mTelephonyManager.getPhoneType(); 174 switch (phoneType) { 175 case TelephonyManager.PHONE_TYPE_GSM: 176 case TelephonyManager.PHONE_TYPE_CDMA: 177 assertTrue("Phone count should be > 0", phoneCount > 0); 178 break; 179 case TelephonyManager.PHONE_TYPE_NONE: 180 assertTrue("Phone count should be 0", phoneCount == 0 || phoneCount == 1); 181 break; 182 default: 183 throw new IllegalArgumentException("Did you add a new phone type? " + phoneType); 184 } 185 } 186 187 /** 188 * Tests that the device properly reports either a valid IMEI if 189 * GSM, a valid MEID or ESN if CDMA, or a valid MAC address if 190 * only a WiFi device. 191 */ testGetDeviceId()192 public void testGetDeviceId() { 193 String deviceId = mTelephonyManager.getDeviceId(); 194 verifyDeviceId(deviceId); 195 } 196 197 /** 198 * Tests that the device properly reports either a valid IMEI if 199 * GSM, a valid MEID or ESN if CDMA, or a valid MAC address if 200 * only a WiFi device. 201 */ testGetDeviceIdForSlotId()202 public void testGetDeviceIdForSlotId() { 203 String deviceId = mTelephonyManager.getDeviceId(mTelephonyManager.getDefaultSim()); 204 verifyDeviceId(deviceId); 205 // Also verify that no exception is thrown for any slot id (including invalid ones) 206 for (int i = -1; i <= mTelephonyManager.getPhoneCount(); i++) { 207 mTelephonyManager.getDeviceId(i); 208 } 209 } 210 verifyDeviceId(String deviceId)211 private void verifyDeviceId(String deviceId) { 212 int phoneType = mTelephonyManager.getPhoneType(); 213 switch (phoneType) { 214 case TelephonyManager.PHONE_TYPE_GSM: 215 assertGsmDeviceId(deviceId); 216 break; 217 218 case TelephonyManager.PHONE_TYPE_CDMA: 219 // LTE device is using IMEI as device id 220 if (mTelephonyManager.getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE) { 221 assertGsmDeviceId(deviceId); 222 } else { 223 assertCdmaDeviceId(deviceId); 224 } 225 break; 226 227 case TelephonyManager.PHONE_TYPE_NONE: 228 if (mCm.getNetworkInfo(ConnectivityManager.TYPE_WIFI) != null) { 229 assertSerialNumber(); 230 assertMacAddress(getWifiMacAddress()); 231 } else if (mCm.getNetworkInfo(ConnectivityManager.TYPE_BLUETOOTH) != null) { 232 assertSerialNumber(); 233 assertMacAddress(getBluetoothMacAddress()); 234 } else { 235 assertTrue(mCm.getNetworkInfo(ConnectivityManager.TYPE_ETHERNET) != null); 236 } 237 break; 238 239 default: 240 throw new IllegalArgumentException("Did you add a new phone type? " + phoneType); 241 } 242 } 243 assertGsmDeviceId(String deviceId)244 private static void assertGsmDeviceId(String deviceId) { 245 // IMEI may include the check digit 246 String imeiPattern = "[0-9]{14,15}"; 247 assertTrue("IMEI device id " + deviceId + " does not match pattern " + imeiPattern, 248 Pattern.matches(imeiPattern, deviceId)); 249 if (deviceId.length() == 15) { 250 // if the ID is 15 digits, the 15th must be a check digit. 251 assertImeiCheckDigit(deviceId); 252 } 253 } 254 assertImeiCheckDigit(String deviceId)255 private static void assertImeiCheckDigit(String deviceId) { 256 int expectedCheckDigit = getLuhnCheckDigit(deviceId.substring(0, 14)); 257 int actualCheckDigit = Character.digit(deviceId.charAt(14), 10); 258 assertEquals("Incorrect check digit for " + deviceId, expectedCheckDigit, actualCheckDigit); 259 } 260 261 /** 262 * Use decimal value (0-9) to index into array to get sum of its digits 263 * needed by Lunh check. 264 * 265 * Example: DOUBLE_DIGIT_SUM[6] = 3 because 6 * 2 = 12 => 1 + 2 = 3 266 */ 267 private static final int[] DOUBLE_DIGIT_SUM = {0, 2, 4, 6, 8, 1, 3, 5, 7, 9}; 268 269 /** 270 * Calculate the check digit by starting from the right, doubling every 271 * each digit, summing all the digits including the doubled ones, and 272 * finding a number to make the sum divisible by 10. 273 * 274 * @param deviceId not including the check digit 275 * @return the check digit 276 */ getLuhnCheckDigit(String deviceId)277 private static int getLuhnCheckDigit(String deviceId) { 278 int sum = 0; 279 int dontDoubleModulus = deviceId.length() % 2; 280 for (int i = deviceId.length() - 1; i >= 0; --i) { 281 int digit = Character.digit(deviceId.charAt(i), 10); 282 if (i % 2 == dontDoubleModulus) { 283 sum += digit; 284 } else { 285 sum += DOUBLE_DIGIT_SUM[digit]; 286 } 287 } 288 sum %= 10; 289 return sum == 0 ? 0 : 10 - sum; 290 } 291 assertCdmaDeviceId(String deviceId)292 private static void assertCdmaDeviceId(String deviceId) { 293 // CDMA device IDs may either be a 14-hex-digit MEID or an 294 // 8-hex-digit ESN. If it's an ESN, it may not be a 295 // pseudo-ESN. 296 if (deviceId.length() == 14) { 297 assertMeidFormat(deviceId); 298 } else if (deviceId.length() == 8) { 299 assertHexadecimalEsnFormat(deviceId); 300 } else { 301 fail("device id on CDMA must be 14-digit hex MEID or 8-digit hex ESN."); 302 } 303 } 304 assertHexadecimalEsnFormat(String deviceId)305 private static void assertHexadecimalEsnFormat(String deviceId) { 306 String esnPattern = "[0-9a-fA-F]{8}"; 307 assertTrue("ESN hex device id " + deviceId + " does not match pattern " + esnPattern, 308 Pattern.matches(esnPattern, deviceId)); 309 assertFalse("ESN hex device id " + deviceId + " must not be a pseudo-ESN", 310 "80".equals(deviceId.substring(0, 2))); 311 } 312 assertMeidFormat(String deviceId)313 private static void assertMeidFormat(String deviceId) { 314 // MEID must NOT include the check digit. 315 String meidPattern = "[0-9a-fA-F]{14}"; 316 assertTrue("MEID device id " + deviceId + " does not match pattern " + meidPattern, 317 Pattern.matches(meidPattern, deviceId)); 318 } 319 assertSerialNumber()320 private void assertSerialNumber() { 321 assertNotNull("Non-telephony devices must have a Build.SERIAL number.", 322 Build.SERIAL); 323 assertTrue("Hardware id must be no longer than 20 characters.", 324 Build.SERIAL.length() <= 20); 325 assertTrue("Hardware id must be alphanumeric.", 326 Pattern.matches("[0-9A-Za-z]+", Build.SERIAL)); 327 } 328 assertMacAddress(String macAddress)329 private void assertMacAddress(String macAddress) { 330 String macPattern = "([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}"; 331 assertTrue("MAC Address " + macAddress + " does not match pattern " + macPattern, 332 Pattern.matches(macPattern, macAddress)); 333 } 334 335 /** @return mac address which requires the WiFi system to be enabled */ getWifiMacAddress()336 private String getWifiMacAddress() { 337 WifiManager wifiManager = (WifiManager) getContext() 338 .getSystemService(Context.WIFI_SERVICE); 339 340 boolean enabled = wifiManager.isWifiEnabled(); 341 342 try { 343 if (!enabled) { 344 wifiManager.setWifiEnabled(true); 345 } 346 347 WifiInfo wifiInfo = wifiManager.getConnectionInfo(); 348 return wifiInfo.getMacAddress(); 349 350 } finally { 351 if (!enabled) { 352 wifiManager.setWifiEnabled(false); 353 } 354 } 355 } 356 getBluetoothMacAddress()357 private String getBluetoothMacAddress() { 358 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 359 if (adapter == null) { 360 return ""; 361 } 362 363 return adapter.getAddress(); 364 } 365 366 private static final String ISO_COUNTRY_CODE_PATTERN = "[a-z]{2}"; 367 testGetNetworkCountryIso()368 public void testGetNetworkCountryIso() { 369 PackageManager packageManager = getContext().getPackageManager(); 370 String countryCode = mTelephonyManager.getNetworkCountryIso(); 371 if (packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { 372 assertTrue("Country code '" + countryCode + "' did not match " 373 + ISO_COUNTRY_CODE_PATTERN, 374 Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode)); 375 } else { 376 // Non-telephony may still have the property defined if it has a SIM. 377 } 378 } 379 testGetSimCountryIso()380 public void testGetSimCountryIso() { 381 PackageManager packageManager = getContext().getPackageManager(); 382 String countryCode = mTelephonyManager.getSimCountryIso(); 383 if (packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { 384 assertTrue("Country code '" + countryCode + "' did not match " 385 + ISO_COUNTRY_CODE_PATTERN, 386 Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode)); 387 } else { 388 // Non-telephony may still have the property defined if it has a SIM. 389 } 390 } 391 } 392