Android課堂筆記(十)——位置、SMS、通話

目錄

一.位置

二.SMS

1.發送(文本)消息

2.跟蹤和確認消息交付

3.偵聽傳入的 SMS

4.實現發送接收SMS 

三.通話

1.撥打電話

2.監視通話狀態 

3.訪問電話屬性

4.實現兩種方式的通話(應用內、撥號器)


一.位置

1.瞭解基於位置的服務

  • LBS (Location Based Services)基於位置的服務:
  • 是信息服務,通過:分組無線服務 (GPRS) / 因特網 / Wi-Fi 服務 進行訪問
  • 常見的 LBS,即各種位置來源和技術,例如:
  • 全球定位系統 (GPS)、信號塔三角測量、公共無線保真 (Wi-Fi) 熱點

1.1 全球定位系統GPS(首選)

  • GPS:基於衛星的導航系統
  • 會定位至少 三顆衛星,計算到每顆衛星之間的距離,推斷自己的位置
  • 接收器使用稱爲“三邊測量”的數學原理計算對象在 二維空間 以及 三維空間中的位置

1.2 信號塔三角測量

  • 信號塔三角測量:無論設備是靜止還是運動狀態
  • 大部分移動網絡工作的基礎是:蜂窩網絡,覆蓋陸地區域的無線電網絡
  • 每個發射區至少有一個 固定位置的 收發器
  • 信號塔三角測量技術: 測量與已知信號塔的角度 + 信號強度 ,確定移動設備的位置

1.3 公共WI-FI熱點

  • 公共 Wi-Fi 熱點可用於確定設備的位置,GPS 相當弱的時候,這項技術非常有效,否則不怎麼用
  • 公共 Wi-Fi 熱點確定設備位置,需要服務提供商 定期掃描區域以收集關於公共 Wi-Fi 熱點的數據
  • 使用以下兩部分信息來建立數據庫: 熱點的媒體訪問控制 (MAC) 地址、熱點可見位置車輛的 GPS座標
  • 要確定設備的位置,需要用到以下過程:
  1. 設備將帶有該設備當前可見的 MAC 地址列表的請求發送給位置服務器
  2. 位置服務器將 MAC地址列表與已知 Wi-Fi熱點的 MAC地址列表相比較
  3. 位置服務器確定設備的大概位置

1.4 使用基於位置的服務

  • 啓用 LBS 的應用中,有兩個主要組件:
  1. LocationManager:提供對設備位置服務的訪問
  2. LocationProviders:是所有類型的位置提供者的基類,位置提供者會定時更新設備的位置
  • 其他用於 LBS(基於位置的服務)的類有:
  1. Address:地址類,一組描述位置的字符串
  2. Criteria:該類提供選擇位置提供者的應用條件,篩選器、經緯度風向時間海拔等
  3. Geocoder:地域編碼類
  4. GpsSatellite:該類表示GPS衛星的當前狀態
  5. Location:地理位置類,非常精確

1.5 訪問基於位置的服務

  • 訪問 LBS,必須使用 LocationManager 系統服務getSystemService(Context.LOCATION_SERVICE);
  • AndroidManifest.xml 文件中包含了權限,應用才能使用 LBS:
  1. android.permission.ACCESS_FINE_LOCATION:GPS需要的權限(GPS_PROVIDER)
  2. android.permission.ACCESS_COARSE_LOCATION:網絡需要12兩個權限(NETWORK_PROVIDER)

2.選擇位置提供者

  • 位置提供者:確定設備的當前位置的技術 稱爲位置提供者
  • 搜索位置提供者:LocationManager類,提供對系統位置服務的訪問
  • 設備進入給定地理位置的附近時,發送應用指定的 Intent
  • 兩個最常用的位置提供者:
  1. LocationManager.GPS_PROVIDER
  2. LocationManager.NETWORK_PROVIDER
  • getProviders()方法:確定可用的位置提供者
public class MainActivity extends Activity {
	TextView tv;
	LocationManager lm; // 聲明對象
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		tv = (TextView) findViewById(R.id.textView1);
        // 獲取位置管理器
		lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		// 設置每一秒獲取一次位置信息
		lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, // 位置提供者,GPS_PROVIDER, NETWORK_PROVIDER,PASSIVE_PROVIDER
				1000,  //更新數據時間爲1秒
				10,    //位置間隔爲10米
				new LocationListener() { //位置監聽器
					@Override // GPS定位信息發生改變時觸發,用於更新位置信息
					public void onLocationChanged(Location arg0) {
						Log.i("map","onLocationChanged");
						// 給出位置提供者,獲取最新的定位
						Location location = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
						if (location != null){
							tv.setText("當前位置:\n" + "緯度:"
									+ location.getLatitude() + "\n經度:"
									+ location.getLongitude());
						}else{
							tv.setText("location爲空,手機沒信號");
						}}
					@Override // 定位提供者關閉時觸發
					public void onProviderDisabled(String arg0) { 
						Log.i("map","onProviderDisabled");
					}
					@Override // 定位提供者啓動時觸發
					public void onProviderEnabled(String arg0) {
						Log.i("map","onProviderEnabled");
					}
					@Override // 位置狀態發生改變時觸發
					public void onStatusChanged(String arg0, int arg1,
							Bundle arg2) {
						Log.i("map","onStatusChanged");

					}});}}

