package com.util; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.Set; import com.limegroup.gnutella.ActivityCallback; import com.limegroup.gnutella.Connection; import com.limegroup.gnutella.Downloader; import com.limegroup.gnutella.Endpoint; import com.limegroup.gnutella.GUID; import com.limegroup.gnutella.MediaType; import com.limegroup.gnutella.R; import com.limegroup.gnutella.RemoteFileDesc; import com.limegroup.gnutella.RouterService; import com.limegroup.gnutella.chat.Chatter; import com.limegroup.gnutella.downloader.AlreadyDownloadingException; import com.limegroup.gnutella.downloader.FileExistsException; import com.limegroup.gnutella.search.HostData; import com.limegroup.gnutella.security.User; import com.limegroup.gnutella.settings.SharingSettings; import com.limegroup.gnutella.util.StringUtils; import com.util.DownloadInfo; import com.util.DownloadService; import com.util.ListStatusView; import com.util.P2pSearchResult; import com.util.SearchResult; import com.util.SearchBar; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.ProgressDialog; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.ServiceConnection; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnErrorListener; import android.os.AsyncTask; import android.os.Bundle; import android.os.Debug; import android.os.Handler; import android.os.IBinder; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import android.widget.AdapterView.OnItemClickListener; public class SearchResultActivity extends Activity { private static final String TAG = Utils.TAG; protected static final int DIALOG_WAITING_FOR_SERVER = 1; protected static final int DIALOG_MUSIC_OPTIONS = 2; private static final int MAX_SEARCH_DELAY = 60000; protected SearchResult mCurrentResult; protected static WaitForRouterServiceTask sWaitForRouterServiceTask; protected SearchBar mSearch; protected String mQuery; protected ProgressDialog mProgressDialog; protected DownloadService mDownloadService; protected byte[] mGuid; protected Handler mHandler = new Handler(); protected ActivityCallback mListener; protected ListView mListView; protected Mp3ListAdapter mAdapter; protected volatile SearchAdapter mSearchAdapter; protected static volatile SearchResultActivity sSearchResultActivity; protected ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { mDownloadService = ((DownloadService.LocalBinder)service).getService(); } public void onServiceDisconnected(ComponentName className) { mDownloadService = null; } }; protected SearchAdapter getSearchAdapter() { return new SearchAdapter(mGuid); } private void download(SearchResult mp3) { mDownloadService.insertDownload(mp3.createDownloadInfo()); Intent intent = new Intent(SearchResultActivity.this, DownloadActivity.class); startActivity(intent); } protected static String getURL(String link) throws IOException { URL url = new URL(link); HttpURLConnection connection = (HttpURLConnection)url.openConnection(); connection.setConnectTimeout(1000); connection.connect(); StringBuilder builder = new StringBuilder(1024); InputStreamReader is = new InputStreamReader(connection.getInputStream()); BufferedReader reader = new BufferedReader(is, 1024); String line = null; while ((line = reader.readLine()) != null) { builder.append(line + "\n"); } return builder.toString(); } @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; } } return null; } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.search_result_menu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.dowloads: Intent intent = new Intent(SearchResultActivity.this, DownloadActivity.class); startActivity(intent); return true; } return false; } protected void startQuery(Intent intent) { mQuery = mSearch.getQuery(); mAdapter.setStatus(ListStatusView.Status.SEARCHING); mAdapter.notifyDataSetChanged(); if (TextUtils.isEmpty(mQuery)) { mQuery = StringUtils.removeIllegalChars(intent.getStringExtra(Constants.QUERY)); } sWaitForRouterServiceTask = new WaitForRouterServiceTask(intent, mQuery); sWaitForRouterServiceTask.execute(); } @Override protected void onNewIntent(Intent intent) { com.util.Utils.D("onNewIntent"); startQuery(intent); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); com.util.Utils.D("onCreate"); sSearchResultActivity = this; bindService(new Intent(this, DownloadService.class), mConnection, Context.BIND_AUTO_CREATE); setContentView(R.layout.result_list); //Utils.addMixedAds(this); mListView = (ListView)findViewById(R.id.result_list); mAdapter = new Mp3ListAdapter( SearchResultActivity.this, R.layout.result_item); mListView.setAdapter(mAdapter); mListView.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View v, int position, long id) { if (mSearchAdapter != null && position < mSearchAdapter.displaySize()) { mCurrentResult = mSearchAdapter.get(position); showDialog(DIALOG_MUSIC_OPTIONS); } } }); mSearch = new SearchBar(this); mListener = new RouterServiceListener(); //App.init(getApplication()); P2PApp.getRouterService(mListener); mHandler.post(new Runnable() { @Override public void run() { startQuery(getIntent()); } }); } @Override protected void onResume() { super.onResume(); //Debug.stopMethodTracing(); } @Override protected void onDestroy() { super.onDestroy(); stopQuery(); unbindService(mConnection); sSearchResultActivity = null; } private void stopQuery() { if (mGuid != null) { RouterService.stopQuery(new GUID(mGuid)); mGuid = null; } } protected class RouterServiceListener implements ActivityCallback { public RouterServiceListener() {} @Override public void acceptChat(Chatter ctr) { } @Override public void addDownload(Downloader d) { } @Override public void addressStateChanged() { } @Override public void browseHostFailed(GUID guid) { } @Override public void chatErrorMessage(Chatter chatter, String str) { // TODO Auto-generated method stub } @Override public void chatUnavailable(Chatter chatter) { // TODO Auto-generated method stub } @Override public void componentLoading(String component) { // TODO Auto-generated method stub } @Override public void connectionClosed(Connection c) { // TODO Auto-generated method stub } @Override public void connectionInitialized(Connection c) { // TODO Auto-generated method stub } @Override public void connectionInitializing(Connection c) { // TODO Auto-generated method stub } @Override public void downloadsComplete() { // TODO Auto-generated method stub } @Override public String getHostValue(String key) { // TODO Auto-generated method stub return null; } @Override public User getUserAuthenticationInfo(String host) { // TODO Auto-generated method stub return null; } @Override public void retryQueryAfterConnect() { stopQuery(); /* (new Thread(new Runnable () { @Override public void run() { try { while (!RouterService.isConnected()) { Thread.sleep(300); } } catch (InterruptedException e) { e.printStackTrace(); } SearchResultActivity.this.runOnUiThread(new Runnable() { @Override public void run() { startQuery(getIntent()); } }); } })).start(); */ try { while (!RouterService.isConnected()) { Thread.sleep(300); } } catch (InterruptedException e) { e.printStackTrace(); } //SearchResultActivity.this.runOnUiThread(new Runnable() { mHandler.post(new Runnable() { @Override public void run() { startQuery(getIntent()); } }); } @Override public synchronized void handleQueryResult( final RemoteFileDesc rfd, final HostData data, final Set<Endpoint> locs) { //com.util.Utils.D("handleQueryResult"); if (mGuid == null) return; if (data == null || rfd == null) { //LOG.logSp("handleQueryResult null"); return; } final byte[] replyGuid = data.getMessageGUID(); mHandler.post(new Runnable() { @Override public void run() { //if (!mSearchAdapter.sameGuid(replyGuid) && mSearchAdapter.size() > 3) { if (!mSearchAdapter.sameGuid(replyGuid)) { return; } /* if (mShowNoResult != null) { mHandler.removeCallbacks(mShowNoResult); mShowNoResult = null; } */ boolean shouldRefresh = mSearchAdapter.add(rfd, data, locs); int oldDisplaySize = mSearchAdapter.displaySize(); //com.util.Utils.D("shouldRefresh: " + shouldRefresh); if (shouldRefresh) { if (mSearchAdapter.isBatchFull()) { mAdapter.setStatus(ListStatusView.Status.LOAD_MORE); } else { mAdapter.setStatus(ListStatusView.Status.SEARCHING); } mAdapter.notifyDataSetChanged(); } else { if (mSearchAdapter.displaySize() != oldDisplaySize) { throw new IllegalStateException("display size does not match: " + mSearchAdapter.displaySize() + " vs " + oldDisplaySize); } } //mAdapter.notifyDataSetChanged(); } }); if (com.util.Utils.DEBUG) { synchronized(System.out) { com.util.Utils.D("Query hit from " + rfd.getHost() + ":" + rfd.getPort() + ":"); com.util.Utils.D("filename: " + rfd.getFileName()); //com.util.Utils.D("filesize: " + rfd.getSize()); //com.util.Utils.D("speed: " + rfd.getSpeed()); //com.util.Utils.D("Quality: " + rfd.getQuality()); //com.util.Utils.D("Wait time: " + rfd.getWaitTime()); } } } @Override public void handleQueryString(String query) { // TODO Auto-generated method stub } @Override public boolean isQueryAlive(GUID guid) { // TODO Auto-generated method stub return false; } @Override public void promptAboutCorruptDownload(Downloader dloader) { // TODO Auto-generated method stub } @Override public void receiveMessage(Chatter chr) { // TODO Auto-generated method stub } @Override public void removeDownload(Downloader d) { // TODO Auto-generated method stub } @Override public void restoreApplication() { // TODO Auto-generated method stub } @Override public void setAnnotateEnabled(boolean enabled) { // TODO Auto-generated method stub } @Override public void showDownloads() { // TODO Auto-generated method stub } } protected class Mp3ListAdapter extends BaseAdapter { private final static int VIEW_TYPE_NORMAL = 0; private final static int VIEW_TYPE_FOOTER = 1; private int mResource; private LayoutInflater mInflater; protected ListStatusView.Status mStatus; public Mp3ListAdapter(Context context, int resource) { mResource = resource; mInflater = (LayoutInflater)context.getSystemService( Context.LAYOUT_INFLATER_SERVICE); mStatus = ListStatusView.Status.OFFLINE; } public void setStatus(ListStatusView.Status status) { mStatus = status; } @Override public int getCount() { boolean showFooter = mStatus == ListStatusView.Status.LOAD_MORE || mStatus == ListStatusView.Status.SEARCHING || mStatus == ListStatusView.Status.NO_RESULT; int footerCount = showFooter ? 1 : 0; int count = 0; if (mSearchAdapter == null) count = footerCount; else count = mSearchAdapter.displaySize() + footerCount; //com.util.Utils.D("getCount: " + count); return count; } @Override public Object getItem(int position) { if (mSearchAdapter == null) return null; if (position < mSearchAdapter.displaySize()) return mSearchAdapter.get(position); return null; // footer. } @Override public long getItemId(int position) { if (mSearchAdapter == null) return -1; if (position < mSearchAdapter.displaySize()) return position; return -1; // footer. } @Override public int getViewTypeCount() { return 2; } @Override public int getItemViewType(int position) { if (mSearchAdapter == null || position == mSearchAdapter.displaySize()) return VIEW_TYPE_FOOTER; return VIEW_TYPE_NORMAL; } protected OnClickListener mLoadMoreListener = 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(); } } }; @Override public View getView(int position, View convertView, ViewGroup parent) { boolean isFooter = (mSearchAdapter == null || position == mSearchAdapter.displaySize()); if (isFooter) { ListStatusView footerView = (ListStatusView) convertView; if (footerView == null) { footerView = (ListStatusView) mInflater.inflate( R.layout.liststatus, null); } if (mStatus == ListStatusView.Status.LOAD_MORE) { footerView.setStatusLoadMore(); footerView.setOnClickListener(mLoadMoreListener); } else if (mStatus == ListStatusView.Status.SEARCHING) { footerView.setStatusSearching(); footerView.setOnClickListener(null); } else if (mStatus == ListStatusView.Status.NO_RESULT) { footerView.setStatusNoResult(); footerView.setOnClickListener(null); } return footerView; } View v; Object item = mSearchAdapter.get(position); if (convertView == null) { v = mInflater.inflate(mResource, parent, false); } else { v = convertView; } SearchResult rs = (SearchResult)item; ((TextView)v.findViewById(R.id.name)).setText(rs.getFileName()); ((TextView)v.findViewById(R.id.size)).setText(Utils.displaySizeInMB(rs.getFileSize())); //com.util.Utils.D(rs.getFileName() + " : " + rs.getSize()); return v; } } private class WaitForRouterServiceTask extends AsyncTask<Void, Void, Integer> { Intent mIntent; String mQuery; public WaitForRouterServiceTask(Intent intent, String query) { mIntent = intent; mQuery = query; } @Override protected void onPostExecute(Integer result) { if (sWaitForRouterServiceTask != this) { return; } sWaitForRouterServiceTask = null; String xml = mIntent == null ? null : mIntent.getStringExtra(Constants.XML); if (xml == null) xml = ""; if (!TextUtils.isEmpty(mQuery) || !TextUtils.isEmpty(xml)) { stopQuery(); mGuid = RouterService.newQueryGUID(); mSearchAdapter = getSearchAdapter(); mAdapter.notifyDataSetChanged(); RouterService.query(mGuid, mQuery, xml, MediaType.TYPE_MP3); } } @Override protected Integer doInBackground(Void... params) { try { while (!RouterService.isConnected()) { com.util.Utils.D("RouterService not ready"); Thread.sleep(500); } } catch (InterruptedException e) { e.printStackTrace(); } return 0; } } public static void handleMp3ListIntent(Context context, String key, String keyWords) { Intent intent = new Intent(context, SearchResultActivity.class); intent.putExtra(key, keyWords); context.startActivity(intent); } public static void handleMp3ListSimpleIntent(Context context, String keyWords) { Intent intent = new Intent(context, SearchResultActivity.class); intent.putExtra(Constants.QUERY, keyWords); context.startActivity(intent); } public static void handleMp3ListXMLIntent(Context context, String keyWords, String xml) { Intent intent = new Intent(context, SearchResultActivity.class); intent.putExtra(Constants.QUERY, keyWords); intent.putExtra(Constants.XML, xml); context.startActivity(intent); } }