PageRenderTime 19ms CodeModel.GetById 1ms app.highlight 15ms RepoModel.GetById 1ms app.codeStats 0ms

/randroid/src/com/google/marvin/randroid/randroid.java

http://eyes-free.googlecode.com/
Java | 302 lines | 247 code | 48 blank | 7 comment | 18 complexity | 8fcad8c42722fd3ec0a80ded3f8ae12c MD5 | raw file
  1package com.google.marvin.randroid;
  2
  3
  4import com.google.tts.TTS;
  5
  6import org.htmlparser.Parser;
  7import org.htmlparser.filters.NodeClassFilter;
  8import org.htmlparser.util.NodeList;
  9import org.htmlparser.util.ParserException;
 10import org.htmlparser.tags.ImageTag;
 11import org.htmlparser.tags.HeadingTag;
 12import org.htmlparser.tags.TextareaTag;
 13import org.htmlparser.tags.ParagraphTag;
 14
 15import android.app.Activity;
 16import android.app.Dialog;
 17import android.app.ProgressDialog;
 18import android.app.AlertDialog.Builder;
 19import android.content.ComponentName;
 20import android.content.DialogInterface;
 21import android.content.Intent;
 22import android.content.SharedPreferences;
 23import android.net.Uri;
 24import android.os.Bundle;
 25import android.preference.PreferenceManager;
 26import android.view.Menu;
 27import android.view.MenuItem;
 28import android.view.View;
 29import android.view.View.OnClickListener;
 30import android.webkit.WebView;
 31import android.widget.Button;
 32import android.widget.ImageButton;
 33import android.widget.TextView;
 34import android.widget.Toast;
 35
 36public class randroid extends Activity {
 37  private static final int PREFS_UPDATED = 42;
 38  private static final String randomUrl = "http://dynamic.xkcd.com/comic/random/";
 39  private static final String comicImagesBaseUrl = "http://imgs.xkcd.com/comics/";
 40  private static final String transcriptsUrlStart =
 41      "http://www.ohnorobot.com/transcribe.pl?comicid=apKHvCCc66NMg&url=http:%2F%2Fxkcd.com%2F";
 42  private static final String transcriptsUrlEnd = "%2F";
 43  private static final String permaLinkText = "Permanent link to this comic: http://xkcd.com/";
 44
 45  private randroid self;
 46
 47  private TTS tts;
 48  private String speakButtonPref;
 49  private Boolean displayToastPref;
 50
 51  private WebView web;
 52  private TextView title;
 53
 54  private String currentComment = "";
 55  private String currentComicNumber = "";
 56  private String currentComicTitle = "";
 57
 58
 59  private ProgressDialog loadingDialog = null;
 60
 61  /** Called when the activity is first created. */
 62  @Override
 63  public void onCreate(Bundle savedInstanceState) {
 64    super.onCreate(savedInstanceState);
 65
 66    self = this;
 67
 68    loadPrefs();
 69
 70    setContentView(R.layout.main);
 71    web = (WebView) findViewById(R.id.webView);
 72    title = (TextView) findViewById(R.id.titleText);
 73
 74    Button randomButton = (Button) findViewById(R.id.randomButton);
 75    randomButton.setOnClickListener(new OnClickListener() {
 76      public void onClick(View arg0) {
 77        loadRandomComic();
 78      }
 79    });
 80
 81    ImageButton speakButton = (ImageButton) findViewById(R.id.speakButton);
 82    speakButton.setOnClickListener(new OnClickListener() {
 83      public void onClick(View arg0) {
 84        speak();
 85      }
 86    });
 87
 88    tts = new TTS(this, null, false);
 89
 90    loadRandomComic();
 91  }
 92
 93  private void speak() {
 94    if (!speakButtonPref.equals(getString(R.string.none))) {
 95      if (tts.isSpeaking()) {
 96        tts.stop();
 97      } else {
 98        tts.speak(currentComment, 0, null);
 99      }
100    }
101    if (displayToastPref) {
102      Toast.makeText(this, currentComment, 1).show();
103    }
104  }
105
106
107
108  private void loadRandomComic() {
109    // Clear the cache before loading so that the size of the app doesn't keep growing.
110    web.clearCache(true);
111    web.clearHistory();
112    loadingDialog =
113        ProgressDialog.show(self, getString(R.string.loading), getString(R.string.please_wait),
114            true);
115    class comicLoader implements Runnable {
116      public void run() {
117        String url = "";
118        try {
119          Parser p = new Parser();
120          p.setURL(randomUrl.toString());
121
122          NodeList headings = p.extractAllNodesThatMatch(new NodeClassFilter(HeadingTag.class));
123          for (int i = 0; i < headings.size(); i++) {
124            HeadingTag n = (HeadingTag) headings.elementAt(i);
125            String headingText = n.getStringText();
126            if (headingText.startsWith(permaLinkText)) {
127              currentComicNumber =
128                  headingText.substring(permaLinkText.length(), headingText.length() - 1);
129              break;
130            }
131          }
132
133          p.reset();
134          NodeList images = p.extractAllNodesThatMatch(new NodeClassFilter(ImageTag.class));
135          for (int i = 0; i < images.size(); i++) {
136            ImageTag n = (ImageTag) images.elementAt(i);
137            String imageUrl = n.getImageURL();
138            if (imageUrl.startsWith(comicImagesBaseUrl)) {
139              url = imageUrl;
140              currentComment = n.getAttribute("title");
141              currentComicTitle = n.getAttribute("alt");
142              break;
143            }
144          }
145
146          if (speakButtonPref.equals(getString(R.string.transcript))) {
147            fetchTranscript();
148          }
149        } catch (ParserException pce) {
150          currentComicTitle = self.getString(R.string.net_error);
151        }
152        web.loadUrl(url);
153        updateDisplay();
154        loadingDialog.dismiss();
155      }
156    }
157    Thread loadThread = (new Thread(new comicLoader()));
158    loadThread.start();
159  }
160
161  private void updateDisplay() {
162    class titleTextUpdater implements Runnable {
163      public void run() {
164        title.setText(currentComicTitle);
165      }
166    }
167    title.post(new titleTextUpdater());
168  }
169
170
171  private void fetchTranscript() {
172    String transcriptUrl = transcriptsUrlStart + currentComicNumber + transcriptsUrlEnd;
173    String transcript = "";
174    try {
175      Parser p = new Parser();
176      p.setURL(transcriptUrl.toString());
177
178      // Sometimes transcripts are inside a textarea
179      NodeList textareas = p.extractAllNodesThatMatch(new NodeClassFilter(TextareaTag.class));
180      if (textareas.size() > 0) {
181        TextareaTag n = (TextareaTag) textareas.elementAt(0);
182        transcript = n.getStringText();
183        if (transcript.length() > 0) {
184          currentComment = transcript.toLowerCase().replaceAll("<br>", "\n");
185          return;
186        }
187      }
188
189      // Other times, they are inside a P
190      p.reset();
191      NodeList paragraphs = p.extractAllNodesThatMatch(new NodeClassFilter(ParagraphTag.class));
192      if (paragraphs.size() > 0) {
193        ParagraphTag n = (ParagraphTag) paragraphs.elementAt(0);
194        transcript = n.getStringText();
195        if (transcript.length() > 0) {
196          currentComment = transcript.toLowerCase().replaceAll("<br>", "\n");
197          return;
198        }
199      }
200    } catch (ParserException pce) {
201      // This can happen if there is a network error. Do nothing here.
202    }
203  }
204
205
206  @Override
207  protected void onDestroy() {
208    if (tts != null) {
209      tts.shutdown();
210    }
211    // Clean up the cache
212    web.clearCache(true);
213    web.clearHistory();
214    super.onDestroy();
215  }
216
217
218
219  @Override
220  public boolean onCreateOptionsMenu(Menu menu) {
221    menu.add(0, R.string.preferences, 0, R.string.preferences).setIcon(
222        android.R.drawable.ic_menu_preferences);
223    menu.add(0, R.string.about, 0, R.string.about).setIcon(android.R.drawable.ic_menu_info_details);
224    return super.onCreateOptionsMenu(menu);
225  }
226
227  @Override
228  public boolean onOptionsItemSelected(MenuItem item) {
229    Intent intent;
230    switch (item.getItemId()) {
231      case R.string.preferences:
232        intent = new Intent(this, PrefsActivity.class);
233        startActivityForResult(intent, PREFS_UPDATED);
234        break;
235      case R.string.about:
236        displayAbout();
237        break;
238    }
239    return super.onOptionsItemSelected(item);
240  }
241
242  @Override
243  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
244    if (requestCode == PREFS_UPDATED) {
245      loadPrefs();
246    }
247    super.onActivityResult(requestCode, resultCode, data);
248  }
249
250  private void loadPrefs() {
251    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
252    // From the game mode setting
253    speakButtonPref = prefs.getString("speak_pref", getString(R.string.commentary));
254    displayToastPref = prefs.getBoolean("display_toast_pref", true);
255  }
256
257  private void displayAbout() {
258    Builder about = new Builder(this);
259
260    about.setTitle(R.string.app_name);
261    about.setMessage(R.string.about_message);
262
263    final Activity self = this;
264
265    about.setNeutralButton(R.string.source, new Dialog.OnClickListener() {
266      public void onClick(DialogInterface dialog, int which) {
267        Intent i = new Intent();
268        ComponentName comp =
269            new ComponentName("com.android.browser", "com.android.browser.BrowserActivity");
270        i.setComponent(comp);
271        i.setAction("android.intent.action.VIEW");
272        i.addCategory("android.intent.category.BROWSABLE");
273        Uri uri = Uri.parse("http://eyes-free.googlecode.com");
274        i.setData(uri);
275        self.startActivity(i);
276      }
277    });
278
279    about.setPositiveButton(R.string.xkcd_website, new Dialog.OnClickListener() {
280      public void onClick(DialogInterface dialog, int which) {
281        Intent i = new Intent();
282        ComponentName comp =
283            new ComponentName("com.android.browser", "com.android.browser.BrowserActivity");
284        i.setComponent(comp);
285        i.setAction("android.intent.action.VIEW");
286        i.addCategory("android.intent.category.BROWSABLE");
287        Uri uri = Uri.parse("http://xkcd.com");
288        i.setData(uri);
289        self.startActivity(i);
290      }
291    });
292
293    about.setNegativeButton(R.string.close, new Dialog.OnClickListener() {
294      public void onClick(DialogInterface dialog, int which) {
295
296      }
297    });
298
299    about.show();
300  }
301
302}