3.AVD中訪問基於位置的服務

  • 啓用 LBS,需要在 AVD配置中 啓用GPS支持
  • 使用 DDMS透視圖中的 位置控件 模擬位置變化,以測試位置特定功能,而不實際移動
  • 仿真器中的三種位置控件: 手工,GPS交換格式 (GPX),Keyhole 標記語言 (KML)
  • 傳感器仿真器: 實時模擬傳感器數據,提供設備的可視化模型及其各種傳感器設置,模擬來自加速計、指南、GPS 以及取向傳感器的傳感器數據
  • 最流行的傳感器仿真器是 OpenIntents傳感器仿真器
  • 以下哪個選項在 Earth 瀏覽器中顯示了地理數據,例如 Google Earth 或 Google Maps 移動版?
  • 傳感器仿真器、手動控件、GPX KML、文件格式

4.創建基於地圖的應用

  • 在 Android平臺上顯示地圖: 使用 Google 地圖
  • 可以通過使用基於 Google Maps 數據的 Google Maps API 將地圖添加到應用
  • com.google.android.gms.maps.MapFragment類 提供用戶控制地圖所需的 UI元素
  • 要在應用中使用地圖,需要創建擴展 Activity類,Google Maps 從因特網下載地圖,並要求設置權限:
<permission
android:name="com.example.android.mapexample.permission.MAPS_RECEIVE"
android:protectionLevel="signature"/>
<uses-permission
android:name="com.example.android.mapexample.permission.MAPS_RECEIVE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> 
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

二.SMS

1.發送(文本)消息

  • SMS:移動設備之間,使用 文本消息通信 常用機制
  • android.telephony.SmsManager類 利用 Android 消息傳遞服務
  • SmsManager 類,使用靜態 getDefault()方法,創建SMS管理器服務實例
  • SmsManager smsManager = SmsManager.getDefault();
  • sendTextMessage()方法:發送文本消息
  • 指定權限發送SMS:android:name="android.permission.SEND_SMS" 

2.跟蹤和確認消息交付

  • SMS可以在多個仿真器實例之間發送,指定目標仿真器的 端口號 爲“收件人”地址
  • 跟蹤發出的消息傳輸是否成功,需要實現並註冊廣播接收器
  • 廣播接收器向sendTextMessage() 發送延時intent :PendingIntent 
  • PendingIntent.getBroadcast(Context c, int reqtCode, Intent i, int flags):
  1. Context c:應發送廣播的上下文
  2. int reqtCode:發送者個人請求代碼,通常是 0(未使用)
  3. Intent i:要廣播的 intent
  4. int flags:控制發送消息時 intent 的未指定部分,如果不需要標誌,可以用 0
  • PendingIntent 的 Flag標記值 可以是以下值:
  1. FLAG_ONE_SHOT:表示該PendingIntent只使用一次
  2. FLAG_NO_CREATE:表示若不存在對應的PendingIntent,則不會創建
  3. FLAG_CANCEL_CURRENT:表示每次取消 相同的當前意圖,創建新的PendingIntent
  4. FLAG_UPDATE_CURRENT:表示每次更新 當前PendingIntent的數據
  5. 0:不需要標誌
  • PendingIntent 成功發送消息 或 發送失敗時發出,結果代碼如下:
  1. Activity.RESULT_OK :發送成功
  2. SmsManager.RESULT_ERROR_GENERIC_FAILURE :普通錯誤,發送失敗
  3. SmsManager.RESULT_ERROR_RADIO_OFF :無線廣播被關閉,開啓飛行、離線模式,發送失敗
  4. SmsManager.RESULT_ERROR_NULL_PDU :缺少PDU,PDU負責發送、編碼短信,發送失敗
  5. SmsManager.RESULT_ERROR_NO_SERVICE:服務不可用,無信號,發送失敗

