How to obtain MAC address of WiFi network interface? - java

It seems the java.net.NetworkInterface implementation of android does not have a
byte[] getHardwareAddress() method
http://developer.android.com/reference/java/net/NetworkInterface.html
I've found several forums of people trying to do this with no definitive answer, I need to get a somewhat cross-device UUID, so I can't rely on phone numbers or in ANDROID_ID (which can be overwritten and which I think depends on the user having a google account)
http://developer.android.com/reference/android/provider/Settings.Secure.html#ANDROID_ID
In linux you can use ifconfig or read from /proc/net/arp and you can easily get the Hardware address.
Is there a file in android that I can read?
There has to be a way to get this address since it's shown in the "Settings > About Phone > Status" of the phone.

Late answer, but it can help others with the same "problem".
The answer is really straight forward:
WifiManager wifiMan = (WifiManager) this.getSystemService(
Context.WIFI_SERVICE);
WifiInfo wifiInf = wifiMan.getConnectionInfo();
String macAddr = wifiInf.getMacAddress();
The above code will get you the MAC address of your device, remember to have wifi enabled when grabbing the address. This code snippet should be used in your Activity.

There has to be a way to get this
address since it's shown in the
"Settings > About Phone > Status" of
the phone.
Which means, if nothing else, you can go putter around the Android open source code, perhaps using Google Code Search, to figure out where it pulls that from.
Doing a bit of puttering myself, it would appear it is using getMacAddress() from WifiInfo.

UPDATE:
Beginning Android 6.0, above API will give you constant MAC address for all the devices, which is 02:00:00:00:00:00. Refer below for detailshttp://developer.android.com/about/versions/marshmallow/android-6.0-changes.html Found another post that claims to find MAC address in 6.0, not tested it thoughHow to get Wi-Fi Mac address in Android Marshmallow

On Android Q, there is no way to access mac address anymore.
WifiInfo.getMacAddress() will always return 02:00:00:00:00:00.
And WifiConfiguration.getRandomizedMacAddress() will not available anymore.

Add Following Permission.
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
WifiManager initialize in onCreate.
WifiManager wifiMgr = (WifiManager) getContext().getSystemService(context.WIFI_SERVICE);
Use following function.
public void WI-FI_MAC() {
WifiInfo wifiInfo = wifiMgr.getConnectionInfo();
String macAddress = wifiInfo.getMacAddress();
}

this my code and work well in android 5 +.
public static String getMacAddress() {
try {
List<NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface nif : all) {
if (!nif.getName().equalsIgnoreCase("wlan0")) continue;
byte[] macBytes = nif.getHardwareAddress();
if (macBytes == null) {
return "";
}
StringBuilder res1 = new StringBuilder();
for (byte b : macBytes) {
// res1.append(Integer.toHexString(b & 0xFF) + ":");
res1.append(String.format("%02X:",b));
}
if (res1.length() > 0) {
res1.deleteCharAt(res1.length() - 1);
}
return res1.toString();
}
} catch (Exception ex) {
//handle exception
}
return "";
}

Related

Android BLE - Unable to Write to ESP32

