diff options
Diffstat (limited to 'java/src')
6 files changed, 83 insertions, 50 deletions
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 0fc26a80e..56b1c786e 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -72,6 +72,7 @@ import com.android.inputmethod.keyboard.KeyboardActionListener; import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.keyboard.MainKeyboardView; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.Utils.Stats; import com.android.inputmethod.latin.define.ProductionFlag; import com.android.inputmethod.latin.suggestions.SuggestionStripView; @@ -1905,7 +1906,6 @@ public final class LatinIME extends InputMethodService implements KeyboardAction private boolean handleSeparator(final int primaryCode, final int x, final int y, final int spaceState) { if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.recordTimeForLogUnitSplit(); ResearchLogger.latinIME_handleSeparator(primaryCode, mWordComposer.isComposingWord()); } boolean didAutoCorrect = false; @@ -2174,8 +2174,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // Called from {@link SuggestionStripView} through the {@link SuggestionStripView#Listener} // interface @Override - public void pickSuggestionManually(final int index, final String suggestion) { + public void pickSuggestionManually(final int index, final SuggestedWordInfo suggestionInfo) { final SuggestedWords suggestedWords = mSuggestedWords; + final String suggestion = suggestionInfo.mWord; // If this is a punctuation picked from the suggestion strip, pass it to onCodeInput if (suggestion.length() == 1 && isShowingPunctuationList()) { // Word separators are suggested before the user inputs something. @@ -2241,7 +2242,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // AND it's in none of our current dictionaries (main, user or otherwise). // Please note that if mSuggest is null, it means that everything is off: suggestion // and correction, so we shouldn't try to show the hint - final boolean showingAddToDictionaryHint = index == 0 && mSuggest != null + final boolean showingAddToDictionaryHint = + SuggestedWordInfo.KIND_TYPED == suggestionInfo.mKind && mSuggest != null // If the suggestion is not in the dictionary, the hint should be shown. && !AutoCorrection.isValidWord(mSuggest.getUnigramDictionaries(), suggestion, true); diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java index dcb514a5e..59ad28fc9 100644 --- a/java/src/com/android/inputmethod/latin/StringUtils.java +++ b/java/src/com/android/inputmethod/latin/StringUtils.java @@ -115,11 +115,12 @@ public final class StringUtils { // - This does not work for Greek, because it returns upper case instead of title case. // - It does not work for Serbian, because it fails to account for the "lj" character, // which should be "Lj" in title case and "LJ" in upper case. - // - It does not work for Dutch, because it fails to account for the "ij" digraph, which - // are two different characters but both should be capitalized as "IJ" as if they were - // a single letter. - // - It also does not work with unicode surrogate code points. - return s.toUpperCase(locale).charAt(0) + s.substring(1); + // - It does not work for Dutch, because it fails to account for the "ij" digraph when it's + // written as two separate code points. They are two different characters but both should + // be capitalized as "IJ" as if they were a single letter in most words (not all). If the + // unicode char for the ligature is used however, it works. + final int cutoff = s.offsetByCodePoints(0, 1); + return s.substring(0, cutoff).toUpperCase(locale) + s.substring(cutoff).toLowerCase(locale); } private static final int[] EMPTY_CODEPOINTS = {}; @@ -176,17 +177,27 @@ public final class StringUtils { return list.toArray(new String[list.size()]); } - // This method assumes the text is not empty or null. + // This method assumes the text is not null. For the empty string, it returns CAPITALIZE_NONE. public static int getCapitalizationType(final String text) { // If the first char is not uppercase, then the word is either all lower case or // camel case, and in either case we return CAPITALIZE_NONE. - if (!Character.isUpperCase(text.codePointAt(0))) return CAPITALIZE_NONE; final int len = text.length(); + int index = 0; + for (; index < len; index = text.offsetByCodePoints(index, 1)) { + if (Character.isLetter(text.codePointAt(index))) { + break; + } + } + if (index == len) return CAPITALIZE_NONE; + if (!Character.isUpperCase(text.codePointAt(index))) { + return CAPITALIZE_NONE; + } int capsCount = 1; int letterCount = 1; - for (int i = 1; i < len; i = text.offsetByCodePoints(i, 1)) { + for (index = text.offsetByCodePoints(index, 1); index < len; + index = text.offsetByCodePoints(index, 1)) { if (1 != capsCount && letterCount != capsCount) break; - final int codePoint = text.codePointAt(i); + final int codePoint = text.codePointAt(index); if (Character.isUpperCase(codePoint)) { ++capsCount; ++letterCount; diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java index 8c3d3b08c..eeaf828a7 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java @@ -62,6 +62,7 @@ import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.ResourceUtils; import com.android.inputmethod.latin.SuggestedWords; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.Utils; import com.android.inputmethod.latin.define.ProductionFlag; import com.android.inputmethod.research.ResearchLogger; @@ -72,7 +73,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick OnLongClickListener { public interface Listener { public void addWordToUserDictionary(String word); - public void pickSuggestionManually(int index, String word); + public void pickSuggestionManually(int index, SuggestedWordInfo word); } // The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}. @@ -656,8 +657,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick @Override public boolean onCustomRequest(final int requestCode) { final int index = requestCode; - final String word = mSuggestedWords.getWord(index); - mListener.pickSuggestionManually(index, word); + final SuggestedWordInfo wordInfo = mSuggestedWords.getInfo(index); + mListener.pickSuggestionManually(index, wordInfo); dismissMoreSuggestions(); return true; } @@ -807,8 +808,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick if (index >= mSuggestedWords.size()) return; - final String word = mSuggestedWords.getWord(index); - mListener.pickSuggestionManually(index, word); + final SuggestedWordInfo wordInfo = mSuggestedWords.getInfo(index); + mListener.pickSuggestionManually(index, wordInfo); } @Override diff --git a/java/src/com/android/inputmethod/research/BootBroadcastReceiver.java b/java/src/com/android/inputmethod/research/BootBroadcastReceiver.java index c5f095919..4f86526a7 100644 --- a/java/src/com/android/inputmethod/research/BootBroadcastReceiver.java +++ b/java/src/com/android/inputmethod/research/BootBroadcastReceiver.java @@ -25,9 +25,10 @@ import android.content.Intent; */ public final class BootBroadcastReceiver extends BroadcastReceiver { @Override - public void onReceive(Context context, Intent intent) { + public void onReceive(final Context context, final Intent intent) { if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) { - ResearchLogger.scheduleUploadingService(context); + UploaderService.cancelAndRescheduleUploadingService(context, + true /* needsRescheduling */); } } } diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java index fbfa9c977..e0bd37c1e 100644 --- a/java/src/com/android/inputmethod/research/ResearchLogger.java +++ b/java/src/com/android/inputmethod/research/ResearchLogger.java @@ -20,16 +20,13 @@ import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.KEYBOAR import android.accounts.Account; import android.accounts.AccountManager; -import android.app.AlarmManager; import android.app.AlertDialog; import android.app.Dialog; -import android.app.PendingIntent; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnCancelListener; import android.content.Intent; import android.content.SharedPreferences; -import android.content.SharedPreferences.Editor; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; @@ -74,22 +71,16 @@ import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.define.ProductionFlag; import com.android.inputmethod.research.MotionEventReader.ReplayData; -import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; -import java.io.InputStreamReader; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.charset.Charset; -import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Date; import java.util.List; -import java.util.Locale; import java.util.Random; -import java.util.UUID; /** * Logs the use of the LatinIME keyboard. @@ -254,7 +245,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang mUploadNowIntent = new Intent(mLatinIME, UploaderService.class); mUploadNowIntent.putExtra(UploaderService.EXTRA_UPLOAD_UNCONDITIONALLY, true); if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - scheduleUploadingService(mLatinIME); + UploaderService.cancelAndRescheduleUploadingService(mLatinIME, + true /* needsRescheduling */); } mReplayer.setKeyboardSwitcher(keyboardSwitcher); } @@ -268,25 +260,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang ResearchSettings.writeResearchLastDirCleanupTime(mPrefs, now); } - /** - * Arrange for the UploaderService to be run on a regular basis. - * - * Any existing scheduled invocation of UploaderService is removed and rescheduled. This may - * cause problems if this method is called often and frequent updates are required, but since - * the user will likely be sleeping at some point, if the interval is less that the expected - * sleep duration and this method is not called during that time, the service should be invoked - * at some point. - */ - public static void scheduleUploadingService(Context context) { - final Intent intent = new Intent(context, UploaderService.class); - final PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0); - final AlarmManager manager = - (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - manager.cancel(pendingIntent); - manager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, - UploaderService.RUN_INTERVAL, UploaderService.RUN_INTERVAL, pendingIntent); - } - public void mainKeyboardView_onAttachedToWindow(final MainKeyboardView mainKeyboardView) { mMainKeyboardView = mainKeyboardView; maybeShowSplashScreen(); @@ -790,8 +763,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } private boolean isAllowedToLog() { - return !mIsPasswordView && !mIsLoggingSuspended && sIsLogging && !mInFeedbackDialog - && !isReplaying(); + return !mIsPasswordView && !mIsLoggingSuspended && sIsLogging && !mInFeedbackDialog; } public void requestIndicatorRedraw() { diff --git a/java/src/com/android/inputmethod/research/UploaderService.java b/java/src/com/android/inputmethod/research/UploaderService.java index 6a9f5c1f4..6a9717b7c 100644 --- a/java/src/com/android/inputmethod/research/UploaderService.java +++ b/java/src/com/android/inputmethod/research/UploaderService.java @@ -18,6 +18,8 @@ package com.android.inputmethod.research; import android.app.AlarmManager; import android.app.IntentService; +import android.app.PendingIntent; +import android.content.Context; import android.content.Intent; import android.os.Bundle; @@ -43,11 +45,17 @@ public final class UploaderService extends IntentService { @Override protected void onHandleIntent(final Intent intent) { + // We may reach this point either because the alarm fired, or because the system explicitly + // requested that an Upload occur. In the latter case, we want to cancel the alarm in case + // it's about to fire. + cancelAndRescheduleUploadingService(this, false /* needsRescheduling */); + final Uploader uploader = new Uploader(this); if (!uploader.isPossibleToUpload()) return; if (isUploadingUnconditionally(intent.getExtras()) || uploader.isConvenientToUpload()) { uploader.doUpload(); } + cancelAndRescheduleUploadingService(this, true /* needsRescheduling */); } private boolean isUploadingUnconditionally(final Bundle bundle) { @@ -57,4 +65,42 @@ public final class UploaderService extends IntentService { } return false; } + + /** + * Arrange for the UploaderService to be run on a regular basis. + * + * Any existing scheduled invocation of UploaderService is removed and optionally rescheduled. + * This may cause problems if this method is called so often that no scheduled invocation is + * ever run. But if the delay is short enough that it will go off when the user is sleeping, + * then there should be no starvation. + * + * @param context {@link Context} object + * @param needsRescheduling whether to schedule a future intent to be delivered to this service + */ + public static void cancelAndRescheduleUploadingService(final Context context, + final boolean needsRescheduling) { + final PendingIntent pendingIntent = getPendingIntentForService(context); + final AlarmManager alarmManager = (AlarmManager) context.getSystemService( + Context.ALARM_SERVICE); + cancelAnyScheduledServiceAlarm(alarmManager, pendingIntent); + if (needsRescheduling) { + scheduleServiceAlarm(alarmManager, pendingIntent); + } + } + + private static PendingIntent getPendingIntentForService(final Context context) { + final Intent intent = new Intent(context, UploaderService.class); + return PendingIntent.getService(context, 0, intent, 0); + } + + private static void cancelAnyScheduledServiceAlarm(final AlarmManager alarmManager, + final PendingIntent pendingIntent) { + alarmManager.cancel(pendingIntent); + } + + private static void scheduleServiceAlarm(final AlarmManager alarmManager, + final PendingIntent pendingIntent) { + alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, UploaderService.RUN_INTERVAL, + pendingIntent); + } } |