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;
19  
20  import java.util.ArrayList;
21  import java.util.List;
22  import java.util.Map;
23  
24  import sk.baka.ambient.AmbientApplication;
25  import sk.baka.ambient.ConfigurationBean;
26  import sk.baka.ambient.R;
27  import sk.baka.ambient.activity.main.MainActivity;
28  import sk.baka.ambient.collection.TrackMetadataBean;
29  import sk.baka.ambient.collection.TrackOriginEnum;
30  import sk.baka.ambient.collection.TrackMetadataBean.Builder;
31  import sk.baka.ambient.commons.Binder;
32  import sk.baka.ambient.views.ViewUtils;
33  import android.app.Activity;
34  import android.content.Intent;
35  import android.graphics.Bitmap;
36  import android.graphics.BitmapFactory;
37  import android.graphics.Matrix;
38  import android.graphics.drawable.BitmapDrawable;
39  import android.graphics.drawable.Drawable;
40  import android.os.Bundle;
41  import android.view.View;
42  import android.widget.ArrayAdapter;
43  import android.widget.Button;
44  import android.widget.Spinner;
45  import android.widget.TabHost;
46  import android.widget.TabHost.TabSpec;
47  
48  /***
49   * Configures Ambient.
50   * 
51   * @author Martin Vysny
52   */
53  public final class ConfigActivity extends Activity {
54  
55  	private final AmbientApplication app = AmbientApplication.getInstance();
56  
57  	private final void initSpinner(final int spinnerId,
58  			final List<CharSequence> captions) {
59  		final ArrayAdapter<CharSequence> playerNotifAdapter = new ArrayAdapter<CharSequence>(
60  				this, android.R.layout.simple_spinner_item, captions);
61  		playerNotifAdapter
62  				.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
63  		final Spinner spinner = (Spinner) findViewById(spinnerId);
64  		spinner.setAdapter(playerNotifAdapter);
65  	}
66  
67  	@Override
68  	protected void onCreate(Bundle arg0) {
69  		super.onCreate(arg0);
70  		// initialize components
71  		setContentView(R.layout.config);
72  		final TabHost th = (TabHost) findViewById(R.id.configTabhost);
73  		setupTabhost(th);
74  		initSpinner(R.id.configNotificationType,
75  				ConfigurationBean.TrackChangeNotifEnum.getCaptions(this));
76  		initSpinner(R.id.configNotificationLocation,
77  				ConfigurationBean.TrackChangeNotifLocationEnum
78  						.getCaptions(this));
79  		// load components with data
80  		loadFrom(app.getStateHandler().getConfig());
81  		final Button save = (Button) findViewById(R.id.configSave);
82  		save.setOnClickListener(clickListener);
83  		final Button notifPreview = (Button) findViewById(R.id.configNotificationPreview);
84  		notifPreview.setOnClickListener(clickListener);
85  		final Button defaults = (Button) findViewById(R.id.configDefaults);
86  		defaults.setOnClickListener(clickListener);
87  		final Button cachePurge = (Button) findViewById(R.id.configCoverCachePurge);
88  		cachePurge.setOnClickListener(clickListener);
89  	}
90  
91  	/***
92  	 * List of bitmaps to be destroyed when the activity itself is destroyed.
93  	 */
94  	private final List<Bitmap> bitmaps = new ArrayList<Bitmap>();
95  
96  	@Override
97  	protected void onDestroy() {
98  		ViewUtils.recycleBitmaps(bitmaps);
99  		super.onDestroy();
100 	}
101 
102 	private void setupTabhost(TabHost th) {
103 		th.setup();
104 		TabSpec s = th.newTabSpec("collection");
105 		s.setIndicator(getString(R.string.collection_short),
106 				getDrawable(R.drawable.collection48));
107 		s.setContent(R.id.configCollection);
108 		th.addTab(s);
109 		s = th.newTabSpec("playlist");
110 		s.setIndicator(getString(R.string.playlist_short),
111 				getDrawable(R.drawable.playlist48));
112 		s.setContent(R.id.configPlaylist);
113 		th.addTab(s);
114 		s = th.newTabSpec("notification");
115 		s.setIndicator(getString(R.string.notification_short),
116 				getDrawable(R.drawable.notification));
117 		s.setContent(R.id.configNotification);
118 		th.addTab(s);
119 		s = th.newTabSpec("player");
120 		s.setIndicator(getString(R.string.player_short),
121 				getDrawable(R.drawable.player48));
122 		s.setContent(R.id.configPlayer);
123 		th.addTab(s);
124 		th.setCurrentTab(0);
125 	}
126 
127 	private Drawable getDrawable(final int resid) {
128 		Bitmap bitmap = BitmapFactory
129 				.decodeResource(this.getResources(), resid);
130 		bitmaps.add(bitmap);
131 		final Matrix m = new Matrix();
132 		m.setScale(0.75f, 0.75f);
133 		bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap
134 				.getHeight(), m, true);
135 		bitmaps.add(bitmap);
136 		return new BitmapDrawable(bitmap);
137 	}
138 
139 	private final Button.OnClickListener clickListener = new Button.OnClickListener() {
140 		public void onClick(View arg0) {
141 			switch (arg0.getId()) {
142 			case R.id.configSave: {
143 				final ConfigurationBean bean = getCurrentSettings();
144 				if (bean == null) {
145 					return;
146 				}
147 				Binder.copy(bean, app.getStateHandler().getConfig());
148 				final Intent storeSettings = new Intent(ConfigActivity.this,
149 						MainActivity.class);
150 				storeSettings.putExtra(MainActivity.INTENTDATA_STORECONFIG,
151 						true);
152 				startActivity(storeSettings);
153 				finish();
154 			}
155 				break;
156 			case R.id.configNotificationPreview: {
157 				final ConfigurationBean bean = getCurrentSettings();
158 				if (bean == null) {
159 					return;
160 				}
161 				AmbientApplication.getInstance().getNotificator()
162 						.notifyOnNextTrack(TEST_TRACK, bean);
163 			}
164 				break;
165 			case R.id.configDefaults: {
166 				loadFrom(new ConfigurationBean());
167 			}
168 				break;
169 			case R.id.configCoverCachePurge: {
170 				AmbientApplication.getInstance().getCovers().purge();
171 			}
172 				break;
173 			}
174 		}
175 	};
176 
177 	private final static TrackMetadataBean TEST_TRACK;
178 	static {
179 		final Builder b = TrackMetadataBean.newBuilder();
180 		b.setOrigin(TrackOriginEnum.LocalFs).setTitle("The demo track title")
181 				.setArtist("The best artist");
182 		b.setComposer("Some composer").setAlbum("Demo album").setGenre(
183 				"Rock, Pop, Techno");
184 		b.setTrackNumber("01").setLocation("/somewhere/demo.mp3");
185 		b.setLength(531).setBitrate(256).setFileSize(5000000);
186 		b.setYearReleased("1998").setFrequency(44100);
187 		TEST_TRACK = b.build(-1);
188 	}
189 
190 	/***
191 	 * Returns currently selected values on the configuration activity. If
192 	 * <code>null</code> then some validation error occurred
193 	 * 
194 	 * @return bean instance or <code>null</code> if error occurred.
195 	 */
196 	public ConfigurationBean getCurrentSettings() {
197 		final ConfigurationBean bean = new ConfigurationBean();
198 		try {
199 			if (!saveTo(bean))
200 				return null;
201 			return bean;
202 		} catch (Exception e) {
203 			app.error(ConfigActivity.class, true,
204 					getString(R.string.configSaveError), e);
205 			return null;
206 		}
207 	}
208 
209 	/***
210 	 * Loads the bean data into this activity.
211 	 * 
212 	 * @param bean
213 	 *            the bean to read data from.
214 	 */
215 	public void loadFrom(final ConfigurationBean bean) {
216 		Binder.bindBeanView(bean, findViewById(R.id.configRoot), true, false);
217 	}
218 
219 	/***
220 	 * Store values selected in this activity into given bean.
221 	 * 
222 	 * @param bean
223 	 *            the bean to store.
224 	 * @return <code>true</code> if everything is okay, <code>false</code>
225 	 *         otherwise.
226 	 */
227 	public boolean saveTo(final ConfigurationBean bean) {
228 		final Map<Integer, String> errors = Binder.bindBeanView(bean,
229 				findViewById(R.id.configRoot), false, true);
230 		if (!errors.isEmpty()) {
231 			final Map.Entry<Integer, String> firstErr = errors.entrySet()
232 					.iterator().next();
233 			final int viewId = firstErr.getKey();
234 			final String errMsg = firstErr.getValue();
235 			final View view = findViewById(viewId);
236 			AmbientApplication.getInstance().error(ConfigActivity.class, true,
237 					errMsg, null);
238 			view.requestFocus();
239 			return false;
240 		}
241 		return true;
242 	}
243 }