<acronym id="s8ci2"><small id="s8ci2"></small></acronym>
<rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
<acronym id="s8ci2"></acronym>
<acronym id="s8ci2"><center id="s8ci2"></center></acronym>

您好,歡迎來電子發燒友網! ,新用戶?[免費注冊]

您的位置:電子發燒友網>電子百科>外接配件>藍牙適配器>

智能藍牙防丟器

2019年05月31日 11:02 lq 作者: 用戶評論(0

藍牙無線設備實現串行通信是通過無線射頻鏈接,利用藍牙模塊實現。藍牙模塊主要由無線收發單元、鏈路控制單元和鏈路管理及主機I/O這3個單元組成。就藍牙射頻模塊來說,為了在提高收發性能的同時減小器件的體積和成本,各公司都采用了自己特有的一些技術,從而使藍牙射頻模塊的結構都不盡相同。

但就其基本原理來說,藍牙射頻模塊一般由接收模塊、發送模塊和合成器這三個模塊組成。

藍牙傳輸的原理:

1 主從關系:

藍牙技術規定每一對設備之間進行藍牙通訊時,必須一個為主角色,另一為從角色,才能進行通信,通信時,必須由主端進行查找,發起配對,建鏈成功后,雙方即可收發數據。理論上,一個藍牙主端設備,可同時與7個藍牙從端設備進行通訊。一個具備藍牙通訊功能的設備, 可以在兩個角色間切換,平時工作在從模式,等待其它主設備來連接,需要時,轉換為主模式,向其它設備發起呼叫。一個藍牙設備以主模式發起呼叫時,需要知道對方的藍牙地址,配對密碼等信息,配對完成后,可直接發起呼叫。

2 呼叫過程:

藍牙主端設備發起呼叫,首先是查找,找出周圍處于可被查找的藍牙設備。主端設備找到從端藍牙設備后,與從端藍牙設備進行配對,此時需要輸入從端設備的PIN碼,也有設備不需要輸入PIN碼。配對完成后,從端藍牙設備會記錄主端設備的信任信息,此時主端即可向從端設備發起呼叫,已配對的設備在下次呼叫時,不再需要重新配對。已配對的設備,做為從端的藍牙耳機也可以發起建鏈請求,但做數據通訊的藍牙模塊一般不發起呼叫。鏈路建立成功后,主從兩端之間即可進行雙向的數據或語音通訊。在通信狀態下,主端和從端設備都可以發起斷鏈,斷開藍牙鏈路。

3 數據傳輸

藍牙數據傳輸應用中,一對一串口數據通訊是最常見的應用之一,藍牙設備在出廠前即提前設好兩個藍牙設備之間的配對信息,主端預存有從端設備的PIN碼、地址等,兩端設備加電即自動建鏈,透明串口傳輸,無需外圍電路干預。一對一應用中從端設備可以設為兩種類型,一是靜默狀態,即只能與指定的主端通信,不被別的藍牙設備查找;二是開發狀態,既可被指定主端查找,也可以被別的藍牙設備查找建鏈。

1 什么是智能藍牙防丟器

所謂智能藍牙(Smart Bluetooth)防丟器,是采用藍牙技術專門為智能手機設計的防丟器。其工作原理主要是通過距離變化來判斷物品是否還控制在你的安全范圍。主要適用于手機、錢包、鑰匙、行李等貴重物品的防丟,也可用于防止兒童或寵物的走失 。[請看正版請百度:beautifulzzzz(看樓主博客園官方博客,享高質量生活)嘻嘻?。。。?/p>

圖 1-1 藍牙防丟器應用領域

2 藍牙防丟器的主要構造

目前比較成熟的產品一般是采用藍牙4.0技術,具有低功耗、雙向防丟、自動報警等優點。雖然市場上該類產品種類繁多、層出不窮,但其核心構成一般包括:藍牙4.0芯片、藍牙芯片輔助電路、藍牙天線、蜂鳴器、開關、電源等。

圖 2-1 藍牙防丟器構成

3 藍牙模塊的選擇

由于這是第一個智能硬件DIY篇,樓主可不想一下子把大家給嚇倒了。所以這里我們先用一個相對簡單但常用的藍牙模塊HC-05/HC-06進行DIY 。如下圖該模塊把天線、濾波電路、Soc、晶振都集成在了一起,當我們用的時候只要關注1、2、12、13、24、26這幾個引腳就能實現比較完整的藍牙通信功能,這樣就為我們制作藍牙防丟器節省了很多挑選元件、設計電路、焊接制板的功夫,是不是超贊呀?

圖 3-1 藍牙模塊1

其實還有更贊的呢!由于考慮到很多讀者在硬件方面還都是新手,初次拿到郵票邊緣式引腳的模塊會焊接不好,于是樓主又找到了一款封裝更好的藍牙模塊(其實就是把上面的模塊加一個托,然后將VCCGNDTXDRXD四個關鍵的引腳引出)。當我們只是想把藍牙模塊作為標簽時,只要在VCC和GND之間給它加上相應的電壓就行了;當想用它進行無線數據傳輸時,這時TXD和RXD兩個引腳就起作用了。

圖 3-2 藍牙模塊2

4 開始制作一個簡易的藍牙防丟器

上面說了這么多了,那么我們的藍牙防丟器的設計方案到底是什么樣的呢?簡單起見,咱么僅僅實現通過距離變化來判斷物品是否還控制在你的安全范圍內的具有核心功能的防丟器,對于節能功能、雙向報警功能甚至是自拍功能咱們就先不考慮了。哈哈,可能說到這里大家還是對咱們要做的防丟器一點想法都沒有,其實通過上面的鋪墊樓主有信心大家可以在一分鐘之內知道怎么完成它!

圖 4-1 簡易藍牙防丟器

相信很多看完上面圖片同學會恍然大悟——不是嘛,只要將藍牙模塊接上相應的電源模塊就能夠做成一個簡單的可以發出藍牙信號的防丟器了!對的,由于我們沒有加入復雜的通信功能,所以我們僅僅把藍牙模塊通上電做成一個藍牙標簽就可以了。但是大家不要高興太早,雖然是第一個DIY,樓主也不會這么水吧~(沒發現上面圖片中手機屏幕里的應用還是一片空白嗎?哈哈)。

5 如何找到并學習要用到的API

上面制作藍牙防丟器的硬件部分讓大家覺得沒什么挑戰性,那么接下來的東西可就有一定難度了!記得樓主當時學安卓藍牙開發的時候費了好大力氣的。這里樓主強烈建議大家著手了解安卓某個功能的應用時最好去安卓開發者社區,但是隨著Google被屏Android Developer也不能被訪問了。雖然樓主在MIT網站上又找到了一個類似的網頁,但是訪問速度不是那么流暢,為了方便,LZ挑出了和本節相關的知識幫助大家理解和運用。

圖 5-1 Android Developer頁面

6 安卓藍牙編程小知識

安卓平臺支持藍牙協議棧,允許一臺設備和其他設備進行無線數據交換,當大家想使用藍牙時可以通過調用相應的API實現功能。這些API提供的主要功能有:

△ 掃描搜索其他藍牙設備(Scan for other Bluetooth devices)

△ 查詢本地藍牙適配器配對的藍牙設備(Query the local Bluetooth adapter for paired Bluetooth devices)

△ 建立RFCOMM通道(Establish RFCOMM channels)

△ 連接其他設備(Connect to other devices through service discovery)

△ 與其他設備進行數據交換(Transfer data to and from other devices)

△ 管理多組連接(Manage multiple connections)

當準備在應用程序中使用藍牙時,首先需要在manifest文件中包含BLUETOOTH和BLUETOOTH_ADMIN權限:

《uses-permission android:name=“android.permission.BLUETOOTH_ADMIN” /》

《uses-permission android:name=“android.permission.BLUETOOTH” /》

接著涉及藍牙的操作主要有:1、開啟藍牙 2、關閉藍牙 3、能被搜到 4、獲取配對設備 5、傳輸數據。由于本節只涉及到搜索周邊設備,所以配對并傳輸數據暫時不介紹。

7 安卓藍牙編程主要操作

要想通過編程操作藍牙設備,首先我們得了解一下有可供我們使用的相關類及其成員函數有哪些,如下圖:藍牙設備包括本地設備和遠程設備,本地設備對應的類為BluetoothAdapter,遠程設備對應的類為BluetoothDevice,兩者的成員函數基本相同,樓主將在接下來詳細講解。

圖 7-1 藍牙設備相關函數

7_1 打開本地藍牙設備

我們要做帶有藍牙的應用,首先要保證用戶的本地藍牙設備是打開的,否則什么都不管直接使用搜索、連接、通信等函數肯定會得到和預期不一樣的效果。但是有時候用戶為了節省電池電量會把藍牙關閉,那我們該怎么辦呢?

其實,遇到這種情況大家也不用擔心!請看下面的解決方案:其中第1行調用BluetoothAdapter的getDefaultAdapter()方法獲得本地藍牙設備,接著調用isEnabled()判斷本地藍牙設備是否被打開,如果被打開了就執行接下來的操作,否則可以發送Intent消息,請求打開本地藍牙設備,接著待用戶打開藍牙后再進入接下來的操作。

1 mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

2 if (!mBluetoothAdapter.isEnabled()) {

3 Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

4 startActivityForResult(enableIntent, REQUEST_ENABLE_BT);

5 } else {

6 nextOperation();

7 }

這時候有些同學可能要吐槽樓主了“你上面發送、請求、接著、然后說的挺輕巧,我怎么知道我發送完Intent消息后系統到底干了什么?用戶又如何打開藍牙的?應用程序又在哪里等待用戶完成打開藍牙事件,然后在哪里執行nextOperation()函數的?”哈哈,樓主知道大家動手心切啦!下面將給大家詳細介紹這一過程。

想解答大家的這些問題還得看上面代碼:其中第4行startActIvityForResult會啟動一個系統Preference Activity并將ACTION_REQUEST_ENABLE靜態常量作為其動作字符串,得到的Preference Activity如下圖:

該Activity提醒用戶是否授予權限打開本地藍牙設備,當用戶點擊“是”或者“否”的時候,該Activity將會關閉。我們可以使用onActivityResult處理程序中返回的結果代碼參數來確定是否操作成功。

正如上面介紹,當用戶點擊“是”授予藍牙權限請求后,確認請求的Activity會關閉,在下面的函數中將會收到此操作的消息,這樣我們就能很瀟灑的在第4行安全的進入接下來的操作了。

1 protected void onActivityResult(int requestCode,int resultCode,Intent data){

2 if(requestCode==ENABLE_BLUETOOTH){

3 if(resultCode==RESULT_OK){

4 nextOperation();

5 }

6 }

7 }

7_2 搜索周邊藍牙設備

上面解決了藍牙設備打開問題,接下來我們就要嘗試調用相關函數搜索周邊的藍牙設備,這樣我們就能知道我們制作的藍牙防丟器是否在我們周邊了(是不是很興奮呢?)。

這里我們要用到BluetoothAdapter的成員函數startDiscovery,該方法可以執行一個異步方式獲得周邊藍牙設備,因為是一個異步的方法所以我們不需要考慮線程被阻塞問題,整個過程大約需要12秒時間。這時我們可以注冊一個BroadcastReceiver 對象來接收查找到的藍牙設備信息,我們通過Filter來過濾ACTION_FOUND這個Intent動作以獲取每個遠程設備的詳細信息,過濾ACTION_DISCOVERY_FINISHED這個Intent動作以獲取整個藍牙搜索過程結束的信息。

1 // Register for broadcasts when a device is discovered

2 IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);

3 this.registerReceiver(mReceiver, filter);

4 // Register for broadcasts when discovery has finished

5 filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);

