Bluetooth结构
1、JAVA层
frameworks/base/core/java/android/bluetooth/
包含了bluetooth的JAVA类。
2、JNI层
frameworks/base/core/jni/android_bluetooth_开头的文件
定义了bluez通过JNI到上层的接口。
frameworks/base/core/jni/android_server_bluetoothservice.cpp
调用硬件适配层的接口system/bluetooth/bluedroid/bluetooth.c
3、bluez库
external/bluez/
这是bluez用户空间的库,开源的bluetooth代码,包括很多协议,生成libbluetooth.so。
4、硬件适配层
system/bluetooth/bluedroid/bluetooth.c
包含了对硬件操作的接口
system/bluetooth/data/*
一些配置文件,复制到/etc/bluetooth/。
还有其他一些测试代码和工具。
一、简略介绍Bluetooth开发使用到的类
1、BluetoothAdapter,蓝牙适配器,可判断蓝牙设备是否可用等功能。
常用方法列举如下:
cancelDiscovery() ,取消搜索过程,在进行蓝牙设备搜索时,如果调用该方法会停止搜索。(搜索过程会持续12秒)
disable()关闭蓝牙,也就是我们常说的禁用蓝牙。
enable()打开蓝牙,这个方法打开蓝牙但不会弹出提示,正常流程操作下,我们会让系统提示用户是否打开蓝牙设备。如下两行代码可轻松搞定。
Intent enabler=new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enabler,reCode);//同startActivity(enabler);(在主Activity启动一个二级Activity,reCode一般等于3,一定记得要在AndroidManifest.xml里面添加蓝牙权限)
getAddress()获取本地蓝牙地址
getDefaultAdapter()获取默认BluetoothAdapter,实际上,也只有这一种方法获取BluetoothAdapter
getName()获取本地蓝牙名称
getRemoteDevice(String address)根据蓝牙地址获取远程蓝牙设备
getState()获取本地蓝牙适配器当前状态(感觉可能调试的时候更需要)
isDiscovering()判断当前是否正在查找设备,是返回true
isEnabled()判断蓝牙是否打开,已打开返回true,否则,返回false
listenUsingRfcommWithServiceRecord(String name,UUID uuid)根据名称,UUID创建并返回
BluetoothServerSocket,这是创建BluetoothSocket服务器端的第一步
startDiscovery()开始搜索,这是搜索的第一步
2.BluetoothDevice看名字就知道,这个类描述了一个蓝牙设备
createRfcommSocketToServiceRecord(UUIDuuid)根据UUID创建并返回一个BluetoothSocket
这个方法也是我们获取BluetoothDevice的目的——创建BluetoothSocket
这个类其他的方法,如getAddress(),getName(),同BluetoothAdapter
这个类有几个隐藏方法,涉及到蓝牙的自动配对,setPin,createBond,cancelPairingUserInput,等方法(需要通过java的反射,调用这几个隐藏方法)
3.BluetoothServerSocket如果去除了Bluetooth相信大家一定再熟悉不过了,既然是Socket,方法就应该都差不多,
这个类一种只有三个方法
两个重载的accept(),accept(inttimeout)两者的区别在于后面的方法指定了过时时间,需要注意的是,执行这两个方法的时候,直到接收到了客户端的请求(或是过期之后),都会阻塞线程,应该放在新线程里运行!
还有一点需要注意的是,这两个方法都返回一个BluetoothSocket,最后的连接也是服务器端与客户端的两个BluetoothSocket的连接
close()关闭!
4.BluetoothSocket,跟BluetoothServerSocket相对,是客户端
一共5个方法,不出意外,都会用到
close(),关闭
connect()连接
getInptuStream()获取输入流
getOutputStream()获取输出流
getRemoteDevice()获取远程设备,这里指的是获取bluetoothSocket指定连接的那个远程蓝牙设备
二、蓝牙设备的发现、查找。
1.基于安全性考虑,设置开启可被搜索后,Android系统会默认给出120秒的时间,其他设备能在这120秒内搜索到它。Intent enable = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
startActivityForResult(enalbe,REQUEST_DISCOVERABLE);
2.搜索蓝牙设备
BluetoothAdapter _bluetooth = BluetoothAdapter.getDefaultAdapter();
_bluetooth.startDiscovery();
3.关闭蓝牙设备
BluetoothAdapter _bluetooth = BluetoothAdapter.getDefaultAdapter();
_bluetooth.disable();
4.创建蓝牙客户端
BluetoothSocket socket = device.createRfcommSocketToServiceRecord(UUID.fromString(UUID号));
socket.connect();
4.创建蓝牙服务端
BluetoothServerSocket _serverSocket = _bluetooth.listenUsingRfcommWithServiceRecord(服务端名称,UUID.fromeString(UUID号));
BluetoothSocket socket = _serverSocket.accept();
InputStream inputStream = socket.getInputStream();
三、相关代码实现
注:tcp_ip模块需要在系统setting模块中,完成蓝牙的配对,只有配对成功的,才能进行socket通信(具体如何配对和如何自动配对,将在bluetoot3或者4中进行讲解)
AndridManifest.xml
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
<
manifest
xmlns:android
=
"http://schemas.android.com/apk/res/android"
package
=
"com.example.thecaseforbluetooth"
android:versionCode
=
"1"
android:versionName
=
"1.0"
>
<
uses-sdk
android:minSdkVersion
=
"8"
android:targetSdkVersion
=
"15"
/>
<
uses-permission
android:name
=
"android.permission.BLUETOOTH_ADMIN"
/>
<
uses-permission
android:name
=
"android.permission.BLUETOOTH"
/>
<
application
android:icon
=
"@drawable/ic_launcher"
android:label
=
"@string/app_name"
android:theme
=
"@style/AppTheme"
>
<
activity
android:name
=
".BluetoothActivity"
android:label
=
"@string/title_activity_bluetooth"
>
<
intent-filter
>
<
action
android:name
=
"android.intent.action.MAIN"
/>
<
category
android:name
=
"android.intent.category.LAUNCHER"
/>
</
intent-filter
>
</
activity
>
</
application
>
</
manifest
>
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
<
LinearLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
xmlns:tools
=
"http://schemas.android.com/tools"
android:id
=
"@+id/LinearLayout1"
android:layout_width
=
"match_parent"
android:layout_height
=
"match_parent"
android:orientation
=
"vertical"
>
<
Button
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:id
=
"@+id/btnSearch"
android:text
=
"查找设备"
/>
<
Button
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:id
=
"@+id/btnExit"
android:text
=
"退出应用"
/>
<
Button
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:id
=
"@+id/btnDis"
android:text
=
"设置可被发现"
/>
<
Button
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:id
=
"@+id/btnserver"
android:text
=
"启动服务端"
/>
<
ToggleButton
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:id
=
"@+id/tbtnSwitch"
android:text
=
"开/关 蓝牙设备"
/>
<
ListView
android:layout_width
=
"fill_parent"
android:layout_height
=
"wrap_content"
android:id
=
"@+id/lvDevices"
/>
</
LinearLayout
>
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
|
package
com.example.thecaseforbluetooth;
import
java.util.ArrayList;
import
java.util.Set;
import
android.app.Activity;
import
android.bluetooth.BluetoothAdapter;
import
android.bluetooth.BluetoothDevice;
import
android.content.BroadcastReceiver;
import
android.content.Context;
import
android.content.Intent;
import
android.content.IntentFilter;
import
android.os.Bundle;
import
android.view.Menu;
import
android.view.View;
import
android.view.View.OnClickListener;
import
android.widget.AdapterView;
import
android.widget.AdapterView.OnItemClickListener;
import
android.widget.ArrayAdapter;
import
android.widget.Button;
import
android.widget.ListView;
import
android.widget.Toast;
import
android.widget.ToggleButton;
public
class
BluetoothActivity
extends
Activity {
public
Button searchBtn;
//搜索蓝牙设备
public
Button exitBtn;
//退出应用
public
Button discoverBtn;
//设置可被发现
public
ToggleButton openBtn;
//开关蓝牙设备
public
Button serverbtn;
public
ListView listView;
//蓝牙设备清单
public
ArrayAdapter<String> adapter;
public
ArrayList<String> list =
new
ArrayList<String>();
private
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Set<BluetoothDevice> bondDevices ;
public
Context context ;
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
searchBtn = (Button)findViewById(R.id.btnSearch);
exitBtn = (Button)findViewById(R.id.btnExit);
discoverBtn = (Button)findViewById(R.id.btnDis);
openBtn = (ToggleButton)findViewById(R.id.tbtnSwitch);
serverbtn = (Button)findViewById(R.id.btnserver);
listView = (ListView)findViewById(R.id.lvDevices);
context = getApplicationContext();
adapter =
new
ArrayAdapter<String>(
this
, android.R.layout.simple_list_item_1,list);
listView.setAdapter(adapter);
openBtn.setChecked(
false
);
//注册广播接收信号
IntentFilter intent =
new
IntentFilter();
intent.addAction(BluetoothDevice.ACTION_FOUND);
// 用BroadcastReceiver来取得搜索结果
intent.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
//每当扫描模式变化的时候,应用程序可以为通过ACTION_SCAN_MODE_CHANGED值来监听全局的消息通知。比如,当设备停止被搜寻以后,该消息可以被系统通知給应用程序。
intent.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
//每当蓝牙模块被打开或者关闭,应用程序可以为通过ACTION_STATE_CHANGED值来监听全局的消息通知。
registerReceiver(searchReceiver, intent);
//显示已配对设备以及搜索未配对设备
searchBtn.setOnClickListener(
new
OnClickListener() {
@Override
public
void
onClick(View v) {
// TODO Auto-generated method stub
if
(bluetoothAdapter.isDiscovering()){
bluetoothAdapter.cancelDiscovery();
}
list.clear();
bondDevices = bluetoothAdapter.getBondedDevices();
for
(BluetoothDevice device : bondDevices) {
String str =
" 已配对完成 "
+ device.getName() +
" "
+ device.getAddress();
list.add(str);
adapter.notifyDataSetChanged();
}
bluetoothAdapter.startDiscovery();
}
});
//退出应用
exitBtn.setOnClickListener(
new
OnClickListener() {
@Override
public
void
onClick(View v) {
// TODO Auto-generated method stub
BluetoothActivity.
this
.finish();
}
});
//设置蓝牙设备可发现
discoverBtn.setOnClickListener(
new
OnClickListener() {
@Override
public
void
onClick(View v) {
// TODO Auto-generated method stub
Intent discoverIntent =
new
Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,
300
);
startActivity(discoverIntent);
}
});
//开关蓝牙设备
openBtn.setOnClickListener(
new
OnClickListener() {
@Override
public
void
onClick(View v) {
// TODO Auto-generated method stub
if
(openBtn.isChecked() ==
true
){
bluetoothAdapter.disable();
}
else
if
(openBtn.isChecked() ==
false
){
bluetoothAdapter.enable();
}
}
});
//作为服务端开启
serverbtn.setOnClickListener(
new
OnClickListener() {
@Override
public
void
onClick(View v) {
// TODO Auto-generated method stub
ServerThread serverThread =
new
ServerThread(bluetoothAdapter, context);
Toast.makeText(context,
"server 端启动"
,
5000
).show();
serverThread.start();
}
});
listView.setOnItemClickListener(
new
ItemClickListener());
}
@Override
public
void
onStart() {
super
.onStart();
// If BT is not on, request that it be enabled.
if
(bluetoothAdapter ==
null
){
Toast.makeText(context,
"蓝牙设备不可用"
,
5000
).show();
}
if
(!bluetoothAdapter.isEnabled()) {
Intent enableIntent =
new
Intent(
BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent,
3
);
}
}
@Override
public
boolean
onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return
true
;
}
private
final
BroadcastReceiver searchReceiver =
new
BroadcastReceiver() {
@Override
public
void
onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String action = intent.getAction();
BluetoothDevice device =
null
;
if
(BluetoothDevice.ACTION_FOUND.equals(action)){
device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if
(device.getBondState() == BluetoothDevice.BOND_NONE) {
Toast.makeText(context, device.getName()+
""
,
5000
).show();
String str =
" 未配对完成 "
+ device.getName() +
" "
+ device.getAddress();
if
(list.indexOf(str) == -
1
)
// 防止重复添加
list.add(str);
}
adapter.notifyDataSetChanged();
}
}
};
public
class
ItemClickListener
implements
OnItemClickListener {
@Override
public
void
onItemClick(AdapterView<?> arg0, View arg1,
int
arg2,
long
arg3) {
// TODO Auto-generated method stub
if
(bluetoothAdapter.isDiscovering())
bluetoothAdapter.cancelDiscovery();
String str = list.get(arg2);
String address = str.substring(str.length() -
17
);
BluetoothDevice btDev = bluetoothAdapter.getRemoteDevice(address);
ClientThread clientThread =
new
ClientThread(btDev, context);
clientThread.start();
}}
}
|
|
1
2
3
4
5
6
7
8
|
package
com.example.thecaseforbluetooth;
public
interface
Bluetoothprotocol {
public
static
final
String PROTOCOL_SCHEME_L2CAP =
"btl2cap"
;
public
static
final
String PROTOCOL_SCHEME_RFCOMM =
"btspp"
;
public
static
final
String PROTOCOL_SCHEME_BT_OBEX =
"btgoep"
;
public
static
final
String PROTOCOL_SCHEME_TCP_OBEX =
"tcpobex"
;
}
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
package
com.example.thecaseforbluetooth;
import
java.io.IOException;
import
java.io.InputStream;
import
java.io.OutputStream;
import
java.util.UUID;
import
android.bluetooth.BluetoothAdapter;
import
android.bluetooth.BluetoothServerSocket;
import
android.bluetooth.BluetoothSocket;
import
android.content.Context;
import
android.os.Message;
import
android.util.Log;
import
android.widget.Toast;
public
class
ServerThread
extends
Thread {
public
BluetoothServerSocket mserverSocket;
public
BluetoothAdapter bluetoothAdapter;
public
BluetoothSocket socket;
public
Context context;
public
ServerThread(BluetoothAdapter bluetoothAdapter,Context context) {
this
.bluetoothAdapter = bluetoothAdapter;
this
.context = context;
}
public
void
run() {
try
{
/* 创建一个蓝牙服务器
* 参数分别:服务器名称、UUID */
mserverSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord(Bluetoothprotocol.PROTOCOL_SCHEME_RFCOMM,
UUID.fromString(
"00001101-0000-1000-8000-00805F9B34FB"
));
// /* 接受客户端的连接请求 */
socket = mserverSocket.accept();
//下面代码作者偷懒,读写另外起一个线程最好
//接收数据
byte
[] buffer =
new
byte
[
1024
];
int
bytes;
InputStream mmInStream =
null
;
try
{
mmInStream = socket.getInputStream();
}
catch
(IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println(
"zhoulc server"
);
while
(
true
){
if
( (bytes = mmInStream.read(buffer)) >
0
)
{
byte
[] buf_data =
new
byte
[bytes];
for
(
int
i=
0
; i<bytes; i++)
{
buf_data[i] = buffer[i];
}
String s =
new
String(buf_data);
System.out.println(s+
"zhoulc server is in"
);
}
}
}
catch
(Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
package
com.example.thecaseforbluetooth;
import
java.io.IOException;
import
java.io.OutputStream;
import
java.util.UUID;
import
android.bluetooth.BluetoothDevice;
import
android.bluetooth.BluetoothSocket;
import
android.content.Context;
import
android.widget.Toast;
public
class
ClientThread
extends
Thread {
public
BluetoothSocket socket;
public
BluetoothDevice device;
public
Context context;
public
ClientThread(BluetoothDevice device,Context context){
this
.device = device;
this
.context = context;
}
public
void
run() {
try
{
//创建一个Socket连接:只需要服务器在注册时的UUID号
socket = device.createRfcommSocketToServiceRecord(UUID.fromString(
"00001101-0000-1000-8000-00805F9B34FB"
));
//连接
socket.connect();
//下面代码作者偷懒,读写另外起一个线程最好
//发送数据
if
(socket ==
null
)
{
Toast.makeText(context,
"链接失败"
,
5000
).show();
return
;
}
System.out.println(
"zhoulc client"
);
while
(
true
){
try
{
System.out.println(
"zhoulc client is in"
);
String msg =
"hello everybody I am client"
;
OutputStream os = socket.getOutputStream();
os.write(msg.getBytes());
}
catch
(IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
catch
(IOException e)
{
e.printStackTrace();
}
}
}
|
1352

被折叠的 条评论
为什么被折叠?