3.偵聽傳入的 SMS

  • 接收到SMS時,將觸發具有操作 SMS_RECEIVED 的廣播,該廣播通知所有接收器已收到 SMS
  • 需要 RECEIVED_SMS 權限:android.permission.RECEIVE_SMS
  • SMS 廣播意圖 包含了 傳入SMS 的詳細信息
  • android.telephony.SmsMessage類對象 存儲在 數組 中並打包到 SMS廣播 intent 束內
  • SmsMessage.createFromPdu() 方法:將 PDU字節數組 轉換成 字符串
  • 偵聽傳入的消息,要通過偵聽 android.provider.Telephony.SMS_RECEIVED 動作字符串的意圖過濾器:
finalStringRECEIVED_SMS = "android.provider.Telephony.SMS_RECEIVED";
IntentFilter filter = new IntentFilter(RECEIVED_SMS);
BroadcastReceiver receiver = new IncomingSMSReceiver();
registerReceiver(receiver, filter);

4.實現發送接收SMS 

// MainActivity.java
public class MainActivity extends Activity {
        // 聲明、獲取組件,註冊監聽器...
		sm=SmsManager.getDefault(); // 獲取默認的短信管理器,用於發送短信,然後設置權限
		send.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				// 獲取手機號和短信信息
				String to=etTo.getText().toString();
				String msg=etMsg.getText().toString();
                // 延時發送意圖:PendingIntent
				Intent i1=new Intent(MainActivity.this,SendReceiver.class);
				PendingIntent sendPi=PendingIntent.getBroadcast(MainActivity.this,0,i1,0);
				//1. 目標手機號
				//2. SMSC中心,短消息服務中心,一個號碼,給null,說明使用默認的短信服務中心
				//3. 短信內容
				//4. 一個PendingIntent對象,如果你發送消息後,希望發送一個廣播
				//5. 一個PendingInteng對象,如果對方接受消息成功後,希望發送一個廣播
				sm.sendTextMessage(to,null,msg,sendPi,null); // 發送短信,參數在上面
				Toast.makeText(MainActivity.this,"消息發出", Toast.LENGTH_SHORT).show();				
			}});}}

// SendReceiver.java:發送短信,一定不要忘記註冊廣播接收器
public class SendReceiver extends BroadcastReceiver{
	@Override
	public void onReceive(Context context, Intent intent) {
		int resultCode=getResultCode(); //發送信息結果碼
		switch(resultCode){
		case Activity.RESULT_OK:
			Toast.makeText(context, "短信發送成功!",Toast.LENGTH_LONG).show();
			break;
		case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
			Toast.makeText(context, "普通錯誤,發送失敗",Toast.LENGTH_LONG).show();
			break;
		case SmsManager.RESULT_ERROR_NO_SERVICE: // 收不到信號
			Toast.makeText(context, "服務不可用,發送失敗",Toast.LENGTH_LONG).show();
			break;
		case SmsManager.RESULT_ERROR_NULL_PDU: // PDU負責編碼短信和發送短信
			Toast.makeText(context, "沒有提供PDU,發送失敗",Toast.LENGTH_LONG).show();
			break;
		case SmsManager.RESULT_ERROR_RADIO_OFF: // 開啓了飛行或離線模式
			Toast.makeText(context, "無線廣播被關閉,發送失敗!",Toast.LENGTH_LONG).show();
			break;
		}}}

// ReceiveReceiver.java:接收短信,一定不要忘記註冊廣播接收器
public class ReceiveReceiver extends BroadcastReceiver{
	@Override
	public void onReceive(Context context, Intent intent) {
		Bundle bundle=intent.getExtras(); // getExtras():獲取短信數據包
		Object[] data=(Object[])bundle.get("pdus"); // 通過鍵pdus獲取短信列表,是一個對象數組
		SmsMessage[] messages=new SmsMessage[data.length];
		for(int i=0;i<data.length;i++){
			// 短信以 PDU編碼發送,要讀取信息,需要將 PDU編碼數據 轉成 字節數組
			messages[i]=SmsMessage.createFromPdu((byte[])data[i]);
			String from=messages[i].getOriginatingAddress(); //獲取發信人的手機號
			String msg=messages[i].getMessageBody();         //獲取短信內容
			Toast.makeText(context,"收到新短信:\n發信人:"+from+"\n短信內容:"+msg,
					Toast.LENGTH_LONG).show();
		}}}

三.通話

1.撥打電話

  • 電話通信包括:語音通話 和 視頻通話
  • 創建撥號器並撥打電話,可使用具有以下 action屬性的 隱式intent:
  • ACTION_CALL:ACTION_CALL intent 啓動 應用內部呼叫 (in-call) 活動,需要 CALL_PHONE 權限
  • ACTION_DIAL:ACTION_DIAL intent 啓動 撥號器呼叫活動但讓用戶初始化呼叫
  • 使用 tel 撥打號碼如下:
  • Intent intent = new Intent Intent.ACTION_DIAL,Uri.parse("tel:5623451")); 
  • startActivity(intent)

