/* * Copyright (C) 2010 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.inputmethod.keyboard.internal; import android.content.res.TypedArray; import android.util.Log; import android.util.SparseArray; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.utils.XmlParseUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.util.Arrays; import java.util.HashMap; import javax.annotation.Nonnull; import javax.annotation.Nullable; public final class KeyStylesSet { private static final String TAG = KeyStylesSet.class.getSimpleName(); private static final boolean DEBUG = false; @Nonnull private final HashMap mStyles = new HashMap<>(); @Nonnull private final KeyboardTextsSet mTextsSet; @Nonnull private final KeyStyle mEmptyKeyStyle; @Nonnull private static final String EMPTY_STYLE_NAME = ""; public KeyStylesSet(@Nonnull final KeyboardTextsSet textsSet) { mTextsSet = textsSet; mEmptyKeyStyle = new EmptyKeyStyle(textsSet); mStyles.put(EMPTY_STYLE_NAME, mEmptyKeyStyle); } private static final class EmptyKeyStyle extends KeyStyle { EmptyKeyStyle(@Nonnull final KeyboardTextsSet textsSet) { super(textsSet); } @Override @Nullable public String[] getStringArray(final TypedArray a, final int index) { return parseStringArray(a, index); } @Override @Nullable public String getString(final TypedArray a, final int index) { return parseString(a, index); } @Override public int getInt(final TypedArray a, final int index, final int defaultValue) { return a.getInt(index, defaultValue); } @Override public int getFlags(final TypedArray a, final int index) { return a.getInt(index, 0); } } private static final class DeclaredKeyStyle extends KeyStyle { private final HashMap mStyles; private final String mParentStyleName; private final SparseArray mStyleAttributes = new SparseArray<>(); public DeclaredKeyStyle(@Nonnull final String parentStyleName, @Nonnull final KeyboardTextsSet textsSet, @Nonnull final HashMap styles) { super(textsSet); mParentStyleName = parentStyleName; mStyles = styles; } @Override @Nullable public String[] getStringArray(final TypedArray a, final int index) { if (a.hasValue(index)) { return parseStringArray(a, index); } final Object value = mStyleAttributes.get(index); if (value != null) { final String[] array = (String[])value; return Arrays.copyOf(array, array.length); } final KeyStyle parentStyle = mStyles.get(mParentStyleName); return parentStyle.getStringArray(a, index); } @Override @Nullable public String getString(final TypedArray a, final int index) { if (a.hasValue(index)) { return parseString(a, index); } final Object value = mStyleAttributes.get(index); if (value != null) { return (String)value; } final KeyStyle parentStyle = mStyles.get(mParentStyleName); return parentStyle.getString(a, index); } @Override public int getInt(final TypedArray a, final int index, final int defaultValue) { if (a.hasValue(index)) { return a.getInt(index, defaultValue); } final Object value = mStyleAttributes.get(index); if (value != null) { return (Integer)value; } final KeyStyle parentStyle = mStyles.get(mParentStyleName); return parentStyle.getInt(a, index, defaultValue); } @Override public int getFlags(final TypedArray a, final int index) { final int parentFlags = mStyles.get(mParentStyleName).getFlags(a, index); final Integer value = (Integer)mStyleAttributes.get(index); final int styleFlags = (value != null) ? value : 0; final int flags = a.getInt(index, 0); return flags | styleFlags | parentFlags; } public void readKeyAttributes(final TypedArray keyAttr) { // TODO: Currently not all Key attributes can be declared as style. readString(keyAttr, R.styleable.Keyboard_Key_altCode); readString(keyAttr, R.styleable.Keyboard_Key_keySpec); readString(keyAttr, R.styleable.Keyboard_Key_keyHintLabel); readStringArray(keyAttr, R.styleable.Keyboard_Key_moreKeys); readStringArray(keyAttr, R.styleable.Keyboard_Key_additionalMoreKeys); readFlags(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags); readString(keyAttr, R.styleable.Keyboard_Key_keyIconDisabled); readInt(keyAttr, R.styleable.Keyboard_Key_maxMoreKeysColumn); readInt(keyAttr, R.styleable.Keyboard_Key_backgroundType); readFlags(keyAttr, R.styleable.Keyboard_Key_keyActionFlags); } private void readString(final TypedArray a, final int index) { if (a.hasValue(index)) { mStyleAttributes.put(index, parseString(a, index)); } } private void readInt(final TypedArray a, final int index) { if (a.hasValue(index)) { mStyleAttributes.put(index, a.getInt(index, 0)); } } private void readFlags(final TypedArray a, final int index) { if (a.hasValue(index)) { final Integer value = (Integer)mStyleAttributes.get(index); final int styleFlags = value != null ? value : 0; mStyleAttributes.put(index, a.getInt(index, 0) | styleFlags); } } private void readStringArray(final TypedArray a, final int index) { if (a.hasValue(index)) { mStyleAttributes.put(index, parseStringArray(a, index)); } } } public void parseKeyStyleAttributes(final TypedArray keyStyleAttr, final TypedArray keyAttrs, final XmlPullParser parser) throws XmlPullParserException { final String styleName = keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_styleName); if (styleName == null) { throw new XmlParseUtils.ParseException( KeyboardBuilder.TAG_KEY_STYLE + " has no styleName attribute", parser); } if (DEBUG) { Log.d(TAG, String.format("<%s styleName=%s />", KeyboardBuilder.TAG_KEY_STYLE, styleName)); if (mStyles.containsKey(styleName)) { Log.d(TAG, KeyboardBuilder.TAG_KEY_STYLE + " " + styleName + " is overridden at " + parser.getPositionDescription()); } } final String parentStyleInAttr = keyStyleAttr.getString( R.styleable.Keyboard_KeyStyle_parentStyle); if (parentStyleInAttr != null && !mStyles.containsKey(parentStyleInAttr)) { throw new XmlParseUtils.ParseException( "Unknown parentStyle " + parentStyleInAttr, parser); } final String parentStyleName = (parentStyleInAttr == null) ? EMPTY_STYLE_NAME : parentStyleInAttr; final DeclaredKeyStyle style = new DeclaredKeyStyle(parentStyleName, mTextsSet, mStyles); style.readKeyAttributes(keyAttrs); mStyles.put(styleName, style); } @Nonnull public KeyStyle getKeyStyle(final TypedArray keyAttr, final XmlPullParser parser) throws XmlParseUtils.ParseException { final String styleName = keyAttr.getString(R.styleable.Keyboard_Key_keyStyle); if (styleName == null) { return mEmptyKeyStyle; } final KeyStyle style = mStyles.get(styleName); if (style == null) { throw new XmlParseUtils.ParseException("Unknown key style: " + styleName, parser); } return style; } }