6 this.registerReceiver(mReceiver, filter);

上面講的可能有點專業,下面俺用一種簡單非專業的方式向大家介紹一下:每次我們想編程搜索周邊的藍牙設備時,只要簡單調用BluetoothAdapter的成員函數startDiscovery就可以了。所謂的異步方法大家可以這樣理解——start方法就好像一個總司令告訴情報搜查員去搜查情報,然后自己繼續做自己的事,情報員去收集各種情報;這里的filter就好像總司令告訴情報搜查員,我只要ACTION_FOUND和ACTION_DISCOVERY_FINISHED信息;那么這里的mReceiver就是總司令指定的情報搜查員了。

接下來就讓咱們神奇的情報搜查員登場!如下,相信大家一看就明白了,咱們的情報搜查員會一絲不茍地將總司令下達的任務執行。這樣當他收到FOUND動作信息時就用第6~8行的方法將每個發現的藍牙設備的名字和地址存儲進一個Vector中,這樣等自己完成任務時,就能告訴總司令任務完成,所有周邊藍牙情報都在xxx向量中(嘻嘻,多么讓領導喜歡的員工呀?。?。

1 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {

2 @Override

3 public void onReceive(Context context, Intent intent) {

4 String action = intent.getAction();

5 if (BluetoothDevice.ACTION_FOUND.equals(action)) {

6 BluetoothDevice device =

7 intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

8 mDevicesVector.add(device.getName() + “ ” + device.getAddress());

9 } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {

10 //。。。

11 }

12 }

13 };

7_3 獲取藍牙設備信號強度

到目前想必很多人已經能夠一氣呵成自己的簡單藍牙防丟器了,因為大家已經掌握了硬件部分的設計方法、擁有軟件藍牙開發打開和搜索周邊藍牙的編程技巧。但是如果心急的同學只用前面介紹的一點小知識的話,肯定設計的小東西很不盡人意(自己都不好意思給自己及格)。是不是出現了藍牙防丟器放到很遠很遠時應用程序才會報告東西已丟?如果是這樣請耐心地看完下面的介紹(也許能給你更多的啟發(⊙o⊙)哦)。

想必大家也想到了問題所在——距離沒控制好!如果我們能夠知道藍牙防丟器距離我們手機的距離那就好了,這樣我們就能設定一個范圍值,當它超出這個范圍時手機就發出丟失警告,這樣就不會出現防丟器要放很遠才能被手機察覺已丟失的問題了。要解決這個問題就要向大家介紹一下無線傳感器網絡中的RSSI了!

RSSI全名Received Signal Strength Indication,翻譯過來是接收的信號強度指示。在我們的經驗中一般離得越近信號越強,所以通過這個RSSI能夠大致估計接收點與發射點之間的距離。而在無線傳感器網絡中經常會設置多個固定的發射源(也是所謂的標簽),然后根據一定的算法來確定移動目標的空間位置信息。例如下圖左分別在A、B、C三點放置三個發射功率相同的信號源(標簽),這樣移動點D通過收集A、B、C三點的RSSI并估計距離rA、rB、rC,由于這個距離并不是完全精準,所以三個圓并不一定交于一點,大多數情況是下面交于一個公共區域的情況,而移動點D的當前位置很有可能在該區域。

圖 7-2 藍牙標簽定位

我們這里只要簡單地用到通過RSSI估計手機和防丟器之間的距離就行了,上面的定位技術相信大家也能舉一反三輕松搞定((^o^)/~其實沒那么簡單,哈哈)。那么在安卓編程時如何獲得RSSI呢?其實并不難,我們可以利用和獲取周邊藍牙設備的名稱和地址類似的方法獲取RSSI:

1 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

2 mDevicesVector.add(device.getName() + “ ” + device.getAddress());

3 short rssi = intent.getExtras().getShort(BluetoothDevice.EXTRA_RSSI);

4 mRSSIVector.add(rssi);

8 著手開發我們的APP

1) 使用Eclipse創建一個安卓項目,命名為first_test,并將Activity Name命名為UI_Main,Layout Name命名為ui_main(如圖8-1所示)。

