1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of 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,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.inputmethod.keyboard.internal;
18 
19 import android.content.res.TypedArray;
20 import android.util.Log;
21 import android.util.SparseArray;
22 
23 import com.android.inputmethod.latin.R;
24 import com.android.inputmethod.latin.utils.XmlParseUtils;
25 
26 import org.xmlpull.v1.XmlPullParser;
27 import org.xmlpull.v1.XmlPullParserException;
28 
29 import java.util.Arrays;
30 import java.util.HashMap;
31 
32 public final class KeyStylesSet {
33     private static final String TAG = KeyStylesSet.class.getSimpleName();
34     private static final boolean DEBUG = false;
35 
36     private final HashMap<String, KeyStyle> mStyles = new HashMap<>();
37 
38     private final KeyboardTextsSet mTextsSet;
39     private final KeyStyle mEmptyKeyStyle;
40     private static final String EMPTY_STYLE_NAME = "<empty>";
41 
KeyStylesSet(final KeyboardTextsSet textsSet)42     public KeyStylesSet(final KeyboardTextsSet textsSet) {
43         mTextsSet = textsSet;
44         mEmptyKeyStyle = new EmptyKeyStyle(textsSet);
45         mStyles.put(EMPTY_STYLE_NAME, mEmptyKeyStyle);
46     }
47 
48     private static final class EmptyKeyStyle extends KeyStyle {
EmptyKeyStyle(final KeyboardTextsSet textsSet)49         EmptyKeyStyle(final KeyboardTextsSet textsSet) {
50             super(textsSet);
51         }
52 
53         @Override
getStringArray(final TypedArray a, final int index)54         public String[] getStringArray(final TypedArray a, final int index) {
55             return parseStringArray(a, index);
56         }
57 
58         @Override
getString(final TypedArray a, final int index)59         public String getString(final TypedArray a, final int index) {
60             return parseString(a, index);
61         }
62 
63         @Override
getInt(final TypedArray a, final int index, final int defaultValue)64         public int getInt(final TypedArray a, final int index, final int defaultValue) {
65             return a.getInt(index, defaultValue);
66         }
67 
68         @Override
getFlags(final TypedArray a, final int index)69         public int getFlags(final TypedArray a, final int index) {
70             return a.getInt(index, 0);
71         }
72     }
73 
74     private static final class DeclaredKeyStyle extends KeyStyle {
75         private final HashMap<String, KeyStyle> mStyles;
76         private final String mParentStyleName;
77         private final SparseArray<Object> mStyleAttributes = new SparseArray<>();
78 
DeclaredKeyStyle(final String parentStyleName, final KeyboardTextsSet textsSet, final HashMap<String, KeyStyle> styles)79         public DeclaredKeyStyle(final String parentStyleName, final KeyboardTextsSet textsSet,
80                 final HashMap<String, KeyStyle> styles) {
81             super(textsSet);
82             mParentStyleName = parentStyleName;
83             mStyles = styles;
84         }
85 
86         @Override
getStringArray(final TypedArray a, final int index)87         public String[] getStringArray(final TypedArray a, final int index) {
88             if (a.hasValue(index)) {
89                 return parseStringArray(a, index);
90             }
91             final Object value = mStyleAttributes.get(index);
92             if (value != null) {
93                 final String[] array = (String[])value;
94                 return Arrays.copyOf(array, array.length);
95             }
96             final KeyStyle parentStyle = mStyles.get(mParentStyleName);
97             return parentStyle.getStringArray(a, index);
98         }
99 
100         @Override
getString(final TypedArray a, final int index)101         public String getString(final TypedArray a, final int index) {
102             if (a.hasValue(index)) {
103                 return parseString(a, index);
104             }
105             final Object value = mStyleAttributes.get(index);
106             if (value != null) {
107                 return (String)value;
108             }
109             final KeyStyle parentStyle = mStyles.get(mParentStyleName);
110             return parentStyle.getString(a, index);
111         }
112 
113         @Override
getInt(final TypedArray a, final int index, final int defaultValue)114         public int getInt(final TypedArray a, final int index, final int defaultValue) {
115             if (a.hasValue(index)) {
116                 return a.getInt(index, defaultValue);
117             }
118             final Object value = mStyleAttributes.get(index);
119             if (value != null) {
120                 return (Integer)value;
121             }
122             final KeyStyle parentStyle = mStyles.get(mParentStyleName);
123             return parentStyle.getInt(a, index, defaultValue);
124         }
125 
126         @Override
getFlags(final TypedArray a, final int index)127         public int getFlags(final TypedArray a, final int index) {
128             final int parentFlags = mStyles.get(mParentStyleName).getFlags(a, index);
129             final Integer value = (Integer)mStyleAttributes.get(index);
130             final int styleFlags = (value != null) ? value : 0;
131             final int flags = a.getInt(index, 0);
132             return flags | styleFlags | parentFlags;
133         }
134 
readKeyAttributes(final TypedArray keyAttr)135         public void readKeyAttributes(final TypedArray keyAttr) {
136             // TODO: Currently not all Key attributes can be declared as style.
137             readString(keyAttr, R.styleable.Keyboard_Key_altCode);
138             readString(keyAttr, R.styleable.Keyboard_Key_keySpec);
139             readString(keyAttr, R.styleable.Keyboard_Key_keyHintLabel);
140             readStringArray(keyAttr, R.styleable.Keyboard_Key_moreKeys);
141             readStringArray(keyAttr, R.styleable.Keyboard_Key_additionalMoreKeys);
142             readFlags(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags);
143             readString(keyAttr, R.styleable.Keyboard_Key_keyIconDisabled);
144             readInt(keyAttr, R.styleable.Keyboard_Key_maxMoreKeysColumn);
145             readInt(keyAttr, R.styleable.Keyboard_Key_backgroundType);
146             readFlags(keyAttr, R.styleable.Keyboard_Key_keyActionFlags);
147         }
148 
readString(final TypedArray a, final int index)149         private void readString(final TypedArray a, final int index) {
150             if (a.hasValue(index)) {
151                 mStyleAttributes.put(index, parseString(a, index));
152             }
153         }
154 
readInt(final TypedArray a, final int index)155         private void readInt(final TypedArray a, final int index) {
156             if (a.hasValue(index)) {
157                 mStyleAttributes.put(index, a.getInt(index, 0));
158             }
159         }
160 
readFlags(final TypedArray a, final int index)161         private void readFlags(final TypedArray a, final int index) {
162             if (a.hasValue(index)) {
163                 final Integer value = (Integer)mStyleAttributes.get(index);
164                 final int styleFlags = value != null ? value : 0;
165                 mStyleAttributes.put(index, a.getInt(index, 0) | styleFlags);
166             }
167         }
168 
readStringArray(final TypedArray a, final int index)169         private void readStringArray(final TypedArray a, final int index) {
170             if (a.hasValue(index)) {
171                 mStyleAttributes.put(index, parseStringArray(a, index));
172             }
173         }
174     }
175 
parseKeyStyleAttributes(final TypedArray keyStyleAttr, final TypedArray keyAttrs, final XmlPullParser parser)176     public void parseKeyStyleAttributes(final TypedArray keyStyleAttr, final TypedArray keyAttrs,
177             final XmlPullParser parser) throws XmlPullParserException {
178         final String styleName = keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_styleName);
179         if (DEBUG) {
180             Log.d(TAG, String.format("<%s styleName=%s />",
181                     KeyboardBuilder.TAG_KEY_STYLE, styleName));
182             if (mStyles.containsKey(styleName)) {
183                 Log.d(TAG, "key-style " + styleName + " is overridden at "
184                         + parser.getPositionDescription());
185             }
186         }
187 
188         String parentStyleName = EMPTY_STYLE_NAME;
189         if (keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_parentStyle)) {
190             parentStyleName = keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_parentStyle);
191             if (!mStyles.containsKey(parentStyleName)) {
192                 throw new XmlParseUtils.ParseException(
193                         "Unknown parentStyle " + parentStyleName, parser);
194             }
195         }
196         final DeclaredKeyStyle style = new DeclaredKeyStyle(parentStyleName, mTextsSet, mStyles);
197         style.readKeyAttributes(keyAttrs);
198         mStyles.put(styleName, style);
199     }
200 
getKeyStyle(final TypedArray keyAttr, final XmlPullParser parser)201     public KeyStyle getKeyStyle(final TypedArray keyAttr, final XmlPullParser parser)
202             throws XmlParseUtils.ParseException {
203         if (!keyAttr.hasValue(R.styleable.Keyboard_Key_keyStyle)) {
204             return mEmptyKeyStyle;
205         }
206         final String styleName = keyAttr.getString(R.styleable.Keyboard_Key_keyStyle);
207         if (!mStyles.containsKey(styleName)) {
208             throw new XmlParseUtils.ParseException("Unknown key style: " + styleName, parser);
209         }
210         return mStyles.get(styleName);
211     }
212 }
213