aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/ActionBatch.java48
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java6
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java12
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java48
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionary.java13
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFactory.java8
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java2
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java20
-rw-r--r--java/src/com/android/inputmethod/latin/RichInputConnection.java15
-rw-r--r--java/src/com/android/inputmethod/latin/Settings.java4
-rw-r--r--java/src/com/android/inputmethod/latin/SubtypeLocale.java4
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java58
-rw-r--r--java/src/com/android/inputmethod/latin/utils/DebugLogUtils.java (renamed from java/src/com/android/inputmethod/latin/utils/LogUtils.java)4
-rw-r--r--java/src/com/android/inputmethod/latin/utils/UserLogRingCharBuffer.java134
-rw-r--r--java/src/com/android/inputmethod/latin/utils/Utils.java136
15 files changed, 268 insertions, 244 deletions
diff --git a/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java b/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java
index be9f87930..3bed2c7a0 100644
--- a/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java
+++ b/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java
@@ -28,7 +28,7 @@ import android.util.Log;
import com.android.inputmethod.compat.DownloadManagerCompatUtils;
import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.utils.LogUtils;
+import com.android.inputmethod.latin.utils.DebugLogUtils;
import com.android.inputmethod.latin.utils.Utils;
import java.util.LinkedList;
@@ -100,7 +100,7 @@ public final class ActionBatch {
final boolean mForceStartNow;
public StartDownloadAction(final String clientId,
final WordListMetadata wordList, final boolean forceStartNow) {
- LogUtils.l("New download action for client ", clientId, " : ", wordList);
+ DebugLogUtils.l("New download action for client ", clientId, " : ", wordList);
mClientId = clientId;
mWordList = wordList;
mForceStartNow = forceStartNow;
@@ -112,7 +112,7 @@ public final class ActionBatch {
Log.e(TAG, "UpdateAction with a null parameter!");
return;
}
- LogUtils.l("Downloading word list");
+ DebugLogUtils.l("Downloading word list");
final SQLiteDatabase db = MetadataDbHelper.getDb(context, mClientId);
final ContentValues values = MetadataDbHelper.getContentValuesByWordListId(db,
mWordList.mId, mWordList.mVersion);
@@ -134,7 +134,7 @@ public final class ActionBatch {
+ " for an upgrade action. Fall back to download.");
}
// Download it.
- LogUtils.l("Upgrade word list, downloading", mWordList.mRemoteFilename);
+ DebugLogUtils.l("Upgrade word list, downloading", mWordList.mRemoteFilename);
// TODO: if DownloadManager is disabled or not installed, download by ourselves
if (null == manager) return;
@@ -180,7 +180,7 @@ public final class ActionBatch {
final long downloadId = UpdateHandler.registerDownloadRequest(manager, request, db,
mWordList.mId, mWordList.mVersion);
- LogUtils.l("Starting download of", uri, "with id", downloadId);
+ DebugLogUtils.l("Starting download of", uri, "with id", downloadId);
PrivateLog.log("Starting download of " + uri + ", id : " + downloadId);
}
}
@@ -197,7 +197,7 @@ public final class ActionBatch {
public InstallAfterDownloadAction(final String clientId,
final ContentValues wordListValues) {
- LogUtils.l("New InstallAfterDownloadAction for client ", clientId, " : ",
+ DebugLogUtils.l("New InstallAfterDownloadAction for client ", clientId, " : ",
wordListValues);
mClientId = clientId;
mWordListValues = wordListValues;
@@ -216,7 +216,7 @@ public final class ActionBatch {
+ " for an InstallAfterDownload action. Bailing out.");
return;
}
- LogUtils.l("Setting word list as installed");
+ DebugLogUtils.l("Setting word list as installed");
final SQLiteDatabase db = MetadataDbHelper.getDb(context, mClientId);
MetadataDbHelper.markEntryAsFinishedDownloadingAndInstalled(db, mWordListValues);
}
@@ -232,7 +232,7 @@ public final class ActionBatch {
final WordListMetadata mWordList;
public EnableAction(final String clientId, final WordListMetadata wordList) {
- LogUtils.l("New EnableAction for client ", clientId, " : ", wordList);
+ DebugLogUtils.l("New EnableAction for client ", clientId, " : ", wordList);
mClientId = clientId;
mWordList = wordList;
}
@@ -243,7 +243,7 @@ public final class ActionBatch {
Log.e(TAG, "EnableAction with a null parameter!");
return;
}
- LogUtils.l("Enabling word list");
+ DebugLogUtils.l("Enabling word list");
final SQLiteDatabase db = MetadataDbHelper.getDb(context, mClientId);
final ContentValues values = MetadataDbHelper.getContentValuesByWordListId(db,
mWordList.mId, mWordList.mVersion);
@@ -267,7 +267,7 @@ public final class ActionBatch {
// The word list to disable. May not be null.
final WordListMetadata mWordList;
public DisableAction(final String clientId, final WordListMetadata wordlist) {
- LogUtils.l("New Disable action for client ", clientId, " : ", wordlist);
+ DebugLogUtils.l("New Disable action for client ", clientId, " : ", wordlist);
mClientId = clientId;
mWordList = wordlist;
}
@@ -278,7 +278,7 @@ public final class ActionBatch {
Log.e(TAG, "DisableAction with a null word list!");
return;
}
- LogUtils.l("Disabling word list : " + mWordList);
+ DebugLogUtils.l("Disabling word list : " + mWordList);
final SQLiteDatabase db = MetadataDbHelper.getDb(context, mClientId);
final ContentValues values = MetadataDbHelper.getContentValuesByWordListId(db,
mWordList.mId, mWordList.mVersion);
@@ -314,7 +314,7 @@ public final class ActionBatch {
// The word list to make available. May not be null.
final WordListMetadata mWordList;
public MakeAvailableAction(final String clientId, final WordListMetadata wordlist) {
- LogUtils.l("New MakeAvailable action", clientId, " : ", wordlist);
+ DebugLogUtils.l("New MakeAvailable action", clientId, " : ", wordlist);
mClientId = clientId;
mWordList = wordlist;
}
@@ -331,7 +331,7 @@ public final class ActionBatch {
Log.e(TAG, "Unexpected state of the word list '" + mWordList.mId + "' "
+ " for a makeavailable action. Marking as available anyway.");
}
- LogUtils.l("Making word list available : " + mWordList);
+ DebugLogUtils.l("Making word list available : " + mWordList);
// If mLocalFilename is null, then it's a remote file that hasn't been downloaded
// yet, so we set the local filename to the empty string.
final ContentValues values = MetadataDbHelper.makeContentValues(0,
@@ -363,7 +363,7 @@ public final class ActionBatch {
// The word list to mark pre-installed. May not be null.
final WordListMetadata mWordList;
public MarkPreInstalledAction(final String clientId, final WordListMetadata wordlist) {
- LogUtils.l("New MarkPreInstalled action", clientId, " : ", wordlist);
+ DebugLogUtils.l("New MarkPreInstalled action", clientId, " : ", wordlist);
mClientId = clientId;
mWordList = wordlist;
}
@@ -380,7 +380,7 @@ public final class ActionBatch {
Log.e(TAG, "Unexpected state of the word list '" + mWordList.mId + "' "
+ " for a markpreinstalled action. Marking as preinstalled anyway.");
}
- LogUtils.l("Marking word list preinstalled : " + mWordList);
+ DebugLogUtils.l("Marking word list preinstalled : " + mWordList);
// This word list is pre-installed : we don't have its file. We should reset
// the local file name to the empty string so that we don't try to open it
// accidentally. The remote filename may be set by the application if it so wishes.
@@ -404,7 +404,7 @@ public final class ActionBatch {
private final String mClientId;
final WordListMetadata mWordList;
public UpdateDataAction(final String clientId, final WordListMetadata wordlist) {
- LogUtils.l("New UpdateData action for client ", clientId, " : ", wordlist);
+ DebugLogUtils.l("New UpdateData action for client ", clientId, " : ", wordlist);
mClientId = clientId;
mWordList = wordlist;
}
@@ -422,7 +422,7 @@ public final class ActionBatch {
Log.e(TAG, "Trying to update data about a non-existing word list. Bailing out.");
return;
}
- LogUtils.l("Updating data about a word list : " + mWordList);
+ DebugLogUtils.l("Updating data about a word list : " + mWordList);
final ContentValues values = MetadataDbHelper.makeContentValues(
oldValues.getAsInteger(MetadataDbHelper.PENDINGID_COLUMN),
oldValues.getAsInteger(MetadataDbHelper.TYPE_COLUMN),
@@ -456,7 +456,7 @@ public final class ActionBatch {
final boolean mHasNewerVersion;
public ForgetAction(final String clientId, final WordListMetadata wordlist,
final boolean hasNewerVersion) {
- LogUtils.l("New TryRemove action for client ", clientId, " : ", wordlist);
+ DebugLogUtils.l("New TryRemove action for client ", clientId, " : ", wordlist);
mClientId = clientId;
mWordList = wordlist;
mHasNewerVersion = hasNewerVersion;
@@ -468,7 +468,7 @@ public final class ActionBatch {
Log.e(TAG, "TryRemoveAction with a null word list!");
return;
}
- LogUtils.l("Trying to remove word list : " + mWordList);
+ DebugLogUtils.l("Trying to remove word list : " + mWordList);
final SQLiteDatabase db = MetadataDbHelper.getDb(context, mClientId);
final ContentValues values = MetadataDbHelper.getContentValuesByWordListId(db,
mWordList.mId, mWordList.mVersion);
@@ -528,7 +528,7 @@ public final class ActionBatch {
// The word list to delete. May not be null.
final WordListMetadata mWordList;
public StartDeleteAction(final String clientId, final WordListMetadata wordlist) {
- LogUtils.l("New StartDelete action for client ", clientId, " : ", wordlist);
+ DebugLogUtils.l("New StartDelete action for client ", clientId, " : ", wordlist);
mClientId = clientId;
mWordList = wordlist;
}
@@ -539,7 +539,7 @@ public final class ActionBatch {
Log.e(TAG, "StartDeleteAction with a null word list!");
return;
}
- LogUtils.l("Trying to delete word list : " + mWordList);
+ DebugLogUtils.l("Trying to delete word list : " + mWordList);
final SQLiteDatabase db = MetadataDbHelper.getDb(context, mClientId);
final ContentValues values = MetadataDbHelper.getContentValuesByWordListId(db,
mWordList.mId, mWordList.mVersion);
@@ -567,7 +567,7 @@ public final class ActionBatch {
// The word list to delete. May not be null.
final WordListMetadata mWordList;
public FinishDeleteAction(final String clientId, final WordListMetadata wordlist) {
- LogUtils.l("New FinishDelete action for client", clientId, " : ", wordlist);
+ DebugLogUtils.l("New FinishDelete action for client", clientId, " : ", wordlist);
mClientId = clientId;
mWordList = wordlist;
}
@@ -578,7 +578,7 @@ public final class ActionBatch {
Log.e(TAG, "FinishDeleteAction with a null word list!");
return;
}
- LogUtils.l("Trying to delete word list : " + mWordList);
+ DebugLogUtils.l("Trying to delete word list : " + mWordList);
final SQLiteDatabase db = MetadataDbHelper.getDb(context, mClientId);
final ContentValues values = MetadataDbHelper.getContentValuesByWordListId(db,
mWordList.mId, mWordList.mVersion);
@@ -635,7 +635,7 @@ public final class ActionBatch {
* @param reporter a Reporter to send errors to.
*/
public void execute(final Context context, final ProblemReporter reporter) {
- LogUtils.l("Executing a batch of actions");
+ DebugLogUtils.l("Executing a batch of actions");
Queue<Action> remainingActions = mActions;
while (!remainingActions.isEmpty()) {
final Action a = remainingActions.poll();
diff --git a/java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java b/java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java
index 4aa4d4b43..62b905dc5 100644
--- a/java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java
+++ b/java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java
@@ -31,7 +31,7 @@ import android.text.TextUtils;
import android.util.Log;
import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.utils.LogUtils;
+import com.android.inputmethod.latin.utils.DebugLogUtils;
import java.io.File;
import java.io.FileNotFoundException;
@@ -220,7 +220,7 @@ public final class DictionaryProvider extends ContentProvider {
@Override
public Cursor query(final Uri uri, final String[] projection, final String selection,
final String[] selectionArgs, final String sortOrder) {
- LogUtils.l("Uri =", uri);
+ DebugLogUtils.l("Uri =", uri);
PrivateLog.log("Query : " + uri);
final String clientId = getClientId(uri);
final int match = matchUri(uri);
@@ -228,7 +228,7 @@ public final class DictionaryProvider extends ContentProvider {
case DICTIONARY_V1_WHOLE_LIST:
case DICTIONARY_V2_WHOLE_LIST:
final Cursor c = MetadataDbHelper.queryDictionaries(getContext(), clientId);
- LogUtils.l("List of dictionaries with count", c.getCount());
+ DebugLogUtils.l("List of dictionaries with count", c.getCount());
PrivateLog.log("Returned a list of " + c.getCount() + " items");
return c;
case DICTIONARY_V2_DICT_INFO:
diff --git a/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java b/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java
index c6cadb823..99cc5b924 100644
--- a/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java
+++ b/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java
@@ -25,7 +25,7 @@ import android.text.TextUtils;
import android.util.Log;
import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.utils.LogUtils;
+import com.android.inputmethod.latin.utils.DebugLogUtils;
import java.io.File;
import java.util.ArrayList;
@@ -773,13 +773,13 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
if (TextUtils.isEmpty(valuesClientId) || null == valuesMetadataUri
|| null == valuesMetadataAdditionalId) {
// We need all these columns to be filled in
- LogUtils.l("Missing parameter for updateClientInfo");
+ DebugLogUtils.l("Missing parameter for updateClientInfo");
return;
}
if (!clientId.equals(valuesClientId)) {
// Mismatch! The client violates the protocol.
- LogUtils.l("Received an updateClientInfo request for ", clientId, " but the values "
- + "contain a different ID : ", valuesClientId);
+ DebugLogUtils.l("Received an updateClientInfo request for ", clientId,
+ " but the values " + "contain a different ID : ", valuesClientId);
return;
}
final SQLiteDatabase defaultDb = getDb(context, "");
@@ -848,7 +848,7 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
final ContentValues r) {
switch (r.getAsInteger(TYPE_COLUMN)) {
case TYPE_BULK:
- LogUtils.l("Ended processing a wordlist");
+ DebugLogUtils.l("Ended processing a wordlist");
// Updating a bulk word list is a three-step operation:
// - Add the new entry to the table
// - Remove the old entry from the table
@@ -870,7 +870,7 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
// the phone is suddenly cut during an update.
final int filenameIndex = c.getColumnIndex(LOCAL_FILENAME_COLUMN);
do {
- LogUtils.l("Setting for removal", c.getString(filenameIndex));
+ DebugLogUtils.l("Setting for removal", c.getString(filenameIndex));
filenames.add(c.getString(filenameIndex));
} while (c.moveToNext());
}
diff --git a/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java b/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java
index 936d00d25..719f24e59 100644
--- a/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java
+++ b/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java
@@ -38,7 +38,7 @@ import android.util.Log;
import com.android.inputmethod.compat.ConnectivityManagerCompatUtils;
import com.android.inputmethod.compat.DownloadManagerCompatUtils;
import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.utils.LogUtils;
+import com.android.inputmethod.latin.utils.DebugLogUtils;
import com.android.inputmethod.latin.utils.Utils;
import java.io.File;
@@ -185,8 +185,8 @@ public final class UpdateHandler {
final String clientId = cursor.getString(0);
final String metadataUri =
MetadataDbHelper.getMetadataUriAsString(context, clientId);
- PrivateLog.log("Update for clientId " + LogUtils.s(clientId));
- LogUtils.l("Update for clientId", clientId, " which uses URI ", metadataUri);
+ PrivateLog.log("Update for clientId " + DebugLogUtils.s(clientId));
+ DebugLogUtils.l("Update for clientId", clientId, " which uses URI ", metadataUri);
uris.add(metadataUri);
} while (cursor.moveToNext());
} finally {
@@ -213,14 +213,14 @@ public final class UpdateHandler {
*/
private static void updateClientsWithMetadataUri(final Context context,
final boolean updateNow, final String metadataUri) {
- PrivateLog.log("Update for metadata URI " + LogUtils.s(metadataUri));
+ PrivateLog.log("Update for metadata URI " + DebugLogUtils.s(metadataUri));
// Adding a disambiguator to circumvent a bug in older versions of DownloadManager.
// DownloadManager also stupidly cuts the extension to replace with its own that it
// gets from the content-type. We need to circumvent this.
final String disambiguator = "#" + System.currentTimeMillis()
+ Utils.getVersionName(context) + ".json";
final Request metadataRequest = new Request(Uri.parse(metadataUri + disambiguator));
- LogUtils.l("Request =", metadataRequest);
+ DebugLogUtils.l("Request =", metadataRequest);
final Resources res = context.getResources();
// By default, download over roaming is allowed and all network types are allowed too.
@@ -256,7 +256,7 @@ public final class UpdateHandler {
final long downloadId;
synchronized (sSharedIdProtector) {
downloadId = manager.enqueue(metadataRequest);
- LogUtils.l("Metadata download requested with id", downloadId);
+ DebugLogUtils.l("Metadata download requested with id", downloadId);
// If there is already a download in progress, it's been there for a while and
// there is probably something wrong with download manager. It's best to just
// overwrite the id and request it again. If the old one happens to finish
@@ -328,11 +328,11 @@ public final class UpdateHandler {
*/
public static long registerDownloadRequest(final DownloadManager manager, final Request request,
final SQLiteDatabase db, final String id, final int version) {
- LogUtils.l("RegisterDownloadRequest for word list id : ", id, ", version ", version);
+ DebugLogUtils.l("RegisterDownloadRequest for word list id : ", id, ", version ", version);
final long downloadId;
synchronized (sSharedIdProtector) {
downloadId = manager.enqueue(request);
- LogUtils.l("Download requested with id", downloadId);
+ DebugLogUtils.l("Download requested with id", downloadId);
MetadataDbHelper.markEntryAsDownloading(db, id, version, downloadId);
}
return downloadId;
@@ -418,7 +418,7 @@ public final class UpdateHandler {
// Get and check the ID of the file that was downloaded
final long fileId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, NOT_AN_ID);
PrivateLog.log("Download finished with id " + fileId);
- LogUtils.l("DownloadFinished with id", fileId);
+ DebugLogUtils.l("DownloadFinished with id", fileId);
if (NOT_AN_ID == fileId) return; // Spurious wake-up: ignore
final DownloadManager manager =
@@ -428,7 +428,7 @@ public final class UpdateHandler {
final ArrayList<DownloadRecord> recordList =
getDownloadRecordsForCompletedDownloadInfo(context, downloadInfo);
if (null == recordList) return; // It was someone else's download.
- LogUtils.l("Received result for download ", fileId);
+ DebugLogUtils.l("Received result for download ", fileId);
// TODO: handle gracefully a null pointer here. This is practically impossible because
// we come here only when DownloadManager explicitly called us when it ended a
@@ -505,7 +505,7 @@ public final class UpdateHandler {
private static void publishUpdateCycleCompletedEvent(final Context context) {
// Even if this is not successful, we have to publish the new state.
PrivateLog.log("Publishing update cycle completed event");
- LogUtils.l("Publishing update cycle completed event");
+ DebugLogUtils.l("Publishing update cycle completed event");
for (UpdateEventListener listener : linkedCopyOfList(sUpdateEventListeners)) {
listener.updateCycleCompleted();
}
@@ -519,12 +519,12 @@ public final class UpdateHandler {
// {@link handleWordList(Context,InputStream,ContentValues)}.
// Handle the downloaded file according to its type
if (downloadRecord.isMetadata()) {
- LogUtils.l("Data D/L'd is metadata for", downloadRecord.mClientId);
+ DebugLogUtils.l("Data D/L'd is metadata for", downloadRecord.mClientId);
// #handleMetadata() closes its InputStream argument
handleMetadata(context, new ParcelFileDescriptor.AutoCloseInputStream(
manager.openDownloadedFile(fileId)), downloadRecord.mClientId);
} else {
- LogUtils.l("Data D/L'd is a word list");
+ DebugLogUtils.l("Data D/L'd is a word list");
final int wordListStatus = downloadRecord.mAttributes.getAsInteger(
MetadataDbHelper.STATUS_COLUMN);
if (MetadataDbHelper.STATUS_DOWNLOADING == wordListStatus) {
@@ -584,7 +584,7 @@ public final class UpdateHandler {
*/
private static void handleMetadata(final Context context, final InputStream stream,
final String clientId) throws IOException, BadFormatException {
- LogUtils.l("Entering handleMetadata");
+ DebugLogUtils.l("Entering handleMetadata");
final List<WordListMetadata> newMetadata;
final InputStreamReader reader = new InputStreamReader(stream);
try {
@@ -594,7 +594,7 @@ public final class UpdateHandler {
reader.close();
}
- LogUtils.l("Downloaded metadata :", newMetadata);
+ DebugLogUtils.l("Downloaded metadata :", newMetadata);
PrivateLog.log("Downloaded metadata\n" + newMetadata);
final ActionBatch actions = computeUpgradeTo(context, clientId, newMetadata);
@@ -619,7 +619,7 @@ public final class UpdateHandler {
// DownloadManager does not have the ability to put the file directly where we want
// it, so we had it download to a temporary place. Now we move it. It will be deleted
// automatically by DownloadManager.
- LogUtils.l("Downloaded a new word list :", downloadRecord.mAttributes.getAsString(
+ DebugLogUtils.l("Downloaded a new word list :", downloadRecord.mAttributes.getAsString(
MetadataDbHelper.DESCRIPTION_COLUMN), "for", downloadRecord.mClientId);
PrivateLog.log("Downloaded a new word list with description : "
+ downloadRecord.mAttributes.getAsString(MetadataDbHelper.DESCRIPTION_COLUMN)
@@ -678,9 +678,9 @@ public final class UpdateHandler {
*/
private static void copyFile(final InputStream in, final OutputStream out)
throws IOException {
- LogUtils.l("Copying files");
+ DebugLogUtils.l("Copying files");
if (!(in instanceof FileInputStream) || !(out instanceof FileOutputStream)) {
- LogUtils.l("Not the right types");
+ DebugLogUtils.l("Not the right types");
copyFileFallback(in, out);
} else {
try {
@@ -689,7 +689,7 @@ public final class UpdateHandler {
sourceChannel.transferTo(0, Integer.MAX_VALUE, destinationChannel);
} catch (IOException e) {
// Can't work with channels, or something went wrong. Copy by hand.
- LogUtils.l("Won't work");
+ DebugLogUtils.l("Won't work");
copyFileFallback(in, out);
}
}
@@ -704,7 +704,7 @@ public final class UpdateHandler {
*/
private static void copyFileFallback(final InputStream in, final OutputStream out)
throws IOException {
- LogUtils.l("Falling back to slow copy");
+ DebugLogUtils.l("Falling back to slow copy");
final byte[] buffer = new byte[FILE_COPY_BUFFER_SIZE];
for (int readBytes = in.read(buffer); readBytes >= 0; readBytes = in.read(buffer))
out.write(buffer, 0, readBytes);
@@ -719,10 +719,10 @@ public final class UpdateHandler {
*/
private static String getTempFileName(final Context context, final String locale)
throws IOException {
- LogUtils.l("Entering openTempFileOutput");
+ DebugLogUtils.l("Entering openTempFileOutput");
final File dir = context.getFilesDir();
final File f = File.createTempFile(locale + "___", DICT_FILE_SUFFIX, dir);
- LogUtils.l("File name is", f.getName());
+ DebugLogUtils.l("File name is", f.getName());
return f.getName();
}
@@ -743,7 +743,7 @@ public final class UpdateHandler {
final String clientId, List<WordListMetadata> from, List<WordListMetadata> to) {
final ActionBatch actions = new ActionBatch();
// Upgrade existing word lists
- LogUtils.l("Comparing dictionaries");
+ DebugLogUtils.l("Comparing dictionaries");
final Set<String> wordListIds = new TreeSet<String>();
// TODO: Can these be null?
if (null == from) from = new ArrayList<WordListMetadata>();
@@ -758,7 +758,7 @@ public final class UpdateHandler {
final WordListMetadata newInfo = null == metadataInfo
|| metadataInfo.mFormatVersion > MAXIMUM_SUPPORTED_FORMAT_VERSION
? null : metadataInfo;
- LogUtils.l("Considering updating ", id, "currentInfo =", currentInfo);
+ DebugLogUtils.l("Considering updating ", id, "currentInfo =", currentInfo);
if (null == currentInfo && null == newInfo) {
// This may happen if a new word list appeared that we can't handle.
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 05b1a2ee1..f36c9e878 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -78,20 +78,23 @@ public final class BinaryDictionary extends Dictionary {
* @param length the length of the binary data.
* @param useFullEditDistance whether to use the full edit distance in suggestions
* @param dictType the dictionary type, as a human-readable string
+ * @param isUpdatable whether to open the dictionary file in writable mode.
*/
public BinaryDictionary(final String filename, final long offset, final long length,
- final boolean useFullEditDistance, final Locale locale, final String dictType) {
+ final boolean useFullEditDistance, final Locale locale, final String dictType,
+ final boolean isUpdatable) {
super(dictType);
mLocale = locale;
mNativeSuggestOptions.setUseFullEditDistance(useFullEditDistance);
- loadDictionary(filename, offset, length);
+ loadDictionary(filename, offset, length, isUpdatable);
}
static {
JniUtils.loadNativeLibrary();
}
- private static native long openNative(String sourceDir, long dictOffset, long dictSize);
+ private static native long openNative(String sourceDir, long dictOffset, long dictSize,
+ boolean isUpdatable);
private static native void closeNative(long dict);
private static native int getProbabilityNative(long dict, int[] word);
private static native boolean isValidBigramNative(long dict, int[] word1, int[] word2);
@@ -105,8 +108,8 @@ public final class BinaryDictionary extends Dictionary {
// TODO: Move native dict into session
private final void loadDictionary(final String path, final long startOffset,
- final long length) {
- mNativeDict = openNative(path, startOffset, length);
+ final long length, final boolean isUpdatable) {
+ mNativeDict = openNative(path, startOffset, length, isUpdatable);
}
@Override
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
index 5b98613a4..3721132c5 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
@@ -60,7 +60,8 @@ public final class DictionaryFactory {
if (null != assetFileList) {
for (final AssetFileAddress f : assetFileList) {
final BinaryDictionary binaryDictionary = new BinaryDictionary(f.mFilename,
- f.mOffset, f.mLength, useFullEditDistance, locale, Dictionary.TYPE_MAIN);
+ f.mOffset, f.mLength, useFullEditDistance, locale, Dictionary.TYPE_MAIN,
+ false /* isUpdatable */);
if (binaryDictionary.isValidDictionary()) {
dictList.add(binaryDictionary);
}
@@ -113,7 +114,8 @@ public final class DictionaryFactory {
return null;
}
return new BinaryDictionary(sourceDir, afd.getStartOffset(), afd.getLength(),
- false /* useFullEditDistance */, locale, Dictionary.TYPE_MAIN);
+ false /* useFullEditDistance */, locale, Dictionary.TYPE_MAIN,
+ false /* isUpdatable */);
} catch (android.content.res.Resources.NotFoundException e) {
Log.e(TAG, "Could not find the resource");
return null;
@@ -142,7 +144,7 @@ public final class DictionaryFactory {
for (final AssetFileAddress address : dictionaryList) {
final BinaryDictionary binaryDictionary = new BinaryDictionary(address.mFilename,
address.mOffset, address.mLength, useFullEditDistance, locale,
- Dictionary.TYPE_MAIN);
+ Dictionary.TYPE_MAIN, false /* isUpdatable */);
dictionaryCollection.addDictionary(binaryDictionary);
}
return dictionaryCollection;
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index f357e2a1e..9cdb86c2d 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -286,7 +286,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
// Build the new binary dictionary
final BinaryDictionary newBinaryDictionary = new BinaryDictionary(filename, 0, length,
- true /* useFullEditDistance */, null, mDictType);
+ true /* useFullEditDistance */, null, mDictType, false /* isUpdatable */);
if (mBinaryDictionary != null) {
// Ensure all threads accessing the current dictionary have finished before swapping in
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 0efe0eba7..6fcac9a65 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -926,19 +926,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
}
- // TODO: refactor the following code to be less contrived.
- // "newSelStart != composingSpanEnd" || "newSelEnd != composingSpanEnd" means
- // that the cursor is not at the end of the composing span, or there is a selection.
- // "mLastSelectionStart != newSelStart" means that the cursor is not in the same place
- // as last time we were called (if there is a selection, it means the start hasn't
- // changed, so it's the end that did).
- final boolean selectionChanged = (newSelStart != composingSpanEnd
- || newSelEnd != composingSpanEnd) && mLastSelectionStart != newSelStart;
+ final boolean selectionChanged = mLastSelectionStart != newSelStart
+ || mLastSelectionEnd != newSelEnd;
// if composingSpanStart and composingSpanEnd are -1, it means there is no composing
// span in the view - we can use that to narrow down whether the cursor was moved
// by us or not. If we are composing a word but there is no composing span, then
// we know for sure the cursor moved while we were composing and we should reset
- // the state.
+ // the state. TODO: rescind this policy: the framework never removes the composing
+ // span on its own accord while editing. This test is useless.
+
final boolean noComposingSpan = composingSpanStart == -1 && composingSpanEnd == -1;
// If the keyboard is not visible, we don't need to do all the housekeeping work, as it
// will be reset when the keyboard shows up anyway.
@@ -979,6 +975,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (isSuggestionsStripVisible()) {
mHandler.postResumeSuggestions();
}
+ mConnection.userMovedCursor(newSelEnd);
// Reset the last recapitalization.
mRecapitalizeStatus.deactivate();
mKeyboardSwitcher.updateShiftState();
@@ -2655,11 +2652,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
}
- // Used by the RingCharBuffer
- public boolean isWordSeparator(final int code) {
- return mSettings.getCurrent().isWordSeparator(code);
- }
-
// TODO: Make this private
// Outside LatinIME, only used by the {@link InputTestsBase} test suite.
@UsedForTesting
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index d431ad60b..6e3e7b218 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -28,7 +28,7 @@ import android.view.inputmethod.InputConnection;
import com.android.inputmethod.latin.define.ProductionFlag;
import com.android.inputmethod.latin.utils.CapsModeUtils;
-import com.android.inputmethod.latin.utils.LogUtils;
+import com.android.inputmethod.latin.utils.DebugLogUtils;
import com.android.inputmethod.latin.utils.StringUtils;
import com.android.inputmethod.research.ResearchLogger;
@@ -107,7 +107,7 @@ public final class RichInputConnection {
+ "\nActual text = " + reference.length() + " " + reference;
((LatinIME)mParent).debugDumpStateAndCrashWithException(context);
} else {
- Log.e(TAG, LogUtils.getStackTrace(2));
+ Log.e(TAG, DebugLogUtils.getStackTrace(2));
Log.e(TAG, "Exp <> Actual : " + mCurrentCursorPosition + " <> " + et.selectionStart);
}
}
@@ -156,7 +156,7 @@ public final class RichInputConnection {
if (mNestLevel != 1) {
// TODO: exception instead
Log.e(TAG, "Batch edit level incorrect : " + mNestLevel);
- Log.e(TAG, LogUtils.getStackTrace(4));
+ Log.e(TAG, DebugLogUtils.getStackTrace(4));
}
}
@@ -340,7 +340,6 @@ public final class RichInputConnection {
public void setComposingRegion(final int start, final int end) {
if (DEBUG_BATCH_NESTING) checkBatchEdit();
if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
- mCurrentCursorPosition = end;
final CharSequence textBeforeCursor =
getTextBeforeCursor(DEFAULT_TEXT_CACHE_SIZE + (end - start), 0);
mCommittedTextBeforeComposingText.setLength(0);
@@ -731,6 +730,14 @@ public final class RichInputConnection {
}
/**
+ * The user moved the cursor by hand. Take a note of it.
+ * @param newCursorPosition The new cursor position.
+ */
+ public void userMovedCursor(final int newCursorPosition) {
+ mCurrentCursorPosition = newCursorPosition;
+ }
+
+ /**
* Looks at the text just before the cursor to find out if it looks like a URL.
*
* The weakest point here is, if we don't have enough text bufferized, we may fail to realize
diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java
index 084d3308c..adc92d021 100644
--- a/java/src/com/android/inputmethod/latin/Settings.java
+++ b/java/src/com/android/inputmethod/latin/Settings.java
@@ -152,6 +152,10 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
return mSettingsValues.mWordSeparators;
}
+ public boolean isWordSeparator(final int code) {
+ return mSettingsValues.isWordSeparator(code);
+ }
+
public Locale getCurrentLocale() {
return mCurrentLocale;
}
diff --git a/java/src/com/android/inputmethod/latin/SubtypeLocale.java b/java/src/com/android/inputmethod/latin/SubtypeLocale.java
index 3f94aca3a..30df2eb4e 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeLocale.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeLocale.java
@@ -26,9 +26,9 @@ import android.util.Log;
import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.DebugLogUtils;
import com.android.inputmethod.latin.utils.LocaleUtils;
import com.android.inputmethod.latin.utils.LocaleUtils.RunInLocale;
-import com.android.inputmethod.latin.utils.LogUtils;
import com.android.inputmethod.latin.utils.StringUtils;
import java.util.HashMap;
@@ -242,7 +242,7 @@ public final class SubtypeLocale {
+ " nameResId=" + subtype.getNameResId()
+ " locale=" + subtype.getLocale()
+ " extra=" + subtype.getExtraValue()
- + "\n" + LogUtils.getStackTrace());
+ + "\n" + DebugLogUtils.getStackTrace());
return "";
}
}
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
index b6caf9b7b..9565f63f7 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
@@ -86,6 +86,7 @@ final class SuggestionStripLayoutHelper {
private final float mAlphaObsoleted;
private final float mCenterSuggestionWeight;
private final int mCenterPositionInStrip;
+ private final int mTypedWordPositionWhenAutocorrect;
private final Drawable mMoreSuggestionsHint;
private static final String MORE_SUGGESTIONS_HINT = "\u2026";
private static final String LEFTWARDS_ARROW = "\u2190";
@@ -159,6 +160,10 @@ final class SuggestionStripLayoutHelper {
mMoreSuggestionsHint = getMoreSuggestionsHint(res,
res.getDimension(R.dimen.more_suggestions_hint_text_size), mColorAutoCorrect);
mCenterPositionInStrip = mSuggestionsCountInStrip / 2;
+ // Assuming there are at least three suggestions. Also, note that the suggestions are
+ // laid out according to script direction, so this is left of the center for LTR scripts
+ // and right of the center for RTL scripts.
+ mTypedWordPositionWhenAutocorrect = mCenterPositionInStrip - 1;
mMoreSuggestionsBottomGap = res.getDimensionPixelOffset(
R.dimen.more_suggestions_bottom_gap);
mMoreSuggestionsRowHeight = res.getDimensionPixelSize(R.dimen.more_suggestions_row_height);
@@ -233,24 +238,31 @@ final class SuggestionStripLayoutHelper {
return spannedWord;
}
- private int getIndexInSuggestedWords(final int positionInStrip,
+ private int getPositionInSuggestionStrip(final int indexInSuggestedWords,
final SuggestedWords suggestedWords) {
- // TODO: This works for 3 suggestions. Revisit this algorithm when there are 5 or more
- // suggestions.
- final int mostImportantIndexInSuggestedWords = suggestedWords.willAutoCorrect()
- ? SuggestedWords.INDEX_OF_AUTO_CORRECTION : SuggestedWords.INDEX_OF_TYPED_WORD;
- if (positionInStrip == mCenterPositionInStrip) {
- return mostImportantIndexInSuggestedWords;
+ final int indexToDisplayMostImportantSuggestion;
+ final int indexToDisplaySecondMostImportantSuggestion;
+ if (suggestedWords.willAutoCorrect()) {
+ indexToDisplayMostImportantSuggestion = SuggestedWords.INDEX_OF_AUTO_CORRECTION;
+ indexToDisplaySecondMostImportantSuggestion = SuggestedWords.INDEX_OF_TYPED_WORD;
+ } else {
+ indexToDisplayMostImportantSuggestion = SuggestedWords.INDEX_OF_TYPED_WORD;
+ indexToDisplaySecondMostImportantSuggestion = SuggestedWords.INDEX_OF_AUTO_CORRECTION;
}
- if (positionInStrip == mostImportantIndexInSuggestedWords) {
+ if (indexInSuggestedWords == indexToDisplayMostImportantSuggestion) {
return mCenterPositionInStrip;
}
- return positionInStrip;
+ if (indexInSuggestedWords == indexToDisplaySecondMostImportantSuggestion) {
+ return mTypedWordPositionWhenAutocorrect;
+ }
+ // If neither of those, the order in the suggestion strip is the same as in SuggestedWords.
+ return indexInSuggestedWords;
}
- private int getSuggestionTextColor(final int positionInStrip,
+ private int getSuggestionTextColor(final int indexInSuggestedWords,
final SuggestedWords suggestedWords) {
- final int indexInSuggestedWords = getIndexInSuggestedWords(positionInStrip, suggestedWords);
+ final int positionInStrip =
+ getPositionInSuggestionStrip(indexInSuggestedWords, suggestedWords);
// TODO: Need to revisit this logic with bigram suggestions
final boolean isSuggested = (indexInSuggestedWords != SuggestedWords.INDEX_OF_TYPED_WORD);
@@ -352,7 +364,7 @@ final class SuggestionStripLayoutHelper {
* increase towards the right for LTR scripts and the left for RTL scripts, starting with 0.
* The position of the most important suggestion is in {@link #mCenterPositionInStrip}. This
* usually doesn't match the index in <code>suggedtedWords</code> -- see
- * {@link #getIndexInSuggestedWords(int,SuggestedWords)}.
+ * {@link #getPositionInSuggestionStrip(int,SuggestedWords)}.
*
* @param positionInStrip the position in the suggestion strip.
* @param width the maximum width for layout in pixels.
@@ -413,10 +425,19 @@ final class SuggestionStripLayoutHelper {
private void setupWordViewsTextAndColor(final SuggestedWords suggestedWords,
final int countInStrip) {
+ // Clear all suggestions first
+ for (int positionInStrip = 0; positionInStrip < countInStrip; ++positionInStrip) {
+ mWordViews.get(positionInStrip).setText(null);
+ // Make this inactive for touches in {@link #layoutWord(int,int)}.
+ if (SuggestionStripView.DBG) {
+ mDebugInfoViews.get(positionInStrip).setText(null);
+ }
+ }
final int count = Math.min(suggestedWords.size(), countInStrip);
- for (int positionInStrip = 0; positionInStrip < count; positionInStrip++) {
- final int indexInSuggestedWords =
- getIndexInSuggestedWords(positionInStrip, suggestedWords);
+ for (int indexInSuggestedWords = 0; indexInSuggestedWords < count;
+ indexInSuggestedWords++) {
+ final int positionInStrip =
+ getPositionInSuggestionStrip(indexInSuggestedWords, suggestedWords);
final TextView wordView = mWordViews.get(positionInStrip);
// {@link TextView#getTag()} is used to get the index in suggestedWords at
// {@link SuggestionStripView#onClick(View)}.
@@ -428,13 +449,6 @@ final class SuggestionStripLayoutHelper {
Utils.getDebugInfo(suggestedWords, indexInSuggestedWords));
}
}
- for (int positionInStrip = count; positionInStrip < countInStrip; positionInStrip++) {
- mWordViews.get(positionInStrip).setText(null);
- // Make this inactive for touches in {@link #layoutWord(int,int)}.
- if (SuggestionStripView.DBG) {
- mDebugInfoViews.get(positionInStrip).setText(null);
- }
- }
}
private void layoutPunctuationSuggestions(final SuggestedWords suggestedWords,
diff --git a/java/src/com/android/inputmethod/latin/utils/LogUtils.java b/java/src/com/android/inputmethod/latin/utils/DebugLogUtils.java
index a0d2e0495..c4ead0ad1 100644
--- a/java/src/com/android/inputmethod/latin/utils/LogUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/DebugLogUtils.java
@@ -23,8 +23,8 @@ import com.android.inputmethod.latin.LatinImeLogger;
/**
* A class for logging and debugging utility methods.
*/
-public final class LogUtils {
- private final static String TAG = LogUtils.class.getSimpleName();
+public final class DebugLogUtils {
+ private final static String TAG = DebugLogUtils.class.getSimpleName();
private final static boolean sDBG = LatinImeLogger.sDBG;
/**
diff --git a/java/src/com/android/inputmethod/latin/utils/UserLogRingCharBuffer.java b/java/src/com/android/inputmethod/latin/utils/UserLogRingCharBuffer.java
new file mode 100644
index 000000000..3e67e8216
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/utils/UserLogRingCharBuffer.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ */
+
+package com.android.inputmethod.latin.utils;
+
+import android.inputmethodservice.InputMethodService;
+
+import com.android.inputmethod.annotations.UsedForTesting;
+import com.android.inputmethod.latin.Settings;
+import com.android.inputmethod.latin.utils.Utils.UsabilityStudyLogUtils;
+
+public final class UserLogRingCharBuffer {
+ public /* for test */ static final int BUFSIZE = 20;
+ public /* for test */ int mLength = 0;
+
+ private static UserLogRingCharBuffer sUserLogRingCharBuffer = new UserLogRingCharBuffer();
+ private static final char PLACEHOLDER_DELIMITER_CHAR = '\uFFFC';
+ private static final int INVALID_COORDINATE = -2;
+ private boolean mEnabled = false;
+ private int mEnd = 0;
+ private char[] mCharBuf = new char[BUFSIZE];
+ private int[] mXBuf = new int[BUFSIZE];
+ private int[] mYBuf = new int[BUFSIZE];
+
+ private UserLogRingCharBuffer() {
+ // Intentional empty constructor for singleton.
+ }
+
+ @UsedForTesting
+ public static UserLogRingCharBuffer getInstance() {
+ return sUserLogRingCharBuffer;
+ }
+
+ public static UserLogRingCharBuffer init(final InputMethodService context,
+ final boolean enabled, final boolean usabilityStudy) {
+ if (!(enabled || usabilityStudy)) {
+ return null;
+ }
+ sUserLogRingCharBuffer.mEnabled = true;
+ UsabilityStudyLogUtils.getInstance().init(context);
+ return sUserLogRingCharBuffer;
+ }
+
+ private static int normalize(final int in) {
+ int ret = in % BUFSIZE;
+ return ret < 0 ? ret + BUFSIZE : ret;
+ }
+
+ // TODO: accept code points
+ @UsedForTesting
+ public void push(final char c, final int x, final int y) {
+ if (!mEnabled) {
+ return;
+ }
+ mCharBuf[mEnd] = c;
+ mXBuf[mEnd] = x;
+ mYBuf[mEnd] = y;
+ mEnd = normalize(mEnd + 1);
+ if (mLength < BUFSIZE) {
+ ++mLength;
+ }
+ }
+
+ public char pop() {
+ if (mLength < 1) {
+ return PLACEHOLDER_DELIMITER_CHAR;
+ }
+ mEnd = normalize(mEnd - 1);
+ --mLength;
+ return mCharBuf[mEnd];
+ }
+
+ public char getBackwardNthChar(final int n) {
+ if (mLength <= n || n < 0) {
+ return PLACEHOLDER_DELIMITER_CHAR;
+ }
+ return mCharBuf[normalize(mEnd - n - 1)];
+ }
+
+ public int getPreviousX(final char c, final int back) {
+ final int index = normalize(mEnd - 2 - back);
+ if (mLength <= back
+ || Character.toLowerCase(c) != Character.toLowerCase(mCharBuf[index])) {
+ return INVALID_COORDINATE;
+ }
+ return mXBuf[index];
+ }
+
+ public int getPreviousY(final char c, final int back) {
+ int index = normalize(mEnd - 2 - back);
+ if (mLength <= back
+ || Character.toLowerCase(c) != Character.toLowerCase(mCharBuf[index])) {
+ return INVALID_COORDINATE;
+ }
+ return mYBuf[index];
+ }
+
+ public String getLastWord(final int ignoreCharCount) {
+ final StringBuilder sb = new StringBuilder();
+ int i = ignoreCharCount;
+ for (; i < mLength; ++i) {
+ final char c = mCharBuf[normalize(mEnd - 1 - i)];
+ if (!Settings.getInstance().isWordSeparator(c)) {
+ break;
+ }
+ }
+ for (; i < mLength; ++i) {
+ char c = mCharBuf[normalize(mEnd - 1 - i)];
+ if (!Settings.getInstance().isWordSeparator(c)) {
+ sb.append(c);
+ } else {
+ break;
+ }
+ }
+ return sb.reverse().toString();
+ }
+
+ public void reset() {
+ mLength = 0;
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/utils/Utils.java b/java/src/com/android/inputmethod/latin/utils/Utils.java
index 390d306c8..c4e18ed7e 100644
--- a/java/src/com/android/inputmethod/latin/utils/Utils.java
+++ b/java/src/com/android/inputmethod/latin/utils/Utils.java
@@ -26,7 +26,6 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.inputmethodservice.InputMethodService;
import android.net.Uri;
-import android.os.AsyncTask;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
@@ -34,9 +33,7 @@ import android.os.Process;
import android.text.TextUtils;
import android.util.Log;
-import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.Constants;
-import com.android.inputmethod.latin.LatinIME;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
@@ -63,135 +60,6 @@ public final class Utils {
// This utility class is not publicly instantiable.
}
- /**
- * Cancel an {@link AsyncTask}.
- *
- * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this
- * task should be interrupted; otherwise, in-progress tasks are allowed
- * to complete.
- */
- public static void cancelTask(final AsyncTask<?, ?, ?> task,
- final boolean mayInterruptIfRunning) {
- if (task != null && task.getStatus() != AsyncTask.Status.FINISHED) {
- task.cancel(mayInterruptIfRunning);
- }
- }
-
- // TODO: Make this an external class
- public /* for test */ static final class RingCharBuffer {
- public /* for test */ static final int BUFSIZE = 20;
- public /* for test */ int mLength = 0;
-
- private static RingCharBuffer sRingCharBuffer = new RingCharBuffer();
- private static final char PLACEHOLDER_DELIMITER_CHAR = '\uFFFC';
- private static final int INVALID_COORDINATE = -2;
- private InputMethodService mContext;
- private boolean mEnabled = false;
- private int mEnd = 0;
- private char[] mCharBuf = new char[BUFSIZE];
- private int[] mXBuf = new int[BUFSIZE];
- private int[] mYBuf = new int[BUFSIZE];
-
- private RingCharBuffer() {
- // Intentional empty constructor for singleton.
- }
-
- @UsedForTesting
- public static RingCharBuffer getInstance() {
- return sRingCharBuffer;
- }
-
- public static RingCharBuffer init(final InputMethodService context, final boolean enabled,
- final boolean usabilityStudy) {
- if (!(enabled || usabilityStudy)) {
- return null;
- }
- sRingCharBuffer.mContext = context;
- sRingCharBuffer.mEnabled = true;
- UsabilityStudyLogUtils.getInstance().init(context);
- return sRingCharBuffer;
- }
-
- private static int normalize(final int in) {
- int ret = in % BUFSIZE;
- return ret < 0 ? ret + BUFSIZE : ret;
- }
-
- // TODO: accept code points
- @UsedForTesting
- public void push(final char c, final int x, final int y) {
- if (!mEnabled) {
- return;
- }
- mCharBuf[mEnd] = c;
- mXBuf[mEnd] = x;
- mYBuf[mEnd] = y;
- mEnd = normalize(mEnd + 1);
- if (mLength < BUFSIZE) {
- ++mLength;
- }
- }
-
- public char pop() {
- if (mLength < 1) {
- return PLACEHOLDER_DELIMITER_CHAR;
- }
- mEnd = normalize(mEnd - 1);
- --mLength;
- return mCharBuf[mEnd];
- }
-
- public char getBackwardNthChar(final int n) {
- if (mLength <= n || n < 0) {
- return PLACEHOLDER_DELIMITER_CHAR;
- }
- return mCharBuf[normalize(mEnd - n - 1)];
- }
-
- public int getPreviousX(final char c, final int back) {
- final int index = normalize(mEnd - 2 - back);
- if (mLength <= back
- || Character.toLowerCase(c) != Character.toLowerCase(mCharBuf[index])) {
- return INVALID_COORDINATE;
- }
- return mXBuf[index];
- }
-
- public int getPreviousY(final char c, final int back) {
- int index = normalize(mEnd - 2 - back);
- if (mLength <= back
- || Character.toLowerCase(c) != Character.toLowerCase(mCharBuf[index])) {
- return INVALID_COORDINATE;
- }
- return mYBuf[index];
- }
-
- public String getLastWord(final int ignoreCharCount) {
- final StringBuilder sb = new StringBuilder();
- final LatinIME latinIme = (LatinIME)mContext;
- int i = ignoreCharCount;
- for (; i < mLength; ++i) {
- final char c = mCharBuf[normalize(mEnd - 1 - i)];
- if (!latinIme.isWordSeparator(c)) {
- break;
- }
- }
- for (; i < mLength; ++i) {
- char c = mCharBuf[normalize(mEnd - 1 - i)];
- if (!latinIme.isWordSeparator(c)) {
- sb.append(c);
- } else {
- break;
- }
- }
- return sb.reverse().toString();
- }
-
- public void reset() {
- mLength = 0;
- }
- }
-
// TODO: Make this an external class
public static final class UsabilityStudyLogUtils {
// TODO: remove code duplication with ResearchLog class
@@ -409,7 +277,7 @@ public final class Utils {
// TODO: Make this an external class
public static final class Stats {
public static void onNonSeparator(final char code, final int x, final int y) {
- RingCharBuffer.getInstance().push(code, x, y);
+ UserLogRingCharBuffer.getInstance().push(code, x, y);
LatinImeLogger.logOnInputChar();
}
@@ -424,7 +292,7 @@ public final class Utils {
for (int i = 0; i < length; i = Character.offsetByCodePoints(separator, i, 1)) {
int codePoint = Character.codePointAt(separator, i);
// TODO: accept code points
- RingCharBuffer.getInstance().push((char)codePoint, x, y);
+ UserLogRingCharBuffer.getInstance().push((char)codePoint, x, y);
}
LatinImeLogger.logOnInputSeparator();
}