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.activity.main;
20  
21  import java.text.ParseException;
22  import java.util.Arrays;
23  import java.util.List;
24  
25  import sk.baka.ambient.ActionsEnum;
26  import sk.baka.ambient.AmbientApplication;
27  import sk.baka.ambient.AppState;
28  import sk.baka.ambient.ConfigurationBean;
29  import sk.baka.ambient.IApplicationListener;
30  import sk.baka.ambient.R;
31  import sk.baka.ambient.activity.AmpacheClientActivity;
32  import sk.baka.ambient.activity.AmpacheClientBean;
33  import sk.baka.ambient.activity.main.cb.AbstractCollectionController;
34  import sk.baka.ambient.collection.CollectionSynchronizer;
35  import sk.baka.ambient.collection.ICollection;
36  import sk.baka.ambient.collection.TrackOriginEnum;
37  import sk.baka.ambient.collection.ampache.AmpacheClient;
38  import sk.baka.ambient.collection.ampache.AmpacheServer;
39  import sk.baka.ambient.collection.ampache.CollectionImpl;
40  import sk.baka.ambient.collection.local.MediaStoreCollection;
41  import sk.baka.ambient.commons.IOUtils;
42  import sk.baka.ambient.commons.MiscUtils;
43  import sk.baka.ambient.commons.TagFormatter;
44  import sk.baka.ambient.views.gesturelist.GesturesListView;
45  import android.app.Activity;
46  import android.content.Context;
47  import android.content.Intent;
48  import android.net.wifi.WifiInfo;
49  import android.net.wifi.WifiManager;
50  import android.view.View;
51  import android.widget.TextView;
52  
53  /***
54   * Browses the Ampache server and optionally allows a synchronization of tracks.
55   * 
56   * @author Martin Vysny
57   */
58  public final class AmpacheController extends AbstractCollectionController
59  		implements IApplicationListener {
60  	/***
61  	 * The Embedded Ampache server.
62  	 */
63  	final private AmpacheServer server;
64  
65  	private final List<ActionsEnum> actions = Arrays.asList(ActionsEnum.Back,
66  			ActionsEnum.CollectionYear, ActionsEnum.AmpacheSynchronize,
67  			ActionsEnum.AmpacheStartServer, ActionsEnum.AmpacheConfigureClient);
68  
69  	/***
70  	 * Creates new ampache controller.
71  	 * 
72  	 * @param mainActivity
73  	 *            the owning activity.
74  	 * @param playlistView
75  	 *            the playlist view.
76  	 */
77  	public AmpacheController(final Activity mainActivity,
78  			final GesturesListView playlistView) {
79  		super(R.id.ampacheBrowser, R.id.ampacheList, mainActivity,
80  				playlistView, new CollectionImpl(new AmpacheClient(null), null,
81  						null), R.id.ampachePath);
82  		app.registerProvider(TrackOriginEnum.Ampache, collection);
83  		final ICollection serverBackend = new MediaStoreCollection(mainActivity
84  				.getContentResolver());
85  		server = new AmpacheServer(
86  				app.getStateHandler().getConfig().ampacheEmbeddedPassword,
87  				serverBackend);
88  		ampacheClientChanged();
89  		initButtonBar(R.id.ampacheButtons, actions);
90  	}
91  
92  	private void startEmbedded() {
93  		try {
94  			server.start(AmpacheServer.PORT, null);
95  			actions.set(3, ActionsEnum.AmpacheStopServer);
96  			initButtonBar(R.id.ampacheButtons, actions);
97  			setupWifiPolling(true);
98  		} catch (final Exception e) {
99  			app.error(AmpacheController.class, true, "Server failed to start",
100 					e);
101 		}
102 	}
103 
104 	private void stopEmbedded() {
105 		server.stop();
106 		actions.set(3, ActionsEnum.AmpacheStartServer);
107 		initButtonBar(R.id.ampacheButtons, actions);
108 		setupWifiPolling(false);
109 	}
110 
111 	@Override
112 	protected void onAction(ActionsEnum action) {
113 		if (action == ActionsEnum.AmpacheSynchronize) {
114 			synchronizeTracks();
115 			return;
116 		} else if (action == ActionsEnum.AmpacheConfigureClient) {
117 			mainActivity.startActivity(new Intent(mainActivity,
118 					AmpacheClientActivity.class));
119 			return;
120 		} else if (action == ActionsEnum.AmpacheStartServer) {
121 			startEmbedded();
122 			return;
123 		} else if (action == ActionsEnum.AmpacheStopServer) {
124 			stopEmbedded();
125 			return;
126 		}
127 		super.onAction(action);
128 	}
129 
130 	private void synchronizeTracks() {
131 		try {
132 			final ICollection localColl = new MediaStoreCollection(mainActivity
133 					.getContentResolver());
134 			final CollectionSynchronizer synchronizer = new CollectionSynchronizer(
135 					localColl, collection, new TagFormatter(
136 							"sync/{%artist/}{{%year }%album/}{%track }%title"),
137 					"/sdcard", app.getBackgroundTasks());
138 			app.getBackgroundTasks().schedule(synchronizer,
139 					CollectionSynchronizer.class, true,
140 					app.getString(R.string.synchronizingCollection));
141 		} catch (ParseException e) {
142 			app.error(AmpacheController.class, true, app
143 					.getString(R.string.parsePathFormatFailed), e);
144 		}
145 	}
146 
147 	/***
148 	 * Invoked when the Ampache client configuration changes.
149 	 */
150 	void ampacheClientChanged() {
151 		final AmpacheClientBean bean = app.getStateHandler().getStartupState().ampacheClient;
152 		final CollectionImpl ampache = (CollectionImpl) collection;
153 		ampache.reset(bean == null ? new AmpacheClientBean() : bean);
154 		reset();
155 	}
156 
157 	@Override
158 	public void destroy() {
159 		server.stop();
160 		setupWifiPolling(false);
161 		super.destroy();
162 	}
163 
164 	private final Runnable wifiStatus = new Runnable() {
165 		public void run() {
166 			AmbientApplication.getHandler().postDelayed(wifiStatus, 1000);
167 			final WifiManager manager = (WifiManager) mainActivity
168 					.getSystemService(Context.WIFI_SERVICE);
169 			final TextView status = (TextView) mainView
170 					.findViewById(R.id.ampacheServerWifiStatus);
171 			if (!manager.isWifiEnabled()) {
172 				status.setText(MiscUtils.format(R.string.wifiOff,
173 						AmpacheServer.PORT));
174 			} else {
175 				final WifiInfo info = manager.getConnectionInfo();
176 				if (info == null || info.getSSID() == null) {
177 					status.setText(MiscUtils.format(R.string.wifiNotConnected,
178 							AmpacheServer.PORT));
179 				} else {
180 					status.setText(MiscUtils.format(R.string.wifiConnected,
181 							AmpacheServer.PORT, info.getSSID(), IOUtils
182 									.formatIP(info.getIpAddress())));
183 				}
184 			}
185 		}
186 	};
187 
188 	private void setupWifiPolling(boolean enable) {
189 		AmbientApplication.getHandler().removeCallbacks(wifiStatus);
190 		mainView.findViewById(R.id.ampacheServerWifiStatus).setVisibility(
191 				enable ? View.VISIBLE : View.GONE);
192 		if (enable) {
193 			AmbientApplication.getHandler().post(wifiStatus);
194 		}
195 	}
196 
197 	public void clipboardChanged() {
198 		// do nothing
199 	}
200 
201 	public void configChanged(ConfigurationBean config) {
202 		server.reset(config.ampacheEmbeddedPassword);
203 	}
204 
205 	public void offline(boolean offline) {
206 		if (offline) {
207 			stopEmbedded();
208 		}
209 		mainView.findViewById(R.id.ampacheBrowserControls).setVisibility(
210 				offline ? View.GONE : View.VISIBLE);
211 		mainView.findViewById(R.id.ampacheOffline).setVisibility(
212 				offline ? View.VISIBLE : View.GONE);
213 	}
214 
215 	public void stateChanged(AppState state) {
216 		ampacheClientChanged();
217 	}
218 
219 	@Override
220 	protected void visibilityChanged(boolean visible) {
221 		if (!visible) {
222 			return;
223 		}
224 		final boolean offline = !app.getStateHandler().getStartupState().online;
225 		offline(offline);
226 	}
227 
228 	@Override
229 	protected void performZoom(boolean zoom) {
230 		super.performZoom(zoom);
231 		initButtonBar(R.id.ampacheButtons, actions);
232 	}
233 }