圖8-1 新建安卓項目

2) 展開res文件夾下的layout文件夾,雙擊ui_main.xml文件,選擇xml編輯模式,并將其代碼改為:

1 《?xml version=“1.0” encoding=“utf-8”?》

2 《LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”

3 android:layout_width=“fill_parent”

4 android:layout_height=“fill_parent”

5 android:orientation=“vertical” 》

6

7 《SurfaceView

8 android:id=“@+id/surfaceView”

9 android:layout_width=“match_parent”

10 android:layout_height=“wrap_content”

11 android:layout_weight=“0.75” /》

12

13 《Button

14 android:id=“@+id/button_add”

15 android:layout_width=“match_parent”

16 android:layout_height=“wrap_content”

17 android:text=“添加藍牙防丟器” /》

18

19 《Button

20 android:id=“@+id/button_start”

21 android:layout_width=“match_parent”

22 android:layout_height=“wrap_content”

23 android:text=“開始防丟” /》

24

25 《/LinearLayout》

操作說明:這里修改的ui_main.xml為應用的主界面(如圖8-2所示)。該頁面采用LinearLayout布局模式,從上到下依次為用于動態顯示藍牙信號強弱的SurfaceView控件、用于添加防丟設備的按鈕和用于開始防丟控制的按鈕。

