View Javadoc

1   /***
2    *     Ambient - A music player for the Android platform
3    Copyright (C) 2007 Martin Vysny
4    
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation, either version 3 of the License, or
8    (at your option) any later version.
9    
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14  
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17   */
18  
19  package sk.baka.ambient;
20  
21  import sk.baka.ambient.collection.TrackMetadataBean;
22  import sk.baka.ambient.commons.Interval;
23  import sk.baka.ambient.playerservice.PlayerStateEnum;
24  import sk.baka.ambient.playlist.PlaylistItem;
25  import sk.baka.ambient.playlist.Random;
26  import sk.baka.ambient.playlist.Repeat;
27  import android.content.BroadcastReceiver;
28  import android.content.Context;
29  import android.content.Intent;
30  import android.content.IntentFilter;
31  import android.net.ConnectivityManager;
32  import android.net.NetworkInfo;
33  import android.net.wifi.WifiManager;
34  import android.net.wifi.WifiManager.WifiLock;
35  import android.util.Log;
36  
37  /***
38   * Ensures that the WiFi is not turned off while playing an online content.
39   * Thread-unsafe, should be invoked from the main Handler instance only.
40   * 
41   * @author Martin Vysny
42   */
43  final class PowerHandler extends BroadcastReceiver implements
44  		IPlaylistPlayerListener {
45  
46  	private final AmbientApplication app;
47  
48  	/***
49  	 * Creates new power handler.
50  	 * 
51  	 * @param app
52  	 *            owner application.
53  	 */
54  	public PowerHandler(final AmbientApplication app) {
55  		this.app = app;
56  		app.getBus().addHandler(this);
57  		app.registerReceiver(this, new IntentFilter(
58  				ConnectivityManager.CONNECTIVITY_ACTION));
59  	}
60  
61  	public void playbackStateChanged(PlayerStateEnum state) {
62  		if (state == PlayerStateEnum.Stopped) {
63  			freeWifiLock();
64  		} else if (state == PlayerStateEnum.Playing) {
65  			lockWifiIfNecessary(null, false);
66  		}
67  	}
68  
69  	public void playlistChanged(Interval target) {
70  		// do nothing
71  	}
72  
73  	public void randomChanged(Random random) {
74  		// do nothing
75  	}
76  
77  	public void repeatChanged(Repeat repeat) {
78  		// do nothing
79  	}
80  
81  	public void trackChanged(PlaylistItem track, boolean play,
82  			int positionMillis) {
83  		if (play) {
84  			if (track.getTrack().isLocal()) {
85  				freeWifiLock();
86  				return;
87  			}
88  			lockWifiIfNecessary(track.getTrack(), false);
89  		}
90  	}
91  
92  	private void lockWifiIfNecessary(final TrackMetadataBean track,
93  			final boolean wifiConnected) {
94  		if (wifiLock != null) {
95  			// already locked. bail out
96  			return;
97  		}
98  		if (track == null) {
99  			final TrackMetadataBean t = app.getPlaylist()
100 					.getCurrentlyPlayingTrack();
101 			if (t != null) {
102 				lockWifiIfNecessary(t, wifiConnected);
103 			}
104 			return;
105 		}
106 		if (track.isLocal()) {
107 			return;
108 		}
109 		if (!wifiConnected && !isWifiConnected()) {
110 			return;
111 		}
112 		// okay, might be using WiFi to access the server. Lock it
113 		final WifiManager wifiMan = (WifiManager) app
114 				.getSystemService(Context.WIFI_SERVICE);
115 		wifiLock = wifiMan.createWifiLock(PowerHandler.class.getName());
116 		Log.i(PowerHandler.class.getSimpleName(), "Acquiring WiFi lock");
117 		wifiLock.acquire();
118 	}
119 
120 	private boolean isWifiConnected() {
121 		final ConnectivityManager manager = (ConnectivityManager) app
122 				.getSystemService(Context.CONNECTIVITY_SERVICE);
123 		final NetworkInfo info = manager
124 				.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
125 		return info != null && info.isConnected();
126 	}
127 
128 	private WifiLock wifiLock = null;
129 
130 	public void trackPositionChanged(int position, boolean playing) {
131 		// do nothing
132 	}
133 
134 	/***
135 	 * Destroys this handler and drops any power locks being held.
136 	 */
137 	void destroy() {
138 		app.unregisterReceiver(this);
139 		freeWifiLock();
140 	}
141 
142 	private void freeWifiLock() {
143 		if (wifiLock != null) {
144 			Log.i(PowerHandler.class.getSimpleName(), "Dropping WiFi lock");
145 			wifiLock.release();
146 			wifiLock = null;
147 		}
148 	}
149 
150 	@Override
151 	public void onReceive(Context context, Intent intent) {
152 		if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY,
153 				false)) {
154 			freeWifiLock();
155 			return;
156 		}
157 		if (intent
158 				.getBooleanExtra(ConnectivityManager.EXTRA_IS_FAILOVER, false)) {
159 			final boolean isPlaying = app.getPlaylist().getPlaybackState() == PlayerStateEnum.Playing;
160 			if (!isPlaying) {
161 				// do nothing
162 				return;
163 			}
164 			final NetworkInfo newInfo = intent
165 					.getParcelableExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO);
166 			if (newInfo == null) {
167 				// probably still reconnecting. Do nothing and wait
168 				return;
169 			}
170 			if (newInfo.getType() == ConnectivityManager.TYPE_WIFI) {
171 				lockWifiIfNecessary(null, true);
172 				return;
173 			}
174 			// switching to a non-WIFI Internet provider. The playback might
175 			// still be using WIFI access though: check this possibility
176 			if (!isWifiConnected()) {
177 				freeWifiLock();
178 			}
179 		}
180 	}
181 }