第15章 網路與通訊 15-1 WebView元件-行動瀏覽器 15-2 簡訊處理-我的簡訊 15-3 寄送電子郵件-郵件寄送工具

Slides:



Advertisements
Similar presentations
第一單元 建立java 程式.
Advertisements

第16章 首頁畫面小工具與硬體介面 16-1 首頁畫面小工具-手機靜音切換 16-2 感測器與遊戲控制-跳跳球遊戲
第13章 繪圖與多媒體 13-1 顯示圖檔-行動相簿 13-2 音樂播放-音樂播放器 13-3 影片播放-視訊播放器
第13章 繪圖與多媒體 13-1 顯示圖檔-行動相簿 13-2 音樂播放-音樂播放器 13-3 影片播放-視訊播放器
實驗五:多媒體播放器選單介面.
Part 2 開發Android應用程式的流程
位置與地圖應用 此投影片為講解Android如何取得定位經緯度和使用Google Map地圖.
第二章 JAVA语言基础.
Android + Web Service 建國科技大學 資管系 饒瑞佶 2017/3 V1.
手持式裝置之隨身照護應用 Android開發環境設定 鐘國家 老師.
手持式裝置之隨身照護應用 Android開發環境設定 鐘國家 老師.
Android App 系統開發教學 Luna 陳雯琳 2014/12/18
厦门大学数据库实验室 报告人:谢荣东 导师:林子雨 2014年8月30日
實驗四:單位轉換程式.
第2章 建立Android應用程式 2-1 Java語言、XML文件與Android 2-2 建立第一個Android應用程式
Chapter 13 Android 實戰演練.
Android + JUnit 單元測試 建國科技大學資管系 饒瑞佶 2012/8/19V4.
第14章 Google地圖與定位服務 14-1 定位服務-我在哪裡 14-2 地圖解碼服務-找出景點座標
實驗十三:顯示目前經緯度位置.
Ch06 再談選單元件 物件導向系統實務.
使用Android控制Arduino 史先强
第10章 App微信分享的实现 倚动实验室.
第一个Android程序 本讲大纲: 1、创建Android应用程序 2、Android项目结构说明 3、运行Android应用程序
第8章 Android内容提供者(ContentProvider)应用
Android智慧型手機程式設計實務應用班
客戶端的檔案上傳 HtmlInputFile檔案控制項 上傳單一檔案 同時上傳多個檔案.
Chapter 7 Android應用元件 Android應用元件可以幫助我們獲得系統資源訊息(ActivityManager)、提供系統服務(Service)、搜尋系統服務(SearchManager)、監聽Intent訊息(Broadcast Receiver)以及資料共享(ContentProvider和ContentResolver)。
第9章 使用意圖啟動活動與內建應用程式 9-1 意圖的基礎 9-2 使用意圖啟動活動
程式設計實作.
CH7 佈局、按鈕與文字編輯元件.
Android + Service 建國科技大學 資管系 饒瑞佶.
第10章 儲存偏好設定、檔案與資料庫 10-1 存取偏好設定 10-2 檔案存取 10-3 關聯式資料庫與SQLite
實驗十四:顯示與控制地圖.
第6章 建立Android使用介面 6-1 介面元件的基礎 6-2 Android的事件處理 6-3 按鈕元件 6-4 文字元件
第8章 對話方塊與資源管理 8-1 對話方塊的基礎 8-2 建立與顯示對話方塊 8-3 使用DialogFragment建立對話方塊
App Inventor2呼叫PHP存取MySQL
Android App簡介及 App Inventor 2體驗 靜宜大學資管系 楊子青
Java 程式設計 講師:FrankLin.
Java程序设计 第2章 基本数据类型及操作.
生活智慧王 樹德科技大學 資訊工程系 指導教授 : 陳毓璋 教授 小組成員: 劉上緯 翁維廷 洪文財.
第一單元 建立java 程式.
VS.NET 2003 IDE.
實驗十一:待辦事項程式 (儲存在手機上).
主编:钟元生 赵圣鲁.
透過YouTuBe API取得資料 建國科技大學 資管系 饒瑞佶 2018/1 V1.
Android Application Component
網路應用.
Ch17 SharedPreference與檔案應用
實驗九:延續實驗八, 製作一個完整音樂播放器
Location Based Services - LBS
安裝 / 操作 flashget SOP (以Win 7 作業系統為範例)
期末考.
VS.NET 2003 IDE.
第二章 Java语法基础.
Broadcasts (廣播) 靜宜大學資管系 楊子青
第二章 Java基本语法 讲师:复凡.
進階UI元件:ListView元件以及複選 靜宜大學資管系 楊子青
實驗十:影片播放.
Android Speech To Text(STT)
Activity的生命週期: 播放音樂與影片 靜宜大學資管系 楊子青
用Intent啟動程式中的其他Activity、運用WebView顯示網頁 靜宜大學資管系 楊子青
第2章 Java语言基础.
第9章 BroadcastReceiver的使用
讀取網路資料及JSON開放資料 靜宜大學資管系 楊子青
加速感測器 靜宜大學資管系 楊子青.
NFC (近場通訊, Near Field Communication) 靜宜大學資管系 楊子青
SQLite資料庫 靜宜大學資管系 楊子青.
第二章 Java基础语法 北京传智播客教育
Part 8 Broadcast Receiver、Service和App Widget
Summary
Presentation transcript:

