Get current Wifi SSID Android 10 - android

I try to get my currend Wifi SSID on Android 10.
Code from Android 9 or lower does not work anymore.
Is there any sample for Android 10.
Regards Hacki

Since API 26 (Android 8 Oreo) you need to obtain the user location permission in order to get the wifi name (SSID), which is why also in Android 9 (API 28), Android 10 (API 29) or Android 11 (API 30) and newer you may get <unknown name> as the SSID returned or 02:00:00:00:00:00.
For that, in AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
I will provide some demo code written in Kotlin.
For declaring your permission request success code, we store it in a companion object (Kotlin way for storing constants) inside the class we are testing from (MainActivity in this case) or you may define a class explicitly for constants, which is actually a common practice.
class MainActivity : AppCompatActivity() {
...
companion object {
const val PERMISSION_CODE_ACCEPTED = 1
const val PERMISSION_CODE_NOT_AVAILABLE = 0
}
...
}
In your testing activity:
when(requestLocationPermission()){
MainActivity.PERMISSION_CODE_ACCEPTED -> getWifiSSID()
}
For checking an requesting the permission:
fun requestLocationPermission(): Int {
if (ContextCompat.checkSelfPermission(this,
android.Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
android.Manifest.permission.ACCESS_FINE_LOCATION)) {
} else {
// request permission
ActivityCompat.requestPermissions(this,
arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION),
MainActivity.PERMISSION_CODE_ACCEPTED)
}
} else {
// already granted
return MainActivity.PERMISSION_CODE_ACCEPTED
}
// not available
return MainActivity.PERMISSION_CODE_NOT_AVAILABLE
}
For actually getting the SSID (wifi name):
fun getWifiSSID() {
val mWifiManager: WifiManager = (this.getApplicationContext().getSystemService(Context.WIFI_SERVICE) as WifiManager)!!
val info: WifiInfo = mWifiManager.getConnectionInfo()
if (info.getSupplicantState() === SupplicantState.COMPLETED) {
val ssid: String = info.getSSID()
Log.d("wifi name", ssid)
} else {
Log.d("wifi name", "could not obtain the wifi name")
}
}
Tested on the emulator on API 29 (Android 10).
2020-10-04 15:35:28.625 13013-13013/com.example.myapplication D/wifi name: "AndroidWifi"

Set his two permissions requests into your project manifest file:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"\>
Than you have to set Application permission manually by using Settings screen of Android.

Related

Need android.permission.BLUETOOTH_CONNECT permission for AttributionSource in Android 12

Migrating from android 30 to the android 31 version, I am trying to connect to the paired Bluetooth device in my app.
But, I am facing an issue when I tried to get the paired device list.
val pairedDevices: Set<BluetoothDevice>? = bluetoothAdapter?.bondedDevices
pairedDevices?.forEach { device ->
if(device.address.lowercase() == configHelper.bluetoothAddress.lowercase()){
bluetoothDevice = device
paymentTerminalName = device.name
paymentTerminalMAC = device.address // MAC address
UUIDFromPaymentTerminal = device.uuids[0].uuid // UUID specifies the service that the the server provides
}
}
if(bluetoothDevice == null){
//payment terminal is not paired yet
throw ex
}
socket = bluetoothDevice!!.createRfcommSocketToServiceRecord(UUIDFromPaymentTerminal)
//cancel discovery, otherwise it slows down the connection process
bluetoothAdapter!!.cancelDiscovery()
(socket!! as BluetoothSocket).connect()
I am getting the below error,
java.lang.SecurityException: Need android.permission.BLUETOOTH_CONNECT
permission for AttributionSource { uid = 10414, packageName =
com.test.app, attributionTag = null, token =
android.os.BinderProxy#8a4f87d, next = null }: AdapterService
getBondedDevices
I have added bluetooth permission to my manifest file,
<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" />
Let me know where am I missing to get the paired device in kotlin 1.5.0
The BLUETOOTH_CONNECT & BLUETOOTH_SCAN permissions are runtime permissions, these permissions have to be asked during the runtime of your application.
The BLUETOOTH_SCAN permission should be asked before you scan for devices and the BLUETOOTH_CONNECT permission should be asked before you connect to a device.
An example of a permission requester for an single permission within the Fragments architecture:
val requestConnectPermission: ActivityResultLauncher<String> =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { permissionGranted ->
if (permissionGranted) {
// connect to device
}
}
An example of a requester for multiple permissions within the Fragments architecture:
val permissionRequester: ActivityResultLauncher<Array<String>> = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
if (permissions.values.all { it }) {
// connect to device
}
}
To handle a single permission request within an Composable is slightly different, you can do the following:
val permissionRequester =
rememberLauncherForActivityResult(contract = ActivityResultContracts.RequestPermission()) { granted ->
if (granted) {
// connect to device
}
}
requestConnectPermission?.launch(Manifest.permission.BLUETOOTH_CONNECT)
And for multiple permissions at once:
val permissionRequester =
rememberLauncherForActivityResult(contract = ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
if (permissions.values.all { it }) {
// connect to device
}
}
Before you should use such a permission launcher you should check if the user has already accepted the permissions. If not you can launch a request. An example to launch a single permission request:
if (ActivityCompat.checkSelfPermission(requireContext(), BLUETOOTH_CONNECT) == PERMISSION_GRANTED) {
// connect to device
} else {
permissionRequester.launch(BLUETOOTH_CONNECT)
}
And if you want to launch multiple permission requests at once you can do this:
if (ActivityCompat.checkSelfPermission(requireContext(), BLUETOOTH_CONNECT) == PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(requireContext(), BLUETOOTH_SCAN) == PERMISSION_GRANTED) {
// connect to device
} else {
permissionRequester.launch(arrayOf(BLUETOOTH_CONNECT, BLUETOOTH_SCAN))
}
More info about permissions can be found here.

