summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AndroidManifest.xml7
-rw-r--r--res/raw/most_visited.ktpl85
-rw-r--r--res/values-xlarge/dimensions.xml5
-rw-r--r--res/values/dimensions.xml5
-rw-r--r--res/values/strings.xml5
-rw-r--r--res/xml/lab_preferences.xml6
-rw-r--r--src/com/android/browser/BrowserSettings.java13
-rw-r--r--src/com/android/browser/Tab.java4
-rw-r--r--src/com/android/browser/homepages/HomeProvider.java81
-rw-r--r--src/com/android/browser/homepages/RequestHandler.java145
-rw-r--r--src/com/android/browser/homepages/Template.java279
11 files changed, 635 insertions, 0 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 5b844e0..9ceaf82 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -223,6 +223,13 @@
<action android:name="android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED"/>
</intent-filter>
</receiver>
+
+ <!-- For custom home pages (like most visited) -->
+ <provider
+ android:name=".homepages.HomeProvider"
+ android:authorities="com.android.browser.home"
+ android:readPermission="com.android.browser.permission.READ_HISTORY_BOOKMARKS"
+ android:exported="false" />
</application>
</manifest>
diff --git a/res/raw/most_visited.ktpl b/res/raw/most_visited.ktpl
new file mode 100644
index 0000000..04b9eee
--- /dev/null
+++ b/res/raw/most_visited.ktpl
@@ -0,0 +1,85 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html>
+<head>
+<title><%@ string/new_tab %></title>
+<meta name="viewport" content="width=device-width; initial-scale=1.0;" />
+
+<style type="text/css">
+
+* {
+ padding: 0;
+ margin: 0;
+}
+
+body {
+ text-align: center;
+ margin: 16px auto;
+ padding: 0 8px 0 8px;
+ max-width: <%@ dimen/mv_max_width %>px;
+}
+
+#most_visited h3 {
+ text-align: center;
+ padding: 0;
+ margin: 5px 0 5px 0px;
+}
+
+.thumbwrap li {
+ display: inline-block;
+ margin: 0 7px 15px 7px;
+ padding: 0;
+}
+
+@media all and (orientation:portrait) {
+.thumbwrap li {
+ width: <%@ dimen/mv_item_width_portrait %>px;
+}
+}
+
+@media all and (orientation:landscape) {
+.thumbwrap li {
+ width: <%@ dimen/mv_item_width %>px;
+}
+}
+
+.thumbwrap a {
+ display: block;
+ text-decoration: none;
+ color: #000;
+}
+
+.thumbwrap img {
+ border: <%@ dimen/mv_border_width %>px solid #e0e0e0;
+ border-radius: 5px;
+ width: 100%;
+}
+
+.thumbwrap .caption {
+ margin-top: 2px;
+ margin-left: 4px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ display: block;
+ font-size: .8em;
+ text-align: left;
+}
+
+</style>
+
+</head>
+<body>
+ <h3><%@ string/tab_most_visited %></h3>
+ <ul class="thumbwrap">
+ <%{ most_visited %>
+ <li>
+ <a href="<%= url %>">
+ <img class="wrimg" src="<%= thumbnail %>" />
+ <span class="caption"><%= title %></span>
+ </a>
+ </li>
+ <%} most_visited %>
+ </ul>
+</body>
+</html>
diff --git a/res/values-xlarge/dimensions.xml b/res/values-xlarge/dimensions.xml
index 5b86c86..9f5a602 100644
--- a/res/values-xlarge/dimensions.xml
+++ b/res/values-xlarge/dimensions.xml
@@ -14,4 +14,9 @@
<dimen name="bookmarkThumbnailWidth">180dip</dimen>
<dimen name="bookmarkThumbnailHeight">120dip</dimen>
<dimen name="favicon_padded_size">24dip</dimen>
+ <!-- For the most visited page -->
+ <dimen name="mv_max_width">1010dp</dimen>
+ <dimen name="mv_item_width">231dp</dimen>
+ <dimen name="mv_item_width_portrait">213dp</dimen>
+ <dimen name="mv_border_width">3dp</dimen>
</resources>
diff --git a/res/values/dimensions.xml b/res/values/dimensions.xml
index 03127dd..d50ce13 100644
--- a/res/values/dimensions.xml
+++ b/res/values/dimensions.xml
@@ -33,4 +33,9 @@
<dimen name="qc_slop">15dip</dimen>
<dimen name="bookmark_widget_thumb_size">32dip</dimen>
<dimen name="bookmark_widget_favicon_size">26dip</dimen>
+ <!-- For the most visited page -->
+ <dimen name="mv_max_width">830dp</dimen>
+ <dimen name="mv_item_width">96dp</dimen>
+ <dimen name="mv_item_width_portrait">96dp</dimen>
+ <dimen name="mv_border_width">3dp</dimen>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index b8a45bf..9c12dc3 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -609,6 +609,11 @@
<!-- Summary for lab quick controls feature [CHAR LIMIT=80] -->
<string name="pref_lab_quick_controls_summary">
Swipe thumb from left or right edge to access quick controls</string>
+ <!-- Title for lab "Most Visited" homepage feature [CHAR LIMIT=40] -->
+ <string name="pref_lab_most_visited_homepage">Most Visited Homepage</string>
+ <!-- Summary for lab "Most Visited" homepage feature [CHAR LIMIT=80] -->
+ <string name="pref_lab_most_visited_homepage_summary">
+ Sets your homepage to show the most visited pages.</string>
<!-- Title for a dialog displayed when the browser has a data connectivity
problem -->
<string name="browserFrameNetworkErrorLabel">Data connectivity problem</string>
diff --git a/res/xml/lab_preferences.xml b/res/xml/lab_preferences.xml
index 2168471..16a5169 100644
--- a/res/xml/lab_preferences.xml
+++ b/res/xml/lab_preferences.xml
@@ -23,4 +23,10 @@
android:title="@string/pref_lab_quick_controls"
android:summary="@string/pref_lab_quick_controls_summary" />
+ <CheckBoxPreference
+ android:key="use_most_visited_homepage"
+ android:defaultValue="false"
+ android:title="@string/pref_lab_most_visited_homepage"
+ android:summary="@string/pref_lab_most_visited_homepage_summary" />
+
</PreferenceScreen>
diff --git a/src/com/android/browser/BrowserSettings.java b/src/com/android/browser/BrowserSettings.java
index 267056e..ca8091f 100644
--- a/src/com/android/browser/BrowserSettings.java
+++ b/src/com/android/browser/BrowserSettings.java
@@ -17,6 +17,7 @@
package com.android.browser;
+import com.android.browser.homepages.HomeProvider;
import com.android.browser.search.SearchEngine;
import com.android.browser.search.SearchEngines;
@@ -119,6 +120,7 @@ public class BrowserSettings extends Observable implements OnSharedPreferenceCha
// Lab settings
private boolean quickControls = false;
+ private boolean useMostVisitedHomepage = false;
// By default the error console is shown once the user navigates to about:debug.
// The setting can be then toggled from the settings menu.
@@ -171,6 +173,7 @@ public class BrowserSettings extends Observable implements OnSharedPreferenceCha
public final static String PREF_USER_AGENT = "user_agent";
public final static String PREF_QUICK_CONTROLS = "enable_quick_controls";
+ public final static String PREF_MOST_VISITED_HOMEPAGE = "use_most_visited_homepage";
private static final String DESKTOP_USERAGENT = "Mozilla/5.0 (Macintosh; " +
"U; Intel Mac OS X 10_6_3; en-us) AppleWebKit/533.16 (KHTML, " +
@@ -496,6 +499,7 @@ public class BrowserSettings extends Observable implements OnSharedPreferenceCha
}
quickControls = p.getBoolean(PREF_QUICK_CONTROLS, quickControls);
+ useMostVisitedHomepage = p.getBoolean(PREF_MOST_VISITED_HOMEPAGE, useMostVisitedHomepage);
// Only set these on startup if it is a dev build
if (DEV_BUILD) {
@@ -525,6 +529,9 @@ public class BrowserSettings extends Observable implements OnSharedPreferenceCha
}
public String getHomePage() {
+ if (useMostVisitedHomepage) {
+ return HomeProvider.MOST_VISITED;
+ }
return homeUrl;
}
@@ -584,6 +591,10 @@ public class BrowserSettings extends Observable implements OnSharedPreferenceCha
return quickControls;
}
+ public boolean useMostVisitedHomepage() {
+ return useMostVisitedHomepage;
+ }
+
public boolean showDebugSettings() {
return showDebugSettings;
}
@@ -847,6 +858,8 @@ public class BrowserSettings extends Observable implements OnSharedPreferenceCha
update();
} else if (PREF_QUICK_CONTROLS.equals(key)) {
quickControls = p.getBoolean(PREF_QUICK_CONTROLS, quickControls);
+ } else if (PREF_MOST_VISITED_HOMEPAGE.equals(key)) {
+ useMostVisitedHomepage = p.getBoolean(PREF_MOST_VISITED_HOMEPAGE, useMostVisitedHomepage);
}
}
}
diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java
index 320d3b3..5ef7564 100644
--- a/src/com/android/browser/Tab.java
+++ b/src/com/android/browser/Tab.java
@@ -16,6 +16,7 @@
package com.android.browser;
+import com.android.browser.homepages.HomeProvider;
import com.android.common.speech.LoggingEvents;
import android.app.Activity;
@@ -1568,6 +1569,9 @@ class Tab {
}
String getUrl() {
+ if (HomeProvider.MOST_VISITED.equals(mCurrentState.mUrl)) {
+ return "";
+ }
return mCurrentState.mUrl;
}
diff --git a/src/com/android/browser/homepages/HomeProvider.java b/src/com/android/browser/homepages/HomeProvider.java
new file mode 100644
index 0000000..5c368eb
--- /dev/null
+++ b/src/com/android/browser/homepages/HomeProvider.java
@@ -0,0 +1,81 @@
+
+/*
+ * Copyright (C) 2011 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.android.browser.homepages;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.res.AssetFileDescriptor;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.IOException;
+
+public class HomeProvider extends ContentProvider {
+
+ private static final String TAG = "HomeProvider";
+ public static final String AUTHORITY = "com.android.browser.home";
+ public static final String MOST_VISITED = "content://" + AUTHORITY + "/";
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return null;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public boolean onCreate() {
+ return false;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+ return null;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection,
+ String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public ParcelFileDescriptor openFile(Uri uri, String mode) {
+ try {
+ ParcelFileDescriptor[] pipes = ParcelFileDescriptor.createPipe();
+ final ParcelFileDescriptor write = pipes[1];
+ AssetFileDescriptor afd = new AssetFileDescriptor(write, 0, -1);
+ new RequestHandler(getContext(), uri, afd.createOutputStream()).start();
+ return pipes[0];
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to handle request: " + uri, e);
+ return null;
+ }
+ }
+
+}
diff --git a/src/com/android/browser/homepages/RequestHandler.java b/src/com/android/browser/homepages/RequestHandler.java
new file mode 100644
index 0000000..a53fb52
--- /dev/null
+++ b/src/com/android/browser/homepages/RequestHandler.java
@@ -0,0 +1,145 @@
+
+/*
+ * Copyright (C) 2011 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.android.browser.homepages;
+
+import com.android.browser.R;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import android.content.Context;
+import android.content.UriMatcher;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.Browser;
+import android.util.Base64;
+import android.util.Log;
+
+public class RequestHandler extends Thread {
+
+ private static final String TAG = "RequestHandler";
+ private static final int INDEX = 1;
+ private static final int RESOURCE = 2;
+ private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+
+ Uri mUri;
+ Context mContext;
+ OutputStream mOutput;
+
+ static {
+ sUriMatcher.addURI(HomeProvider.AUTHORITY, "/", INDEX);
+ sUriMatcher.addURI(HomeProvider.AUTHORITY, "res/*/*", RESOURCE);
+ }
+
+ public RequestHandler(Context context, Uri uri, OutputStream out) {
+ mUri = uri;
+ mContext = context;
+ mOutput = out;
+ }
+
+ @Override
+ public void run() {
+ super.run();
+ try {
+ doHandleRequest();
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to handle request: " + mUri, e);
+ } finally {
+ cleanup();
+ }
+ }
+
+ void doHandleRequest() throws IOException {
+ int match = sUriMatcher.match(mUri);
+ switch (match) {
+ case INDEX:
+ writeTemplatedIndex();
+ break;
+ case RESOURCE:
+ writeResource(getUriResourcePath());
+ break;
+ }
+ }
+
+ void writeTemplatedIndex() throws IOException {
+ Template t = Template.getCachedTemplate(mContext, R.raw.most_visited);
+ Cursor cursor = mContext.getContentResolver().query(Browser.BOOKMARKS_URI,
+ new String[] { "DISTINCT url", "title", "thumbnail" },
+ "(visits > 0 OR bookmark = 1) AND url NOT LIKE 'content:%' AND thumbnail IS NOT NULL", null, "visits DESC LIMIT 12");
+
+ t.assignLoop("most_visited", new Template.CursorListEntityWrapper(cursor) {
+ @Override
+ public void writeValue(OutputStream stream, String key) throws IOException {
+ Cursor cursor = getCursor();
+ if (key.equals("url")) {
+ stream.write(cursor.getString(0).getBytes());
+ } else if (key.equals("title")) {
+ stream.write(cursor.getString(1).getBytes());
+ } else if (key.equals("thumbnail")) {
+ stream.write("data:image/png;base64,".getBytes());
+ byte[] thumb = cursor.getBlob(2);
+ stream.write(Base64.encode(thumb, Base64.DEFAULT));
+ }
+ }
+ });
+ t.write(mOutput);
+ }
+
+ String getUriResourcePath() {
+ final Pattern pattern = Pattern.compile("/?res/([\\w/]+)");
+ Matcher m = pattern.matcher(mUri.getPath());
+ if (m.matches()) {
+ return m.group(1);
+ } else {
+ return mUri.getPath();
+ }
+ }
+
+ void writeResource(String fileName) throws IOException {
+ Resources res = mContext.getResources();
+ int id = res.getIdentifier(fileName, null, mContext.getPackageName());
+ if (id != 0) {
+ InputStream in = res.openRawResource(id);
+ byte[] buf = new byte[4096];
+ int read;
+ while ((read = in.read(buf)) > 0) {
+ mOutput.write(buf, 0, read);
+ }
+ }
+ }
+
+ void writeString(String str) throws IOException {
+ mOutput.write(str.getBytes());
+ }
+
+ void writeString(String str, int offset, int count) throws IOException {
+ mOutput.write(str.getBytes(), offset, count);
+ }
+
+ void cleanup() {
+ try {
+ mOutput.close();
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to close pipe!", e);
+ }
+ }
+
+}
diff --git a/src/com/android/browser/homepages/Template.java b/src/com/android/browser/homepages/Template.java
new file mode 100644
index 0000000..c1a6b0e
--- /dev/null
+++ b/src/com/android/browser/homepages/Template.java
@@ -0,0 +1,279 @@
+
+/*
+ * Copyright (C) 2011 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.android.browser.homepages;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.util.TypedValue;
+
+public class Template {
+
+ private static HashMap<Integer, Template> sCachedTemplates = new HashMap<Integer, Template>();
+
+ public static Template getCachedTemplate(Context context, int id) {
+ synchronized (sCachedTemplates) {
+ Template template = sCachedTemplates.get(id);
+ if (template == null) {
+ template = new Template(context, id);
+ sCachedTemplates.put(id, template);
+ }
+ // Return a copy so that we don't share data
+ return template.copy();
+ }
+ }
+
+ interface Entity {
+ void write(OutputStream stream, EntityData params) throws IOException;
+ }
+
+ interface EntityData {
+ void writeValue(OutputStream stream, String key) throws IOException;
+ ListEntityIterator getListIterator(String key);
+ }
+
+ interface ListEntityIterator extends EntityData {
+ void reset();
+ boolean moveToNext();
+ }
+
+ static class StringEntity implements Entity {
+
+ byte[] mValue;
+
+ public StringEntity(String value) {
+ mValue = value.getBytes();
+ }
+
+ @Override
+ public void write(OutputStream stream, EntityData params) throws IOException {
+ stream.write(mValue);
+ }
+
+ }
+
+ static class SimpleEntity implements Entity {
+
+ String mKey;
+
+ public SimpleEntity(String key) {
+ mKey = key;
+ }
+
+ @Override
+ public void write(OutputStream stream, EntityData params) throws IOException {
+ params.writeValue(stream, mKey);
+ }
+
+ }
+
+ static class ListEntity implements Entity {
+
+ String mKey;
+ Template mSubTemplate;
+
+ public ListEntity(Context context, String key, String subTemplate) {
+ mKey = key;
+ mSubTemplate = new Template(context, subTemplate);
+ }
+
+ @Override
+ public void write(OutputStream stream, EntityData params) throws IOException {
+ ListEntityIterator iter = params.getListIterator(mKey);
+ iter.reset();
+ while (iter.moveToNext()) {
+ mSubTemplate.write(stream, iter);
+ }
+ }
+
+ }
+
+ public abstract static class CursorListEntityWrapper implements ListEntityIterator {
+
+ private Cursor mCursor;
+
+ public CursorListEntityWrapper(Cursor cursor) {
+ mCursor = cursor;
+ }
+
+ @Override
+ public boolean moveToNext() {
+ return mCursor.moveToNext();
+ }
+
+ @Override
+ public void reset() {
+ mCursor.moveToPosition(-1);
+ }
+
+ @Override
+ public ListEntityIterator getListIterator(String key) {
+ return null;
+ }
+
+ public Cursor getCursor() {
+ return mCursor;
+ }
+
+ }
+
+ static class HashMapEntityData implements EntityData {
+
+ HashMap<String, Object> mData;
+
+ public HashMapEntityData(HashMap<String, Object> map) {
+ mData = map;
+ }
+
+ @Override
+ public ListEntityIterator getListIterator(String key) {
+ return (ListEntityIterator) mData.get(key);
+ }
+
+ @Override
+ public void writeValue(OutputStream stream, String key) throws IOException {
+ stream.write((byte[]) mData.get(key));
+ }
+
+ }
+
+ private List<Entity> mTemplate;
+ private HashMap<String, Object> mData = new HashMap<String, Object>();
+ private Template(Context context, int tid) {
+ this(context, readRaw(context, tid));
+ }
+
+ private Template(Context context, String template) {
+ mTemplate = new ArrayList<Entity>();
+ template = replaceConsts(context, template);
+ parseTemplate(context, template);
+ }
+
+ private Template(Template copy) {
+ mTemplate = copy.mTemplate;
+ }
+
+ Template copy() {
+ return new Template(this);
+ }
+
+ void parseTemplate(Context context, String template) {
+ final Pattern pattern = Pattern.compile("<%([=\\{])\\s*(\\w+)\\s*%>");
+ Matcher m = pattern.matcher(template);
+ int start = 0;
+ while (m.find()) {
+ String static_part = template.substring(start, m.start());
+ if (static_part.length() > 0) {
+ mTemplate.add(new StringEntity(static_part));
+ }
+ String type = m.group(1);
+ String name = m.group(2);
+ if (type.equals("=")) {
+ mTemplate.add(new SimpleEntity(name));
+ } else if (type.equals("{")) {
+ Pattern p = Pattern.compile("<%\\}\\s*" + Pattern.quote(name) + "\\s*%>");
+ Matcher end_m = p.matcher(template);
+ if (end_m.find(m.end())) {
+ start = m.end();
+ m.region(end_m.end(), template.length());
+ String subTemplate = template.substring(start, end_m.start());
+ mTemplate.add(new ListEntity(context, name, subTemplate));
+ start = end_m.end();
+ continue;
+ }
+ }
+ start = m.end();
+ }
+ String static_part = template.substring(start, template.length());
+ if (static_part.length() > 0) {
+ mTemplate.add(new StringEntity(static_part));
+ }
+ }
+
+ public void assign(String name, String value) {
+ mData.put(name, value.getBytes());
+ }
+
+ public void assignLoop(String name, ListEntityIterator iter) {
+ mData.put(name, iter);
+ }
+
+ public void write(OutputStream stream) throws IOException {
+ write(stream, new HashMapEntityData(mData));
+ }
+
+ public void write(OutputStream stream, EntityData data) throws IOException {
+ for (Entity ent : mTemplate) {
+ ent.write(stream, data);
+ }
+ }
+
+ private static String replaceConsts(Context context, String template) {
+ final Pattern pattern = Pattern.compile("<%@\\s*(\\w+/\\w+)\\s*%>");
+ final Resources res = context.getResources();
+ final String packageName = context.getPackageName();
+ Matcher m = pattern.matcher(template);
+ StringBuffer sb = new StringBuffer();
+ while (m.find()) {
+ String name = m.group(1);
+ if (name.startsWith("drawable/")) {
+ m.appendReplacement(sb, "res/" + name);
+ } else {
+ int id = res.getIdentifier(name, null, packageName);
+ if (id != 0) {
+ TypedValue value = new TypedValue();
+ res.getValue(id, value, true);
+ String replacement;
+ if (value.type == TypedValue.TYPE_DIMENSION) {
+ float dimen = res.getDimension(id);
+ int dimeni = (int) dimen;
+ if (dimeni == dimen)
+ replacement = Integer.toString(dimeni);
+ else
+ replacement = Float.toString(dimen);
+ } else {
+ replacement = value.coerceToString().toString();
+ }
+ m.appendReplacement(sb, replacement);
+ }
+ }
+ }
+ m.appendTail(sb);
+ return sb.toString();
+ }
+
+ private static String readRaw(Context context, int id) {
+ InputStream ins = context.getResources().openRawResource(id);
+ try {
+ byte[] buf = new byte[ins.available()];
+ ins.read(buf);
+ return new String(buf, "utf-8");
+ } catch (IOException ex) {
+ return "<html><body>Error</body></html>";
+ }
+ }
+
+}