第15章 網路與通訊 15-1 WebView元件-行動瀏覽器 15-2 簡訊處理-我的簡訊 15-3 寄送電子郵件-郵件寄送工具 15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 15-5 簡訊與定位服務-GPS間諜簡訊

15-1 WebView元件-行動瀏覽器 在Android應用程式可以使用WebView元件來瀏覽網頁內容,換句話說,我們可以使用WebView元件建立自己的瀏覽器。

15-1 WebView元件-行動瀏覽器 步驟一:開啟和執行Android Studio專案 請啟動Android Studio開啟專案Ch15_1,內含1個Java類別檔和版面配置檔activity_main.xml,其執行結果如右圖所示:

15-1 WebView元件-行動瀏覽器 步驟二:建立WebView元件的版面配置 行動瀏覽器的使用介面是定義在activity_main.xml版面配置檔,在刪除TextView元件後,水平編排1個EditText(txtUrl)和Button(button,onClick屬性值是button_Click)元件,如下圖所示:

15-1 WebView元件-行動瀏覽器 步驟三:建立Activity活動類別 在MainActivity活動類別的開頭宣告成員變數ProgressBar、WebView和EditText物件,如下所示: public class MainActivity extends ActionBarActivity { private ProgressBar progressbar; private WebView web; private EditText txtUrl; …... }

15-1 WebView元件-行動瀏覽器 步驟三:建立Activity活動類別-onCreate()方法 在覆寫onCreate()方法載入版面配置後,依序取得ProgressBar、WebView和EditText物件,如下所示: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); progressbar = (ProgressBar) findViewById(R.id.progressBar); web = (WebView) findViewById(R.id.webView); initWebBrowser(); txtUrl = (EditText) findViewById(R.id.txtUrl); String strUrl = txtUrl.getText().toString(); loadUrl(web, strUrl); }

15-1 WebView元件-行動瀏覽器 步驟三:建立Activity活動類別-initWebBrowser()方法 在initWebBrowser()方法初始WebView物件和顯示載入網頁的進度對話方塊,如下所示: public void initWebBrowser() { // 初始WebView元件 web.getSettings().setJavaScriptEnabled(true); web.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY); web.setWebViewClient(new WebViewClient(){ public boolean shouldOverrideUrlLoading( final WebView view, final String url) { loadUrl(view, url); return true; } });

15-1 WebView元件-行動瀏覽器 步驟三:建立Activity活動類別-setWebChromeClient()方法 WebView物件的setWebChromeClient()方法指定使用的WebChromeClient客戶端物件,如下所示: web.setWebChromeClient(new WebChromeClient(){ public void onProgressChanged(WebView view,int progress) { progressbar.setProgress(progress); super.onProgressChanged(view, progress); } });

15-1 WebView元件-行動瀏覽器 步驟三:建立Activity活動類別-loadUrl()方法 自訂方法loadUrl()可以在WebView元件載入網頁,如下所示: public void loadUrl(final WebView view,final String url){ progressbar.setProgress(0); view.loadUrl(url); }

15-1 WebView元件-行動瀏覽器 步驟三:建立Activity活動類別-button_Click()方法 Button元件的事件處理方法是當使用者在EditText元件輸入新網址後,按下按鈕,就呼叫此方法來載入URL網址的網頁,如下所示: public void button_Click(View view) { String strUrl = txtUrl.getText().toString(); loadUrl(web, strUrl); }

15-1 WebView元件-行動瀏覽器 步驟三:建立Activity活動類別-onKeyDown()方法 在onKeyDown()方法是處理使用者按下返回鍵(BACK)回到上一頁網頁,如果沒有上一頁網頁,就顯示對話方塊,確認是否離開行動瀏覽器,如下所示: @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if ((keyCode == KeyEvent.KEYCODE_BACK) && web.canGoBack()) { web.goBack(); return true; } else if(keyCode == KeyEvent.KEYCODE_BACK) {

15-1 WebView元件-行動瀏覽器 步驟三:建立Activity活動類別-onKeyDown()方法 AlertDialog.Builder aDlg = new AlertDialog.Builder(this); aDlg.setTitle("離開行動瀏覽器") .setMessage("請確認離開行動瀏覽器?") .setPositiveButton("是", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int i) { MainActivity.this.finish(); } }) .setNegativeButton("否", null).show(); return true; return super.onKeyDown(keyCode, event);

