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
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
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 }