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
356
357
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
372
373
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 }