1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.example.android.simplewiktionary; 18 19 import com.example.android.simplewiktionary.SimpleWikiHelper.ApiException; 20 import com.example.android.simplewiktionary.SimpleWikiHelper.ParseException; 21 22 import android.app.PendingIntent; 23 import android.app.Service; 24 import android.appwidget.AppWidgetManager; 25 import android.appwidget.AppWidgetProvider; 26 import android.content.ComponentName; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.res.Resources; 30 import android.net.Uri; 31 import android.os.IBinder; 32 import android.text.format.Time; 33 import android.util.Log; 34 import android.widget.RemoteViews; 35 36 import java.util.regex.Matcher; 37 import java.util.regex.Pattern; 38 39 /** 40 * Define a simple widget that shows the Wiktionary "Word of the day." To build 41 * an update we spawn a background {@link Service} to perform the API queries. 42 */ 43 public class WordWidget extends AppWidgetProvider { 44 @Override 45 public void onUpdate(Context context, AppWidgetManager appWidgetManager, 46 int[] appWidgetIds) { 47 // To prevent any ANR timeouts, we perform the update in a service 48 context.startService(new Intent(context, UpdateService.class)); 49 } 50 51 public static class UpdateService extends Service { 52 @Override 53 public void onStart(Intent intent, int startId) { 54 // Build the widget update for today 55 RemoteViews updateViews = buildUpdate(this); 56 57 // Push update for this widget to the home screen 58 ComponentName thisWidget = new ComponentName(this, WordWidget.class); 59 AppWidgetManager manager = AppWidgetManager.getInstance(this); 60 manager.updateAppWidget(thisWidget, updateViews); 61 } 62 63 /** 64 * Build a widget update to show the current Wiktionary 65 * "Word of the day." Will block until the online API returns. 66 */ 67 public RemoteViews buildUpdate(Context context) { 68 // Pick out month names from resources 69 Resources res = context.getResources(); 70 String[] monthNames = res.getStringArray(R.array.month_names); 71 72 // Find current month and day 73 Time today = new Time(); 74 today.setToNow(); 75 76 // Build today's page title, like "Wiktionary:Word of the day/March 21" 77 String pageName = res.getString(R.string.template_wotd_title, 78 monthNames[today.month], today.monthDay); 79 RemoteViews updateViews = null; 80 String pageContent = ""; 81 82 try { 83 // Try querying the Wiktionary API for today's word 84 SimpleWikiHelper.prepareUserAgent(context); 85 pageContent = SimpleWikiHelper.getPageContent(pageName, false); 86 } catch (ApiException e) { 87 Log.e("WordWidget", "Couldn't contact API", e); 88 } catch (ParseException e) { 89 Log.e("WordWidget", "Couldn't parse API response", e); 90 } 91 92 // Use a regular expression to parse out the word and its definition 93 Pattern pattern = Pattern.compile(SimpleWikiHelper.WORD_OF_DAY_REGEX); 94 Matcher matcher = pattern.matcher(pageContent); 95 if (matcher.find()) { 96 // Build an update that holds the updated widget contents 97 updateViews = new RemoteViews(context.getPackageName(), R.layout.widget_word); 98 99 String wordTitle = matcher.group(1); 100 updateViews.setTextViewText(R.id.word_title, wordTitle); 101 updateViews.setTextViewText(R.id.word_type, matcher.group(2)); 102 updateViews.setTextViewText(R.id.definition, matcher.group(3).trim()); 103 104 // When user clicks on widget, launch to Wiktionary definition page 105 String definePage = res.getString(R.string.template_define_url, 106 Uri.encode(wordTitle)); 107 Intent defineIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(definePage)); 108 PendingIntent pendingIntent = PendingIntent.getActivity(context, 109 0 /* no requestCode */, defineIntent, 0 /* no flags */); 110 updateViews.setOnClickPendingIntent(R.id.widget, pendingIntent); 111 112 } else { 113 // Didn't find word of day, so show error message 114 updateViews = new RemoteViews(context.getPackageName(), R.layout.widget_message); 115 CharSequence errorMessage = context.getText(R.string.widget_error); 116 updateViews.setTextViewText(R.id.message, errorMessage); 117 } 118 return updateViews; 119 } 120 121 @Override 122 public IBinder onBind(Intent intent) { 123 // We don't need to bind to this service 124 return null; 125 } 126 } 127 } 128