圖 8-2 ui_main.xml效果

3) 右擊layout,依次選擇New|Android XML File新建安卓XML文件。

4) 將新建的Android XML File命名為ui_list,點擊Finish按鈕。接著同第二步將新建的ui_list.xml修改為:

1 《?xml version=“1.0” encoding=“utf-8”?》

2 《LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”

3 android:layout_width=“fill_parent”

4 android:layout_height=“fill_parent”

5 android:orientation=“vertical” 》

6

7 《ListView

8 android:id=“@+id/listView1”

9 android:layout_width=“match_parent”

10 android:layout_height=“wrap_content”

11 android:layout_weight=“1” 》

12 《/ListView》

13

14 《Button

15 android:id=“@+id/button_search”

16 android:layout_width=“match_parent”

17 android:layout_height=“wrap_content”

18 android:text=“search” /》

19

20 《Button

21 android:id=“@+id/button_ok”

22 android:layout_width=“match_parent”

23 android:layout_height=“wrap_content”

24 android:text=“OK” /》

25

26 《/LinearLayout》

操作說明:這里新建的ui_list.xml為搜索并添加藍牙防丟器界面。該界面同樣采用LinearLayout布局模式,包含一個用于開始搜索的按鈕、一個用于列出搜索結果的list和一個用于確認返回的OK按鈕。

5) 右擊src文件夾下的包名,依次選擇New|Class命令(如圖8-3所示)

圖 8-3 新建類

6) 新建類文件命名為My_BTS,點擊Finish按鈕。

7) 將My_BTS.java文件修改為:

1 package com.example.first_test;

2

3 import java.util.Vector;

4

5 public class My_BTS {

6 public String mName;

7 public String mAddr;

8 public Vector《Short》 mRSSIVector;

9

10 public My_BTS() {

11 mName = new String();

12 mAddr = new String();

13 mRSSIVector = new Vector《Short》();

14 }

15

16 public My_BTS(String name, String addr) {

17 mName = name;

18 mAddr = addr;

19 mRSSIVector = new Vector《Short》();

20 }

21 }

操作說明:該類表示藍牙防丟器。其中mName和mAddr分別表示藍牙防丟器的名字和地址;mSSIVector用來存放一段時間檢測到該藍牙防丟器的RSSI值(之所以保留多組數據,是方便今后大家擴展)。

8) 采用同樣的方法新建一個Func_Draw.java文件,并將文件修改為:

1 package com.example.first_test;

2

3 import java.util.Vector;

4

5 import android.graphics.Canvas;

6 import android.graphics.Color;

7 import android.graphics.Paint;

8 import android.graphics.Paint.Style;

9 import android.view.SurfaceHolder;

10

