package org.pyload.android.client.fragments; import java.util.ArrayList; import java.util.List; import org.pyload.android.client.R; import org.pyload.android.client.pyLoad; import org.pyload.android.client.module.Utils; import org.pyload.android.client.pyLoadApp; import org.pyload.android.client.components.TabHandler; import org.pyload.android.client.dialogs.CaptchaDialog; import org.pyload.android.client.module.GuiTask; import org.pyload.thrift.CaptchaTask; import org.pyload.thrift.DownloadInfo; import org.pyload.thrift.DownloadStatus; import org.pyload.thrift.Pyload.Client; import org.pyload.thrift.ServerStatus; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnDismissListener; import android.content.Intent; import android.media.RingtoneManager; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.support.v4.app.ListFragment; import android.support.v4.app.NotificationCompat; import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.LayoutInflater; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.BaseAdapter; import android.widget.ProgressBar; import android.widget.TextView; public class OverviewFragment extends ListFragment implements OnDismissListener, TabHandler { public final static int CAPTCHA_DIALOG = 0; private pyLoadApp app; private Client client; private OverviewAdapter adp; private List<DownloadInfo> downloads; private ServerStatus status; private CaptchaTask captcha; private int lastCaptcha = -1; private int interval = 5; private boolean update = false; private boolean dialogOpen = false; // tab position private int pos = -1; /** * GUI Elements */ private TextView statusServer; private TextView reconnect; private TextView speed; private TextView active; private final Handler mHandler = new Handler(); private final Runnable mUpdateResults = new Runnable() { public void run() { onDataReceived(); } }; private final Runnable runUpdate = new Runnable() { public void run() { client = app.getClient(); downloads = client.statusDownloads(); status = client.statusServer(); if (client.isCaptchaWaiting()) { Log.d("pyLoad", "Captcha available"); captcha = client.getCaptchaTask(false); Log.d("pyload", captcha.resultType); showNotification(); } else { app.setCaptchaNotificationShown(false); } } }; private final Runnable cancelUpdate = new Runnable() { public void run() { stopUpdate(); } }; private final Runnable mUpdateTimeTask = new Runnable() { public void run() { refresh(); if (update) mHandler.postDelayed(this, interval * 1000); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); app = (pyLoadApp) getActivity().getApplicationContext(); downloads = new ArrayList<DownloadInfo>(); adp = new OverviewAdapter(app, R.layout.overview_item, downloads); } public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.overview, null, false); statusServer = (TextView) v.findViewById(R.id.status_server); reconnect = (TextView) v.findViewById(R.id.reconnect); speed = (TextView) v.findViewById(R.id.speed); active = (TextView) v.findViewById(R.id.active); // toggle pause on click statusServer.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { app.addTask(new GuiTask(new Runnable() { public void run() { Client client = app.getClient(); client.togglePause(); } }, app.handleSuccess)); } }); // toggle reconnect on click reconnect.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { app.addTask(new GuiTask(new Runnable() { public void run() { Client client = app.getClient(); client.toggleReconnect(); } }, app.handleSuccess)); } }); if (status != null && downloads != null) onDataReceived(); registerForContextMenu(v.findViewById(android.R.id.list)); return v; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setListAdapter(adp); } @Override public void onStart() { super.onStart(); onSelected(); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { MenuInflater inflater = getActivity().getMenuInflater(); inflater.inflate(R.menu.overview_context_menu, menu); menu.setHeaderTitle(R.string.choose_action); } @Override public boolean onContextItemSelected(MenuItem item) { if (!app.isCurrentTab(pos)) return false; AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo) item .getMenuInfo(); final int id = menuInfo.position; final DownloadInfo info = downloads.get(id); switch (item.getItemId()) { case R.id.abort: app.addTask(new GuiTask(new Runnable() { public void run() { client = app.getClient(); ArrayList<Integer> fids = new ArrayList<Integer>(); fids.add(info.fid); client.stopDownloads(fids); } }, new Runnable() { public void run() { refresh(); } })); return true; default: return super.onContextItemSelected(item); } } @Override public void onSelected() { startUpdate(); } @Override public void onDeselected() { stopUpdate(); } private void startUpdate() { // already update running if (update) return; try { interval = Integer.parseInt(app.prefs .getString("refresh_rate", "5")); } catch (NumberFormatException e) { // somehow contains illegal value interval = 5; } update = true; mHandler.post(mUpdateTimeTask); } private void stopUpdate() { update = false; mHandler.removeCallbacks(mUpdateTimeTask); } /** * Called when Status data received */ protected void onDataReceived() { OverviewAdapter adapter = (OverviewAdapter) getListAdapter(); adapter.setDownloads(downloads); statusServer.setText(app.verboseBool(status.download)); reconnect.setText(app.verboseBool(status.reconnect)); speed.setText(Utils.formatSize(status.speed) + "/s"); active.setText(String.format("%d / %d", status.active, status.total)); if (captcha != null && app.prefs.getBoolean("pull_captcha", true) && captcha.resultType != null // string null bug && captcha.resultType.equals("textual") && lastCaptcha != captcha.tid) { showDialog(); } } public void refresh() { if (!app.hasConnection()) return; GuiTask task = new GuiTask(runUpdate, mUpdateResults); task.setCritical(cancelUpdate); app.addTask(task); } private void showDialog() { if (dialogOpen || captcha == null) return; CaptchaDialog dialog = CaptchaDialog.newInstance(captcha); lastCaptcha = captcha.tid; Log.d("pyLoad", "Got Captcha Task"); dialog.setOnDismissListener(this); dialogOpen = true; try { dialog.show(getFragmentManager(), CaptchaDialog.class.getName()); } catch (IllegalStateException e) { dialogOpen = false; // seems to appear when overview is already closed Log.e("pyLoad", "Dialog state error", e); } catch (NullPointerException e) { dialogOpen = false; // something is null, but why? Log.e("pyLoad", "Dialog null pointer error", e); } } public void onDismiss(DialogInterface arg0) { captcha = null; dialogOpen = false; } @Override public void setPosition(int pos) { this.pos = pos; } private void showNotification() { if (!app.getCaptchaNotificationShown()) { app.setCaptchaNotificationShown(true); NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(app) .setSmallIcon(R.drawable.ic_launcher) .setContentTitle(getString(R.string.captcha_notification)) .setContentText(getString(R.string.captcha_notification_desc)); Intent notificationIntent = new Intent(app, pyLoad.class); notificationIntent.putExtra("CaptchaNotification", true); PendingIntent contentIntent = PendingIntent.getActivity(app, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT); mBuilder.setContentIntent(contentIntent); NotificationManager mNotificationManager = (NotificationManager)app.getSystemService(Context.NOTIFICATION_SERVICE); Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); mBuilder.setSound(alarmSound); mNotificationManager.notify(0, mBuilder.build()); } } } /** * Renders the single ListView items * * @author RaNaN * */ class OverviewAdapter extends BaseAdapter { static class ViewHolder { private TextView name; private ProgressBar progress; private TextView size; private TextView percent; private TextView size_done; private TextView speed; private TextView eta; } private final pyLoadApp app; private List<DownloadInfo> downloads; private final int rowResID; private final LayoutInflater layoutInflater; public OverviewAdapter(final pyLoadApp app, final int rowResID, List<DownloadInfo> downloads) { this.app = app; this.rowResID = rowResID; this.downloads = downloads; layoutInflater = (LayoutInflater) app .getSystemService(Context.LAYOUT_INFLATER_SERVICE); } public void setDownloads(List<DownloadInfo> downloads) { this.downloads = downloads; notifyDataSetChanged(); } public int getCount() { return downloads.size(); } public Object getItem(int id) { return downloads.get(id); } public long getItemId(int pos) { return pos; } public View getView(int position, View convertView, ViewGroup parent) { DownloadInfo info = downloads.get(position); if (convertView == null) { convertView = layoutInflater.inflate(rowResID, null); ViewHolder holder = new ViewHolder(); holder.name = (TextView) convertView.findViewById(R.id.name); holder.progress = (ProgressBar) convertView .findViewById(R.id.progress); holder.size = (TextView) convertView.findViewById(R.id.size); holder.speed = (TextView) convertView.findViewById(R.id.speed); holder.size_done = (TextView) convertView .findViewById(R.id.size_done); holder.eta = (TextView) convertView.findViewById(R.id.eta); holder.percent = (TextView) convertView.findViewById(R.id.percent); convertView.setTag(holder); } ViewHolder holder = (ViewHolder) convertView.getTag(); // name is null sometimes somehow if (info.name != null && !info.name.equals(holder.name.getText())) { holder.name.setText(info.name); } holder.progress.setProgress(info.percent); if (info.status == DownloadStatus.Downloading) { holder.size.setText(Utils.formatSize(info.size)); holder.percent.setText(info.percent + "%"); holder.size_done.setText(Utils.formatSize(info.size - info.bleft)); holder.speed.setText(Utils.formatSize(info.speed) + "/s"); holder.eta.setText(info.format_eta); } else if (info.status == DownloadStatus.Waiting) { holder.size.setText(R.string.lambda); holder.percent.setText(R.string.lambda); holder.size_done.setText(R.string.lambda); holder.speed.setText(info.statusmsg); holder.eta.setText(info.format_wait); } else { holder.size.setText(R.string.lambda); holder.percent.setText(R.string.lambda); holder.size_done.setText(R.string.lambda); holder.speed.setText(info.statusmsg); holder.eta.setText(R.string.lambda); } return convertView; } public boolean hasStableIds() { return false; } }