• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * 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, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package com.android.inputmethod.latin;
18 
19 import android.content.res.Resources;
20 import android.graphics.Paint;
21 import android.graphics.drawable.Drawable;
22 import android.text.TextUtils;
23 
24 import com.android.inputmethod.keyboard.Key;
25 import com.android.inputmethod.keyboard.Keyboard;
26 import com.android.inputmethod.keyboard.KeyboardSwitcher;
27 import com.android.inputmethod.keyboard.KeyboardView;
28 import com.android.inputmethod.keyboard.internal.KeyboardBuilder;
29 import com.android.inputmethod.keyboard.internal.KeyboardParams;
30 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
31 
32 public class MoreSuggestions extends Keyboard {
33     private static final boolean DBG = LatinImeLogger.sDBG;
34 
35     public static final int SUGGESTION_CODE_BASE = 1024;
36 
MoreSuggestions(Builder.MoreSuggestionsParam params)37     private MoreSuggestions(Builder.MoreSuggestionsParam params) {
38         super(params);
39     }
40 
41     public static class Builder extends KeyboardBuilder<Builder.MoreSuggestionsParam> {
42         private final MoreSuggestionsView mPaneView;
43         private SuggestedWords mSuggestions;
44         private int mFromPos;
45         private int mToPos;
46 
47         public static class MoreSuggestionsParam extends KeyboardParams {
48             private final int[] mWidths = new int[SuggestionsView.MAX_SUGGESTIONS];
49             private final int[] mRowNumbers = new int[SuggestionsView.MAX_SUGGESTIONS];
50             private final int[] mColumnOrders = new int[SuggestionsView.MAX_SUGGESTIONS];
51             private final int[] mNumColumnsInRow = new int[SuggestionsView.MAX_SUGGESTIONS];
52             private static final int MAX_COLUMNS_IN_ROW = 3;
53             private int mNumRows;
54             public Drawable mDivider;
55             public int mDividerWidth;
56 
layout(SuggestedWords suggestions, int fromPos, int maxWidth, int minWidth, int maxRow, KeyboardView view)57             public int layout(SuggestedWords suggestions, int fromPos, int maxWidth, int minWidth,
58                     int maxRow, KeyboardView view) {
59                 clearKeys();
60                 final Paint paint = new Paint();
61                 paint.setAntiAlias(true);
62                 final Resources res = view.getContext().getResources();
63                 mDivider = res.getDrawable(R.drawable.more_suggestions_divider);
64                 // TODO: Drawable itself should has an alpha value.
65                 mDivider.setAlpha(128);
66                 mDividerWidth = mDivider.getIntrinsicWidth();
67                 final int padding = (int) res.getDimension(
68                         R.dimen.more_suggestions_key_horizontal_padding);
69 
70                 int row = 0;
71                 int pos = fromPos, rowStartPos = fromPos;
72                 final int size = Math.min(suggestions.size(), SuggestionsView.MAX_SUGGESTIONS);
73                 while (pos < size) {
74                     final CharSequence word = suggestions.getWord(pos);
75                     // TODO: Should take care of text x-scaling.
76                     mWidths[pos] = (int)view.getDefaultLabelWidth(word, paint) + padding;
77                     final int numColumn = pos - rowStartPos + 1;
78                     final int columnWidth =
79                             (maxWidth - mDividerWidth * (numColumn - 1)) / numColumn;
80                     if (numColumn > MAX_COLUMNS_IN_ROW
81                             || !fitInWidth(rowStartPos, pos + 1, columnWidth)) {
82                         if ((row + 1) >= maxRow) {
83                             break;
84                         }
85                         mNumColumnsInRow[row] = pos - rowStartPos;
86                         rowStartPos = pos;
87                         row++;
88                     }
89                     mColumnOrders[pos] = pos - rowStartPos;
90                     mRowNumbers[pos] = row;
91                     pos++;
92                 }
93                 mNumColumnsInRow[row] = pos - rowStartPos;
94                 mNumRows = row + 1;
95                 mBaseWidth = mOccupiedWidth = Math.max(
96                         minWidth, calcurateMaxRowWidth(fromPos, pos));
97                 mBaseHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight + mVerticalGap;
98                 return pos - fromPos;
99             }
100 
fitInWidth(int startPos, int endPos, int width)101             private boolean fitInWidth(int startPos, int endPos, int width) {
102                 for (int pos = startPos; pos < endPos; pos++) {
103                     if (mWidths[pos] > width)
104                         return false;
105                 }
106                 return true;
107             }
108 
calcurateMaxRowWidth(int startPos, int endPos)109             private int calcurateMaxRowWidth(int startPos, int endPos) {
110                 int maxRowWidth = 0;
111                 int pos = startPos;
112                 for (int row = 0; row < mNumRows; row++) {
113                     final int numColumnInRow = mNumColumnsInRow[row];
114                     int maxKeyWidth = 0;
115                     while (pos < endPos && mRowNumbers[pos] == row) {
116                         maxKeyWidth = Math.max(maxKeyWidth, mWidths[pos]);
117                         pos++;
118                     }
119                     maxRowWidth = Math.max(maxRowWidth,
120                             maxKeyWidth * numColumnInRow + mDividerWidth * (numColumnInRow - 1));
121                 }
122                 return maxRowWidth;
123             }
124 
125             private static final int[][] COLUMN_ORDER_TO_NUMBER = {
126                 { 0, },
127                 { 1, 0, },
128                 { 2, 0, 1},
129             };
130 
getNumColumnInRow(int pos)131             public int getNumColumnInRow(int pos) {
132                 return mNumColumnsInRow[mRowNumbers[pos]];
133             }
134 
getColumnNumber(int pos)135             public int getColumnNumber(int pos) {
136                 final int columnOrder = mColumnOrders[pos];
137                 final int numColumn = getNumColumnInRow(pos);
138                 return COLUMN_ORDER_TO_NUMBER[numColumn - 1][columnOrder];
139             }
140 
getX(int pos)141             public int getX(int pos) {
142                 final int columnNumber = getColumnNumber(pos);
143                 return columnNumber * (getWidth(pos) + mDividerWidth);
144             }
145 
getY(int pos)146             public int getY(int pos) {
147                 final int row = mRowNumbers[pos];
148                 return (mNumRows -1 - row) * mDefaultRowHeight + mTopPadding;
149             }
150 
getWidth(int pos)151             public int getWidth(int pos) {
152                 final int numColumnInRow = getNumColumnInRow(pos);
153                 return (mOccupiedWidth - mDividerWidth * (numColumnInRow - 1)) / numColumnInRow;
154             }
155 
markAsEdgeKey(Key key, int pos)156             public void markAsEdgeKey(Key key, int pos) {
157                 final int row = mRowNumbers[pos];
158                 if (row == 0)
159                     key.markAsBottomEdge(this);
160                 if (row == mNumRows - 1)
161                     key.markAsTopEdge(this);
162 
163                 final int numColumnInRow = mNumColumnsInRow[row];
164                 final int column = getColumnNumber(pos);
165                 if (column == 0)
166                     key.markAsLeftEdge(this);
167                 if (column == numColumnInRow - 1)
168                     key.markAsRightEdge(this);
169             }
170         }
171 
Builder(MoreSuggestionsView paneView)172         public Builder(MoreSuggestionsView paneView) {
173             super(paneView.getContext(), new MoreSuggestionsParam());
174             mPaneView = paneView;
175         }
176 
layout(SuggestedWords suggestions, int fromPos, int maxWidth, int minWidth, int maxRow)177         public Builder layout(SuggestedWords suggestions, int fromPos, int maxWidth,
178                 int minWidth, int maxRow) {
179             final Keyboard keyboard = KeyboardSwitcher.getInstance().getLatinKeyboard();
180             final int xmlId = R.xml.kbd_suggestions_pane_template;
181             load(keyboard.mId.cloneWithNewXml(mResources.getResourceEntryName(xmlId), xmlId));
182             mParams.mVerticalGap = mParams.mTopPadding = keyboard.mVerticalGap / 2;
183 
184             final int count = mParams.layout(suggestions, fromPos, maxWidth, minWidth, maxRow,
185                     mPaneView);
186             mFromPos = fromPos;
187             mToPos = fromPos + count;
188             mSuggestions = suggestions;
189             return this;
190         }
191 
getDebugInfo(SuggestedWords suggestions, int pos)192         private static String getDebugInfo(SuggestedWords suggestions, int pos) {
193             if (!DBG) return null;
194             final SuggestedWordInfo wordInfo = suggestions.getInfo(pos);
195             if (wordInfo == null) return null;
196             final String info = wordInfo.getDebugString();
197             if (TextUtils.isEmpty(info)) return null;
198             return info;
199         }
200 
201         @Override
build()202         public MoreSuggestions build() {
203             final MoreSuggestionsParam params = mParams;
204             for (int pos = mFromPos; pos < mToPos; pos++) {
205                 final int x = params.getX(pos);
206                 final int y = params.getY(pos);
207                 final int width = params.getWidth(pos);
208                 final String word = mSuggestions.getWord(pos).toString();
209                 final String info = getDebugInfo(mSuggestions, pos);
210                 final int index = pos + SUGGESTION_CODE_BASE;
211                 final Key key = new Key(
212                         params, word, info, null, index, null, x, y, width,
213                         params.mDefaultRowHeight);
214                 params.markAsEdgeKey(key, pos);
215                 params.onAddKey(key);
216                 final int columnNumber = params.getColumnNumber(pos);
217                 final int numColumnInRow = params.getNumColumnInRow(pos);
218                 if (columnNumber < numColumnInRow - 1) {
219                     final Key.Spacer spacer = new Key.Spacer(params, params.mDivider, x + width, y,
220                             params.mDividerWidth, params.mDefaultRowHeight);
221                     params.onAddKey(spacer);
222                 }
223             }
224             return new MoreSuggestions(params);
225         }
226     }
227 }
228