11 public class Func_Draw {

12 private static Vector《Paint》 mPaint = new Vector《Paint》();

13 public static Integer times = 0;// 防丟搜索次數

14 public static float Bei = 200;// 繪制圖形時放大倍數

15

16 public static void initPaint() {

17 Paint paint0 = new Paint();

18 paint0.setAntiAlias(true);

19 paint0.setStyle(Style.STROKE);

20 paint0.setColor(Color.RED);

21 mPaint.add(paint0);

22 Paint paint1 = new Paint();

23 paint1.setAntiAlias(true);

24 paint1.setStyle(Style.STROKE);

25 paint1.setColor(Color.GREEN);

26 mPaint.add(paint1);

27 Paint paint2 = new Paint();

28 paint2.setAntiAlias(true);

29 paint2.setStyle(Style.STROKE);

30 paint2.setColor(Color.BLUE);

31 mPaint.add(paint2);

32 Paint paint3 = new Paint();

33 paint3.setAntiAlias(true);

34 paint3.setStyle(Style.STROKE);

35 paint3.setColor(Color.YELLOW);

36 mPaint.add(paint3);

37 Paint paint4 = new Paint();

38 paint4.setAntiAlias(true);

39 paint4.setStyle(Style.STROKE);

40 paint4.setColor(Color.WHITE);

41 mPaint.add(paint4);

42 Paint paint5 = new Paint();

43 paint5.setAntiAlias(true);

44 paint5.setStyle(Style.STROKE);

45 paint5.setColor(Color.LTGRAY);

46 mPaint.add(paint5);

47 Paint paint6 = new Paint();

48 paint6.setAntiAlias(true);

49 paint6.setStyle(Style.STROKE);

50 paint6.setColor(Color.CYAN);

51 mPaint.add(paint6);

52 }

53

54 public static void draw(SurfaceHolder mHolder) {

55 Canvas canvas = mHolder.lockCanvas();

56 canvas.drawRGB(0, 0, 0);

57 for (int i = 0; i 《 UI_Main.mBTSArrayList.size(); i++) {

58 boolean find = false;

59 short rssi = 0;

60 for (int j = 0; j 《 UI_Main.mFuncBT.mAddrVector.size(); j++) {

61 if (UI_Main.mBTSArrayList.get(i).mAddr

62 .equals(UI_Main.mFuncBT.mAddrVector.get(j))) {

63 find = true;

64 rssi = UI_Main.mFuncBT.mRSSIVector.get(j);

65 }

66 }

67 if (find == false) {

68 canvas.drawText(

69 times + “: NOT_FIND ”

70 + UI_Main.mBTSArrayList.get(i).mName, 5,

71 i * 10 + 12, mPaint.get(i));

72 } else {

73 float power = (float) ((Math.abs(rssi) - 59) / (10 * 2.0));

74 float dis = (float) Math.pow(10, power);

75

76 canvas.drawText(

77 times + “: FIND ” + UI_Main.mBTSArrayList.get(i).mName

78 + “ dis: ” + new Float(dis).toString()

79 + “ rssi: ” + rssi, 5, i * 10 + 12,

80 mPaint.get(i));

81 canvas.drawCircle(canvas.getWidth() / 2,

82 canvas.getHeight() / 2, Bei * dis, mPaint.get(i));//畫圓圈

83 }

84 }

85 times++;

86 mHolder.unlockCanvasAndPost(canvas);// 更新屏幕顯示內容

87 UI_Main.mFuncBT.mRSSIVector.clear();

88 UI_Main.mFuncBT.mNameVector.clear();

89 UI_Main.mFuncBT.mAddrVector.clear();

90 }

91 }

操作說明:該類提供在SurfaceView上繪制功能。其中靜態方法initPaint對畫筆進行初始化,draw函數負責繪制。

draw函數的核心在于canvas繪圖,canvas繪圖的過程和我們在白紙上繪繪圖的過程很像,如:

l 第55行鎖定canvas相當于得到一張紙;

l 第56行用RGB為0的顏色來刷新canvas相當于用橡皮擦把紙上原來的東西擦掉;

l 第68和76行drawText相當于在紙的相應位置寫文字;

l 第81行drawCircle相當于在紙的相應位置繪制一個指定的圓;

l 第86行的nlockCanvasAndPost相當于你把繪制好的作品拿出來展示給別人看;

正是因為canvas的加鎖和解鎖這一機制,才保證了繪制過程中屏幕正確地顯示。

接著再來理解這里draw函數的功能:mBTSArrayList是一個My_BTS類型的數組,保存我們想要防丟的藍牙防丟器設備的名稱、地址等信息;mFuncBT是一個可以實時搜索周邊藍牙設備的一個對象,其靜態變量mNameVector、mAddrVector、mRSSIVector保存著實時搜索結果;這樣核心部分的功能便是通過兩層循環遍歷待防丟設備是否在本次搜索中,如果不在則顯示“NOT_FIND”,如果在則由RSSI計算距離。(效果如圖8-4)

圖 8-4 找到藍牙設備圖

9) 新建一個Func_BT.java文件,并修改為:

1 package com.example.first_test;

2

3 import java.util.Vector;

4

5 import android.app.Activity;

6 import android.bluetooth.BluetoothAdapter;

7 import android.bluetooth.BluetoothDevice;

8 import android.content.BroadcastReceiver;

9 import android.content.Context;

10 import android.content.Intent;

11 import android.content.IntentFilter;

12 import android.os.Bundle;

13 import android.os.Handler;

14 import android.os.Message;

15

