| // Copyright 2008, The Android Open Source Project |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are met: |
| // |
| // 1. Redistributions of source code must retain the above copyright notice, |
| // this list of conditions and the following disclaimer. |
| // 2. Redistributions in binary form must reproduce the above copyright notice, |
| // this list of conditions and the following disclaimer in the documentation |
| // and/or other materials provided with the distribution. |
| // 3. Neither the name of Google Inc. nor the names of its contributors may be |
| // used to endorse or promote products derived from this software without |
| // specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
| // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
| // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
| // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| package android.webkit.gears; |
| |
| import android.content.Context; |
| import android.telephony.CellLocation; |
| import android.telephony.ServiceState; |
| import android.telephony.gsm.GsmCellLocation; |
| import android.telephony.PhoneStateListener; |
| import android.telephony.TelephonyManager; |
| import android.util.Log; |
| import android.webkit.WebView; |
| |
| /** |
| * Radio data provider implementation for Android. |
| */ |
| public final class AndroidRadioDataProvider extends PhoneStateListener { |
| |
| /** Logging tag */ |
| private static final String TAG = "Gears-J-RadioProvider"; |
| |
| /** Network types */ |
| private static final int RADIO_TYPE_UNKNOWN = 0; |
| private static final int RADIO_TYPE_GSM = 1; |
| private static final int RADIO_TYPE_WCDMA = 2; |
| |
| /** Simple container for radio data */ |
| public static final class RadioData { |
| public int cellId = -1; |
| public int locationAreaCode = -1; |
| public int signalStrength = -1; |
| public int mobileCountryCode = -1; |
| public int mobileNetworkCode = -1; |
| public int homeMobileCountryCode = -1; |
| public int homeMobileNetworkCode = -1; |
| public int radioType = RADIO_TYPE_UNKNOWN; |
| public String carrierName; |
| |
| /** |
| * Constructs radioData object from the given telephony data. |
| * @param telephonyManager contains the TelephonyManager instance. |
| * @param cellLocation contains information about the current GSM cell. |
| * @param signalStrength is the strength of the network signal. |
| * @param serviceState contains information about the network service. |
| * @return a new RadioData object populated with the currently |
| * available network information or null if there isn't |
| * enough information. |
| */ |
| public static RadioData getInstance(TelephonyManager telephonyManager, |
| CellLocation cellLocation, int signalStrength, |
| ServiceState serviceState) { |
| |
| if (!(cellLocation instanceof GsmCellLocation)) { |
| // This also covers the case when cellLocation is null. |
| // When that happens, we do not bother creating a |
| // RadioData instance. |
| return null; |
| } |
| |
| RadioData radioData = new RadioData(); |
| GsmCellLocation gsmCellLocation = (GsmCellLocation) cellLocation; |
| |
| // Extract the cell id, LAC, and signal strength. |
| radioData.cellId = gsmCellLocation.getCid(); |
| radioData.locationAreaCode = gsmCellLocation.getLac(); |
| radioData.signalStrength = signalStrength; |
| |
| // Extract the home MCC and home MNC. |
| String operator = telephonyManager.getSimOperator(); |
| radioData.setMobileCodes(operator, true); |
| |
| if (serviceState != null) { |
| // Extract the carrier name. |
| radioData.carrierName = serviceState.getOperatorAlphaLong(); |
| |
| // Extract the MCC and MNC. |
| operator = serviceState.getOperatorNumeric(); |
| radioData.setMobileCodes(operator, false); |
| } |
| |
| // Finally get the radio type. |
| int type = telephonyManager.getNetworkType(); |
| if (type == TelephonyManager.NETWORK_TYPE_UMTS) { |
| radioData.radioType = RADIO_TYPE_WCDMA; |
| } else if (type == TelephonyManager.NETWORK_TYPE_GPRS |
| || type == TelephonyManager.NETWORK_TYPE_EDGE) { |
| radioData.radioType = RADIO_TYPE_GSM; |
| } |
| |
| // Print out what we got. |
| Log.i(TAG, "Got the following data:"); |
| Log.i(TAG, "CellId: " + radioData.cellId); |
| Log.i(TAG, "LAC: " + radioData.locationAreaCode); |
| Log.i(TAG, "MNC: " + radioData.mobileNetworkCode); |
| Log.i(TAG, "MCC: " + radioData.mobileCountryCode); |
| Log.i(TAG, "home MNC: " + radioData.homeMobileNetworkCode); |
| Log.i(TAG, "home MCC: " + radioData.homeMobileCountryCode); |
| Log.i(TAG, "Signal strength: " + radioData.signalStrength); |
| Log.i(TAG, "Carrier: " + radioData.carrierName); |
| Log.i(TAG, "Network type: " + radioData.radioType); |
| |
| return radioData; |
| } |
| |
| private RadioData() {} |
| |
| /** |
| * Parses a string containing a mobile country code and a mobile |
| * network code and sets the corresponding member variables. |
| * @param codes is the string to parse. |
| * @param homeValues flags whether the codes are for the home operator. |
| */ |
| private void setMobileCodes(String codes, boolean homeValues) { |
| if (codes != null) { |
| try { |
| // The operator numeric format is 3 digit country code plus 2 or |
| // 3 digit network code. |
| int mcc = Integer.parseInt(codes.substring(0, 3)); |
| int mnc = Integer.parseInt(codes.substring(3)); |
| if (homeValues) { |
| homeMobileCountryCode = mcc; |
| homeMobileNetworkCode = mnc; |
| } else { |
| mobileCountryCode = mcc; |
| mobileNetworkCode = mnc; |
| } |
| } catch (IndexOutOfBoundsException ex) { |
| Log.e( |
| TAG, |
| "AndroidRadioDataProvider: Invalid operator numeric data: " + ex); |
| } catch (NumberFormatException ex) { |
| Log.e( |
| TAG, |
| "AndroidRadioDataProvider: Operator numeric format error: " + ex); |
| } |
| } |
| } |
| }; |
| |
| /** The native object ID */ |
| private long nativeObject; |
| |
| /** The last known cellLocation */ |
| private CellLocation cellLocation = null; |
| |
| /** The last known signal strength */ |
| private int signalStrength = -1; |
| |
| /** The last known serviceState */ |
| private ServiceState serviceState = null; |
| |
| /** |
| * Our TelephonyManager instance. |
| */ |
| private TelephonyManager telephonyManager; |
| |
| /** |
| * Public constructor. Uses the webview to get the Context object. |
| */ |
| public AndroidRadioDataProvider(WebView webview, long object) { |
| super(); |
| nativeObject = object; |
| telephonyManager = (TelephonyManager) webview.getContext().getSystemService( |
| Context.TELEPHONY_SERVICE); |
| if (telephonyManager == null) { |
| Log.e(TAG, |
| "AndroidRadioDataProvider: could not get tepephony manager."); |
| throw new NullPointerException( |
| "AndroidRadioDataProvider: telephonyManager is null."); |
| } |
| |
| // Register for cell id, signal strength and service state changed |
| // notifications. |
| telephonyManager.listen(this, PhoneStateListener.LISTEN_CELL_LOCATION |
| | PhoneStateListener.LISTEN_SIGNAL_STRENGTH |
| | PhoneStateListener.LISTEN_SERVICE_STATE); |
| } |
| |
| /** |
| * Should be called when the provider is no longer needed. |
| */ |
| public void shutdown() { |
| telephonyManager.listen(this, PhoneStateListener.LISTEN_NONE); |
| Log.i(TAG, "AndroidRadioDataProvider shutdown."); |
| } |
| |
| @Override |
| public void onServiceStateChanged(ServiceState state) { |
| serviceState = state; |
| notifyListeners(); |
| } |
| |
| @Override |
| public void onSignalStrengthChanged(int asu) { |
| signalStrength = asu; |
| notifyListeners(); |
| } |
| |
| @Override |
| public void onCellLocationChanged(CellLocation location) { |
| cellLocation = location; |
| notifyListeners(); |
| } |
| |
| private void notifyListeners() { |
| RadioData radioData = RadioData.getInstance(telephonyManager, cellLocation, |
| signalStrength, serviceState); |
| if (radioData != null) { |
| onUpdateAvailable(radioData, nativeObject); |
| } |
| } |
| |
| /** |
| * The native method called when new radio data is available. |
| * @param radioData is the RadioData instance to pass to the native side. |
| * @param nativeObject is a pointer to the corresponding |
| * AndroidRadioDataProvider C++ instance. |
| */ |
| private static native void onUpdateAvailable( |
| RadioData radioData, long nativeObject); |
| } |