1bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
2bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck/*
3bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck * Copyright (C) 2011 The Android Open Source Project
4bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck *
5bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck * Licensed under the Apache License, Version 2.0 (the "License");
6bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck * you may not use this file except in compliance with the License.
7bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck * You may obtain a copy of the License at
8bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck *
9bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck *      http://www.apache.org/licenses/LICENSE-2.0
10bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck *
11bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck * Unless required by applicable law or agreed to in writing, software
12bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck * distributed under the License is distributed on an "AS IS" BASIS,
13bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck * See the License for the specific language governing permissions and
15bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck * limitations under the License.
16bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck */
17bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reckpackage com.android.browser.homepages;
18bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
19bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reckimport java.io.IOException;
20bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reckimport java.io.InputStream;
21bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reckimport java.io.OutputStream;
22bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reckimport java.util.ArrayList;
23bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reckimport java.util.HashMap;
24bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reckimport java.util.List;
25bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reckimport java.util.regex.Matcher;
26bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reckimport java.util.regex.Pattern;
27bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
28bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reckimport android.content.Context;
29bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reckimport android.content.res.Resources;
30bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reckimport android.database.Cursor;
31bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reckimport android.util.TypedValue;
32bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
331b7d2b95670a6c94cb29e0f4b965cebdf6f65bdaJohn Reckimport com.android.browser.R;
341b7d2b95670a6c94cb29e0f4b965cebdf6f65bdaJohn Reck
35bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reckpublic class Template {
36bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
37bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    private static HashMap<Integer, Template> sCachedTemplates = new HashMap<Integer, Template>();
38bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
39bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    public static Template getCachedTemplate(Context context, int id) {
40bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        synchronized (sCachedTemplates) {
41bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            Template template = sCachedTemplates.get(id);
42bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            if (template == null) {
43bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                template = new Template(context, id);
44bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                sCachedTemplates.put(id, template);
45bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            }
46bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            // Return a copy so that we don't share data
47bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            return template.copy();
48bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        }
49bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    }
50bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
51bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    interface Entity {
52bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        void write(OutputStream stream, EntityData params) throws IOException;
53bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    }
54bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
55bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    interface EntityData {
56bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        void writeValue(OutputStream stream, String key) throws IOException;
57bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        ListEntityIterator getListIterator(String key);
58bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    }
59bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
60bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    interface ListEntityIterator extends EntityData {
61bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        void reset();
62bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        boolean moveToNext();
63bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    }
64bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
65bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    static class StringEntity implements Entity {
66bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
67bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        byte[] mValue;
68bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
69bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        public StringEntity(String value) {
70bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            mValue = value.getBytes();
71bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        }
72bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
73bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        @Override
74bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        public void write(OutputStream stream, EntityData params) throws IOException {
75bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            stream.write(mValue);
76bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        }
77bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
78bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    }
79bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
80bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    static class SimpleEntity implements Entity {
81bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
82bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        String mKey;
83bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
84bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        public SimpleEntity(String key) {
85bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            mKey = key;
86bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        }
87bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
88bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        @Override
89bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        public void write(OutputStream stream, EntityData params) throws IOException {
90bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            params.writeValue(stream, mKey);
91bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        }
92bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
93bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    }
94bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
95bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    static class ListEntity implements Entity {
96bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
97bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        String mKey;
98bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        Template mSubTemplate;
99bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
100bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        public ListEntity(Context context, String key, String subTemplate) {
101bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            mKey = key;
102bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            mSubTemplate = new Template(context, subTemplate);
103bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        }
104bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
105bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        @Override
106bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        public void write(OutputStream stream, EntityData params) throws IOException {
107bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            ListEntityIterator iter = params.getListIterator(mKey);
108bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            iter.reset();
109bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            while (iter.moveToNext()) {
110bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                mSubTemplate.write(stream, iter);
111bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            }
112bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        }
113bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
114bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    }
115bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
116bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    public abstract static class CursorListEntityWrapper implements ListEntityIterator {
117bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
118bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        private Cursor mCursor;
119bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
120bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        public CursorListEntityWrapper(Cursor cursor) {
121bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            mCursor = cursor;
122bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        }
123bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
124bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        @Override
125bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        public boolean moveToNext() {
126bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            return mCursor.moveToNext();
127bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        }
128bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
129bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        @Override
130bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        public void reset() {
131bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            mCursor.moveToPosition(-1);
132bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        }
133bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
134bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        @Override
135bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        public ListEntityIterator getListIterator(String key) {
136bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            return null;
137bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        }
138bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
139bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        public Cursor getCursor() {
140bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            return mCursor;
141bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        }
142bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
143bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    }
144bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
145bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    static class HashMapEntityData implements EntityData {
146bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
147bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        HashMap<String, Object> mData;
148bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
149bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        public HashMapEntityData(HashMap<String, Object> map) {
150bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            mData = map;
151bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        }
152bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
153bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        @Override
154bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        public ListEntityIterator getListIterator(String key) {
155bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            return (ListEntityIterator) mData.get(key);
156bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        }
157bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
158bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        @Override
159bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        public void writeValue(OutputStream stream, String key) throws IOException {
160bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            stream.write((byte[]) mData.get(key));
161bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        }
162bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
163bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    }
164bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
165bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    private List<Entity> mTemplate;
166bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    private HashMap<String, Object> mData = new HashMap<String, Object>();
167bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    private Template(Context context, int tid) {
168bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        this(context, readRaw(context, tid));
169bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    }
170bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
171bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    private Template(Context context, String template) {
172bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        mTemplate = new ArrayList<Entity>();
173bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        template = replaceConsts(context, template);
174bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        parseTemplate(context, template);
175bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    }
176bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
177bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    private Template(Template copy) {
178bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        mTemplate = copy.mTemplate;
179bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    }
180bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
181bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    Template copy() {
182bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        return new Template(this);
183bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    }
184bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
185bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    void parseTemplate(Context context, String template) {
186bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        final Pattern pattern = Pattern.compile("<%([=\\{])\\s*(\\w+)\\s*%>");
187bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        Matcher m = pattern.matcher(template);
188bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        int start = 0;
189bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        while (m.find()) {
190bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            String static_part = template.substring(start, m.start());
191bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            if (static_part.length() > 0) {
192bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                mTemplate.add(new StringEntity(static_part));
193bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            }
194bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            String type = m.group(1);
195bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            String name = m.group(2);
196bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            if (type.equals("=")) {
197bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                mTemplate.add(new SimpleEntity(name));
198bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            } else if (type.equals("{")) {
199bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                Pattern p = Pattern.compile("<%\\}\\s*" + Pattern.quote(name) + "\\s*%>");
200bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                Matcher end_m = p.matcher(template);
201bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                if (end_m.find(m.end())) {
202bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                    start = m.end();
203bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                    m.region(end_m.end(), template.length());
204bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                    String subTemplate = template.substring(start, end_m.start());
205bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                    mTemplate.add(new ListEntity(context, name, subTemplate));
206bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                    start = end_m.end();
207bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                    continue;
208bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                }
209bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            }
210bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            start = m.end();
211bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        }
212bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        String static_part = template.substring(start, template.length());
213bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        if (static_part.length() > 0) {
214bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            mTemplate.add(new StringEntity(static_part));
215bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        }
216bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    }
217bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
218bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    public void assign(String name, String value) {
219bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        mData.put(name, value.getBytes());
220bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    }
221bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
222bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    public void assignLoop(String name, ListEntityIterator iter) {
223bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        mData.put(name, iter);
224bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    }
225bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
226bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    public void write(OutputStream stream) throws IOException {
227bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        write(stream, new HashMapEntityData(mData));
228bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    }
229bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
230bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    public void write(OutputStream stream, EntityData data) throws IOException {
231bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        for (Entity ent : mTemplate) {
232bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            ent.write(stream, data);
233bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        }
234bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    }
235bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
236bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    private static String replaceConsts(Context context, String template) {
237bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        final Pattern pattern = Pattern.compile("<%@\\s*(\\w+/\\w+)\\s*%>");
238bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        final Resources res = context.getResources();
2391b7d2b95670a6c94cb29e0f4b965cebdf6f65bdaJohn Reck        final String packageName = R.class.getPackage().getName();
240bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        Matcher m = pattern.matcher(template);
241bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        StringBuffer sb = new StringBuffer();
242bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        while (m.find()) {
243bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            String name = m.group(1);
244bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            if (name.startsWith("drawable/")) {
245bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                m.appendReplacement(sb, "res/" + name);
246bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            } else {
247bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                int id = res.getIdentifier(name, null, packageName);
248bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                if (id != 0) {
249bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                    TypedValue value = new TypedValue();
250bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                    res.getValue(id, value, true);
251bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                    String replacement;
252bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                    if (value.type == TypedValue.TYPE_DIMENSION) {
253bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                        float dimen = res.getDimension(id);
254bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                        int dimeni = (int) dimen;
255bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                        if (dimeni == dimen)
256bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                            replacement = Integer.toString(dimeni);
257bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                        else
258bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                            replacement = Float.toString(dimen);
259bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                    } else {
260bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                        replacement = value.coerceToString().toString();
261bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                    }
262bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                    m.appendReplacement(sb, replacement);
263bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck                }
264bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            }
265bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        }
266bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        m.appendTail(sb);
267bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        return sb.toString();
268bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    }
269bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
270bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    private static String readRaw(Context context, int id) {
271bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        InputStream ins = context.getResources().openRawResource(id);
272bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        try {
273bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            byte[] buf = new byte[ins.available()];
274bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            ins.read(buf);
275bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            return new String(buf, "utf-8");
276bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        } catch (IOException ex) {
277bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck            return "<html><body>Error</body></html>";
278bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck        }
279bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck    }
280bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck
281bafe58a83ade9cfa5c91e7033fae2d08a64603e8John Reck}
282