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