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