On Android 10 (Q) I try to connect to a wifi without internet access with WifiNetworkSpecifier.
The first connection work without any problem. After that first connection I can't connect anymore.
Then I have to switch Off/On the wifi network again and than it works one time again.
This problem I have with a Xiaomi Mi 9 SE, with a Samsung Galaxy S10e the error does not exist.
How can I solve this problem, because I can't switch off/on the wifi programmatically on Android Q.
Has anyone a workaround for this problem?
My workaround is to inform the user to do a switch off/on by him self and start a panelIntent. But this is not a fine solution for me.
Here is my code:
On the init():
if (Build.VERSION.SDK_INT >= LOLLIPOP)
{
NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED);
networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
networkRequestBuilder.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
if (SDK_INT >= Q)
{
WifiNetworkSpecifier.Builder wifiNetworkSpecifierBuilder = new WifiNetworkSpecifier.Builder();
wifiNetworkSpecifierBuilder.setSsid(ssid);
wifiNetworkSpecifierBuilder.setWpa2Passphrase(password);
WifiNetworkSpecifier wifiNetworkSpecifier = wifiNetworkSpecifierBuilder.build();
networkRequestBuilder.setNetworkSpecifier(wifiNetworkSpecifier);
}
networkRequest = networkRequestBuilder.build();
networkCallback = new NetworkCallback()
{
#Override
public void onAvailable(Network network)
...
};
}
if (SDK_INT < Q)
{...}
... when the thread is running:
#Override
public void run()
{
NetworkBinding();
while (runSendThread)
{...}
NetworkUnbinding();
}
... and the bindingMethodes:
public void NetworkBinding()
{
try
{
if (SDK_INT >= VERSION_CODES.LOLLIPOP)
{
mConManager.requestNetwork(networkRequest, networkCallback);
}
}
catch (Exception e)
{
HandleException(e);
}
}
public void NetworkUnbinding()
{
try
{
if (Build.VERSION.SDK_INT >= VERSION_CODES.M)
{
mConManager.bindProcessToNetwork(null);
}
if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP)
{
mConManager.unregisterNetworkCallback(networkCallback);
android.net.ConnectivityManager.setProcessDefaultNetwork(null);
}
}
catch (Exception e)
{
HandleException(e);
}
}
For others who have similar situations:
I have found out, that the problem was on the router which needed a firmware-update.
I think some newer phones try to find out if the network is ok and if they do not get the right response they mark the network as corrupt.
After the firmware-update, the connections work with every phone.
Related
I had this function to connect in Wifi network, below Android 10 it works fine, but when I tried on Android 10, I had a successful connection but WITHOUT internet, I knew it's a bug in Android 10 but I found this application which can connect to wifi from Android 10 with no problem.
I'm blocked for days.
My function :
private void connectToWifi(String ssid, String password)
{
WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
try {
Log.e(TAG,"connection wifi pre Q");
WifiConfiguration wifiConfig = new WifiConfiguration();
wifiConfig.SSID = "\"" + ssid + "\"";
wifiConfig.preSharedKey = "\"" + password + "\"";
int netId = wifiManager.addNetwork(wifiConfig);
wifiManager.disconnect();
wifiManager.enableNetwork(netId, true);
wifiManager.reconnect();
} catch ( Exception e) {
e.printStackTrace();
}
} else {
Log.e(TAG,"connection wifi Q");
WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier.Builder()
.setSsid( ssid )
.setWpa2Passphrase(password)
.build();
NetworkRequest networkRequest = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.setNetworkSpecifier(wifiNetworkSpecifier)
.build();
connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
networkCallback = new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(Network network) {
super.onAvailable(network);
connectivityManager.bindProcessToNetwork(network);
Log.e(TAG,"onAvailable");
}
#Override
public void onLosing(#NonNull Network network, int maxMsToLive) {
super.onLosing(network, maxMsToLive);
Log.e(TAG,"onLosing");
}
#Override
public void onLost(Network network) {
super.onLost(network);
Log.e(TAG, "losing active connection");
}
#Override
public void onUnavailable() {
super.onUnavailable();
Log.e(TAG,"onUnavailable");
}
};
connectivityManager.requestNetwork(networkRequest,networkCallback);
}
}
So far what is working for me on the majority of devices I have tested with, with a fallback option to at least stop the dreaded 'looping request' and to allow a successful manual connection
The below code is written in Kotlin, please google how to covert to Java if needed.
Create a NetworkCallback which is required for API >= 29 (prior it was not required but could be used)
val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
super.onAvailable(network)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// To make sure that requests don't go over mobile data
connectivityManager.bindProcessToNetwork(network)
} else {
connectivityManager.setProcessDefaultNetwork(network)
}
}
override fun onLost(network: Network) {
super.onLost(network)
// This is to stop the looping request for OnePlus & Xiaomi models
connectivityManager.bindProcessToNetwork(null)
connectivityManager.unregisterNetworkCallback(networkCallback)
// Here you can have a fallback option to show a 'Please connect manually' page with an Intent to the Wifi settings
}
}
Connect to a network as follows:
val wifiNetworkSpecifier = WifiNetworkSpecifier.Builder()
.setSsid(ssid)
.setWpa2Passphrase(pass)
.build()
val networkRequest = NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
// Add the below 2 lines if the network should have internet capabilities.
// Adding/removing other capabilities has made no known difference so far
// .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
// .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
.setNetworkSpecifier(wifiNetworkSpecifier)
.build()
connectivityManager.requestNetwork(networkRequest, networkCallback)
As stated here by Google, some OEM Roms are not 'holding on to the request' and therefore the connection is dropping instantly. OnePlus have fixed this problem in some of their later models but not all. This bug will continuously exist for certain phone models on certain Android builds, therefore a successful fallback (i.e. a manual connection with no network disruption) is required. No known workaround is available, but if found I will update it here as an option.
To remove the network, do the following:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//This is required for Xiaomi models for disconnecting
connectivityManager.bindProcessToNetwork(null)
} else {
connectivityManager.setProcessDefaultNetwork(null)
}
connectivityManager.unregisterNetworkCallback(it)
Please keep in mind, an automatic connection allows for an automatic & manual disconnection. A manual connection (such as the suggested fallback for OnePlus devices) does not allow an automatic disconnection. This will also need to be handled within the app for a better UX design when it comes to IoT devices.
Some extra small tips & info:
now that a system dialog opens, the app calls onPause and onResume respectively. This affected my logic regarding automatic connection to IoT devices. In some case, onResume is called before the network callback is finished.
In regards to tests, I have yet to be able to get around the dialog by just using espresso and it may block some tests that were working before API 29. It may be possible using other frameworks such as uiautomator. In my case I adjusted the tests to work up until the dialog shows, and run further tests thereafter.
Using Intents.init() does not work.
onUnavailable is called when the the network has been found, but the user cancels. It is not called when the network was not found or if the user cancels the dialog before the network has been found, in this case no other methods are called, use onResume to catch it.
when it fails on the OnePlus it called onAvailable() -> onCapabilitiesChanged() -> onBlockedStatusChanged (blocked: false) -> onCapabilitiesChanged() -> onLost() respectively
removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) wont help keep the connection on a OnePlus as stated here
setting the Bssid wont help keep the connection on a OnePlus as stated here
google cannot help, they have stated it is out of their hands here
OnePlus forum posts confirming it working for some models (but not all) after an update, see here, here & here
when GPS is switched off, the SSID names of networks are not available
if the dialog comes several times, check your own activity lifecycle, in my case some models were calling onResume before the network callback was received.
manually connecting to a network without internet capabilities needs user confirmation to keep the connection (sometimes in the form of a dialog or as a notification), if ignored, the system will disconnect from the network shortly afterwards
List of devices tested:
Google Pixel 2 - No issues found
Samsung S10 SM-G970F - No issues found
Samsung S9 SM-G960F - No issues found
One Plus A5000 (OxegenOS 10.0.1) - Major Issue with automatic connection
HTC One M8 (LineageOS 17.1) - No issues found
Xiaomi Mi Note 10 - Issue with disconnecting (Fixed, see code example)
Samsung A50 - Dialog repetitively appears after successful connection (sometimes)
Huawei Mate Pro 20 - Dialog repetitively appears after successful connection (sometimes)
Huawei P40 Lite - Doesn't call onLost()
CAT S62 Pro - No issues found
Sony Xperia SZ2 - No issues found
Samsung Note10 - No issues found
In case if you want to connect to WiFi with INTERNET, you should use this kind of NetworkRequest:
NetworkRequest request = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.setNetworkSpecifier(wifiNetworkSpecifier)
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
.build();
Also, you need specify default route for your process to make requests to connected WiFi AP permanently. Just add call of next method to your NetworkCallback under onAvaliable like this:
networkCallback = new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(Network network) {
createNetworkRoute(network, connectivityManager);
}
};
if (connectivityManager!= null) connectivityManager.requestNetwork(request, networkCallback);
.
#RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private static void createNetworkRoute(Network network, ConnectivityManager connectivityManager) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
connectivityManager.bindProcessToNetwork(network);
} else {
ConnectivityManager.setProcessDefaultNetwork(network);
}
}
Don't forget disconnect from the bound network:
connectivityManager.unregisterNetworkCallback(networkCallback);
Finally, you can find best practice in different libraries like WifiUtils.
You can try wifisuggestion api, I'm able to connect using them.
final WifiNetworkSuggestion suggestion1 =
new WifiNetworkSuggestion.Builder()
.setSsid("YOUR_SSID")
.setWpa2Passphrase("YOUR_PRE_SHARED_KEY")
.build();
final List<WifiNetworkSuggestion> suggestionsList =
new ArrayList<WifiNetworkSuggestion>();
suggestionsList.add(suggestion1);
WifiManager wifiManager =
(WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
int status = wifiManager.addNetworkSuggestions(suggestionsList);
if (status == 0 ){
Toast.makeText(this,"PSK network added",Toast.LENGTH_LONG).show();
Log.i(TAG, "PSK network added: "+status);
}else {
Toast.makeText(this,"PSK network not added",Toast.LENGTH_LONG).show();
Log.i(TAG, "PSK network not added: "+status);
}
Since Android 10, I've have to use the following code to connect to a specific wifi network.
private ConnectivityManager mConnectivityManager;
#Override
public void onCreate(#Nullable Bundle savedInstanceState){
// instantiate the connectivity manager
mConnectivityManager = (ConnectivityManager) this.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
}
public void connect(String ssid, String password) {
NetworkSpecifier networkSpecifier = new WifiNetworkSpecifier.Builder()
.setSsid(ssid)
.setWpa2Passphrase(password)
.setIsHiddenSsid(true) //specify if the network does not broadcast itself and OS must perform a forced scan in order to connect
.build();
NetworkRequest networkRequest = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.setNetworkSpecifier(networkSpecifier)
.build();
mConnectivityManager.requestNetwork(networkRequest, mNetworkCallback);
}
public void disconnectFromNetwork(){
//Unregistering network callback instance supplied to requestNetwork call disconnects phone from the connected network
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
}
private ConnectivityManager.NetworkCallback mNetworkCallback = new ConnectivityManager.NetworkCallback(){
#Override
public void onAvailable(#NonNull Network network) {
super.onAvailable(network);
//phone is connected to wifi network
}
#Override
public void onLosing(#NonNull Network network, int maxMsToLive) {
super.onLosing(network, maxMsToLive);
//phone is about to lose connection to network
}
#Override
public void onLost(#NonNull Network network) {
super.onLost(network);
//phone lost connection to network
}
#Override
public void onUnavailable() {
super.onUnavailable();
//user cancelled wifi connection
}
};
References:
https://anutoshdatta.medium.com/new-wifi-apis-on-android-10-481c525108b7
https://developer.android.com/guide/topics/connectivity/wifi-suggest
I was also facing the same issue, even after 3 months I was unable to solve this. But I have found one awesome and cool solution.
startActivity(new Intent("android.settings.panel.action.INTERNET_CONNECTIVITY"))
Just add these lines instead of connecting to the wifi from the app, this will prompt user to select a wifi and connect and as soon as user do it, it will connect to the wifi and also it will have internet also.
Just connecting to the wifi from the app will not access the internet. Do this, this is the best solution.
So, the solution for me is compile your app with targetSdkVersion 28.
and for connection to wifi use this function
connectToWifi(String ssid, String key)
it's just a workaround for the moment, waiting Google to publish a fix for this bug, for more information the issue reported to Google : issuetracker.google.com/issues/138335744
public void connectToWifi(String ssid, String key) {
Log.e(TAG, "connection wifi pre Q");
WifiConfiguration wifiConfig = new WifiConfiguration();
wifiConfig.SSID = "\"" + ssid + "\"";
wifiConfig.preSharedKey = "\"" + key + "\"";
int netId = wifiManager.addNetwork(wifiConfig);
if (netId == -1) netId = getExistingNetworkId(wifiConfig.SSID);
wifiManager.disconnect();
wifiManager.enableNetwork(netId, true);
wifiManager.reconnect();
}
If you have root access (adb root):
Manually connect to the Wifi Network of your choosing.
Pull these ADB files:
adb pull /data/misc/wifi/WifiConfigStore.xml
adb pull /data/misc/wifi/WifiConfigStore.xml.encrypted-checksum
Save in a folder that would designate the Wifi Network:
Ex: GarageWifi
Ex: BusinessWifi
Copy to location of your choosing. Don't change the names of the files you pulled.
Whenever you want to connect to a desired wifi network:
adb push <location>\WifiConfigStore.xml /data/misc/wifi/
adb push <location>\WifiConfigStore.xml.encrypted-checksum /data/misc/wifi/
adb reboot
Basically, what I need is check if my Wifi connection has Internet access. The most effective way I know is with sock.connect() but I need to be sure that the connection will be done through the Wifi network and this is my main issue,
I was searching for a few days about this and there is not a good response to this.
There are a lot of solutions like How do I see if Wi-Fi is connected on Android? but they only check if the device is connected to a router. I need to know if the router as internet access
My best approximation was this:
Socket sock = new Socket();
ConnectivityManager
cm = (ConnectivityManager) mContext.getApplicationContext()
.getSystemService(Context.CONNECTIVITY_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
Network net = cm.getActiveNetwork();
net.bindSocket(sock);
}
sock.connect(new InetSocketAddress("8.8.8.8", 53), 1500);
sock.close();
But this has some limitations. The biggest limitation is that only works for API >= 23.
Also, if I am in China I think that hostname "8.8.8.8" will not work, right?
And finally, cm.getActiveNetwork() will only be the WIFI network if my device is connected to a wifi network, and this is not totally true because it is possible to modify the default active network.
What I need to know is:
Is there any working alternative for API >= 16?
Is there a good hostname that will work fine in China?
Any help will be appreciated,
Thanks in advance!
Yes you have to check with a remote server in order to be sure.
A common way would be like this:
NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting();
if (isConnected) {
try {
InetAddress ipAddr = InetAddress.getByName("google.com");
if (ipAddr.isReachable(5000)) {
// Internet access OK!
}
} catch (Exception e) {
// Error handling...
}
}
Prefer domain names when calling getByName rather than IPs (https://docs.oracle.com/javase/7/docs/api/java/net/InetAddress.html#getByName(java.lang.String))
If you want to avoid the connectivity manager you can register a BroadcastReceiver for WifiManager.NETWORK_STATE_CHANGED_ACTION events and you will know if you are connected to a WiFi (the current state is received almost immediately).
As regards the region issue I am out of ideas, maybe use NTP servers instead of google (much more innocent servers) or try Baidu!?
Finally, I came to a solution:
public interface Consumer {
void accept(Boolean internet);
}
class InternetCheck extends AsyncTask<Void, Void, Boolean> {
private Consumer mConsumer;
public InternetCheck(Consumer consumer) {
mConsumer = consumer;
execute();
}
#Override
protected Boolean doInBackground(Void... voids) {
Socket socket = null;
try {
WifiManager wifiManager = (WifiManager) mContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
if (wifiManager != null) {
socket = new Socket();
socket.setKeepAlive(false);
String localIpAddress = getIpAddress(wifiManager);
socket.bind(new InetSocketAddress(localIpAddress, 0));
socket.connect(new InetSocketAddress("8.8.8.8", 53), 1500);
return true;
}
return false;
} catch (IOException e) {
//unbind();
return false;
}finally {
if(socket != null && !socket.isClosed()) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
#Override
protected void onPostExecute(Boolean internet) {
mConsumer.accept(internet);
}
}
public static String getIpAddress(WifiManager wifiManager) {
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
int ipAddress = wifiInfo.getIpAddress();
return String.format(Locale.getDefault(), "%d.%d.%d.%d", (ipAddress & 0xff), (ipAddress >> 8 & 0xff),
(ipAddress >> 16 & 0xff), (ipAddress >> 24 & 0xff));
}
I came to a solution after saw this question. With this, I obtained the IP address of my wifi connection and with this, I was able to bind the socket (socket.bind(...)) to the wifi connection and be check if my router had internet access.
I hope this solution helps somebody in the future :)
I'm using the following code to connect to a WiFi network without internet connection, because it hosts its own web-server where I want to connect even if there is no internet connection available.
WifiConfiguration wifiConfiguration = new WifiConfiguration();
wifiConfiguration.SSID = String.format("\"%s\"", scanResult.SSID);
wifiConfiguration.preSharedKey = String.format("\"%s\"", "secret");
int netId = wifiManager.addNetwork(wifiConfiguration)
wifiManager.disconnect();
wifiManager.enableNetwork(netId, true);
wifiManager.reconnect();
This works fine on every device below Android Marshmallow (I'm using CM13, so is it maybe related to CyanogenMod?): When I use this code to connect, Android still uses the mobile connection and mark the WiFi symbol with an exclamation mark. Seconds later it shows a notification with the question if I want to stay connected, because the network has no internet connection.
Problem: My app tries to connect automatically to my web-server which fail, because there is obviously no internet connection. Of course it would be possible to wait until I can reach my web-server, but it should work without user interaction.
How does ChromeCast or any other IoT device solve this? I never saw a notification like this when I was setting up my ChromeCast device.
I solved this by binding (connectivityManager.bindProcessToNetwork(network);) the current process to the connected network. This prevents the "keep using this network" Dialog and allows you to communicate with the device over wifi.
NetworkRequest.Builder builder;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
builder = new NetworkRequest.Builder();
//set the transport type do WIFI
builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
connectivityManager.requestNetwork(builder.build(), new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(Network network) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (Build.VERSION.RELEASE.equalsIgnoreCase("6.0")) {
if (!Settings.System.canWrite(mActivity)) {
Intent goToSettings = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
goToSettings.setData(Uri.parse("package:" + mActivity.getPackageName()));
mActivity.startActivity(goToSettings);
}
}
connectivityManager.bindProcessToNetwork(null);
if (mSsid.contains("my_iot_device-xxxxxxxxx")) {
connectivityManager.bindProcessToNetwork(network);
} else {
}
} else {
//This method was deprecated in API level 23
ConnectivityManager.setProcessDefaultNetwork(null);
if (mSsid.contains("my_iot_device-xxxxxxxxx")) {
ConnectivityManager.setProcessDefaultNetwork(network);
} else {
}
}
try {
//do a callback or something else to alert your code that it's ok to send the message through socket now
} catch (Exception e) {
Crashlytics.logException(e);
e.printStackTrace();
}
connectivityManager.unregisterNetworkCallback(this);
}
});
}
When I tried to enable wifi tethering from the following code it throws the exception
java.lang.reflect.InvocationTargetException at java.lang.reflect.Method.invoke(Native Method) at com.....
.... not granted this permission: android.permission.WRITE_SETTINGS
But this works fine in android 6.0 and below versions. And also tried with giving android.permission.WRITE_SETTINGS too.
Is there any limitation in accessing wifiAP in android 6.1?
Follow I attached the code sample that I used to enable hotspot.
WifiConfiguration netConfig = new WifiConfiguration();
netConfig.SSID = ssId;
netConfig.preSharedKey = passkey;
netConfig.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
netConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
try {
boolean apstatus = (Boolean) method.invoke(wifiManager, netConfig, true);
for (Method isWifiApEnabledmethod : wmMethods) {
if (isWifiApEnabledmethod.getName().equals("isWifiApEnabled")) {
while (!(Boolean) isWifiApEnabledmethod.invoke(wifiManager)) {}
for (Method method1 : wmMethods) {
if (method1.getName().equals("getWifiApState")) {
int apstate;
apstate = (Integer) method1.invoke(wifiManager);
Log.i(TAG, "Apstate ::: " + apstate);
}
}
}
}
if (apstatus) {
Log.d(TAG, "Access Point created");
} else {
Log.d(TAG, "Access Point creation failed");
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
I think Android M don't support to create hotspot programmatically . You can take your Marshmallow user to settings page to create hotspot by himself. below code will help yo to go setting page.
startActivity(
new Intent(Settings.ACTION_SETTINGS));
This is not the correct way.But this fixed the issue.
Changed the target sdk version to 21. Then hotspot will start programmatically even in android 6.0.1. Think there should be a proper way to do this for android 6 and later versions. I think requesting runtime permissions needs to execute those kind of processess.
This talks about the android permission requesting in runtime
Set target SDK version 21 and ask for write_settings permission in your activity. Also add android.permission.WRITE_SETTINGS permission in manifest.
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.WRITE_SETTINGS)){
}else {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_SETTINGS},
121);
}
For more details please visit http://developer.android.com/training/permissions/requesting.html
Guys I tried everything and I wasn't able to start the hotspot in Android 6.0.
You can just check if Api is >= 23, and if so just take the user to settings page to create hotspot by himself.
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
final Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
final ComponentName cn = new ComponentName(
"com.android.settings",
"com.android.settings.TetherSettings");
intent.setComponent(cn);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity( intent);
}else{
createhotSpot();
}
Permission is not your problem. You need something like this code :
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.System.canWrite(getApplicationContext())) {
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS, Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, 200); //You need a callback for activity result so that check if user enabled this feature, go for starting hotspot (google for it)
} else {
// Do your stuff about starting hotspot (in network thread)
}
}
I'm developing an app that needs that the device creates an access point. I'm testing the code on a Nexus 7 (Android 4.2.1) and a Nexus 10 (4.2.2) and I get the same problem in both. I manage to enable the access point but every device that tries to connect stays "Obtaining ip address". Any idea why? I tested the same code in a galaxy tab 10" (Android 4.0.3) and it works perfect.
private void createWifiAccessPoint(String pSSID)
{
if(mWifiManager.isWifiEnabled())
{
mWifiManager.setWifiEnabled(false);
}
Method[] wmMethods = mWifiManager.getClass().getDeclaredMethods();
boolean methodFound=false;
for(Method method: wmMethods){
if(method.getName().equals("setWifiApEnabled"))
{
methodFound=true;
WifiConfiguration netConfig = new WifiConfiguration();
netConfig.SSID = pSSID;
try {
boolean apstatus = (Boolean) method.invoke(mWifiManager, netConfig,true);
for (Method isWifiApEnabledmethod: wmMethods)
{
if(isWifiApEnabledmethod.getName().equals("isWifiApEnabled"))
{
while(!(Boolean)isWifiApEnabledmethod.invoke(mWifiManager)){
};
for(Method method1: wmMethods){
if(method1.getName().equals("getWifiApState")){
int apstate;
apstate=(Integer)method1.invoke(mWifiManager);
Toast.makeText(this, netConfig.SSID + String.valueOf(apstate), Toast.LENGTH_LONG).show();
}
}
}
}
if(apstatus)
{
System.out.println("success");
}else
{
System.out.println("failed");
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
if(!methodFound){
}
}
I suspect your problem is that the device you are trying to connect with is expected to be supplied with an IP address etc, from the DHCP server in the Nexus device. Your code is just creating an access point. You probably need a static IP address on both ends of the link. That said, I'm not sure how that should be done, as I have more or less exactly the same problem myself.
See Unable to programatically create working Wi-Fi access point on Jellybean tablet
I have attempted to associate an IP address with the access point, and although I appear to have done that, I have still been unable to establish a connection so I only have a partial answer to your question I'm afraid.