Home | History | Annotate | Download | only in internal
      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 
     17 package com.android.inputmethod.keyboard.internal;
     18 
     19 import android.content.res.Resources;
     20 import android.content.res.TypedArray;
     21 import android.util.Xml;
     22 
     23 import com.android.inputmethod.keyboard.Key;
     24 import com.android.inputmethod.keyboard.Keyboard;
     25 import com.android.inputmethod.latin.R;
     26 import com.android.inputmethod.latin.utils.ResourceUtils;
     27 
     28 import org.xmlpull.v1.XmlPullParser;
     29 
     30 import 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  */
     37 public 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