blob: c920d45e4966659536bb6e3f73e0bf96112750e6 [file] [log] [blame]
// 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);
}