After rooting and requesting superuser permission what do I need to do to enable/disable gps in my application?
ON Rooted Device try this just use su for enabling gps on high accuracy mode
Process proc=Runtime.getRuntime().exec(new String[]{"su",
"pm grant com.your_app_packagename android.permission.WRITE_SECURE_SETTINGS",
"settings put secure location_providers_allowed gps,network,wifi"});
proc.waitFor();
Run these command on background thread :)
further you can refer to this link here
You aren't supposed to to protect the privacy of the user. However it is possible by exploiting a bug. See this for how:
How can I enable or disable the GPS programmatically on Android?
Note that this may not work on all versions of Android - see
https://android.googlesource.com/platform/packages/apps/Settings/+/4b21f7cd9424eeb83838071a4419912ee5d5e41d
where they indicate it has been fixed but i'm not sure which versions have the fix (if any).
This code works on ROOTED phones if the app is moved to /system/aps, and they have the following permissions in the manifest:
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
Code
private void turnGpsOn (Context context) {
beforeEnable = Settings.Secure.getString (context.getContentResolver(),
Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
String newSet = String.format ("%s,%s",
beforeEnable,
LocationManager.GPS_PROVIDER);
try {
Settings.Secure.putString (context.getContentResolver(),
Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
newSet);
} catch(Exception e) {}
}
private void turnGpsOff (Context context) {
if (null == beforeEnable) {
String str = Settings.Secure.getString (context.getContentResolver(),
Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
if (null == str) {
str = "";
} else {
String[] list = str.split (",");
str = "";
int j = 0;
for (int i = 0; i < list.length; i++) {
if (!list[i].equals (LocationManager.GPS_PROVIDER)) {
if (j > 0) {
str += ",";
}
str += list[i];
j++;
}
}
beforeEnable = str;
}
}
try {
Settings.Secure.putString (context.getContentResolver(),
Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
beforeEnable);
} catch(Exception e) {}
}
Related
Pre Marshmallow my app would obtain it's device MAC address via BluetoothAdapter.getDefaultAdapter().getAddress().
Now with Marshmallow Android is returning 02:00:00:00:00:00.
I saw some link(sorry not sure where now) that said you need to add the additional permission
<uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS"/>
to be able to get it. However it isn't working for me.
Is there some additional permission needed to get the mac address?
I am not sure it is pertinent here but the manifest also includes
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
So is there a way to get the local bluetooth mac address?
zmarties is right but you can still get the mac address via reflection or Settings.Secure:
String macAddress = android.provider.Settings.Secure.getString(context.getContentResolver(), "bluetooth_address");
Access to the mac address has been deliberately removed:
To provide users with greater data protection, starting in this release, Android removes programmatic access to the device’s local hardware identifier for apps using the Wi-Fi and Bluetooth APIs.
(from Android 6.0 Changes)
You can access Mac address from the file
"/sys/class/net/" + networkInterfaceName+ "/address" ,where networkInterfaceName can be wlan0 or eth1.But Its permission may be read-protected,so it may not work in some devices.
I am also attaching the code part which i got from SO.
public static String getWifiMacAddress() {
try {
String interfaceName = "wlan0";
List<NetworkInterface> interfaces = Collections
.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface intf : interfaces) {
if (!intf.getName().equalsIgnoreCase(interfaceName)) {
continue;
}
byte[] mac = intf.getHardwareAddress();
if (mac == null) {
return "";
}
StringBuilder buf = new StringBuilder();
for (byte aMac : mac) {
buf.append(String.format("%02X:", aMac));
}
if (buf.length() > 0) {
buf.deleteCharAt(buf.length() - 1);
}
return buf.toString();
}
} catch (Exception exp) {
exp.printStackTrace();
}
return "";
}
First the following permissions have to be added to Manifest;
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS" />
Then,
public static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS = "bluetooth_address";
String macAddress = Settings.Secure.getString(getContentResolver(), SECURE_SETTINGS_BLUETOOTH_ADDRESS);
After that the application has to be signed with OEM / System key. Tested and verified on Android 8.1.0.
Please use the below code to get the bluetooth mac address. let me know if any issues.
private String getBluetoothMacAddress() {
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();
}
return bluetoothMacAddress;
}
Getting the MAC address via reflection can look like this:
private static String getBtAddressViaReflection() {
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Object bluetoothManagerService = new Mirror().on(bluetoothAdapter).get().field("mService");
if (bluetoothManagerService == null) {
Log.w(TAG, "couldn't find bluetoothManagerService");
return null;
}
Object address = new Mirror().on(bluetoothManagerService).invoke().method("getAddress").withoutArgs();
if (address != null && address instanceof String) {
Log.w(TAG, "using reflection to get the BT MAC address: " + address);
return (String) address;
} else {
return null;
}
}
using a reflection library (net.vidageek:mirror) but you'll get the idea.
Since below method return null for android O.
String macAddress = android.provider.Settings.Secure.getString(context.getContentResolver(), "bluetooth_address");
I found new way to get Bluetooth Mac address, you can try by using below command line.
su strings /data/misc/bluedroid/bt_config.conf | grep Address
NOTE: In my case, i was working with root device so my app has super user permission.
As it turns out, I ended up not getting the MAC address from Android. The bluetooth device ended up providing the Android device MAC address, which was stored and then used when needed. Yeah it seems a little funky but on the project I was on, the bluetooth device software was also being developed and this turned out to be the best way to deal with the situation.
Worked great
private String getBluetoothMacAddress() {
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
String bluetoothMacAddress = "";
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 | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignore) {
}
return bluetoothMacAddress;
}
I'm trying to read the data already stored by me in the Arduino kit, I'm using the physicaloid library to achieve this. I tested the kit (reading data) by connecting it to my PC using the Type B USB cable provided by Arduino itself and using Tera Term. The data begins to transfer after I press '#' on the keyboard (specific to our implementation).
But when I connect it my Android tablet and use the test project by physicaloid to open a device and start communicating, every time I click 'open' it shows a Toast saying it cannot open. I give permission to access the USB device every time it prompts me. Here is the sample program which I had created to read the data:
if(mPhysicaloid.open()){
Toast.makeText(getBaseContext(), "communicating", Toast.LENGTH_SHORT).show();
String signalToStart = new String("#");
byte[] bufToWrite = signalToStart.getBytes();
mPhysicaloid.write(bufToWrite, bufToWrite.length);
byte[] buf = new byte[255];
mPhysicaloid.read(buf);
String data = new String(buf);
tvResult.setText(data);
mPhysicaloid.close();
}
else
Toast.makeText(getBaseContext(), "no communication with device", Toast.LENGTH_LONG).show();
Now here's what I want to know about the data coming from the Arduino USB cable: is it in the RS232 format where the Android device is not able to understand (I don't know, I may be making a blunder here by asking this data format) or is it in the USB data format that is suitable for the Android device to understand? Please help, I have searched over this the whole day. What can I do to open the device and communicate?
I finally got the idea of reading the data from serial USB device. So I thought I'd share it:
First, get all the USB devices attached (if more than one) and get a suitable interface and search for endpoints to communicate with. While initializing the USB device make sure you consider the USB device which you really want to communicate with. You can do that by considering product id and Vendor id.
The code for doing the above described..
private boolean searchEndPoint() {
usbInterface = null;//class level variables, declare these.
endpointOut = null;
endpointIn = null;
Log.d("USB","Searching device and endpoints...");
if (device == null) {
usbDevices = usbManager.getDeviceList();
Iterator<UsbDevice> deviceIterator = usbDevices.values().iterator();
while (deviceIterator.hasNext()) {
UsbDevice tempDevice = deviceIterator.next();
/**Search device for targetVendorID(class level variables[vendorId = SOME_NUMBER and productId=SOME_NUMBER] which u can find) and targetProductID.*/
if (tempDevice .getVendorId() == vendorId) {
if (tempDevice .getProductId() == productId) {
device = tempDevice ;
}
}
}
}
if (device == null){
Log.d("USB","The device with specified VendorId and ProductId not found");
return false;
}
else
Log.d("USB","device found");
/**Search for UsbInterface with Endpoint of USB_ENDPOINT_XFER_BULK,
*and direction USB_DIR_OUT and USB_DIR_IN
*/
try{
for (int i = 0; i < device.getInterfaceCount(); i++) {
UsbInterface usbif = device.getInterface(i);
UsbEndpoint tOut = null;
UsbEndpoint tIn = null;
int tEndpointCnt = usbif.getEndpointCount();
if (tEndpointCnt >= 2) {
for (int j = 0; j < tEndpointCnt; j++) {
if (usbif.getEndpoint(j).getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
if (usbif.getEndpoint(j).getDirection() == UsbConstants.USB_DIR_OUT) {
tOut = usbif.getEndpoint(j);
} else if (usbif.getEndpoint(j).getDirection() == UsbConstants.USB_DIR_IN) {
tIn = usbif.getEndpoint(j);
}
}
}
if (tOut != null && tIn != null) {
/** This interface have both USB_DIR_OUT
* And USB_DIR_IN of USB_ENDPOINT_XFER_BULK
*/
usbInterface = usbif;
endpointOut = tOut;
endpointIn = tIn;
}
}
}
if (usbInterface == null) {
Log.d("USB","No suitable interface found!");
return false;
} else {
Log.d("USB","Suitable interface found!");
return true;
}
}catch(Exception ex){
ex.printStackTrace();
return false;
}
}
Now you have a device, USB interface, and endpoints ready for communication. Now it's time to establish a connection between your Android device and USB device.
Below is the code for this (and checking whether the connection is up and communicating):
private boolean checkUsbCOMM() {
/**Value for setting request, on the USB connection.*/
final int RQSID_SET_CONTROL_LINE_STATE = 0x22;
boolean success = false;
Log.d("USB","Checking USB Device for communication: ");
try{
Boolean permitToRead = SUSBS_usbManager.hasPermission(SUSBS_device);
if (permitToRead) {
//class level variable(connection, usbManager : declare it)
connection = usbManager.openDevice(device);
if (connection != null) {
connection.claimInterface(usbInterface, true);
int usbResult;
usbResult = connection.controlTransfer(0x21, //requestType
RQSID_SET_CONTROL_LINE_STATE, //SET_CONTROL_LINE_STATE(request)
0, //value
0, //index
null, //buffer
0, //length
500); //timeout = 500ms
Log.i("USB","controlTransfer(SET_CONTROL_LINE_STATE)[must be 0 or greater than 0]: "+usbResult);
if(usbResult >= 0)
success = true;
else
success = false;
}
}
else {
/**If permission is not there then ask for permission*/
usbManager.requestPermission(device, mPermissionIntent);
Log.d("USB","Requesting Permission to access USB Device: ");
}
return success;
}catch(Exception ex){
ex.printStackTrace();
return false;
}
}
Voila, the USB device is now able to communicate. So let's read using a separate thread:
if(device!=null){
Thread readerThread = new Thread(){
public void run(){
int usbResult = -1000;
int totalBytes = 0;
StringBuffer sb = new StringBuffer();
String usbReadResult=null;
byte[] bytesIn ;
try {
while(true){
/**Reading data until there is no more data to receive from USB device.*/
bytesIn = new byte[endpointIn.getMaxPacketSize()];
usbResult = connection.bulkTransfer(endpointIn,
bytesIn, bytesIn.length, 500);
/**The data read during each bulk transfer is logged*/
Log.i("USB","data-length/read: "+usbResult);
/**The USB result is negative when there is failure in reading or
* when there is no more data to be read[That is :
* The USB device stops transmitting data]*/
if(usbResult < 0){
Log.d("USB","Breaking out from while, usb result is -1");
break;
}
/**Total bytes read from the USB device*/
totalBytes = totalBytes+usbResult;
Log.i("USB","TotalBytes read: "+totalBytes);
for(byte b: bytesIn){
if(b == 0 )
break;
else{
sb.append((char) b);
}
}
}
/**Converting byte data into characters*/
usbReadResult = new String(sb);
Log.d("USB","The result: "+usbReadResult);
//usbResult holds the data read.
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
/**Starting thread to read data from USB.*/
SUSBS_readerThread.start();
SUSBS_readerThread.join();
}
For permission, make sure you add a PendingIntent as well add the permission to your manifest.
AndroidManifest : <uses-feature android:name="android.hardware.usb.host" />
PendingIntent:
private PendingIntent mPermissionIntent;
private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
mPermissionIntent = PendingIntent.getBroadcast(MainActivity.this,
0, new Intent(ACTION_USB_PERMISSION), 0);
/**Setting up the Broadcast receiver to request a permission to allow the APP to access the USB device*/
IntentFilter filterPermission = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(mUsbReceiver, filterPermission);
Starting with Android 4.2 , turning on/off airplane mode isn't supported using normal APIs.
It should probably work when WRITE_SECURE_SETTINGS permission is granted, but that's only for system apps (as I've read).
What should be done in order to do it on devices with root?
Should a system app also require root in order to toggle airplane mode?
To toggle Airplane / Flight mode on and off on an Android rooted device (phone, tablet, note), you can do the following:
private final String COMMAND_FLIGHT_MODE_1 = "settings put global airplane_mode_on";
private final String COMMAND_FLIGHT_MODE_2 = "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state";
#SuppressLint("NewApi")
#SuppressWarnings("deprecation")
public void setFlightMode(Context context) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {
// API 17 onwards.
if (isRooted(context)) {
int enabled = isFlightModeEnabled(context) ? 0 : 1;
// Set Airplane / Flight mode using su commands.
String command = COMMAND_FLIGHT_MODE_1 + " " + enabled;
executeCommandWithoutWait(context, "-c", command);
command = COMMAND_FLIGHT_MODE_2 + " " + enabled;
executeCommandWithoutWait(context, "-c", command);
} else {
try {
// No root permission, just show Airplane / Flight mode setting screen.
Intent intent = new Intent(Settings.ACTION_AIRPLANE_MODE_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.e(TAG, "Setting screen not found due to: " + e.fillInStackTrace());
}
}
} else {
// API 16 and earlier.
boolean enabled = isFlightModeEnabled(context);
Settings.System.putInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, enabled ? 0 : 1);
Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intent.putExtra("state", !enabled);
context.sendBroadcast(intent);
}
To check whether Airplane / Flight mode is already on and off, do the following:
#SuppressLint("NewApi")
#SuppressWarnings("deprecation")
private boolean isFlightModeEnabled(Context context) {
boolean mode = false;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {
// API 17 onwards
mode = Settings.Global.getInt(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
} else {
// API 16 and earlier.
mode = Settings.System.getInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) == 1;
}
return mode;
}
To execute su command, do the following:
private void executeCommandWithoutWait(Context context, String option, String command) {
boolean success = false;
String su = "su";
for (int i=0; i < 3; i++) {
// "su" command executed successfully.
if (success) {
// Stop executing alternative su commands below.
break;
}
if (i == 1) {
su = "/system/xbin/su";
} else if (i == 2) {
su = "/system/bin/su";
}
try {
// execute command
Runtime.getRuntime().exec(new String[]{su, option, command});
} catch (IOException e) {
Log.e(TAG, "su command has failed due to: " + e.fillInStackTrace());
}
}
}
Alternatively, if your app:
Was signed with an Android framework's certificate; and
Was installed to the /system/app/ directory; and
Have the relevant tags declared in AndroidManifest.xml file (e.g. WRITE_SECURE_SETTINGS, etc).
then you can just do this:
Settings.Global.putInt(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, isEnabled ? 0 : 1);
Since anything defined in Settings.Global can be read-write by system apps - even third-party app created as a system app.
Does anybody know how to retrieve cell tower list on GSM and CDMA on Android.
I have been trying to use Google Maps Locations API:
https://developers.google.com/maps/documentation/business/geolocation/
And I want to get cell towers information with these fields:
cellId: Unique identifier of the cell. On GSM, this is the Cell ID (CID); CDMA networks use the Base Station ID (BID).
locationAreaCode: The Location Area Code (LAC) for GSM networks; CDMA networks use Network ID (NID).
mobileCountryCode: The cell tower's Mobile Country Code (MCC).
mobileNetworkCode: The cell tower's Mobile Network Code. This is the MNC for GSM, or the System ID (SID) for CDMA.
age: The number of milliseconds since this cell was primary. If age is 0, the cellId represents a current measurement.
signalStrength: Radio signal strength measured in dBm.
timingAdvance: The timing advance value.
This code doesn't especially getting cell towers information.
TelephonyManager tel = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
// Type of the network
int phoneTypeInt = tel.getPhoneType();
String phoneType = null;
phoneType = phoneTypeInt == TelephonyManager.PHONE_TYPE_GSM ? "gsm" : phoneType;
phoneType = phoneTypeInt == TelephonyManager.PHONE_TYPE_CDMA ? "cdma" : phoneType;
try {
if (phoneType != null) {
params.put("radioType", phoneType);
}
} catch (Exception e) {}
/*
* The below code doesn't work I think.
*/
JSONArray cellList = new JSONArray();
List<NeighboringCellInfo> neighCells = tel.getNeighboringCellInfo();
for (int i = 0; i < neighCells.size(); i++) {
try {
JSONObject cellObj = new JSONObject();
NeighboringCellInfo thisCell = neighCells.get(i);
cellObj.put("cellId", thisCell.getCid());
cellList.put(cellObj);
} catch (Exception e) {}
}
if (cellList.length() > 0) {
try {
params.put("cellTowers", cellList);
} catch (JSONException e) {}
}
And I set permissions like this:
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_UPDATES"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
Please help me, thank you.
I had this problem much more recently and it ended up being the fact that
getNeighboringCellInfo
is deprecated from API 23 up. To get around this use something like the following (it's quite annoying, really):
public static JSONArray getCellInfo(Context ctx){
TelephonyManager tel = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);
JSONArray cellList = new JSONArray();
// Type of the network
int phoneTypeInt = tel.getPhoneType();
String phoneType = null;
phoneType = phoneTypeInt == TelephonyManager.PHONE_TYPE_GSM ? "gsm" : phoneType;
phoneType = phoneTypeInt == TelephonyManager.PHONE_TYPE_CDMA ? "cdma" : phoneType;
//from Android M up must use getAllCellInfo
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
List<NeighboringCellInfo> neighCells = tel.getNeighboringCellInfo();
for (int i = 0; i < neighCells.size(); i++) {
try {
JSONObject cellObj = new JSONObject();
NeighboringCellInfo thisCell = neighCells.get(i);
cellObj.put("cellId", thisCell.getCid());
cellObj.put("lac", thisCell.getLac());
cellObj.put("rssi", thisCell.getRssi());
cellList.put(cellObj);
} catch (Exception e) {
}
}
} else {
List<CellInfo> infos = tel.getAllCellInfo();
for (int i = 0; i<infos.size(); ++i) {
try {
JSONObject cellObj = new JSONObject();
CellInfo info = infos.get(i);
if (info instanceof CellInfoGsm){
CellSignalStrengthGsm gsm = ((CellInfoGsm) info).getCellSignalStrength();
CellIdentityGsm identityGsm = ((CellInfoGsm) info).getCellIdentity();
cellObj.put("cellId", identityGsm.getCid());
cellObj.put("lac", identityGsm.getLac());
cellObj.put("dbm", gsm.getDbm());
cellList.put(cellObj);
} else if (info instanceof CellInfoLte) {
CellSignalStrengthLte lte = ((CellInfoLte) info).getCellSignalStrength();
CellIdentityLte identityLte = ((CellInfoLte) info).getCellIdentity();
cellObj.put("cellId", identityLte.getCi());
cellObj.put("tac", identityLte.getTac());
cellObj.put("dbm", lte.getDbm());
cellList.put(cellObj);
}
} catch (Exception ex) {
}
}
}
return cellList;
}
Your phone might not support this function.
See this: http://code.google.com/p/android/issues/detail?id=24136
and this: Which Android phone models support getNeighboringCellInfo()?
It's not your phone, which doesn't support this info, it is purely crappy implementation of the RIL related C and Java used to provide those API calls, which prevent this. If you manage to go into the Service Mode menus (which vary widely from phone to phone) you will have full and instant access to RSSI and loads of other types of signals. You should blame Google (or your OEM) for not fixing those problems and provide better access to RF related variables.
How do i get Mac Id of android device programmatically. I have done with IMIE Code and I know how to check Mac id on device manually but have no idea how to find out programmatically.
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
WifiInfo wInfo = wifiManager.getConnectionInfo();
String macAddress = wInfo.getMacAddress();
Also, add below permission in your manifest file
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
Please refer to Android 6.0 Changes.
To provide users with greater data protection, starting in this release, Android removes programmatic access to the device’s local hardware identifier for apps using the Wi-Fi and Bluetooth APIs. The WifiInfo.getMacAddress() and the BluetoothAdapter.getAddress() methods now return a constant value of 02:00:00:00:00:00.
To access the hardware identifiers of nearby external devices via Bluetooth and Wi-Fi scans, your app must now have the ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permissions.
See this post where I have submitted Utils.java example to provide pure-java implementations and works without WifiManager. Some android devices may not have wifi available or are using ethernet wiring.
Utils.getMACAddress("wlan0");
Utils.getMACAddress("eth0");
Utils.getIPAddress(true); // IPv4
Utils.getIPAddress(false); // IPv6
With this code you will be also able to get MacAddress in Android 6.0 also
public static String getMacAddr() {
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) {}
return "02:00:00:00:00:00";
}
EDIT 1.
This answer got a bug where a byte that in hex form got a single digit, will not appear with a "0" before it. The append to res1 has been changed to take care of it.
It's Working
package com.keshav.fetchmacaddress;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.List;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e("keshav","getMacAddr -> " +getMacAddr());
}
public static String getMacAddr() {
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 "";
}
}
UPDATE 1
This answer got a bug where a byte that in hex form got a single digit, will not appear with a "0" before it. The append to res1 has been changed to take care of it.
StringBuilder res1 = new StringBuilder();
for (byte b : macBytes) {
// res1.append(Integer.toHexString(b & 0xFF) + ":");
res1.append(String.format("%02X:",b));
}
Recent update from Developer.Android.com
Don't work with MAC addresses MAC addresses are globally unique, not
user-resettable, and survive factory resets. For these reasons, it's
generally not recommended to use MAC address for any form of user
identification. Devices running Android 10 (API level 29) and higher
report randomized MAC addresses to all apps that aren't device owner
apps.
Between Android 6.0 (API level 23) and Android 9 (API level 28), local
device MAC addresses, such as Wi-Fi and Bluetooth, aren't available
via third-party APIs. The WifiInfo.getMacAddress() method and the
BluetoothAdapter.getDefaultAdapter().getAddress() method both return
02:00:00:00:00:00.
Additionally, between Android 6.0 and Android 9, you must hold the
following permissions to access MAC addresses of nearby external
devices available via Bluetooth and Wi-Fi scans:
Method/Property Permissions Required
ACCESS_FINE_LOCATION or
ACCESS_COARSE_LOCATION
Source: https://developer.android.com/training/articles/user-data-ids.html#version_specific_details_identifiers_in_m
Here the Kotlin version of Arth Tilvas answer:
fun getMacAddr(): String {
try {
val all = Collections.list(NetworkInterface.getNetworkInterfaces())
for (nif in all) {
if (!nif.getName().equals("wlan0", ignoreCase=true)) continue
val macBytes = nif.getHardwareAddress() ?: return ""
val res1 = StringBuilder()
for (b in 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 (ex: Exception) {
}
return "02:00:00:00:00:00"
}
private fun getMac(): String? =
try {
NetworkInterface.getNetworkInterfaces()
.toList()
.find { networkInterface -> networkInterface.name.equals("wlan0", ignoreCase = true) }
?.hardwareAddress
?.joinToString(separator = ":") { byte -> "%02X".format(byte) }
} catch (ex: Exception) {
ex.printStackTrace()
null
}
There is a simple way:
Android:
String macAddress =
android.provider.Settings.Secure.getString(this.getApplicationContext().getContentResolver(), "android_id");
Xamarin:
Settings.Secure.GetString(this.ContentResolver, "android_id");