How to Increase Bluetooth pairing window timeout in Android - android

I am trying to increase the timeout of the bluetooth pairing window (currently the window stays for only few seconds). Is there any way to achieve this action ?
I have already tried methods from these stackoverflow links :
How to pair Bluetooth device programmatically Android
How to programmatically pair a bluetooth device on Android
Android bluetooth, override pairing prompts
None of the above links have the answer what i am looking for, is there anybody to help me to solve this problem ? is there any method to increase the time-out of the bluetooth pairing screen

Ty this, the Pairing window will never timeout
public void pairDevice(final BluetoothDevice device) {
String ACTION_PAIRING_REQUEST = "android.bluetooth.device.action.PAIRING_REQUEST";
Intent intent = new Intent(ACTION_PAIRING_REQUEST);
String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE";
intent.putExtra(EXTRA_DEVICE, device);
String EXTRA_PAIRING_VARIANT = "android.bluetooth.device.extra.PAIRING_VARIANT";
int PAIRING_VARIANT_PIN = 0;
intent.putExtra(EXTRA_PAIRING_VARIANT, PAIRING_VARIANT_PIN);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}

Related

How to get Bluetooth Headset battery level?

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())
}

Using fetchUuidsWithSdp() to prevent friendly name caching

DEFINITION:
My non-android device (NAD) is a Bluetooth device who loops its name from 60 to 0 and resets in an infinite fashion.
OBJECTIVE:
What I'm trying is to do is to have my android device as closely as possible detect that countdown and initiate an alarm as close to that of the NAD counter as possible.
I'm doing this by getting the native BluetoothAdapter of my device to startDiscovery() manually by tying the function to onscreen buttons and keeping an eye on the toasts I set through my BroadcastReceiver, which updates onscreen Textviews Which enables me to monitor what my device is receiving in real-time
REQUIREMENT:
System & resource efficiency is not a concern in this context.
PROBLEM:(Keep an eye out for PART 1 and PART 2 in the code)
I'm not sure how using fetchUuidsWithSdp() is helping me since the TextView it's updating remains empty and the Textview getting populated by the EXTRA_NAME extra from intent returning action ACTION_NAME_CHANGED is the cached, initial discovery name (ie. my application is not reading a name after initial discovery).
my code can be found below
Sorry for any newbie mistakes,I'm trying my best :)
public class BTBroadcastReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
//pulling the action name from the broadcasted intent
String action = intent.getAction();
if(BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)){
sToaster("StartedD");//show toast that Discovery has started
}
else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){
sToaster("EndedD");//show toast signifying end of discovery
/*
if(notfound){
mBTAdapter.startDiscovery();
}*/
}
else if(BluetoothDevice.ACTION_FOUND.equals(action)){
//when a device is found
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
//make sure it's indeed my NAD device by checking MAC address
if(device.getAddress().equals(MACAddress)){
if(notfound){
//show device name on screen
sToaster("FOUND DEvice");
notfound = false;
NAD = device;
NameShower.setText(device.getName());
}
else{
//do nothing if it's the second time the device is found
}
}
}
else if(BluetoothDevice.ACTION_NAME_CHANGED.equals(action)){
//name changed
BluetoothDevice foundDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
//make sure it's indeed my NAD device
if(foundDevice.equals(NAD)){
sToaster("Name Change!"); //show on screen that the name change intent has been caught
//PART1
//to prevent caching of the old device name StackOverflow article
//advised using this function i don't totally understand yet
//NAD.fetchUuidsWithSdp();
//either commented or not commented the outcome is the same (no refresh of the name)
//PART2
//tried showing the new name two different ways below, neither of which are effective
//by inspecting the TextViews on-screen
NameShower.setText(foundDevice.getName());
EventView.setText(intent.getStringExtra(BluetoothDevice.EXTRA_NAME));
}
}
}
};
I have worked on a bluetooth project and what I perceived was that the discovery process should be in an Intent which can be left registered in the background. And to discover the devices in range, you just need to invoke the BTDevice.startDiscovery() to search them.
Generally the startDiscovery() drains battery if enabled continuously.
If you want, I can edit this post to share a snipet that I used to scan for devices.
Hope this helps !

createRfcommSocketToServiceRecord works but listenUsingRfcommWithServiceRecord does not

I am trying to control a Hands-Free link with my device. The following works just fine:
UUID HFP_UUID_GET_HF = UUID.fromString("0000111E-0000-1000-8000-00805F9B34FB");
BluetoothSocket aBluetoothSocket = mDevice
.createRfcommSocketToServiceRecord(HFP_UUID_GET_HF);
and I get a socket that I can read and right to. No problem. However, I also want to listen for an incoming connection and get that socket. I tried this:
UUID HFP_UUID = UUID.fromString("0000111F-0000-1000-8000-00805F9B34FB");
UUID HFP_UUID_GET_HF = UUID.fromString("0000111E-0000-1000-8000-00805F9B34FB");
BluetoothServerSocket tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord("HFP", HFP_UUID);
BluetoothSocket aBluetoothSocket = tmp.accept();
However, even though the two devices connect I never get a socket back. BTW if I use the UUID that starts with 111E in this second code block here I get a service discovery io error, which makes sense -- I know that my device is using uuid 111F and the other device uses UUID 111E.
Has anyone ran into this issue before? I need to be able to have complete control over all data that gets sent from the phone on that rfcomm channel. I cannot use reflection ; i.e.
Class<?>[] args = new Class[] { int.class };
int HFP_CHANNEL = 10;
Method listenOn = BluetoothAdapter.class.getDeclaredMethod("listenUsingRfcommOn", args);
BluetoothServerSocket my_server = (BluetoothServerSocket) (listenOn.invoke(mBluetoothAdapter,
new Object[] { HFP_CHANNEL }));
BluetoothSocket m_BluetoothSocket = my_server.accept();
because that also throws an io error -- channel already in use, unless anyone knows a way to turn off the hands-free system service. Afaik that is part of bluetoothd (Im using Android 4.1 here) and I need that to remain running (Im not sure if I even can turn it off)

How to get access to the BluetoothPairingDialog.java in android?

Is there any way to forcefully click on "pair button" whenever the Bluetooth pairing dialog appears?
I don't know how to get access to the pairing dialog, but I was able to "force" pairing in the following way:
1) register a BroadcastReceiver for the action:
android.bluetooth.device.action.PAIRING_REQUEST
2) once the action is received, "force" the PIN using reflection:
String DEVICE_PIN = "12345";
final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (intent.getAction().equals("android.bluetooth.device.action.PAIRING_REQUEST")) {
byte[] pin = (byte[]) BluetoothDevice.class.getMethod("convertPinToBytes", String.class).invoke(BluetoothDevice.class, ARDUINO_PIN);
BluetoothDevice.class.getMethod("setPin", byte[].class).invoke(device, pin);
}
It worked for me on GB and ICS (don't know if it works on newer releases).

Setting airplane mode does not completely work

I've written the code below to set the phone into airplane mode to save power. The devices is being used as a WiFi-Hotspot to relay data from some sensors in a village in Indonesia. The sensors send their data at the same time so I just need to come out of airplane mode for five minutes at midnight and then reenter airplane mode.
The problem is the cellular radio is not shut off and the airplane icon does not appear. Though the the phone reports its status as airplane_mode on, it is still possible to call it. Other widgets in the marketplace seem to fare no better. I've tried "Airplane Mode Wi-Fi Tool". It too can not get the airplane icon to appear nor disable cell radio. When watching LogCat while using the device settings to go to Airplane mode, I can see that much more is happening than when trying from the program.
If I load my program on a Droid, this code works as expected. AIRPLANE_MODE_RADIOS is set to cell, bluetooth, wifi.
The offending device is a Samsung Galaxy 5, I5500 tested with:
-Froyo 2.2 build FROYO.UYJP2
-Froyo 2.2.1 build FROYO.UYJPE
One interesting side note: if I programmatically set airplane mode and then power cycle the device, it comes up in full airplane mode, rejects incoming calls etc.
Do others have similar stories with this or other devices? Is there a way to specifically turn off cell only?
public static void setAirplaneMode(Context context, boolean status) {
boolean isAM = Settings.System.getInt(context.getContentResolver(),
Settings.System.AIRPLANE_MODE_ON, 0) != 0;
String radios = Settings.System.getString(context.getContentResolver(),
Settings.System.AIRPLANE_MODE_RADIOS);
//This line is reporting all radios affected but annunciator does not seem to think so. Does not show airplane
Wake.logger("Airplane mode is: " + isAM + " changing to " + status + " For radios: " + radios, false);
// It appears Airplane mode should only be toggled. Don't reset to
// current state.
if (isAM && !status) {
Settings.System.putInt(context.getContentResolver(),
Settings.System.AIRPLANE_MODE_ON, 0);
Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intent.putExtra("state", 0);
context.sendBroadcast(intent);
return;
}
if (!isAM && status) {
Settings.System.putInt(context.getContentResolver(),
Settings.System.AIRPLANE_MODE_ON, 1);
Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intent.putExtra("state", 1);
context.sendBroadcast(intent);
return;
}
}
Classic bit twister error. The extra data argument in the broadcast intent needed to be true/false, not 1/0. Ugh!!!
intent.putExtra("state", true); //Not 1!!
One phone worked another didn't. Now both do.

Categories

Resources