15-1 WebView元件-行動瀏覽器 步驟四:在AndroidManifest.xml新增存取Internet權限 行動瀏覽器因為需要連線Internet,所以在AndroidManifest.xml檔新增INTERNET權限,如下所示: <uses-permission android:name="android.permission.INTERNET"/>

15-2 簡訊處理-我的簡訊 行動裝置的主要功能就是對外通訊,我們除了使用語音通話外,另一個常用功能是「簡訊」(Short Message Service,SMS),即手機的文字訊息服務。 在這一節筆者準備說明如何在Android應用程式收發簡訊,我們需要使用廣播接收器來取得與顯示簡訊的內容。

15-2 簡訊處理-我的簡訊 步驟一:開啟和執行Android Studio專案 請啟動Android Studio開啟專案Ch15_2,內含2個Java類別檔和1個版面配置檔activity_main.xml,因為需要測試簡訊傳送,我們需要同時啟動2個Android模擬器,以筆者為例是GPhone和MyPhone,在視窗標題文字的「:」符號前是電話號碼,以此例分別為5554和5556。 請在GPhone模擬器執行Android專案Ch15_2,其執行結果如右圖所示:

15-2 簡訊處理-我的簡訊 步驟二:建立寄送簡訊使用介面的版面配置 寄送簡訊的使用介面是定義在activity_main.xml版面配置檔,依序垂直編排2個TextView和EditText(txtPhoneNo、txtMessage)元件,一個Button元件,如下圖所示:

15-2 簡訊處理-我的簡訊 步驟三:建立Activity活動類別寄送簡訊 在MainActivity活動類別的開頭宣告成員變數EditText物件txtPhoneNo和txtMessage,如下所示: public class MainActivity extends ActionBarActivity { private EditText txtPhoneNo, txtMessage; … }

15-2 簡訊處理-我的簡訊 步驟三:建立Activity活動類別寄送簡訊-onCreate() 在覆寫的onCreate()方法載入版面配置後,可以取得2個EditText物件,如下所示: @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); txtPhoneNo = (EditText) findViewById(R.id.txtPhoneNo); txtMessage = (EditText) findViewById(R.id.txtMessage); }

15-2 簡訊處理-我的簡訊 步驟三:建立Activity活動類別寄送簡訊-button_Click() public void button_Click(View view) { String phoneNo = txtPhoneNo.getText().toString(); String message = txtMessage.getText().toString(); if (phoneNo.length() > 0 && message.length() > 0) sendSMS(phoneNo, message); else Toast.makeText(this, "請確認輸入電話號碼和訊息內容!", Toast.LENGTH_SHORT).show(); }