I have been trying to get BLE to work properly. I am needing to connect to an ESP32 and send wifi credentials for the device's initial setup. I have attempted to find code that functions and works correctly but have been unable to do so.
My overall goal is to have the user input the SSID and password, then the next screen called BLEScanner then has a scanner where the user will select the device and press connect. Once the device connects, I am trying to have the application handle the data transfer without the user needing to provide any more input. In the code below, the user inputs the wifi credentials in a previous view that passes the information to BLEScanner.
I am running the application on a LG Nexus 5. It is running Android 6.0.1
I am attempting to use the following code to write to a Gatt characteristic after I discover it. When I get the list, I am parsing through the characteristics that I have discovered and attempting to write to all of the characteristics. To write to the characteristics, I am doing the following. gattCharacteristic is type BluetoothGattCharacteristic. bluetoothGatt is of type BluetoothGatt. HomeBoyEugene is the SSID of a local coffee shop, which is why is is listed in the code at the end of the question.
gattCharacteristic.setValue("SSID_AS_STRING");
gattCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
bluetoothGatt.writeCharacteristic(gattCharacteristic);
I have noticed some strange behavior while trying to get this to work correctly. The first is that when I perform a permissions check, ActivityCompat.checkSelfPermission(this, BLUETOOTH_CONNECT) does not return as PERMISSION_GRANTED. I have tried to include methods to grant the permissions but they are not working. I have also included the permission in my Manifest, using the following block.
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
This is the segment of code that I am using to try to get permissions for BLUETOOTH_CONNECT:
ActivityCompat.requestPermissions(BLEScanner.this, new String[] { BLUETOOTH_CONNECT }, 0);
Okay here's where we get into the confusing behavior. I'm using the following block to read the value of the characteristic and convert it into a string so I can print it into Logcat in Android Studio
byte[] hex2 = gattCharacteristic.getValue();
String str2 = new String(hex2, StandardCharsets.UTF_8);
When I perform this operation, it is returning the value that I am attempting to write to it, i.e. SSID_AS_STRING. However, the ESP32 is not recognizing a write event. The ESP will display on its console whenever a write event occurs and we have verified that the ESP code works with other third party apps. I am trying to figure out now why it would seem that I am writing to the characteristics on my end and that I am able to read the value that I am writing to it, but the ESP is not actually writing to it.
Below is a large snippet of the code. I have a lot of print statements throughout, but figured you would like to see everything in context.
private void displayGattServices(List<BluetoothGattService> gattServices) {
if (gattServices == null) return;
String mWriteValue = "Testing";
Log.i("gattServices", String.valueOf(gattServices));
// Loops through available GATT Services.
for (BluetoothGattService gattService : gattServices) {
final String uuid = gattService.getUuid().toString();
System.out.println("Service discovered: " + uuid);
BLEScanner.this.runOnUiThread(new Runnable() {
public void run() {
Log.i("service", "Service discovered: " + uuid + "\n");
}
});
new ArrayList<HashMap<String, String>>();
List<BluetoothGattCharacteristic> gattCharacteristics =
gattService.getCharacteristics();
// Loops through available Characteristics.
for (BluetoothGattCharacteristic gattCharacteristic :
gattCharacteristics) {
final String charUuid = gattCharacteristic.getUuid().toString();
//System.out.println("Characteristic discovered for service: " + charUuid);
gattCharacteristic.setValue("HomeBoyEugene");
gattCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
if (ActivityCompat.checkSelfPermission(this, BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
Log.i("Permission Check","Checking Permissions for writeCharacteristic");
ActivityCompat.requestPermissions(BLEScanner.this, new String[] { BLUETOOTH_CONNECT }, 0);
}
bluetoothGatt.writeCharacteristic(gattCharacteristic);
Log.i("characteristics", "Characteristic discovered for service: " + charUuid + "\n");
Log.i("read characteristics", String.valueOf(bluetoothGatt.readCharacteristic(gattCharacteristic)));
byte[] hex2 = gattCharacteristic.getValue();
String str2 = new String(hex2, StandardCharsets.UTF_8);
Log.i("value", String.valueOf(str2));
Log.i("spacer", "----------------------------------------");
}
Log.i("BREAK","=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
// Second loop to try to read what was written to the characteristics in the previous for loop
for (BluetoothGattCharacteristic gattCharacteristic :
gattCharacteristics) {
byte[] hex2 = gattCharacteristic.getValue();
String str2 = new String(hex2, StandardCharsets.UTF_8);
Log.i("value", String.valueOf(str2));
}
Log.i("BREAK","=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=/");
}
}
Any and all help is much appreciated. I don't really know how to word what I'm asking but I'm out of ideas on how to continue with debugging this. Thanks!

No IMEI for Android Developers in Android 10

As Android is serious about security and trying to make new android versions more secure, its becoming tough for developers to keep up-to date with new security features and find old methods alternatives to make their app compatible with old features.
This question is about IMEI in New Android 10!
The old method was super easy to get IMEI number by using below code
String deviceId = "";
if (Build.VERSION.SDK_INT >= 26) {
if (telMgr.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
deviceId = telMgr.getMeid();
} else if (telMgr.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) {
deviceId = telMgr.getImei();
} else {
deviceId = ""; // default!!!
}
} else {
deviceId = telMgr.getDeviceId();
}
In New Android 10 it is now restricted to get IMEI number. According to android documentation
apps must have the READ_PRIVILEGED_PHONE_STATE privileged permission in order to access the device's non-resettable identifiers, which include both IMEI and serial number.
The problem is that when we try to ask run time permissions with
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE
My compiler does not recognize this permissions and i got error on this line but when i ask this permission in manifest file it does recognize this line but through warning that this permission is only for system apps.
I want to make my app compatible with Android 10 and want to get IMEI. How can i get IMEI number in Android 10 without becoming device owner or profile owner ?
Only device owner apps can read unique identifiers or your app must be a system app with READ_PRIVILEGED_PHONE_STATE. You can't ask this permission for a normal app.
Android 10 Restricted developer to Access IMEI number.
You can have a alternate solution by get Software ID. You can use software id as a unique id. Please find below code as i use in Application.
public static String getDeviceId(Context context) {
String deviceId;
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
deviceId = Settings.Secure.getString(context.getContentResolver(),Settings.Secure.ANDROID_ID);
}else {
final TelephonyManager mTelephony = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
if (mTelephony.getDeviceId() != null) {
deviceId = mTelephony.getDeviceId();
} else {
deviceId = Settings.Secure.getString(
context.getContentResolver(),
Settings.Secure.ANDROID_ID);
}
}
return deviceId;
}
To get a unique identifier you can use FirebaseInstanceId.getInstance().getId(); or String uniqueID = UUID.randomUUID().toString();. Have a look here for best practices https://developer.android.com/training/articles/user-data-ids#java

Java IP Address,MAC address return with name of device [duplicate]

This question already has an answer here:
Android Quickly Find All Local Devices on Network
(1 answer)
Closed 6 years ago.
I am trying to code in android to return the name of all devices and their ip on the wifi. I am having trouble on how to approach this. All of the examples online return only the localhost and its information. i.e.
try {
InetAddress localhost = InetAddress.getLocalHost();
System.out.println(" IP Addr: " + localhost.getHostAddress());
// Just in case this host has multiple IP addresses....
InetAddress[] allMyIps = InetAddress.getAllByName(localhost.getCanonicalHostName());
if (allMyIps != null && allMyIps.length > 1) {
System.out.println(" Full list of IP addresses:");
for (int i = 0; i < allMyIps.length; i++) {
System.out.println(" " + allMyIps[i]);
}
}
} catch (UnknownHostException e) {
System.out.println(" (error retrieving server host name)");
}
try {
System.out.println("Full list of Network Interfaces:");
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
NetworkInterface intf = en.nextElement();
System.out.println(" " + intf.getName() + " " + intf.getDisplayName());
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
System.out.println(" " + enumIpAddr.nextElement().toString());
}
}
} catch (SocketException e) {
System.out.println(" (error retrieving network interface list)");
}
This is not necessarily What I want, since I want to return all of the devices on the wifi.
I don't know how to go about this.
please help, thank you !
WifiManager This class provides the primary API for managing all aspects of Wi-Fi connectivity. Get an instance of this class by calling Context.getSystemService(Context.WIFI_SERVICE). It deals with several categories of items:
The list of configured networks. The list can be viewed and updated, and attributes of individual entries can be modified.
The currently active Wi-Fi network, if any. Connectivity can be established or torn down, and dynamic information about the state of the network can be queried.
Results of access point scans, containing enough information to make decisions about what access point to connect to.
It defines the names of various Intent actions that are broadcast upon any sort of change in Wi-Fi state.
WifiInfo Describes the state of any Wifi connection that is active or is in the process of being set up.
Example:
WifiManager wifiMgr = (WifiManager) getSystemService(WIFI_SERVICE);
WifiInfo wifiInfo = wifiMgr.getConnectionInfo();
int ip = wifiInfo.getIpAddress();
String ipAddress = Formatter.formatIpAddress(ip);
String macAddress = wifiInfo.getMacAddress();
Ensure you have modified your manifest with the following:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
Sources:
1. WifiManager
2. WifiInfo API

