source: other-projects/tipple-android/src/org/tipple/mapDisplay/AudioPlayerView.java@ 26523

Last change on this file since 26523 was 26523, checked in by davidb, 11 years ago

A version of Tipple with the mods Casey made for her Masters work

File size: 17.2 KB
Line 
1package org.tipple.mapDisplay;
2
3import java.util.LinkedList;
4import java.util.List;
5
6import android.content.Context;
7import android.media.MediaPlayer;
8import android.view.View;
9import android.view.ViewGroup;
10import android.widget.Button;
11import android.widget.LinearLayout;
12import android.widget.TextView;
13
14public class AudioPlayerView extends LinearLayout {
15 public AudioPlayerView(Context context) {
16 super(context);
17 // TODO Auto-generated constructor stub
18 }
19
20 TextView text_view_;
21
22 protected Button buttonPlayPause_;
23 protected Button buttonNext_;
24 protected Button buttonShowHideText_;
25
26 protected String stopLabel_;
27
28 protected boolean hasCompletionHandler_;
29
30 protected tippleActivity.TextAudioModeEnum current_text_audio_mode_;
31
32 protected List<MediaPlayer> audioPlayerQueue_;
33 protected List<String> idPlayerQueue_;
34 protected List<String> textPlayerQueue_;
35 protected List<Boolean> visitedPlayerQueue_;
36 protected int absolute_head_pos_;
37 protected int absolute_tail_pos_;
38
39 AudioPlayerView(Context context, TextView text_view) {
40 super(context);
41
42 text_view_ = text_view;
43
44 audioPlayerQueue_ = new LinkedList<MediaPlayer>();
45 idPlayerQueue_ = new LinkedList<String>();
46 textPlayerQueue_ = new LinkedList<String>();
47 visitedPlayerQueue_ = new LinkedList<Boolean>();
48
49 absolute_head_pos_ = 0;
50 absolute_tail_pos_ = -1;
51
52 // media buttons - play/pause, and next song/audio as horizontal layout,
53 // 50% each
54
55 stopLabel_ = "Stop";
56
57 LayoutParams layout_params = new LinearLayout.LayoutParams(
58 ViewGroup.LayoutParams.WRAP_CONTENT,
59 ViewGroup.LayoutParams.MATCH_PARENT, 1);
60
61 buttonPlayPause_ = new Button(context);
62 buttonPlayPause_.setLayoutParams(layout_params);
63 buttonPlayPause_.setText("Play");
64 buttonPlayPause_.setEnabled(false);
65
66 buttonNext_ = new Button(context);
67 buttonNext_.setLayoutParams(layout_params);
68 buttonNext_.setText(stopLabel_);
69 buttonNext_.setEnabled(false);
70
71 hasCompletionHandler_ = false;
72
73 buttonPlayPause_.setOnClickListener(new View.OnClickListener() {
74 public void onClick(View v) {
75
76 if (isPlaying()) {
77 // Change to pause
78
79 // tippleActivity.log.optMessage("Manual Pause Audio",
80 // textPlayerQueue_.get(0));
81
82 pauseAudio();
83 } else {
84 // Must be paused => resume playing
85 // tippleActivity.log.optMessage("Manual Play/Resume Audio",
86 // textPlayerQueue_.get(0));
87
88 playResumeAudio();
89 }
90 }
91 });
92
93 buttonNext_.setOnClickListener(new View.OnClickListener() {
94 @Override
95 public void onClick(View v) {
96 // tippleActivity.log.optMessage("Manual Next Audio Location");
97 nextAudioLocation();
98 }
99 });
100
101 // Optional show text button
102
103 buttonShowHideText_ = new Button(context);
104 buttonShowHideText_.setLayoutParams(layout_params);
105 buttonShowHideText_.setText("Show Text");
106 buttonShowHideText_.setEnabled(false);
107
108 buttonShowHideText_.setOnClickListener(new View.OnClickListener() {
109 public void onClick(View v) {
110 // tippleActivity.log.optMessage("Manual Show/Hide Text");
111
112 if (text_view_.getVisibility() == View.INVISIBLE) {
113 // tippleActivity.log.optMessage("Manual Show Text");
114 text_view_.setVisibility(View.VISIBLE);
115 buttonShowHideText_.setText("Hide Text");
116 } else {
117 // tippleActivity.log.optMessage("Manual Hide Text");
118 text_view_.setVisibility(View.INVISIBLE);
119 buttonShowHideText_.setText("Show Text");
120 }
121 }
122 });
123
124 // Horozontal layout is:
125 // Play | OptText | Next
126
127 addView(buttonPlayPause_);
128
129 /*
130 * current_text_audio_mode_ = tippleActivity.textAudioMode; if
131 * (current_text_audio_mode_ ==
132 * tippleActivity.TextAudioModeEnum.AUDIO_PLUS_TEXT) {
133 * addView(buttonShowHideText_); }
134 */
135 addView(buttonShowHideText_);
136
137 addView(buttonNext_);
138 }
139
140 // delete the public then call this method?
141 void resetAudioView() {
142 audioPlayerQueue_.clear();
143 idPlayerQueue_.clear();
144 textPlayerQueue_.clear();
145 visitedPlayerQueue_.clear();
146 audioPlayerQueue_ = new LinkedList<MediaPlayer>();
147 idPlayerQueue_ = new LinkedList<String>();
148 textPlayerQueue_ = new LinkedList<String>();
149 visitedPlayerQueue_ = new LinkedList<Boolean>();
150
151 absolute_head_pos_ = 0;
152 absolute_tail_pos_ = -1;
153
154 }
155
156 protected boolean audioViewIsActive() {
157 return ((current_text_audio_mode_ == tippleActivity.TextAudioModeEnum.AUDIO_ONLY)
158 || (current_text_audio_mode_ == tippleActivity.TextAudioModeEnum.AUDIO_PLUS_TEXT) || (current_text_audio_mode_ == tippleActivity.TextAudioModeEnum.TEXT_PLUS_AUDIO));
159
160 }
161
162 protected boolean textViewIsActive() {
163 return ((current_text_audio_mode_ == tippleActivity.TextAudioModeEnum.TEXT_ONLY)
164 || (current_text_audio_mode_ == tippleActivity.TextAudioModeEnum.TEXT_PLUS_AUDIO) || (current_text_audio_mode_ == tippleActivity.TextAudioModeEnum.AUDIO_PLUS_TEXT));
165
166 }
167
168 public void refreshView() {
169 if (current_text_audio_mode_ != tippleActivity.textAudioMode) {
170 // There has been a mode change
171
172 if (tippleActivity.textAudioMode == tippleActivity.TextAudioModeEnum.AUDIO_PLUS_TEXT) {
173 // ensure both play/pause and show/hide removed, then add in
174 // order needed
175
176 if (this.indexOfChild(buttonPlayPause_) >= 0) {
177 this.removeView(buttonPlayPause_);
178 }
179 if (this.indexOfChild(buttonShowHideText_) >= 0) {
180 this.removeView(buttonShowHideText_);
181 }
182 this.addView(buttonPlayPause_, 0);
183 this.addView(buttonShowHideText_, 1);
184
185 stopLabel_ = "Stop";
186 }
187
188 else if (tippleActivity.textAudioMode == tippleActivity.TextAudioModeEnum.AUDIO_ONLY) {
189 // ensure show/hide is gone, and only add play/pause if needed
190 if (this.indexOfChild(buttonShowHideText_) >= 0) {
191 // Don't want to see a show/hide text button
192 this.removeView(buttonShowHideText_);
193 }
194 if (this.indexOfChild(buttonPlayPause_) < 0) {
195 this.addView(buttonPlayPause_);
196 }
197 stopLabel_ = "Stop";
198 }
199
200 else if (tippleActivity.textAudioMode == tippleActivity.TextAudioModeEnum.TEXT_PLUS_AUDIO) {
201 // ensure both play/pause and show/hide removed, then add in
202 // order needed
203 if (this.indexOfChild(buttonPlayPause_) >= 0) {
204 this.removeView(buttonPlayPause_);
205 }
206 if (this.indexOfChild(buttonShowHideText_) >= 0) {
207 this.removeView(buttonShowHideText_);
208 }
209
210 this.addView(buttonShowHideText_, 0);
211 this.addView(buttonPlayPause_, 1);
212
213 stopLabel_ = "Stop";
214 }
215
216 else if (tippleActivity.textAudioMode == tippleActivity.TextAudioModeEnum.TEXT_ONLY) {
217 // ensure play/pause is gone, and only add show/hide if needed
218
219 if (this.indexOfChild(buttonPlayPause_) >= 0) {
220 // Don't want to see a play button
221 this.removeView(buttonPlayPause_);
222 }
223
224 if (this.indexOfChild(buttonShowHideText_) < 0) {
225 this.addView(buttonShowHideText_, 0);
226 }
227 stopLabel_ = "End";
228 }
229
230 current_text_audio_mode_ = tippleActivity.textAudioMode;
231 System.out.println("refreshView AudioPlayerView");
232 }
233
234 }
235
236 synchronized public boolean audioQueueEmpty() {
237 return (audioPlayerQueue_.size() == 0);
238 }
239
240 synchronized public boolean outstandingAudioPending() {
241 return (audioPlayerQueue_.size() > 1);
242 }
243
244 synchronized public int audioQueueLength() {
245 return audioPlayerQueue_.size();
246 }
247
248 synchronized public boolean addAudio(String new_id) {
249 // Assume audio should be added, unless an existing match is found
250 boolean add_audio = true;
251
252 int rev_pos = audioPlayerQueue_.size() - 1;
253 for (int i = 0; i < 3; i++) {
254 if (rev_pos < 0) {
255 break;
256 }
257
258 String id = idPlayerQueue_.get(rev_pos);
259
260 if (new_id.equals(id)) {
261 add_audio = false;
262 }
263
264 rev_pos--;
265 }
266
267 return add_audio;
268 }
269
270 synchronized public void queueAudio(String audio_filename, String id,
271 String text, boolean previously_visited) {
272 MediaPlayer mp = new MediaPlayer();
273 try {
274
275 mp.setDataSource(audio_filename);
276 mp.prepare();
277 audioPlayerQueue_.add(mp);
278 idPlayerQueue_.add(id);
279 textPlayerQueue_.add(text);
280 visitedPlayerQueue_.add(previously_visited);
281
282 absolute_tail_pos_++;
283
284 int audio_queue_len = audioPlayerQueue_.size();
285 int mod_head_pos = absolute_head_pos_ % 3;
286
287 if (audio_queue_len == 1) {
288 // Nothing to do, not enough data to allow the user to play
289 // anything
290 return;
291 } else if (audio_queue_len == 2) {
292
293 // mod_head_pos==0 => title followed by text => ready to play
294 // mod_head_pos==1 => text followed by beep => "stop"
295 // mod_head_pos==2 => beep followed title => "skip to next"
296
297 if (mod_head_pos == 0) {
298 // just queued up a title and text (at the head of the
299 // queue)
300 // => make play active if not already so
301 if (!buttonPlayPause_.isEnabled()) {
302 // buttonPlayPause_.setText("Play");
303 buttonPlayPause_.setEnabled(true);
304 }
305 if (!buttonShowHideText_.isEnabled()) {
306 buttonShowHideText_.setEnabled(true);
307
308 }
309 buttonNext_.setText(stopLabel_);
310 buttonNext_.setEnabled(true);
311 } else if (mod_head_pos == 1) {
312
313 buttonNext_.setText(stopLabel_);
314 buttonNext_.setEnabled(true);
315 } else {
316 // mod_head_pos==2
317 buttonNext_.setText("Skip to Next (1)");
318 buttonNext_.setEnabled(true);
319 }
320 } else {
321 // length >= 3
322
323 // mod_head_pos==0 => title at head, spans loc if len >3
324 // mod_head_pos==1 => text at head, guaranteed to span loc =>
325 // "skip to next"
326 // mod_head_pos==2 => beep at head, guaranteed to span loc =>
327 // "skip to next"
328
329 if ((mod_head_pos == 0) && (audio_queue_len == 3)) {
330 // stop
331 buttonNext_.setText(stopLabel_);
332 buttonNext_.setEnabled(true);
333 } else {
334 // for everything else, the queue spans to another location
335
336 int relative_adjustment_pos = mod_head_pos - 1;
337 int num_remaining_locations = (audio_queue_len + relative_adjustment_pos) / 3;
338
339 buttonNext_.setText("Skip to Next ("
340 + num_remaining_locations + ")");
341 buttonNext_.setEnabled(true);
342 }
343 }
344 } catch (Exception e) {
345 e.printStackTrace();
346 }
347 }
348
349 synchronized public void queueAudio(String audio_filename, String id,
350 String text) {
351 queueAudio(audio_filename, id, text, false);
352 }
353
354 synchronized public void removeAudioTrack() {
355 if (audioPlayerQueue_.size() > 0) {
356
357 // tippleActivity.log.optMessage("Remove Audio Track",
358 // "Queue size was: " + audioPlayerQueue_.size());
359
360 MediaPlayer mp = audioPlayerQueue_.remove(0);
361 idPlayerQueue_.remove(0);
362 textPlayerQueue_.remove(0);
363 visitedPlayerQueue_.remove(0);
364
365 absolute_head_pos_++;
366 mp.stop();
367 mp.release();
368
369 hasCompletionHandler_ = false;
370 } else {
371 System.err.println("Error: No audio in queue to remove");
372 }
373 }
374
375 synchronized public void removeAudioLocation() {
376 int audio_queue_len = audioPlayerQueue_.size();
377
378 if (audio_queue_len > 0) {
379
380 // tippleActivity.log.optMessage("Remove Audio Location",
381 // "Queue size was: " + audioPlayerQueue_.size());
382
383 int mod_head_pos = absolute_head_pos_ % 3;
384 int need_to_skip = 3 - mod_head_pos;
385
386 // remove up to the next absolute multiple of 3
387 for (int i = 0; i < need_to_skip; i++) {
388 MediaPlayer mp = audioPlayerQueue_.remove(0);
389 idPlayerQueue_.remove(0);
390 textPlayerQueue_.remove(0);
391 visitedPlayerQueue_.remove(0);
392 absolute_head_pos_++;
393
394 mp.stop();
395 mp.release();
396 if (audioPlayerQueue_.size() == 0) {
397 // happens if there is no beep on the last location
398 break;
399 }
400 }
401
402 hasCompletionHandler_ = false;
403 } else {
404 System.err.println("Error: No audio in queue to remove");
405 }
406 }
407
408 synchronized public void onAudioCompletion(MediaPlayer mp) {
409 mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
410
411 @Override
412 public void onCompletion(MediaPlayer mp) {
413 nextAudioTrack();
414 }
415 });
416 }
417
418 synchronized public void onVisitedAudioCompletion(MediaPlayer mp) {
419 mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
420
421 @Override
422 public void onCompletion(MediaPlayer mp) {
423 playResumeAudioInternal();
424 }
425 });
426 }
427
428 public boolean updateTextViewIfHeadIsNewLocation() {
429 boolean updated = false;
430
431 if ((absolute_head_pos_ % 3) == 0) {
432 // start of a new location
433 String text_desc = textPlayerQueue_.get(0);
434 if (visitedPlayerQueue_.get(0)) {// return true or false
435 text_desc += "\n(Previously Visited)";
436 }
437 text_desc += "\n------";
438
439 if (textPlayerQueue_.size() > 1) {
440 text_desc += "\n" + textPlayerQueue_.get(1);
441 }
442
443 text_view_.setText(text_desc);
444 updated = true;
445 }
446
447 return updated;
448 }
449
450 synchronized public void playResumeAudio() {
451 if (audioPlayerQueue_.size() > 0) {
452
453 if ((audioViewIsActive()) && (visitedPlayerQueue_.get(0))) {
454 // Play (synchronously) the "previously visited" message before
455 // moving on to
456 // describing the location itself
457 MediaPlayer mp = new MediaPlayer();
458
459 try {
460 // mp.setDataSource(tippleLocationManager.prevVisitedFilename);
461 mp.setDataSource(TippleLocationManagerVersion2.prevVisitedFilename);
462
463 mp.prepare();
464 onVisitedAudioCompletion(mp);
465 mp.start();
466 } catch (Exception e) {
467 e.printStackTrace();
468 }
469 } else {
470 // go straight on and play the queued audio
471 playResumeAudioInternal();
472 }
473 } else {
474 System.err
475 .println("Error: No audio in queue to start playing --call palyResumeAudio function");
476
477 }
478
479 }
480
481 synchronized public void playResumeAudioInternal() {
482 if (audioPlayerQueue_.size() > 0) {
483 // tippleActivity.log.optMessage("Play/Resume Audio",
484 // "Queue size was: " + audioPlayerQueue_.size());
485
486 MediaPlayer mp = audioPlayerQueue_.get(0);
487
488 if (!hasCompletionHandler_) {
489
490 updateTextViewIfHeadIsNewLocation();
491
492 onAudioCompletion(mp);
493 hasCompletionHandler_ = true;
494 }
495
496 if (audioViewIsActive() || ((absolute_head_pos_ % 3) == 2)) {
497 // allow it to play a "ding" even in text only mode
498 mp.start();
499 }
500 buttonPlayPause_.setText("Pause"); // next operation
501 } else {
502 System.err
503 .println("Error: No audio in queue to start playing --call playResumeAudioInternal function");
504 }
505
506 }
507
508 synchronized public void pauseAudio() {
509 if (audioPlayerQueue_.size() > 0) {
510 MediaPlayer mp = audioPlayerQueue_.get(0);
511 mp.pause();
512 buttonPlayPause_.setText("Play/Resume"); // next operation
513 } else {
514 System.err.println("Error: No audio in queue to pause");
515 }
516 }
517
518 synchronized public void nextAudioLocation() {
519 removeAudioLocation(); // stops it if currently playing
520
521 int remaining_audio_len = audioQueueLength();
522 if (remaining_audio_len > 0) {
523 playResumeAudio();
524
525 int mod_head_pos = absolute_head_pos_ % 3;
526 /*
527 * int relative_adjustment_pos = 1 - mod_head_pos; int
528 * num_remaining_locations =
529 * (remaining_audio_len+relative_adjustment_pos)/3;
530 *
531 * if (num_remaining_locations>=1) {
532 *
533 * buttonNext_.setText("Skip to Next (" + num_remaining_locations +
534 * ")"); buttonNext_.setEnabled(true); }
535 */
536
537 int num_remaining_locations = (remaining_audio_len + mod_head_pos) / 3;
538
539 if (num_remaining_locations > 1) {
540
541 buttonNext_.setText("Skip to Next ("
542 + (num_remaining_locations - 1) + ")");
543 buttonNext_.setEnabled(true);
544 }
545
546 else {
547 buttonNext_.setText(stopLabel_);
548 buttonNext_.setEnabled(true);
549 buttonPlayPause_.setText("Play");
550 buttonPlayPause_.setEnabled(true);
551 buttonShowHideText_.setText("Show Text");
552 buttonShowHideText_.setEnabled(true);
553 }
554 } else {
555 buttonNext_.setText(stopLabel_);
556 buttonNext_.setEnabled(false);
557 buttonPlayPause_.setText("Play");
558 buttonPlayPause_.setEnabled(false);
559
560 if (text_view_.getVisibility() == View.VISIBLE) {
561 // tippleActivity.log.optMessage("Audio Hide Text");
562 text_view_.setVisibility(View.INVISIBLE);
563 }
564 buttonShowHideText_.setText("Show Text");
565 buttonShowHideText_.setEnabled(false);
566 }
567 }
568
569 synchronized public void nextAudioTrack() {
570 removeAudioTrack(); // stops it if currently playing
571
572 int remaining_audio_len = audioQueueLength();
573 if (remaining_audio_len > 0) {
574 playResumeAudio();
575
576 int num_remaining_locations = ((remaining_audio_len - 1) / 3);
577
578 if (num_remaining_locations >= 1) {
579
580 buttonNext_.setText("Skip to Next (" + num_remaining_locations
581 + ")");
582 buttonNext_.setEnabled(true);
583 } else {
584 buttonNext_.setText(stopLabel_);
585 buttonNext_.setEnabled(true);
586 // buttonPlayPause_.setText("Play");
587 buttonPlayPause_.setEnabled(true);
588 buttonShowHideText_.setEnabled(true);
589 }
590 } else {
591 buttonNext_.setText(stopLabel_);
592 buttonNext_.setEnabled(false);
593 buttonPlayPause_.setText("Play");
594 buttonPlayPause_.setEnabled(false);
595
596 if (text_view_.getVisibility() == View.VISIBLE) {
597 tippleActivity.log.optMessage("Audio Hide Text");
598 text_view_.setVisibility(View.INVISIBLE);
599 }
600 buttonShowHideText_.setText("Show Text");
601 buttonShowHideText_.setEnabled(false);
602
603 }
604 }
605
606 synchronized public boolean isPlaying() {
607 boolean is_playing = false;
608 if (audioPlayerQueue_.size() > 0) {
609 is_playing = audioPlayerQueue_.get(0).isPlaying();
610 }
611 return is_playing;
612 }
613
614}
Note: See TracBrowser for help on using the repository browser.