How to take the connected Wifi SSID

I need to take SSID of connected WiFi and first i tried this:
val wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
val wifiInfo = wifiManager.connectionInfo
textField.text = wifiInfo.ssid
But wifiInfo.ssid returns <unknown ssid> when testing on emulator with API 30 or Xiaomi Redmi Note 8 Pro(Android 11), just as in emulator with API 27 wifiInfo.ssid returns correct SSID.
Then i tried this:
val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val request = NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build()
val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
super.onCapabilitiesChanged(network, networkCapabilities)
//wifiInfo = networkCapabilities.transportInfo as WifiInfo
Log.d("%%%", "onCapabilitiesChanged: ${networkCapabilities.transportInfo}")
}
}
connectivityManager.requestNetwork(request, networkCallback)
connectivityManager.registerNetworkCallback(request, networkCallback)
But networkCapabilities.transportInfo always null
EDIT:
Permissions in manifest file
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_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.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
Request location permission in OnCreate():
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 1)
And it successfully granted.
SOLVE 1:
I just forget to on Geolocation on my phone)
It solves problem while i using first method taking wifiinfi by wifiManager.connectionInfo but when i use second one by networkCapabilities.transportInfo it still returns null, and since first method is Deprecated in java maybe it is not good to use it.
Then, I would be glad to have your comments about the second method.
Google assumes that knowing ssid means knowing location.
Go for fine location permission and you will see.

RSSI Scanning: onBluetoothLeDeviceFound Callback not called on Pixel 1

I'am working on a RSSI scanner for Android. I want to archieve this via constantly scanning for BLE devices. So if the RSSI of a device should be figured out it needs to advertise via BLE. The measuring device start scanning in really short intervalls and as it finds the advertiser the RSSI can be read in the scan result.
That results in folowing code on the advertiser side:
fun beginAdvertise() {
val advertiser = BluetoothAdapter.getDefaultAdapter().bluetoothLeAdvertiser
val settings = AdvertiseSettings.Builder()
.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
.setConnectable(false)
.build()
val data = AdvertiseData.Builder()
.setIncludeDeviceName(true)
.build()
val advertisingCallback = object : AdvertiseCallback() {
override fun onStartFailure(errorCode: Int) {
Log.e("BLE", "Advertising onStartFailure: " + errorCode);
super.onStartFailure(errorCode)
}
}
advertiser.startAdvertising(settings, data, advertisingCallback);
}
The function for the scanning device gets called every 20ms (I tried much longer delays) and looks like this:
private val onBluetoothLeDeviceFound = object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult?) {
result?.let {...}}
fun startScan() {
val scanner = mBluetoothAdapter?.bluetoothLeScanner
val scanSetting =
ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE).build()
scanner?.startScan(
null,
scanSetting,
onBluetoothLeDeviceFound
)
}
This code is working perfectly on my Pixel 2 devices. But if I try it on Pixel 1 (one on Android 9, the other on Android 10) devices the onBluetoothLeDeviceFound callback does not get called.
I have these permissions:
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCTION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
I really don'T know what I should try out next. Thank you for your help!
The solution was simple, but time consuming. You dont just need to have the location permissions, but also have to enable location services! On the Pixel 2 devices, they were randomly turned on, so it worked there, but not on the Pixel 1.

Android - Not granted USE_BIOMETRIC

