/***************************************************************************
* Copyright 2006-2016 by Christian Ihle *
* contact@kouchat.net *
* *
* This file is part of KouChat. *
* *
* KouChat is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of *
* the License, or (at your option) any later version. *
* *
* KouChat is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with KouChat. *
* If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
package net.usikkert.kouchat.android.service;
import net.usikkert.kouchat.android.chatwindow.AndroidUserInterface;
import net.usikkert.kouchat.android.settings.AndroidSetting;
import net.usikkert.kouchat.android.settings.AndroidSettings;
import net.usikkert.kouchat.event.NetworkConnectionListener;
import net.usikkert.kouchat.event.SettingsListener;
import net.usikkert.kouchat.settings.Setting;
import net.usikkert.kouchat.util.Validate;
import android.net.wifi.WifiManager;
import android.os.PowerManager;
/**
* Acquires and releases the wake lock, the wifi lock and the multicast lock when appropriate.
*
* <p>The wake lock is optional, and helps avoid timeouts because the cpu goes to sleep,
* and thus can't process packets from the network.</p>
*
* <p>The wifi lock can help with packet loss on some devices.</p>
*
* <p>The multicast lock is needed to process multicast packets on some devices.
* The <code>Asus Transformer TF101</code> does not care, but the <code>HTC One</code> does not send
* or receive any multicast packets without a lock.</p>
*
* <p>It's important to keep the locks as fields, and not just as variables, since
* garbage collected locks are automatically released.</p>
*
* @author Christian Ihle
*/
public class LockHandler implements NetworkConnectionListener, SettingsListener {
public static final String WAKE_LOCK = "KouChat wake lock";
public static final String WIFI_LOCK = "KouChat wifi lock";
public static final String MULTICAST_LOCK = "KouChat multicast lock";
private final PowerManager.WakeLock wakeLock;
private final WifiManager.WifiLock wifiLock;
private final WifiManager.MulticastLock multicastLock;
private final AndroidSettings settings;
public LockHandler(final AndroidUserInterface androidUserInterface,
final AndroidSettings settings,
final WifiManager wifiManager,
final PowerManager powerManager) {
Validate.notNull(androidUserInterface, "AndroidUserInterface can not be null");
Validate.notNull(settings, "Settings can not be null");
Validate.notNull(wifiManager, "WifiManager can not be null");
Validate.notNull(powerManager, "PowerManager can not be null");
this.settings = settings;
this.wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK);
this.wifiLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, WIFI_LOCK);
this.multicastLock = wifiManager.createMulticastLock(MULTICAST_LOCK);
androidUserInterface.registerNetworkConnectionListener(this);
settings.addSettingsListener(this);
}
/**
* It's important to release the multicast lock when the network goes down,
* as it can't be reused when the network is back up.
*
* <p>Releasing the other locks as well, as there is no point in keeping locks when there is no network.</p>
*/
@Override
public void networkWentDown(final boolean silent) {
releaseAllLocks();
}
/**
* Need to get the multicast lock before it starts to connect. If not, some of the first messages will be filtered.
*
* <p>Gets the other locks too, if it's enabled, to keep awake from the start.</p>
*/
@Override
public void beforeNetworkCameUp() {
acquireEnabledLocks();
}
/**
* To late do do anything.
*/
@Override
public void networkCameUp(final boolean silent) {
}
/**
* Listens for changes in the wake lock setting, and acquires or releases the wake lock accordingly.
*
* @param setting The setting which was changed.
*/
@Override
public void settingChanged(final Setting setting) {
if (setting.equals(AndroidSetting.WAKE_LOCK)) {
if (settings.isWakeLockEnabled()) {
acquireWakeLock();
}
else {
releaseWakeLock();
}
}
}
/**
* Releases all the locks, if they are being held.
*/
public synchronized void releaseAllLocks() {
releaseMulticastLock();
releaseWifiLock();
releaseWakeLock();
}
/**
* Acquires the wifi lock and multicast lock, if not already held.
* And the wake lock, if it's enabled and not already held.
*/
public void acquireEnabledLocks() {
if (settings.isWakeLockEnabled()) {
acquireWakeLock();
}
acquireWifiLock();
acquireMulticastLock();
}
/**
* Returns if the wifi lock has been acquired and is currently held (active).
*
* @return If the wifi lock is held.
*/
public boolean wifiLockIsHeld() {
return wifiLock.isHeld();
}
/**
* Returns if the multicast lock has been acquired and is currently held (active).
*
* @return If the multicast lock is held.
*/
public boolean multicastLockIsHeld() {
return multicastLock.isHeld();
}
/**
* Returns if the wake lock has been acquired and is currently held (active).
*
* @return If the wake lock is held.
*/
public boolean wakeLockIsHeld() {
return wakeLock.isHeld();
}
private void acquireWifiLock() {
if (!wifiLockIsHeld()) {
wifiLock.acquire();
}
}
private void releaseWifiLock() {
if (wifiLockIsHeld()) {
wifiLock.release();
}
}
private void acquireMulticastLock() {
if (!multicastLockIsHeld()) {
multicastLock.acquire();
}
}
private void releaseMulticastLock() {
if (multicastLockIsHeld()) {
multicastLock.release();
}
}
private void acquireWakeLock() {
if (!wakeLockIsHeld()) {
wakeLock.acquire();
}
}
private void releaseWakeLock() {
if (wakeLockIsHeld()) {
wakeLock.release();
}
}
}