手机定位
有一类事件必须依赖于手机信号方能触发,如果把设备中的sim卡拔出,或者该设备本身不支持sim卡(如ipad),那么这类事件将永远不会被触发。在Android中,这类事件包括定位事件和手机信号事件。
与定位有关的类主要有:
1、定位条件器Criteria : 该类用于设置定位的前提条件,比如精度、速度、海拔、方位等等信息。
2、定位管理器LocationManager : 该类用于获取定位信息的提供者,设置监听器,并获取最近一次的位置信息。
3、定位监听器LocationListener : 该类用于监听定位信息的变化事件,如定位提供者的开关、位置信息发生变化等等。
定位条件器
Criteria的常用参数设置方法如下:
setAccuracy : 设置定位精确度。有两个取值,ACCURACY_FINE表示精度高,ACCURACY_COARSE表示精度低
setSpeedAccuracy : 设置速度的定位精确度。有两个取值,ACCURACY_HIGH表示精度高,ACCURACY_LOW表示精度低
setAltitudeRequired : 设置是否需要海拔信息。取值true表示需要,false表示不需要
setBearingRequired : 设置是否需要方位信息。取值true表示需要,false表示不需要
setCostAllowed : 设置是否允许运营商收费。取值true表示允许,false表示不允许
setPowerRequirement : 设置对电源的需求。有三个取值,POWER_LOW表示耗电低,POWER_MEDIUM表示耗电中等,POWER_HIGH表示耗电高
定位管理器
管理器类名 : LocationManager
获取管理器实例的方法:
LocationManager mLocationMgr = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
管理器的常用方法如下:
getBestProvider : 获取最佳的定位提供者。第一个参数设置条件器Criteria,第二个参数一般取值true。返回值主要有两个:GPS定位返回gps,网络定位返回network
isProviderEnabled : 判断指定提供者是否可用
getLastKnownLocation : 获取最近一次的定位地点
requestLocationUpdates : 设置定位监听器
定位监听器
监听器类名 : LocationListener
设置监听器的方法:
requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener)
其中第一个参数设置定位提供者,第二个参数设置位置更新的最小间隔时间,第三个参数设置位置更新的最小距离,第四个参数设置监听器实例。
监听器需要重写的方法:
onLocationChanged : 在位置地点发生变化时调用
onProviderDisabled : 在定位提供者被用户关闭时调用
onProviderEnabled : 在定位提供者被用户开启时调用
onStatusChanged : 在定位提供者的状态发生变化时调用。状态值有三个:OUT_OF_SERVICE表示在服务范围之外,TEMPORARILY_UNAVAILABLE表示暂时不可用,AVAILABLE表示可用
手机定位示例
手机开启GPS信号,GPS定位的截图如下:
手机关闭GPS信号,网络定位的截图如下:
定位信息获取的示例代码如下:
import com.example.exmmobile.util.Utils;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.widget.TextView;
public class LocationActivity extends Activity {
private final static String TAG = "LocationActivity";
private TextView tv_location;
private String mLocation="";
private LocationManager mLocationMgr;
private Criteria mCriteria = new Criteria();
private Handler mHandler = new Handler();
private boolean bLocationEnable = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_location);
initWidget();
initLocation();
mHandler.postDelayed(mRefresh, 100);
}
private void initWidget() {
tv_location = (TextView) findViewById(R.id.tv_location);
mLocationMgr = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
// 设置定位精确度 Criteria.ACCURACY_COARSE 比较粗略, Criteria.ACCURACY_FINE 则比较精细
mCriteria.setAccuracy(Criteria.ACCURACY_FINE);
// 设置是否需要海拔信息 Altitude
mCriteria.setAltitudeRequired(true);
// 设置是否需要方位信息 Bearing
mCriteria.setBearingRequired(true);
// 设置是否允许运营商收费
mCriteria.setCostAllowed(true);
// 设置对电源的需求
mCriteria.setPowerRequirement(Criteria.POWER_LOW);
}
private void initLocation() {
String bestProvider = mLocationMgr.getBestProvider(mCriteria, true);
if (bestProvider == null) {
bestProvider = LocationManager.NETWORK_PROVIDER;
}
if (mLocationMgr.isProviderEnabled(bestProvider)) {
tv_location.setText("\n正在获取"+bestProvider+"定位对象");
mLocation = String.format("\n定位类型=%s", bestProvider);
beginLocation(bestProvider);
bLocationEnable = true;
} else {
tv_location.setText("\n"+bestProvider+"定位不可用");
bLocationEnable = false;
}
}
@SuppressLint("DefaultLocale")
private void setLocationText(Location location) {
if (location != null) {
String desc = String.format("%s\n定位对象信息如下:\n\t其中时间:%s\n\t其中经度:%f\n\t其中纬度:%f\n\t其中高度:%f",
mLocation, Utils.getNowDateTime(),
location.getLongitude(), location.getLatitude(), location.getAltitude());
Log.d(TAG, desc);
tv_location.setText(desc);
} else {
tv_location.setText(mLocation+"\n暂未获取到定位对象");
}
}
private void beginLocation(String method) {
mLocationMgr.requestLocationUpdates(method, 300, 0, mLocationListener);
Location location = mLocationMgr.getLastKnownLocation(method);
setLocationText(location);
}
// 位置监听器
private LocationListener mLocationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
setLocationText(location);
}
@Override
public void onProviderDisabled(String arg0) {
}
@Override
public void onProviderEnabled(String arg0) {
}
@Override
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
}
};
private Runnable mRefresh = new Runnable() {
@Override
public void run() {
if (bLocationEnable == false) {
initLocation();
mHandler.postDelayed(this, 1000);
}
}
};
}
手机基站和信号
手机要能接收基站的信号,才能打电话和发短信。手机制式目前有4G、3G、2G,同样的,基站和信号也分4G、3G、2G。4G的网络是LTE,2G的网络是GSM,3G的网络在国内根据运营商划分(移动是TD,电信是CDMA,联通是WCDMA)。不过基站与信号事件在实际开发中用得不多,一般是运营商的网优业务才会用到。
与基站和信号有关的类主要有:
1、电话管理器TelephonyManager : 该类用于提供运营商信息、蜂窝网络信息、当前的基站信息等等。
2、手机状态监听器PhoneStateListener : 该类用于监听基站或者信号信息的变化事件。
电话管理器
管理器类名 : TelephonyManager
获取管理器实例的方法:
TelephonyManager mTelMgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
管理器的常用方法如下:
getNetworkOperator : 获取运营商信息。返回字符串的前三位是国家代码(中国的为460),后两位是运营商代码(中国移动为0,中国联通为1,中国电信为2)
getNetworkType : 获取运营商网络类型。
getNetworkClass : 获取运营商网络类别。取值1表示2G,取值2表示3G,取值3表示4G
getCellLocation : 获取当前连接的基站信息。
getNeighboringCellInfo : 获取附近的基站信息。
getAllCellInfo : 获取可连接的所有基站信息。
listen : 设置手机状态监听器。
手机状态监听器
监听器类名 : PhoneStateListener
设置监听器的方法:
listen(PhoneStateListener listener, int events)
其中第一个参数设置手机状态监听器,第二个参数指定要监听的事件类型。
监听器需要重写的方法:
onCellLocationChanged : 在基站位置发生变化时调用,对应的监听类型是LISTEN_CELL_LOCATION
onCellInfoChanged : 在基站信息发生变化时调用,对应的监听类型是LISTEN_CELL_INFO
onSignalStrengthsChanged : 在信号强度发生变化时调用,对应的监听类型是LISTEN_SIGNAL_STRENGTHS
获取手机基站和信号的示例
手机开启4G信号,找到LTE基站和信号信息的截图如下:
手机关闭4G信号,找到TD基站和信号信息的截图如下:
基站和信号获取的示例代码如下:
import java.util.List;
import com.example.exmmobile.util.Utils;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.telephony.CellIdentityCdma;
import android.telephony.CellIdentityGsm;
import android.telephony.CellIdentityLte;
import android.telephony.CellIdentityWcdma;
import android.telephony.CellInfo;
import android.telephony.CellInfoCdma;
import android.telephony.CellInfoGsm;
import android.telephony.CellInfoLte;
import android.telephony.CellInfoWcdma;
import android.telephony.CellLocation;
import android.telephony.PhoneStateListener;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.telephony.cdma.CdmaCellLocation;
import android.telephony.gsm.GsmCellLocation;
import android.widget.TextView;
public class StationActivity extends Activity {
private final static String TAG = "StationActivity";
private TextView tv_station;
private TextView tv_net;
private String mDevice="", mStation="", mSignal="";
private TelephonyManager mTelMgr;
private int mCellType = Utils.TYPE_GSM;
private Handler mHandler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_station);
initWidget();
mHandler.postDelayed(mRefresh, 100);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private void listenCellInfo() {
MyPhoneStateListener mCellInfoListener = new MyPhoneStateListener();
mTelMgr.listen(mCellInfoListener, PhoneStateListener.LISTEN_CELL_INFO);
}
private void initWidget() {
tv_station = (TextView) findViewById(R.id.tv_station);
tv_net = (TextView) findViewById(R.id.tv_net);
mTelMgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
MyPhoneStateListener mSignalStrengthListener = new MyPhoneStateListener();
mTelMgr.listen(mSignalStrengthListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
MyPhoneStateListener mCellLocationListener = new MyPhoneStateListener();
mTelMgr.listen(mCellLocationListener, PhoneStateListener.LISTEN_CELL_LOCATION);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
listenCellInfo();
}
}
private class MyPhoneStateListener extends PhoneStateListener {
@Override
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
super.onSignalStrengthsChanged(signalStrength);
int gsm_sign = -113+2*signalStrength.getGsmSignalStrength();
int lte_sinr = 99;
int lte_rsrp = 99;
int lte_rsrq = 99;
int lte_rssnr = 0;
int lte_cqi = 0;
try {
lte_sinr = (Integer) signalStrength.getClass().getMethod("getLteSignalStrength").invoke(signalStrength);
lte_rsrp = (Integer) signalStrength.getClass().getMethod("getLteRsrp").invoke(signalStrength);
lte_rsrq = (Integer) signalStrength.getClass().getMethod("getLteRsrq").invoke(signalStrength);
lte_rssnr = (Integer) signalStrength.getClass().getMethod("getLteRssnr").invoke(signalStrength);
lte_cqi = (Integer) signalStrength.getClass().getMethod("getLteCqi").invoke(signalStrength);
} catch (Exception e) {
e.printStackTrace();
return;
}
mSignal = "";
if (mCellType == Utils.TYPE_LTE || Utils.getClassType(mTelMgr, mTelMgr.getNetworkType())==Utils.TYPE_4G) {
mSignal = String.format("%s\nLTE信号更新时间=%s\n gsm_sign=%d\n lte_sinr=%d\n lte_rsrp=%d\n lte_rsrq=%d\n lte_rssnr=%d\n lte_cqi=%d",
mSignal, Utils.getNowDateTime(), gsm_sign, lte_sinr, lte_rsrp, lte_rsrq, lte_rssnr, lte_cqi);
} else if (mCellType == Utils.TYPE_GSM) {
mSignal = String.format("%s\nGSM信号更新时间=%s\n gsm_sign=%d",
mSignal, Utils.getNowDateTime(), gsm_sign);
} else if (mCellType == Utils.TYPE_WCDMA) {
mSignal = String.format("%s\nTD信号更新时间=%s\n td_sign=%d",
mSignal, Utils.getNowDateTime(), gsm_sign);
}
mSignal += "\n";
tv_station.setText(mStation+mSignal);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
public void onCellInfoChanged(List<CellInfo> cellList) {
super.onCellInfoChanged(cellList);
int count = (cellList==null)?0:cellList.size();
tv_net.setText(mDevice+"\n\t\t已连接的基站个数="+count);
refreshStation(cellList);
}
@Override
public void onCellLocationChanged(CellLocation location) {
super.onCellLocationChanged(location);
mHandler.postDelayed(mRefresh, 100);
}
}
// MCC,Mobile Country Code,移动国家代码(中国的为460);
// MNC,Mobile Network Code,移动网络号码(中国移动为0,中国联通为1,中国电信为2);
// LAC,Location Area Code,位置区域码;
// CID,Cell Identity,基站编号;
// BSSS,Base station signal strength,基站信号强度。
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private void refreshStation(List<CellInfo> cellList) {
if (cellList == null) {
return;
}
GsmCellLocation location = (GsmCellLocation) mTelMgr.getCellLocation();
int cid = location.getCid();
boolean is_found = false;
mStation = "";
mCellType = Utils.TYPE_LTE;
for (int i=0; i<cellList.size(); i++) {
CellInfo cell = cellList.get(i);
if (cell.toString().indexOf(""+cid) >= 0) {
is_found = true;
if ((cell instanceof CellInfoLte)) {
mCellType = Utils.TYPE_LTE;
CellIdentityLte cellLte = ((CellInfoLte)cell).getCellIdentity();
mStation = String.format("%s\nLTE基站更新时间=%s", mStation, Utils.getNowDateTime());
mStation = String.format("%s\n mcc=%d", mStation, cellLte.getMcc());
mStation = String.format("%s\n mnc=%d", mStation, cellLte.getMnc());
mStation = String.format("%s\n lte_tac=%d", mStation, cellLte.getTac());
mStation = String.format("%s\n lte_ci=%d", mStation, cellLte.getCi());
mStation = String.format("%s\n lte_pci=%d", mStation, cellLte.getPci());
} else if ((cell instanceof CellInfoGsm)) {
mCellType = Utils.TYPE_GSM;
CellIdentityGsm cellGsm = ((CellInfoGsm)cell).getCellIdentity();
mStation = String.format("%s\nGSM基站更新时间=%s", mStation, Utils.getNowDateTime());
mStation = String.format("%s\n mcc=%d", mStation, cellGsm.getMcc());
mStation = String.format("%s\n mnc=%d", mStation, cellGsm.getMnc());
mStation = String.format("%s\n gsm_lac=%d", mStation, cellGsm.getLac());
mStation = String.format("%s\n gsm_cid=%d", mStation, cellGsm.getCid());
} else if ((cell instanceof CellInfoCdma)) {
String operator = mTelMgr.getNetworkOperator();
int mcc = Integer.parseInt(operator.substring(0, 3));
int mnc = Integer.parseInt(operator.substring(3, 5));
mCellType = Utils.TYPE_CDMA;
CellIdentityCdma cellCdma = ((CellInfoCdma)cell).getCellIdentity();
mStation = String.format("%s\nCDMA基站更新时间=%s", mStation, Utils.getNowDateTime());
mStation = String.format("%s\n mcc=%d", mStation, mcc);
mStation = String.format("%s\n mnc=%d", mStation, mnc);
mStation = String.format("%s\n lac(network_id)=%d", mStation, cellCdma.getNetworkId());
mStation = String.format("%s\n system_id=%d", mStation, cellCdma.getSystemId());
mStation = String.format("%s\n cellid=%d", mStation, cellCdma.getBasestationId()/16);
} else if ((cell instanceof CellInfoWcdma)) {
mCellType = Utils.TYPE_WCDMA;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
refreshHigher3G(cell);
} else {
initLowerStation(mCellType, null);
}
}
break;
}
}
tv_station.setText(mStation+mSignal);
if (is_found == false) {
initLowerStation(0, null);
}
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
private void refreshHigher3G(CellInfo cell) {
CellIdentityWcdma cellWcdma = ((CellInfoWcdma)cell).getCellIdentity();
mStation = String.format("%s\nTD基站更新时间=%s", mStation, Utils.getNowDateTime());
mStation = String.format("%s\n mcc=%d", mStation, cellWcdma.getMcc());
mStation = String.format("%s\n mnc=%d", mStation, cellWcdma.getMnc());
mStation = String.format("%s\n td_lac=%d", mStation, cellWcdma.getLac());
mStation = String.format("%s\n td_ci=%d", mStation, cellWcdma.getCid());
mStation = String.format("%s\n td_psc=%d", mStation, cellWcdma.getPsc());
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private void initHigherStation() {
List<CellInfo> cell_list = mTelMgr.getAllCellInfo();
int count = (cell_list==null)?0:cell_list.size();
tv_net.setText(mDevice+"\n 已连接的基站个数="+count);
if (Utils.getClassType(mTelMgr, mTelMgr.getNetworkType())==Utils.TYPE_4G) {
if (cell_list==null || cell_list.size()==0) {
initLowerStation(0, null);
mHandler.postDelayed(mRefresh4G, 100);
} else {
refreshStation(cell_list);
}
} else {
initLowerStation(0, null);
}
}
private void initLowerStation(int cell_type, CellLocation location) {
mStation = "";
String operator = mTelMgr.getNetworkOperator();
int mcc = Integer.parseInt(operator.substring(0, 3));
int mnc = Integer.parseInt(operator.substring(3, 5));
int lac = 0, cid = 0;
if (location == null) {
GsmCellLocation gsmLocation = (GsmCellLocation) mTelMgr.getCellLocation();
lac = gsmLocation.getLac();
cid = gsmLocation.getCid();
} else {
GsmCellLocation gsmLocation = (GsmCellLocation) location;
lac = gsmLocation.getLac();
cid = gsmLocation.getCid();
}
if (Utils.getNetworkTypeName(mTelMgr, mTelMgr.getNetworkType()).indexOf("CDMA")>=0) {
CdmaCellLocation locationCdma = (CdmaCellLocation) mTelMgr.getCellLocation();
mCellType = Utils.TYPE_CDMA;
mStation = String.format("%s\nCDMA基站更新时间=%s", mStation, Utils.getNowDateTime());
mStation = String.format("%s\n mcc=%d", mStation, mcc);
mStation = String.format("%s\n mnc=%d", mStation, mnc);
mStation = String.format("%s\n lac(network_id)=%d", mStation, locationCdma.getNetworkId());
mStation = String.format("%s\n system_id=%d", mStation, locationCdma.getSystemId());
mStation = String.format("%s\n cellid=%d", mStation, locationCdma.getBaseStationId()/16);
} else if (cell_type==Utils.TYPE_WCDMA || Utils.getClassType(mTelMgr, mTelMgr.getNetworkType())==Utils.TYPE_3G) {
mCellType = Utils.TYPE_WCDMA;
mStation = String.format("%s\nTD基站更新时间=%s", mStation, Utils.getNowDateTime());
mStation = String.format("%s\n mcc=%d", mStation, mcc);
mStation = String.format("%s\n mnc=%d", mStation, mnc);
mStation = String.format("%s\n td_lac=%d", mStation, lac);
mStation = String.format("%s\n td_ci=%d", mStation, cid);
} else if (Utils.getClassType(mTelMgr, mTelMgr.getNetworkType())==Utils.TYPE_4G) {
mCellType = Utils.TYPE_LTE;
mStation = String.format("%s\nLTE基站更新时间=%s", mStation, Utils.getNowDateTime());
mStation = String.format("%s\n mcc=%d", mStation, mcc);
mStation = String.format("%s\n mnc=%d", mStation, mnc);
mStation = String.format("%s\n lte_tac=%d", mStation, lac);
mStation = String.format("%s\n lte_ci=%d", mStation, cid);
mStation = String.format("%s\n lte_pci=%d", mStation, -1);
} else {
mCellType = Utils.TYPE_GSM;
mStation = String.format("%s\nGSM基站更新时间=%s", mStation, Utils.getNowDateTime());
mStation = String.format("%s\n mcc=%d", mStation, mcc);
mStation = String.format("%s\n mnc=%d", mStation, mnc);
mStation = String.format("%s\n gsm_lac=%d", mStation, lac);
mStation = String.format("%s\n gsm_cid=%d", mStation, cid);
}
tv_station.setText(mStation+mSignal);
}
private void initStation() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
initHigherStation();
} else {
initLowerStation(0, null);
}
}
private Runnable mRefresh4G = new Runnable() {
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
public void run() {
List<CellInfo> cell_list = mTelMgr.getAllCellInfo();
if (cell_list==null || cell_list.size()==0) {
mHandler.postDelayed(this, 1000);
} else {
refreshStation(cell_list);
}
}
};
private Runnable mRefresh = new Runnable() {
@Override
public void run() {
if (mTelMgr.getNetworkType()==Utils.TYPE_UNKNOWN || mTelMgr.getCellLocation()==null) {
mHandler.postDelayed(this, 1000);
} else {
mDevice = String.format("%s\n 网络类型=%s %s", "",
Utils.getNetworkTypeName(mTelMgr, mTelMgr.getNetworkType()),
Utils.getClassName(mTelMgr, mTelMgr.getNetworkType()));
initStation();
}
}
};
}
点此查看Android开发笔记的完整目录