1// Copyright 2008, The Android Open Source Project 2// 3// Redistribution and use in source and binary forms, with or without 4// modification, are permitted provided that the following conditions are met: 5// 6// 1. Redistributions of source code must retain the above copyright notice, 7// this list of conditions and the following disclaimer. 8// 2. Redistributions in binary form must reproduce the above copyright notice, 9// this list of conditions and the following disclaimer in the documentation 10// and/or other materials provided with the distribution. 11// 3. Neither the name of Google Inc. nor the names of its contributors may be 12// used to endorse or promote products derived from this software without 13// specific prior written permission. 14// 15// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 16// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 17// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 18// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 26package android.webkit.gears; 27 28import android.content.Context; 29import android.telephony.CellLocation; 30import android.telephony.ServiceState; 31import android.telephony.SignalStrength; 32import android.telephony.gsm.GsmCellLocation; 33import android.telephony.PhoneStateListener; 34import android.telephony.TelephonyManager; 35import android.util.Log; 36import android.webkit.WebView; 37 38/** 39 * Radio data provider implementation for Android. 40 */ 41public final class AndroidRadioDataProvider extends PhoneStateListener { 42 43 /** Logging tag */ 44 private static final String TAG = "Gears-J-RadioProvider"; 45 46 /** Network types */ 47 private static final int RADIO_TYPE_UNKNOWN = 0; 48 private static final int RADIO_TYPE_GSM = 1; 49 private static final int RADIO_TYPE_WCDMA = 2; 50 private static final int RADIO_TYPE_CDMA = 3; 51 private static final int RADIO_TYPE_EVDO = 4; 52 private static final int RADIO_TYPE_1xRTT = 5; 53 54 /** Simple container for radio data */ 55 public static final class RadioData { 56 public int cellId = -1; 57 public int locationAreaCode = -1; 58 // TODO: use new SignalStrength instead of asu 59 public int signalStrength = -1; 60 public int mobileCountryCode = -1; 61 public int mobileNetworkCode = -1; 62 public int homeMobileCountryCode = -1; 63 public int homeMobileNetworkCode = -1; 64 public int radioType = RADIO_TYPE_UNKNOWN; 65 public String carrierName; 66 67 /** 68 * Constructs radioData object from the given telephony data. 69 * @param telephonyManager contains the TelephonyManager instance. 70 * @param cellLocation contains information about the current GSM cell. 71 * @param signalStrength is the strength of the network signal. 72 * @param serviceState contains information about the network service. 73 * @return a new RadioData object populated with the currently 74 * available network information or null if there isn't 75 * enough information. 76 */ 77 public static RadioData getInstance(TelephonyManager telephonyManager, 78 CellLocation cellLocation, int signalStrength, 79 ServiceState serviceState) { 80 81 if (!(cellLocation instanceof GsmCellLocation)) { 82 // This also covers the case when cellLocation is null. 83 // When that happens, we do not bother creating a 84 // RadioData instance. 85 return null; 86 } 87 88 RadioData radioData = new RadioData(); 89 GsmCellLocation gsmCellLocation = (GsmCellLocation) cellLocation; 90 91 // Extract the cell id, LAC, and signal strength. 92 radioData.cellId = gsmCellLocation.getCid(); 93 radioData.locationAreaCode = gsmCellLocation.getLac(); 94 radioData.signalStrength = signalStrength; 95 96 // Extract the home MCC and home MNC. 97 String operator = telephonyManager.getSimOperator(); 98 radioData.setMobileCodes(operator, true); 99 100 if (serviceState != null) { 101 // Extract the carrier name. 102 radioData.carrierName = serviceState.getOperatorAlphaLong(); 103 104 // Extract the MCC and MNC. 105 operator = serviceState.getOperatorNumeric(); 106 radioData.setMobileCodes(operator, false); 107 } 108 109 // Finally get the radio type. 110 //TODO We have to edit the parameter for getNetworkType regarding CDMA 111 int type = telephonyManager.getNetworkType(); 112 if (type == TelephonyManager.NETWORK_TYPE_UMTS) { 113 radioData.radioType = RADIO_TYPE_WCDMA; 114 } else if (type == TelephonyManager.NETWORK_TYPE_GPRS 115 || type == TelephonyManager.NETWORK_TYPE_EDGE) { 116 radioData.radioType = RADIO_TYPE_GSM; 117 } else if (type == TelephonyManager.NETWORK_TYPE_CDMA) { 118 radioData.radioType = RADIO_TYPE_CDMA; 119 } else if (type == TelephonyManager.NETWORK_TYPE_EVDO_0) { 120 radioData.radioType = RADIO_TYPE_EVDO; 121 } else if (type == TelephonyManager.NETWORK_TYPE_EVDO_A) { 122 radioData.radioType = RADIO_TYPE_EVDO; 123 } else if (type == TelephonyManager.NETWORK_TYPE_1xRTT) { 124 radioData.radioType = RADIO_TYPE_1xRTT; 125 } 126 127 // Print out what we got. 128 Log.i(TAG, "Got the following data:"); 129 Log.i(TAG, "CellId: " + radioData.cellId); 130 Log.i(TAG, "LAC: " + radioData.locationAreaCode); 131 Log.i(TAG, "MNC: " + radioData.mobileNetworkCode); 132 Log.i(TAG, "MCC: " + radioData.mobileCountryCode); 133 Log.i(TAG, "home MNC: " + radioData.homeMobileNetworkCode); 134 Log.i(TAG, "home MCC: " + radioData.homeMobileCountryCode); 135 Log.i(TAG, "Signal strength: " + radioData.signalStrength); 136 Log.i(TAG, "Carrier: " + radioData.carrierName); 137 Log.i(TAG, "Network type: " + radioData.radioType); 138 139 return radioData; 140 } 141 142 private RadioData() {} 143 144 /** 145 * Parses a string containing a mobile country code and a mobile 146 * network code and sets the corresponding member variables. 147 * @param codes is the string to parse. 148 * @param homeValues flags whether the codes are for the home operator. 149 */ 150 private void setMobileCodes(String codes, boolean homeValues) { 151 if (codes != null) { 152 try { 153 // The operator numeric format is 3 digit country code plus 2 or 154 // 3 digit network code. 155 int mcc = Integer.parseInt(codes.substring(0, 3)); 156 int mnc = Integer.parseInt(codes.substring(3)); 157 if (homeValues) { 158 homeMobileCountryCode = mcc; 159 homeMobileNetworkCode = mnc; 160 } else { 161 mobileCountryCode = mcc; 162 mobileNetworkCode = mnc; 163 } 164 } catch (IndexOutOfBoundsException ex) { 165 Log.e( 166 TAG, 167 "AndroidRadioDataProvider: Invalid operator numeric data: " + ex); 168 } catch (NumberFormatException ex) { 169 Log.e( 170 TAG, 171 "AndroidRadioDataProvider: Operator numeric format error: " + ex); 172 } 173 } 174 } 175 }; 176 177 /** The native object ID */ 178 private long nativeObject; 179 180 /** The last known cellLocation */ 181 private CellLocation cellLocation = null; 182 183 /** The last known signal strength */ 184 // TODO: use new SignalStrength instead of asu 185 private int signalStrength = -1; 186 187 /** The last known serviceState */ 188 private ServiceState serviceState = null; 189 190 /** 191 * Our TelephonyManager instance. 192 */ 193 private TelephonyManager telephonyManager; 194 195 /** 196 * Public constructor. Uses the webview to get the Context object. 197 */ 198 public AndroidRadioDataProvider(WebView webview, long object) { 199 super(); 200 nativeObject = object; 201 telephonyManager = (TelephonyManager) webview.getContext().getSystemService( 202 Context.TELEPHONY_SERVICE); 203 if (telephonyManager == null) { 204 Log.e(TAG, 205 "AndroidRadioDataProvider: could not get tepephony manager."); 206 throw new NullPointerException( 207 "AndroidRadioDataProvider: telephonyManager is null."); 208 } 209 210 // Register for cell id, signal strength and service state changed 211 // notifications. 212 telephonyManager.listen(this, PhoneStateListener.LISTEN_CELL_LOCATION 213 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS 214 | PhoneStateListener.LISTEN_SERVICE_STATE); 215 } 216 217 /** 218 * Should be called when the provider is no longer needed. 219 */ 220 public void shutdown() { 221 telephonyManager.listen(this, PhoneStateListener.LISTEN_NONE); 222 Log.i(TAG, "AndroidRadioDataProvider shutdown."); 223 } 224 225 @Override 226 public void onServiceStateChanged(ServiceState state) { 227 serviceState = state; 228 notifyListeners(); 229 } 230 231 @Override 232 public void onSignalStrengthsChanged(SignalStrength ss) { 233 int gsmSignalStrength = ss.getGsmSignalStrength(); 234 signalStrength = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength); 235 notifyListeners(); 236 } 237 238 @Override 239 public void onCellLocationChanged(CellLocation location) { 240 cellLocation = location; 241 notifyListeners(); 242 } 243 244 private void notifyListeners() { 245 RadioData radioData = RadioData.getInstance(telephonyManager, cellLocation, 246 signalStrength, serviceState); 247 if (radioData != null) { 248 onUpdateAvailable(radioData, nativeObject); 249 } 250 } 251 252 /** 253 * The native method called when new radio data is available. 254 * @param radioData is the RadioData instance to pass to the native side. 255 * @param nativeObject is a pointer to the corresponding 256 * AndroidRadioDataProvider C++ instance. 257 */ 258 private static native void onUpdateAvailable( 259 RadioData radioData, long nativeObject); 260} 261