/* * Copyright (C) 2012 asksven * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.asksven.betterwifionoff.services; import java.util.Calendar; import com.asksven.android.common.kernelutils.Wakelocks; import com.asksven.betterwifionoff.R; import com.asksven.betterwifionoff.TimedCheckAlarmReceiver; import com.asksven.betterwifionoff.WifiConnectedAlarmReceiver; import com.asksven.betterwifionoff.WifiOffAlarmReceiver; import com.asksven.betterwifionoff.data.CellDBHelper; import com.asksven.betterwifionoff.data.CellInfo; import com.asksven.betterwifionoff.data.CellLogEntry; import com.asksven.betterwifionoff.data.EventLogger; import com.asksven.betterwifionoff.utils.CellUtil; import com.asksven.betterwifionoff.utils.WifiControl; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.IBinder; import android.preference.PreferenceManager; import android.util.Log; /** * @author sven * */ public class SetWifiStateService extends Service { private static final String TAG = "BetterWifiOnOff.SetWifiStateService"; public static final String EXTRA_STATE = "com.asksven.betterwifionoff.WifiState"; public static final String EXTRA_REASON_OFF = "com.asksven.betterwifionoff.WifiReasonOff"; private static final int ALARM_WIFI_OFF = 12; private static final int ALARM_WIFI_CONNECTED = 13; private static final int ALARM_TIMER = 14; @Override public int onStartCommand(Intent intent, int flags, int startId) { SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); boolean state = intent.getBooleanExtra(EXTRA_STATE, false); // tells whether Wifi is turned off because it was scheduled to go off boolean reasonOff = intent.getBooleanExtra(EXTRA_REASON_OFF, false); Log.i(TAG, "Called with extra " + state + ", " + reasonOff); boolean bCheckWakelocks = sharedPrefs.getBoolean("wifi_on_if_wakelock", false); boolean bCheckKnownCid = sharedPrefs.getBoolean("wifi_on_only_when_known_cid", false); // if location awareness is on only turn on wifi when the cell id is known (tagged) if (state && bCheckKnownCid) { CellLogEntry cellInfo = CellUtil.getCurrentCell(this); if (cellInfo != null) { int cid = cellInfo.getCid(); CellDBHelper db = new CellDBHelper(this); String tags = db.getCellTagsAsString(cid); db.close(); if (tags.equals("")) { // unknown cell: do nothing Log.d(TAG, "Cell " + cid + " has no tags: do not turn wifi on"); EventLogger.getInstance(this).addStatusChangedEvent(this.getString(R.string.event_unknown_cell)); stopSelf(); return START_NOT_STICKY; } else { // known cell: go on Log.d(TAG, "Cell " + cid + " has tags " + tags + ": turn wifi on"); EventLogger.getInstance(this).addStatusChangedEvent(this.getString(R.string.event_known_cell)); } } } // if Wifi is going to be tured off (reasonOff distinguishes the case) we may want to respect Wakelocks // This must be done here (instead of the Alarm receiver as there is a wakelock being held while alarms are processed if (reasonOff && !state && (bCheckWakelocks)) { if (Wakelocks.hasWakelocks(this)) { Log.d(TAG, "Wakelock detected: postponing Wifi off"); EventLogger.getInstance(this).addStatusChangedEvent(this.getString(R.string.event_wakelock_detected)); SetWifiStateService.scheduleRetryWifiOffAlarm(this); stopSelf(); return START_NOT_STICKY; } else { Log.d(TAG, "No wakelocks detected: turning Wifi off"); EventLogger.getInstance(this).addStatusChangedEvent(this.getString(R.string.event_no_wakelock_detected)); } } try { WifiControl.setWifi(this, state); // write the last action SharedPreferences.Editor editor = sharedPrefs.edit(); if (state) { editor.putString("last_action", "on"); } else { editor.putString("last_action", "off"); } editor.commit(); // cancel pending alarms planned to turn wifi on or off if (state) { cancelWifiOffAlarm(this); } else { cancelWifiConnectedAlarm(this); } // check if we need to schedule and alarm for delayed check if a connection could be established boolean bProcess = sharedPrefs.getBoolean("wifi_on_if_connected", true); if (state && bProcess) { String strInterval = sharedPrefs.getString("wifi_off_delay", "30"); int delay = 30; try { delay = Integer.valueOf(strInterval); } catch (Exception e) { } SetWifiStateService.scheduleWifiConnectedAlarm(this); } } catch (Exception e) { Log.e(TAG, "An error occured: " + e.getMessage()); } stopSelf(); return START_NOT_STICKY; } @Override public IBinder onBind(Intent intent) { return null; } /** * Adds an alarm to schedule a wakeup to retrieve the current location */ public static boolean scheduleWifiOffAlarm(Context ctx) { Log.i(TAG, "scheduleOffAlarm called"); // reset the retry counter SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(ctx); SharedPreferences.Editor editor = sharedPrefs.edit(); editor.putInt("wifi_off_retries", 0); editor.commit(); // store a reference for throughput measurement if (sharedPrefs.getBoolean("wifi_on_if_activity", false)) { WifiControl.snapshot(ctx); } // cancel any exiting alarms cancelWifiOffAlarm(ctx); // create a new one starting to count NOW SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx); String strInterval = prefs.getString("wifi_off_delay", "30"); int iInterval = 30; try { iInterval = Integer.valueOf(strInterval); } catch (Exception e) { } EventLogger.getInstance(ctx).addStatusChangedEvent(ctx.getString(R.string.event_scheduling_wifi_off_in, iInterval)); long fireAt = System.currentTimeMillis() + (iInterval * 1000); Intent intent = new Intent(ctx, WifiOffAlarmReceiver.class); PendingIntent sender = PendingIntent.getBroadcast(ctx, ALARM_WIFI_OFF, intent, PendingIntent.FLAG_UPDATE_CURRENT); // Get the AlarmManager service AlarmManager am = (AlarmManager) ctx.getSystemService(ALARM_SERVICE); am.set(AlarmManager.RTC_WAKEUP, fireAt, sender); return true; } /** * Adds an alarm to schedule a wakeup to retrieve the current location */ public static boolean scheduleRetryWifiOffAlarm(Context ctx) { Log.i(TAG, "scheduleOffAlarm called"); // cancel any exiting alarms cancelWifiOffAlarm(ctx); SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(ctx); int retries = sharedPrefs.getInt("wifi_off_retries", 0) + 1; if (retries <= 5) { SharedPreferences.Editor editor = sharedPrefs.edit(); editor.putInt("wifi_off_retries", retries); editor.commit(); } // store a reference for throughput measurement if (sharedPrefs.getBoolean("wifi_on_if_activity", false)) { WifiControl.snapshot(ctx); } // create a new one starting to count NOW SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx); String strInterval = prefs.getString("wifi_off_delay", "30"); int iInterval = 30; try { iInterval = Integer.valueOf(strInterval); } catch (Exception e) { iInterval = 30; } if (retries >= 5) { // set timeout to 15 minutes iInterval = 15 * 60; } else { // increase interval depending on retries iInterval = iInterval + (iInterval * retries); } EventLogger.getInstance(ctx).addStatusChangedEvent(ctx.getString(R.string.event_scheduling_wifi_off_in, iInterval)); long fireAt = System.currentTimeMillis() + (iInterval * 1000); Intent intent = new Intent(ctx, WifiOffAlarmReceiver.class); PendingIntent sender = PendingIntent.getBroadcast(ctx, ALARM_WIFI_OFF, intent, PendingIntent.FLAG_UPDATE_CURRENT); // Get the AlarmManager service AlarmManager am = (AlarmManager) ctx.getSystemService(ALARM_SERVICE); am.set(AlarmManager.RTC_WAKEUP, fireAt, sender); return true; } /** * Cancels the current alarm (if existing) */ public static void cancelWifiOffAlarm(Context ctx) { // check if there is an intent pending Intent intent = new Intent(ctx, WifiOffAlarmReceiver.class); PendingIntent sender = PendingIntent.getBroadcast(ctx, ALARM_WIFI_OFF, intent, PendingIntent.FLAG_UPDATE_CURRENT); if (sender != null) { // Get the AlarmManager service AlarmManager am = (AlarmManager) ctx.getSystemService(ALARM_SERVICE); am.cancel(sender); } } /** * Adds an alarm to schedule a wakeup to retrieve the current location */ public static boolean scheduleWifiConnectedAlarm(Context ctx) { Log.i(TAG, "scheduleWifiConnectedAlarm called"); // create a new one starting to count NOW SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx); String strInterval = prefs.getString("wifi_off_delay", "30"); int iInterval = 30; try { iInterval = Integer.valueOf(strInterval); } catch (Exception e) { } EventLogger.getInstance(ctx).addStatusChangedEvent(ctx.getString(R.string.event_scheduling_wifi_off_in, iInterval)); long fireAt = System.currentTimeMillis() + (iInterval * 1000); Intent intent = new Intent(ctx, WifiConnectedAlarmReceiver.class); PendingIntent sender = PendingIntent.getBroadcast(ctx, ALARM_WIFI_CONNECTED, intent, PendingIntent.FLAG_UPDATE_CURRENT); // Get the AlarmManager service AlarmManager am = (AlarmManager) ctx.getSystemService(ALARM_SERVICE); am.set(AlarmManager.RTC_WAKEUP, fireAt, sender); return true; } /** * Cancels the current alarm (if existing) */ public static void cancelWifiConnectedAlarm(Context ctx) { // check if there is an intent pending Intent intent = new Intent(ctx, WifiConnectedAlarmReceiver.class); PendingIntent sender = PendingIntent.getBroadcast(ctx, ALARM_WIFI_CONNECTED, intent, PendingIntent.FLAG_UPDATE_CURRENT); if (sender != null) { // Get the AlarmManager service AlarmManager am = (AlarmManager) ctx.getSystemService(ALARM_SERVICE); am.cancel(sender); } } /** * Adds an alarm to schedule a wakeup to retrieve the current location */ public static boolean scheduleTimerAlarm(Context ctx) { Log.i(TAG, "scheduleTimerAlarm called"); // create a new one starting to count NOW SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx); if (prefs.getBoolean("timed_check", false)) { String strInterval = prefs.getString("timed_check_delay", "0"); int iInterval = 0; try { iInterval = Integer.valueOf(strInterval); } catch (Exception e) { } if (iInterval != 0) { long fireAt = System.currentTimeMillis() + (iInterval * 1000); Intent intent = new Intent(ctx, TimedCheckAlarmReceiver.class); PendingIntent sender = PendingIntent.getBroadcast(ctx, ALARM_TIMER, intent, PendingIntent.FLAG_UPDATE_CURRENT); // Get the AlarmManager service AlarmManager am = (AlarmManager) ctx.getSystemService(ALARM_SERVICE); am.set(AlarmManager.RTC_WAKEUP, fireAt, sender); } } return true; } /** * Cancels the current alarm (if existing) */ public static void cancelTimerAlarm(Context ctx) { // check if there is an intent pending Intent intent = new Intent(ctx, WifiConnectedAlarmReceiver.class); PendingIntent sender = PendingIntent.getBroadcast(ctx, ALARM_TIMER, intent, PendingIntent.FLAG_UPDATE_CURRENT); if (sender != null) { // Get the AlarmManager service AlarmManager am = (AlarmManager) ctx.getSystemService(ALARM_SERVICE); am.cancel(sender); } } }