Home | History | Annotate | Download | only in internal
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy of
      6  * 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, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations under
     14  * the License.
     15  */
     16 
     17 package com.android.inputmethod.keyboard.internal;
     18 
     19 import android.content.res.TypedArray;
     20 import android.util.Log;
     21 
     22 import com.android.inputmethod.keyboard.internal.KeyboardBuilder.ParseException;
     23 import com.android.inputmethod.latin.R;
     24 
     25 import org.xmlpull.v1.XmlPullParser;
     26 
     27 import java.util.ArrayList;
     28 import java.util.HashMap;
     29 
     30 public class KeyStyles {
     31     private static final String TAG = "KeyStyles";
     32     private static final boolean DEBUG = false;
     33 
     34     private final HashMap<String, DeclaredKeyStyle> mStyles =
     35             new HashMap<String, DeclaredKeyStyle>();
     36     private static final KeyStyle EMPTY_KEY_STYLE = new EmptyKeyStyle();
     37 
     38     public interface KeyStyle {
     39         public CharSequence[] getTextArray(TypedArray a, int index);
     40         public CharSequence getText(TypedArray a, int index);
     41         public int getInt(TypedArray a, int index, int defaultValue);
     42         public int getFlag(TypedArray a, int index, int defaultValue);
     43         public boolean getBoolean(TypedArray a, int index, boolean defaultValue);
     44     }
     45 
     46     /* package */ static class EmptyKeyStyle implements KeyStyle {
     47         private EmptyKeyStyle() {
     48             // Nothing to do.
     49         }
     50 
     51         @Override
     52         public CharSequence[] getTextArray(TypedArray a, int index) {
     53             return parseTextArray(a, index);
     54         }
     55 
     56         @Override
     57         public CharSequence getText(TypedArray a, int index) {
     58             return a.getText(index);
     59         }
     60 
     61         @Override
     62         public int getInt(TypedArray a, int index, int defaultValue) {
     63             return a.getInt(index, defaultValue);
     64         }
     65 
     66         @Override
     67         public int getFlag(TypedArray a, int index, int defaultValue) {
     68             return a.getInt(index, defaultValue);
     69         }
     70 
     71         @Override
     72         public boolean getBoolean(TypedArray a, int index, boolean defaultValue) {
     73             return a.getBoolean(index, defaultValue);
     74         }
     75 
     76         protected static CharSequence[] parseTextArray(TypedArray a, int index) {
     77             if (!a.hasValue(index))
     78                 return null;
     79             final CharSequence text = a.getText(index);
     80             return parseCsvText(text);
     81         }
     82 
     83         /* package */ static CharSequence[] parseCsvText(CharSequence text) {
     84             final int size = text.length();
     85             if (size == 0) return null;
     86             if (size == 1) return new CharSequence[] { text };
     87             final StringBuilder sb = new StringBuilder();
     88             ArrayList<CharSequence> list = null;
     89             int start = 0;
     90             for (int pos = 0; pos < size; pos++) {
     91                 final char c = text.charAt(pos);
     92                 if (c == ',') {
     93                     if (list == null) list = new ArrayList<CharSequence>();
     94                     if (sb.length() == 0) {
     95                         list.add(text.subSequence(start, pos));
     96                     } else {
     97                         list.add(sb.toString());
     98                         sb.setLength(0);
     99                     }
    100                     start = pos + 1;
    101                     continue;
    102                 } else if (c == '\\') {
    103                     if (start == pos) {
    104                         // Skip escape character at the beginning of the value.
    105                         start++;
    106                         pos++;
    107                     } else {
    108                         if (start < pos && sb.length() == 0)
    109                             sb.append(text.subSequence(start, pos));
    110                         pos++;
    111                         if (pos < size)
    112                             sb.append(text.charAt(pos));
    113                     }
    114                 } else if (sb.length() > 0) {
    115                     sb.append(c);
    116                 }
    117             }
    118             if (list == null) {
    119                 return new CharSequence[] { sb.length() > 0 ? sb : text.subSequence(start, size) };
    120             } else {
    121                 list.add(sb.length() > 0 ? sb : text.subSequence(start, size));
    122                 return list.toArray(new CharSequence[list.size()]);
    123             }
    124         }
    125     }
    126 
    127     private static class DeclaredKeyStyle extends EmptyKeyStyle {
    128         private final HashMap<Integer, Object> mAttributes = new HashMap<Integer, Object>();
    129 
    130         @Override
    131         public CharSequence[] getTextArray(TypedArray a, int index) {
    132             return a.hasValue(index)
    133                     ? super.getTextArray(a, index) : (CharSequence[])mAttributes.get(index);
    134         }
    135 
    136         @Override
    137         public CharSequence getText(TypedArray a, int index) {
    138             return a.hasValue(index)
    139                     ? super.getText(a, index) : (CharSequence)mAttributes.get(index);
    140         }
    141 
    142         @Override
    143         public int getInt(TypedArray a, int index, int defaultValue) {
    144             final Integer value = (Integer)mAttributes.get(index);
    145             return super.getInt(a, index, (value != null) ? value : defaultValue);
    146         }
    147 
    148         @Override
    149         public int getFlag(TypedArray a, int index, int defaultValue) {
    150             final Integer value = (Integer)mAttributes.get(index);
    151             return super.getFlag(a, index, defaultValue) | (value != null ? value : 0);
    152         }
    153 
    154         @Override
    155         public boolean getBoolean(TypedArray a, int index, boolean defaultValue) {
    156             final Boolean value = (Boolean)mAttributes.get(index);
    157             return super.getBoolean(a, index, (value != null) ? value : defaultValue);
    158         }
    159 
    160         private DeclaredKeyStyle() {
    161             super();
    162         }
    163 
    164         private void parseKeyStyleAttributes(TypedArray keyAttr) {
    165             // TODO: Currently not all Key attributes can be declared as style.
    166             readInt(keyAttr, R.styleable.Keyboard_Key_code);
    167             readText(keyAttr, R.styleable.Keyboard_Key_keyLabel);
    168             readText(keyAttr, R.styleable.Keyboard_Key_keyOutputText);
    169             readText(keyAttr, R.styleable.Keyboard_Key_keyHintLabel);
    170             readTextArray(keyAttr, R.styleable.Keyboard_Key_moreKeys);
    171             readFlag(keyAttr, R.styleable.Keyboard_Key_keyLabelOption);
    172             readInt(keyAttr, R.styleable.Keyboard_Key_keyIcon);
    173             readInt(keyAttr, R.styleable.Keyboard_Key_keyIconPreview);
    174             readInt(keyAttr, R.styleable.Keyboard_Key_keyIconShifted);
    175             readInt(keyAttr, R.styleable.Keyboard_Key_maxMoreKeysColumn);
    176             readInt(keyAttr, R.styleable.Keyboard_Key_backgroundType);
    177             readBoolean(keyAttr, R.styleable.Keyboard_Key_isRepeatable);
    178             readBoolean(keyAttr, R.styleable.Keyboard_Key_enabled);
    179         }
    180 
    181         private void readText(TypedArray a, int index) {
    182             if (a.hasValue(index))
    183                 mAttributes.put(index, a.getText(index));
    184         }
    185 
    186         private void readInt(TypedArray a, int index) {
    187             if (a.hasValue(index))
    188                 mAttributes.put(index, a.getInt(index, 0));
    189         }
    190 
    191         private void readFlag(TypedArray a, int index) {
    192             final Integer value = (Integer)mAttributes.get(index);
    193             if (a.hasValue(index))
    194                 mAttributes.put(index, a.getInt(index, 0) | (value != null ? value : 0));
    195         }
    196 
    197         private void readBoolean(TypedArray a, int index) {
    198             if (a.hasValue(index))
    199                 mAttributes.put(index, a.getBoolean(index, false));
    200         }
    201 
    202         private void readTextArray(TypedArray a, int index) {
    203             final CharSequence[] value = parseTextArray(a, index);
    204             if (value != null)
    205                 mAttributes.put(index, value);
    206         }
    207 
    208         private void addParent(DeclaredKeyStyle parentStyle) {
    209             mAttributes.putAll(parentStyle.mAttributes);
    210         }
    211     }
    212 
    213     public void parseKeyStyleAttributes(TypedArray keyStyleAttr, TypedArray keyAttrs,
    214             XmlPullParser parser) {
    215         final String styleName = keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_styleName);
    216         if (DEBUG) Log.d(TAG, String.format("<%s styleName=%s />",
    217                 KeyboardBuilder.TAG_KEY_STYLE, styleName));
    218         if (mStyles.containsKey(styleName))
    219             throw new ParseException("duplicate key style declared: " + styleName, parser);
    220 
    221         final DeclaredKeyStyle style = new DeclaredKeyStyle();
    222         if (keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_parentStyle)) {
    223             final String parentStyle = keyStyleAttr.getString(
    224                     R.styleable.Keyboard_KeyStyle_parentStyle);
    225             final DeclaredKeyStyle parent = mStyles.get(parentStyle);
    226             if (parent == null)
    227                 throw new ParseException("Unknown parentStyle " + parentStyle, parser);
    228             style.addParent(parent);
    229         }
    230         style.parseKeyStyleAttributes(keyAttrs);
    231         mStyles.put(styleName, style);
    232     }
    233 
    234     public KeyStyle getKeyStyle(String styleName) {
    235         return mStyles.get(styleName);
    236     }
    237 
    238     public KeyStyle getEmptyKeyStyle() {
    239         return EMPTY_KEY_STYLE;
    240     }
    241 }
    242