15-2 簡訊處理-我的簡訊 步驟三:建立Activity活動類別寄送簡訊-sendSMS() private void sendSMS(String phoneNumber, String message) { String SENT = "SMS_SENT"; String DELIVERED = "SMS_DELIVERED"; registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context content, Intent intent) { switch (getResultCode()) { case Activity.RESULT_OK: Toast.makeText(getBaseContext(), "簡訊送出", Toast.LENGTH_SHORT).show(); break; case SmsManager.RESULT_ERROR_GENERIC_FAILURE: Toast.makeText(getBaseContext(), "一般錯誤!",

15-2 簡訊處理-我的簡訊 步驟三:建立Activity活動類別寄送簡訊-sendSMS() case SmsManager.RESULT_ERROR_NO_SERVICE: Toast.makeText(getBaseContext(), "沒有服務!", Toast.LENGTH_SHORT).show(); break; case SmsManager.RESULT_ERROR_NULL_PDU: Toast.makeText(getBaseContext(), "空的PDU", case SmsManager.RESULT_ERROR_RADIO_OFF: Toast.makeText(getBaseContext(), "沒有訊號", } }, new IntentFilter(SENT));

15-2 簡訊處理-我的簡訊 步驟三:建立Activity活動類別寄送簡訊-sendSMS() 當簡訊送達,我們再建立一個廣播接收器取得是否送達的結果,如下所示: registerReceiver(new BroadcastReceiver() { public void onReceive(Context content, Intent intent) { switch (getResultCode()) { case Activity.RESULT_OK: Toast.makeText(getBaseContext(), "簡訊已經送達!", Toast.LENGTH_SHORT).show(); break; case Activity.RESULT_CANCELED: Toast.makeText(getBaseContext(), "簡訊沒有送達!", } }, new IntentFilter(DELIVERED));

15-2 簡訊處理-我的簡訊 步驟三:建立Activity活動類別寄送簡訊-sendSMS() 寄送簡訊首先是建立PendingIntent物件,如下所示: PendingIntent sentPI = PendingIntent.getBroadcast( this, 0, new Intent(SENT), 0); PendingIntent deliveredPI = PendingIntent.getBroadcast( this, 0, new Intent(DELIVERED), 0); 上述PendingIntent物件包裝的Intent物件分別送出SMS_SENT和SMS_DELIVERED廣播。

15-2 簡訊處理-我的簡訊 步驟三:建立Activity活動類別寄送簡訊-sendSMS() 然後取得SmsManager物件寄送簡訊,使用SmsManager類別的getDefault()方法來取得此物件,如下所示: SmsManager sms = SmsManager.getDefault(); sms.sendTextMessage(phoneNumber, null, message, sentPI, deliveredPI); }

15-2 簡訊處理-我的簡訊 步驟四:建立BroadcastReceiver類別接收簡訊-1 在Android應用程式可以使用廣播接收器接收行動裝置收到簡訊的系統廣播,換句話說,我們可以透過它來過濾出我們需要的簡訊,在第15-5節就是使用此方法來找出間諜簡訊。 Android Studio專案Ch15_2建立SMSReceiver.java類別檔的廣播接收器,如下所示: public class SMSReceiver extends BroadcastReceiver { … }

15-2 簡訊處理-我的簡訊 步驟四:建立BroadcastReceiver類別接收簡訊-2 我們需要覆寫onReceive()方法來建立廣播接收器,如下所示: @Override public void onReceive(Context context, Intent intent) { Bundle bundle = intent.getExtras(); SmsMessage[] msgs = null; String str = ""; 如果有,就取出簡訊中的電話號碼和內容,簡訊內容是儲存在PDU格式的Object[]陣列,如下所示: if (bundle != null) { Object[] pdus = (Object[]) bundle.get("pdus"); msgs = new SmsMessage[pdus.length];

15-2 簡訊處理-我的簡訊 步驟四:建立BroadcastReceiver類別接收簡訊-3 for (int i = 0; i < msgs.length; i++){ msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]); str += "SMS from " + msgs[i].getOriginatingAddress(); str += " :"; str += msgs[i].getMessageBody().toString(); str += "\n"; } Toast.makeText(context, str, Toast.LENGTH_LONG).show();

15-2 簡訊處理-我的簡訊 步驟五:在AndroidManifest.xml註冊廣播接收器和新增權限1 SMSReceiver廣播接收器需要在AndroidManifest.xml檔註冊,Telephony.SMS_RECEIVED是處理行動裝置收到簡訊的系統廣播,如下所示: <receiver android:name=".SMSReceiver"> <intent-filter> <action android:name= "android.provider.Telephony.SMS_RECEIVED" /> </intent-filter> </receiver>

15-2 簡訊處理-我的簡訊 步驟五:在AndroidManifest.xml註冊廣播接收器和新增權限2 <uses-permission android:name="android.permission.SEND_SMS" /> <uses-permission android:name="android.permission.RECEIVE_SMS" />

15-3 寄送電子郵件-郵件寄送工具 如同簡訊,我們也可以建立Android應用程式來寄送電子郵件,不過,我們並不是直接寄送,而是透過Intent物件呼叫內建郵件工具來寄送電子郵件。

15-3 寄送電子郵件-郵件寄送工具 步驟一:開啟和執行Android Studio專案 請啟動Android Studio開啟專案Ch15_3,內含1個Java類別檔和版面配置檔activity_main.xml,其執行結果如下圖所示:

15-3 寄送電子郵件-郵件寄送工具 步驟二:建立郵件寄送工具使用介面的版面配置 寄送郵件的使用介面是定義在activity_main.xml版面配置檔,依序垂直編排2個TextView和EditText(txtAddress、txtBody)元件,一個Button元件,如下圖所示:

15-3 寄送電子郵件-郵件寄送工具 步驟三:建立Activity活動類別寄送電子郵件 在MainActivity活動類別的開頭宣告成員變數Button和EditText物件變數,如下所示: public class MainActivity extends ActionBarActivity { Button send; EditText address, emailbody; … }

15-3 寄送電子郵件-郵件寄送工具 步驟三:建立Activity活動類別寄送電子郵件-onCreate() 在覆寫onCreate()方法載入版面配置後,取得2個EditText物件的郵件內容,如下所示: @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); address = (EditText) findViewById(R.id.txtAddress); emailbody = (EditText) findViewById(R.id.txtBody); }

15-3 寄送電子郵件-郵件寄送工具 步驟三:建立Activity活動類別寄送電子郵件-button_Click() 在Button元件的事件處理方法啟動內建郵件工具來寄送電子郵件,首先使用if條件檢查是否有輸入電子郵件地址,然後建立Intent物件,如下所示: public void button_Click(View view) { if (!address.getText().toString().trim().equalsIgnoreCase("")) { Intent eIntent = new Intent( android.content.Intent.ACTION_SEND); eIntent.setType("plain/text"); eIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{ address.getText().toString()}); eIntent.putExtra(Intent.EXTRA_TEXT, emailbody.getText()); startActivity(Intent.createChooser(eIntent, "寄送電子郵件...")); } else { Toast.makeText(this, "請輸入電子郵件地址..", Toast.LENGTH_LONG).show();

15-4 檔案下載與AsyncTask抽象類別- 大型檔案下載 在Android應用程式下載檔案建議使用執行緒,我們可以直接繼承AsyncTask抽象類別來建立執行緒,此類別可以建立執行緒來執行背景作業,換句話說,我們可以直接繼承AsyncTask抽象類別來執行大型檔案的下載。

15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟一:開啟和執行Android Studio專案 請啟動Android Studio開啟專案Ch15_4,內含2個Java類別檔和版面配置檔activity_main.xml,其執行結果如下圖所示:

15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟二:建立大型檔案下載使用介面的版面配置 大型檔案下載的使用介面是定義在activity_main.xml版面配置檔,依序編排2個TextView和EditText元件,最後是Button元件,如下圖所示:

15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟三:DialogFragment執行進度對話方塊-1 DialogFragment執行進度對話方塊是修改第8-3-3節範例,ProgressDialogFragment類別繼承DialogFragment類別,和宣告成員變數pDialog,如下所示: public class ProgressDialogFragment extends DialogFragment { private ProgressDialog pDialog; ….... }

在newInstance()類別方法建立ProgressDialogFragment物件後,指定附加的標題文字參數,如下所示: 15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟三:DialogFragment執行進度對話方塊-newInstance() 在newInstance()類別方法建立ProgressDialogFragment物件後,指定附加的標題文字參數,如下所示: static ProgressDialogFragment newInstance(String title) { ProgressDialogFragment dlg = new ProgressDialogFragment(); Bundle args = new Bundle(); args.putString("title", title); dlg.setArguments(args); return dlg; }

15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟三:DialogFragment執行進度對話方塊-onCreateDialog() 在覆寫onCreateDialog()方法取得標題文字參數title後,建立ProgressDialog進度對話方塊物件,如下所示: @Override public Dialog onCreateDialog(Bundle savedInstanceState) { String title = getArguments().getString("title"); pDialog = new ProgressDialog(getActivity()); pDialog.setTitle(title); pDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); pDialog.setProgress(0); return pDialog; }

在updateProgress()方法呼叫setProgress()方法來更新目前進度,如下所示: 15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟三:DialogFragment執行進度對話方塊-updateProgress() 在updateProgress()方法呼叫setProgress()方法來更新目前進度,如下所示: public void updateProgress(Integer progress) { pDialog.setProgress(progress); }

15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟四:在Activity類別使用AsyncTask類別下載檔案 在MainActivity活動類別開頭宣告成員變數ProgressDialogFragment物件變數,和檔案名稱字串,如下所示: public class MainActivity extends ActionBarActivity { private ProgressDialogFragment dlg; private String filename; ….... }

在覆寫onCreate()方法載入版面配置後,取得Button物件和建立Click事件處理方法,如下所示: 15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟四:在Activity類別使用AsyncTask類別下載檔案-onCreate() 在覆寫onCreate()方法載入版面配置後,取得Button物件和建立Click事件處理方法,如下所示: @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btn = (Button)findViewById(R.id.button); 上述程式碼取得Button元件btn後,指定傾聽者物件的事件處理方法,這是使用匿名內層類別建立的傾聽者物件。

實作介面的onClick()方法,如下所示: 15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟四:在Activity類別使用AsyncTask類別下載檔案-onCreate() 實作介面的onClick()方法,如下所示: btn.setOnClickListener(new View.OnClickListener(){ public void onClick(View v) { EditText txtUrl = (EditText) findViewById(R.id.txtUrl); String url = txtUrl.getText().toString(); EditText txtFile = (EditText) findViewById(R.id.txtFile); filename = txtFile.getText().toString(); new AsyncDownloadLargeFile(filename).execute(url); } });

15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟四:在Activity類別使用AsyncTask類別下載檔案-抽象類別1 class AsyncDownloadLargeFile extends AsyncTask<String, Integer, String> { private String file; public AsyncDownloadLargeFile(String filename) { file = filename; } ……

15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟四:在Activity類別使用AsyncTask類別下載檔案-抽象類別2 Step 1:首先呼叫onPreExecute()方法建立和啟動執行緒,通常我們會在此方法設定作業和顯示進度對話方塊,如下所示: @Override protected void onPreExecute() { super.onPreExecute(); dlg = ProgressDialogFragment.newInstance("下載檔案..."); FragmentManager fm = getSupportFragmentManager(); dlg.show(fm, "progressdialog"); }

15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟四:在Activity類別使用AsyncTask類別下載檔案-抽象類別3 Step 2:doInBackground(Params...)方法是在onPreExecute()方法之後執行,我們可以在此方法執行長時間的背景作業,例如:下載大型檔案,執行期間可以呼叫publishProgress(Progress...)方法送出目前進度,然後在Step 3的onProgressUpdate()方法更新。doInBackground()方法參數String後的省略符號「...」,表示參數是可變長度的參數列,第1個參數是urls[0](詳見第A-4-4節的說明),如下所示: @Override protected String doInBackground(String... urls) { int count; try { URL url = new URL(urls[0]); URLConnection con = url.openConnection(); con.connect(); int len = con.getContentLength(); Log.d("Ch15_4", "檔案尺寸: " + len); InputStream in = new BufferedInputStream(url.openStream()); OutputStream out = new FileOutputStream("/sdcard/" + file);

15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟四:在Activity類別使用AsyncTask類別下載檔案-抽象類別4 下方程式碼是使用while迴圈讀取遠端檔案和寫入下載檔案至SD卡,publishProgress()方法更新下載檔案的進度,如下所示: byte data[] = new byte[1024]; long total = 0; while ((count = in.read(data)) != -1) { total += count; publishProgress((int)((total*100)/len)); out.write(data, 0, count); } out.flush(); out.close(); in.close(); } catch (Exception e) {} return null;

15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟四:在Activity類別使用AsyncTask類別下載檔案-抽象類別5 Step 3:當在Step 2呼叫publishProgress()方法後,就會呼叫onProgressUpdate(Progress...)方法,我們可以在此方法更新進度,例如:更新進度對話方塊顯示的進度,即呼叫updateProgress()方法,Integer後的省略符號「...」表示參數是可變長度的參數列,第1個參數是progress[0] (詳見第A-4-4節的說明),如下所示: @Override protected void onProgressUpdate(Integer... progress) { Log.d("Ch15_4", "進度: " + progress[0]); dlg.updateProgress(progress[0]); }

15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟四:在Activity類別使用AsyncTask類別下載檔案-抽象類別6 Step 4:onPostExecute(Result)是在背景操作執行完畢後呼叫,我們可以在此步驟隱藏進度對話方塊,其方法參數並沒有使用,如下所示: @Override protected void onPostExecute(String unused) { dlg.dismiss(); }

15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟五:在AndroidManifest.xml新增權限 大型檔案下載因為需要連線Internet和在外部儲存裝置寫入檔案,所以在AndroidManifest.xml檔需要新增INTERNET和WRITE_EXTERNAL_STORAGE權限,如下所示: <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name= "android.permission.WRITE_EXTERNAL_STORAGE"/>

15-5 簡訊與定位服務-GPS間諜簡訊 GPS間諜簡訊是簡訊與定位服務的應用,當執行此程式,只需接到特定暗號的簡訊,行動裝置就會自動送出簡訊告知目前行動裝置的經緯度座標,換句話說,我們可以發送簡訊來得知遺失手機的位置,或使用簡訊來查詢或追蹤小孩或老人家目前的位置。

15-5 簡訊與定位服務-GPS間諜簡訊 步驟一:開啟和執行Android Studio專案 請啟動Android Studio開啟專案Ch15_5,內含2個Java類別檔和版面配置檔activity_main.xml。首先啟動Android Device Monitor,在左邊選準備執行程式的GPhone模擬器;右邊選【Emulator Control】標籤找到輸入經緯度座標的欄位,如下圖所示:

15-5 簡訊與定位服務-GPS間諜簡訊 步驟二:建立GPS間諜簡訊使用介面的版面配置 GPS間諜簡訊的使用介面是定義在activity_main.xml版面配置檔,依序編排1個TextView和EditText元件來輸入暗號,最後是Button元件(onClick屬性值是button_Click),如下圖所示:

15-5 簡訊與定位服務-GPS間諜簡訊 步驟三:建立Activity活動輸入和儲存暗號-1 在MainActivity活動類別的開頭宣告public的3個常數,和2個成員變數SharedPreferences和EditText物件變數,如下所示: public class MainActivity extends ActionBarActivity { public static final String PREFERENCES = "SPYSMSPreferences"; public static final String PREFERENCES_CODE = "SPYSMSPreferenceCode"; public static final String PREFERENCES_CODE_DEFAULT = "SPY"; private EditText txtCode; private SharedPreferences prefs; …... }

15-5 簡訊與定位服務-GPS間諜簡訊 步驟三:建立Activity活動輸入和儲存暗號- onCreate() 在覆寫onCreate()方法載入版面配置後,取得EditText元件和SharedPreferences物件,如下所示: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); txtCode = (EditText) findViewById(R.id.txtCode); prefs = getSharedPreferences(PREFERENCES, MODE_PRIVATE); }

15-5 簡訊與定位服務-GPS間諜簡訊 步驟三:建立Activity活動輸入和儲存暗號- button_Click() 在Button元件的事件處理方法是以使用者偏好設定檔來儲存暗號,在取得SharedPreferences.Editor物件後,呼叫putString()和apply()方法寫入暗號字串至檔案,如下所示: public void button_Click(View view) { SharedPreferences.Editor prefEdit = prefs.edit(); prefEdit.putString(PREFERENCES_CODE, txtCode.getText().toString()); prefEdit.apply(); Toast.makeText(this, "成功儲存暗號!", Toast.LENGTH_SHORT).show(); }

15-5 簡訊與定位服務-GPS間諜簡訊 步驟四:建立BroadcastReceiver類別接收簡訊-1 在Android應用程式可以使用廣播接收器接收行動裝置收到簡訊的系統廣播,然後過濾簡訊找出內容為暗號的簡訊,如果是間諜簡訊,就取得目前的定位位置,然後回覆簡訊,其內容是經緯度座標。 Android Studio專案Ch15_5建立SMSReceiver.java類別檔的廣播接收器,如下所示: public class SMSReceiver extends BroadcastReceiver { … }

15-5 簡訊與定位服務-GPS間諜簡訊 步驟四:建立BroadcastReceiver類別接收簡訊-2 onReceive()方法 讀取簡訊內容來檢查是否是擁有暗號的簡訊,如下所示: @Override public void onReceive(Context context, Intent intent) { if(intent.getAction().equalsIgnoreCase( "android.provider.Telephony.SMS_RECEIVED")) { SmsMessage[] messages = getMessagesFromIntent(intent); if(messages != null){ for(int i = 0; i < messages.length; i++){ SmsMessage message = messages[i]; if(matchesSpyMessage( context,message.getDisplayMessageBody())){ Log.i("Ch15_5", "收到間諜簡訊!"); sendSpySms(context, message.getOriginatingAddress()); break; }

15-5 簡訊與定位服務-GPS間諜簡訊 步驟四:建立BroadcastReceiver類別接收簡訊-3 getMessagesFromIntent()方法 在自訂的getMessagesFromIntent()方法可以取得簡訊內容,參數是Intent物件,傳回值是SmsMessage[]陣列,如下所示: private SmsMessage[] getMessagesFromIntent(Intent intent) { SmsMessage retMsgs[] = null; Bundle bundle = intent.getExtras(); try { Object pdus[] = (Object[]) bundle.get("pdus"); retMsgs = new SmsMessage[pdus.length]; for (int n = 0; n < pdus.length; n++) { byte[] byteData = (byte[]) pdus[n]; retMsgs[n] = SmsMessage.createFromPdu(byteData); } } catch (Exception e) { Log.e("Ch15_5", "取得簡訊內容失敗...", e); return retMsgs;

15-5 簡訊與定位服務-GPS間諜簡訊 步驟四:建立BroadcastReceiver類別接收簡訊-4 matchesSpyMessage()方法 在自訂matchesSpyMessage()方法的參數是Context物件和簡訊內容的String字串,方法讀取使用者偏好設定的暗號來比對是否是一則間諜簡訊,如下所示: private boolean matchesSpyMessage(Context context, String message) { SharedPreferences preferences = context.getSharedPreferences( Ch15_5Activity.PREFERENCES, Context.MODE_PRIVATE); String code = preferences.getString( Ch15_5Activity.PREFERENCES_CODE, Ch15_5Activity.PREFERENCES_CODE_DEFAULT); return code.equalsIgnoreCase(message); }

15-5 簡訊與定位服務-GPS間諜簡訊 步驟四:建立BroadcastReceiver類別接收簡訊-5 sendSpySms()方法 當確認暗號正確是一則間諜簡訊,我們就呼叫自訂sendSpySms()方法回覆行動裝置經緯度座標的簡訊,如下所示: private void sendSpySms(Context context, String phoneNum) { LocationManager manager; Location current; String best; manager = (LocationManager) context.getSystemService( Context.LOCATION_SERVICE); 上述程式碼取得定位服務的LoactionManager物件後,建立Criteria物件取得最佳的定位提供者,如下所示: Criteria criteria = new Criteria(); best = manager.getBestProvider(criteria, true); current = manager.getLastKnownLocation(best);

15-5 簡訊與定位服務-GPS間諜簡訊 步驟四:建立BroadcastReceiver類別接收簡訊-6 然後使用StringBuffer物件的append()方法新增徑度和緯度來建立簡訊內容的Uri字串,如下所示: if (current != null) { StringBuffer sb = new StringBuffer(); sb.append("geo:"); sb.append(current.getLatitude()); sb.append(","); sb.append(current.getLongitude()); String message = sb.toString(); SmsManager sms = SmsManager.getDefault(); sms.sendTextMessage(phoneNum, null, message, null, null); Log.i("Ch15_5", "送出簡訊:'" + message + "'至電話:" + phoneNum); } else Log.e("Ch15_5", "取得GPS位置失敗...");

15-5 簡訊與定位服務-GPS間諜簡訊 步驟五:在AndroidManifest.xml註冊廣播接收器和新增權限1 SMSReceiver廣播接收器需要在AndroidManifest.xml檔註冊,Telephony.SMS_RECEIVED是處理行動裝置收到簡訊的系統廣播,如下所示: <receiver android:name=".SMSReceiver" android:enabled="true" android:exported="true" > <intent-filter> <action android:name= "android.provider.Telephony.SMS_RECEIVED" /> </intent-filter> </receiver>

15-5 簡訊與定位服務-GPS間諜簡訊 步驟五:在AndroidManifest.xml註冊廣播接收器和新增權限2 <uses-permission android:name="android.permission.SEND_SMS" /> <uses-permission android:name="android.permission.RECEIVE_SMS" /> <uses-permission android:name= "android.permission.ACCESS_FINE_LOCATION"/>

End