How to turn on/off wifi hotspot programmatically in Android 8.0 (Oreo)
Asked Answered
K

3

22

I know how to turn on/off wifi hot spot using reflection in android using below method.

private static boolean changeWifiHotspotState(Context context,boolean enable) {
        try {
            WifiManager manager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
            Method method = manager.getClass().getDeclaredMethod("setWifiApEnabled", WifiConfiguration.class,
                    Boolean.TYPE);
            method.setAccessible(true);
            WifiConfiguration configuration = enable ? getWifiApConfiguration(manager) : null;
            boolean isSuccess = (Boolean) method.invoke(manager, configuration, enable);
            return isSuccess;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

But the above method is not working Android 8.0(Oreo).

When I execute above method in Android 8.0, I am getting below statement in logcat.

com.gck.dummy W/WifiManager: com.gck.dummy attempted call to setWifiApEnabled: enabled = true

Is there any other way to on/off hotspot on android 8.0

Ki answered 31/8, 2017 at 14:48 Comment(3)
Do you want to turn off wifi or hotspotTrifoliate
I want to turn on/off hotspot...not wifi...Ki
is it possible that they removed this way of doing it in Android O? Turning on the wifi hotspot isn't part of the Android sdk. So this way that's been going around using reflection is somewhat hackyRoommate
K
21

Finally I got the solution. Android 8.0, they provided public api to turn on/off hotspot. WifiManager

Below is the code to turn on hotspot

private WifiManager.LocalOnlyHotspotReservation mReservation;

@RequiresApi(api = Build.VERSION_CODES.O)
private void turnOnHotspot() {
    WifiManager manager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);

    manager.startLocalOnlyHotspot(new WifiManager.LocalOnlyHotspotCallback() {

        @Override
        public void onStarted(WifiManager.LocalOnlyHotspotReservation reservation) {
            super.onStarted(reservation);
            Log.d(TAG, "Wifi Hotspot is on now");
            mReservation = reservation;
        }

        @Override
        public void onStopped() {
            super.onStopped();
            Log.d(TAG, "onStopped: ");
        }

        @Override
        public void onFailed(int reason) {
            super.onFailed(reason);
            Log.d(TAG, "onFailed: ");
        }
    }, new Handler());
}

private void turnOffHotspot() {
    if (mReservation != null) {
        mReservation.close();
    }
}

onStarted(WifiManager.LocalOnlyHotspotReservation reservation) method will be called if hotspot is turned on.. Using WifiManager.LocalOnlyHotspotReservation reference you call close() method to turn off hotspot.

Note: To turn on hotspot, the Location(GPS) should be enabled in the device. Otherwise, it will throw SecurityException

Ki answered 1/9, 2017 at 8:56 Comment(19)
I've got this error "java.lang.SecurityException: UID 10103 does not have Location permission" although I enabled the Location in the device and add the permissions in the manifest file. What are the permissions you added?Selflove
@JeanCreuzédesChâtelliers As per the docs, app should have CHANGE_WIFI_STATE and ACCESS_COARSE_LOCATION permissions. And before turning on Hotspot, GPS(location) should be on. Make sure that above mentioned 2 permissions are granted.Ki
Oops, sorry. I forgot to activate the ACCESS_COARSE_LOCATION permission although I added it in the manifest.Selflove
But something I don't understand is when I activate the hotspot manually, I don't have to activate the GPS but when I activate the hotspot programmatically, I need the GPS...Selflove
How do I set the SSID name using this method? Right now I get something like "AndroidShare_xxxx"Pollak
This is fine when you want to create a closed network. Your hotspot will not have internet access. See [developer.android.com/reference/android/net/wifi/…, android.os.Handler)]Acheron
Okay, but how to turn on the WiFi Hotspot with internet?Squamation
@AidenFry_HREUK..I think if Mobile data is ON then hotspot automatically share internet with connected devices.Ki
Please, could you provide the code to close the hotspot. I don't understand what you say with "Using WifiManager.LocalOnlyHotspotReservation reference you call close() method to turn off hotspot."Relativity
@Ton..I added method to close the hotspot.Ki
@Ki As per android docs this method. "Request a local only hotspot that an application can use to communicate between co-located devices connected to the created WiFi hotspot. The network created by this method will not have Internet access.." developer.android.com/reference/android/net/wifi/… DO YOU HAVE ANY IDEA HOW WE CAN TURN ON IT FOR INTERNET CONNECTION?Moselle
@AnujJPandey Sorry I didn't find any way to turn on hotspot with the internet connection. If I found any solution, I will update the answer.Ki
i dont know why the answer was given ^ as this does not fulfill the need. This way you donot have internet.Margarettmargaretta
@BilalShahid..Here the question is about how to turn on hotspot. It is not for internet connectivity. This is for shareit like apps.Ki
@Ki thanks, I got the solution and it's working fine for me.Moselle
@AnujJPandey can you share the solution?Ki
@Ki you can implement turn on/off using this project on git : github.com/aegis1980/WifiHotSpot For Configuration follow this link: #54500728Moselle
after restarting app you won't have reference mReservation to disable wifi hotspot, so you have to enable first and then disableAndromede
wifiManager.isWifiEnabled = false is deprecated but it still works for disabling WiFi and WiFi HotSpot and it's better then your solution for disabling WiFi because you don't need mReservation (which will be destroyed when app dies)Andromede
H
24

