2009-03-13 22:11:42 +00:00
|
|
|
/*
|
2013-01-08 08:57:26 +00:00
|
|
|
* Copyright (C) 2009 The Android Open Source Project
|
2012-07-25 08:51:43 +00:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*
|
2013-01-08 08:57:26 +00:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2012-07-25 08:51:43 +00:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
2009-03-13 22:11:42 +00:00
|
|
|
|
2011-02-22 08:28:55 +00:00
|
|
|
#define LOG_TAG "LatinIME: jni: BinaryDictionary"
|
2011-01-07 06:01:51 +00:00
|
|
|
|
2013-06-04 10:16:47 +00:00
|
|
|
#include "com_android_inputmethod_latin_BinaryDictionary.h"
|
2009-03-13 22:11:42 +00:00
|
|
|
|
2012-08-03 08:59:26 +00:00
|
|
|
#include <cerrno>
|
2013-06-04 10:16:47 +00:00
|
|
|
#include <cstring> // for memset()
|
2011-01-07 06:01:51 +00:00
|
|
|
#include <fcntl.h>
|
2012-08-03 08:59:26 +00:00
|
|
|
#include <sys/mman.h>
|
2013-06-11 08:04:40 +00:00
|
|
|
#include <unistd.h>
|
2013-05-30 15:02:57 +00:00
|
|
|
|
2013-06-04 10:16:47 +00:00
|
|
|
#include "defines.h"
|
2012-08-10 08:16:39 +00:00
|
|
|
#include "jni.h"
|
|
|
|
#include "jni_common.h"
|
2013-06-11 03:01:49 +00:00
|
|
|
#include "suggest/core/dictionary/binary_dictionary_format_utils.h"
|
2013-06-02 23:34:42 +00:00
|
|
|
#include "suggest/core/dictionary/binary_dictionary_info.h"
|
2013-05-30 15:02:57 +00:00
|
|
|
#include "suggest/core/dictionary/dictionary.h"
|
2013-06-03 01:36:00 +00:00
|
|
|
#include "suggest/core/suggest_options.h"
|
2013-06-11 08:04:40 +00:00
|
|
|
#include "utils/autocorrection_threshold_utils.h"
|
2012-08-10 08:16:39 +00:00
|
|
|
|
2011-02-22 08:28:55 +00:00
|
|
|
namespace latinime {
|
2009-03-13 22:11:42 +00:00
|
|
|
|
2012-08-01 09:03:55 +00:00
|
|
|
class ProximityInfo;
|
|
|
|
|
2012-08-14 05:22:27 +00:00
|
|
|
static void releaseDictBuf(const void *dictBuf, const size_t length, const int fd);
|
2011-07-20 09:42:32 +00:00
|
|
|
|
2013-01-11 16:18:00 +00:00
|
|
|
static jlong latinime_BinaryDictionary_open(JNIEnv *env, jclass clazz, jstring sourceDir,
|
|
|
|
jlong dictOffset, jlong dictSize) {
|
2011-01-07 06:01:51 +00:00
|
|
|
PROF_OPEN;
|
|
|
|
PROF_START(66);
|
2012-08-09 14:23:35 +00:00
|
|
|
const jsize sourceDirUtf8Length = env->GetStringUTFLength(sourceDir);
|
|
|
|
if (sourceDirUtf8Length <= 0) {
|
2012-01-13 09:01:22 +00:00
|
|
|
AKLOGE("DICT: Can't get sourceDir string");
|
2011-01-07 06:01:51 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2012-08-09 14:23:35 +00:00
|
|
|
char sourceDirChars[sourceDirUtf8Length + 1];
|
|
|
|
env->GetStringUTFRegion(sourceDir, 0, env->GetStringLength(sourceDir), sourceDirChars);
|
|
|
|
sourceDirChars[sourceDirUtf8Length] = '\0';
|
2011-01-07 06:01:51 +00:00
|
|
|
int fd = 0;
|
2011-10-28 08:06:58 +00:00
|
|
|
void *dictBuf = 0;
|
2013-06-25 07:03:30 +00:00
|
|
|
int offset = 0;
|
2011-01-09 07:32:58 +00:00
|
|
|
fd = open(sourceDirChars, O_RDONLY);
|
2011-01-07 06:01:51 +00:00
|
|
|
if (fd < 0) {
|
2012-01-13 09:01:22 +00:00
|
|
|
AKLOGE("DICT: Can't open sourceDir. sourceDirChars=%s errno=%d", sourceDirChars, errno);
|
2011-01-07 06:01:51 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
int pagesize = getpagesize();
|
2013-06-25 07:03:30 +00:00
|
|
|
offset = static_cast<int>(dictOffset) % pagesize;
|
|
|
|
int adjDictOffset = static_cast<int>(dictOffset) - offset;
|
|
|
|
int adjDictSize = static_cast<int>(dictSize) + offset;
|
2012-11-01 08:05:08 +00:00
|
|
|
dictBuf = mmap(0, adjDictSize, PROT_READ, MAP_PRIVATE, fd, adjDictOffset);
|
2011-01-07 06:01:51 +00:00
|
|
|
if (dictBuf == MAP_FAILED) {
|
2012-01-13 09:01:22 +00:00
|
|
|
AKLOGE("DICT: Can't mmap dictionary. errno=%d", errno);
|
2011-01-07 06:01:51 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2013-06-25 07:03:30 +00:00
|
|
|
dictBuf = static_cast<char *>(dictBuf) + offset;
|
2011-01-07 06:01:51 +00:00
|
|
|
if (!dictBuf) {
|
2012-01-13 09:01:22 +00:00
|
|
|
AKLOGE("DICT: dictBuf is null");
|
2011-01-07 06:01:51 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2011-10-28 08:06:58 +00:00
|
|
|
Dictionary *dictionary = 0;
|
2013-06-02 23:34:42 +00:00
|
|
|
if (BinaryDictionaryFormat::UNKNOWN_VERSION
|
|
|
|
== BinaryDictionaryFormat::detectFormatVersion(static_cast<uint8_t *>(dictBuf),
|
2013-05-08 06:24:20 +00:00
|
|
|
static_cast<int>(dictSize))) {
|
2012-01-13 09:01:22 +00:00
|
|
|
AKLOGE("DICT: dictionary format is unknown, bad magic number");
|
2013-06-25 07:03:30 +00:00
|
|
|
releaseDictBuf(static_cast<const char *>(dictBuf) - offset, adjDictSize, fd);
|
2011-07-20 09:42:32 +00:00
|
|
|
} else {
|
2013-06-25 07:03:30 +00:00
|
|
|
dictionary = new Dictionary(dictBuf, static_cast<int>(dictSize), fd, offset);
|
2011-07-20 09:42:32 +00:00
|
|
|
}
|
2011-01-07 06:01:51 +00:00
|
|
|
PROF_END(66);
|
|
|
|
PROF_CLOSE;
|
2013-01-29 16:04:42 +00:00
|
|
|
return reinterpret_cast<jlong>(dictionary);
|
2009-03-13 22:11:42 +00:00
|
|
|
}
|
|
|
|
|
2013-01-11 16:18:00 +00:00
|
|
|
static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jclass clazz, jlong dict,
|
2012-08-08 12:23:25 +00:00
|
|
|
jlong proximityInfo, jlong dicTraverseSession, jintArray xCoordinatesArray,
|
2012-08-10 08:16:39 +00:00
|
|
|
jintArray yCoordinatesArray, jintArray timesArray, jintArray pointerIdsArray,
|
2013-05-24 17:21:04 +00:00
|
|
|
jintArray inputCodePointsArray, jint inputSize, jint commitPoint, jintArray suggestOptions,
|
|
|
|
jintArray prevWordCodePointsForBigrams, jintArray outputCodePointsArray,
|
|
|
|
jintArray scoresArray, jintArray spaceIndicesArray, jintArray outputTypesArray) {
|
2012-08-14 05:22:27 +00:00
|
|
|
Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
|
2011-01-07 06:01:51 +00:00
|
|
|
if (!dictionary) return 0;
|
2012-08-14 05:22:27 +00:00
|
|
|
ProximityInfo *pInfo = reinterpret_cast<ProximityInfo *>(proximityInfo);
|
2013-06-03 07:12:20 +00:00
|
|
|
DicTraverseSession *traverseSession =
|
|
|
|
reinterpret_cast<DicTraverseSession *>(dicTraverseSession);
|
2012-08-10 08:16:39 +00:00
|
|
|
|
|
|
|
// Input values
|
2013-01-11 16:18:00 +00:00
|
|
|
int xCoordinates[inputSize];
|
|
|
|
int yCoordinates[inputSize];
|
|
|
|
int times[inputSize];
|
|
|
|
int pointerIds[inputSize];
|
2012-08-10 08:16:39 +00:00
|
|
|
const jsize inputCodePointsLength = env->GetArrayLength(inputCodePointsArray);
|
|
|
|
int inputCodePoints[inputCodePointsLength];
|
|
|
|
const jsize prevWordCodePointsLength =
|
|
|
|
prevWordCodePointsForBigrams ? env->GetArrayLength(prevWordCodePointsForBigrams) : 0;
|
|
|
|
int prevWordCodePointsInternal[prevWordCodePointsLength];
|
|
|
|
int *prevWordCodePoints = 0;
|
2013-01-11 16:18:00 +00:00
|
|
|
env->GetIntArrayRegion(xCoordinatesArray, 0, inputSize, xCoordinates);
|
|
|
|
env->GetIntArrayRegion(yCoordinatesArray, 0, inputSize, yCoordinates);
|
|
|
|
env->GetIntArrayRegion(timesArray, 0, inputSize, times);
|
|
|
|
env->GetIntArrayRegion(pointerIdsArray, 0, inputSize, pointerIds);
|
2012-08-10 08:16:39 +00:00
|
|
|
env->GetIntArrayRegion(inputCodePointsArray, 0, inputCodePointsLength, inputCodePoints);
|
|
|
|
if (prevWordCodePointsForBigrams) {
|
|
|
|
env->GetIntArrayRegion(prevWordCodePointsForBigrams, 0, prevWordCodePointsLength,
|
|
|
|
prevWordCodePointsInternal);
|
|
|
|
prevWordCodePoints = prevWordCodePointsInternal;
|
|
|
|
}
|
|
|
|
|
2013-05-24 17:21:04 +00:00
|
|
|
const jsize numberOfOptions = env->GetArrayLength(suggestOptions);
|
|
|
|
int options[numberOfOptions];
|
|
|
|
env->GetIntArrayRegion(suggestOptions, 0, numberOfOptions, options);
|
2013-05-30 00:18:03 +00:00
|
|
|
SuggestOptions givenSuggestOptions(options, numberOfOptions);
|
2013-05-24 17:21:04 +00:00
|
|
|
|
2012-08-10 08:16:39 +00:00
|
|
|
// Output values
|
2013-01-11 16:18:00 +00:00
|
|
|
/* By the way, let's check the output array length here to make sure */
|
2012-10-29 09:06:22 +00:00
|
|
|
const jsize outputCodePointsLength = env->GetArrayLength(outputCodePointsArray);
|
2013-01-11 16:18:00 +00:00
|
|
|
if (outputCodePointsLength != (MAX_WORD_LENGTH * MAX_RESULTS)) {
|
|
|
|
AKLOGE("Invalid outputCodePointsLength: %d", outputCodePointsLength);
|
|
|
|
ASSERT(false);
|
|
|
|
return 0;
|
|
|
|
}
|
2012-08-10 08:16:39 +00:00
|
|
|
const jsize scoresLength = env->GetArrayLength(scoresArray);
|
2013-01-11 16:18:00 +00:00
|
|
|
if (scoresLength != MAX_RESULTS) {
|
|
|
|
AKLOGE("Invalid scoresLength: %d", scoresLength);
|
2013-01-11 09:59:01 +00:00
|
|
|
ASSERT(false);
|
|
|
|
return 0;
|
|
|
|
}
|
2013-01-11 16:18:00 +00:00
|
|
|
int outputCodePoints[outputCodePointsLength];
|
2012-08-10 08:16:39 +00:00
|
|
|
int scores[scoresLength];
|
|
|
|
const jsize spaceIndicesLength = env->GetArrayLength(spaceIndicesArray);
|
|
|
|
int spaceIndices[spaceIndicesLength];
|
|
|
|
const jsize outputTypesLength = env->GetArrayLength(outputTypesArray);
|
|
|
|
int outputTypes[outputTypesLength];
|
2012-10-29 09:06:22 +00:00
|
|
|
memset(outputCodePoints, 0, sizeof(outputCodePoints));
|
2012-08-24 05:51:15 +00:00
|
|
|
memset(scores, 0, sizeof(scores));
|
|
|
|
memset(spaceIndices, 0, sizeof(spaceIndices));
|
|
|
|
memset(outputTypes, 0, sizeof(outputTypes));
|
2012-07-11 03:07:44 +00:00
|
|
|
|
|
|
|
int count;
|
2013-05-30 00:18:03 +00:00
|
|
|
if (givenSuggestOptions.isGesture() || inputSize > 0) {
|
2012-08-08 12:23:25 +00:00
|
|
|
count = dictionary->getSuggestions(pInfo, traverseSession, xCoordinates, yCoordinates,
|
2013-01-11 16:18:00 +00:00
|
|
|
times, pointerIds, inputCodePoints, inputSize, prevWordCodePoints,
|
2013-05-30 00:18:03 +00:00
|
|
|
prevWordCodePointsLength, commitPoint, &givenSuggestOptions, outputCodePoints,
|
|
|
|
scores, spaceIndices, outputTypes);
|
2012-07-11 03:07:44 +00:00
|
|
|
} else {
|
2012-08-10 08:16:39 +00:00
|
|
|
count = dictionary->getBigrams(prevWordCodePoints, prevWordCodePointsLength,
|
2013-01-11 16:18:00 +00:00
|
|
|
inputCodePoints, inputSize, outputCodePoints, scores, outputTypes);
|
2012-07-11 03:07:44 +00:00
|
|
|
}
|
|
|
|
|
2012-08-10 08:16:39 +00:00
|
|
|
// Copy back the output values
|
2012-10-29 09:06:22 +00:00
|
|
|
env->SetIntArrayRegion(outputCodePointsArray, 0, outputCodePointsLength, outputCodePoints);
|
2012-08-10 08:16:39 +00:00
|
|
|
env->SetIntArrayRegion(scoresArray, 0, scoresLength, scores);
|
|
|
|
env->SetIntArrayRegion(spaceIndicesArray, 0, spaceIndicesLength, spaceIndices);
|
|
|
|
env->SetIntArrayRegion(outputTypesArray, 0, outputTypesLength, outputTypes);
|
|
|
|
|
2009-03-13 22:11:42 +00:00
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2013-03-18 04:08:31 +00:00
|
|
|
static jint latinime_BinaryDictionary_getProbability(JNIEnv *env, jclass clazz, jlong dict,
|
2012-08-09 15:40:34 +00:00
|
|
|
jintArray wordArray) {
|
2012-08-14 05:22:27 +00:00
|
|
|
Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
|
2012-08-09 15:40:34 +00:00
|
|
|
if (!dictionary) return 0;
|
|
|
|
const jsize codePointLength = env->GetArrayLength(wordArray);
|
|
|
|
int codePoints[codePointLength];
|
|
|
|
env->GetIntArrayRegion(wordArray, 0, codePointLength, codePoints);
|
2013-03-18 04:08:31 +00:00
|
|
|
return dictionary->getProbability(codePoints, codePointLength);
|
2009-03-13 22:11:42 +00:00
|
|
|
}
|
|
|
|
|
2013-01-11 16:18:00 +00:00
|
|
|
static jboolean latinime_BinaryDictionary_isValidBigram(JNIEnv *env, jclass clazz, jlong dict,
|
2012-04-27 06:50:21 +00:00
|
|
|
jintArray wordArray1, jintArray wordArray2) {
|
2012-08-14 05:22:27 +00:00
|
|
|
Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
|
2013-01-29 16:04:42 +00:00
|
|
|
if (!dictionary) return JNI_FALSE;
|
2012-08-09 15:40:34 +00:00
|
|
|
const jsize codePointLength1 = env->GetArrayLength(wordArray1);
|
|
|
|
const jsize codePointLength2 = env->GetArrayLength(wordArray2);
|
|
|
|
int codePoints1[codePointLength1];
|
|
|
|
int codePoints2[codePointLength2];
|
|
|
|
env->GetIntArrayRegion(wordArray1, 0, codePointLength1, codePoints1);
|
|
|
|
env->GetIntArrayRegion(wordArray2, 0, codePointLength2, codePoints2);
|
|
|
|
return dictionary->isValidBigram(codePoints1, codePointLength1, codePoints2, codePointLength2);
|
2012-04-27 06:50:21 +00:00
|
|
|
}
|
|
|
|
|
2013-01-11 16:18:00 +00:00
|
|
|
static jfloat latinime_BinaryDictionary_calcNormalizedScore(JNIEnv *env, jclass clazz,
|
2012-10-29 09:06:22 +00:00
|
|
|
jintArray before, jintArray after, jint score) {
|
2012-08-09 15:40:34 +00:00
|
|
|
jsize beforeLength = env->GetArrayLength(before);
|
|
|
|
jsize afterLength = env->GetArrayLength(after);
|
2012-10-29 09:06:22 +00:00
|
|
|
int beforeCodePoints[beforeLength];
|
|
|
|
int afterCodePoints[afterLength];
|
|
|
|
env->GetIntArrayRegion(before, 0, beforeLength, beforeCodePoints);
|
|
|
|
env->GetIntArrayRegion(after, 0, afterLength, afterCodePoints);
|
2013-06-11 08:04:40 +00:00
|
|
|
return AutocorrectionThresholdUtils::calcNormalizedScore(beforeCodePoints, beforeLength,
|
2012-10-29 09:06:22 +00:00
|
|
|
afterCodePoints, afterLength, score);
|
2012-01-12 09:44:40 +00:00
|
|
|
}
|
|
|
|
|
2013-01-11 16:18:00 +00:00
|
|
|
static jint latinime_BinaryDictionary_editDistance(JNIEnv *env, jclass clazz, jintArray before,
|
2012-10-29 09:06:22 +00:00
|
|
|
jintArray after) {
|
2012-08-09 15:40:34 +00:00
|
|
|
jsize beforeLength = env->GetArrayLength(before);
|
|
|
|
jsize afterLength = env->GetArrayLength(after);
|
2012-10-29 09:06:22 +00:00
|
|
|
int beforeCodePoints[beforeLength];
|
|
|
|
int afterCodePoints[afterLength];
|
|
|
|
env->GetIntArrayRegion(before, 0, beforeLength, beforeCodePoints);
|
|
|
|
env->GetIntArrayRegion(after, 0, afterLength, afterCodePoints);
|
2013-06-11 08:04:40 +00:00
|
|
|
return AutocorrectionThresholdUtils::editDistance(beforeCodePoints, beforeLength,
|
2012-10-29 09:06:22 +00:00
|
|
|
afterCodePoints, afterLength);
|
2012-01-12 09:44:40 +00:00
|
|
|
}
|
|
|
|
|
2013-01-11 16:18:00 +00:00
|
|
|
static void latinime_BinaryDictionary_close(JNIEnv *env, jclass clazz, jlong dict) {
|
2012-08-14 05:22:27 +00:00
|
|
|
Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
|
2011-01-07 06:01:51 +00:00
|
|
|
if (!dictionary) return;
|
2013-06-25 07:03:30 +00:00
|
|
|
const BinaryDictionaryInfo *const binaryDictionaryInfo = dictionary->getBinaryDictionaryInfo();
|
|
|
|
const int dictBufOffset = binaryDictionaryInfo->getDictBufOffset();
|
|
|
|
const void *dictBuf = binaryDictionaryInfo->getDictBuf();
|
2011-01-07 06:01:51 +00:00
|
|
|
if (!dictBuf) return;
|
2013-06-25 07:03:30 +00:00
|
|
|
releaseDictBuf(static_cast<const char *>(dictBuf) - dictBufOffset,
|
|
|
|
binaryDictionaryInfo->getDictSize() + dictBufOffset,
|
|
|
|
binaryDictionaryInfo->getMmapFd());
|
2011-07-20 09:42:32 +00:00
|
|
|
delete dictionary;
|
|
|
|
}
|
|
|
|
|
2012-08-14 05:22:27 +00:00
|
|
|
static void releaseDictBuf(const void *dictBuf, const size_t length, const int fd) {
|
|
|
|
int ret = munmap(const_cast<void *>(dictBuf), length);
|
2011-01-07 06:01:51 +00:00
|
|
|
if (ret != 0) {
|
2012-01-13 09:01:22 +00:00
|
|
|
AKLOGE("DICT: Failure in munmap. ret=%d errno=%d", ret, errno);
|
2011-01-07 06:01:51 +00:00
|
|
|
}
|
2011-07-20 09:42:32 +00:00
|
|
|
ret = close(fd);
|
2011-01-07 06:01:51 +00:00
|
|
|
if (ret != 0) {
|
2012-01-13 09:01:22 +00:00
|
|
|
AKLOGE("DICT: Failure in close. ret=%d errno=%d", ret, errno);
|
2011-01-07 06:01:51 +00:00
|
|
|
}
|
2009-03-13 22:11:42 +00:00
|
|
|
}
|
|
|
|
|
2013-06-04 10:16:47 +00:00
|
|
|
static const JNINativeMethod sMethods[] = {
|
|
|
|
{
|
|
|
|
const_cast<char *>("openNative"),
|
|
|
|
const_cast<char *>("(Ljava/lang/String;JJ)J"),
|
|
|
|
reinterpret_cast<void *>(latinime_BinaryDictionary_open)
|
|
|
|
},
|
|
|
|
{
|
|
|
|
const_cast<char *>("closeNative"),
|
|
|
|
const_cast<char *>("(J)V"),
|
|
|
|
reinterpret_cast<void *>(latinime_BinaryDictionary_close)
|
|
|
|
},
|
|
|
|
{
|
|
|
|
const_cast<char *>("getSuggestionsNative"),
|
|
|
|
const_cast<char *>("(JJJ[I[I[I[I[III[I[I[I[I[I[I)I"),
|
|
|
|
reinterpret_cast<void *>(latinime_BinaryDictionary_getSuggestions)
|
|
|
|
},
|
|
|
|
{
|
|
|
|
const_cast<char *>("getProbabilityNative"),
|
|
|
|
const_cast<char *>("(J[I)I"),
|
|
|
|
reinterpret_cast<void *>(latinime_BinaryDictionary_getProbability)
|
|
|
|
},
|
|
|
|
{
|
|
|
|
const_cast<char *>("isValidBigramNative"),
|
|
|
|
const_cast<char *>("(J[I[I)Z"),
|
|
|
|
reinterpret_cast<void *>(latinime_BinaryDictionary_isValidBigram)
|
|
|
|
},
|
|
|
|
{
|
|
|
|
const_cast<char *>("calcNormalizedScoreNative"),
|
|
|
|
const_cast<char *>("([I[II)F"),
|
|
|
|
reinterpret_cast<void *>(latinime_BinaryDictionary_calcNormalizedScore)
|
|
|
|
},
|
|
|
|
{
|
|
|
|
const_cast<char *>("editDistanceNative"),
|
|
|
|
const_cast<char *>("([I[I)I"),
|
|
|
|
reinterpret_cast<void *>(latinime_BinaryDictionary_editDistance)
|
|
|
|
}
|
2009-03-13 22:11:42 +00:00
|
|
|
};
|
|
|
|
|
2011-02-22 08:28:55 +00:00
|
|
|
int register_BinaryDictionary(JNIEnv *env) {
|
2012-07-25 08:51:43 +00:00
|
|
|
const char *const kClassPathName = "com/android/inputmethod/latin/BinaryDictionary";
|
2012-10-08 02:46:14 +00:00
|
|
|
return registerNativeMethods(env, kClassPathName, sMethods, NELEMS(sMethods));
|
2009-03-13 22:11:42 +00:00
|
|
|
}
|
2011-06-18 04:09:55 +00:00
|
|
|
} // namespace latinime
|