My app is communicating with another device by wifi.
I tried to ask all permissions at app's start, but is never asked about wifi.
By the way, every time I need to change wifi, user must give permission.
How can I ask for change wifi state permission once and never bother user again?
Sample of code that I used to change wifi is below
WifiConfiguration wifiConfig = new WifiConfiguration();
wifiConfig.SSID = String.format("\"%s\"", ssid);
if (!key.equals(""))
wifiConfig.preSharedKey = String.format("\"%s\"", key);
final int netId = wifiManager.addNetwork(wifiConfig);
Log.d("Network ID", Integer.toString(netId));
wifiManager.disconnect();
wifiManager.enableNetwork(netId, true);
wifiManager.reconnect();
The permission my phone is asked about below
It is Russian. Translation is "Would you give this app a permission to turn on/turn off WIFI?".
I tested it on another phone, and it keeps happening. Both phones is xiaomi and have their own android version MIUI.
Add this code snippet in AndroidManifest.xml:
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
And use this code:
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
wifi.setWifiEnabled(false); // activate/deactivate wifi
You only need to declare it in AndroidManifest.xml:
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
Android > 6.0 user prompted runtime permission is NOT required for CHANGE_WIFI_STATE, because it is one of the safe ones.
If something is still goes wrong, please provide code sample which you are using.
UPD:
Tested your code on Samsung J5 with Android 6.0 and everithing works fine.
Also you are using deprecated methods. You need to use something like this for >= Android.O
In manifest:
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS"
tools:ignore="ProtectedPermissions" />
And code:
WifiNetworkSpecifier.Builder builder = new WifiNetworkSpecifier.Builder();
builder.setSsid("SSID");
builder.setWpa2Passphrase("PASSWORD");
WifiNetworkSpecifier wifiNetworkSpecifier = builder.build();
NetworkRequest.Builder networkRequestBuilder1 = new NetworkRequest.Builder();
networkRequestBuilder1.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
networkRequestBuilder1.setNetworkSpecifier(wifiNetworkSpecifier);
NetworkRequest nr = networkRequestBuilder1.build();
final ConnectivityManager cm = (ConnectivityManager)
getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
ConnectivityManager.NetworkCallback networkCallback = new
ConnectivityManager.NetworkCallback() {
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
public void onAvailable(Network network) {
super.onAvailable(network);
Log.d("TEST", "onAvailable:" + network);
cm.bindProcessToNetwork(network);
}
};
cm.requestNetwork(nr, networkCallback);
Related
I'm trying to create a camera picker functionality on the app and I face some of the methods of camera picture is deprecated so I trying to resolve the code and not using any depricated method.
First on manifest declares the permissions
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
after that create a Camera intent:
private var imageStr:Uri?=null
val values = ContentValues()
values.put(Media.TITLE, "New Picture")
values.put(Media.DESCRIPTION, "From the Camera")
imageStr = requireActivity().contentResolver.insert(EXTERNAL_CONTENT_URI, values)
// camera intent
val intent = Intent(ACTION_IMAGE_CAPTURE)
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageStr)
startForCameraResult.launch(intent)
and after that we get the value on startForCameraResult:
private val startForCameraResult = registerForActivityResult(StartActivityForResult()) {
if (it.resultCode == RESULT_OK) {
profileImage.setImageURI(imageStr)
}
}
Here is the code And The problem is I always get imagestr is null.
Please show me the right direction to handle this issue.
Thanks
If you are using targetSdkVersion 29 & compileSdkVersion 29 you need to set android:requestLegacyExternalStorage="true" in application tag of AndroidManifest.xml file.
I'm working on a simple system app in Oreo AOSP to turn ON wifi Hotspot with predefined SSID and preshared key.
As my APP is built as a system app so i don't need reflection.
MainActivity.java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean result = false;
WifiManager mwifiManager;
mwifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);
try {
Method method = mwifiManager.getClass().getMethod("getWifiApConfiguration");
WifiConfiguration netconfig = (WifiConfiguration) method.invoke(mwifiManager);
netconfig.SSID = "DummyApp";
netconfig.preSharedKey = "1234567890";
netconfig.allowedKeyManagement.set(4);
mwifiManager.setWifiEnabled(false);
method = mwifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
result = (boolean) method.invoke(mwifiManager, netconfig, true);
if (!result) {
Toast.makeText(this, "Hotspot creation failed", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Wifi Enabled", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
}
finish();
}
#Override
protected void onResume() {
super.onResume();
}
}
AndroidManifest.xml
android:protectionLevel="signature|privileged"
android:sharedUserId="android.uid.system">
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<!-- for wifi -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.TETHER_PRIVILEGED" />
Wifi Should turn ON but getting following result:
Toast Message: Hotspot creation failed
Logcat: WifiManager: PACKAGE_NAME attempted call to setWifiApEnabled: enabled = true
update1: How to turn on/off wifi hotspot programmatically in Android 8.0 (Oreo)
I have tried above changes. It will turn on Hotspot locally but no custom SSID and password.
update2: After getting input from #Mr.AF.
Method setConfigMethod = mWifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
......code snip.........
netconfig.allowedKeyManagement.set(4);
Method Method = mWifiManager.getClass().getMethod("setWifiApConfiguration", WifiConfiguration.class);
HOTSPOT Creation FAiled
To turn ON Portable HotSpot in Android Nougat and below following code works.
Method method = mwifiManager.getClass().getMethod("getWifiApConfiguration");
WifiConfiguration netconfig = (WifiConfiguration) method.invoke(mwifiManager);
method = mwifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
result = (boolean) method.invoke(mwifiManager, netconfig, true);
Above API is deprecated in Oreo.
Following is a #system hidden API in oreo, If the android application is built as a system app then only below API code can be accessed. In my case, I can use the below API.
ConnectivityManager oncm = (ConnectivityManager)ontext.getSystemService(Context.CONNECTIVITY_SERVICE);
oncm.startTethering(ConnectivityManager.TETHERING_WIFI, true, new ConnectivityManager.OnStartTetheringCallback() {
#Override
public void onTetheringStarted() {
super.onTetheringStarted();
Log.i(TAG, "Hotspot is successfully opened");
}
#Override
public void onTetheringFailed() {
super.onTetheringFailed();
Log.e(TAG, "Hotspot failed to open");
}
});
You don't need to use reflection for versions>=Oreo. After android's public exposed API startLocalOnlyHotspot. I've explained this answer in detail on this question on Stackoveflow.
I'm developing and Android app with Bluetooth but sometimes I have problems with LE devices discovering: usually the discovery callback return me the the devices found but sometimes, stops working and does not return me the devices.
I tested the code (in debug mode) in different devices (Samsung, LG) and with different Android version (8.0, 6.0, 4.4) but the problem is the same, is not systematic and after some time, it return to works fine.
I have applied all the suggestions found in internet:
Android can't find any BLE devices
Bluetooth LE Scanning Sometimes Doesn't Find Devices
Android Bluetooth Low Energy code compatible with API>=21 AND API<21
but the problem persist.
Below a snips of manifest:
.
.
.
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-feature android:name="android.hardware.location.gps" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
.
.
.
and bluetooth code:
public BLEH_RES StartDiscovery()
{
.
.
.
CheckPermission();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
return(scanLeDevice21(true));
else
return(scanLeDevice18(true));
}
/**
* Scan BLE devices on Android API 20 to last version (Android 9.0)
*
* #param enable Enable scan
*/
#RequiresApi(21)
private BLEH_RES scanLeDevice21(boolean enable)
{
bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
if (bluetoothLeScanner == null)
return(BLEH_RES.BLE_NOT_SUPPORTED);
if (enable)
{
ScanSettings.Builder scanSettings = new ScanSettings.Builder();
scanSettings.setScanMode(SCAN_MODE_LOW_LATENCY);
bluetoothLeScanner.startScan(null, scanSettings.build(), BLEScanCallback);
}
else
bluetoothLeScanner.stopScan(BLEScanCallback);
return(BLEH_RES.OK);
}
/**
* Scan BLE devices on Android API 18 to 20
*
* #param enable Enable scan
*/
private BLEH_RES scanLeDevice18(boolean enable)
{
if(bluetoothAdapter == null)
return(BLEH_RES.BT_NOT_SUPPORTED);
if (enable)
{
bluetoothAdapter.startDiscovery();
bluetoothAdapter.startLeScan(mLeScanCallback);
}
else
{
bluetoothAdapter.cancelDiscovery();
bluetoothAdapter.stopLeScan(mLeScanCallback);
}
return(BLEH_RES.OK);
}
#RequiresApi(21)
private ScanCallback BLEScanCallback = new ScanCallback()
{
#Override
public void onScanResult(int callbackType, ScanResult result)
{
addDevice(result.getDevice(), result.getRssi(), result.getScanRecord().getBytes());
}
#Override
public void onScanFailed(int errorCode)
{
for(ErrorEvent ee:errorEventList)
ee.onError(BLEH_EVENT_ERROR.SCAN_FAILED);
}
};
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback()
{
#Override
public void onLeScan(final BluetoothDevice bluetoothDevice, int rssi,byte[] scanRecord)
{
addDevice(bluetoothDevice, rssi, scanRecord);
}
};
Can you suggest me anything to solve this problem?
Make sure that GPS is enabled all the time you searching devices. Also suggest you to watch this about BLE
https://youtu.be/jDykHjn-4Ng
I solved my problem by following the suggestions in this link: https://stackoverflow.com/a/42267678/7006955
I add to my code all the code suggested and it works fine also in Android 4
After developing a working system in 6.0 (S6) I'm testing the same code in 8.0 (S9) and I've noticed that ConnectivityManager.requestNetwork() is no longer doing anything.
Here is the function I'm using:
public static void enableWifi() {
ConnectivityManager connectivityManager = (ConnectivityManager)
mContext.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkRequest.Builder request = new NetworkRequest.Builder();
request.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
request.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
connectivityManager.requestNetwork(
request.build(),
new ConnectivityManager.NetworkCallback() {
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
public void onAvailable(Network network) {
connectivityManager.bindProcessToNetwork(network);
Log.i(TAG, "bindProcessToNetwork called");
}
},
30000
);
}
after calling this function, I check to see whether the connection has been switched to Wifi for 20 seconds:
wifiManager.setWifiEnabled(true);
enableWifi();
long start_time = System.currentTimeMillis();
while (!MainActivity.getNetworkClass(mContext).contains("WIFI")) {
if (System.currentTimeMillis() - start_time > 20000) {
Log.i(TAG, "connection timed out");
}
}
After the timeout I'm still on the 4G network, wifi is never truly enabled. All logs shown above are called, yet the network state never changes to Wifi.
The manifest:
<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.INTERNET"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
Edit:
After much frustration I was able to establish a connection once using this setup, but not again since. I am not sure where to even begin troubleshooting this and assume it's a bug in 8.0 until I find otherwise.
Using the Connectivity Manager Class we can get access to either wifi or Internet Network:
ConnectivityManager connec = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
// ARE WE CONNECTED TO THE NET
if ( connec.getNetworkInfo(0).getState() == NetworkInfo.State.CONNECTED ||
connec.getNetworkInfo(1).getState() == NetworkInfo.State.CONNECTED ) {
// ...
}
where 0 and 1 respectively refers to mobile and wifi connection
If my Android device is connected to both, can we switch between any of the networks or can we disable any of the networks? Like using a function:
connec.getNetworkInfo(0).setState(NetworkInfo.State.DISCONNECTED);
I know of enabling or disabling wifi:
WifiManager wifiManager = (WifiManager)this.context.getSystemService(Context.WIFI_SERVICE);
wifiManager.setWifiEnabled(status);
where status may be true or false as per requirement.
Edit:
You also need the following permissions in your manifest file:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
To Enable WiFi:
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
wifi.setWifiEnabled(true);
To Disable WiFi:
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
wifi.setWifiEnabled(false);
Note:
To access with WiFi state, we have to add following permissions inside the AndroidManifest.xml file:
android.permission.ACCESS_WIFI_STATE
android.permission.UPDATE_DEVICE_STATS
android.permission.CHANGE_WIFI_STATE
A complete solution:
try {
WifiManager wifi = (WifiManager)
context.getSystemService(Context.WIFI_SERVICE);
WifiConfiguration wc = new WifiConfiguration();
wc.SSID = "\"SSIDName\"";
wc.preSharedKey = "\"password\"";
wc.hiddenSSID = true;
wc.status = WifiConfiguration.Status.ENABLED;
wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
wc.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
wc.allowedPairwiseCiphers
.set(WifiConfiguration.PairwiseCipher.TKIP);
wc.allowedPairwiseCiphers
.set(WifiConfiguration.PairwiseCipher.CCMP);
wc.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
boolean b=wifi.isWifiEnabled();
if (b) {
wifi.setWifiEnabled(false);
Toast.makeText(context, "yes", Toast.LENGTH_SHORT).show();
} else {
wifi.setWifiEnabled(true);
Toast.makeText(context, "no", Toast.LENGTH_SHORT).show();
}
//Log.d("WifiPreference", "enableNetwork returned " + b );
} catch (Exception e) {
e.printStackTrace();
}
Reference: http://amitkumar-android.blogspot.com/p/installation-steps.html
In Android Q (Android 10) you can't enable/disable wifi programmatically anymore. Use Settings Panel to toggle wifi connectivity:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// can also use `Settings.Panel.ACTION_WIFI` to enable/disable only WiFi
val panelIntent = Intent(Settings.Panel.ACTION_INTERNET_CONNECTIVITY)
startActivityForResult(panelIntent, 0)
} else {
// use previous solution, add appropriate permissions to AndroidManifest file (see answers above)
(this.context?.getSystemService(Context.WIFI_SERVICE) as? WifiManager)?.apply { isWifiEnabled = true /*or false*/ }
}
To enable disable Wifi use the WifiManager class to get system(android device) services for Wifi :
WifiManager wifi =(WifiManager)getSystemService(Context.WIFI_SERVICE);
Now the object wifi of the WifiManager class is used to get the wifi status:
if(wifi.isWifiEnabled())
//Perform Operation
else
//Other Operation
And most importantly do not forget to give the following permission in your Android Manifest File:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
To get detailed info and full sample code of the project for enable/disable Wifi on android visit my website link.
This method is deprecated now from now starting with Android Q.
Try This will really help.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {// if build version is less than Q try the old traditional method
if (!wifiManager.isWifiEnabled()) {
wifiManager.setWifiEnabled(true);
btnOnOff.setText("Wifi ONN");
} else {
wifiManager.setWifiEnabled(false);
btnOnOff.setText("Wifi OFF");
}
} else {// if it is Android Q and above go for the newer way NOTE: You can also use this code for less than android Q also
Intent panelIntent = new Intent(Settings.Panel.ACTION_WIFI);
startActivityForResult(panelIntent, 1);
}
add this permission in your manifest and than use the above code to change WiFi state:
<!--permission ge enable and disable WIFI in android-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
I could not access the context object directly.
My solution is as following:
Context appContext = Android.App.Application.Context;
var wifiManager = (WifiManager)appContext.GetSystemService(WifiService);
wifiManager.SetWifiEnabled(state);
Also I had to change some writings eg. WIFI_SERVICE vs. WifiService.
It is possible to enable/disable wifi on pre Android 10 devices using the following code:
WifiManager wifiManager =
(WifiManager)this.context.getSystemService(Context.WIFI_SERVICE);
wifiManager.setWifiEnabled(status);
But note that it is not possible to do this anymore on Android 10 and probably going ahead as well.
https://issuetracker.google.com/issues/141011684
Android 10 (Q) onwards wifi can not be enabled/disabled you need to open the setting intent,
// for android Q and above
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
Intent panelIntent = new
Intent(Settings.Panel.ACTION_INTERNET_CONNECTIVITY);
startActivityForResult(panelIntent, 0);
} else {
// for previous android version
WifiManager wifiManager = (WifiManager)
this.getApplicationContext().getSystemService(WIFI_SERVICE);
wifiManager.setWifiEnabled(true);
}
In manifest,
<uses-permission
android:name="android.permission.CHANGE_WIFI_STATE"
android:required="true" />