初次提交

This commit is contained in:
2022-09-19 18:05:01 +08:00
commit 57051fc44b
5401 changed files with 325410 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
package com.bn.pp10;
//用于管理公共常量的常量类
public class Constant {
// 由Service中的Handler发送的消息类型
public static final int MSG_READ = 2;
public static final int MSG_DEVICE_NAME = 4;
// 从Service中的Handler发来的主键名
public static final String DEVICE_NAME = "device_name";
}

View File

@@ -0,0 +1,147 @@
package com.bn.pp10;
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.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
/**
* 设备列表的Activity
*/
public class MyDeviceListActivity extends Activity {
// extra信息名称
public static String EXTRA_DEVICE_ADDR = "device_address";
// 成员变量
private BluetoothAdapter myBtAdapter;
private ArrayAdapter<String> myAdapterPaired;
private ArrayAdapter<String> myAdapterNew;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 设置窗口
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.device_list);
// 设置为当结果是Activity.RESULT_CANCELED时返回到该Activity的调用者
setResult(Activity.RESULT_CANCELED);
// 初始化搜索按钮
Button scanBtn = (Button) findViewById(R.id.button_scan);
scanBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
doDiscovery();
v.setVisibility(View.GONE);// 使按钮不可见
}
});
// 初始化适配器
myAdapterPaired = new ArrayAdapter<String>(this,
R.layout.device_name);// 已配对的
myAdapterNew = new ArrayAdapter<String>(this,
R.layout.device_name);// 新发现的
// 将已配对的设备放入列表中
ListView lvPaired = (ListView) findViewById(R.id.paired_devices);
lvPaired.setAdapter(myAdapterPaired);
lvPaired.setOnItemClickListener(mDeviceClickListener);
// 将新发现的设备放入列表中
ListView lvNewDevices = (ListView) findViewById(R.id.new_devices);
lvNewDevices.setAdapter(myAdapterNew);
lvNewDevices.setOnItemClickListener(mDeviceClickListener);
// 注册发现设备时的广播
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
this.registerReceiver(mReceiver, filter);
// 注册搜索完成时的广播
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
this.registerReceiver(mReceiver, filter);
// 获取本地蓝牙适配器
myBtAdapter = BluetoothAdapter.getDefaultAdapter();
// 获取已配对的设备
Set<BluetoothDevice> pairedDevices = myBtAdapter.getBondedDevices();
// 将所有已配对设备信息放入列表中
if (pairedDevices.size() > 0) {
findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
for (BluetoothDevice device : pairedDevices) {
myAdapterPaired.add(device.getName() + "\n"
+ device.getAddress());
}
} else {
String noDevices = getResources().getText(R.string.none_paired)
.toString();
myAdapterPaired.add(noDevices);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (myBtAdapter != null) {// 确保不再搜索设备
myBtAdapter.cancelDiscovery();
}
// 取消广播监听器
this.unregisterReceiver(mReceiver);
}
// 使用蓝牙适配器搜索设备的方法
private void doDiscovery() {
// 在标题上显示正在搜索的标志
setProgressBarIndeterminateVisibility(true);
setTitle(R.string.scanning);
// 显示搜索到的新设备的副标题
findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);
if (myBtAdapter.isDiscovering()) {// 如果正在搜索,取消本次搜索
myBtAdapter.cancelDiscovery();
}
myBtAdapter.startDiscovery();// 开始搜索
}
// 列表中设备按下时的监听器
private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {
public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) {
myBtAdapter.cancelDiscovery();// 取消搜索
// 获取设备的MAC地址
String msg = ((TextView) v).getText().toString();
String address = msg.substring(msg.length() - 17);
// 创建带有MAC地址的Intent
Intent intent = new Intent();
intent.putExtra(EXTRA_DEVICE_ADDR, address);
// 设备结果并退出Activity
setResult(Activity.RESULT_OK, intent);
finish();
}
};
// 监听搜索到的设备的BroadcastReceiver
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// 如果找到设备
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// 从Intent中获取BluetoothDevice对象
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// 如果没有配对,将设备加入新设备列表
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
myAdapterNew.add(device.getName() + "\n"
+ device.getAddress());
}
// 当搜索完成后改变Activity的标题
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED
.equals(action)) {
setProgressBarIndeterminateVisibility(false);
setTitle(R.string.select_device);
if (myAdapterNew.getCount() == 0) {
String noDevices = getResources().getText(
R.string.none_found).toString();
myAdapterNew.add(noDevices);
}
}
}
};
}

View File

