1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of 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, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.inputmethod.latin.utils; 18 19 import android.inputmethodservice.InputMethodService; 20 21 import com.android.inputmethod.annotations.UsedForTesting; 22 import com.android.inputmethod.latin.LatinImeLogger; 23 import com.android.inputmethod.latin.settings.Settings; 24 25 public final class UserLogRingCharBuffer { 26 public /* for test */ static final int BUFSIZE = 20; 27 public /* for test */ int mLength = 0; 28 29 private static UserLogRingCharBuffer sUserLogRingCharBuffer = new UserLogRingCharBuffer(); 30 private static final char PLACEHOLDER_DELIMITER_CHAR = '\uFFFC'; 31 private static final int INVALID_COORDINATE = -2; 32 private boolean mEnabled = false; 33 private int mEnd = 0; 34 private char[] mCharBuf = new char[BUFSIZE]; 35 private int[] mXBuf = new int[BUFSIZE]; 36 private int[] mYBuf = new int[BUFSIZE]; 37 38 private UserLogRingCharBuffer() { 39 // Intentional empty constructor for singleton. 40 } 41 42 @UsedForTesting 43 public static UserLogRingCharBuffer getInstance() { 44 return sUserLogRingCharBuffer; 45 } 46 47 public static UserLogRingCharBuffer init(final InputMethodService context, 48 final boolean enabled, final boolean usabilityStudy) { 49 if (!(enabled || usabilityStudy)) { 50 return null; 51 } 52 sUserLogRingCharBuffer.mEnabled = true; 53 UsabilityStudyLogUtils.getInstance().init(context); 54 return sUserLogRingCharBuffer; 55 } 56 57 private static int normalize(final int in) { 58 int ret = in % BUFSIZE; 59 return ret < 0 ? ret + BUFSIZE : ret; 60 } 61 62 // TODO: accept code points 63 @UsedForTesting 64 public void push(final char c, final int x, final int y) { 65 if (!mEnabled) { 66 return; 67 } 68 if (LatinImeLogger.sUsabilityStudy) { 69 UsabilityStudyLogUtils.getInstance().writeChar(c, x, y); 70 } 71 mCharBuf[mEnd] = c; 72 mXBuf[mEnd] = x; 73 mYBuf[mEnd] = y; 74 mEnd = normalize(mEnd + 1); 75 if (mLength < BUFSIZE) { 76 ++mLength; 77 } 78 } 79 80 public char pop() { 81 if (mLength < 1) { 82 return PLACEHOLDER_DELIMITER_CHAR; 83 } 84 mEnd = normalize(mEnd - 1); 85 --mLength; 86 return mCharBuf[mEnd]; 87 } 88 89 public char getBackwardNthChar(final int n) { 90 if (mLength <= n || n < 0) { 91 return PLACEHOLDER_DELIMITER_CHAR; 92 } 93 return mCharBuf[normalize(mEnd - n - 1)]; 94 } 95 96 public int getPreviousX(final char c, final int back) { 97 final int index = normalize(mEnd - 2 - back); 98 if (mLength <= back 99 || Character.toLowerCase(c) != Character.toLowerCase(mCharBuf[index])) { 100 return INVALID_COORDINATE; 101 } 102 return mXBuf[index]; 103 } 104 105 public int getPreviousY(final char c, final int back) { 106 int index = normalize(mEnd - 2 - back); 107 if (mLength <= back 108 || Character.toLowerCase(c) != Character.toLowerCase(mCharBuf[index])) { 109 return INVALID_COORDINATE; 110 } 111 return mYBuf[index]; 112 } 113 114 public String getLastWord(final int ignoreCharCount) { 115 final StringBuilder sb = new StringBuilder(); 116 int i = ignoreCharCount; 117 for (; i < mLength; ++i) { 118 final char c = mCharBuf[normalize(mEnd - 1 - i)]; 119 if (!Settings.getInstance().isWordSeparator(c)) { 120 break; 121 } 122 } 123 for (; i < mLength; ++i) { 124 char c = mCharBuf[normalize(mEnd - 1 - i)]; 125 if (!Settings.getInstance().isWordSeparator(c)) { 126 sb.append(c); 127 } else { 128 break; 129 } 130 } 131 return sb.reverse().toString(); 132 } 133 134 public void reset() { 135 mLength = 0; 136 } 137 } 138