19419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa/*
29419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa * Copyright (C) 2013 The Android Open Source Project
39419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa *
49419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa * Licensed under the Apache License, Version 2.0 (the "License");
59419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa * you may not use this file except in compliance with the License.
69419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa * You may obtain a copy of the License at
79419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa *
89419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa *      http://www.apache.org/licenses/LICENSE-2.0
99419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa *
109419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa * Unless required by applicable law or agreed to in writing, software
119419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa * distributed under the License is distributed on an "AS IS" BASIS,
129419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa * See the License for the specific language governing permissions and
149419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa * limitations under the License.
159419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa */
169419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa
179419e02fd98e044136bf8888ad9781900ba42469Ken Wakasapackage com.android.inputmethod.latin.utils;
189419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa
199419e02fd98e044136bf8888ad9781900ba42469Ken Wakasaimport android.inputmethodservice.InputMethodService;
209419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa
219419e02fd98e044136bf8888ad9781900ba42469Ken Wakasaimport com.android.inputmethod.annotations.UsedForTesting;
22cfcf6660fc369fefd4028451334a9c2eda9bc4e5Ken Wakasaimport com.android.inputmethod.latin.LatinImeLogger;
23a7d2fc6befa1b16883200a653fc01deb4d94944dKen Wakasaimport com.android.inputmethod.latin.settings.Settings;
249419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa
259419e02fd98e044136bf8888ad9781900ba42469Ken Wakasapublic final class UserLogRingCharBuffer {
269419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    public /* for test */ static final int BUFSIZE = 20;
279419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    public /* for test */ int mLength = 0;
289419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa
299419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    private static UserLogRingCharBuffer sUserLogRingCharBuffer = new UserLogRingCharBuffer();
309419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    private static final char PLACEHOLDER_DELIMITER_CHAR = '\uFFFC';
319419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    private static final int INVALID_COORDINATE = -2;
329419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    private boolean mEnabled = false;
339419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    private int mEnd = 0;
349419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    private char[] mCharBuf = new char[BUFSIZE];
359419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    private int[] mXBuf = new int[BUFSIZE];
369419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    private int[] mYBuf = new int[BUFSIZE];
379419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa
389419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    private UserLogRingCharBuffer() {
399419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        // Intentional empty constructor for singleton.
409419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    }
419419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa
429419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    @UsedForTesting
439419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    public static UserLogRingCharBuffer getInstance() {
449419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        return sUserLogRingCharBuffer;
459419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    }
469419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa
479419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    public static UserLogRingCharBuffer init(final InputMethodService context,
489419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa            final boolean enabled, final boolean usabilityStudy) {
499419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        if (!(enabled || usabilityStudy)) {
509419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa            return null;
519419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        }
529419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        sUserLogRingCharBuffer.mEnabled = true;
539419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        UsabilityStudyLogUtils.getInstance().init(context);
549419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        return sUserLogRingCharBuffer;
559419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    }
569419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa
579419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    private static int normalize(final int in) {
589419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        int ret = in % BUFSIZE;
599419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        return ret < 0 ? ret + BUFSIZE : ret;
609419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    }
619419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa
629419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    // TODO: accept code points
639419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    @UsedForTesting
649419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    public void push(final char c, final int x, final int y) {
659419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        if (!mEnabled) {
669419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa            return;
679419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        }
68cfcf6660fc369fefd4028451334a9c2eda9bc4e5Ken Wakasa        if (LatinImeLogger.sUsabilityStudy) {
69cfcf6660fc369fefd4028451334a9c2eda9bc4e5Ken Wakasa            UsabilityStudyLogUtils.getInstance().writeChar(c, x, y);
70cfcf6660fc369fefd4028451334a9c2eda9bc4e5Ken Wakasa        }
719419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        mCharBuf[mEnd] = c;
729419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        mXBuf[mEnd] = x;
739419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        mYBuf[mEnd] = y;
749419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        mEnd = normalize(mEnd + 1);
759419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        if (mLength < BUFSIZE) {
769419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa            ++mLength;
779419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        }
789419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    }
799419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa
809419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    public char pop() {
819419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        if (mLength < 1) {
829419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa            return PLACEHOLDER_DELIMITER_CHAR;
839419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        }
849419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        mEnd = normalize(mEnd - 1);
859419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        --mLength;
869419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        return mCharBuf[mEnd];
879419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    }
889419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa
899419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    public char getBackwardNthChar(final int n) {
909419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        if (mLength <= n || n < 0) {
919419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa            return PLACEHOLDER_DELIMITER_CHAR;
929419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        }
939419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        return mCharBuf[normalize(mEnd - n - 1)];
949419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    }
959419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa
969419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    public int getPreviousX(final char c, final int back) {
979419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        final int index = normalize(mEnd - 2 - back);
989419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        if (mLength <= back
999419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa                || Character.toLowerCase(c) != Character.toLowerCase(mCharBuf[index])) {
1009419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa            return INVALID_COORDINATE;
1019419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        }
1029419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        return mXBuf[index];
1039419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    }
1049419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa
1059419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    public int getPreviousY(final char c, final int back) {
1069419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        int index = normalize(mEnd - 2 - back);
1079419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        if (mLength <= back
1089419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa                || Character.toLowerCase(c) != Character.toLowerCase(mCharBuf[index])) {
1099419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa            return INVALID_COORDINATE;
1109419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        }
1119419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        return mYBuf[index];
1129419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    }
1139419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa
1149419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    public String getLastWord(final int ignoreCharCount) {
1159419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        final StringBuilder sb = new StringBuilder();
1169419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        int i = ignoreCharCount;
1179419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        for (; i < mLength; ++i) {
1189419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa            final char c = mCharBuf[normalize(mEnd - 1 - i)];
1199419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa            if (!Settings.getInstance().isWordSeparator(c)) {
1209419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa                break;
1219419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa            }
1229419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        }
1239419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        for (; i < mLength; ++i) {
1249419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa            char c = mCharBuf[normalize(mEnd - 1 - i)];
1259419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa            if (!Settings.getInstance().isWordSeparator(c)) {
1269419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa                sb.append(c);
1279419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa            } else {
1289419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa                break;
1299419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa            }
1309419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        }
1319419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        return sb.reverse().toString();
1329419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    }
1339419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa
1349419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    public void reset() {
1359419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa        mLength = 0;
1369419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa    }
1379419e02fd98e044136bf8888ad9781900ba42469Ken Wakasa}
138