package com.example.myapplication;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import android.widget.AdapterView;
public class BluetoothSendMsgActivity extends AppCompatActivity {
private static final int REQUEST_LOCATION_PERMISSION = 1;
private static final long SCAN_PERIOD = 10000;
private static final String TAG = "BLECommunication";
private BluetoothAdapter mBluetoothAdapter;
private BluetoothLeScanner mBluetoothLeScanner;
private Handler mHandler;
private boolean mScanning;
private ArrayAdapter<String> mDeviceListAdapter;
private List<BluetoothDevice> mDeviceList;
private BluetoothGatt mBluetoothGatt;
private BluetoothGattCharacteristic mWriteCharacteristic;
private BluetoothGattCharacteristic mReadCharacteristic;
private EditText inputEditText;
private TextView responseTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bluetooth_send_msg);
inputEditText = findViewById(R.id.inputEditText);
responseTextView = findViewById(R.id.responseTextView);
Button sendButton = findViewById(R.id.sendButton);
mHandler = new Handler();
mDeviceList = new ArrayList<>();
mDeviceListAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1);
ListView listDevices = findViewById(R.id.list_devices);
listDevices.setAdapter(mDeviceListAdapter);
// 为 ListView 添加点击事件监听器
listDevices.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
BluetoothDevice device = mDeviceList.get(position);
scanLeDevice(false); // 停止扫描
connectToDevice(device);
Log.i(TAG, "---------------------------------------1009" );
}
});
inputEditText = findViewById(R.id.inputEditText);
responseTextView = findViewById(R.id.responseTextView);
Button btnStartScan = findViewById(R.id.btn_start_scan);
btnStartScan.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (checkLocationPermission()) {
scanLeDevice(true);
}
}
});
// 获取蓝牙管理器
BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
//-------------------------- start
// 假设已经获取到目标设备的地址
// String deviceAddress = "A2:E0:5A:6D:21:67";
// BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(deviceAddress);
// Log.i(TAG, "----Bluetooth name is " + mBluetoothAdapter.getName());
// // 连接设备
// mBluetoothGatt = device.connectGatt(this, false, gattCallback);
sendButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
responseTextView.setText("Feedback: ---------");
String message = inputEditText.getText().toString();
sendMessage(message);
}
});
//-------------------------- end
mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
}
private void sendMessage(String message) {
Log.i(TAG, "---------------------------------------2009" );
if (mWriteCharacteristic != null) {
Log.i(TAG, "---------------------------------------3009" );
mWriteCharacteristic.setValue(message.getBytes());
mBluetoothGatt.writeCharacteristic(mWriteCharacteristic);
}
}
private boolean checkLocationPermission() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSION);
Log.i(TAG, "--------------checkLocationPermission-------------------------false" );
return false;
}
Log.i(TAG, "--------------checkLocationPermission-------------------------true" );
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_LOCATION_PERMISSION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
scanLeDevice(true);
} else {
Toast.makeText(this, "Location permission is required for BLE scanning", Toast.LENGTH_SHORT).show();
}
}
}
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mScanning = false;
mBluetoothLeScanner.stopScan(mLeScanCallback);
}
}, SCAN_PERIOD);
mScanning = true;
mBluetoothLeScanner.startScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothLeScanner.stopScan(mLeScanCallback);
}
}
private final ScanCallback mLeScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
BluetoothDevice device = result.getDevice();
if (!mDeviceList.contains(device)) {
mDeviceList.add(device);
mDeviceListAdapter.add(device.getName() + " - " + device.getAddress());
mDeviceListAdapter.notifyDataSetChanged();
// Connect to the first device found for simplicity
if (mDeviceList.size() == 1) {
scanLeDevice(false);
connectToDevice(device);
}
}
}
};
private void connectToDevice(BluetoothDevice device) {
Log.i(TAG, "---------------------------------------4009------------------" );
// if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
// return;
// }
Log.i(TAG, "---------------------------------------5009------------------" );
mBluetoothGatt = device.connectGatt(this, false, gattCallback);
}
// private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
// @Override
// public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
// super.onConnectionStateChange(gatt, status, newState);
// if (newState == BluetoothProfile.STATE_CONNECTED) {
// // Discover services after connection
// gatt.discoverServices();
// }
// }
//
// @Override
// public void onServicesDiscovered(BluetoothGatt gatt, int status) {
// Log.d("TAG", "---------------------------3001" );
// super.onServicesDiscovered(gatt, status);
// if (status == BluetoothGatt.GATT_SUCCESS) {
// List<BluetoothGattService> services = gatt.getServices();
// for (BluetoothGattService service : services) {
// List<BluetoothGattCharacteristic> characteristics = service.getCharacteristics();
// for (BluetoothGattCharacteristic characteristic : characteristics) {
// if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) != 0) {
// Log.d("TAG", "---------------------------2001" );
// mWriteCharacteristic = characteristic;
// }
// if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) {
// mReadCharacteristic = characteristic;
// gatt.setCharacteristicNotification(characteristic, true);
// }
// }
// }
// }
// }
//
// @Override
// public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
// super.onCharacteristicChanged(gatt, characteristic);
// if (characteristic == mReadCharacteristic) {
// final String receivedMessage = new String(characteristic.getValue());
// runOnUiThread(new Runnable() {
// @Override
// public void run() {
// responseTextView.setText("Received Message: " + receivedMessage);
// }
// });
// }
// }
// };
// 用于标记是否刚刚进行了写入操作
private boolean isJustWritten = false;
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.i(TAG, "Connected to GATT server.");
// 连接成功后,发现服务
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.i(TAG, "Disconnected from GATT server.");
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
// 查找可写和可读特征
List<BluetoothGattService> services = gatt.getServices();
for (BluetoothGattService service : services) {
List<BluetoothGattCharacteristic> characteristics = service.getCharacteristics();
for (BluetoothGattCharacteristic characteristic : characteristics) {
Log.w(TAG, "--------------------------------9000002-------");
if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) != 0) {
Log.w(TAG, "--------------------------------9000001-------");
mWriteCharacteristic = characteristic;
}
if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) {
mReadCharacteristic = characteristic;
gatt.setCharacteristicNotification(mReadCharacteristic, true);
// 获取描述符并启用通知
BluetoothGattDescriptor descriptor = mReadCharacteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
if (descriptor != null) {
Log.w(TAG, "--------onServicesDiscovered descriptor ");
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descriptor);
}
}
}
}
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
if (characteristic == mReadCharacteristic) {
byte[] data = characteristic.getValue();
final String response = new String(data, StandardCharsets.UTF_8);
if (isJustWritten) {
// 如果是刚刚写入操作后的反馈
Log.d(TAG, "Received feedback after write: " + response);
runOnUiThread(new Runnable() {
@Override
public void run() {
responseTextView.setText("Feedback: " + response);
}
});
// 重置标记
isJustWritten = false;
}
}
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d(TAG, "Write characteristic success");
// 标记刚刚进行了写入操作
isJustWritten = true;
}
}
};
@Override
protected void onDestroy() {
super.onDestroy();
if (mBluetoothGatt != null) {
mBluetoothGatt.close();
}
}
}
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<!-- 第一个 ImageView,靠右上角 -->
<!-- 第二个 ImageView,靠左上角 -->
<ImageView
android:id="@+id/imageView5"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginTop="4dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/seting_3" />
<ImageView
android:id="@+id/imageView"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginTop="4dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/back_2" />
<!-- Start Scan 按钮 -->
<!-- ListView -->
<Button
android:id="@+id/btn_start_scan"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:text="Start Scan"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView5" />
<!-- 输入框 -->
<ListView
android:id="@+id/list_devices"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_start_scan" />
<!-- 发送按钮 -->
<!-- 响应文本视图 -->
<EditText
android:id="@+id/inputEditText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:hint="Enter message"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/list_devices" />
<Button
android:id="@+id/sendButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Send"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/responseTextView" />
<TextView
android:id="@+id/responseTextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:paddingTop="16dp"
android:text="Response will be shown here"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/inputEditText" />
</androidx.constraintlayout.widget.ConstraintLayout>