I need to know UUID on API 8 (2.2) or possibly 2.3.3.
As I understand the documentation, this should be allowed:
phoneDevice = blueAdapter.getRemoteDevice(phoneAddress);
ParcelUuid[] phoneUuids = phoneDevice.getUuids(); // Won't compile
Eclipse gives me:
"The method getUuids() is undefined for the type BluetoothDevice."
But see:
http://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getUuids()
Also, I would like to know how the UUIDs are "parceled" inside the ParcelUuid[]. In case I ever manage to get there, how do I retrieve a UUID from a parcelUuid[]? Documentation for Android bluetooth seems to be very poor, in my opinion.
What a joke!
Now I try to get it from the intent, but this too gives: *"EXTRA_UUID cannot be resolved or is not a field"*:
intent.getParcelableExtra(BluetoothDevice.EXTRA_UUID);
You have to use reflection to use the getUuids() and fetchUuidsWithSdp() on android version < 3. So, try the code:
Method method = phoneDevice.getClass().getMethod("getUuids", null);
ParcelUuid[] phoneUuids = (ParcelUuid[]) method.invoke(phoneDevice, null);
//this will support from API level 15 and above.
Broadcast Action: This intent is used to broadcast the UUID wrapped as a ParcelUuid of the remote device after it has been fetched. This intent is sent only when the UUIDs of the remote device are requested to be fetched using Service Discovery Protocol
Always contains the extra field EXTRA_DEVICE
Always contains the extra field EXTRA_UUID
Requires BLUETOOTH to receive.
Constant Value: "android.bluetooth.device.action.UUID"
//no way to degrade its hardware related. there is no supporting jar also. http://developer.android.com/sdk/compatibility-library.html
Unfortunately, I don't think there is any good way to get the UUID's supported by a BluetoothDevice with API level < 15. I guess that's why they added the new functions in API 15.
Note, from the docs for BluetoothClass
BluetoothClass is useful as a hint to roughly describe a device (for
example to show an icon in the UI), but does not reliably describe
which Bluetooth profiles or services are actually supported by a
device. Accurate service discovery is done through SDP requests, which
are automatically performed when creating an RFCOMM socket with
createRfcommSocketToServiceRecord(UUID) and
listenUsingRfcommWithServiceRecord(String, UUID).
So, perhaps the device class could be used as a hint as to what services will be available until you perform one of the listed functions. Certainly it doesn't hurt to check the class since this won't require any additional bluetooth operations.
Note that the service class is also available (it is part of the device class) but this is just a general class, not a listing of specific services (like from SDP).
try BluetoothAdapter class
any question, read: http://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html
In case you can not get UUID from getUuids() method. Please try the other way.
After scanned successfully, you should receive byte[] (scanRecord), so from this result, if you can recognize UUID format you can split step by step to get correct UUID as these codes.
P/s : Important thing, you should know UUID format to get from index correctly.
// Put item into hash map
// UUID from index 10 to 24 : 12233445566778899aabbccddeeff0
StringBuilder mSbUUID = new StringBuilder();
for (int i = 0; i < scanRecord.length; i++) {
// UUID
if (i >= 10 & i <= 24) {
if (Integer.toHexString(
scanRecord[i]).contains("ffffff")) {
mSbUUID.append(Integer.toHexString(scanRecord[i]).replace("ffffff", "") + "-");
} else {
mSbUUID.append(Integer.toHexString(scanRecord[i]) + "-");
}
}
}
Related
I have already successfully used BLE advertising to broadcast information from one android device and receive it on another. Now I want the observer to be a Unity-app running on the HoloLens v2. The HoloLens does not need to connect to the android-device as I am aware that this does not seem to be supported. I am looking for a broadcaster -> observer solution.
As mentioned, I already have the broadcaster written and it works fine with android -> android. Now I have implemented my observer in Unity, largely inspired by this article, and it looks like this:
#if ENABLE_WINMD_SUPPORT
using System;
using Windows.Devices.Bluetooth.Advertisement;
#endif
public class DemoManager : MonoBehaviour
{
[SerializeField] private StatusDisplay statusDisplay;
private void Awake()
{
#if ENABLE_WINMD_SUPPORT
StartWatcher();
#else
statusDisplay.Display("UWP APIs are not supported on this platform!");
#endif
}
#if ENABLE_WINMD_SUPPORT
private void StartWatcher()
{
void OnAdvertisementReceived(object sender, BluetoothLEAdvertisementReceivedEventArgs eventArgs)
{
statusDisplay.Display("Advertisement received!");
}
try {
BluetoothLEAdvertisementWatcher watcher = new BluetoothLEAdvertisementWatcher();
watcher.AdvertisementFilter.Advertisement.ManufacturerData.Add(GetManufacturerData());
watcher.Received += OnAdvertisementReceived;
watcher.Start();
statusDisplay.Display("Watcher started!");
} catch (Exception e){
statusDisplay.Display($"Watcher could not start! Error: {e.Message}");
}
}
private BluetoothLEManufacturerData GetManufacturerData()
{
var manufacturerData = new BluetoothLEManufacturerData();
manufacturerData.CompanyId = 1234;
return manufacturerData;
}
#endif
}
The StatusDisplay script is used for displaying text in a thread-safe way. The company-id 1234 is also used by the broadcaster.
My app has bluetooth capabilities (enabled both in the Unity-editor and in the built solution)
All looks very promising, but sadly the advertisement never seems to be received, or at the very least I am getting no corresponding status message.
Does anybody have any ide what might be wrong? Does anyone have any experience with this problem?
We tested the Bluetooth.Advertisement API and works well on the HoloLens. I found that you assigned the CompanyId(a 16-bit unsigned integer) property a signed decimal number, but we usually provide a hexadecimal number as a Bluetooth LE company identifier code. Could you double-check this point both in your watcher and publisher? For example, it should look like 0xFFFE. Besides, more information about how to use the Bluetooth Advertisement API to send and receive Bluetooth Low Energy advertisements please see:Bluetooth advertisement sample
The problem was not with the Unity-side. My advertisement was malformed. I tested my advertisements with a observer that I also wrote myself on Android. So I accounted for the incorrect formatting there, but of course, the C# Advertisement-watcher did not.
I'm trying to build an app which gets battery level of currently connected Bluetooth headset. This app can be used on phones which don't have this functionality built-in.
While searching on stackoverflow, I found How to get Bluetooth Headset battery status in android this question. I got the currently connected Bluetooth headset using BluetoothProfile.HEADSET profile.
But in the device object of type BluetoothDevice I don't see any method or property to get battery level of Bluetooth Headset.
I can get the device name and isAudioConnected.
If question is about Bluetooth HFP feature: HF indicators feature is optional for the both sides. If the both sides support it, BluetoothHeadset will broadcast BluetoothHeadset.ACTION_HF_INDICATORS_VALUE_CHANGED with BluetoothHeadset.EXTRA_HF_INDICATORS_IND_ID equal 2 (Battery Level) and BluetoothHeadset.EXTRA_HF_INDICATORS_IND_VALUE with scope 0..100. Do not remember Android version were it was implemented, you should check it.
Also battery level can be implemented in device using vendor specific HFP AT commands (especially for old handsfree devices) and maybe BLE.
I found a solution, but it only works on android 8 and above
I took this code from here
Kotlin
fun getBatteryLevel(pairedDevice: BluetoothDevice?): Int {
return pairedDevice?.let { bluetoothDevice ->
(bluetoothDevice.javaClass.getMethod("getBatteryLevel"))
.invoke(pairedDevice) as Int
} ?: -1
}
The first thing to register BroadcastReciver by "android.bluetooth.device.action.BATTERY_LEVEL_CHANGED"
and you can receive this action by the broadcast receiver then get extra data by "android.bluetooth.device.extra.BATTERY_LEVEL"
and if you want to trigger this action, you need to reconnect your Bluetooth device or Bluetooth device battery level happened to change.
Good luck for you.
Connected AirPods Pro to OnePlus 5T with Android 9.
None of those registered events happen:
"android.bluetooth.device.action.BATTERY_LEVEL_CHANGED"
"android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED"
"android.bluetooth.headset.action.HF_INDICATORS_VALUE_CHANGED"
I am Able to achieve the handset battery Level in Java
try {
BluetoothDevice device = bluetoothAdapter.getRemoteDevice("Connected device ID");
java.lang.reflect.Method method;
method = device.getClass().getMethod("getBatteryLevel");
int value = (int) method.invoke(device);
result.success(value);
} catch (Exception ex) {
result.error("invalid_argument", "'deviceId' argument is required to be string", null);
break;
}
This is #Kirill Martyuk answer as an Extension variable
val BluetoothDevice.batteryLevel
get() = this.let { device ->
val method = device.javaClass.getMethod("getBatteryLevel")
method.invoke(device) as Int?
} ?: -1
Usage would be something like
val manager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager?
val adapter = manager?.adapter
val devices = adapter?.bondedDevices.orEmpty()
devices.forEach { device ->
Log.d("DEVICE_NAME", device.name)
Log.d("CHARGE_LEVEL", device.batteryLevel.toString())
}
I feel like I am on crazy pills right now. A specific part of my application has been working just fine for several days, and today it just stopped working and I can not figure out why. This part of my code used to output the total data since boot that each specific app has sent and received. Now, the values always show up as 0.
A couple things that may or may not be affecting this:
1.) My Nexus 4 was just updated to Android 4.3 today, but I doubt this is an issue because this worked just fine right after I updated.
2.) With the Android API 18 update, some methods from the Traffic Stats API are now deprecated, but these are methods I am not even using, so this should have no effect.
http://developer.android.com/reference/android/net/TrafficStats.html
All help is greatly appreciated.
PackageManager packageManager=this.getPackageManager();
List<ApplicationInfo> appList=packageManager.getInstalledApplications(0);
for (ApplicationInfo appInfo : appList) {
String appLabel = (String) packageManager.getApplicationLabel(appInfo);
int uid = appInfo.uid;
Log.d("data", String.valueOf(TrafficStats.getUidRxBytes(uid) + TrafficStats.getUidTxBytes(uid)));
Update[January 23, 2014]: Testing the getUidRxBytes() and getUidTxBytes() on my Nexus 4 running Android 4.4.2 shows that the values are no longer 0, but are reporting the correct statistics.
I have reported the issue to the AOSP issue tracker: here
I have also created an alternate solution to the problem which I have pasted below:
private Long getTotalBytesManual(int localUid){
File dir = new File("/proc/uid_stat/");
String[] children = dir.list();
if(!Arrays.asList(children).contains(String.valueOf(localUid))){
return 0L;
}
File uidFileDir = new File("/proc/uid_stat/"+String.valueOf(localUid));
File uidActualFileReceived = new File(uidFileDir,"tcp_rcv");
File uidActualFileSent = new File(uidFileDir,"tcp_snd");
String textReceived = "0";
String textSent = "0";
try {
BufferedReader brReceived = new BufferedReader(new FileReader(uidActualFileReceived));
BufferedReader brSent = new BufferedReader(new FileReader(uidActualFileSent));
String receivedLine;
String sentLine;
if ((receivedLine = brReceived.readLine()) != null) {
textReceived = receivedLine;
}
if ((sentLine = brSent.readLine()) != null) {
textSent = sentLine;
}
}
catch (IOException e) {
}
return Long.valueOf(textReceived).longValue() + Long.valueOf(textReceived).longValue();
}
The TrafficStats class get the information about network traffic from the /proc/uid_stat/<uid> directory. This contains information about the tcp, udp bytes and packets sent and received. If the files are not present the TrafficStats class can't get the network stats. You can check if the files are present, If not you are out of luck and should look for other way.
If the files are present you can try to read it yourself.
Also the getUidTxBytes() and getUIDRxBytes() report only the TCP traffic and miss UDP traffic. So if your app is doing lots of UDP traffic (like voip) then you'll not get any info.
There is already a bug filed for this : https://code.google.com/p/android/issues/detail?id=32410
I have done some detailed research about this, and to clarify some details, since Android 4.3 the TrafficStats API has changed in the way it extracts details from the device.
Prior to Android 4.3 the UID traffic stats were available for TCP and UDP and included API for bytes and packets & sent and received. That data was extracted from the /proc/uid_stat/[pid]/* files.
In Android 4.3, the developers has decided to switch to a better and more safe API, using the xt_qtaguid UID statistics, which is part of the netfilter kernel module in Linux.
This API (procfs) allows access based on process UID, and this is why when you try to access to TrafficStats API in Android=>4.3 you will get zero information for not-own UID.
btw, the commit that caused the issue is the following:
https://github.com/android/platform_frameworks_base/commit/92be93a94edafb5906e8bc48e6fee9dd07f5049e
*Improve TrafficStats UID APIs.
Deprecate transport layer statistics, leaving only the summarized
network layer statistics.
Improve documentation to be clear about layers where measurements
occur, and their behavior since boot. Under the hood, move to using
xt_qtaguid UID statistics.
Bug: 6818637, 7013662
Change-Id: I9f26992e5fcdebd88c671e5765bd91229e7b0016*
I have 2 Android devices using WiFi Direct. On one device I can get information about the other device using the WifiP2pManager class, and request a connection to the other device. However when I request a connection, the other device pops up a little window and asks the user if they want to accept the connection request.
Is it possible to auto-accept these connection requests? I.E to be able to connect to the other device without user confirmation?
It can be easily done with the help of Xposed framework. You just need to replace the single method inside one of android java classes (see the link from snihalani's answer). But of course to use Xposed your device must be rooted. The main idea can be expressed in the following code (using Xposed)
#Override
public void handleLoadPackage(LoadPackageParam lpparam) {
try {
Class<?> wifiP2pService = Class.forName("android.net.wifi.p2p.WifiP2pService", false, lpparam.classLoader);
for (Class<?> c : wifiP2pService.getDeclaredClasses()) {
//XposedBridge.log("inner class " + c.getSimpleName());
if ("P2pStateMachine".equals(c.getSimpleName())) {
XposedBridge.log("Class " + c.getName() + " found");
Method notifyInvitationReceived = c.getDeclaredMethod("notifyInvitationReceived");
final Method sendMessage = c.getMethod("sendMessage", int.class);
XposedBridge.hookMethod(notifyInvitationReceived, new XC_MethodReplacement() {
#Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
final int PEER_CONNECTION_USER_ACCEPT = 0x00023000 + 2;
sendMessage.invoke(param.thisObject, PEER_CONNECTION_USER_ACCEPT);
return null;
}
});
break;
}
}
} catch (Throwable t) {
XposedBridge.log(t);
}
}
I tested it on SGS4 stock 4.2.2 ROM and it worked.
I guess the same could be done with the help of Substrate for android.
From my current understanding of the API, You cannot really accept connections automatically without user's intervention. You can initiate a connection, that doesn't require user intervention. If both of your devices are mobile devices, you will have to accept connection request on one end.
I have put this as a feature request in android project hosting.
You can monitor their response here: https://code.google.com/p/android/issues/detail?id=30880
Based on the comments, do you really need to connect to the devices if you just want to track and log the vehicles around you ?
I don't know the scope of the project, but you could simply use the WifiP2pDeviceList that you get when you request the peers in the WifiP2pManager. You could get the list of the devices (~= vehicles) around you and could log this.
Connection is useful if you want to send more detailed information I guess.
If you can modify the framework, you can ignore the accept window and direct send the "PEER_CONNECTION_USER_ACCEPT".
Base on Android 5.0, "frameworks/opt/net/wifi/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java".
You must find the "notifyInvitationReceived", and modify to ...
private void notifyInvitationReceived() {
/*Direct sends the accept message.*/
sendMessage(PEER_CONNECTION_USER_ACCEPT);
/*
... old code
*/
}
I'm writing an Android app which receives information from a Bluetooth device. Our client has suggested that the Bluetooth device (which they produce) will change its name depending on certain conditions - for the simplest example its name will sometimes be "xxx-ON" and sometimes "xxx-OFF". My app is just supposed to seek this BT transmitter (I use BluetoothAdapter.startDiscovery() ) and do different things depending on the name it finds. I am NOT pairing with the Bluetooth device (though I suppose it might be possible, the app is supposed to eventually work with multiple Android devices and multiple BT transmitters so I'm not sure it would be a good idea).
My code works fine to detect BT devices and find their names. Also, if the device goes off, I can detect the next time I seek, that it is not there. But it seems that if it is there and it changes name, I pick up the old name - presumably it is cached somewhere. Even if the bluetooth device goes off, and we notice that, the next time I detect it, I still see the old name.
I found this issue in Google Code: here but it was unclear to me even how to use the workaround given ("try to connect"). Has anyone done this and had any luck? Can you share code?
Is there a simple way to just delete the cached names and search again so I always find the newest names? Even a non-simple way would be good (I am writing for a rooted device).
Thanks
I would suggest 'fetchUuidsWithSdp()'. It's significance is that, unlike the similar getUuids() method, fetchUuidsWithSdp causes the device to update cached information about the remote device. And I believe this includes the remote name as well as the SPD.
Note that both the methods I mentioned are hidden prior to 4.0.3, so your code would look l ike this:
public static void startServiceDiscovery( BluetoothDevice device ) {
// Need to use reflection prior to API 15
Class cl = null;
try {
cl = Class.forName("android.bluetooth.BluetoothDevice");
} catch( ClassNotFoundException exc ) {
Log.e(CTAG, "android.bluetooth.BluetoothDevice not found." );
}
if (null != cl) {
Class[] param = {};
Method method = null;
try {
method = cl.getMethod("fetchUuidsWithSdp", param);
} catch( NoSuchMethodException exc ) {
Log.e(CTAG, "fetchUuidsWithSdp not found." );
}
if (null != method) {
Object[] args = {};
try {
method.invoke(device, args);
} catch (Exception exc) {
Log.e(CTAG, "Failed to invoke fetchUuidsWithSdp method." );
}
}
}
}
You'll then need to listen for the BluetoothDevice.ACTION_NAME_CHANGED intent, and extract BluetoothDevice.EXTRA_NAME from it.
Let me know if that helps.