code: /*
      arXiv mobile - a Free arXiv app for android
      http://code.google.com/p/arxiv-mobile/
  
      Copyright (C) 2010 Jack Deslippe
  
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      the Free Software Foundation; either version 2 of the License, or
      (at your option) any later version.
  
      This program 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 this program; if not, write to the Free Software
      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  
   */
  
  package com.commonsware.android.arXiv;
  
  import java.io.StringReader;
  import java.net.URL;
  import java.util.List;
  
  import javax.xml.parsers.SAXParser;
  import javax.xml.parsers.SAXParserFactory;
  
  import org.xml.sax.InputSource;
  import org.xml.sax.XMLReader;
  
  import android.app.ListActivity;
  import android.app.ProgressDialog;
  import android.content.Intent;
  import android.graphics.Typeface;
  import android.os.Bundle;
  import android.os.Handler;
  import android.os.Message;
  import android.view.Menu;
  import android.view.MenuItem;
  import android.view.View;
  import android.view.ViewGroup;
  import android.view.Window;
  import android.widget.ArrayAdapter;
  import android.widget.ListView;
  import android.widget.TextView;
  import android.widget.Button;
  import android.widget.Toast;
  import android.widget.LinearLayout;
  import android.view.LayoutInflater;
  import android.util.Log;
  
  public class RSSListWindow extends ListActivity {
  
      public RSSListWindow thisActivity;
      
      //UI-Views
      public ListView list;
      private TextView txt;
      private TextView header;
      
      private String name;
      private String urlAddress;
      private String query;
      private String[] titles;
      private String[] links;
      private String[] listText;
      private String[] listText2;
      private String[] descriptions;
      private String[] creators;
      private int fontSize;
      private arXivDB droidDB;
      private Feed favFeed;
      private Boolean vFavorite = false;
      private Boolean vLoaded = false;
      private int version;
  
      public static final int INCREASE_ID = Menu.FIRST + 1;
      public static final int DECREASE_ID = Menu.FIRST + 2;
      public static final int FAVORITE_ID = Menu.FIRST + 3;
  
      class myCustomAdapter extends ArrayAdapter {
  
          myCustomAdapter() {
              super(RSSListWindow.this, R.layout.searchrow, listText);
          }
  
          public View getView(int position, View convertView, ViewGroup parent) {
  
              View row=convertView;
              ViewHolder holder;
  
              if (row==null) {
                  LayoutInflater inflater=getLayoutInflater();
                  row=inflater.inflate(R.layout.searchrow, parent, false);
                  holder=new ViewHolder();
                  holder.text1=(TextView)row.findViewById(R.id.text1);
                  holder.text2=(TextView)row.findViewById(R.id.text2);
                  holder.linLay=(LinearLayout)row.findViewById(R.id.linlay);
                  row.setTag(holder);
              } else {
                  holder=(ViewHolder)row.getTag();
              }
              holder.text1.setText(listText[position]);
              holder.text1.setTextSize(fontSize);
              holder.text2.setText(listText2[position]);
              holder.text2.setTextSize(fontSize-2);
              if (position%2 == 0) {
                  holder.linLay.setBackgroundResource(R.drawable.back2);
              } else {
                  holder.linLay.setBackgroundResource(R.drawable.back4);
              }
              return(row);
  
          }
  
          public class ViewHolder{
              public TextView text1;
              public TextView text2;
              public LinearLayout linLay;
          }
  
      }
  
      private Handler handlerSetList = new Handler() {
          @Override
          public void handleMessage(Message msg) {
  
              setListAdapter(new myCustomAdapter());
  
          }
      };
  
      private Handler handlerDoneLoading = new Handler() {
          @Override
          public void handleMessage(Message msg) {
              vLoaded = true;
              setProgressBarIndeterminateVisibility(false);
          }
      };
  
      private boolean applyMenuChoice(MenuItem item) {
          switch (item.getItemId()) {
          case INCREASE_ID:
              if (fontSize < 22) {
                  if (fontSize < 10) {
                      fontSize = 10;
                  }
                  fontSize = fontSize + 2;
                  droidDB = new arXivDB(thisActivity);
                  droidDB.changeSize(fontSize);
                  droidDB.close();
                  if (vLoaded) {
                      handlerSetList.sendEmptyMessage(0);
                  }
              }
              return (true);
          case DECREASE_ID:
              if (fontSize > 10) {
                  if (fontSize > 22) {
                      fontSize = 22;
                  }
                  fontSize = fontSize - 2;
                  droidDB = new arXivDB(thisActivity);
                  droidDB.changeSize(fontSize);
                  droidDB.close();
                  if (vLoaded) {
                      handlerSetList.sendEmptyMessage(0);
                  }
              }
              return (true);
          case FAVORITE_ID:
              favoritePressed(null);
              return (true);
          }
          return (false);
      }
  
      private void getInfoFromXML() {
  
          final ProgressDialog dialog = ProgressDialog.show(this, "",
                  "Loading. Please wait...", true, true);
          setProgressBarIndeterminateVisibility(true);
  
          Thread t2 = new Thread() {
              public void run() {
                  try {
  
                      waiting(200);
  
                      txt.post(new Runnable() {
                          public void run() {
                              txt.setText("Loading");
                          }
                      });
  
                      URL url = new URL(urlAddress);
                      SAXParserFactory spf = SAXParserFactory.newInstance();
                      SAXParser sp = spf.newSAXParser();
                      XMLReader xr = sp.getXMLReader();
                      XMLHandlerRSS myXMLHandler = new XMLHandlerRSS();
                      xr.setContentHandler(myXMLHandler);
  
                      Boolean vcompleted = true;
  
                      try {
                          xr.parse(new InputSource(url.openStream()));
                      } catch (Exception saxe) {
                          if (myXMLHandler.numItems == 0) {
                              txt.post(new Runnable() {
                                  public void run() {
                                      txt.setText(R.string.couldnt_parse);
                                  }
                              });
                              vcompleted = false;
                          }
                      }
  
                      int nitems = myXMLHandler.numItems;
                      final String tdate = myXMLHandler.date.replace("T"," ").replace("Z","");;
                      final int nitemst = nitems;
  
                      if (vcompleted) {
                          txt.post(new Runnable() {
                              public void run() {
                                  txt.setText(nitemst
                                          + " new submissions.\nRefreshed: "
                                          + tdate);
                              }
                          });
                      }
  
                      if (nitemst != myXMLHandler.icount) {
                          nitems = myXMLHandler.icount;
                          final int nitemst2 = nitems;
                          txt.post(new Runnable() {
                              public void run() {
                                  txt
                                          .setText(nitemst
                                                  + " new submissions.  Refreshed: "
                                                  + tdate
                                                  + "\nError in feed - only showing first "
                                                  + nitemst2 + " results.");
                              }
                          });
                      }
  
                      titles = new String[nitems];
                      creators = new String[nitems];
                      links = new String[nitems];
                      listText = new String[nitems];
                      listText2 = new String[nitems];
                      descriptions = new String[nitems];
  
                      for (int i = 0; i < nitems; i++) {
                          titles[i] = myXMLHandler.titles[i].replaceAll(
                                  "(.arXiv.*)", "");
                          //String category = "";
                          String category = myXMLHandler.titles[i].replaceAll(".*\\[","").replace("])","").replace("] UPDATED)","");
                          creators[i] = myXMLHandler.creators[i];
                          links[i] = myXMLHandler.links[i];
                          descriptions[i] = myXMLHandler.descriptions[i];
                          listText[i] = titles[i];
                          listText2[i] = "";
  
                          String creatort = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<begin>"
                                  + creators[i] + "\n</begin>";
                          try {
                              SAXParserFactory spf2 = SAXParserFactory
                                      .newInstance();
                              SAXParser sp2 = spf2.newSAXParser();
                              XMLReader xr2 = sp2.getXMLReader();
                              XMLHandlerCreator myXMLHandler2 = new XMLHandlerCreator();
                              xr2.setContentHandler(myXMLHandler2);
                              xr2.parse(new InputSource(
                                      new StringReader(creatort)));
                              listText2[i] = listText2[i] + "-Authors: "
                                + myXMLHandler2.creators[0];
                              for (int j = 1; j < myXMLHandler2.numItems; j++) {
                                  //listText[i] = listText[i] + " - "
                                  listText2[i] = listText2[i] + ", "
                                          + myXMLHandler2.creators[j];
                              }
                          } catch (Exception e) {
                          }
                          if (myXMLHandler.titles[i].contains("UPDATED")) {
                              listText2[i] = listText2[i] + "\n-Updated";
                          }
                          if (!query.contains(category)) {
                              listText2[i] = listText2[i] + "\n-Cross-Ref: "+category;
                          }
                      }
  
                      handlerSetList.sendEmptyMessage(0);
  
                  } catch (Exception e) {
  
                      final Exception ef = e;
                      txt.post(new Runnable() {
                          public void run() {
                              txt.setText("Failed "+ef);
                          }
                      });
  
                  }
  
                  dialog.dismiss();
                  handlerDoneLoading.sendEmptyMessage(0);
              }
          };
          t2.start();
      }
  
      public void favoritePressed(View button) {
          droidDB = new arXivDB(this);
          droidDB.insertFeed(name+" (RSS)", name, query, -2, -2);
          Toast.makeText(this, R.string.added_to_favorites_rss,
                  Toast.LENGTH_LONG).show();
          droidDB.close();
          vFavorite=true;
          if (version > 10) {
              invalidateOptionsMenu();
          }
      }
  
  
      /** Called when the activity is first created. */
      @Override
      public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
          setContentView(R.layout.searchlist);
  
          version = android.os.Build.VERSION.SDK_INT;
  
          Intent myIntent = getIntent();
          name = myIntent.getStringExtra("keyname");
          query = myIntent.getStringExtra("keyurl");
          urlAddress = "http://export.arxiv.org/rss/" + query;
  
          Log.d("Arxiv - ","RSS "+urlAddress);
  
          header = (TextView) findViewById(R.id.theaderlis);
  
          Typeface face = Typeface.createFromAsset(getAssets(),
                  "fonts/LiberationSans.ttf");
          header.setTypeface(face);
  
          header.setText(name);
  
          thisActivity = this;
  
          txt = (TextView) findViewById(R.id.txt);
  
          droidDB = new arXivDB(thisActivity);
          fontSize = droidDB.getSize();
          //Log.d("EMD - ","Fontsize "+fontSize);
          if (fontSize == 0) {
              fontSize = 16;
              droidDB.changeSize(fontSize);
          }
          List<Feed> favorites = droidDB.getFeeds();
          for (Feed feed : favorites) {
              if (query.equals(feed.url)) {
                  favFeed=feed;
                  vFavorite=true;
                  if (version > 10) {
                      invalidateOptionsMenu();
                  }
              }
          }
          droidDB.close();
  
          droidDB.close();
  
          getInfoFromXML();
  
      }
  
      @Override
      public boolean onCreateOptionsMenu(Menu menu) {
          populateMenu(menu);
          return (super.onCreateOptionsMenu(menu));
      }
  
      @Override
      public boolean onPrepareOptionsMenu(Menu menu) {
          menu.clear();
          populateMenu(menu);
          return (super.onCreateOptionsMenu(menu));
      }
  
      public void onListItemClick(ListView parent, View v, int position, long id) {
          Intent myIntent = new Intent(this, SingleItemWindow.class);
          myIntent.putExtra("keytitle", titles[position]);
          myIntent.putExtra("keylink", links[position]);
          myIntent.putExtra("keydescription", descriptions[position]);
          myIntent.putExtra("keycreator", creators[position]);
          myIntent.putExtra("keyname", name);
          startActivity(myIntent);
      }
  
      @Override
      public boolean onOptionsItemSelected(MenuItem item) {
          return (applyMenuChoice(item) || super.onOptionsItemSelected(item));
      }
  
      private void populateMenu(Menu menu) {
          menu.add(Menu.NONE, INCREASE_ID, Menu.NONE, "Increase Font");
          menu.add(Menu.NONE, DECREASE_ID, Menu.NONE, "Decrease Font");
          if (!vFavorite) {
              menu.add(Menu.NONE, FAVORITE_ID, Menu.NONE, "Add to Favorites");
          }
      }
  
      private void waiting(int n) {
          long t0, t1;
          t0 = System.currentTimeMillis();
          do {
              t1 = System.currentTimeMillis();
          } while (t1 - t0 < n);
      }
  
  }
  