16 public class Func_BT {

17 private BluetoothAdapter mBtAdapter;// 藍牙適配器

18 private static final int ENABLE_BLUETOOTH = 1;

19 // 分別用于存儲設備名地址名稱和RSSI的向量

20 public Vector《String》 mNameVector;

21 public Vector《String》 mAddrVector;

22 public Vector《Short》 mRSSIVector;

23

24 private Handler myHandler;

25 private Activity activity;

26

27 public Func_BT(Activity activity, Handler myHandler) {

28 this.myHandler = myHandler;

29 this.activity = activity;

30

31 mNameVector = new Vector《String》();// 向量

32 mAddrVector = new Vector《String》();

33 mRSSIVector = new Vector《Short》();

34

35 IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);

36 activity.registerReceiver(mReceiver, filter);

37 filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);

38 activity.registerReceiver(mReceiver, filter);

39 activity.registerReceiver(mReceiver, filter);

40

41 mBtAdapter = BluetoothAdapter.getDefaultAdapter();

42 }

43

44 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {

45 @Override

46 public void onReceive(Context context, Intent intent) {

47 String action = intent.getAction();

48 if (BluetoothDevice.ACTION_FOUND.equals(action)) {

49 BluetoothDevice device = intent

50 .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

51 short rssi = intent.getExtras().getShort(

52 BluetoothDevice.EXTRA_RSSI);

53 mNameVector.add(device.getName());

54 mAddrVector.add(device.getAddress());

55 mRSSIVector.add(rssi);

56 } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED

57 .equals(action)) {

58 /*if (mNameVector.size() != 0) {

59 Message msg = new Message();// 消息

60 msg.what = 0x01;// 消息類別

61 myHandler.sendMessage(msg);

62 }*/

63 }

64 }

65 };

66

67 public void doDiscovery() {

68 if (mBtAdapter.isDiscovering()) {

69 mBtAdapter.cancelDiscovery();

70 }

71 mBtAdapter.startDiscovery();

72 new TimeLimitThread().start();

73 }

74

75 public void openBT() {

76 // 如果沒有打開則打開

77 if (!mBtAdapter.isEnabled()) {

78 Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

79 activity.startActivityForResult(intent, ENABLE_BLUETOOTH);

80 } else {

81 doDiscovery();

82 }

83 }

84

85 protected void onActivityResult(int requestCode, int resultCode, Intent data){

86 if (requestCode == ENABLE_BLUETOOTH) {

87 if (resultCode == Activity.RESULT_OK) {

88 doDiscovery();

89 }

90 }

91 }

92

93 public void setHandler(Handler myHandler) {

94 this.myHandler = myHandler;

95 }

96

97 public void setFunc_BT(Activity activity, Handler myHandler) {

98 this.myHandler = myHandler;

99 this.activity = activity;

100 }

101

102 class TimeLimitThread extends Thread{

103 public void run() {

104 try {

105 sleep(3000);

106 if (mBtAdapter.isDiscovering()) {

107 mBtAdapter.cancelDiscovery();

108 }

109 Message msg = new Message();// 消息

110 msg.what = 0x01;// 消息類別

111 myHandler.sendMessage(msg);

112 } catch (InterruptedException e) {

113 e.printStackTrace();

114 }

115 }

116 }

117 }

操作說明:該類用來實時搜索周邊藍牙設備,并把搜索結果保存在其靜態成員變量mNameVector、mAddrVector、mRSSIVector中。此外這里還使用Handler用于向調用其搜索方法的Activity發送本次搜索完畢的消息。具體介紹如下:

l 第27到42行為構造函數,主要負責成員變量初始化、注冊filter、獲取本地藍牙設備;

l 第44到65行為BroadcastReceiver,主要負責異步搜索周邊藍牙設備的廣播的接收;

l 第67到73行為開始搜索周邊藍牙設備函數;

l 第75到83行為帶有檢查本地藍牙是否開啟并能夠發出開啟請求的搜索周邊藍牙設備函數;

l 第85到91行為接收用戶是否授權打開藍牙設備的Activity的結果函數;

l 第102到116行是一個線程類主要用于限定搜索周邊藍牙設備的最長時間(默認為12s左右);

正是因為加了獨立用于限定搜索時長的線程,才讓搜索過程的時間長短便于我們控制,但是sleep的時間也不要設置的過小,否則會出現一個藍牙設備也搜索不到的情況。(建議最好參照第七部分——“安卓藍牙編程主要操作”來理解本部分的代碼)

10) 修改UI_Main.java為:

1 package com.example.first_test;

2

3 import java.util.ArrayList;

4 import android.app.Activity;

5 import android.content.Intent;

6 import android.os.Bundle;

7 import android.os.Handler;

8 import android.os.Message;

9 import android.view.SurfaceHolder;

10 import android.view.SurfaceHolder.Callback;

11 import android.view.SurfaceView;

12 import android.view.View;

13 import android.view.View.OnClickListener;

14 import android.widget.Button;

15