I thought the LocalOnlyHotspot route was the way to, but as @edsappfactory.com said in the comments - it only gives closed network, no internet access.

In Oreo hot-spotting/tethering moved to ConnectionManager, and its annotated @SystemApi, so (nominally) inaccessible.

As part of something else I was doing, I made an app and put it on github here. It uses reflection to get at the function and DexMaker to generate a subclass of ConnectionManager.OnStartTetheringCallback (which is also inaccessible).

Think it all works okay - bit rough around the edges, so please feel free to make better!

Relevant bits of code are in:

I lost patience trying to get my DexMaker-generated callback to fire the MyOnStartTetheringCallback so all that code is in disarray and commented out.

Hyperspace answered 19/3, 2018 at 5:20 Comment(18)
Hi! I was checking your solution and is awesome, it works perfectly, nice job.Heisenberg
@Hyperspace It's working.... do you have idea that how to change name and pass of hotspot on oreo?Moselle
@AnujJPandey somebody else actually asked me that on GitHub recently. You would have to find where they moved methods for changing those settings in the Android code and maybe try using Reflection. Do not think its in ConnectionManager. Sorry can't be much more help.Hyperspace
@Hyperspace thanks for reverting, I found the solution and thanks again for such awesome work, on reflection... keep it up.Moselle
@anujjpandey Great. Any chance you could put your solution somewhere - in a Gist or GitHub so I can point ppl towards it next time I'm asked? Could commit to my original gitgub code if that easier.Hyperspace
sure, shortly I'll.Moselle
Thanks,you saved my day!Who
@AnujJPandey Great to hear that you got some solution for fetching name and password for WifiHotspot. Can you please share the code.Winterwinterbottom
how can we read the name and pass of wifi hotspot in Android Oreo??Winterwinterbottom
@VishalSharma Method getConfigMethod = mWifiManager.getClass().getMethod("getWifiApConfiguration"); wifiConfig = (WifiConfiguration) getConfigMethod.invoke(mWifiManager);Moselle
@AnujJPandey I tried this ealrier as well, and tried again after your suggestion, but it's throwing an exception :::: Caused by: java.lang.SecurityException: App not allowed to read or update stored WiFi Ap config. Is there somthing that needs to be added for accessing this method?Winterwinterbottom
Yes because it's only allowed to system signed build/vendor app.Moselle
But you mentioned above that you got it working in Android Oreo. Anyways thanks for answering!Winterwinterbottom
@Hyperspace I got an issue on LG devices with version 8.0, "startTethering" method call is throwing an exception "NoSuchMethodException". Is there some case that this will not work in LG devices??Winterwinterbottom
@AnujJPandey can i Know how to change the hotspot name in oreo?Zephyr
@Zephyr yes, I'll update that, please create separate question, because this do not relate with the current questionMoselle
@AnujJPandey I have added new question https://mcmap.net/q/271159/-how-to-change-wificonfigration-in-oreo-device/8603832 please reply on thatZephyr
@Zephyr here is the git link for configuration of wifi hotspot name and pass :github.com/anujjpandey/HotSpotOnOreo Please rate up the ans if it's work for youMoselle
K
21

