/* * Copyright (C) 2012 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.Resources; import android.content.res.TypedArray; import android.util.Xml; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.utils.ResourceUtils; import org.xmlpull.v1.XmlPullParser; import java.util.ArrayDeque; /** * Container for keys in the keyboard. All keys in a row are at the same Y-coordinate. * Some of the key size defaults can be overridden per row from what the {@link Keyboard} * defines. */ public final class KeyboardRow { // keyWidth enum constants private static final int KEYWIDTH_NOT_ENUM = 0; private static final int KEYWIDTH_FILL_RIGHT = -1; private final KeyboardParams mParams; /** The height of this row. */ private final int mRowHeight; private final ArrayDeque mRowAttributesStack = new ArrayDeque<>(); // TODO: Add keyActionFlags. private static class RowAttributes { /** Default width of a key in this row. */ public final float mDefaultKeyWidth; /** Default keyLabelFlags in this row. */ public final int mDefaultKeyLabelFlags; /** Default backgroundType for this row */ public final int mDefaultBackgroundType; /** * Parse and create key attributes. This constructor is used to parse Row tag. * * @param keyAttr an attributes array of Row tag. * @param defaultKeyWidth a default key width. * @param keyboardWidth the keyboard width that is required to calculate keyWidth attribute. */ public RowAttributes(final TypedArray keyAttr, final float defaultKeyWidth, final int keyboardWidth) { mDefaultKeyWidth = keyAttr.getFraction(R.styleable.Keyboard_Key_keyWidth, keyboardWidth, keyboardWidth, defaultKeyWidth); mDefaultKeyLabelFlags = keyAttr.getInt(R.styleable.Keyboard_Key_keyLabelFlags, 0); mDefaultBackgroundType = keyAttr.getInt(R.styleable.Keyboard_Key_backgroundType, Key.BACKGROUND_TYPE_NORMAL); } /** * Parse and update key attributes using default attributes. This constructor is used * to parse include tag. * * @param keyAttr an attributes array of include tag. * @param defaultRowAttr default Row attributes. * @param keyboardWidth the keyboard width that is required to calculate keyWidth attribute. */ public RowAttributes(final TypedArray keyAttr, final RowAttributes defaultRowAttr, final int keyboardWidth) { mDefaultKeyWidth = keyAttr.getFraction(R.styleable.Keyboard_Key_keyWidth, keyboardWidth, keyboardWidth, defaultRowAttr.mDefaultKeyWidth); mDefaultKeyLabelFlags = keyAttr.getInt(R.styleable.Keyboard_Key_keyLabelFlags, 0) | defaultRowAttr.mDefaultKeyLabelFlags; mDefaultBackgroundType = keyAttr.getInt(R.styleable.Keyboard_Key_backgroundType, defaultRowAttr.mDefaultBackgroundType); } } private final int mCurrentY; // Will be updated by {@link Key}'s constructor. private float mCurrentX; public KeyboardRow(final Resources res, final KeyboardParams params, final XmlPullParser parser, final int y) { mParams = params; final TypedArray keyboardAttr = res.obtainAttributes(Xml.asAttributeSet(parser), R.styleable.Keyboard); mRowHeight = (int)ResourceUtils.getDimensionOrFraction(keyboardAttr, R.styleable.Keyboard_rowHeight, params.mBaseHeight, params.mDefaultRowHeight); keyboardAttr.recycle(); final TypedArray keyAttr = res.obtainAttributes(Xml.asAttributeSet(parser), R.styleable.Keyboard_Key); mRowAttributesStack.push(new RowAttributes( keyAttr, params.mDefaultKeyWidth, params.mBaseWidth)); keyAttr.recycle(); mCurrentY = y; mCurrentX = 0.0f; } public int getRowHeight() { return mRowHeight; } public void pushRowAttributes(final TypedArray keyAttr) { final RowAttributes newAttributes = new RowAttributes( keyAttr, mRowAttributesStack.peek(), mParams.mBaseWidth); mRowAttributesStack.push(newAttributes); } public void popRowAttributes() { mRowAttributesStack.pop(); } public float getDefaultKeyWidth() { return mRowAttributesStack.peek().mDefaultKeyWidth; } public int getDefaultKeyLabelFlags() { return mRowAttributesStack.peek().mDefaultKeyLabelFlags; } public int getDefaultBackgroundType() { return mRowAttributesStack.peek().mDefaultBackgroundType; } public void setXPos(final float keyXPos) { mCurrentX = keyXPos; } public void advanceXPos(final float width) { mCurrentX += width; } public int getKeyY() { return mCurrentY; } public float getKeyX(final TypedArray keyAttr) { if (keyAttr == null || !keyAttr.hasValue(R.styleable.Keyboard_Key_keyXPos)) { return mCurrentX; } final float keyXPos = keyAttr.getFraction(R.styleable.Keyboard_Key_keyXPos, mParams.mBaseWidth, mParams.mBaseWidth, 0); if (keyXPos >= 0) { return keyXPos + mParams.mLeftPadding; } // If keyXPos is negative, the actual x-coordinate will be // keyboardWidth + keyXPos. // keyXPos shouldn't be less than mCurrentX because drawable area for this // key starts at mCurrentX. Or, this key will overlaps the adjacent key on // its left hand side. final int keyboardRightEdge = mParams.mOccupiedWidth - mParams.mRightPadding; return Math.max(keyXPos + keyboardRightEdge, mCurrentX); } public float getKeyWidth(final TypedArray keyAttr, final float keyXPos) { if (keyAttr == null) { return getDefaultKeyWidth(); } final int widthType = ResourceUtils.getEnumValue(keyAttr, R.styleable.Keyboard_Key_keyWidth, KEYWIDTH_NOT_ENUM); switch (widthType) { case KEYWIDTH_FILL_RIGHT: // If keyWidth is fillRight, the actual key width will be determined to fill // out the area up to the right edge of the keyboard. final int keyboardRightEdge = mParams.mOccupiedWidth - mParams.mRightPadding; return keyboardRightEdge - keyXPos; default: // KEYWIDTH_NOT_ENUM return keyAttr.getFraction(R.styleable.Keyboard_Key_keyWidth, mParams.mBaseWidth, mParams.mBaseWidth, getDefaultKeyWidth()); } } }