Android开发笔记(四十六)手机相关事件

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/aqi00/article/details/50511517

手机定位

有一类事件必须依赖于手机信号方能触发,如果把设备中的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开发笔记的完整目录

展开阅读全文

没有更多推荐了,返回首页