Finally I got the solution. Android 8.0, they provided public api to turn on/off hotspot. WifiManager

Below is the code to turn on hotspot

private WifiManager.LocalOnlyHotspotReservation mReservation;

@RequiresApi(api = Build.VERSION_CODES.O)
private void turnOnHotspot() {
    WifiManager manager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);

    manager.startLocalOnlyHotspot(new WifiManager.LocalOnlyHotspotCallback() {

        @Override
        public void onStarted(WifiManager.LocalOnlyHotspotReservation reservation) {
            super.onStarted(reservation);
            Log.d(TAG, "Wifi Hotspot is on now");
            mReservation = reservation;
        }

        @Override
        public void onStopped() {
            super.onStopped();
            Log.d(TAG, "onStopped: ");
        }

        @Override
        public void onFailed(int reason) {
            super.onFailed(reason);
            Log.d(TAG, "onFailed: ");
        }
    }, new Handler());
}

private void turnOffHotspot() {
    if (mReservation != null) {
        mReservation.close();
    }
}

onStarted(WifiManager.LocalOnlyHotspotReservation reservation) method will be called if hotspot is turned on.. Using WifiManager.LocalOnlyHotspotReservation reference you call close() method to turn off hotspot.

Note: To turn on hotspot, the Location(GPS) should be enabled in the device. Otherwise, it will throw SecurityException

Ki answered 1/9, 2017 at 8:56 Comment(19)
I've got this error "java.lang.SecurityException: UID 10103 does not have Location permission" although I enabled the Location in the device and add the permissions in the manifest file. What are the permissions you added?Selflove
@JeanCreuzédesChâtelliers As per the docs, app should have CHANGE_WIFI_STATE and ACCESS_COARSE_LOCATION permissions. And before turning on Hotspot, GPS(location) should be on. Make sure that above mentioned 2 permissions are granted.Ki
Oops, sorry. I forgot to activate the ACCESS_COARSE_LOCATION permission although I added it in the manifest.Selflove
But something I don't understand is when I activate the hotspot manually, I don't have to activate the GPS but when I activate the hotspot programmatically, I need the GPS...Selflove
How do I set the SSID name using this method? Right now I get something like "AndroidShare_xxxx"Pollak
This is fine when you want to create a closed network. Your hotspot will not have internet access. See [developer.android.com/reference/android/net/wifi/…, android.os.Handler)]Acheron
Okay, but how to turn on the WiFi Hotspot with internet?Squamation
@AidenFry_HREUK..I think if Mobile data is ON then hotspot automatically share internet with connected devices.Ki
Please, could you provide the code to close the hotspot. I don't understand what you say with "Using WifiManager.LocalOnlyHotspotReservation reference you call close() method to turn off hotspot."Relativity
@Ton..I added method to close the hotspot.Ki
@Ki As per android docs this method. "Request a local only hotspot that an application can use to communicate between co-located devices connected to the created WiFi hotspot. The network created by this method will not have Internet access.." developer.android.com/reference/android/net/wifi/… DO YOU HAVE ANY IDEA HOW WE CAN TURN ON IT FOR INTERNET CONNECTION?Moselle
@AnujJPandey Sorry I didn't find any way to turn on hotspot with the internet connection. If I found any solution, I will update the answer.Ki
i dont know why the answer was given ^ as this does not fulfill the need. This way you donot have internet.Margarettmargaretta
@BilalShahid..Here the question is about how to turn on hotspot. It is not for internet connectivity. This is for shareit like apps.Ki
@Ki thanks, I got the solution and it's working fine for me.Moselle
@AnujJPandey can you share the solution?Ki
@Ki you can implement turn on/off using this project on git : github.com/aegis1980/WifiHotSpot For Configuration follow this link: #54500728Moselle
after restarting app you won't have reference mReservation to disable wifi hotspot, so you have to enable first and then disableAndromede
wifiManager.isWifiEnabled = false is deprecated but it still works for disabling WiFi and WiFi HotSpot and it's better then your solution for disabling WiFi because you don't need mReservation (which will be destroyed when app dies)Andromede
W
4

