Importing Wikitionary/SimpleWiktionary sample code from http://code.google.com/p/wiktionary-android/.
Original code by Jeffrey Sharkey <jsharkey@android.com>.
Modifications:
- Remove .classpath, .project, and default.properties.
- Remove generated files (/gen).
- Create Android.mk and _index.html.
- Cleaned up whitespace and converted to match AOSP style guide.
- Renamed SimpleWiktionary to WiktionarySimple to keep both samples next to each other in the
directory listing.
- Removed the android:text attribute in the BulletPoint due to localization issues.
diff --git a/samples/WiktionarySimple/Android.mk b/samples/WiktionarySimple/Android.mk
new file mode 100644
index 0000000..a5a1423
--- /dev/null
+++ b/samples/WiktionarySimple/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := samples
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := WiktionarySimple
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/samples/WiktionarySimple/AndroidManifest.xml b/samples/WiktionarySimple/AndroidManifest.xml
new file mode 100644
index 0000000..c6b8724
--- /dev/null
+++ b/samples/WiktionarySimple/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.simplewiktionary"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <application android:icon="@drawable/app_icon" android:label="@string/app_name">
+
+ <!-- Broadcast Receiver that will process AppWidget updates -->
+ <receiver android:name=".WordWidget" android:label="@string/widget_name">
+ <intent-filter>
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+ </intent-filter>
+ <meta-data android:name="android.appwidget.provider"
+ android:resource="@xml/widget_word" />
+ </receiver>
+
+ <!-- Service to perform web API queries -->
+ <service android:name=".WordWidget$UpdateService" />
+
+ </application>
+
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="4" />
+
+</manifest>
diff --git a/samples/WiktionarySimple/_index.html b/samples/WiktionarySimple/_index.html
new file mode 100644
index 0000000..cf8142e
--- /dev/null
+++ b/samples/WiktionarySimple/_index.html
@@ -0,0 +1,10 @@
+<p>A sample application that demonstrates how to create an interactive widget for display on the Android home screen.</p>
+
+<p>When installed, this adds a "Wiktionary simple" option to the widget
+installation menu. The word of the day is downloaded from Wiktionary and
+displayed in a frame. Touching the widget will open a new browser session and
+load the word's Wiktionary entry.</p>
+
+<p>A more advanced version of this sample is available in the Wiktionary directory.</p>
+
+<img alt="" src="../images/wiktionary.png"/>
diff --git a/samples/WiktionarySimple/res/drawable/app_icon.png b/samples/WiktionarySimple/res/drawable/app_icon.png
new file mode 100644
index 0000000..2b1417a
--- /dev/null
+++ b/samples/WiktionarySimple/res/drawable/app_icon.png
Binary files differ
diff --git a/samples/WiktionarySimple/res/drawable/star_logo.png b/samples/WiktionarySimple/res/drawable/star_logo.png
new file mode 100644
index 0000000..b32d175
--- /dev/null
+++ b/samples/WiktionarySimple/res/drawable/star_logo.png
Binary files differ
diff --git a/samples/WiktionarySimple/res/drawable/widget_bg.xml b/samples/WiktionarySimple/res/drawable/widget_bg.xml
new file mode 100644
index 0000000..692a13d
--- /dev/null
+++ b/samples/WiktionarySimple/res/drawable/widget_bg.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- The stateful background drawable for a widget -->
+ <item android:state_window_focused="false" android:drawable="@drawable/widget_bg_normal" />
+ <item android:state_pressed="true" android:drawable="@drawable/widget_bg_pressed" />
+ <item android:state_focused="true" android:drawable="@drawable/widget_bg_selected" />
+ <item android:drawable="@drawable/widget_bg_normal" />
+</selector>
diff --git a/samples/WiktionarySimple/res/drawable/widget_bg_normal.9.png b/samples/WiktionarySimple/res/drawable/widget_bg_normal.9.png
new file mode 100644
index 0000000..314eb8e
--- /dev/null
+++ b/samples/WiktionarySimple/res/drawable/widget_bg_normal.9.png
Binary files differ
diff --git a/samples/WiktionarySimple/res/drawable/widget_bg_pressed.9.png b/samples/WiktionarySimple/res/drawable/widget_bg_pressed.9.png
new file mode 100644
index 0000000..cc23e78
--- /dev/null
+++ b/samples/WiktionarySimple/res/drawable/widget_bg_pressed.9.png
Binary files differ
diff --git a/samples/WiktionarySimple/res/drawable/widget_bg_selected.9.png b/samples/WiktionarySimple/res/drawable/widget_bg_selected.9.png
new file mode 100644
index 0000000..ef0cdc0
--- /dev/null
+++ b/samples/WiktionarySimple/res/drawable/widget_bg_selected.9.png
Binary files differ
diff --git a/samples/WiktionarySimple/res/layout/widget_message.xml b/samples/WiktionarySimple/res/layout/widget_message.xml
new file mode 100644
index 0000000..ba94714
--- /dev/null
+++ b/samples/WiktionarySimple/res/layout/widget_message.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/widget"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ style="@style/WidgetBackground">
+
+ <TextView
+ android:id="@+id/message"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="12dip"
+ android:padding="10dip"
+ android:gravity="center"
+ android:text="@string/widget_loading"
+ style="@style/Text.Loading" />
+
+</LinearLayout>
diff --git a/samples/WiktionarySimple/res/layout/widget_word.xml b/samples/WiktionarySimple/res/layout/widget_word.xml
new file mode 100644
index 0000000..0e76f0b
--- /dev/null
+++ b/samples/WiktionarySimple/res/layout/widget_word.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/widget"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ style="@style/WidgetBackground">
+
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:src="@drawable/star_logo" />
+
+ <TextView
+ android:id="@+id/word_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="14dip"
+ android:layout_marginBottom="1dip"
+ android:includeFontPadding="false"
+ android:singleLine="true"
+ android:ellipsize="end"
+ style="@style/Text.WordTitle" />
+
+ <TextView
+ android:id="@+id/word_type"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/word_title"
+ android:layout_toLeftOf="@id/icon"
+ android:layout_alignBaseline="@id/word_title"
+ android:paddingLeft="4dip"
+ android:includeFontPadding="false"
+ android:singleLine="true"
+ android:ellipsize="end"
+ style="@style/Text.WordType" />
+
+ <TextView
+ android:id="@+id/bullet"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/word_title"
+ android:paddingRight="4dip"
+ android:includeFontPadding="false"
+ android:singleLine="true"
+ style="@style/BulletPoint" />
+
+ <TextView
+ android:id="@+id/definition"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/word_title"
+ android:layout_toRightOf="@id/bullet"
+ android:paddingRight="5dip"
+ android:paddingBottom="4dip"
+ android:includeFontPadding="false"
+ android:lineSpacingMultiplier="0.9"
+ android:maxLines="4"
+ android:fadingEdge="vertical"
+ style="@style/Text.Definition" />
+
+</RelativeLayout>
diff --git a/samples/WiktionarySimple/res/values/strings.xml b/samples/WiktionarySimple/res/values/strings.xml
new file mode 100644
index 0000000..65e44cb
--- /dev/null
+++ b/samples/WiktionarySimple/res/values/strings.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <string name="app_name">Wiktionary simple example</string>
+
+ <string name="template_user_agent">"%s/%s (Linux; Android)"</string>
+ <string name="template_wotd_title">"Wiktionary:Word of the day/%s %s"</string>
+ <string name="template_define_url">"http://en.wiktionary.org/wiki/%s"</string>
+
+ <string name="widget_name">Wiktionary simple</string>
+
+ <string name="widget_loading">Loading word\nof day\u2026</string>
+ <string name="widget_error">No word of\nday found</string>
+
+ <string-array name="month_names">
+ <item>January</item>
+ <item>February</item>
+ <item>March</item>
+ <item>April</item>
+ <item>May</item>
+ <item>June</item>
+ <item>July</item>
+ <item>August</item>
+ <item>September</item>
+ <item>October</item>
+ <item>November</item>
+ <item>December</item>
+ </string-array>
+
+</resources>
diff --git a/samples/WiktionarySimple/res/values/styles.xml b/samples/WiktionarySimple/res/values/styles.xml
new file mode 100644
index 0000000..42d679c
--- /dev/null
+++ b/samples/WiktionarySimple/res/values/styles.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+
+ <style name="WidgetBackground">
+ <item name="android:background">@drawable/widget_bg</item>
+ </style>
+
+ <style name="BulletPoint">
+ <item name="android:textSize">13sp</item>
+ <item name="android:textColor">@android:color/black</item>
+ </style>
+
+ <style name="Text" />
+
+ <style name="Text.Loading">
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">@android:color/black</item>
+ </style>
+
+ <style name="Text.WordTitle">
+ <item name="android:textSize">16sp</item>
+ <item name="android:textStyle">bold</item>
+ <item name="android:textColor">@android:color/black</item>
+ </style>
+
+ <style name="Text.WordType">
+ <item name="android:textSize">14sp</item>
+ <item name="android:textStyle">italic</item>
+ <item name="android:textColor">@android:color/black</item>
+ </style>
+
+ <style name="Text.Definition">
+ <item name="android:textSize">13sp</item>
+ <item name="android:textColor">@android:color/black</item>
+ </style>
+
+</resources>
diff --git a/samples/WiktionarySimple/res/xml/widget_word.xml b/samples/WiktionarySimple/res/xml/widget_word.xml
new file mode 100644
index 0000000..46d31c3
--- /dev/null
+++ b/samples/WiktionarySimple/res/xml/widget_word.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
+ android:minWidth="146dip"
+ android:minHeight="72dip"
+ android:updatePeriodMillis="86400000"
+ android:initialLayout="@layout/widget_message" />
diff --git a/samples/WiktionarySimple/src/com/example/android/simplewiktionary/SimpleWikiHelper.java b/samples/WiktionarySimple/src/com/example/android/simplewiktionary/SimpleWikiHelper.java
new file mode 100644
index 0000000..bb39d7b
--- /dev/null
+++ b/samples/WiktionarySimple/src/com/example/android/simplewiktionary/SimpleWikiHelper.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.simplewiktionary;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.StatusLine;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.net.Uri;
+import android.util.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Helper methods to simplify talking with and parsing responses from a
+ * lightweight Wiktionary API. Before making any requests, you should call
+ * {@link #prepareUserAgent(Context)} to generate a User-Agent string based on
+ * your application package name and version.
+ */
+public class SimpleWikiHelper {
+ private static final String TAG = "SimpleWikiHelper";
+
+ /**
+ * Regular expression that splits "Word of the day" entry into word
+ * name, word type, and the first description bullet point.
+ */
+ public static final String WORD_OF_DAY_REGEX =
+ "(?s)\\{\\{wotd\\|(.+?)\\|(.+?)\\|([^#\\|]+).*?\\}\\}";
+
+ /**
+ * Partial URL to use when requesting the detailed entry for a specific
+ * Wiktionary page. Use {@link String#format(String, Object...)} to insert
+ * the desired page title after escaping it as needed.
+ */
+ private static final String WIKTIONARY_PAGE =
+ "http://en.wiktionary.org/w/api.php?action=query&prop=revisions&titles=%s&" +
+ "rvprop=content&format=json%s";
+
+ /**
+ * Partial URL to append to {@link #WIKTIONARY_PAGE} when you want to expand
+ * any templates found on the requested page. This is useful when browsing
+ * full entries, but may use more network bandwidth.
+ */
+ private static final String WIKTIONARY_EXPAND_TEMPLATES =
+ "&rvexpandtemplates=true";
+
+ /**
+ * {@link StatusLine} HTTP status code when no server error has occurred.
+ */
+ private static final int HTTP_STATUS_OK = 200;
+
+ /**
+ * Shared buffer used by {@link #getUrlContent(String)} when reading results
+ * from an API request.
+ */
+ private static byte[] sBuffer = new byte[512];
+
+ /**
+ * User-agent string to use when making requests. Should be filled using
+ * {@link #prepareUserAgent(Context)} before making any other calls.
+ */
+ private static String sUserAgent = null;
+
+ /**
+ * Thrown when there were problems contacting the remote API server, either
+ * because of a network error, or the server returned a bad status code.
+ */
+ public static class ApiException extends Exception {
+ public ApiException(String detailMessage, Throwable throwable) {
+ super(detailMessage, throwable);
+ }
+
+ public ApiException(String detailMessage) {
+ super(detailMessage);
+ }
+ }
+
+ /**
+ * Thrown when there were problems parsing the response to an API call,
+ * either because the response was empty, or it was malformed.
+ */
+ public static class ParseException extends Exception {
+ public ParseException(String detailMessage, Throwable throwable) {
+ super(detailMessage, throwable);
+ }
+ }
+
+ /**
+ * Prepare the internal User-Agent string for use. This requires a
+ * {@link Context} to pull the package name and version number for this
+ * application.
+ */
+ public static void prepareUserAgent(Context context) {
+ try {
+ // Read package name and version number from manifest
+ PackageManager manager = context.getPackageManager();
+ PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0);
+ sUserAgent = String.format(context.getString(R.string.template_user_agent),
+ info.packageName, info.versionName);
+
+ } catch(NameNotFoundException e) {
+ Log.e(TAG, "Couldn't find package information in PackageManager", e);
+ }
+ }
+
+ /**
+ * Read and return the content for a specific Wiktionary page. This makes a
+ * lightweight API call, and trims out just the page content returned.
+ * Because this call blocks until results are available, it should not be
+ * run from a UI thread.
+ *
+ * @param title The exact title of the Wiktionary page requested.
+ * @param expandTemplates If true, expand any wiki templates found.
+ * @return Exact content of page.
+ * @throws ApiException If any connection or server error occurs.
+ * @throws ParseException If there are problems parsing the response.
+ */
+ public static String getPageContent(String title, boolean expandTemplates)
+ throws ApiException, ParseException {
+ // Encode page title and expand templates if requested
+ String encodedTitle = Uri.encode(title);
+ String expandClause = expandTemplates ? WIKTIONARY_EXPAND_TEMPLATES : "";
+
+ // Query the API for content
+ String content = getUrlContent(String.format(WIKTIONARY_PAGE,
+ encodedTitle, expandClause));
+ try {
+ // Drill into the JSON response to find the content body
+ JSONObject response = new JSONObject(content);
+ JSONObject query = response.getJSONObject("query");
+ JSONObject pages = query.getJSONObject("pages");
+ JSONObject page = pages.getJSONObject((String) pages.keys().next());
+ JSONArray revisions = page.getJSONArray("revisions");
+ JSONObject revision = revisions.getJSONObject(0);
+ return revision.getString("*");
+ } catch (JSONException e) {
+ throw new ParseException("Problem parsing API response", e);
+ }
+ }
+
+ /**
+ * Pull the raw text content of the given URL. This call blocks until the
+ * operation has completed, and is synchronized because it uses a shared
+ * buffer {@link #sBuffer}.
+ *
+ * @param url The exact URL to request.
+ * @return The raw content returned by the server.
+ * @throws ApiException If any connection or server error occurs.
+ */
+ protected static synchronized String getUrlContent(String url) throws ApiException {
+ if (sUserAgent == null) {
+ throw new ApiException("User-Agent string must be prepared");
+ }
+
+ // Create client and set our specific user-agent string
+ HttpClient client = new DefaultHttpClient();
+ HttpGet request = new HttpGet(url);
+ request.setHeader("User-Agent", sUserAgent);
+
+ try {
+ HttpResponse response = client.execute(request);
+
+ // Check if server response is valid
+ StatusLine status = response.getStatusLine();
+ if (status.getStatusCode() != HTTP_STATUS_OK) {
+ throw new ApiException("Invalid response from server: " +
+ status.toString());
+ }
+
+ // Pull content stream from response
+ HttpEntity entity = response.getEntity();
+ InputStream inputStream = entity.getContent();
+
+ ByteArrayOutputStream content = new ByteArrayOutputStream();
+
+ // Read response into a buffered stream
+ int readBytes = 0;
+ while ((readBytes = inputStream.read(sBuffer)) != -1) {
+ content.write(sBuffer, 0, readBytes);
+ }
+
+ // Return result from buffered stream
+ return new String(content.toByteArray());
+ } catch (IOException e) {
+ throw new ApiException("Problem communicating with API", e);
+ }
+ }
+}
diff --git a/samples/WiktionarySimple/src/com/example/android/simplewiktionary/WordWidget.java b/samples/WiktionarySimple/src/com/example/android/simplewiktionary/WordWidget.java
new file mode 100644
index 0000000..d005faa
--- /dev/null
+++ b/samples/WiktionarySimple/src/com/example/android/simplewiktionary/WordWidget.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.simplewiktionary;
+
+import com.example.android.simplewiktionary.SimpleWikiHelper.ApiException;
+import com.example.android.simplewiktionary.SimpleWikiHelper.ParseException;
+
+import android.app.PendingIntent;
+import android.app.Service;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProvider;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.os.IBinder;
+import android.text.format.Time;
+import android.util.Log;
+import android.widget.RemoteViews;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Define a simple widget that shows the Wiktionary "Word of the day." To build
+ * an update we spawn a background {@link Service} to perform the API queries.
+ */
+public class WordWidget extends AppWidgetProvider {
+ @Override
+ public void onUpdate(Context context, AppWidgetManager appWidgetManager,
+ int[] appWidgetIds) {
+ // To prevent any ANR timeouts, we perform the update in a service
+ context.startService(new Intent(context, UpdateService.class));
+ }
+
+ public static class UpdateService extends Service {
+ @Override
+ public void onStart(Intent intent, int startId) {
+ // Build the widget update for today
+ RemoteViews updateViews = buildUpdate(this);
+
+ // Push update for this widget to the home screen
+ ComponentName thisWidget = new ComponentName(this, WordWidget.class);
+ AppWidgetManager manager = AppWidgetManager.getInstance(this);
+ manager.updateAppWidget(thisWidget, updateViews);
+ }
+
+ /**
+ * Build a widget update to show the current Wiktionary
+ * "Word of the day." Will block until the online API returns.
+ */
+ public RemoteViews buildUpdate(Context context) {
+ // Pick out month names from resources
+ Resources res = context.getResources();
+ String[] monthNames = res.getStringArray(R.array.month_names);
+
+ // Find current month and day
+ Time today = new Time();
+ today.setToNow();
+
+ // Build today's page title, like "Wiktionary:Word of the day/March 21"
+ String pageName = res.getString(R.string.template_wotd_title,
+ monthNames[today.month], today.monthDay);
+ RemoteViews updateViews = null;
+ String pageContent = "";
+
+ try {
+ // Try querying the Wiktionary API for today's word
+ SimpleWikiHelper.prepareUserAgent(context);
+ pageContent = SimpleWikiHelper.getPageContent(pageName, false);
+ } catch (ApiException e) {
+ Log.e("WordWidget", "Couldn't contact API", e);
+ } catch (ParseException e) {
+ Log.e("WordWidget", "Couldn't parse API response", e);
+ }
+
+ // Use a regular expression to parse out the word and its definition
+ Pattern pattern = Pattern.compile(SimpleWikiHelper.WORD_OF_DAY_REGEX);
+ Matcher matcher = pattern.matcher(pageContent);
+ if (matcher.find()) {
+ // Build an update that holds the updated widget contents
+ updateViews = new RemoteViews(context.getPackageName(), R.layout.widget_word);
+
+ String wordTitle = matcher.group(1);
+ updateViews.setTextViewText(R.id.word_title, wordTitle);
+ updateViews.setTextViewText(R.id.word_type, matcher.group(2));
+ updateViews.setTextViewText(R.id.definition, matcher.group(3).trim());
+
+ // When user clicks on widget, launch to Wiktionary definition page
+ String definePage = res.getString(R.string.template_define_url,
+ Uri.encode(wordTitle));
+ Intent defineIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(definePage));
+ PendingIntent pendingIntent = PendingIntent.getActivity(context,
+ 0 /* no requestCode */, defineIntent, 0 /* no flags */);
+ updateViews.setOnClickPendingIntent(R.id.widget, pendingIntent);
+
+ } else {
+ // Didn't find word of day, so show error message
+ updateViews = new RemoteViews(context.getPackageName(), R.layout.widget_message);
+ CharSequence errorMessage = context.getText(R.string.widget_error);
+ updateViews.setTextViewText(R.id.message, errorMessage);
+ }
+ return updateViews;
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ // We don't need to bind to this service
+ return null;
+ }
+ }
+}