16 public class UI_Main extends Activity implements Callback {

17

18 public Func_Draw mFuncDraw;

19 public SurfaceHolder mHolder;

20 public static Func_BT mFuncBT;

21 // 防丟設備

22 public static ArrayList《My_BTS》 mBTSArrayList = new ArrayList《My_BTS》();

23

24 // 消息句柄(線程里無法進行界面更新,

25 // 所以要把消息從線程里發送出來在消息句柄里進行處理)

26 public Handler myHandler = new Handler() {

27 @Override

28 public void handleMessage(Message msg) {

29 if (msg.what == 0x01) {

30 Func_Draw.draw(mHolder);

31 }

32 mFuncBT.doDiscovery();

33 }

34 };

35

36 @Override

37 protected void onCreate(Bundle savedInstanceState) {

38 super.onCreate(savedInstanceState);

39 setContentView(R.layout.ui_main);

40

41 Func_Draw.initPaint();

42

43 SurfaceView mSurface = (SurfaceView) findViewById(R.id.surfaceView);

44 mHolder = mSurface.getHolder();

45 mHolder.addCallback(this);

46

47 mFuncBT = new Func_BT(this, myHandler);

48

49 Button mButton1 = (Button) findViewById(R.id.button_start);

50 mButton1.setOnClickListener(new OnClickListener() {

51 @Override

52 public void onClick(View v) {

53 Func_Draw.times = 0;

54 mFuncBT.openBT();

55 }

56 });

57

58 Button mButton2 = (Button) findViewById(R.id.button_add);

59 mButton2.setOnClickListener(new OnClickListener() {

60 @Override

61 public void onClick(View v) {

62 startActivity(new Intent(UI_Main.this, UI_List.class));

63 }

64 });

65 }

66

67 @Override

68 public void surfaceCreated(SurfaceHolder holder) {

69 // TODO Auto-generated method stub

70

71 }

72

73 @Override

74 public void surfaceChanged(SurfaceHolder holder, int format, int width,

75 int height) {

76 // TODO Auto-generated method stub

77

78 }

79

80 @Override

81 public void surfaceDestroyed(SurfaceHolder holder) {

82 // TODO Auto-generated method stub

83

84 }

85 }

操作說明:上面第2步時我們修改了ui_main.xml并做出應用程序主頁面的效果,而該類則是其對應的邏輯實現。

nn 首先看第37到65行的onCreate函數:

l 第39行設置要顯示的頁面為ui_main.xml所展示的效果;

l 第41行調用Func_Draw的靜態initPaint()方法對畫筆進行初始化;

l 第43到45行負責獲取并設置SurfaceView;

l 第47行實例化一個Func_BT;

l 第49到56行是給開始防丟按鈕綁定一個監聽器,一旦點擊該按鈕則執行onClick內代碼;

l 第58到65行是給添加藍牙防丟器綁定一個監聽器,一旦點擊則啟動另一個Activity;

nn 第24到34行實例化一個Handler用于接收Func_BT一次搜索結束時發回結束的消息。在這里一旦收到本次周邊藍牙設備搜索結束的消息就調用Func_Draw.draw(mHolder)進行繪制,然后繼續調用mFuncBT.doDiscovery()實現周期性搜索/防丟。

nn 第67到84行是自動生成的,暫且不用管(也不要刪除?。?。

11) 新建一個UI_List.java文件,并修改代碼為:

1 package com.example.first_test;

2

3 import java.util.ArrayList;

4 import android.annotation.SuppressLint;

5 import android.app.Activity;

6 import android.app.ProgressDialog;

7 import android.content.Intent;

8 import android.os.Bundle;

9 import android.os.Handler;

10 import android.os.Message;

11 import android.util.Log;

12 import android.view.View;

13 import android.view.View.OnClickListener;

14 import android.widget.ArrayAdapter;

15 import android.widget.Button;

16 import android.widget.ListView;

17