2.監視通話狀態 

  • 電話API 可監視電話狀態、檢索來電號碼、管理通話
  • 訪問電話API,需要創建 android.telephony.TelephonyManager類 實例:
  • getSystemService(Context.TELEPHONY_SERVICE
  • READ_PHONE_STATE 權限:訪問電話狀態
  • onCallStateChanged(int state, String incomingNumber):手機狀態改變調用,就是接電話的時候調用
  • incomingNumber表示呼叫號碼,state 參數表示 當前的電話狀態,其值爲以下三種之一:
  1. TelephonyManager.CALL_STATE_IDLE :手機空閒中
  2. TelephonyManager.CALL_STATE_RINGING :電話響起
  3. TelephonyManager.CALL_STATE_OFFHOOK :通話中
  • tele_Manager.listen(callStateListener, PhoneStateListener.LISTEN_CALL_STATE);
  • 還可以偵聽其他事件:
  • LISTEN_CALL_STATE :監聽電話狀態
  • LISTEN_CALL_FORWARDING_INDICATOR :監聽呼叫轉接指示器的變化
  • LISTEN_CELL_LOCATION :監聽設備位置變化
  • LISTEN_SERVICE_STATE:監聽網絡服務狀態變化

3.訪問電話屬性

  • TelephonyManager類: 提供對電話屬性的訪問,獲取當前的電話狀態詳細信息
  • TelephonyManager類 允許訪問:SIM信息 、網絡運營商信息、網絡信息、語音郵件詳細信息
  • 以下代碼段顯示 如何在電話響起時抽取來電的號碼:
String incomingCall = null;
if (telephonyManager.getCallState() == TelephonyManager.CALL_STATE_RINGING)
	incomingCall = telephonyManager.getLine1Number();
  • 以下代碼顯示 如何訪問當前網絡詳細信息:
String Name_sv = Context.TELEPHONY_SERVICE;
TelephonyManager tel_Manager = (TelephonyManager)getSystemService(Name_sv);
String netwk_Country = tel_Manager.getNetworkCountryIso();
String netwk_OpId = tel_Manager.getNetworkOperator();
String netwk_Name = tel_Manager.getNetworkOperatorName();
int netwk_Type = tel_Manager.getNetworkType();
  • 以下哪個選項屬於 TelephonyManager類?
  • LISTEN_CALL_FORWARDING_INDICATOR
  • getNetworkType()
  • FLAG_ONE_SHOT
  • FLAG_UPDATE_CURRENT

4.實現兩種方式的通話(應用內、撥號器)

public class MainActivity extends Activity {
        // 聲明、獲取組件,註冊監聽器....
		dial=(Button)findViewById(R.id.btnDial); // 撥號器
		call=(Button)findViewById(R.id.btnCall); // 自己的程序
		
		// 獲取系統的電話管理服務,得到電話管理器的實例
		tm=(TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
		tm.listen(new PhoneStateListener(){ // 監聽電話狀態,就是接受電話
			@Override // 手機狀態改變時調用:現在的狀態、呼叫的號碼
			public void onCallStateChanged(int state, String incomingNumber) {
				switch(state){ 
				case TelephonyManager.CALL_STATE_IDLE:
					Toast.makeText(MainActivity.this,"電話空閒中",Toast.LENGTH_LONG).show();
					break;
				case TelephonyManager.CALL_STATE_RINGING:
					Toast.makeText(MainActivity.this,"電話響起,來自:"+incomingNumber,Toast.LENGTH_LONG).show();
					break;
				case TelephonyManager.CALL_STATE_OFFHOOK:
					Toast.makeText(MainActivity.this,"通話中",Toast.LENGTH_LONG).show();
					break;
				}}
		}, PhoneStateListener.LISTEN_CALL_STATE);}

	class ButtonListener implements OnClickListener{ // 以下是撥打電話
		@Override
		public void onClick(View v) {
			switch(v.getId()){
			case R.id.btnDial:
				Intent i1=new Intent();
				i1.setAction(Intent.ACTION_DIAL);  // 啓動系統撥號器打電話
				i1.setData(Uri.parse("tel:0532")); // 設定一個號碼顯示在撥號器界面
				startActivity(i1);
				break;
			case R.id.btnCall:
				Intent i2=new Intent();
				i2.setAction(Intent.ACTION_CALL); // 啓動應用內打電話
				i2.setData(Uri.parse("tel:"+etNumber.getText().toString()));
				startActivity(i2);
				break;
			}}}}
  • 應用內通話:
  • 撥號器通話:
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章