I am checking all permisions from the Manifest with the code bellow. Now I added USE_BIOMETRIC permission, because I want to use fingerprint, but this permission is not granted and I don't know why.
I know that USE_BIOMETRIC is normal permission so it shouldn't be asked and should be granted when it's in the Manifest, but it's not.
Checking for other permissions is working and all are granted or asked for it, only this one is not.
I am testing app on 2 phones, emulated Google pixel with Android 8.0 and API 26 and physical Xiaomi Redmi 5 with Android 8.1 and API 27.
Both phones are using fingerprint to unlock screen.
Permisions in the manifest:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
Code that loads permissions from the manifest and check if is granted or not:
fun checkAndRequestPermissions(): Boolean{
var listPermissionsNeeded = ArrayList<String>()
val permissions = retrievePermissions(activity.baseContext)
permissions.forEach {
if(ContextCompat.checkSelfPermission(activity.baseContext, it) != PackageManager.PERMISSION_GRANTED){
listPermissionsNeeded.add(it)
Log.d("Missing permission", it)
}
}
if (!listPermissionsNeeded.isEmpty()) {
val array = arrayOfNulls<String>(listPermissionsNeeded.size)
listPermissionsNeeded.toArray(array)
ActivityCompat.requestPermissions(activity, array, ConstantsStorage.ACTIVITY_REQUEST_PERMISSIONS_CODE)
return false
}
return true
}
companion object {
/**
* Retrieves permissions listed in the manifest file
* #param context Context
* #return Returns String array of permissions
*/
fun retrievePermissions(context: Context): Array<String> {
try {
return context
.packageManager
.getPackageInfo(context.packageName, PackageManager.GET_PERMISSIONS)
.requestedPermissions
} catch (e: PackageManager.NameNotFoundException) {
throw RuntimeException("This should have never happened.", e)
}
}
}
Thank you for your help
According to the new policy in Google Console, you couldn't use this permission on the Manifest. So you should Request and Check in Activity.
You can use BiometricManager to check it:
val biometricManager = BiometricManager.from(this)
when (biometricManager.canAuthenticate(BIOMETRIC_STRONG or DEVICE_CREDENTIAL)) {
BiometricManager.BIOMETRIC_SUCCESS ->
Log.d("MY_APP_TAG", "App can authenticate using biometrics.")
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE ->
Log.e("MY_APP_TAG", "No biometric features available on this device.")
BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE ->
Log.e("MY_APP_TAG", "Biometric features are currently unavailable.")
BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> {
// Prompts the user to create credentials that your app accepts.
val enrollIntent = Intent(Settings.ACTION_BIOMETRIC_ENROLL).apply {
putExtra(Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED,
BIOMETRIC_STRONG or DEVICE_CREDENTIAL)
}
startActivityForResult(enrollIntent, REQUEST_CODE)
}
}
Note: It's very important to add suitable import
import androidx.biometric.BiometricManager;

Determine whether a permission is present in the manifest with Android 23+

I am creating a library that needs to check runtime permissions. I have got runtime permissions working fine and understand the use cases without issues.
However I would like to confirm that the developer using our library has added the permission to their manifest.
The library is a location based library and the developer can either enter ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION into the manifest and I need to be able to determine which they have used (or both) at runtime.
I though using the package manager to check permission would work however this always seems to fail:
PackageManager pm = getPackageManager();
int granted = pm.checkPermission(
Manifest.permission.ACCESS_COARSE_LOCATION,
getPackageName() );
if (granted == PackageManager.PERMISSION_GRANTED)
{
// Use coarse for runtime requests
}
// granted is always PackageManager.PERMISSION_DENIED
Is there some other way to do this in Android v23+?
Off the cuff, retrieve the PackageInfo via PackageManager and getPackageInfo(getPackageName(), PackageManager.GET_PERMISSIONS). Then, look at the requestedPermissions array in the PackageInfo for all the <uses-permission>-requested permissions.
Thanks to answer of CommonsWare I'm created this method Kotlin to check if SMS permission is present on Manifest
fun hasSmsPermissionInManifest(context: Context): Boolean {
val packageInfo = context.packageManager.getPackageInfo(context.packageName, PackageManager.GET_PERMISSIONS)
val permissions = packageInfo.requestedPermissions
if (permissions.isNullOrEmpty())
return false
for (perm in permissions) {
if (perm == Manifest.permission.READ_SMS || perm == Manifest.permission.RECEIVE_SMS)
return true
}
return false
}
or
fun Context.hasSmsPermissionInManifest(): Boolean {
val packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS)
val permissions = packageInfo.requestedPermissions
return permissions?.any { perm -> perm == Manifest.permission.READ_SMS || perm == Manifest.permission.RECEIVE_SMS } ?: false
}

Categories

Resources