https://stackoverflow.com/questions/3871824/how-do-i-keep-wifi-from-disconnecting-when-phone-is-asleep?noredirect=1&lq=1




I have a service which polls a server at certain intervals. I use an AlarmManager and a BroadcastReceiver to start the service. My problem is that after a certain duration, even though the Wifi is still enabled, but for some reason, my application can't contact the server. I get an "Unreachable network" error.

Note that I've already acquired a partial wake lock as well as a wifilock.

Here's my code for the BroadcastReceiver.

public class ServiceAlarmBroadcastReceiver extends BroadcastReceiver {
    public void onReceive(Context context, Intent intent) {
        WakeLock wakeLock = null;
        WifiLock wifiLock = null;
        try {
            PowerManager pm = (PowerManager) context
                    .getSystemService(Context.POWER_SERVICE);

            // acquire a WakeLock to keep the CPU running
            wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                    "MyWakeLock");
            if(!wakeLock.isHeld()){
                wakeLock.acquire();
            }

            Log.i("ServiceAlarmBroadcastReceiver", "WakeLock acquired!");


            WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
            wifiLock = wm.createWifiLock(WifiManager.WIFI_MODE_FULL , "MyWifiLock");
            if(!wifiLock.isHeld()){
                wifiLock.acquire();
            }

            Log.i("ServiceAlarmBroadcastReceiver", "WifiLock acquired!");
            context.startService(new Intent(context, ThePollerService.class));
        } finally {
            // release the WakeLock to allow CPU to sleep
            if (wakeLock != null) {
                if (wakeLock.isHeld()) {
                    wakeLock.release();
                    Log.i("ServiceAlarmBroadcastReceiver", "WakeLock released!");
                }
            }

            // release the WifiLock
            if (wifiLock != null) {
                if (wifiLock.isHeld()) {
                    wifiLock.release();
                    Log.i("ServiceAlarmBroadcastReceiver", "WiFi Lock released!");
                }
            }
        }
    }
}
shareimprove this question
1 
How have you determined that the problem is with the WiFi connection falling asleep. An "Unreachable network" message may have other causes. Have you watched for connectivity broadcasts, or checked the WiFi state with WifiManager, or anything, to confirm your theory? – CommonsWare Oct 6 '10 at 11:17

The problem with the code posted here is that you acquire and release the WakeLock and WifiLock from right inside of your receiver. Unless you are completing your entire task inside of the onStart of your service (which if you are, why even bother having a service???), the locks will be released before your polling task completes.

I would suggest changing your implementation to something like the following:

  1. Have broadcast receiver start service (and that is all)
  2. Have service acquire wake locks and kick off the thread to do your polling operation. The most appropriate spot would be your service onCreate)
  3. After your polled operation is complete, you should stop your polling service
  4. In the onDestroy of your service, you should release the locks you acquired in onStart
shareimprove this answer
1 
Ok, let's assume I'm pooling every 6 hours. With that interval the device probably is in sleep mode with Wifi off. When I request the WAKE_LOCK for wifi, at onStart, it will enable wifi right? But as Wifi takes several seconds to connect to the access point, wont my service be unable to connect to the internet? – Paulo CesarNov 18 '11 at 12:09
   
If the user disabled Wifi, it won't reconnect just because you acquire a lock. Otherwise, you could wait until the active network is connected again before attempting to connect with your service. The WiFi shouldn't take long to be ready since its not entirely disconnected in sleep mode. In fact, I'm not sure if the ConnectivityManager even reports its not connected in that situation. – Justin Breitfeller Nov 19 '11 at 0:20
   
Hi Justin, I think got a nice solution, is to register a BroadcastReceiver that detects when a wifi connection was established, and then check if the last download was older then 12 hours (my pooling interval), and if it is, it will download. – Paulo Cesar Nov 22 '11 at 12:39

Thanks to Tom, I was able to resolve this issue. Here's the code:

Settings.System.putInt(getContentResolver(),
  Settings.System.WIFI_SLEEP_POLICY, 
  Settings.System.WIFI_SLEEP_POLICY_NEVER);
shareimprove this answer
4 
This actually looks very bad - battery wise. How about moving your wifi lock into your service implementation ? Is your service a WakefulIntentService ? The wake lock you get in your receiver won't do much – Mr_and_Mrs_D Apr 27 '13 at 20:49
   
The code above requires the following permission: <uses-permission android:name="android.permission.WRITE_SETTINGS" /> – Slavcho Jul 31 '13 at 9:06 
   
Note that this is deprecated as of API 17. See stackoverflow.com/a/18790243 – MZB Sep 23 '14 at 20:05

Under the WiFi Settings, Menu Key, Advanced Options theirs the WIFI_SLEEP_POLICY option list which when set to never will keep the WiFi connection open while the phone is asleep.

You can manipulate this under Settings.System Package.

http://developer.android.com/reference/android/provider/Settings.System.html#WIFI_SLEEP_POLICY

Hope this helps,

Tom

shareimprove this answer
   
THanks for the reply Tom. How do you actually change this setting? – javauser Oct 6 '10 at 15:12
   
Changing a user's setting for this is not recommended. You should wait with releasing the wake/wifilocks until your jobs are finished. – REJH Oct 1 '15 at 10:44

A little edit to javauser's answer:

private void setNeverSleepPolicy() {
        try {
            ContentResolver cr = getContentResolver();
            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) {
                int set = android.provider.Settings.System.WIFI_SLEEP_POLICY_NEVER;
                android.provider.Settings.System.putInt(cr, android.provider.Settings.System.WIFI_SLEEP_POLICY, set);
            } else {
                int set = android.provider.Settings.Global.WIFI_SLEEP_POLICY_NEVER;
                android.provider.Settings.System.putInt(cr, android.provider.Settings.Global.WIFI_SLEEP_POLICY, set);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
shareimprove this answer
1 
Changing a user's setting for this is not recommended. You should wait with releasing the wake/wifilocks until your jobs are finished. – REJH Oct 1 '15 at 10:44