ProximityInfo.java revision f098fbbef324df034cc04de04d9b5fe6657238c7
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 17package com.android.inputmethod.keyboard; 18 19import com.android.inputmethod.latin.Utils; 20import com.android.inputmethod.latin.spellcheck.SpellCheckerProximityInfo; 21 22import java.util.Arrays; 23import java.util.Collections; 24import java.util.List; 25 26public class ProximityInfo { 27 public static final int MAX_PROXIMITY_CHARS_SIZE = 16; 28 /** Number of key widths from current touch point to search for nearest keys. */ 29 private static float SEARCH_DISTANCE = 1.2f; 30 private static final int[] EMPTY_INT_ARRAY = new int[0]; 31 32 private final int mGridWidth; 33 private final int mGridHeight; 34 private final int mGridSize; 35 private final int mCellWidth; 36 private final int mCellHeight; 37 // TODO: Find a proper name for mKeyboardMinWidth 38 private final int mKeyboardMinWidth; 39 private final int mKeyboardHeight; 40 private final int[][] mGridNeighbors; 41 42 ProximityInfo( 43 int gridWidth, int gridHeight, int minWidth, int height, int keyWidth, List<Key> keys) { 44 mGridWidth = gridWidth; 45 mGridHeight = gridHeight; 46 mGridSize = mGridWidth * mGridHeight; 47 mCellWidth = (minWidth + mGridWidth - 1) / mGridWidth; 48 mCellHeight = (height + mGridHeight - 1) / mGridHeight; 49 mKeyboardMinWidth = minWidth; 50 mKeyboardHeight = height; 51 mGridNeighbors = new int[mGridSize][]; 52 if (minWidth == 0 || height == 0) { 53 // No proximity required. Keyboard might be mini keyboard. 54 return; 55 } 56 computeNearestNeighbors(keyWidth, keys); 57 } 58 59 public static ProximityInfo getDummyProximityInfo() { 60 return new ProximityInfo(1, 1, 1, 1, 1, Collections.<Key>emptyList()); 61 } 62 63 public static ProximityInfo getSpellCheckerProximityInfo() { 64 final ProximityInfo spellCheckerProximityInfo = getDummyProximityInfo(); 65 spellCheckerProximityInfo.mNativeProximityInfo = 66 spellCheckerProximityInfo.setProximityInfoNative( 67 SpellCheckerProximityInfo.ROW_SIZE, 68 480, 300, 10, 3, SpellCheckerProximityInfo.PROXIMITY); 69 return spellCheckerProximityInfo; 70 } 71 72 private int mNativeProximityInfo; 73 static { 74 Utils.loadNativeLibrary(); 75 } 76 private native int setProximityInfoNative(int maxProximityCharsSize, int displayWidth, 77 int displayHeight, int gridWidth, int gridHeight, int[] proximityCharsArray); 78 private native void releaseProximityInfoNative(int nativeProximityInfo); 79 80 private final void setProximityInfo(int[][] gridNeighborKeyIndexes, int keyboardWidth, 81 int keyboardHeight, List<Key> keys) { 82 int[] proximityCharsArray = new int[mGridSize * MAX_PROXIMITY_CHARS_SIZE]; 83 Arrays.fill(proximityCharsArray, KeyDetector.NOT_A_CODE); 84 for (int i = 0; i < mGridSize; ++i) { 85 final int proximityCharsLength = gridNeighborKeyIndexes[i].length; 86 for (int j = 0; j < proximityCharsLength; ++j) { 87 proximityCharsArray[i * MAX_PROXIMITY_CHARS_SIZE + j] = 88 keys.get(gridNeighborKeyIndexes[i][j]).mCode; 89 } 90 } 91 mNativeProximityInfo = setProximityInfoNative(MAX_PROXIMITY_CHARS_SIZE, 92 keyboardWidth, keyboardHeight, mGridWidth, mGridHeight, proximityCharsArray); 93 } 94 95 public int getNativeProximityInfo() { 96 return mNativeProximityInfo; 97 } 98 99 @Override 100 protected void finalize() throws Throwable { 101 try { 102 if (mNativeProximityInfo != 0) { 103 releaseProximityInfoNative(mNativeProximityInfo); 104 mNativeProximityInfo = 0; 105 } 106 } finally { 107 super.finalize(); 108 } 109 } 110 111 private void computeNearestNeighbors(int defaultWidth, List<Key> keys) { 112 final int thresholdBase = (int) (defaultWidth * SEARCH_DISTANCE); 113 final int threshold = thresholdBase * thresholdBase; 114 // Round-up so we don't have any pixels outside the grid 115 final int[] indices = new int[keys.size()]; 116 final int gridWidth = mGridWidth * mCellWidth; 117 final int gridHeight = mGridHeight * mCellHeight; 118 for (int x = 0; x < gridWidth; x += mCellWidth) { 119 for (int y = 0; y < gridHeight; y += mCellHeight) { 120 final int centerX = x + mCellWidth / 2; 121 final int centerY = y + mCellHeight / 2; 122 int count = 0; 123 for (int i = 0; i < keys.size(); i++) { 124 final Key key = keys.get(i); 125 if (key.squaredDistanceToEdge(centerX, centerY) < threshold) 126 indices[count++] = i; 127 } 128 final int[] cell = new int[count]; 129 System.arraycopy(indices, 0, cell, 0, count); 130 mGridNeighbors[(y / mCellHeight) * mGridWidth + (x / mCellWidth)] = cell; 131 } 132 } 133 setProximityInfo(mGridNeighbors, mKeyboardMinWidth, mKeyboardHeight, keys); 134 } 135 136 public int[] getNearestKeys(int x, int y) { 137 if (mGridNeighbors == null) { 138 return EMPTY_INT_ARRAY; 139 } 140 if (x >= 0 && x < mKeyboardMinWidth && y >= 0 && y < mKeyboardHeight) { 141 int index = (y / mCellHeight) * mGridWidth + (x / mCellWidth); 142 if (index < mGridSize) { 143 return mGridNeighbors[index]; 144 } 145 } 146 return EMPTY_INT_ARRAY; 147 } 148} 149