I was tasked with writing an app that gets details of how much power is being consumed by different apps. I was looking at the PowerProfile class and I am not sure what exactly it is used for. There is this method in the class
Returns the average current in mA consumed by the subsystem
Parameters:
type the subsystem type
Returns:
the average current in milliAmps.
public double getAveragePower(String type) {
if (sPowerMap.containsKey(type)) {
Object data = sPowerMap.get(type);
if (data instanceof Double[]) {
return ((Double[])data)[0];
} else {
return (Double) sPowerMap.get(type);
}
} else {
return 0;
}
}
If I test it by using it as follows:
String POWER_BLUETOOTH_ACTIVE = "bluetooth.active";
String POWER_PROFILE = "com.android.internal.os.PowerProfile";
try{
Constructor[] constructors = Class.forName(POWER_PROFILE).getConstructors();
Constructor c = constructors[0];
Class[] paramTypes = c.getParameterTypes();
Object params = (Object) this.getActivity().getBaseContext();
Object filledObject = c.newInstance(params);
Method batteryMeth1 = Class.forName(POWER_PROFILE).getMethod("getAveragePower", String.class);
Object barglist1[] = new Object[1];
barglist1[0] = new Object[1];
barglist1[0] = POWER_BLUETOOTH_ACTIVE;
double btlife = (Double) btMeth1.invoke(filledObject, barglist1);
Log.d("BatteryLog", "average BT active mAH " + btlife);
btInfo.setText("avg bt mAH is " + btlife);
}
catch (Exception e)
{
Log.d("BTLOg", "average BT active mAH " + btlife);
}
Then I always get 38.8 for bluetooth mAH used, even if I use my Bluetooth a bunch in between runs. Is this normal, and why would I always get the same mAH values?
The bluetooth is consuming power when pairing with other device or transmitting/receiving mode. Pairing mode is responsible to discover active bluetooth nearby then make a connection for the first time to get the MAC address & name of the bluetooth. It's like you are going to say hi to a beautiful stranger (pairing), it takes much courage ,no? then you can make a conversation (transmitting/receiving mode). Power consume in pairing mode is greater (more courage) than bluetooth transmittin/receiving mode whether there are data streamed or not. But for some bluetooth module embedded in your device there are some bluetooth supported sleep mode. The power draw in sleep mode is so little.
So in your case, maybe the bluetooth already in paired mode so it's consume the same amount. Try to pair the bluetooth or discovery bluetooth in Android it might consume more power
Related
We are experimenting with a bunch of new tablets, and every one we tried is having issues with slow transfer rates with the RN4678 board. We currently use the Lenovo M10 FHD Plus. We tried a few such as the Teclast M40S, Nokia T20, and Samsung Galaxy Tab A8. The first two had horrible transfer rates, while the latter was okay but not ideal. We cannot use the Lenovo M10 Plus 3rd Gen because the buttons are too close to the corner to use with our tablet holders.
Here is my code:
public void SendMessage(BluetoothSocket socket, String msg) {
OutputStream outStream;
try {
outStream = BluetoothConnectionService.outputStream;
outStream.write("S".getBytes());
Thread.sleep(4000);
processThread = true;
mApp.running = true;
BluetoothSocketListener bsl = new BluetoothSocketListener(socket,
CollectingDetail.this);
Thread messageListener = new Thread(bsl);
messageListener.start();
timer = new CounterClass(remaingTime, 1000);
timer.start();
bt_stop.setText("Stop");
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
registerReceiver(bluetoothReceiver, filter);
bluetoothReceiver.setRegistered(true);
} catch (IOException | InterruptedException e) {
Log.e("BLUETOOTH_COMMS", e.getMessage());
connectSocket();
}
}
public static class BluetoothSocketListener implements Runnable {
private final WeakReference<CollectingDetail> wrActivity;
private BluetoothSocket socket;
public BluetoothSocketListener(BluetoothSocket socket, CollectingDetail collectingDetail) {
this.socket = socket;
wrActivity = new WeakReference<CollectingDetail>(collectingDetail);
}
#Override
public void run() {
final CollectingDetail activity = wrActivity.get();
if (activity != null) {
activity.inStream = null;
if (!Thread.currentThread().isInterrupted()) {
int bufferSize = 512;
byte[] buffer = new byte[bufferSize];
Log.i("Bluetooth bytes", new String(buffer));
activity.inStream = BluetoothConnectionService.inputStream;
int availableBytes;
int bytesRead = -1;
String message = "";
while (activity.processThread) {
message = "";
try {
availableBytes = activity.inStream.available();
if (availableBytes > 0) {
bytesRead = activity.inStream.read(buffer);
if (bytesRead != -1 && bytesRead < bufferSize) {
message = new String(buffer, 0, bytesRead);
if (activity.mainHandler != null) {
activity.mainHandler.post(new MessagePoster(message, activity));
}
}
}
} catch (IOException e) {
Log.e("BLUETOOTH_COMMS", "Error reading bytes");
try {
socket.close();
} catch (IOException e1) {
Log.e("BLUETOOTH_COMMS", "Could not close socket");
}
activity.processThread = false;
}
}
}
}
}
}
public void seprateData(String message) {
try {
message = message.replaceAll("(\\r\\n|\\n|\\r)", ",");
String[] a = message.split(",");
boolean goodData = false;
for (int i = 0; i < a.length; i++) {
final String data = a[i];
if (data.length() > 0 && !data.equals(" ")) {
if (data.length() >= 10 && data.startsWith("5A")) {
al_sepratedMessageList.add(data);
goodData = true;
}
}
}
if (goodData) {
calculation();
if (ConnectThrough.equalsIgnoreCase("usb")) {
UsbConnectionSerivce.sendMessage("K");
} else {
BluetoothConnectionService.sendMessage(socket, "K");
}
}
} catch (Exception e) {
Log.e("BiSym", "Error Parsing BiSym Data");
}
}
Is there any way we can increase the transfer rate without changing the firmware? It appears others have faced similar problems, but none of the answers have a real solution. Could you please help me out. Thanks.
I fear this may not be software-solvable and may be an issue with BT hardware or firmware. How would I communicate with my boss about this?
I fear this may not be software-solvable and may be an issue with BT hardware or firmware. How would I communicate with my boss about this?
The difference is in the quality of the filtering of the signal, a better filter, narrower bandwidth, means lower Signal to Noise Ratio. Lower SNR means faster transfer.
Better analog filters, mean more components and slightly more cost and loss, however, due to the wide-band nature of Bluetooth, most analog filters can only filter out of band signals (nearby AM/FM/TV broadcasters).
In addition to the analog filters, digital filters are applied to the signal to narrow the bandwidth within the band, this technique incurs little loss, but requires more processing power to be included in the chip, more transistors, more costs.
The order of the filter and the type FIR or IIR determine the characteristics of the filer.
Most designers will minimize the cost to meet the minimum specifications, some will balance the cost versus performance and go further, you never know.
You tell your boss, the the better platforms perform digital filtering well beyond what the Bluetooth specification requires.
I just tested the Teclast M40 Plus which doesn't have this problem.
Something wants to make me believe it is an issue with the UNISOC Bluetooth stack. The Teclast M40 Plus has MediaTek which doesn't have this issue.
EDIT: Also tested on Lenovo M10 Plus 3rd Gen with MediaTek Helio G80, no issue. If we have to use it, we may need a new tablet holder.
Have you repeated the tests? Bluetooth uses the same frequencies as 2.4 GHz Wifi and microwave ovens. In a congested Wifi environment, and/or too many Bluetooth connections(mice, keyboards, headphones, speakers, watches ...), slowdowns are normal for high-speed transfers.
Wifi 6 MIMO utilizes all three distinct channels in the 2.4G band, (1,6,11) of the 12 overlapping. Higher bandwidth/speeds are available in 5.4G (and above), but wall penetration and signal propagation factors keep 2.4G as the primary band in the absence of other possibilities.
There is only so much space in the 2.4G band that Bluetooth operates.
Repeat your tests in an area without interference and see if you get the same results.
A cheap isolation method is to build a Faraday Cage out of .25 inch chicken wire fencing. Isolate the sender and receiver inside of the cage and measure the throughput.
In an uncontrolled environment, hundreds to thousands of tests for each device are required across different time spans to establish a true baseline measurement. You never know when you neighbor is going to start or stop a variable bit-rate video, or move a mouse.Every action contributes to the background noise in the band.
I want to get the value of the HRM of an "A&D UA-651BLE" device.
this is what's written in the datasheet of this device to get the HRM value:
Set the application to pairing mode to start scanning.
Start pairing of A&D BLE device following each instruction manual.
At pairing mode, the application should set time and date and any other device settings
to A&D BLE device. After successful pairing, A&D BLE device shows “End” on the screen.
Take a measurement and finish the measurement, then A&D BLE device start BLE
connection with advertising. The application starts scanning with suitable interval so that
the application catches the advertising of A&D BLE device as soon as it can.
At initial connection or pairing, the Application set “2” to CCCD (Client Characteristic
Configuration Descriptor) so that A&D BLE device sends a measurement data with
Indication.
After A&D device recognizes to be set “2” to CCCD and to be synchronized time and date
within 5 seconds after connected, send the data with Indication.
If the timeout set CCCD and time and date is expired, A&D BLE device will not send data
and store the data in memory. The stored data in A&D BLE device can send next
successful connection.
this is my service code:
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
// This is specific to Heart Rate Measurement.
if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
}
and this is the method that read data:
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
for(byte byteChar : data)
stringBuilder.append(String.format("%02X ", byteChar));
Log.e("HRM value",stringBuilder.toString());
dataComposition.put(characteristic.getUuid().toString(),stringBuilder.toString());
intent.putExtra(EXTRA_DATA,dataComposition);
}
the problem is that this code doesn't return any data !!
There's an Android Open Source Project example that does precisely this, easiest option would be to clone the android-BluetoothLeGatt code, build and compare it to your own. If you can't spot the difference / issue simply deploy both app's and step through both sets of code. Having some known working code will also help to rule out the possibility that the HRM is not functioning properly.
Do you have and example , i try this with equal device and i cant obtain the information y try with
public String response() {
if (mConnected) {
mBluetoothLeService.readCharacteristic(characteristica);
byte response[] = characteristica.getValue();
String respuesta = ReadBytes(response);
mBluetoothLeService.disconnect();
return respuesta;
} else {
return null;
}
}
On sometime, BluetoothDevice.getName() return null. How can i fix it?
remoteDeviceName maybe null in following code. And i need distinguish my device and other devices by remoteDeviceName.
BluetoothAdapter.getDefaultAdapter().startLeScan(new LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, final int rssi,
byte[] scanRecord) {
String remoteDeviceName = device.getName();
Log.d("Scanning", "scan device " + remoteDeviceName);
});
Finally, i found out the solution:
1.For device connected:
Read device name from gatt characteristic org.bluetooth.characteristic.gap.device_name of service org.bluetooth.service.generic_access.
2.For device no connected:
/**
* Get device name from ble advertised data
*/
private LeScanCallback mScanCb = new LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, final int rssi,
byte[] scanRecord) {
final BleAdvertisedData badata = BleUtil.parseAdertisedData(scanRecord);
String deviceName = device.getName();
if( deviceName == null ){
deviceName = badata.getName();
}
}
////////////////////// Helper Classes: BleUtil and BleAdvertisedData ///////////////
final public class BleUtil {
private final static String TAG=BleUtil.class.getSimpleName();
public static BleAdvertisedData parseAdertisedData(byte[] advertisedData) {
List<UUID> uuids = new ArrayList<UUID>();
String name = null;
if( advertisedData == null ){
return new BleAdvertisedData(uuids, name);
}
ByteBuffer buffer = ByteBuffer.wrap(advertisedData).order(ByteOrder.LITTLE_ENDIAN);
while (buffer.remaining() > 2) {
byte length = buffer.get();
if (length == 0) break;
byte type = buffer.get();
switch (type) {
case 0x02: // Partial list of 16-bit UUIDs
case 0x03: // Complete list of 16-bit UUIDs
while (length >= 2) {
uuids.add(UUID.fromString(String.format(
"%08x-0000-1000-8000-00805f9b34fb", buffer.getShort())));
length -= 2;
}
break;
case 0x06: // Partial list of 128-bit UUIDs
case 0x07: // Complete list of 128-bit UUIDs
while (length >= 16) {
long lsb = buffer.getLong();
long msb = buffer.getLong();
uuids.add(new UUID(msb, lsb));
length -= 16;
}
break;
case 0x09:
byte[] nameBytes = new byte[length-1];
buffer.get(nameBytes);
try {
name = new String(nameBytes, "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
break;
default:
buffer.position(buffer.position() + length - 1);
break;
}
}
return new BleAdvertisedData(uuids, name);
}
}
public class BleAdvertisedData {
private List<UUID> mUuids;
private String mName;
public BleAdvertisedData(List<UUID> uuids, String name){
mUuids = uuids;
mName = name;
}
public List<UUID> getUuids(){
return mUuids;
}
public String getName(){
return mName;
}
}
BluetoothDevice.getName() may return null if the name could not be determined. This could be due to any number of factors. Regardless, the name is the friendly name of the device, and shouldn't be used to distinguish it from other devices. Instead, use the hardware address through getAddress().
I know this is old but this more spec-oriented answer may help answer some cases.
In Bluetooth Low Energy, advertisement and scan-response data is only required to have the Bluetooth Address. Advertisement data is how a client BTLE endpoint discovers a service device. A client can request a scan response and get more data. The device name is optional in this data. However, the BTLE spec requires that all Bluetooth Low Energy endpoints support the Generic Access service which is required to support the Device Name characteristic. Unfortunately, to read that characteristic the Android must first connect and do service discovery. If the advertisement/scan response does not provide the information, I do not believe Android connects to the device to get the name. At least I have never seen any indication of connecting without the app specifically requesting a connection. This is not what you want to be required to do if you want to make a decision to connect.
Fortunately, most BTLE devices I have worked with do provide their name in the advertisement or scan response.
Another possibility is that the device may place the name in the scan response part of the advertisement. Depending upon how one has set up Android's BTLE scanner, one might get only the advertisement data and not the scan response. In this case the name will not be found if the device puts it in the scan response. The default scanner settings, however, are such that a scan response must be received before the scan data is passed up to the app.
On Marshmallow, utilize ScanRecord.getDeviceName() to retrieve the local name embedded in the scan record.
BluetoothDevice.getName() is unreliable if the local name is included in a scan response, rather than in the immediate advertising packet.
#Override
public void onScanResult(int callbackType, ScanResult scanResult) {
super.onScanResult(callbackType, scanResult);
// Retrieve device name via ScanRecord.
String deviceName = scanResult.getScanRecord().getDeviceName();
}
I was trying to display name of my RN4020 Bluetooth module and faced the same issue. Found the problem in Microchip's forum:
If you enabled private service or MLDP, the maximum bytes of device
name is 6 bytes, due to the 31 byte advertisement payload limitation.
I had set the device name to 9 characters. Setting the name to 4 bytes fixed the issue.
If you recognize the UUID's of your custom services so you know its your device you can also connect to the device and read its name (if its longer than 6 bytes in my case). This was also suggested in Microchips forum.
http://www.microchip.com/forums/m846328.aspx
I've found that if you query for the device's name immediately after it's picked up at scanning it may return null. To get around this I poll a runnable every second or so on the UI thread a maximum of 3 times (So 3 seconds), and the name is usually resolved by then.
Note, in the snippet provided, the enclosing class implements Runnable, hence why I can pass this into View.postDelayed(Runnable action, long delayMillis)
private static final int MAX_NAME_CHECKS = 3;
private static final int NAME_CHECK_PERIOD = 1000;
int nameChecks;
#Override
public void run() {
resolveName();
}
/**
* Checks for the device name, for a maximum of {#link ViewHolder#MAX_NAME_CHECKS}
* as the name may not have been resolved at binding.
*/
private void resolveName() {
if (device != null) {
String name = device.getName();
boolean isEmptyName = TextUtils.isEmpty(name);
if (isEmptyName) deviceName.setText(R.string.unknown_device);
else deviceName.setText(name);
// Check later if device name is resolved
if (nameChecks++ < MAX_NAME_CHECKS && isEmptyName)
itemView.postDelayed(this, NAME_CHECK_PERIOD);
}
}
For someone hasn't found the solution.
Bluetooth advertisement package has maximum size is 31 bytes. So if your device has long name. It can be truncated.
See: https://devzone.nordicsemi.com/f/nordic-q-a/14/what-s-the-maximum-size-for-an-advertisement-package
If you do want to get correct name of bluetooth device (even long name), please don't use startLeScan(). Instead of it, using method startDiscovery().
Google said: "The discovery process usually involves an inquiry scan of about 12 seconds, followed by a page scan of each device found to retrieve its Bluetooth name.". I've tried and it works like a charm.
See: https://developer.android.com/guide/topics/connectivity/bluetooth
i want to make a modification to my project and right now the project status is.....
it is searches the available WiFi networks and shows the list with info of the network this works properly.Now i want to search and see the details of the devices connected to the network.
Is there any way to find these devices ?
Your comment will be useful for me, Thanks.
You can loop over the IP ranges, and "ping" them.
It is not the best / fastest method (UDP is better) but, it works in many cases.
The sample code below returns the list of the IP addresses connected to the current network.
private int LoopCurrentIP = 0;
public ArrayList<InetAddress> getConnectedDevices(String YourPhoneIPAddress) {
ArrayList<InetAddress> ret = new ArrayList<InetAddress>();
LoopCurrentIP = 0;
String IPAddress = "";
String[] myIPArray = YourPhoneIPAddress.split("\\.");
InetAddress currentPingAddr;
for (int i = 0; i <= 255; i++) {
try {
// build the next IP address
currentPingAddr = InetAddress.getByName(myIPArray[0] + "." +
myIPArray[1] + "." +
myIPArray[2] + "." +
Integer.toString(LoopCurrentIP));
// 50ms Timeout for the "ping"
if (currentPingAddr.isReachable(50)) {
ret.add(currentPingAddr);
}
} catch (UnknownHostException ex) {
} catch (IOException ex) {
}
LoopCurrentIP++;
}
return ret;
}
Would you like to discover a specific device ? Or you need the list of all connected devices? The second I don't think is possible.
EDIT
Discovering specific devices:
Using UDP Broadcast. Some reference can be found here!
There are some protocols that are supported by some devices( routers, HDD, etc...), like UPNP!
If you develop a software on the device which you would like to discover you could create a UDP server listening on a specific port.
Your client will just send a broadcast message on that port and your Server will send a response with the information you need.
Here it is a simple example.
What I want to do is to count 3G traffic and WiFi traffic respectively. Now I know how to do with WiFi. Below is the source code for WiFi. By this way I can count WiFi traffic for all the android phones of all manufactures. But I haven't found a similar way for 3g. Does anyone know?
//to get wifi interface
private static String getProp(String prop){
String output = "";
try{
Class<?> sp = Class.forName("android.os.SystemProperites");
Method get = sp.getMethod("get",String.class);
output = (String)get.invoke(null,prop);
}catch(Exception e){
e.printStackTrace();
}
return output;
}
//to get the traffic from system file
...
...
if (connectinTpe == ConnectivityManager.TYPE_WIFI){
String wifiInterface = getProp("wifi.interface");
if(wifiInterface == null || "".equals(wifiInterface)) wifiInterface = "eth0";
rxFile = "/sys/class/net/" +wifiInterface+ "/statistics/rx_bytes";
txFile = "/sys/class/net/" +wifiInterface+ "/statistics/tx_bytes";
}
...
...
Starting from API level 8 (Android 2.2) there is a class TrafficStats which provides what you need:
Class that provides network traffic statistics. These statistics
include bytes transmitted and received and network packets transmitted
and received, over all interfaces, over the mobile interface, and on a
per-UID basis.
On the older versions you can use the approach you mentioned (i.e. reading file content of /sys/class/net/... files). This blog post contains an excellent mapping between TrafficStats methods and file locations. And this SO post contains the source its author used to read those files values. According to it you should first try to read number from "/sys/class/net/rmnet0/statistics/rx_bytes" file (for "received bytes" value) and if it fails try "/sys/class/net/ppp0/statistics/rx_bytes" instead.
to get the current type of connection you can use the TelephonyManager: http://developer.android.com/reference/android/telephony/TelephonyManager.html
first check if the device is connected to the default mobile data connection and then check the connection type:
if (connectinTpe == ConnectivityManager.TYPE_MOBILE)
{
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
int curConnectionType = tm.getNetworkType();
if(curConnectionType >= /*connection type you are looking for*/)
{
// do what you want
}
}