18 public class UI_List extends Activity {

19

20 private ArrayList《String》 Items;

21 private ListView myListView;

22 private ArrayAdapter《String》 aa;

23 private boolean getDIV;

24

25 @SuppressLint(“InlinedApi”)

26 protected void onCreate(Bundle savedInstanceState) {

27 super.onCreate(savedInstanceState);

28 setContentView(R.layout.ui_list);

29

30 UI_Main.mFuncBT.setFunc_BT(this, myHandler);

31

32 // 獲取listview并設置為多選

33 myListView = (ListView) findViewById(R.id.listView1);

34 myListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

35 myListView.setTextFilterEnabled(true);

36 // 設置listview數組并綁定

37 Items = new ArrayList《String》();

38 aa = new ArrayAdapter《String》(this,

39 android.R.layout.simple_list_item_checked, Items);

40 myListView.setAdapter(aa);

41

42 // 獲取OK按鈕,并遍歷選擇的設備,返回主Activity

43 Button myButton1 = (Button) findViewById(R.id.button_ok);

44 myButton1.setOnClickListener(new OnClickListener() {

45 @Override

46 public void onClick(View v) {

47 int num = 0;

48 for (int i = 0; i 《 myListView.getCount(); i++) {

49 if (myListView.isItemChecked(i)) {

50 String item = myListView.getItemAtPosition(i)

51 .toString();

52 String name = item.substring(0, item.indexOf(“ ”));

53 String addr = item.substring(item.indexOf(“ ”) + 1);

54 Log.i(“UI_LIST”, name + “ ” + addr);

55 UI_Main.mBTSArrayList

56 .add(num++, new My_BTS(name, addr));

57 }

58 }

59 Intent mIntent = new Intent(UI_List.this, UI_Main.class);

60 mIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

61 startActivity(mIntent);

62 }

63 });

64 // 獲取Search按鈕,設置監聽事件

65 Button myButton2 = (Button) findViewById(R.id.button_search);

66 myButton2.setOnClickListener(new OnClickListener() {

67 @Override

68 public void onClick(View v) {

69 getDIV = false;

70 UI_Main.mFuncBT.openBT();

71 final ProgressDialog dialog = ProgressDialog.show(UI_List.this,

72 “搜索藍牙設備”, “稍等一下~”, true);

73 new Thread(new Runnable() {

74 public void run() {

75 while (getDIV == false);

76 dialog.dismiss();

77 }

78 }).start();

79 }

80 });

81 }

82

83 // 消息句柄(線程里無法進行界面更新,

84 // 所以要把消息從線程里發送出來在消息句柄里進行處理)

85 public Handler myHandler = new Handler() {

86 @Override

87 public void handleMessage(Message msg) {

88 if (msg.what == 0x01) {

89 Items.clear();

90 for (int i = 0; i 《 UI_Main.mFuncBT.mNameVector.size(); i++) {

91 Items.add(i, UI_Main.mFuncBT.mNameVector.get(i) + ‘ ’

92 + UI_Main.mFuncBT.mAddrVector.get(i));

93 aa.notifyDataSetChanged();// 通知數據變化

94 }

95 getDIV = true;

96 UI_Main.mFuncBT.mRSSIVector.clear();

97 UI_Main.mFuncBT.mNameVector.clear();

98 UI_Main.mFuncBT.mAddrVector.clear();

99 }

100 }

101 };

102 }

操作說明:這個類和ui_list.xml也是配套的。因此:

nn 在onCreate中:

l 第28行設置要顯示的頁面為ui_list.xml所展示的效果;

l 第30行負責將周邊藍牙搜索對象的Handler設置為本Activity內的Handler;

l 第32到40行是list相關;

l 第42到80行是兩個按鈕點擊事件監聽相關;

nn 第85到101行的Handler則同UI_Main.java中的Handler類似負責接收周期性藍牙搜索結束消息。在這里當接到藍牙搜索結束的消息后是將搜索到的設備信息放入list中待用戶選擇。(沒有再次調用藍牙搜索)

nn 此外兩個按鈕監聽中執行部分要特別說明下:

l 當點擊OK按鈕時程序將用戶在list中選擇的設備的信息存放在UI_Main.mBTSArrayList中,然后結束當前Activity并啟動UI_Main所對應的Activity。

l 當點擊search按鈕時會啟動周邊藍牙設備搜索并打開一個等待對話框,其中的Thread負責等待直到搜索完畢。

12) 最后(如圖8-5)找到AndroidMainFest.xml文件修改為:

圖 8-5 AnDroidManifest.xml文件

1 《?xml version=“1.0” encoding=“utf-8”?》

2 《manifest xmlns:android=“http://schemas.android.com/apk/res/android”

3 package=“com.example.first_test”

4 android:versionCode=“1”

5 android:versionName=“1.0” 》

6

7 《uses-sdk

8 android:minSdkVersion=“8”

9 android:targetSdkVersion=“19” /》

10

11 《uses-permission android:name=“android.permission.BLUETOOTH_ADMIN” /》

12 《uses-permission android:name=“android.permission.BLUETOOTH” /》

13

14 《application

15 android:allowBackup=“true”

16 android:icon=“@drawable/ic_launcher”

17 android:label=“@string/app_name”

18 android:theme=“@style/AppTheme” 》

19 《activity

20 android:name=“.UI_Main”

21 android:label=“@string/app_name” 》

22 《intent-filter》

23 《action android:name=“android.intent.action.MAIN” /》

24 《category android:name=“android.intent.category.LAUNCHER” /》

25 《/intent-filter》

26 《/activity》

27

28 《activity

29 android:name=“.UI_List”

30 android:label=“@string/app_name” 》

31 《intent-filter》

32 《action android:name=“android.intent.action.UI_List” /》

33 《category android:name=“android.intent.category.DEFAULT” /》

34 《/intent-filter》

35 《/activity》

36

37 《/application》

38

39

40 《/manifest》

操作說明:主要是在11、12行添加藍牙權限以及在28到35行添加一個activity。

非常好我支持^.^

(2) 100%

不好我反對

(0) 0%

( 發表人:李倩 )

      發表評論

      用戶評論
      評價:好評中評差評

      發表評論,獲取積分! 請遵守相關規定!

      ?
      亚洲欧美日韩精品久久_久久精品AⅤ无码中文_日本中文字幕有码在线播放_亚洲视频高清不卡在线观看
      <acronym id="s8ci2"><small id="s8ci2"></small></acronym>
      <rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
      <acronym id="s8ci2"></acronym>
      <acronym id="s8ci2"><center id="s8ci2"></center></acronym>