我想获取连接到我手机的另一台设备的蓝牙信号强度,
如何获取蓝牙信号强度?
我尝试通过谷歌进行大量搜索,但没有找到任何答案。
有人知道我该如何实施吗?
这是我的活动:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
registerReceiver(receiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private final BroadcastReceiver receiver = new BroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(BluetoothDevice.ACTION_FOUND.equals(action)) {
int rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI,Short.MIN_VALUE);
Toast.makeText(getApplicationContext()," RSSI: " + rssi + "dBm", Toast.LENGTH_SHORT).show();
}
}
};
}
我的清单文件中也有蓝牙权限。
要获取信号,您可以检查蓝牙 RSSI,您可以读取已连接设备的 RSSI,或执行蓝牙发现以检查任何附近设备的 RSSI。
基本上,蓝牙发现是向范围内的所有站点广播以进行响应。当每个设备做出响应时,Android 会触发 ACTION_FOUND 意图。在此意图中,您可以获取额外的 EXTRA_RSSI 来获取 RSSI。
请注意,并非所有蓝牙硬件都支持 RSSI。
另相关:Android IRC 办公时间关于 Android 蓝牙 RSSI 的问题 这是一个经典蓝牙广播接收器示例
private final BroadcastReceiver receiver = new BroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(BluetoothDevice.ACTION_FOUND.equals(action)) {
short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI,Short.MIN_VALUE);
Toast.makeText(getApplicationContext()," RSSI: " + rssi + "dBm", Toast.LENGTH_SHORT).show();
}
}
};
我认为你的代码没问题,但你需要实现
startDiscovery()
才能看到结果。
事实是,
BluetoothDevice.EXTRA_RSSI
仅适用于发现设备,当您连接到其中一个设备时,您将无法再获取其RSSI。
在这里,我开发了一个非常简单的活动示例,可以让您查看附近设备的 RSSI。您首先需要在布局中添加一个 TextView 和一个 Button,然后启用蓝牙适配器,然后只需单击按钮即可。
package com.in2apps.rssi;
import android.os.Bundle;
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.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class RSSIActivity extends Activity {
private BluetoothAdapter BTAdapter = BluetoothAdapter.getDefaultAdapter();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rssi);
registerReceiver(receiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
Button boton = (Button) findViewById(R.id.button1);
boton.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
BTAdapter.startDiscovery();
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_rssi, menu);
return true;
}
private final BroadcastReceiver receiver = new BroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(BluetoothDevice.ACTION_FOUND.equals(action)) {
int rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI,Short.MIN_VALUE);
String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
TextView rssi_msg = (TextView) findViewById(R.id.textView1);
rssi_msg.setText(rssi_msg.getText() + name + " => " + rssi + "dBm\n");
}
}
};
}
看起来是这样的:
API 18(Android 4.3)中引入了必要的API。 您需要拨打
BluetoothGatt#readRemoteRssi()
发起请求。 响应显示在 BluetoothCallback#onReadRemoteRssi()
回调中。 (这是处理连接、发现、特征读取等的回调对象)
不再需要广播接收器的东西。
您可以使用 RSSI 获取 BluetoothDevice 的信号强度。这可以使用 BluetoothAdapter 来获取绑定设备来完成。
一旦有了您感兴趣的,只需对其调用 connectGatt() 并定义一个新的 BluetoothGattCallback。这是一个提供很少方法来重写的接口。下面写的两个将允许您在每次连接状态发生变化时获得 rssi。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get the default bluetoothAdapter to store bonded devices into a Set of BluetoothDevice(s)
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// It will work if your bluetooth device is already bounded to your phone
// If not, you can use the startDiscovery() method and connect to your device
Set<BluetoothDevice> bluetoothDeviceSet = bluetoothAdapter.getBondedDevices();
for (BluetoothDevice bluetoothDevice : bluetoothDeviceSet) {
bluetoothDevice.connectGatt(this, true, new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
}
@Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
if(status == BluetoothGatt.GATT_SUCCESS)
Log.d("BluetoothRssi", String.format("BluetoothGat ReadRssi[%d]", rssi));
}
});
}
}
注意:此示例需要在清单文件中声明以下权限
<uses-permission android:name="android.permission.BLUETOOTH" />
这里是记录蓝牙 RSSI ble 设备并记录它们的完整代码,您也可以在文本视图中添加它们。进一步感谢 @memochipan 的代码,无需连接即可获取所有附近设备的 RSSI 值。
RSSI 记录器
class RSSILoggerActivity : AppCompatActivity() {
private lateinit var binding: ActivityRssiBinding
val BLUETOOTH_PERMISSION: Int = 101
private val btAdapter: BluetoothAdapter by lazy {
(applicationContext.getSystemService(
BLUETOOTH_SERVICE
) as BluetoothManager).adapter
}
private val locationManager by lazy {
applicationContext.getSystemService(
LOCATION_SERVICE
) as LocationManager
}
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityRssiBinding.inflate(layoutInflater)
setContentView(binding.root)
registerReceiver(
receiver,
IntentFilter(BluetoothDevice.ACTION_FOUND, BluetoothDevice.ACTION_UUID)
)
requestBluetoothPermission()
requestLocationPermission()
binding.buttonStart.setOnClickListener {
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.BLUETOOTH_SCAN,
) == PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
if (btAdapter.isEnabled && isLocationEnabled()) {
// Start discovery
btAdapter.startDiscovery()
} else {
// Prompt user to enable Bluetooth or location
Toast.makeText(this, "Some issue", Toast.LENGTH_SHORT).show()
}
} else {
Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show()
}
}
}
private fun isLocationEnabled(): Boolean {
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) ||
locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
}
fun requestLocationPermission() {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this,
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_BACKGROUND_LOCATION
),
WRITE_PERMISSION
)
}
}
fun requestBluetoothPermission() {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.BLUETOOTH_SCAN
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this,
arrayOf(
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_ADMIN,
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_CONNECT,
),
BLUETOOTH_PERMISSION
)
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String?>,
grantResults: IntArray,
deviceId: Int
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults, deviceId)
if (requestCode == BLUETOOTH_PERMISSION) {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.BLUETOOTH_SCAN
) == PackageManager.PERMISSION_GRANTED
) {
Log.d("Permission", "Permission has been granted")
}
}
}
}
private val receiver: BroadcastReceiver = object : BroadcastReceiver() {
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
override fun onReceive(context: Context?, intent: Intent) {
val action = intent.action
when (action) {
BluetoothDevice.ACTION_FOUND -> {
val rssi =
intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.Companion.MIN_VALUE)
.toInt()
val device: BluetoothDevice? =
intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
if (device != null)
Log.d(
"Key:",
"${binding.tvRssi.text} ${device.name} : ${device.address} $rssi\n"
)
}
BluetoothDevice.ACTION_UUID -> {
val device: BluetoothDevice? =
intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
val uuidExtra = intent.getParcelableArrayExtra(BluetoothDevice.EXTRA_UUID)
if (uuidExtra != null) {
for (uuid in uuidExtra) {
Log.d("UUID", "Device: ${device?.name} ${device?.address} UUID: $uuid")
}
}
}
}
}
}
}
activity_rssi.xml
<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"
tools:context=".RSSILoggerActivity">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_rssi"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_margin="20dp"
android:background="#F2DEC9"
android:padding="18dp"
android:scrollbars="vertical"
android:textSize="28sp"
app:layout_constraintBottom_toTopOf="@id/buttonStart"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/buttonStart"
android:layout_width="300dp"
android:layout_height="48dp"
android:layout_marginStart="54dp"
android:layout_marginEnd="54dp"
android:layout_marginBottom="32dp"
android:background="#E6A25D"
android:text="Start Measuring"
android:textColor="#FFFFFF"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
权限
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />