I need to obtain device's Bluetooth MAC address.
Before Android 6 it was easy as BluetoothAdapter.getDefaultAdapter().getAddress(). After that we had to use a simple workaround: String macAddress = android.provider.Settings.Secure.getString(context.getContentResolver(), "bluetooth_address");. But later(in Android 8 AFAIK) it was also closed, but another workaround was discovered:
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
String bluetoothMacAddress = "";
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M){
try {
Field mServiceField = bluetoothAdapter.getClass().getDeclaredField("mService");
mServiceField.setAccessible(true);
Object btManagerService = mServiceField.get(bluetoothAdapter);
if (btManagerService != null) {
bluetoothMacAddress = (String) btManagerService.getClass().getMethod("getAddress").invoke(btManagerService);
}
} catch (NoSuchFieldException e) {
} catch (NoSuchMethodException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
} else {
bluetoothMacAddress = bluetoothAdapter.getAddress();
}
But starting from Android 8.1 trying to access that method throws exception:
java.lang.reflect.InvocationTargetException Caused by: java.lang.SecurityException: Need LOCAL_MAC_ADDRESS permission: Neither user 10141 nor current process has android.permission.LOCAL_MAC_ADDRESS, which means that this method requires permission, available only for system-level apps.
So the question is if there is any workaround to get Bluetooth address in Android 8.1?
Related
Recently I modified my Android code for Android-12.
I was not having android-12 related bluetooth connect permissions for my API. So I handled as below :
public List<BluetoothDevice> getHfpDevices() {
List<BluetoothDevice> hfpConnectedDevs = new ArrayList<>();
try {
if (mHeadsetService != null) {
hfpConnectedDevs = mHeadsetService.getConnectedDevices();
}
} catch (SecurityException ex) {
Log.e(TAG, "Security Exception in Android-12", ex);
}
return hfpConnectedDevs;
}
Does this catch the securityException thrown when this API is accessed ? or do I need to handle the Exception itself ?
catch (Exception ex) {
PS : I don't want to add the requestPermission flow as of now. I just need to solve the exception raised when this API is called
I can't find in the doc how to retrieve if device is configured as a portable hotspot.
I've read How to detect if a network is (configured as) a mobile hotspot on Android? but I don't know if the feature has been implemented?
You can use below code to check if Tethering is enabled or not on your device:
private static Method isWifiApEnabledMethod;
public static boolean isWifiApEnabled(WifiManager wifiManager) {
if (isWifiApEnabledMethod == null) {
try {
isWifiApEnabledMethod = wifiManager.getClass().getDeclaredMethod("isWifiApEnabled");
isWifiApEnabledMethod.setAccessible(true); //in the case of visibility change in future APIs
} catch (NoSuchMethodException e) {
Log.w(TAG, "Can't get method by reflection", e);
}
}
if (isWifiApEnabledMethod != null) {
try {
return (Boolean) isWifiApEnabledMethod.invoke(wifiManager);
} catch (IllegalAccessException e) {
Log.e(TAG, "Can't invoke method by reflection", e);
} catch (InvocationTargetException e) {
Log.e(TAG, "Can't invoke method by reflection", e);
}
}
return false;
}
Don't forget to add below permission in AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
For the SO link mentioned above in question:
This feature is not available i.e. has not been implemented.
For more information check this link where Google officially marked the status as Status: Won't Fix (Obsolete)
Hope this will help you. Thanks!
As shown in this picture here :
BLE Scanner getting Alias if exists
I am trying to do the same on my app. I'm able to get the device name and pretty much all the information that i need, but i'm unable to get the Alias, knowing by the android App BLE scanner that first : it exists, and second : it's possible to get it.
I did try to use that method :
try {
Method m = device.getNative().getClass().getMethod("getAlias");
Object res = null;
if (m != null ) {
res = m.invoke(device.getNative());
}
if(res != null)
Alias = res.toString();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
if(name == null)
name = device.getName_debug();
Where device.getNative() access the lower level instance of the BluetoothDevice.
But it's returning the device name not the alias.
Note : Maybe the "Alias" is not the right word to describe the variable that i'm trying to access.
If someone could help i would appreciate.
I have gone through some of the NFC related topics. But I did not find a clear and simple way to work with it or using NFC?
Another question is How can we recognize the device supports NFC or not,
Is there any code for that?
what makes it different from bluetooth?
All suggestions will be appreciated.
To check if device support NFC :
NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE);
NfcAdapter adapter = manager.getDefaultAdapter();
if (adapter != null && adapter.isEnabled()) {
//Yes NFC available
}else{
//Your device doesn't support NFC
}
And here is all for NFC : https://developer.android.com/guide/topics/connectivity/nfc/index.html
If you have rooted device you can easily toggle NFC mode:
public static boolean powerNfc(boolean isOn, Context context) {
boolean success = false;
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(context);
if (nfcAdapter != null) {
Class<?> NfcManagerClass;
Method setNfcEnabled;
try {
NfcManagerClass = Class.forName(nfcAdapter.getClass().getName());
setNfcEnabled = NfcManagerClass.getDeclaredMethod(isOn ? "enable" : "disable");
setNfcEnabled.setAccessible(true);
success = (Boolean) setNfcEnabled.invoke(nfcAdapter);
} catch (ClassNotFoundException e) {
} catch (NoSuchMethodException e) {
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
}
return success;
}
You also need to add permission write secure settings.
It's already tested.
I am developing an application which needs to send sms in pdu mode.
I am using this code but it gives NoSuchElementException on first line.
try {
Method m2 = sms.getClass().getDeclaredMethod("sendRawPdu", pdu.getClass(), pdu.getClass(), piSent.getClass(), piDelivered.getClass());
m2.setAccessible(true);
SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(null, "", "Test", false);
Object[] arrayOfObject2 = new Object[5];
arrayOfObject2[0] = pdus.encodedScAddress;
arrayOfObject2[1] = pdus.encodedMessage;
arrayOfObject2[2] = piSent;
arrayOfObject2[3] = piDelivered;
arrayOfObject2[4] = null;
try {
m2.invoke(sms, arrayOfObject2);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
Any help will be appreciated.
I tried it on Lollipop, but there is no method related to sendRawPdu
Do a little more thing just print the list of methods available to check if there is any method related to sendRawPdu
Method[] methods = sms.getClass().getDeclaredMethods();
boolean methodAvailable = false;
for(Method m : methods) {
Log.d("SmsManager", m.toString());
if(m.toString().contains("sendRawPdu")) {
methodAvailable = true;
}
}
now you have methodAvailable, if it is true you can send Raw PDU, if not then you can't. sendRawPdu was available before JellyBeans. Try to run this on Pre JellyBeans devices.