As per Jon suggestion, I got another way to enable WifiHotSpot in Android Oreo and above.

public boolean enableTetheringNew(MyTetheringCallback callback) {
    File outputDir = mContext.getCodeCacheDir();
    try {
        proxy = ProxyBuilder.forClass(classOnStartTetheringCallback())
                .dexCache(outputDir).handler(new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                       switch (method.getName()) {
                            case "onTetheringStarted":
                                callback.onTetheringStarted();
                                break;
                            case "onTetheringFailed":
                                callback.onTetheringFailed();
                                break;
                            default:
                                ProxyBuilder.callSuper(proxy, method, args);
                        }
                        return null;
                    }

                }).build();
    } catch (IOException e) {
        e.printStackTrace();
    }
    ConnectivityManager manager = (ConnectivityManager) mContext.getApplicationContext().getSystemService(ConnectivityManager.class);

    Method method = null;
    try {
        method = manager.getClass().getDeclaredMethod("startTethering", int.class, boolean.class, classOnStartTetheringCallback(), Handler.class);
        if (method == null) {
            Log.e(TAG, "startTetheringMethod is null");
        } else {
            method.invoke(manager, TETHERING_WIFI, false, proxy, null);

        }
        return true;
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
    return false;
}

private Class classOnStartTetheringCallback() {
    try {
        return Class.forName("android.net.ConnectivityManager$OnStartTetheringCallback");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
    return null;
}
Winterwinterbottom answered 7/9, 2018 at 9:47 Comment(12)
What is ProxyBuilder? And where are your constant declarations?Sapsucker
ProxyBuilder is similar to the java.lang.reflect.Proxy class, but this works for classes instead of interfaces (java.lang.reflect.Proxy works).Winterwinterbottom
Hi @VishalSharma, is this working on Oreo, shares internet after Tether?Supersede
@KanakSony Yes it is working on almost all the Oreo devices with internet sharing except the LGE one.Winterwinterbottom
thats' great! Can I somehow get the working snippet please?Supersede
can you please share if you have a working version? Thanks.Westbrooks
yeah, if anybody has a working sample, it would be greatly appreciated.Wednesday
anybody has succeeded in making this code working ?Memorandum
Yes is working fine, but there are some missing informations here. First of all, you need to import DexMaker github.com/linkedin/dexmaker to make it work, because that's the only way to access to ProxyBuilder. And then you have to define your own callback, that this method need to call when tethering is started or there are errors while starting it down.Spouse
Right, This requires DexMaker and after adding dexmaker, the above code can be utilized to enable tethering.Winterwinterbottom
@VishalSharma I have everything wired up properly, but I have no idea what to do with the TETHERING_WIFI constant. Could you explain what value is supposed to go there? Thank you!Criminate
@Criminate Hi, got little late, but your answer is : private static final int TETHERING_WIFI = 0;Winterwinterbottom

© 2022 - 2024 — McMap. All rights reserved.