1/* 2 * Copyright (C) 2012 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 17package com.android.inputmethod.keyboard.internal; 18 19import android.content.res.Resources; 20import android.content.res.TypedArray; 21import android.util.Xml; 22 23import com.android.inputmethod.keyboard.Key; 24import com.android.inputmethod.keyboard.Keyboard; 25import com.android.inputmethod.latin.R; 26import com.android.inputmethod.latin.utils.ResourceUtils; 27 28import org.xmlpull.v1.XmlPullParser; 29 30import java.util.ArrayDeque; 31 32/** 33 * Container for keys in the keyboard. All keys in a row are at the same Y-coordinate. 34 * Some of the key size defaults can be overridden per row from what the {@link Keyboard} 35 * defines. 36 */ 37public final class KeyboardRow { 38 // keyWidth enum constants 39 private static final int KEYWIDTH_NOT_ENUM = 0; 40 private static final int KEYWIDTH_FILL_RIGHT = -1; 41 42 private final KeyboardParams mParams; 43 /** The height of this row. */ 44 private final int mRowHeight; 45 46 private final ArrayDeque<RowAttributes> mRowAttributesStack = new ArrayDeque<>(); 47 48 // TODO: Add keyActionFlags. 49 private static class RowAttributes { 50 /** Default width of a key in this row. */ 51 public final float mDefaultKeyWidth; 52 /** Default keyLabelFlags in this row. */ 53 public final int mDefaultKeyLabelFlags; 54 /** Default backgroundType for this row */ 55 public final int mDefaultBackgroundType; 56 57 /** 58 * Parse and create key attributes. This constructor is used to parse Row tag. 59 * 60 * @param keyAttr an attributes array of Row tag. 61 * @param defaultKeyWidth a default key width. 62 * @param keyboardWidth the keyboard width that is required to calculate keyWidth attribute. 63 */ 64 public RowAttributes(final TypedArray keyAttr, final float defaultKeyWidth, 65 final int keyboardWidth) { 66 mDefaultKeyWidth = keyAttr.getFraction(R.styleable.Keyboard_Key_keyWidth, 67 keyboardWidth, keyboardWidth, defaultKeyWidth); 68 mDefaultKeyLabelFlags = keyAttr.getInt(R.styleable.Keyboard_Key_keyLabelFlags, 0); 69 mDefaultBackgroundType = keyAttr.getInt(R.styleable.Keyboard_Key_backgroundType, 70 Key.BACKGROUND_TYPE_NORMAL); 71 } 72 73 /** 74 * Parse and update key attributes using default attributes. This constructor is used 75 * to parse include tag. 76 * 77 * @param keyAttr an attributes array of include tag. 78 * @param defaultRowAttr default Row attributes. 79 * @param keyboardWidth the keyboard width that is required to calculate keyWidth attribute. 80 */ 81 public RowAttributes(final TypedArray keyAttr, final RowAttributes defaultRowAttr, 82 final int keyboardWidth) { 83 mDefaultKeyWidth = keyAttr.getFraction(R.styleable.Keyboard_Key_keyWidth, 84 keyboardWidth, keyboardWidth, defaultRowAttr.mDefaultKeyWidth); 85 mDefaultKeyLabelFlags = keyAttr.getInt(R.styleable.Keyboard_Key_keyLabelFlags, 0) 86 | defaultRowAttr.mDefaultKeyLabelFlags; 87 mDefaultBackgroundType = keyAttr.getInt(R.styleable.Keyboard_Key_backgroundType, 88 defaultRowAttr.mDefaultBackgroundType); 89 } 90 } 91 92 private final int mCurrentY; 93 // Will be updated by {@link Key}'s constructor. 94 private float mCurrentX; 95 96 public KeyboardRow(final Resources res, final KeyboardParams params, 97 final XmlPullParser parser, final int y) { 98 mParams = params; 99 final TypedArray keyboardAttr = res.obtainAttributes(Xml.asAttributeSet(parser), 100 R.styleable.Keyboard); 101 mRowHeight = (int)ResourceUtils.getDimensionOrFraction(keyboardAttr, 102 R.styleable.Keyboard_rowHeight, params.mBaseHeight, params.mDefaultRowHeight); 103 keyboardAttr.recycle(); 104 final TypedArray keyAttr = res.obtainAttributes(Xml.asAttributeSet(parser), 105 R.styleable.Keyboard_Key); 106 mRowAttributesStack.push(new RowAttributes( 107 keyAttr, params.mDefaultKeyWidth, params.mBaseWidth)); 108 keyAttr.recycle(); 109 110 mCurrentY = y; 111 mCurrentX = 0.0f; 112 } 113 114 public int getRowHeight() { 115 return mRowHeight; 116 } 117 118 public void pushRowAttributes(final TypedArray keyAttr) { 119 final RowAttributes newAttributes = new RowAttributes( 120 keyAttr, mRowAttributesStack.peek(), mParams.mBaseWidth); 121 mRowAttributesStack.push(newAttributes); 122 } 123 124 public void popRowAttributes() { 125 mRowAttributesStack.pop(); 126 } 127 128 public float getDefaultKeyWidth() { 129 return mRowAttributesStack.peek().mDefaultKeyWidth; 130 } 131 132 public int getDefaultKeyLabelFlags() { 133 return mRowAttributesStack.peek().mDefaultKeyLabelFlags; 134 } 135 136 public int getDefaultBackgroundType() { 137 return mRowAttributesStack.peek().mDefaultBackgroundType; 138 } 139 140 public void setXPos(final float keyXPos) { 141 mCurrentX = keyXPos; 142 } 143 144 public void advanceXPos(final float width) { 145 mCurrentX += width; 146 } 147 148 public int getKeyY() { 149 return mCurrentY; 150 } 151 152 public float getKeyX(final TypedArray keyAttr) { 153 if (keyAttr == null || !keyAttr.hasValue(R.styleable.Keyboard_Key_keyXPos)) { 154 return mCurrentX; 155 } 156 final float keyXPos = keyAttr.getFraction(R.styleable.Keyboard_Key_keyXPos, 157 mParams.mBaseWidth, mParams.mBaseWidth, 0); 158 if (keyXPos >= 0) { 159 return keyXPos + mParams.mLeftPadding; 160 } 161 // If keyXPos is negative, the actual x-coordinate will be 162 // keyboardWidth + keyXPos. 163 // keyXPos shouldn't be less than mCurrentX because drawable area for this 164 // key starts at mCurrentX. Or, this key will overlaps the adjacent key on 165 // its left hand side. 166 final int keyboardRightEdge = mParams.mOccupiedWidth - mParams.mRightPadding; 167 return Math.max(keyXPos + keyboardRightEdge, mCurrentX); 168 } 169 170 public float getKeyWidth(final TypedArray keyAttr, final float keyXPos) { 171 if (keyAttr == null) { 172 return getDefaultKeyWidth(); 173 } 174 final int widthType = ResourceUtils.getEnumValue(keyAttr, 175 R.styleable.Keyboard_Key_keyWidth, KEYWIDTH_NOT_ENUM); 176 switch (widthType) { 177 case KEYWIDTH_FILL_RIGHT: 178 // If keyWidth is fillRight, the actual key width will be determined to fill 179 // out the area up to the right edge of the keyboard. 180 final int keyboardRightEdge = mParams.mOccupiedWidth - mParams.mRightPadding; 181 return keyboardRightEdge - keyXPos; 182 default: // KEYWIDTH_NOT_ENUM 183 return keyAttr.getFraction(R.styleable.Keyboard_Key_keyWidth, 184 mParams.mBaseWidth, mParams.mBaseWidth, getDefaultKeyWidth()); 185 } 186 } 187} 188