package com.happy.life; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import android.app.AlertDialog; import android.app.Dialog; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnErrorListener; import android.os.AsyncTask; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.Toast; import com.limegroup.gnutella.Downloader; import com.limegroup.gnutella.GUID; import com.limegroup.gnutella.RemoteFileDesc; import com.limegroup.gnutella.RouterService; import com.limegroup.gnutella.downloader.AlreadyDownloadingException; import com.limegroup.gnutella.downloader.FileExistsException; import com.limegroup.gnutella.settings.SharingSettings; import com.util.Constants; import com.util.DownloadInfo; import com.util.ListStatusView; import com.util.P2pSearchResult; import com.util.SearchAdapter; import com.util.SearchResult; import com.util.SearchResultActivity; public class MusicSearchResultActivity extends SearchResultActivity { private static final String TAG = Utils.TAG; private static final int DIALOG_MUSIC_STREAMING = 3; private static final int MUSIC_OPTION_DOWNLOAD = 0; private static final int MUSIC_OPTION_PREVIEW = 1; private static volatile SogouMusicSearcher sSogouMusicSearcher = new SogouMusicSearcher(); private static FetchMp3ListTask sFetchMp3ListTask; private static volatile MediaPlayer sPlayer; protected MusicSearchBar mMusicSearch; MusicMp3ListAdapter mMusicAdapter; private ProgressDialog mStreaming; private static volatile Thread sPreviewThread; protected static volatile MusicSearchResultActivity sMusicSearchResultActivity; protected SearchAdapter getSearchAdapter() { return new MusicSearchAdapter(mGuid); } @Override protected void onCreate(Bundle savedInstanceState) { sMusicSearchResultActivity = this; super.sSearchResultActivity = sMusicSearchResultActivity; super.onCreate(savedInstanceState); App.init(getApplication()); mMusicSearch = new MusicSearchBar(this); super.mSearch = mMusicSearch; mMusicAdapter = new MusicMp3ListAdapter( MusicSearchResultActivity.this, R.layout.result_item); super.mAdapter = mMusicAdapter; super.mListView.setAdapter(mMusicAdapter); } private void download(SearchResult mp3) { mDownloadService.insertDownload(mp3.createDownloadInfo()); Intent intent = new Intent(MusicSearchResultActivity.this, MusicDownloadActivity.class); startActivity(intent); } private void preview(final SearchResult mp3) { if (mDownloadService.fileBeingDownloaded(mp3)) { runOnUiThread(new Runnable() { @Override public void run() { if (mStreaming != null) { mStreaming.dismiss(); } Utils.Error(MusicSearchResultActivity.this, "You can't preivew the music while it is being downloaded"); } }); return; } if (sPreviewThread != null) { sPreviewThread.interrupt(); sPreviewThread = null; } if (mp3 instanceof P2pSearchResult) { sPreviewThread = new Thread(new Runnable() { @SuppressWarnings("unchecked") @Override public void run() { boolean previewError = false; Downloader downloader = null; MediaPlayer player = null; try { RemoteFileDesc rfd = ((P2pSearchResult)mp3).getFirstRFD(); if (rfd == null) { previewError = true; Log.e(TAG, "No rfd for preview."); return; } RemoteFileDesc rfds[] = new RemoteFileDesc[] { rfd }; player = sPlayer; if (player != null) { player.release(); } downloader = RouterService.download(rfds, Collections.EMPTY_SET, true, new GUID(((P2pSearchResult)mp3).getGuid())); if (downloader == null) { previewError = true; Log.e(TAG, "No downloader for preview."); return; } String targetFile = downloader.getFile().getName(); int state = downloader.getState(); // Wait until we start to download. while (state != Downloader.DOWNLOADING) { // But if we can't continue, break the loop. if (state == Downloader.ABORTED || state == Downloader.GAVE_UP || state == Downloader.DISK_PROBLEM || state == Downloader.CORRUPT_FILE || state == Downloader.WAITING_FOR_USER || state == Downloader.RECOVERY_FAILED || state == Downloader.PAUSED) { previewError = true; Log.e(TAG, "Invalid preview state: " + state); break; } Thread.sleep(1000); state = downloader.getState(); } while (!previewError) { String readyUrl = "http://localhost:" + Constants.MINI_SERVER_PORT + "/cmd=ready&file=" + URLEncoder.encode(targetFile); String ready = getURL(readyUrl).trim(); state = downloader.getState(); com.util.Utils.D("isReady: " + ready); com.util.Utils.D("state: " + state); if (ready.equals("true")) { break; } Thread.sleep(1000); } if (!previewError) { if (TextUtils.isEmpty(mp3.getFileName())) { previewError = true; Log.e(TAG, "Empty preview filename."); return; } String previewUrl = "http://localhost:" + Constants.MINI_SERVER_PORT + "/file=" + URLEncoder.encode(downloader.getFile().getName()) + "&dwfile=" + URLEncoder.encode(mp3.getFileName()); player = new MediaPlayer(); player.reset(); com.util.Utils.D("preview url: " + previewUrl); player.setDataSource(previewUrl); com.util.Utils.D("+++ player data source set"); player.prepare(); com.util.Utils.D("+++ player prepared"); player.start(); com.util.Utils.D("+++ player started"); player.setOnCompletionListener(new OnCompletionListener () { @Override public void onCompletion(MediaPlayer mp) { sPlayer = null; com.util.Utils.D("+++ player completed"); if (sPreviewThread != null) sPreviewThread.interrupt(); sPreviewThread = null; if (sSearchResultActivity != null) { sSearchResultActivity.runOnUiThread(new Runnable() { @Override public void run() { MusicSearchResultActivity.this.dismissStreamingDialog(); } }); } } }); sPlayer = player; state = downloader.getState(); while ((DownloadInfo.isDownloading(state) && state != Downloader.WAITING_FOR_USER) || state == Downloader.COMPLETE) { if (state == Downloader.ABORTED || state == Downloader.GAVE_UP || state == Downloader.DISK_PROBLEM || state == Downloader.CORRUPT_FILE || state == Downloader.WAITING_FOR_USER || state == Downloader.RECOVERY_FAILED || state == Downloader.PAUSED) { previewError = true; Log.e(TAG, "Invalid preview state: " + state); break; } Thread.sleep(1000); state = downloader.getState(); com.util.Utils.D("preview state: " + state); } com.util.Utils.D("+++ Exit state: " + state); } } catch (FileExistsException e) { previewError = true; e.printStackTrace(); } catch (FileNotFoundException e) { previewError = true; e.printStackTrace(); } catch (AlreadyDownloadingException e) { previewError = true; e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { previewError = true; e.printStackTrace(); } catch (IllegalStateException e) { previewError = true; e.printStackTrace(); } catch (IOException e) { previewError = true; e.printStackTrace(); } finally { sPlayer = null; if (player != null) player.release(); // Delete the target file. if (downloader != null) { downloader.stop(); com.util.Utils.D("+++ Downloader stopped"); if (downloader.getFile() == null) return; String targetFile = downloader.getFile().getName(); if (targetFile == null) return; File file = new File(SharingSettings.INCOMPLETE_DIRECTORY, targetFile); if (file.exists()) { file.delete(); } downloader = null; } runOnUiThread(new Runnable() { @Override public void run() { if (mStreaming != null) { mStreaming.dismiss(); } } }); if (previewError) { runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(getApplication(), "Something was wrong", Toast.LENGTH_LONG).show(); } }); } sPreviewThread = null; } } }); sPreviewThread.start(); } else if (mp3 instanceof SogouSearchResult) { final SogouSearchResult sogouMp3 = (SogouSearchResult)mp3; if (sogouMp3.getDownloadUrl() != null && sogouMp3.getDownloadUrl().startsWith("http:")) { sPreviewThread = new Thread(new Runnable() { @Override public void run() { try { MediaPlayer player = sPlayer; if (player != null) { player.release(); } sPlayer = new MediaPlayer(); player = sPlayer; player.reset(); player.setDataSource(sogouMp3.getDownloadUrl()); player.prepare(); player.start(); player.setOnCompletionListener(new OnCompletionListener () { @Override public void onCompletion(MediaPlayer mp) { sPlayer = null; runOnUiThread(new Runnable() { @Override public void run() { if (mStreaming != null) { mStreaming.dismiss(); } } }); } }); player.setOnErrorListener(new OnErrorListener() { @Override public boolean onError(MediaPlayer mp, int what, int extra) { onPlayError(); return true; } }); if (sPlayer == null) { // Someone requested us to stop. player.release(); } } catch (IllegalArgumentException e) { onPlayError(); e.printStackTrace(); } catch (IllegalStateException e) { //onPlayError(); e.printStackTrace(); } catch (IOException e) { onPlayError(); e.printStackTrace(); } finally { sPreviewThread = null; } } }); sPreviewThread.start(); } } } private void onPlayError() { MediaPlayer player = sPlayer; sPlayer = null; if (player != null) player.release(); runOnUiThread(new Runnable() { @Override public void run() { if (mStreaming != null) { mStreaming.dismiss(); } Toast.makeText(getApplication(), "Streaming error", Toast.LENGTH_LONG).show(); } }); } @Override protected Dialog onCreateDialog(int id) { com.util.Utils.D("onCreateDialog() " + id); switch (id) { case DIALOG_WAITING_FOR_SERVER: { if (mProgressDialog == null) { mProgressDialog = new ProgressDialog(this); mProgressDialog.setMessage(getString(R.string.wait)); mProgressDialog.setIndeterminate(true); mProgressDialog.setCancelable(true); } return mProgressDialog; } case DIALOG_MUSIC_OPTIONS: return new AlertDialog.Builder(MusicSearchResultActivity.this) .setItems(R.array.music_item_options, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { switch(which) { case MUSIC_OPTION_DOWNLOAD: if (mCurrentResult == null) return; download(mCurrentResult); break; case MUSIC_OPTION_PREVIEW: if (mCurrentResult == null) return; if (mCurrentResult instanceof SogouSearchResult) { SogouSearchResult sogouResult = (SogouSearchResult)mCurrentResult; mHandler.post(new Runnable() { @Override public void run() { showDialog(DIALOG_MUSIC_STREAMING); } }); if (sogouResult.getDownloadUrl() == null) { new FetchMp3LinkTaskForPreview().execute(sogouResult); break; } } else { mHandler.post(new Runnable() { @Override public void run() { showDialog(DIALOG_MUSIC_STREAMING); } }); preview(mCurrentResult); break; } } } }) .create(); case DIALOG_MUSIC_STREAMING: if (mStreaming == null) { mStreaming = new ProgressDialog(MusicSearchResultActivity.this); mStreaming.setTitle("Streaming music..."); mStreaming.setMessage(getString(R.string.wait)); mStreaming.setIndeterminate(true); mStreaming.setCancelable(false); mStreaming.setButton(getString(R.string.stop), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (mStreaming != null) { mStreaming.dismiss(); mStreaming = null; } MediaPlayer player = sPlayer; sPlayer = null; if (player != null) { player.release(); } if (sPreviewThread != null) { sPreviewThread.interrupt(); sPreviewThread = null; } } }); } return mStreaming; } return null; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.dowloads: Intent intent = new Intent(MusicSearchResultActivity.this, MusicDownloadActivity.class); startActivity(intent); return true; } return false; } @Override protected void startQuery(Intent intent) { super.startQuery(intent); if (!TextUtils.isEmpty(mQuery)) { sSogouMusicSearcher.setQuery(mQuery); sFetchMp3ListTask = new FetchMp3ListTask(getApplication()); sFetchMp3ListTask.execute(); } } public void dismissStreamingDialog() { if (mStreaming != null && mStreaming.isShowing()) { mStreaming.dismiss(); } } private void handleSogouSearchResult(ArrayList<SogouSearchResult> mp3List) { ArrayList<SogouSearchResult> newList = Utils.dedup(mp3List); if (newList != null && mSearchAdapter != null) { for (Iterator<SogouSearchResult> it = newList.iterator(); it.hasNext();) { SogouSearchResult result = it.next(); boolean shouldRefresh = ((MusicSearchAdapter)mSearchAdapter).add(result); int oldDisplaySize = mSearchAdapter.displaySize(); if (shouldRefresh) { if (mSearchAdapter.isBatchFull()) { mMusicAdapter.setStatus(ListStatusView.Status.LOAD_MORE); } else { mMusicAdapter.setStatus(ListStatusView.Status.SEARCHING); } mMusicAdapter.notifyDataSetChanged(); } else { if (mSearchAdapter.displaySize() != oldDisplaySize) { throw new IllegalStateException("display size does not match: " + mSearchAdapter.displaySize() + " vs " + oldDisplaySize); } } } } } protected class MusicMp3ListAdapter extends Mp3ListAdapter { OnClickListener mLoadMoreListener2 = new OnClickListener() { @Override public void onClick(View v) { if (mStatus == ListStatusView.Status.LOAD_MORE) { mSearchAdapter.nextBatch(); if (mSearchAdapter.isBatchFull()) { // If the next page has enough results (full), we // are ok, waiting for user to load more. mAdapter.setStatus(ListStatusView.Status.LOAD_MORE); } else { // Otherwise we don't have enough result. mAdapter.setStatus(ListStatusView.Status.SEARCHING); sFetchMp3ListTask = new FetchMp3ListTask(getApplication()); sFetchMp3ListTask.execute(); } notifyDataSetChanged(); } } }; public MusicMp3ListAdapter(Context context, int resource) { super(context, resource); super.mLoadMoreListener = mLoadMoreListener2; } } private class FetchMp3LinkTaskForPreview extends AsyncTask<SogouSearchResult, Void, SogouSearchResult> { protected SogouSearchResult doInBackground(SogouSearchResult... mp3s) { SogouSearchResult mp3 = mp3s[0]; SogouMusicSearcher.setMusicDownloadUrl(getApplication(), mp3); return mp3; } protected void onPostExecute(SogouSearchResult mp3) { if (mp3.getDownloadUrl() == null) { if (mStreaming != null) { mStreaming.dismiss(); } Toast.makeText(MusicSearchResultActivity.this, R.string.no_download_link, Toast.LENGTH_SHORT).show(); return; } preview(mp3); } } private static class FetchMp3ListTask extends AsyncTask<Void, Void, ArrayList<SogouSearchResult>> { Context mContext; public FetchMp3ListTask(Context context) { super(); mContext = context; } @Override protected void onPostExecute(ArrayList<SogouSearchResult> mp3List) { if (sFetchMp3ListTask != this) { // Another query is going on. return; } sFetchMp3ListTask = null; if (sMusicSearchResultActivity != null) { sMusicSearchResultActivity.handleSogouSearchResult(mp3List); } } @Override protected ArrayList<SogouSearchResult> doInBackground(Void... params) { return sSogouMusicSearcher.getNextResultList(mContext); } } public static void handleMp3ListIntent(Context context, String key, String keyWords) { Intent intent = new Intent(context, MusicSearchResultActivity.class); intent.putExtra(key, keyWords); context.startActivity(intent); } public static void handleMp3ListSimpleIntent(Context context, String keyWords) { Intent intent = new Intent(context, MusicSearchResultActivity.class); intent.putExtra(Constants.QUERY, keyWords); context.startActivity(intent); } public static void handleMp3ListXMLIntent(Context context, String keyWords, String xml) { Intent intent = new Intent(context, MusicSearchResultActivity.class); intent.putExtra(Constants.QUERY, keyWords); intent.putExtra(Constants.XML, xml); context.startActivity(intent); } }