@@ -0,0 +1,243 @@
package com.bn.pp10;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
//用于管理连接的Service
public class MyService {
// 本应用的唯一 UUID
private static final UUID MY_UUID = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
// 成员变量
private final BluetoothAdapter btAdapter;
private final Handler myHandler;
private AcceptThread myAcceptThread;
private ConnectThread myConnectThread;
private ConnectedThread myConnectedThread;
private int myState;
// 表示当前连接状态的常量
public static final int STATE_NONE = 0; // 什么也没做
public static final int STATE_LISTEN = 1; // 正在监听连接
public static final int STATE_CONNECTING = 2; // 正在连接
public static final int STATE_CONNECTED = 3; // 已连接到设备
// 构造器
public MyService(Context context, Handler handler) {
btAdapter = BluetoothAdapter.getDefaultAdapter();
myState = STATE_NONE;
myHandler = handler;
}
//设置当前连接状态的方法
private synchronized void setState(int state) {
myState = state;
}
//获取当前连接状态的方法
public synchronized int getState() {
return myState;
}
//开启service的方法
public synchronized void start() {
// 关闭不必要的线程
if (myConnectThread != null) {myConnectThread.cancel(); myConnectThread = null;}
if (myConnectedThread != null) {myConnectedThread.cancel(); myConnectedThread = null;}
if (myAcceptThread == null) {// 开启线程监听连接
myAcceptThread = new AcceptThread();
myAcceptThread.start();
}
setState(STATE_LISTEN);
}
//连接设备的方法
public synchronized void connect(BluetoothDevice device) {
// 关闭不必要的线程
if (myState == STATE_CONNECTING) {
if (myConnectThread != null) {myConnectThread.cancel(); myConnectThread = null;}
}
if (myConnectedThread != null) {myConnectedThread.cancel(); myConnectedThread = null;}
// 开启线程连接设备
myConnectThread = new ConnectThread(device);
myConnectThread.start();
setState(STATE_CONNECTING);
}
//开启管理和已连接的设备间通话的线程的方法
public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
// 关闭不必要的线程
if (myConnectThread != null) {myConnectThread.cancel(); myConnectThread = null;}
if (myConnectedThread != null) {myConnectedThread.cancel(); myConnectedThread = null;}
if (myAcceptThread != null) {myAcceptThread.cancel(); myAcceptThread = null;}
// 创建并启动ConnectedThread
myConnectedThread = new ConnectedThread(socket);
myConnectedThread.start();
// 发送已连接的设备名称到主界面Activity
Message msg = myHandler.obtainMessage(Constant.MSG_DEVICE_NAME);
Bundle bundle = new Bundle();
bundle.putString(Constant.DEVICE_NAME, device.getName());
msg.setData(bundle);
myHandler.sendMessage(msg);
setState(STATE_CONNECTED);
}
public synchronized void stop() {//停止所有线程的方法
if (myConnectThread != null) {myConnectThread.cancel(); myConnectThread = null;}
if (myConnectedThread != null) {myConnectedThread.cancel(); myConnectedThread = null;}
if (myAcceptThread != null) {myAcceptThread.cancel(); myAcceptThread = null;}
setState(STATE_NONE);
}
public void write(byte[] out) {//向ConnectedThread写入数据的方法
ConnectedThread tmpCt;// 创建临时对象引用
synchronized (this) {// 锁定ConnectedThread
if (myState != STATE_CONNECTED) return;
tmpCt = myConnectedThread;
}
tmpCt.write(out);// 写入数据
}
private class AcceptThread extends Thread {//用于监听连接的线程
// 本地服务器端ServerSocket
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
BluetoothServerSocket tmpSS = null;
try {// 创建用于监听的服务器端ServerSocket
tmpSS = btAdapter.listenUsingRfcommWithServiceRecord("BluetoothChat", MY_UUID);
} catch (IOException e) {
e.printStackTrace();
}
mmServerSocket = tmpSS;
}
public void run() {
setName("AcceptThread");
BluetoothSocket socket = null;
while (myState != STATE_CONNECTED) {//如果没有连接到设备
try {
socket = mmServerSocket.accept();//获取连接的Sock
} catch (IOException e) {
e.printStackTrace();
break;
}
if (socket != null) {// 如果连接成功
synchronized (MyService.this) {
switch (myState) {
case STATE_LISTEN:
case STATE_CONNECTING:
// 开启管理连接后数据交流的线程
connected(socket, socket.getRemoteDevice());
break;
case STATE_NONE:
case STATE_CONNECTED:
try {// 关闭新Socket
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
}
}
}
public void cancel() {
try {
mmServerSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//用于尝试连接其他设备的线程
private class ConnectThread extends Thread {
private final BluetoothSocket myBtSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
mmDevice = device;
BluetoothSocket tmp = null;
// 通过正在连接的设备获取BluetoothSocket
try {
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
e.printStackTrace();
}
myBtSocket = tmp;
}
public void run() {
setName("ConnectThread");
btAdapter.cancelDiscovery();// 取消搜索设备
try {// 连接到BluetoothSocket
myBtSocket.connect();//尝试连接
} catch (IOException e) {
setState(STATE_LISTEN);//连接断开后设置状态为正在监听
try {// 关闭socket
myBtSocket.close();
} catch (IOException e2) {
e.printStackTrace();
}
MyService.this.start();//如果连接不成功重新开启service
return;
}
synchronized (MyService.this) {// 将ConnectThread线程置空
myConnectThread = null;
}
connected(myBtSocket, mmDevice);// 开启管理连接后数据交流的线程
}
public void cancel() {
try {
myBtSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//用于管理连接后数据交流的线程
private class ConnectedThread extends Thread {
private final BluetoothSocket myBtSocket;
private final InputStream mmInStream;
private final OutputStream myOs;
public ConnectedThread(BluetoothSocket socket) {
myBtSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// 获取BluetoothSocket的输入输出流
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
mmInStream = tmpIn;
myOs = tmpOut;
}
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while (true) {// 一直监听输入流
try {
bytes = mmInStream.read(buffer);// 从输入流中读入数据
//将读入的数据发送到主Activity
myHandler.obtainMessage(Constant.MSG_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
e.printStackTrace();
setState(STATE_LISTEN);//连接断开后设置状态为正在监听
break;
}
}
}
//向输出流中写入数据的方法
public void write(byte[] buffer) {
try {
myOs.write(buffer);
} catch (IOException e) {
e.printStackTrace();
}
}
public void cancel() {
try {
myBtSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

View File

@@ -0,0 +1,141 @@
package com.bn.pp10;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
/**
* 用于显示对话的主Activity
*/
public class Sample2_10_Activity extends Activity {
private EditText outEt;// 布局中的控件引用
private Button sendBtn;
private String connectedNameStr = null;// 已连接的设备名称
private StringBuffer outSb;// 发送的字符信息
private BluetoothAdapter btAdapter = null;// 本地蓝牙适配器
private MyService myService = null;// Service引用
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 获取本地蓝牙适配器
btAdapter = BluetoothAdapter.getDefaultAdapter();
}
@Override
public void onStart() {
super.onStart();
// 如果蓝牙没有开启提示开启蓝牙并退出Activity
if (!btAdapter.isEnabled()) {
Toast.makeText(this, "请先开启蓝牙!", Toast.LENGTH_LONG).show();
finish();
} else {// 否则初始化聊天的控件
if (myService == null)
initChat();
}
}
@Override
public synchronized void onResume() {
super.onResume();
if (myService != null) {// 创建并开启Service
// 如果Service为空状态
if (myService.getState() == MyService.STATE_NONE) {
myService.start();// 开启Service
}
}
}
private void initChat() {
outEt = (EditText) findViewById(R.id.edit_text_out);// 获取编辑文本框的引用
// 获取发送按钮引用,并为其添加监听
sendBtn = (Button) findViewById(R.id.button_send);
sendBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// 获取编辑文本框中的文本内容,并发送消息
TextView view = (TextView) findViewById(R.id.edit_text_out);
String message = view.getText().toString();
sendMessage(message);
}
});
myService = new MyService(this, mHandler);// 创建Service对象
// 初始化存储发送消息的StringBuffer
outSb = new StringBuffer("");
}
@Override
public void onDestroy() {
super.onDestroy();
if (myService != null) {// 停止Service
myService.stop();
}
}
// 发送消息的方法
private void sendMessage(String message) {
// 先检查是否已经连接到设备
if (myService.getState() != MyService.STATE_CONNECTED) {
Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT)
.show();
return;
}
if (message.length() > 0) {// 如果消息不为空再发送消息
byte[] send = message.getBytes();// 获取发送消息的字节数组,并发送
myService.write(send);
// 消除StringBuffer和编辑文本框的内容
outSb.setLength(0);
outEt.setText(outSb);
}
}
// 处理从Service发来的消息的Handler
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case Constant.MSG_READ:
byte[] readBuf = (byte[]) msg.obj;
// 创建要发送的信息的字符串
String readMessage = new String(readBuf, 0, msg.arg1);
Toast.makeText(Sample2_10_Activity.this,
connectedNameStr + ": " + readMessage,
Toast.LENGTH_LONG).show();
break;
case Constant.MSG_DEVICE_NAME:
// 获取已连接的设备名称,并弹出提示信息
connectedNameStr = msg.getData().getString(
Constant.DEVICE_NAME);
Toast.makeText(getApplicationContext(),
"已连接到 " + connectedNameStr, Toast.LENGTH_SHORT)
.show();
break;
}
}
};
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case 1:
// 如果设备列表Activity返回一个连接的设备
if (resultCode == Activity.RESULT_OK) {
// 获取设备的MAC地址
String address = data.getExtras().getString(
MyDeviceListActivity.EXTRA_DEVICE_ADDR);
// 获取BLuetoothDevice对象
BluetoothDevice device = btAdapter
.getRemoteDevice(address);
myService.connect(device);// 连接该设备
}
break;
}
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// 启动设备列表Activity搜索设备
Intent serverIntent = new Intent(this, MyDeviceListActivity.class);
startActivityForResult(serverIntent, 1);
return true;
}
}