19

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

Cœur
  • 32,421
  • 21
  • 173
  • 232
Chandrakanth
  • 3,495
  • 2
  • 14
  • 29

3 Answers3

22

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.

deLock
  • 656
  • 7
  • 16
Jon
  • 2,072
  • 2
  • 23
  • 29
  • Hi! I was checking your solution and is awesome, it works perfectly, nice job. – rul3s Aug 02 '18 at 10:02
  • @Jon It's working.... do you have idea that how to change name and pass of hotspot on oreo? – Anuj J Pandey Aug 09 '18 at 14:30
  • 1
    @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. – Jon Aug 12 '18 at 07:03
  • @Jon thanks for reverting, I found the solution and thanks again for such awesome work, on reflection... keep it up. – Anuj J Pandey Aug 12 '18 at 08:35
  • @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. – Jon Aug 13 '18 at 19:32
  • sure, shortly I'll. – Anuj J Pandey Aug 17 '18 at 03:32
  • Thanks,you saved my day! – Jiawei Yang Aug 21 '18 at 10:56
  • @AnujJPandey Great to hear that you got some solution for fetching name and password for WifiHotspot. Can you please share the code. – Vishal Sharma Aug 31 '18 at 12:21
  • how can we read the name and pass of wifi hotspot in Android Oreo?? – Vishal Sharma Aug 31 '18 at 12:22
  • @VishalSharma Method getConfigMethod = mWifiManager.getClass().getMethod("getWifiApConfiguration"); wifiConfig = (WifiConfiguration) getConfigMethod.invoke(mWifiManager); – Anuj J Pandey Sep 04 '18 at 04:55
  • @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? – Vishal Sharma Sep 04 '18 at 07:25
  • Yes because it's only allowed to system signed build/vendor app. – Anuj J Pandey Sep 06 '18 at 03:28
  • But you mentioned above that you got it working in Android Oreo. Anyways thanks for answering! – Vishal Sharma Sep 06 '18 at 08:22
  • @Jon 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?? – Vishal Sharma Sep 07 '18 at 09:49
  • @AnujJPandey can i Know how to change the hotspot name in oreo? – MJM Jan 18 '19 at 12:12
  • @MJM yes, I'll update that, please create separate question, because this do not relate with the current question – Anuj J Pandey Feb 01 '19 at 15:55
  • @AnujJPandey I have added new question https://stackoverflow.com/q/54500228/8603832 please reply on that – MJM Feb 03 '19 at 05:28
  • @MJM here is the git link for configuration of wifi hotspot name and pass :https://github.com/anujjpandey/HotSpotOnOreo Please rate up the ans if it's work for you – Anuj J Pandey Feb 04 '19 at 14:18
19

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

Chandrakanth
  • 3,495
  • 2
  • 14
  • 29
  • 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? – Jean Creuzé des Châtelliers Oct 16 '17 at 15:29
  • 1
    @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. – Chandrakanth Oct 18 '17 at 05:11
  • Oops, sorry. I forgot to activate the ACCESS_COARSE_LOCATION permission although I added it in the manifest. – Jean Creuzé des Châtelliers Oct 19 '17 at 08:50
  • 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... – Jean Creuzé des Châtelliers Oct 19 '17 at 08:53
  • 8
    How do I set the SSID name using this method? Right now I get something like "AndroidShare_xxxx" – Markinson Dec 05 '17 at 12:17
  • 3
    This is fine when you want to create a closed network. Your hotspot will not have internet access. See [https://developer.android.com/reference/android/net/wifi/WifiManager.html#startLocalOnlyHotspot(android.net.wifi.WifiManager.LocalOnlyHotspotCallback, android.os.Handler)] – Ed Manners Dec 19 '17 at 16:37
  • 1
    Okay, but how to turn on the WiFi Hotspot with internet? – AidenFry Jan 02 '18 at 17:29
  • @AidenFry_HREUK..I think if Mobile data is ON then hotspot automatically share internet with connected devices. – Chandrakanth Jan 03 '18 at 05:34
  • 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." – Ton Mar 27 '18 at 10:40
  • @Ton..I added method to close the hotspot. – Chandrakanth Mar 28 '18 at 11:53
  • @Chandrakanth 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.." https://developer.android.com/reference/android/net/wifi/WifiManager#startLocalOnlyHotspot(android.net.wifi.WifiManager.LocalOnlyHotspotCallback,%20android.os.Handler) DO YOU HAVE ANY IDEA HOW WE CAN TURN ON IT FOR INTERNET CONNECTION? – Anuj J Pandey Aug 08 '18 at 12:25
  • @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. – Chandrakanth Aug 09 '18 at 06:59
  • i dont know why the answer was given ^ as this does not fulfill the need. This way you donot have internet. – Bilal Shahid Dec 18 '18 at 18:14
  • @BilalShahid..Here the question is about how to turn on hotspot. It is not for internet connectivity. This is for shareit like apps. – Chandrakanth Dec 19 '18 at 06:38
  • @Chandrakanth thanks, I got the solution and it's working fine for me. – Anuj J Pandey Feb 01 '19 at 15:53
  • @AnujJPandey can you share the solution? – Chandrakanth Feb 04 '19 at 13:39
  • @Chandrakanth you can implement turn on/off using this project on git : https://github.com/aegis1980/WifiHotSpot For Configuration follow this link: https://stackoverflow.com/questions/54500228/how-to-change-wificonfigration-in-oreo-device – Anuj J Pandey Feb 04 '19 at 14:15
  • after restarting app you won't have reference mReservation to disable wifi hotspot, so you have to enable first and then disable – user924 Sep 19 '19 at 07:46
  • `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) – user924 Sep 19 '19 at 07:47
3

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;
}
Vishal Sharma
  • 516
  • 1
  • 4
  • 16