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.wiktionary; 18 19 import com.example.android.wiktionary.SimpleWikiHelper.ApiException; 20 import com.example.android.wiktionary.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, int[] appWidgetIds) { 46 // To prevent any ANR timeouts, we perform the update in a service 47 context.startService(new Intent(context, UpdateService.class)); 48 } 49 50 public static class UpdateService extends Service { 51 @Override 52 public void onStart(Intent intent, int startId) { 53 // Build the widget update for today 54 RemoteViews updateViews = buildUpdate(this); 55 56 // Push update for this widget to the home screen 57 ComponentName thisWidget = new ComponentName(this, WordWidget.class); 58 AppWidgetManager manager = AppWidgetManager.getInstance(this); 59 manager.updateAppWidget(thisWidget, updateViews); 60 } 61 62 @Override 63 public IBinder onBind(Intent intent) { 64 return null; 65 } 66 67 /** 68 * Regular expression that splits "Word of the day" entry into word 69 * name, word type, and the first description bullet point. 70 */ 71 private static final String WOTD_PATTERN = 72 "(?s)\\{\\{wotd\\|(.+?)\\|(.+?)\\|([^#\\|]+).*?\\}\\}"; 73 74 /** 75 * Build a widget update to show the current Wiktionary 76 * "Word of the day." Will block until the online API returns. 77 */ 78 public RemoteViews buildUpdate(Context context) { 79 // Pick out month names from resources 80 Resources res = context.getResources(); 81 String[] monthNames = res.getStringArray(R.array.month_names); 82 83 // Find current month and day 84 Time today = new Time(); 85 today.setToNow(); 86 87 // Build the page title for today, such as "March 21" 88 String pageName = res.getString(R.string.template_wotd_title, 89 monthNames[today.month], today.monthDay); 90 String pageContent = null; 91 92 try { 93 // Try querying the Wiktionary API for today's word 94 SimpleWikiHelper.prepareUserAgent(context); 95 pageContent = SimpleWikiHelper.getPageContent(pageName, false); 96 } catch (ApiException e) { 97 Log.e("WordWidget", "Couldn't contact API", e); 98 } catch (ParseException e) { 99 Log.e("WordWidget", "Couldn't parse API response", e); 100 } 101 102 RemoteViews views = null; 103 Matcher matcher = Pattern.compile(WOTD_PATTERN).matcher(pageContent); 104 if (matcher.find()) { 105 // Build an update that holds the updated widget contents 106 views = new RemoteViews(context.getPackageName(), R.layout.widget_word); 107 108 String wordTitle = matcher.group(1); 109 views.setTextViewText(R.id.word_title, wordTitle); 110 views.setTextViewText(R.id.word_type, matcher.group(2)); 111 views.setTextViewText(R.id.definition, matcher.group(3).trim()); 112 113 // When user clicks on widget, launch to Wiktionary definition page 114 String definePage = String.format("%s://%s/%s", ExtendedWikiHelper.WIKI_AUTHORITY, 115 ExtendedWikiHelper.WIKI_LOOKUP_HOST, wordTitle); 116 Intent defineIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(definePage)); 117 PendingIntent pendingIntent = PendingIntent.getActivity(context, 118 0 /* no requestCode */, defineIntent, 0 /* no flags */); 119 views.setOnClickPendingIntent(R.id.widget, pendingIntent); 120 121 } else { 122 // Didn't find word of day, so show error message 123 views = new RemoteViews(context.getPackageName(), R.layout.widget_message); 124 views.setTextViewText(R.id.message, context.getString(R.string.widget_error)); 125 } 126 return views; 127 } 128 } 129 } 130