/* * Copyright 2012 Brendan McCarthy (brendan@oddsoftware.net) * * This file is part of Feedscribe. * * Feedscribe is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 * as published by the Free Software Foundation. * * Feedscribe is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Feedscribe. If not, see <http://www.gnu.org/licenses/>. */ package net.oddsoftware.android.feedscribe.ui; import java.io.File; import net.oddsoftware.android.feedscribe.AudioPlayer; import net.oddsoftware.android.feedscribe.Globals; import net.oddsoftware.android.feedscribe.R; import net.oddsoftware.android.feedscribe.data.Feed; import net.oddsoftware.android.feedscribe.data.FeedItem; import net.oddsoftware.android.feedscribe.data.FeedManager; import net.oddsoftware.android.utils.TagParser; import net.oddsoftware.android.utils.Utilities; import android.app.Activity; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.provider.MediaStore; import android.view.View; import android.view.View.OnClickListener; import android.webkit.WebView; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.SeekBar; import android.widget.TextView; public class PlayAudioActivity extends Activity { public static final String EXTRA_PATH = "path"; public static final String EXTRA_URL = "url"; public static final String EXTRA_ENCLOSURE_ID = "enclosure_id"; public static final String EXTRA_ITEM_ID = "item_id"; public static final String EXTRA_SEEK_TO = "seek_to"; public static final String EXTRA_FROM_NOTIFICATION = "from_notification"; private Handler mHandler = null; private Runnable mUpdateTask; private SeekBar mSeekBar; private TextView mPositionText; private TextView mDurationText; private String mTitleText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.play_audio_activity); mSeekBar = (SeekBar) findViewById(R.id.seekBar1); mPositionText = (TextView) findViewById(R.id.position_text); mDurationText = (TextView) findViewById(R.id.duration_text); ((ImageButton)findViewById(R.id.btn_pause)).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { onAudioPause(); } }); ((ImageButton)findViewById(R.id.btn_ff)).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { onFastForward(); } }); ((ImageButton)findViewById(R.id.btn_rew)).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { onRewind(); } }); mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onStopTrackingTouch(SeekBar seekBar) { onSeek( seekBar.getProgress() ); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { } }); if( mHandler == null ) { mHandler = new Handler(); } if( mUpdateTask == null ) { mUpdateTask = new Runnable() { @Override public void run() { onTimer(); } }; } /* ContentResolver crThumb = getContentResolver(); BitmapFactory.Options options=new BitmapFactory.Options(); options.inSampleSize = 1; MediaStore.Audio. Bitmap curThumb = MediaStore.Video.Thumbnails.getThumbnail(crThumb, id, MediaStore.Video.Thumbnails.MICRO_KIND, options); iv.setImageBitmap(curThumb); */ AudioPlayer player = AudioPlayer.getInstance(this); boolean started = false; boolean fromNotification = getIntent().getBooleanExtra(EXTRA_FROM_NOTIFICATION, false); long itemId = -1; if( fromNotification ) { // try and get stuff from audio player itemId = player.getItemId(); started = true; loadAlbumArt( itemId, player.getCurrentPath() ); } else { // stop any currently playing dude if(player.isPlaying()) { player.savePosition(); } String path = getIntent().getStringExtra(EXTRA_PATH); String url = getIntent().getStringExtra(EXTRA_URL); itemId = getIntent().getLongExtra(EXTRA_ITEM_ID, 0); long enclosureId = getIntent().getLongExtra(EXTRA_ENCLOSURE_ID, 0); player.setItem(itemId, enclosureId); int seekTo = (int) getIntent().getLongExtra(EXTRA_SEEK_TO, 0); if( path != null ) { started = player.playPath( path, seekTo ); loadAlbumArt( itemId, path ); } else if( url != null ) { started = player.playUrl( url, seekTo ); loadAlbumArt( itemId, null ); } } updateData(itemId); if( started ) { int duration = player.getDuration(); mSeekBar.setMax( duration ); mDurationText.setText( Utilities.formatDuration((duration + 500)/1000) ); ((ImageButton) findViewById(R.id.btn_pause)).setImageResource(android.R.drawable.ic_media_pause); } } private void loadAlbumArt(long itemId, String path) { // load image ImageView iv = (ImageView ) findViewById(R.id.imageView1); Cursor cursorAudio = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, new String[] {MediaStore.Audio.Media.ALBUM_ID, MediaStore.Audio.Media.DATA}, MediaStore.Audio.Media.DATA+ " LIKE \"" + path+ "\"", null, null); if(cursorAudio != null && cursorAudio.moveToFirst()) { Long albumId = Long.valueOf(cursorAudio.getString(cursorAudio.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID))); Cursor cursorAlbum = getContentResolver().query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, new String[] {MediaStore.Audio.Albums._ID, MediaStore.Audio.Albums.ALBUM_ART}, MediaStore.Audio.Albums._ID+ "=" + albumId, null, null); if(cursorAlbum != null && cursorAlbum.moveToFirst()) { String uriString = cursorAlbum.getString(cursorAlbum.getColumnIndex(MediaStore.Audio.Albums.ALBUM_ART)); if(uriString != null) { Uri imageUri = Uri.parse(uriString); Globals.LOG.d("image uri is 1 " + imageUri); iv.setImageURI(imageUri); } } if(cursorAlbum != null) { cursorAlbum.close(); } } if(cursorAudio != null) { cursorAudio.close(); } byte[] data = null; if( path != null ) { TagParser parser = new TagParser(new File(path)); if( parser.findImage()) { String mimeType = parser.getImageMimeType(); data = parser.getImageData(); Globals.LOG.d("trying image mime type " + mimeType + " size " + data.length); } } if(data == null && itemId > 0) { FeedManager feedManager = FeedManager.getInstance(this); Feed feed = feedManager.getFeedByItemId(itemId); data = feedManager.getImage(feed.mImageURL); } if( data != null ) { Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); if( bitmap != null ) { iv.setImageBitmap( bitmap ); } } } private void onAudioPause() { AudioPlayer player = AudioPlayer.getInstance(this); if( ! player.isPaused() ) { player.pause(); player.savePosition(); updateDisplay(); } else { player.resume(); updateDisplay(); } } private void onFastForward() { AudioPlayer.getInstance(this).seekBy( 60 * 1000 ); onTimer(); } private void onRewind() { AudioPlayer.getInstance(this).seekBy( -60 * 1000 ); onTimer(); } private void onTimer() { int timeout = updateDisplay(); Globals.LOG.v("updateDisplay: timeout: " + timeout); mHandler.removeCallbacks(mUpdateTask); if(timeout > 0) { mHandler.postDelayed(mUpdateTask, timeout); } } private void onSeek(int position) { AudioPlayer.getInstance(this).seekTo(position); onTimer(); } private int updateDisplay() { AudioPlayer player = AudioPlayer.getInstance(this); if( !player.hasStarted() ) { mPositionText.setText( Utilities.formatDuration(0) ); mSeekBar.setProgress( 0 ); ((ImageButton) findViewById(R.id.btn_pause)).setImageResource(android.R.drawable.ic_media_play); return -1; } // started playing, update display int position = player.getCurrentPosition(); int seconds = position / 1000; mSeekBar.setProgress( position ); mPositionText.setText( Utilities.formatDuration(seconds) ); int nextTime = 500; int positionVisible = mPositionText.getVisibility(); int pauseIcon; if( player.isPaused() ) { // flash text if( positionVisible == View.VISIBLE ) { positionVisible = View.INVISIBLE; } else { positionVisible = View.VISIBLE; } pauseIcon = android.R.drawable.ic_media_play; // update 2x/second to flash position text nextTime = 500; } else { positionVisible = View.VISIBLE; pauseIcon = android.R.drawable.ic_media_pause; // update on the next whole second of playback nextTime = 1000 - (position % 1000); } mPositionText.setVisibility(positionVisible); ((ImageButton) findViewById(R.id.btn_pause)).setImageResource(pauseIcon); return nextTime; } private void updateData(long itemId) { FeedManager feedManager = FeedManager.getInstance(this); FeedItem feedItem = feedManager.getItemById(itemId); if( feedItem != null) { Feed feed = feedManager.getFeed( feedItem.mFeedId ); WebView webView = (WebView) findViewById(R.id.web_view); webView.loadDataWithBaseURL(null, feedItem.mDescription, "text/html", "utf-8", null); TextView textView = (TextView) findViewById(R.id.titleTextView); StringBuffer titleText = new StringBuffer(); titleText.append( feedItem.mTitle ); if( feedItem.mAuthor.length() > 0 ) { titleText.append(" - "); titleText.append( feedItem.mAuthor ); } else if( feed != null && feed.mName.length() > 0 ) { titleText.append(" - "); titleText.append( feed.mName ); } mTitleText = titleText.toString(); textView.setText( mTitleText ); } } @Override protected void onPause() { mHandler.removeCallbacks(mUpdateTask); AudioPlayer player = AudioPlayer.getInstance(this); if( player.hasStarted() ) { player.savePosition(); } super.onPause(); } @Override protected void onResume() { onTimer(); // update seek bar and kick-off timer // hide notification NotificationManager notificationManager = (NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE ); notificationManager.cancel(Globals.NOTIFICATION_PLAYING); super.onResume(); } @Override protected void onStart() { // hide notification NotificationManager notificationManager = (NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE ); notificationManager.cancel(Globals.NOTIFICATION_PLAYING); super.onStart(); } @Override protected void onStop() { // if playing, create notification AudioPlayer player = AudioPlayer.getInstance(this); if(player.isPlaying()) { Intent notificationIntent = new Intent(this, PlayAudioActivity.class); notificationIntent.putExtra(EXTRA_FROM_NOTIFICATION, true); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT); Notification notification = new Notification(R.drawable.feedscribe_status, null, 0); notification.setLatestEventInfo( this, getResources().getString(R.string.notification_now_playing), mTitleText, pendingIntent ); notification.flags |= Notification.FLAG_ONGOING_EVENT; NotificationManager notificationManager = (NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE ); notificationManager.notify(Globals.NOTIFICATION_PLAYING, notification); } super.onStop(); } }