目錄
一.位置
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座標
- 要確定設備的位置,需要用到以下過程:
- 設備將帶有該設備當前可見的 MAC 地址列表的請求發送給位置服務器
- 位置服務器將 MAC地址列表與已知 Wi-Fi熱點的 MAC地址列表相比較
- 位置服務器確定設備的大概位置
1.4 使用基於位置的服務
- 啓用 LBS 的應用中,有兩個主要組件:
- LocationManager:提供對設備位置服務的訪問
- LocationProviders:是所有類型的位置提供者的基類,位置提供者會定時更新設備的位置
- 其他用於 LBS(基於位置的服務)的類有:
- Address:地址類,一組描述位置的字符串
- Criteria:該類提供選擇位置提供者的應用條件,篩選器、經緯度風向時間海拔等
- Geocoder:地域編碼類
- GpsSatellite:該類表示GPS衛星的當前狀態
- Location:地理位置類,非常精確
1.5 訪問基於位置的服務
- 訪問 LBS,必須使用 LocationManager 系統服務:getSystemService(Context.LOCATION_SERVICE);
- AndroidManifest.xml 文件中包含了權限,應用才能使用 LBS:
- android.permission.ACCESS_FINE_LOCATION:GPS需要的權限(GPS_PROVIDER)
- android.permission.ACCESS_COARSE_LOCATION:網絡需要12兩個權限(NETWORK_PROVIDER)
2.選擇位置提供者
- 位置提供者:確定設備的當前位置的技術 稱爲位置提供者
- 搜索位置提供者:LocationManager類,提供對系統位置服務的訪問
- 設備進入給定地理位置的附近時,發送應用指定的 Intent
- 兩個最常用的位置提供者:
- LocationManager.GPS_PROVIDER
- 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):
- Context c:應發送廣播的上下文
- int reqtCode:發送者個人請求代碼,通常是 0(未使用)
- Intent i:要廣播的 intent
- int flags:控制發送消息時 intent 的未指定部分,如果不需要標誌,可以用 0
- PendingIntent 的 Flag標記值 可以是以下值:
- FLAG_ONE_SHOT:表示該PendingIntent只使用一次
- FLAG_NO_CREATE:表示若不存在對應的PendingIntent,則不會創建
- FLAG_CANCEL_CURRENT:表示每次取消 相同的當前意圖,創建新的PendingIntent
- FLAG_UPDATE_CURRENT:表示每次更新 當前PendingIntent的數據
- 0:不需要標誌
- PendingIntent 成功發送消息 或 發送失敗時發出,結果代碼如下:
- Activity.RESULT_OK :發送成功
- SmsManager.RESULT_ERROR_GENERIC_FAILURE :普通錯誤,發送失敗
- SmsManager.RESULT_ERROR_RADIO_OFF :無線廣播被關閉,開啓飛行、離線模式,發送失敗
- SmsManager.RESULT_ERROR_NULL_PDU :缺少PDU,PDU負責發送、編碼短信,發送失敗
- 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 參數表示 當前的電話狀態,其值爲以下三種之一:
- TelephonyManager.CALL_STATE_IDLE :手機空閒中
- TelephonyManager.CALL_STATE_RINGING :電話響起
- 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; }}}}
- 應用內通話:
- 撥號器通話: