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 synchronized (mLock) { 85 mOnCellLocationChangedCalled = true; 86 mLock.notify(); 87 } 88 } 89 }; 90 mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_CELL_LOCATION); 91 CellLocation.requestLocationUpdate(); 92 Looper.loop(); 93 } 94 }); 95 t.start(); 96 synchronized (mLock) { 97 while (!mOnCellLocationChangedCalled) { 98 mLock.wait(); 99 } 100 } 101 assertTrue(mOnCellLocationChangedCalled); 102 103 // Test unregister 104 t = new TestThread(new Runnable() { 105 public void run() { 106 Looper.prepare(); 107 // unregister the listener 108 mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_NONE); 109 mOnCellLocationChangedCalled = false; 110 // unregister again, to make sure doing so does not call the listener 111 mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_NONE); 112 CellLocation.requestLocationUpdate(); 113 Looper.loop(); 114 } 115 }); 116 117 t.start(); 118 synchronized (mLock) { 119 mLock.wait(TOLERANCE); 120 } 121 assertFalse(mOnCellLocationChangedCalled); 122 } 123 124 /** 125 * The getter methods here are all related to the information about the telephony. 126 * These getters are related to concrete location, phone, service provider company, so 127 * it's no need to get details of these information, just make sure they are in right 128 * condition(>0 or not null). 129 */ testTelephonyManager()130 public void testTelephonyManager() { 131 assertTrue(mTelephonyManager.getNetworkType() >= TelephonyManager.NETWORK_TYPE_UNKNOWN); 132 assertTrue(mTelephonyManager.getPhoneType() >= TelephonyManager.PHONE_TYPE_NONE); 133 assertTrue(mTelephonyManager.getSimState() >= TelephonyManager.SIM_STATE_UNKNOWN); 134 assertTrue(mTelephonyManager.getDataActivity() >= TelephonyManager.DATA_ACTIVITY_NONE); 135 assertTrue(mTelephonyManager.getDataState() >= TelephonyManager.DATA_DISCONNECTED); 136 assertTrue(mTelephonyManager.getCallState() >= TelephonyManager.CALL_STATE_IDLE); 137 138 // Make sure devices without MMS service won't fail on this 139 if (mTelephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE) { 140 assertFalse(mTelephonyManager.getMmsUserAgent().isEmpty()); 141 assertFalse(mTelephonyManager.getMmsUAProfUrl().isEmpty()); 142 } 143 144 // The following methods may return null. Simply call them to make sure they do not 145 // throw any exceptions. 146 mTelephonyManager.getVoiceMailNumber(); 147 mTelephonyManager.getSimOperatorName(); 148 mTelephonyManager.getNetworkCountryIso(); 149 mTelephonyManager.getCellLocation(); 150 mTelephonyManager.getSimSerialNumber(); 151 mTelephonyManager.getSimOperator(); 152 mTelephonyManager.getNetworkOperatorName(); 153 mTelephonyManager.getSubscriberId(); 154 mTelephonyManager.getLine1Number(); 155 mTelephonyManager.getNetworkOperator(); 156 mTelephonyManager.getSimCountryIso(); 157 mTelephonyManager.getVoiceMailAlphaTag(); 158 mTelephonyManager.getNeighboringCellInfo(); 159 mTelephonyManager.isNetworkRoaming(); 160 mTelephonyManager.getDeviceId(); 161 mTelephonyManager.getDeviceSoftwareVersion(); 162 } 163 164 /** 165 * Tests that the device properly reports either a valid IMEI if 166 * GSM, a valid MEID or ESN if CDMA, or a valid MAC address if 167 * only a WiFi device. 168 */ testGetDeviceId()169 public void testGetDeviceId() { 170 String deviceId = mTelephonyManager.getDeviceId(); 171 int phoneType = mTelephonyManager.getPhoneType(); 172 switch (phoneType) { 173 case TelephonyManager.PHONE_TYPE_GSM: 174 assertGsmDeviceId(deviceId); 175 break; 176 177 case TelephonyManager.PHONE_TYPE_CDMA: 178 // LTE device is using IMEI as device id 179 if (mTelephonyManager.getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE) { 180 assertGsmDeviceId(deviceId); 181 } else { 182 assertCdmaDeviceId(deviceId); 183 } 184 break; 185 186 case TelephonyManager.PHONE_TYPE_NONE: 187 if (mCm.getNetworkInfo(ConnectivityManager.TYPE_WIFI) != null) { 188 assertSerialNumber(); 189 assertMacAddress(getWifiMacAddress()); 190 } else if (mCm.getNetworkInfo(ConnectivityManager.TYPE_BLUETOOTH) != null) { 191 assertSerialNumber(); 192 assertMacAddress(getBluetoothMacAddress()); 193 } else { 194 assertTrue(mCm.getNetworkInfo(ConnectivityManager.TYPE_ETHERNET) != null); 195 } 196 break; 197 198 default: 199 throw new IllegalArgumentException("Did you add a new phone type? " + phoneType); 200 } 201 } 202 assertGsmDeviceId(String deviceId)203 private static void assertGsmDeviceId(String deviceId) { 204 // IMEI may include the check digit 205 String imeiPattern = "[0-9]{14,15}"; 206 assertTrue("IMEI device id " + deviceId + " does not match pattern " + imeiPattern, 207 Pattern.matches(imeiPattern, deviceId)); 208 if (deviceId.length() == 15) { 209 // if the ID is 15 digits, the 15th must be a check digit. 210 assertImeiCheckDigit(deviceId); 211 } 212 } 213 assertImeiCheckDigit(String deviceId)214 private static void assertImeiCheckDigit(String deviceId) { 215 int expectedCheckDigit = getLuhnCheckDigit(deviceId.substring(0, 14)); 216 int actualCheckDigit = Character.digit(deviceId.charAt(14), 10); 217 assertEquals("Incorrect check digit for " + deviceId, expectedCheckDigit, actualCheckDigit); 218 } 219 220 /** 221 * Use decimal value (0-9) to index into array to get sum of its digits 222 * needed by Lunh check. 223 * 224 * Example: DOUBLE_DIGIT_SUM[6] = 3 because 6 * 2 = 12 => 1 + 2 = 3 225 */ 226 private static final int[] DOUBLE_DIGIT_SUM = {0, 2, 4, 6, 8, 1, 3, 5, 7, 9}; 227 228 /** 229 * Calculate the check digit by starting from the right, doubling every 230 * each digit, summing all the digits including the doubled ones, and 231 * finding a number to make the sum divisible by 10. 232 * 233 * @param deviceId not including the check digit 234 * @return the check digit 235 */ getLuhnCheckDigit(String deviceId)236 private static int getLuhnCheckDigit(String deviceId) { 237 int sum = 0; 238 int dontDoubleModulus = deviceId.length() % 2; 239 for (int i = deviceId.length() - 1; i >= 0; --i) { 240 int digit = Character.digit(deviceId.charAt(i), 10); 241 if (i % 2 == dontDoubleModulus) { 242 sum += digit; 243 } else { 244 sum += DOUBLE_DIGIT_SUM[digit]; 245 } 246 } 247 sum %= 10; 248 return sum == 0 ? 0 : 10 - sum; 249 } 250 assertCdmaDeviceId(String deviceId)251 private static void assertCdmaDeviceId(String deviceId) { 252 // CDMA device IDs may either be a 14-hex-digit MEID or an 253 // 8-hex-digit ESN. If it's an ESN, it may not be a 254 // pseudo-ESN. 255 if (deviceId.length() == 14) { 256 assertMeidFormat(deviceId); 257 } else if (deviceId.length() == 8) { 258 assertHexadecimalEsnFormat(deviceId); 259 } else { 260 fail("device id on CDMA must be 14-digit hex MEID or 8-digit hex ESN."); 261 } 262 } 263 assertHexadecimalEsnFormat(String deviceId)264 private static void assertHexadecimalEsnFormat(String deviceId) { 265 String esnPattern = "[0-9a-fA-F]{8}"; 266 assertTrue("ESN hex device id " + deviceId + " does not match pattern " + esnPattern, 267 Pattern.matches(esnPattern, deviceId)); 268 assertFalse("ESN hex device id " + deviceId + " must not be a pseudo-ESN", 269 "80".equals(deviceId.substring(0, 2))); 270 } 271 assertMeidFormat(String deviceId)272 private static void assertMeidFormat(String deviceId) { 273 // MEID must NOT include the check digit. 274 String meidPattern = "[0-9a-fA-F]{14}"; 275 assertTrue("MEID device id " + deviceId + " does not match pattern " + meidPattern, 276 Pattern.matches(meidPattern, deviceId)); 277 } 278 assertSerialNumber()279 private void assertSerialNumber() { 280 assertNotNull("Non-telephony devices must have a Build.SERIAL number.", 281 Build.SERIAL); 282 assertTrue("Hardware id must be no longer than 20 characters.", 283 Build.SERIAL.length() <= 20); 284 assertTrue("Hardware id must be alphanumeric.", 285 Pattern.matches("[0-9A-Za-z]+", Build.SERIAL)); 286 } 287 assertMacAddress(String macAddress)288 private void assertMacAddress(String macAddress) { 289 String macPattern = "([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}"; 290 assertTrue("MAC Address " + macAddress + " does not match pattern " + macPattern, 291 Pattern.matches(macPattern, macAddress)); 292 } 293 294 /** @return mac address which requires the WiFi system to be enabled */ getWifiMacAddress()295 private String getWifiMacAddress() { 296 WifiManager wifiManager = (WifiManager) getContext() 297 .getSystemService(Context.WIFI_SERVICE); 298 299 boolean enabled = wifiManager.isWifiEnabled(); 300 301 try { 302 if (!enabled) { 303 wifiManager.setWifiEnabled(true); 304 } 305 306 WifiInfo wifiInfo = wifiManager.getConnectionInfo(); 307 return wifiInfo.getMacAddress(); 308 309 } finally { 310 if (!enabled) { 311 wifiManager.setWifiEnabled(false); 312 } 313 } 314 } 315 getBluetoothMacAddress()316 private String getBluetoothMacAddress() { 317 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 318 if (adapter == null) { 319 return ""; 320 } 321 322 return adapter.getAddress(); 323 } 324 325 private static final String ISO_COUNTRY_CODE_PATTERN = "[a-z]{2}"; 326 testGetNetworkCountryIso()327 public void testGetNetworkCountryIso() { 328 PackageManager packageManager = getContext().getPackageManager(); 329 String countryCode = mTelephonyManager.getNetworkCountryIso(); 330 if (packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { 331 assertTrue("Country code '" + countryCode + "' did not match " 332 + ISO_COUNTRY_CODE_PATTERN, 333 Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode)); 334 } else { 335 // Non-telephony may still have the property defined if it has a SIM. 336 } 337 } 338 testGetSimCountryIso()339 public void testGetSimCountryIso() { 340 PackageManager packageManager = getContext().getPackageManager(); 341 String countryCode = mTelephonyManager.getSimCountryIso(); 342 if (packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { 343 assertTrue("Country code '" + countryCode + "' did not match " 344 + ISO_COUNTRY_CODE_PATTERN, 345 Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode)); 346 } else { 347 // Non-telephony may still have the property defined if it has a SIM. 348 } 349 } 350 } 351