Android : Reconnect to Wi-Fi after entering coverage area while screen turned off

后端 未结 3 803
迷失自我
迷失自我 2020-12-05 22:34

I have been struggling with automatically turning on Wi-Fi as soon as the device is within range of an access point without turning on the screen. It has been very frustrati

3条回答
  •  长情又很酷
    2020-12-05 23:05

    My scenario is slightly different - I do not hold a wifi lock to begin with (and I am on regular android so I had to translate your method).

    Screen off, CPU off, radio dies. Alarm wakes my (wakeful) service up - I hold a (partial) wake lock.

    What I want is - if wifi is enabled to connect to the access point it was connected before the radio died - I acquire a wifi lock and I call your function - wakeWifiUp(). When the radio has died (!wifiInfo.IsConnectedOrConnecting is true) I get a network unreachable when I try to connect. I workaround it as in :

    public final class NetworkService extends WakefulIntentService {
    
        // this is an intent service - runs on its own thread - otherwise it would
        // deadlock as I am using it. Moreover it holds a wakelock and woken up by
        // an AlarmManager's Receiver - works reliably
        private BroadcastReceiver mConnectionReceiver;
        private volatile static CountDownLatch latch;
    
        @Override
        protected void doWakefulWork(Intent intent) {
            WifiLock _wifiLock = null;
            WifiManager wm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
            boolean failedToConnect = true;
            if (wm != null && wm.isWifiEnabled()) {// Don't want to enable it myself
                _wifiLock = wm.createWifiLock(
                /* WifiManager.WIFI_MODE_FULL_HIGH_PERF */0x3, this.getClass()
                    .getName() + ".WIFI_LOCK");
                _wifiLock.acquire();
                failedToConnect = !wakeWifiUp();
            }
            if (failedToConnect) {
                if (_wifiLock != null) _wifiLock.release();
                w("No connection !");
                return;
            }
            HttpURLConnection connection = null;
            try {
                connection = connection(); 
            } catch (IOException e) {/* won't throw - it doesn't do much*/}
            OutputStream serverOutputStream = null;
            try {
                serverOutputStream = connection.getOutputStream(); // now
                // this is really where the connection might seriously throw
                // .... Work ....
            } catch (IOException e) {
                w("IOException sending data " + e.getMessage());
                // I get here : Network unreachable when radio dies
            } finally {
                if (_wifiLock != null) _wifiLock.release();
                if (connection != null) connection.disconnect();
            }
        }
    
        private HttpURLConnection connection() throws MalformedURLException,
                IOException {
            HttpURLConnection connection = (HttpURLConnection) new URL("localhost")
                .openConnection();
            connection.setDoOutput(true); // triggers POST
            connection.setRequestProperty("Connection", "Keep-Alive");
            connection.setRequestProperty("User-Agent",
                "Android Multipart HTTP Client 1.1");
            return connection;
        }
    
        private boolean wakeWifiUp() {
            ConnectivityManager _androidConnectivityMgr = (ConnectivityManager)
                    getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo wifiInfo = _androidConnectivityMgr
                .getNetworkInfo(ConnectivityManager.TYPE_WIFI);
            WifiManager _wifiManager = (WifiManager)
                    getSystemService(Context.WIFI_SERVICE);
            final int wifiState = _wifiManager.getWifiState();
            if (!_wifiManager.isWifiEnabled()
                || wifiState == WifiManager.WIFI_STATE_DISABLED
                || wifiState == WifiManager.WIFI_STATE_DISABLING) {
                // Make sure the Wi-Fi is enabled, required for some devices when
                // enable WiFi does not occur immediately
                d("!_wifiManager.isWifiEnabled()");
                _wifiManager.setWifiEnabled(true);
                // do not enable if not enabled ! FIXME
                return false;
            }
            if (!wifiInfo.isConnectedOrConnecting()) {
                d("Wifi is NOT Connected Or Connecting - "
                    + "wake it up and wait till is up");
                // Do not wait for the OS to initiate a reconnect to a Wi-Fi router
                _wifiManager.pingSupplicant();
                if (wifiState == WifiManager.WIFI_STATE_ENABLED) {
                    try {
                        // Brute force methods required for some devices
                        _wifiManager.setWifiEnabled(false);
                        _wifiManager.setWifiEnabled(true);
                    } catch (SecurityException e) {
                        // Catching exception which should not occur on most
                        // devices. OS bug details at :
                        // https://code.google.com/p/android/issues/detail?id=22036
                    }
                }
                _wifiManager.disconnect();
                _wifiManager.startScan();
                _wifiManager.reassociate();
                _wifiManager.reconnect();
                // THIS IS WHAT I DO TO WAIT FOR A CONNECTION
                try {
                    mConnectionReceiver = new WifiConnectionMonitor();
                    startMonitoringConnection();
                    latch = new CountDownLatch(1);
                    w("I wait");
                    latch.await();
                    w("Woke up");
                    return true; // made it
                } catch (InterruptedException e) {
                    w("Interrupted while waiting for connection", e);
                    return false;
                } finally {
                    stopMonitoringConnection();
                }
            }
            return true;
        }
    
        static void downTheLatch() {
            latch.countDown();
        }
    
        private synchronized void startMonitoringConnection() {
            IntentFilter aFilter = new IntentFilter(
                ConnectivityManager.CONNECTIVITY_ACTION);
            aFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
            registerReceiver(mConnectionReceiver, aFilter);
        }
    
        private synchronized void stopMonitoringConnection() {
            unregisterReceiver(mConnectionReceiver);
        }
    
        private final class WifiConnectionMonitor extends BroadcastReceiver {
    
            @Override
            public void onReceive(Context context, Intent in) {
                String action = in.getAction();
                if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
                    NetworkInfo networkInfo = in
                        .getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
                    d(networkInfo + "");
                    if (networkInfo.isConnected()) {
                        d("Wifi is connected!");
                        NetworkService.downTheLatch(); // HERE THE SERVICE IS WOKEN!
                    }
                }
            }
        }
    }
    

    Btw not all the tricks in wakeWifiUp() are needed (in my case) and all the !_wifiManager.isWifiEnabled() may be ommited - as I only use the net if enabled by the user. I leave it for completeness.

    Recap : in my scenario your method was not enough (if I translated correctly to java and didn't make some silly mistake, which always applies - see also my connection()). I needed to wait for connection to be established - but then all was fine. Not sure still how exactly you were using it - if as I do then the difference might be that you were holding a wifi lock all along

    HTC Nexus 1, 2.3.7, Cyanogen mod (don't shoot I've been given it to test).

    Will keep you posted

提交回复
热议问题