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  package sk.baka.ambient.activity.main;
19  
20  import java.util.ArrayList;
21  import java.util.List;
22  
23  import sk.baka.ambient.ActionsEnum;
24  import sk.baka.ambient.AmbientApplication;
25  import sk.baka.ambient.AppState;
26  import sk.baka.ambient.PlaylistPlayer;
27  import sk.baka.ambient.R;
28  import sk.baka.ambient.AppState.IAppStateAware;
29  import sk.baka.ambient.activity.AboutActivity;
30  import sk.baka.ambient.activity.ConfigActivity;
31  import sk.baka.ambient.activity.StatisticsActivity;
32  import sk.baka.ambient.activity.WelcomeActivity;
33  import sk.baka.ambient.activity.search.SearchActivity;
34  import sk.baka.ambient.activity.search.SearchType;
35  import sk.baka.ambient.collection.TrackMetadataBean;
36  import sk.baka.ambient.commons.Interval;
37  import sk.baka.ambient.commons.MiscUtils;
38  import sk.baka.ambient.commons.SimpleBus;
39  import sk.baka.ambient.playerservice.PlayerStateEnum;
40  import sk.baka.ambient.playlist.Random;
41  import sk.baka.ambient.playlist.Repeat;
42  import sk.baka.ambient.views.gesturelist.GesturesListView;
43  import android.app.ListActivity;
44  import android.content.Intent;
45  import android.os.Bundle;
46  import android.view.Menu;
47  import android.view.MenuItem;
48  
49  /***
50   * The main activity. Handles GUI operations for all GUI components.
51   * 
52   * @author Martin Vysny
53   */
54  public class MainActivity extends ListActivity implements IAppStateAware {
55  	private final AmbientApplication app = AmbientApplication.getInstance();
56  
57  	/***
58  	 * Send an intent with the activity enum name put under this key to activate
59  	 * the activity.
60  	 */
61  	public final static String INTENTDATA_ACTIVITY = "INTENTDATA_ACTIVITY";
62  
63  	/***
64  	 * Send an intent having this extra to save a configuration.
65  	 */
66  	public final static String INTENTDATA_STORECONFIG = "INTENTDATA_STORECONFIG";
67  
68  	/***
69  	 * The list of switchable controllers. Only one of these controllers may be
70  	 * visible at the same time.
71  	 */
72  	private ControllerGroup controllers;
73  
74  	/***
75  	 * The list of always visible controllers.
76  	 */
77  	private ControllerGroup alwaysVisibleControllers;
78  
79  	@Override
80  	public void onCreate(Bundle icicle) {
81  		super.onCreate(icicle);
82  		setContentView(R.layout.mainactivity);
83  		findViewById(R.id.mainPadded).setPadding(5, 2, 5, 3);
84  		findViewById(R.id.mainCaptionPadded).setPadding(5, 4, 5, 0);
85  		controllers = new ControllerGroup();
86  		alwaysVisibleControllers = new ControllerGroup();
87  		alwaysVisibleControllers.add(new WindowButtonsController(this), null);
88  		alwaysVisibleControllers.add(new TaskSwitcherController(this), null);
89  		controllers.add(new PlayerController(this), ActionsEnum.ShowPlayer);
90  		final int playlistViewId = PlaylistController.PLAYLIST_VIEW_ID;
91  		final GesturesListView playlistView = (GesturesListView) findViewById(playlistViewId);
92  		controllers.add(new CollectionController(this, playlistView), ActionsEnum.ShowCollection);
93  		controllers.add(new FileBrowserController(this, playlistView),
94  				ActionsEnum.ShowFileBrowser);
95  		final PlaylistController playlistController = new PlaylistController(this);
96  		playlistController.listView
97  				.setEmptyView(findViewById(android.R.id.empty));
98  		alwaysVisibleControllers.add(playlistController, null);
99  		controllers.add(new PlaylistManagerController(this), ActionsEnum.PlaylistManagement);
100 		final StaticPlaylistController searchResultsController = new StaticPlaylistController(
101 				R.id.searchresults, R.id.searchresultsList, this,
102 				new ArrayList<TrackMetadataBean>(), true);
103 		searchResultsController.listView.dragDropViews.clear();
104 		searchResultsController.listView.dragDropViews.add(playlistView);
105 		controllers.add(searchResultsController, null);
106 		controllers.add(new MagnatuneController(this, playlistView),
107 				ActionsEnum.ShowMagnatune);
108 		controllers.add(new ShoutcastController(this, playlistView),
109 				ActionsEnum.ShowShoutcast);
110 		controllers.add(new ContextController(this), ActionsEnum.ShowContext);
111 		controllers.add(new AmpacheController(this, playlistView),
112 				ActionsEnum.ShowAmpache);
113 		reinit(app.getStateHandler().getStartupState());
114 		handleIntent(getIntent());
115 		showWelcomeScreen();
116 	}
117 
118 	private void showWelcomeScreen() {
119 		String version = app.getStateHandler().getStartupState().welcomeVersion;
120 		if (!MiscUtils.nullEquals(version, app.getVersion())) {
121 			version = app.getVersion();
122 			app.getStateHandler().getStartupState().welcomeVersion = version;
123 			final Intent intent = new Intent(this, WelcomeActivity.class);
124 			startActivity(intent);
125 		}
126 	}
127 
128 	@Override
129 	protected void onDestroy() {
130 		controllers.destroy();
131 		alwaysVisibleControllers.destroy();
132 		super.onDestroy();
133 	}
134 
135 	@Override
136 	protected void onStop() {
137 		storeState(app.getStateHandler().getStartupState());
138 		app.getStateHandler().unregisterStateAware(this);
139 		controllers.flipVisibility(null, false);
140 		final SimpleBus bus = app.getBus();
141 		controllers.unregister(bus);
142 		alwaysVisibleControllers.unregister(bus);
143 		super.onStop();
144 	}
145 
146 	@Override
147 	protected void onStart() {
148 		super.onStart();
149 		final SimpleBus bus = app.getBus();
150 		controllers.registerAndUpdate(bus);
151 		alwaysVisibleControllers.registerAndUpdate(bus);
152 		app.getStateHandler().registerStateAware(this);
153 		final AppState state = app.getStateHandler().getStartupState();
154 		flipVisibility(controllers.get(state.visibleController), Boolean.TRUE);
155 		final boolean zoom = app.getStateHandler().getStartupState().zoomed;
156 		controllers.zoom(zoom);
157 		alwaysVisibleControllers.zoom(zoom);
158 	}
159 
160 	/***
161 	 * Executes given action.
162 	 * 
163 	 * @param action
164 	 *            the action to take, must not be <code>null</code>.
165 	 * @param cycle
166 	 *            if <code>true</code> then random/repeat modes are cycled
167 	 *            instead of being activated.
168 	 */
169 	public void activateAction(final ActionsEnum action, final boolean cycle) {
170 		final PlaylistPlayer play = app.getPlaylist();
171 		switch (action) {
172 		case PlaybackStop:
173 			play.stop();
174 			break;
175 		case PlaybackPrevious:
176 			play.previous();
177 			break;
178 		case PlaybackPause:
179 			play.pause();
180 			break;
181 		case PlaybackPlay:
182 			if (play.getPlaybackState() == PlayerStateEnum.Stopped) {
183 				play.play();
184 			} else {
185 				play.pause();
186 			}
187 			break;
188 		case PlaybackNext:
189 			play.next();
190 			break;
191 		case ShowPlayer:
192 			flipVisibility(PlayerController.class, null);
193 			break;
194 		case ShowCollection:
195 			flipVisibility(CollectionController.class, null);
196 			break;
197 		case RandomNo:
198 			play.setRandom(MiscUtils.nextOrThis(Random.NONE, cycle));
199 			break;
200 		case RandomTracks:
201 			play.setRandom(MiscUtils.nextOrThis(Random.TRACK, cycle));
202 			break;
203 		case RandomAlbums:
204 			play.setRandom(MiscUtils.nextOrThis(Random.ALBUM, cycle));
205 			break;
206 		case RandomAlbumsTracks:
207 			play.setRandom(MiscUtils.nextOrThis(Random.ALBUM_TRACK, cycle));
208 			break;
209 		case RandomAlbumsPlaylist:
210 			play.setRandom(MiscUtils.nextOrThis(Random.ALBUM_PLAYLIST, cycle));
211 			break;
212 		case RepeatNothing:
213 			play.setRepeat(MiscUtils.nextOrThis(Repeat.NO, cycle));
214 			break;
215 		case RepeatAlbum:
216 			play.setRepeat(MiscUtils.nextOrThis(Repeat.ALBUM, cycle));
217 			break;
218 		case RepeatPlaylist: {
219 			play.setRepeat(MiscUtils.nextOrThis(Repeat.PLAYLIST, cycle));
220 		}
221 			break;
222 		case RepeatTrack:
223 			play.setRepeat(MiscUtils.nextOrThis(Repeat.TRACK, cycle));
224 			break;
225 		case PlaylistShuffle:
226 			play.shuffle();
227 			break;
228 		case QueueClear:
229 			play.clearQueue();
230 			break;
231 		case QueueTracks:
232 			final Interval selected = alwaysVisibleControllers
233 					.getController(PlaylistController.class).listView
234 					.getHighlight();
235 			play.queue(selected);
236 			break;
237 		case ShowFileBrowser:
238 			flipVisibility(FileBrowserController.class, null);
239 			break;
240 		case ShowMagnatune:
241 			flipVisibility(MagnatuneController.class, null);
242 			break;
243 		case PlaylistManagement:
244 			flipVisibility(PlaylistManagerController.class, null);
245 			break;
246 		case PlaylistClear:
247 			final Interval allTracks = new Interval(0, app.getPlaylist().size());
248 			play.remove(allTracks);
249 			break;
250 		case PlaylistSortByAlbums:
251 			play.sortByAlbumOrder();
252 			break;
253 		case PlaylistStatic:
254 			play.staticPlaylist();
255 			break;
256 		case PlaylistDynamic:
257 			play.dynamicPlaylist();
258 			break;
259 		case Minimize:
260 			finish();
261 			break;
262 		case Quit:
263 			finish();
264 			app.shutdown();
265 			break;
266 		case ShowStatistics: {
267 			final Intent intent = new Intent(this, StatisticsActivity.class);
268 			startActivity(intent);
269 		}
270 			break;
271 		case Configure: {
272 			final Intent intent = new Intent(this, ConfigActivity.class);
273 			startActivity(intent);
274 		}
275 			break;
276 		case About: {
277 			final Intent intent = new Intent(this, AboutActivity.class);
278 			startActivity(intent);
279 		}
280 			break;
281 		case ShowShoutcast:
282 			flipVisibility(ShoutcastController.class, null);
283 			break;
284 		case ShowContext:
285 			flipVisibility(ContextController.class, null);
286 			break;
287 		case GoOffline:
288 			app.setOffline(true);
289 			break;
290 		case GoOnline:
291 			app.setOffline(false);
292 			break;
293 		case Back:
294 		case PlaylistSave:
295 		case ShowLyrics:
296 		case MagnatuneRescan:
297 		case ShowLicense:
298 		case ShowArtistPage:
299 		case CollectionYear:
300 		case ShoutcastNameTrackSwitch:
301 		case RefreshKaraoke:
302 		case ShowKaraoke:
303 		case ShowWiki:
304 		case AmpacheStartServer:
305 		case AmpacheStopServer:
306 		case AmpacheConfigureClient:
307 		case AmpacheSynchronize:
308 		case DeleteSelected:
309 		case BuyAlbum:
310 		case GoToRoot:
311 			throw new IllegalStateException("Not a global action: " + action);
312 		case ShowAmpache:
313 			flipVisibility(AmpacheController.class, null);
314 			break;
315 		}
316 	}
317 
318 	public void reinit(AppState state) {
319 		flipVisibility(controllers.get(state.visibleController), Boolean.TRUE);
320 	}
321 
322 	private void flipVisibility(AbstractController c, Boolean visibility) {
323 		controllers.flipVisibility(c, visibility);
324 		final ActionsEnum action = (c != null) && c.isVisible() ? controllers
325 				.getActionForController(c) : null;
326 		alwaysVisibleControllers.getController(TaskSwitcherController.class).highlightAction(action);
327 	}
328 
329 	private void flipVisibility(Class<? extends AbstractController> clazz,
330 			Boolean visibility) {
331 		flipVisibility(clazz == null ? null : controllers.getController(clazz),
332 				visibility);
333 	}
334 
335 	public void storeState(AppState state) {
336 		state.visibleController = controllers.getVisibleControllerIndex();
337 	}
338 
339 	@Override
340 	protected void onNewIntent(final Intent intent) {
341 		super.onNewIntent(intent);
342 		handleIntent(intent);
343 	}
344 
345 	private void handleIntent(final Intent intent) {
346 		if (intent.hasExtra(SearchActivity.INTENTKEY_STRING)) {
347 			final String str = intent.getExtras().getString(
348 					SearchActivity.INTENTKEY_STRING);
349 			final SearchType type = SearchActivity.getType(intent.getExtras());
350 			if (type == SearchType.StoredPlaylists) {
351 				controllers.getController(PlaylistManagerController.class).loadPlaylist(str);
352 			} else {
353 				controllers.getController(ShoutcastController.class).showGenre(str);
354 				flipVisibility(ShoutcastController.class, Boolean.TRUE);
355 				// set the visible controller in the state as well - onStart()
356 				// is handled after this handler and could make other controller
357 				// visible.
358 				app.getStateHandler().getStartupState().visibleController = controllers
359 						.getVisibleControllerIndex();
360 			}
361 			return;
362 		}
363 		if (intent.hasExtra(SearchActivity.INTENTKEY_MODEL)) {
364 			final List<TrackMetadataBean> model = SearchActivity
365 					.getModel(intent.getExtras());
366 			final String query = SearchActivity.getQuery(intent.getExtras());
367 			final SearchType type = SearchActivity.getType(intent.getExtras());
368 			controllers.getController(StaticPlaylistController.class)
369 					.setResults(model, query, type);
370 			flipVisibility(StaticPlaylistController.class, Boolean.TRUE);
371 			// set the visible controller in the state as well - onStart() is
372 			// handled after this handler and could make other controller
373 			// visible.
374 			app.getStateHandler().getStartupState().visibleController = controllers
375 					.getVisibleControllerIndex();
376 			return;
377 		}
378 		if (intent.hasExtra(INTENTDATA_STORECONFIG)) {
379 			app.getStateHandler().saveConfig();
380 			return;
381 		}
382 		if (intent.hasExtra(INTENTDATA_ACTIVITY)) {
383 			final String data = intent.getStringExtra(INTENTDATA_ACTIVITY);
384 			final ActionsEnum action = ActionsEnum.valueOf(data);
385 			activateAction(action, false);
386 		}
387 	}
388 
389 	@Override
390 	public boolean onPrepareOptionsMenu(Menu menu) {
391 		super.onPrepareOptionsMenu(menu);
392 		menu.removeGroup(0);
393 		menu.removeGroup(1);
394 		final boolean zoomed = app.getStateHandler().getStartupState().zoomed;
395 		MenuItem item = menu.add(Menu.NONE, 0, 0, zoomed ? R.string.zoomOut
396 				: R.string.zoomIn);
397 		item.setIcon(zoomed ? android.R.drawable.btn_minus
398 				: android.R.drawable.btn_plus);
399 		final boolean playing = app.getPlaylist().getPlaybackState() == PlayerStateEnum.Playing;
400 		item = menu.add(Menu.NONE, 1, 1, playing ? R.string.pause
401 				: R.string.play);
402 		item.setIcon(playing ? R.drawable.pause48 : R.drawable.play48);
403 		return true;
404 	}
405 
406 	@Override
407 	public boolean onOptionsItemSelected(MenuItem item) {
408 		switch (item.getItemId()) {
409 		case 0:
410 			zoom(!app.getStateHandler().getStartupState().zoomed);
411 			return true;
412 		case 1:
413 			switch (app.getPlaylist().getPlaybackState()) {
414 			case Paused:
415 				app.getPlaylist().pause();
416 				break;
417 			case Playing:
418 				app.getPlaylist().pause();
419 				break;
420 			case Stopped:
421 				app.getPlaylist().play();
422 				break;
423 			}
424 			return true;
425 		}
426 		return false;
427 	}
428 	
429 	private void zoom(final boolean zoom) {
430 		app.getStateHandler().getStartupState().zoomed = zoom;
431 		controllers.zoom(zoom);
432 		alwaysVisibleControllers.zoom(zoom);
433 	}
434 }