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.BitSet;
21 import java.util.EnumMap;
22 import java.util.List;
23 import java.util.Map;
24
25 import sk.baka.ambient.ActionsEnum;
26 import sk.baka.ambient.AmbientApplication;
27 import sk.baka.ambient.ZoomEnum;
28 import sk.baka.ambient.commons.Interval;
29 import sk.baka.ambient.views.ButtonBar;
30 import android.app.Activity;
31 import android.graphics.Point;
32 import android.view.View;
33 import android.view.View.OnClickListener;
34 import android.widget.AdapterView;
35 import android.widget.AdapterView.OnItemClickListener;
36
37 /***
38 * A base class each controller must extend. Defines common operations.
39 *
40 * @author Martin Vysny
41 */
42 public abstract class AbstractController {
43 /***
44 * The main view controlled by this controller.
45 */
46 protected View mainView;
47
48 /***
49 * Reference to the main activity.
50 */
51 protected Activity mainActivity;
52
53 /***
54 * Creates new controller.
55 *
56 * @param mainViewId
57 * the view whose visibility is controlled.
58 * @param mainActivity
59 * the activity.
60 */
61 protected AbstractController(final int mainViewId,
62 final Activity mainActivity) {
63 super();
64 this.mainView = mainActivity.findViewById(mainViewId);
65 if (mainView == null) {
66 throw new IllegalArgumentException("No view with id " + mainViewId);
67 }
68 this.mainActivity = mainActivity;
69 app = AmbientApplication.getInstance();
70 }
71
72 /***
73 * Flips the player visibility - shows it if it is hidden or vice versa.
74 */
75 public final void flipVisibility() {
76 if (isVisible()) {
77 hide();
78 } else {
79 show();
80 }
81 }
82
83 /***
84 * Checks if the view controlled by this controller is visible.
85 *
86 * @return <code>true</code> if visible, <code>false</code> otherwise.
87 */
88 public final boolean isVisible() {
89 return mainView.getVisibility() == View.VISIBLE;
90 }
91
92 /***
93 * Shows the view on screen.
94 */
95 public final void show() {
96 if (!isVisible()) {
97 mainView.setVisibility(View.VISIBLE);
98 visibilityChanged(true);
99 }
100 }
101
102 /***
103 * Invoked when the component visibility changes. By default does nothing.
104 *
105 * @param visible
106 * new visibility flag.
107 */
108 protected void visibilityChanged(boolean visible) {
109
110 }
111
112 /***
113 * Hides the view and removes it (the {@link View#GONE} functionality).
114 */
115 public final void hide() {
116 if (isVisible()) {
117 mainView.setVisibility(View.GONE);
118 visibilityChanged(false);
119 }
120 }
121
122 /***
123 * Sets the visibility of the view controlled by this controller.
124 *
125 * @param visible
126 * if <code>true</code> then the view is made visible, otherwise
127 * it is made GONE.
128 */
129 public final void setVisibility(final boolean visible) {
130 if (visible) {
131 show();
132 } else {
133 hide();
134 }
135 }
136
137 /***
138 * Called when an action button is pressed. By default invokes main
139 * activity. Subclasses can override.
140 *
141 * @param action
142 * the action to take
143 */
144 protected void onAction(final ActionsEnum action) {
145 if (action == ActionsEnum.Refresh) {
146 update(null);
147 return;
148 }
149 ((MainActivity) mainActivity).activateAction(action, cycle);
150 }
151
152 /***
153 * If <code>true</code> then random/repeat modes are cycled instead of being
154 * activated.
155 */
156 protected boolean cycle = false;
157
158 /***
159 * The activity button listener.
160 */
161 protected final class Listener implements OnClickListener,
162 OnItemClickListener {
163 public void onClick(View arg0) {
164 final ActionsEnum action = (ActionsEnum) arg0.getTag();
165 onAction(action);
166 }
167
168 @SuppressWarnings("unchecked")
169 public void onItemClick(AdapterView parent, View v, int position,
170 long id) {
171 final List<? extends ActionsEnum> actions = (List<? extends ActionsEnum>) v
172 .getTag();
173 onAction(actions.get(position));
174 }
175 }
176
177 /***
178 * Listens for click actions and activates {@link ActionsEnum} stored in the
179 * tag values.
180 */
181 protected final Listener listener = new Listener();
182
183 /***
184 * Returns the application instance.
185 */
186 protected AmbientApplication app;
187
188 /***
189 * Reinitializes the underlying view. Used when the view was not updated for
190 * a time and is about to be shown on screen. Default implementation does
191 * nothing.
192 *
193 * @param select
194 * reset selection to this interval.
195 */
196 public void update(final Interval select) {
197
198 }
199
200 /***
201 * Initializes given button bar with buttons. The size is 32x32 (48x48 when
202 * hovered) when not zoomed, 48x48 (64x64 when hovered) when zoomed.
203 *
204 * @param buttonbarId
205 * the resource id of the {@link ButtonBar} component.
206 * @param actions
207 * the list of actions.
208 */
209 protected void initButtonBar(final int buttonbarId,
210 List<ActionsEnum> actions) {
211 final boolean buttonsZoomed = ZoomEnum.Buttons.getLevel(zoom) != 0;
212 initButtonBar(buttonbarId, actions, buttonsZoomed ? new Point(48, 48)
213 : new Point(32, 32), buttonsZoomed ? new Point(64, 64)
214 : new Point(48, 48));
215 }
216
217 /***
218 * Initializes given button bar with buttons.
219 *
220 * @param buttonbarId
221 * the resource id of the {@link ButtonBar} component.
222 * @param actions
223 * the list of actions.
224 * @param bitmapSize
225 * the size of all buttons.
226 * @param hoveredBitmapSize
227 * maximum size of a button when hovered.
228 */
229 protected final void initButtonBar(final int buttonbarId,
230 List<ActionsEnum> actions, final Point bitmapSize,
231 final Point hoveredBitmapSize) {
232 final ButtonBar bar = (ButtonBar) mainView.findViewById(buttonbarId);
233 bar.listener = listener;
234 initButtonBar(bar, actions, bitmapSize, hoveredBitmapSize);
235 }
236
237 /***
238 * Checks or un-checks given button on the button bar.
239 *
240 * @param buttonbarId
241 * the button bar
242 * @param actionIndex
243 * the index of the action
244 * @param value
245 * the new value.
246 */
247 protected final void checkButton(final int buttonbarId, int actionIndex,
248 final boolean value) {
249 final ButtonBar b = (ButtonBar) mainView
250 .findViewById(buttonbarId);
251 final BitSet checked = b.getChecked();
252 checked.set(actionIndex, value);
253 b.highlight(b.getHighlight(), checked);
254 }
255
256 /***
257 * Initializes given button bar with buttons.
258 *
259 * @param bar
260 * the {@link ButtonBar} component.
261 * @param actions
262 * the list of actions.
263 * @param bitmapSize
264 * the size of all buttons.
265 * @param hoveredBitmapSize
266 * maximum size of a button when hovered.
267 */
268 public static final void initButtonBar(final ButtonBar bar,
269 final List<ActionsEnum> actions, final Point bitmapSize,
270 final Point hoveredBitmapSize) {
271 final int[] images = new int[actions.size()];
272 final int[] captions = new int[actions.size()];
273 for (int i = 0; i < actions.size(); i++) {
274 images[i] = actions.get(i).icon;
275 captions[i] = actions.get(i).caption;
276 }
277 bar.setBitmaps(images, captions, bitmapSize, hoveredBitmapSize);
278 bar.setTag(actions);
279 }
280
281 /***
282 * The controller is about to be destroyed. No invocations are performed
283 * after this call. The controller should release its resources, stop its
284 * activities etc. Make sure that you call {@code super()} if you override
285 * this method!
286 */
287 public void destroy() {
288 mainActivity = null;
289 mainView = null;
290 }
291
292 /***
293 * Checks if this controller was destroyed.
294 *
295 * @return <code>true</code> if this controller is destroyed.
296 */
297 protected final boolean isDestroyed() {
298 return mainActivity == null;
299 }
300
301 @Override
302 public final boolean equals(Object o) {
303 if (o == null) {
304 return false;
305 }
306 return getClass().equals(o.getClass());
307 }
308
309 @Override
310 public final int hashCode() {
311 return getClass().hashCode();
312 }
313
314 /***
315 * Zooms, or un-zooms the controller.
316 *
317 * @param zoom
318 * new zoom levels.
319 */
320 public final void zoom(final Map<ZoomEnum,Integer> zoom) {
321 this.zoom.putAll(zoom);
322 performZoom(zoom);
323 }
324
325 /***
326 * Zooms, or un-zooms the controller.
327 *
328 * @param zoom
329 * new zoom levels.
330 */
331 protected abstract void performZoom(final Map<ZoomEnum,Integer> zoom);
332
333 private final EnumMap<ZoomEnum,Integer> zoom = ZoomEnum.getMinLevels();
334
335 /***
336 * Checks if this controller is zoomed.
337 *
338 * @return current zoom levels.
339 */
340 protected final EnumMap<ZoomEnum,Integer> getZoom() {
341 return zoom;
342 }
343 }