Android comes equipped with a built-in media player API. For one of
the projects, I had to customize the Android Media player to:
– re-skin UI
– Retrieve the media from a remote URL source
– integrate Twitter, Facebook and Email support
– play, pause, stop modes for the media player
NOTE: Regard this post, MORE SO on coding the media player, rather than the social integration of Twitter and Facebook.
Screenshot
File: media_player_view.xml
File: media_player_fragment.xml
File: MediaPlayerView.java
– re-skin UI
– Retrieve the media from a remote URL source
– integrate Twitter, Facebook and Email support
– play, pause, stop modes for the media player
NOTE: Regard this post, MORE SO on coding the media player, rather than the social integration of Twitter and Facebook.
Screenshot
File: media_player_view.xml
01 | <? xml version = "1.0" encoding = "utf-8" ?> |
02 | < RelativeLayout xmlns:android = "http://schemas.android.com/apk/res/android" |
03 | android:orientation = "vertical" android:layout_gravity = "center" |
04 | android:background = "@drawable/background" android:layout_width = "fill_parent" |
05 | android:layout_height = "fill_parent" > |
06 |
07 | < FrameLayout android:layout_alignParentTop = "true" |
08 | android:id = "@+id/top_fragment" android:layout_width = "wrap_content" |
09 | android:layout_height = "wrap_content" > |
10 | < ImageView android:id = "@+id/mixTapeHeaderLogo" android:src = "@drawable/mix_tape_header_logo" |
11 | android:layout_gravity = "center" android:layout_width = "wrap_content" |
12 | android:paddingTop = "50dip" android:layout_height = "wrap_content" /> |
13 | < include layout = "@layout/top_event_date_fragment" |
14 | android:layout_width = "wrap_content" android:layout_height = "wrap_content" |
15 | android:paddingBottom = "30dip" /> |
16 | </ FrameLayout > |
17 |
18 | < ScrollView xmlns:android = "http://schemas.android.com/apk/res/android" |
19 | android:id = "@+id/scrollView" android:layout_width = "fill_parent" |
20 | android:layout_below = "@+id/top_fragment" android:layout_above = "@+id/social_media_mix_fragment" |
21 | android:layout_height = "wrap_content" > |
22 | < LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android" |
23 | android:paddingLeft = "20dip" android:paddingRight = "20dip" |
24 | android:orientation = "vertical" android:layout_width = "fill_parent" |
25 | android:layout_height = "wrap_content" > |
26 | < TextView android:id = "@+id/musicMixTitle" android:gravity = "center" |
27 | android:paddingBottom = "10dip" android:text = "Song Name" |
28 | android:textColor = "@color/brown" android:textStyle = "bold" |
29 | android:textSize = "32sp" android:layout_width = "fill_parent" |
30 | android:layout_height = "wrap_content" /> |
31 | < TextView android:id = "@+id/musicMixArtist" android:gravity = "center" |
32 | android:paddingBottom = "30dip" android:text = "Song Artist" |
33 | android:textColor = "@color/brown" android:textStyle = "bold" |
34 | android:textSize = "14sp" android:layout_width = "fill_parent" |
35 | android:layout_height = "wrap_content" /> |
36 |
37 | < include layout = "@layout/media_player_fragment" android:id = "@+id/media_player_fragment" |
38 | android:layout_gravity = "center" android:layout_width = "fill_parent" |
39 | android:layout_height = "wrap_content" /> |
40 |
41 | < TextView android:id = "@+id/malibu_disclaimer_fragment_textview" |
42 | android:text = "@string/static_malibu_disclaimer_text" |
43 | android:textColor = "@color/brown" android:gravity = "center" |
44 | android:paddingTop = "10dip" android:paddingBottom = "10dip" |
45 | android:layout_width = "wrap_content" android:layout_height = "wrap_content" /> |
46 | </ LinearLayout > |
47 | </ ScrollView > |
48 |
49 | < include layout = "@layout/social_media_mix_fragment" android:id = "@+id/social_media_mix_fragment" |
50 | android:layout_gravity = "center" android:layout_alignParentBottom = "true" |
51 | android:layout_width = "fill_parent" android:layout_height = "wrap_content" /> |
52 | </ RelativeLayout > |
01 | <? xml version = "1.0" encoding = "utf-8" ?> |
02 | < LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android" |
03 | android:id = "@+id/mediaPlayerLayout" android:orientation = "vertical" |
04 | android:paddingBottom = "80dip" android:gravity = "center" |
05 | android:layout_width = "fill_parent" android:layout_height = "wrap_content" > |
06 |
07 | < LinearLayout android:orientation = "horizontal" |
08 | android:gravity = "center" android:layout_width = "fill_parent" |
09 | android:layout_height = "wrap_content" > |
10 |
11 | < ImageView android:id = "@+id/mediaStopButton" android:src = "@drawable/media_stop_button_selector" |
12 | android:paddingLeft = "10dip" android:paddingRight = "10dip" |
13 | android:layout_width = "wrap_content" android:layout_height = "wrap_content" /> |
14 |
15 | < ImageView android:id = "@+id/mediaPlayButton" android:src = "@drawable/media_play_button_selector" |
16 | android:paddingLeft = "10dip" android:paddingRight = "10dip" |
17 | android:layout_width = "wrap_content" android:layout_height = "wrap_content" /> |
18 | |
19 | < ImageView android:id = "@+id/mediaPauseButton" android:src = "@drawable/media_pause_button_selector" |
20 | android:paddingLeft = "10dip" android:paddingRight = "10dip" |
21 | android:layout_width = "wrap_content" android:layout_height = "wrap_content" /> |
22 |
23 | </ LinearLayout > |
24 | </ LinearLayout > |
001 | package com.malibu.views.mediaplayer; |
002 |
003 | import java.io.IOException; |
004 |
005 | import org.codehaus.jackson.JsonParseException; |
006 | import org.codehaus.jackson.JsonParser; |
007 | import org.codehaus.jackson.map.JsonMappingException; |
008 | import org.codehaus.jackson.map.ObjectMapper; |
009 |
010 | import android.app.Activity; |
011 | import android.app.ProgressDialog; |
012 | import android.content.Context; |
013 | import android.content.Intent; |
014 | import android.content.SharedPreferences; |
015 | import android.media.MediaPlayer; |
016 | import android.os.Bundle; |
017 | import android.os.Handler; |
018 | import android.util.Log; |
019 | import android.view.View; |
020 | import android.view.View.OnClickListener; |
021 | import android.widget.ImageView; |
022 | import android.widget.SeekBar; |
023 | import android.widget.SeekBar.OnSeekBarChangeListener; |
024 | import android.widget.TextView; |
025 | import android.widget.Toast; |
026 |
027 | import com.facebook.android.AsyncFacebookRunner; |
028 | import com.facebook.android.DialogError; |
029 | import com.facebook.android.Facebook; |
030 | import com.facebook.android.Facebook.DialogListener; |
031 | import com.facebook.android.FacebookError; |
032 | import com.pernod_ricard.malibu_rum.android.R; |
033 | import com.malibu.app.config.Config; |
034 | import com.malibu.app.legal.TermsAndConditionsScreen; |
035 | import com.malibu.app.utils.AuthHttpRequest; |
036 | import com.malibu.controllers.social.Twitter; |
037 | import com.malibu.models.music.MusicMix; |
038 |
039 | /** |
040 | * @author wdavid01 |
041 | * |
042 | */ |
043 | public class MediaPlayerScreen extends Activity implements OnClickListener, OnSeekBarChangeListener |
044 | { |
045 | private static final String tag = MediaPlayerScreen. class .getName(); |
046 | private Context context; |
047 |
048 | private MediaPlayer mMediaPlayer = null ; |
049 | private int playbackPosition = 0 ; |
050 | private boolean hasPressedPlayed = false ; |
051 | private boolean hasPressedPaused = false ; |
052 | private boolean hasPressedStopped = false ; |
053 | private final boolean hasPressedRewind = false ; |
054 | private final boolean hasPressedForward = false ; |
055 |
056 | // Control buttons |
057 | private ImageView stopButton = null ; |
058 | private ImageView playButton = null ; |
059 | private ImageView pauseButton = null ; |
060 |
061 | // Social media buttons |
062 | private TextView disclaimer; |
063 | private ImageView socialMediaFacebookButton = null ; |
064 | private ImageView socialMediaTwitterButton = null ; |
065 | private ImageView socialMediaEmailButton = null ; |
066 |
067 | // Remote Music File |
068 | private String mediaUrl = "http://akamai.mindblossom.net/malibu/music/malibu.mp3" ; |
069 | private TextView topEventDateTextview; |
070 | private SharedPreferences prefs; |
071 | private Facebook facebook; |
072 | private AsyncFacebookRunner asyncRunner; |
073 |
074 | private final Handler handler = new Handler(); |
075 | private final Runnable runner = new Runnable() |
076 | { |
077 | @Override |
078 | public void run() |
079 | { |
080 | setData(); |
081 | } |
082 | }; |
083 | private MusicMix mix; |
084 | private ProgressDialog dialog; |
085 | private TextView socialMediaShare; |
086 | private TextView musicMixTitle; |
087 | private TextView musicMixArtist; |
088 |
089 | @Override |
090 | public void onCreate(Bundle savedInstanceState) |
091 | { |
092 | super .onCreate(savedInstanceState); |
093 | Log.d(tag, getResources().getString(R.string.CREATING_VIEW) + MediaPlayerScreen. class .getName()); |
094 | setContentView(R.layout.media_player_view); |
095 | context = this ; |
096 |
097 | prefs = getSharedPreferences(Config.PREFS, Context.MODE_PRIVATE); |
098 |
099 | facebook = new Facebook(Config.FACEBOOK_APP_ID); |
100 | facebook.setAccessToken(prefs.getString(Config.FACEBOOK_ACCESS_TOKEN, null )); |
101 | facebook.setAccessExpires(prefs.getLong(Config.FACEBOOK_EXPIRES, 0 )); |
102 |
103 | asyncRunner = new AsyncFacebookRunner(facebook); |
104 |
105 | topEventDateTextview = (TextView) findViewById(R.id.top_event_date_textview); |
106 | topEventDateTextview.setText(prefs.getString(Config.PREFS_CURRENT_EVENT_TITLE, "" )); |
107 |
108 | socialMediaShare = (TextView) findViewById(R.id.social_media_share); |
109 | socialMediaShare.setOnClickListener( this ); |
110 |
111 | musicMixTitle = (TextView) findViewById(R.id.musicMixTitle); |
112 | musicMixArtist = (TextView) findViewById(R.id.musicMixArtist); |
113 |
114 | // Initial Play button |
115 | pauseButton = (ImageView) this .findViewById(R.id.mediaPauseButton); |
116 | pauseButton.setOnClickListener( this ); |
117 | playButton = (ImageView) this .findViewById(R.id.mediaPlayButton); |
118 | playButton.setOnClickListener( this ); |
119 | stopButton = (ImageView) this .findViewById(R.id.mediaStopButton); |
120 | stopButton.setOnClickListener( this ); |
121 | // Init bottom navigation fragment |
122 | initBottomNavigationFragment(); |
123 |
124 | getData(); |
125 | } |
126 |
127 | @Override |
128 | public void onDestroy() |
129 | { |
130 | super .onDestroy(); |
131 | Log.d(tag, getResources().getString(R.string.DESTROYING_VIEW)); |
132 | killMediaPlayer(); |
133 | } |
134 |
135 | public void getData() |
136 | { |
137 | dialog = ProgressDialog.show( this , "" , getResources().getString(R.string.Loading)); |
138 | Thread thread = new Thread() |
139 | { |
140 |
141 | @Override |
142 | public void run() |
143 | { |
144 | try |
145 | { |
146 | JsonParser jp = AuthHttpRequest.getJsonParser( "musicMix" , "mix" ); |
147 | ObjectMapper mapper = new ObjectMapper(); |
148 |
149 | mix = mapper.readValue(jp, MusicMix. class ); |
150 | handler.post(runner); |
151 | } |
152 | catch (JsonParseException e) |
153 | { |
154 | e.printStackTrace(); |
155 | } |
156 | catch (JsonMappingException e) |
157 | { |
158 | e.printStackTrace(); |
159 | } |
160 | catch (IOException e) |
161 | { |
162 | e.printStackTrace(); |
163 | } |
164 | } |
165 | }; |
166 | thread.start(); |
167 | } |
168 |
169 | private void setData() |
170 | { |
171 | if (mix != null ) |
172 | { |
173 | musicMixArtist.setText(mix.attendeeName); |
174 | musicMixTitle.setText(mix.name); |
175 | mediaUrl = mix.url; |
176 | } |
177 | dialog.dismiss(); |
178 | } |
179 |
180 | private void initBottomNavigationFragment() |
181 | { |
182 | disclaimer = (TextView) this .findViewById(R.id.malibu_disclaimer_fragment_textview); |
183 | disclaimer.setOnClickListener( this ); |
184 | socialMediaFacebookButton = (ImageView) this .findViewById(R.id.social_media_facebook); |
185 | socialMediaFacebookButton.setOnClickListener( this ); |
186 | socialMediaTwitterButton = (ImageView) this .findViewById(R.id.social_media_twitter); |
187 | socialMediaTwitterButton.setOnClickListener( this ); |
188 | socialMediaEmailButton = (ImageView) this .findViewById(R.id.social_media_email); |
189 | socialMediaEmailButton.setOnClickListener( this ); |
190 | } |
191 |
192 | private void killMediaPlayer() |
193 | { |
194 | Log.d(tag, "Closing MediaPlayer ....!" ); |
195 | if (mMediaPlayer != null ) |
196 | { |
197 | try |
198 | { |
199 | Log.d(tag, "Releasing MediaPlayer ....!" ); |
200 | mMediaPlayer.release(); |
201 | } |
202 | catch (Exception e) |
203 | { |
204 | Log.d(tag, e.getMessage()); |
205 | } |
206 | } |
207 | } |
208 |
209 | private void startPlay(String url) throws IllegalArgumentException, IllegalStateException, IOException |
210 | { |
211 |
212 | Log.d(tag, mediaUrl); |
213 |
214 | if (hasPressedPaused == true && hasPressedPlayed == true ) |
215 | { |
216 |
217 | playbackPosition = mMediaPlayer.getCurrentPosition(); |
218 | Log.d(tag, "Resume @: " + playbackPosition); |
219 | mMediaPlayer.seekTo(playbackPosition); |
220 | mMediaPlayer.start(); |
221 | } |
222 | else if (hasPressedStopped == true ) |
223 | { |
224 | Log.d(tag, "Start..." ); |
225 | killMediaPlayer(); |
226 |
227 | Log.d(tag, "Starting MediaPlayer ....!" ); |
228 |
229 | mMediaPlayer = new MediaPlayer(); |
230 | mMediaPlayer.setDataSource(mediaUrl); |
231 | mMediaPlayer.prepare(); |
232 | mMediaPlayer.start(); |
233 | hasPressedPlayed = true ; |
234 | } |
235 | else |
236 | { |
237 | Log.d(tag, "Start..." ); |
238 | killMediaPlayer(); |
239 |
240 | Log.d(tag, "Starting MediaPlayer ....!" ); |
241 | mMediaPlayer = new MediaPlayer(); |
242 | mMediaPlayer.setDataSource(mediaUrl); |
243 | mMediaPlayer.prepare(); |
244 | mMediaPlayer.start(); |
245 | hasPressedPlayed = true ; |
246 | } |
247 | } |
248 |
249 | private void pause() |
250 | { |
251 | Log.d(tag, "Pausing media player..." ); |
252 | mMediaPlayer.pause(); |
253 | playbackPosition = mMediaPlayer.getCurrentPosition(); |
254 | hasPressedPaused = true ; |
255 | } |
256 |
257 | @Override |
258 | public void onClick(View v) |
259 | { |
260 | if (v == disclaimer) |
261 | { |
262 | Intent intent = new Intent( this , TermsAndConditionsScreen. class ); |
263 | startActivity(intent); |
264 | } |
265 |
266 | if (v == playButton) |
267 | { |
268 | try |
269 | { |
270 | startPlay(getMediaUrl()); |
271 | } |
272 | catch (IllegalArgumentException e) |
273 | { |
274 | e.printStackTrace(); |
275 | } |
276 | catch (IllegalStateException e) |
277 | { |
278 | e.printStackTrace(); |
279 | } |
280 | catch (IOException e) |
281 | { |
282 | e.printStackTrace(); |
283 | } |
284 | } |
285 | if (v == pauseButton) |
286 | { |
287 | if (mMediaPlayer != null ) |
288 | { |
289 | Log.d(tag, "MediaPlayer paused..." ); |
290 | pause(); |
291 | } |
292 | } |
293 | if (v == stopButton) |
294 | { |
295 | if (mMediaPlayer != null ) |
296 | { |
297 | Log.d(tag, "MediaPlayer stopped..." ); |
298 | mMediaPlayer.stop(); |
299 | hasPressedPlayed = false ; |
300 | hasPressedStopped = true ; |
301 | playbackPosition = 0 ; |
302 | } |
303 | } |
304 |
305 | // social media |
306 | if (v == socialMediaFacebookButton) |
307 | { |
308 | Log.d(tag, getResources().getString(R.string.VIEW_CLICKED) + "Facebook Connect ..." ); |
309 | Toast.makeText( this , "Facebook Connect" , Toast.LENGTH_SHORT).show(); |
310 |
311 | String description = "I'm listening to " + mix.name + " by " + mix.attendeeName + "." ; |
312 |
313 | Bundle params = new Bundle(); |
314 | params.putString( "description" , description); |
315 | params.putString( "link" , mix.musicMixUrl); |
316 |
317 | facebook.dialog( this , "stream.publish" , params, new DialogListener() |
318 | { |
319 | @Override |
320 | public void onComplete(Bundle values) |
321 | { |
322 | } |
323 |
324 | @Override |
325 | public void onFacebookError(FacebookError e) |
326 | { |
327 | } |
328 |
329 | @Override |
330 | public void onError(DialogError e) |
331 | { |
332 | } |
333 |
334 | @Override |
335 | public void onCancel() |
336 | { |
337 | } |
338 | }); |
339 | } |
340 |
341 | if (v == socialMediaTwitterButton) |
342 | { |
343 | String tweet = "IÕm listening to " + mix.name + " by " + mix.attendeeName + ". " + mix.musicMixUrl + " via #stationinvasion" ; |
344 | new Twitter( this , tweet); |
345 | } |
346 |
347 | if (v == socialMediaEmailButton) |
348 | { |
349 | Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND); |
350 | String description = "I'm listening to " + mix.name + " by " + mix.attendeeName + ".\n\n" + mix.musicMixUrl; |
351 |
352 | emailIntent.setType( "plain/text" ); |
353 | emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "Listening to a music mix | Malibu Station Invasion" ); |
354 | emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, description); |
355 |
356 | startActivity(Intent.createChooser(emailIntent, "Send mail..." )); |
357 | } |
358 | } |
359 |
360 | private void setMediaUrl(String mediaUrl) |
361 | { |
362 | this .mediaUrl = mediaUrl; |
363 | } |
364 |
365 | private String getMediaUrl() |
366 | { |
367 | return mediaUrl; |
368 | } |
369 |
370 | @Override |
371 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) |
372 | { |
373 | seekBar.setProgress(mMediaPlayer.getCurrentPosition()); |
374 | } |
375 |
376 | @Override |
377 | public void onStartTrackingTouch(SeekBar seekBar) |
378 | { |
379 | // TODO Auto-generated method stub |
380 |
381 | } |
382 |
383 | @Override |
384 | public void onStopTrackingTouch(SeekBar seekBar) |
385 | { |
386 | // TODO Auto-generated method stub |
387 |
388 | } |
389 | } |
No comments:
Post a Comment