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