Android: How to get the Serial Number as shown in About Device, Status with Java

On my Android Tablet I go to Settings -> About Device -> Status
In this screen I find a serial number with a length of 11 characters.
I would like to read this serial number with Java.
Anyone an idea how to do that?
Use
String x = Build.SERIAL
For more details check this out.
This is the device serial number.
For MDN or MEID of the device depending on which radio the phone uses (GSM or CDMA), try
TelephonyManager tManager = (TelephonyManager)myActivity.getSystemService(Context.TELEPHONY_SERVICE);
String uid = tManager.getDeviceId();
and include the permission in the manifest file:
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
Very old question, but perhaps the solution from dev here still helps:
public static String getManufacturerSerialNumber() {
String serial = null;
try {
Class<?> c = Class.forName("android.os.SystemProperties");
Method get = c.getMethod("get", String.class, String.class);
serial = (String) get.invoke(c, "ril.serialnumber", "unknown");
} catch (Exception ignored) {}
return serial;
}
Try this:
TextView tv = (TextView)findViewById(R.id.text);
String serial = Build.SERIAL;
tv.setText(serial);

Change the Android bluetooth device name

I know it's possible to get the local device name as described in the solution to this question Display Android Bluetooth Device Name
What I'm interested in knowing is, can I change the local buetooth name (the one other devices see when I'm in discovery mode) programaticlly. I know you can change it by hand, but I'm writing and app and I want to be able to change the name (add a simple flag) so other devices with the same application can scan and instantly know if the phone is also running the app.
tl;dr: How can I change the bluetooth device name on android?
Yes you can change your device name using setName(String name) of BluetoothAdapter type.Following is the sample code:
private BluetoothAdapter bluetoothAdapter = null;
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
void ChangeDeviceName(){
Log.i(LOG, "localdevicename : "+bluetoothAdapter.getName()+" localdeviceAddress : "+bluetoothAdapter.getAddress());
bluetoothAdapter.setName("NewDeviceName");
Log.i(LOG, "localdevicename : "+bluetoothAdapter.getName()+" localdeviceAddress : "+bluetoothAdapter.getAddress());
}
Thanks for the original answer, here are a few things I found when implementing that might help someone else out.
1) BT has to be enabled for setName() to work.
2) It takes time for BT to Enable. ie. you Can't just call enable() then setName()
3) It takes time for the name to "sink in". ie. you can't call getName() right after setName() and expect the new name.
So, here is a snippet of code I came up with to use a runnable to get the job done in the background. It is also time bound to 10seconds, so it won't run forever if there is a problem.
Finally, this is part of our power on check, and we normally leave BT disabled (due to battery). So, I turn BT back off after, you may not want to do that.
// BT Rename
//
final String sNewName = "Syntactics";
final BluetoothAdapter myBTAdapter = BluetoothAdapter.getDefaultAdapter();
final long lTimeToGiveUp_ms = System.currentTimeMillis() + 10000;
if (myBTAdapter != null)
{
String sOldName = myBTAdapter.getName();
if (sOldName.equalsIgnoreCase(sNewName) == false)
{
final Handler myTimerHandler = new Handler();
myBTAdapter.enable();
myTimerHandler.postDelayed(
new Runnable()
{
#Override
public void run()
{
if (myBTAdapter.isEnabled())
{
myBTAdapter.setName(sNewName);
if (sNewName.equalsIgnoreCase(myBTAdapter.getName()))
{
Log.i(TAG_MODULE, "Updated BT Name to " + myBTAdapter.getName());
myBTAdapter.disable();
}
}
if ((sNewName.equalsIgnoreCase(myBTAdapter.getName()) == false) && (System.currentTimeMillis() < lTimeToGiveUp_ms))
{
myTimerHandler.postDelayed(this, 500);
if (myBTAdapter.isEnabled())
Log.i(TAG_MODULE, "Update BT Name: waiting on BT Enable");
else
Log.i(TAG_MODULE, "Update BT Name: waiting for Name (" + sNewName + ") to set in");
}
}
} , 500);
}
}
To change the bluetooth name properly you need to take care of following things:
1) You need following permissions:
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
2) Check the bluetooth state from adapter as you can only change the name of bluetooth is turned on.
val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(bluetoothAdapter.state == BluetoothAdapter.STATE_ON){
bluetoothAdapter.setName("NewDeviceName");
}
3) If the bluetooth is not turned on then you can turn it on with the following command:
bluetoothAdapter.enable()
4) Last thing, please don't use static timers to wait for bluetooth state changes instead the proper way is that you can register for android.bluetooth.adapter.action.STATE_CHANGED broadcast and useBluetoothAdapter.EXTRA_STATE to get the new state of bluetooth whenever it is changed.
Note: Not all devices behave the same when it comes to bluetooth and changing the name due to caching and hw address, so never expect same outcome from all devices.

Categories