Loading java/src/com/android/inputmethod/latin/LatinIME.java +1 −1 Original line number Diff line number Diff line Loading @@ -497,7 +497,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged() // is not guaranteed. It may even be called at the same time on a different thread. if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this); mUserHistoryDictionary = new UserHistoryDictionary( mUserHistoryDictionary = UserHistoryDictionary.getInstance( this, localeStr, Suggest.DIC_USER_HISTORY, mPrefs); mSuggest.setUserHistoryDictionary(mUserHistoryDictionary); } Loading java/src/com/android/inputmethod/latin/UserHistoryDictionary.java +189 −125 Original line number Diff line number Diff line Loading @@ -29,7 +29,9 @@ import android.util.Log; import com.android.inputmethod.latin.UserHistoryForgettingCurveUtils.ForgettingCurveParams; import java.lang.ref.SoftReference; import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; /** * Locally gathers stats about the words user types and various other signals like auto-correction Loading @@ -38,6 +40,7 @@ import java.util.HashMap; public class UserHistoryDictionary extends ExpandableDictionary { private static final String TAG = "UserHistoryDictionary"; public static final boolean DBG_SAVE_RESTORE = false; public static final boolean PROFILE_SAVE_RESTORE = LatinImeLogger.sDBG; /** Any pair being typed or picked */ private static final int FREQUENCY_FOR_TYPED = 2; Loading Loading @@ -77,13 +80,14 @@ public class UserHistoryDictionary extends ExpandableDictionary { /** Locale for which this user history dictionary is storing words */ private final String mLocale; private UserHistoryDictionaryBigramList mBigramList = private final UserHistoryDictionaryBigramList mBigramList = new UserHistoryDictionaryBigramList(); private final Object mPendingWritesLock = new Object(); private static volatile boolean sUpdatingDB = false; private final SharedPreferences mPrefs; private final static HashMap<String, String> sDictProjectionMap; private final static ConcurrentHashMap<String, SoftReference<UserHistoryDictionary>> sLangDictCache = new ConcurrentHashMap<String, SoftReference<UserHistoryDictionary>>(); static { sDictProjectionMap = new HashMap<String, String>(); Loading @@ -107,7 +111,26 @@ public class UserHistoryDictionary extends ExpandableDictionary { sDeleteHistoryBigrams = deleteHistoryBigram; } public UserHistoryDictionary(final Context context, final String locale, final int dicTypeId, public synchronized static UserHistoryDictionary getInstance( final Context context, final String locale, final int dictTypeId, final SharedPreferences sp) { if (sLangDictCache.containsKey(locale)) { final SoftReference<UserHistoryDictionary> ref = sLangDictCache.get(locale); final UserHistoryDictionary dict = ref == null ? null : ref.get(); if (dict != null) { if (PROFILE_SAVE_RESTORE) { Log.w(TAG, "Use cached UserHistoryDictionary for " + locale); } return dict; } } final UserHistoryDictionary dict = new UserHistoryDictionary(context, locale, dictTypeId, sp); sLangDictCache.put(locale, new SoftReference<UserHistoryDictionary>(dict)); return dict; } private UserHistoryDictionary(final Context context, final String locale, final int dicTypeId, SharedPreferences sp) { super(context, dicTypeId); mLocale = locale; Loading @@ -123,12 +146,13 @@ public class UserHistoryDictionary extends ExpandableDictionary { @Override public void close() { flushPendingWrites(); SettingsValues.setLastUserHistoryWriteTime(mPrefs, mLocale); // Don't close the database as locale changes will require it to be reopened anyway // Also, the database is written to somewhat frequently, so it needs to be kept alive // throughout the life of the process. // mOpenHelper.close(); super.close(); // Ignore close because we cache UserHistoryDictionary for each language. See getInstance() // above. // super.close(); } /** Loading Loading @@ -160,7 +184,7 @@ public class UserHistoryDictionary extends ExpandableDictionary { } else { freq = super.setBigramAndGetFrequency(word1, word2, new ForgettingCurveParams(isValid)); } synchronized (mPendingWritesLock) { synchronized (mBigramList) { mBigramList.addBigram(word1, word2); } Loading @@ -168,7 +192,7 @@ public class UserHistoryDictionary extends ExpandableDictionary { } public boolean cancelAddingUserHistory(String word1, String word2) { synchronized (mPendingWritesLock) { synchronized (mBigramList) { if (mBigramList.removeBigram(word1, word2)) { return super.removeBigram(word1, word2); } Loading @@ -180,19 +204,17 @@ public class UserHistoryDictionary extends ExpandableDictionary { * Schedules a background thread to write any pending words to the database. */ private void flushPendingWrites() { synchronized (mPendingWritesLock) { synchronized (mBigramList) { // Nothing pending? Return if (mBigramList.isEmpty()) return; // Create a background thread to write the pending entries new UpdateDbTask(sOpenHelper, mBigramList, mLocale, this).execute(); // Create a new map for writing new entries into while the old one is written to db mBigramList = new UserHistoryDictionaryBigramList(); new UpdateDbTask(sOpenHelper, mBigramList, mLocale, this, mPrefs).execute(); } } /** Used for testing purpose **/ void waitUntilUpdateDBDone() { synchronized (mPendingWritesLock) { synchronized (mBigramList) { while (sUpdatingDB) { try { Thread.sleep(100); Loading @@ -205,6 +227,7 @@ public class UserHistoryDictionary extends ExpandableDictionary { @Override public void loadDictionaryAsync() { synchronized(mBigramList) { final long last = SettingsValues.getLastUserHistoryWriteTime(mPrefs, mLocale); final long now = System.currentTimeMillis(); // Load the words that correspond to the current input locale Loading Loading @@ -232,14 +255,18 @@ public class UserHistoryDictionary extends ExpandableDictionary { super.setBigramAndGetFrequency( word1, word2, new ForgettingCurveParams(fc, now, last)); } synchronized(mPendingWritesLock) { mBigramList.addBigram(word1, word2, (byte)fc); } cursor.moveToNext(); } } } finally { cursor.close(); if (PROFILE_SAVE_RESTORE) { final long diff = System.currentTimeMillis() - now; Log.w(TAG, "PROF: Load User HistoryDictionary: " + mLocale + ", " + diff + "ms."); } } } } Loading Loading @@ -317,14 +344,16 @@ public class UserHistoryDictionary extends ExpandableDictionary { private final DatabaseHelper mDbHelper; private final String mLocale; private final UserHistoryDictionary mUserHistoryDictionary; private final SharedPreferences mPrefs; public UpdateDbTask( DatabaseHelper openHelper, UserHistoryDictionaryBigramList pendingWrites, String locale, UserHistoryDictionary dict) { String locale, UserHistoryDictionary dict, SharedPreferences prefs) { mBigramList = pendingWrites; mLocale = locale; mDbHelper = openHelper; mUserHistoryDictionary = dict; mPrefs = prefs; } /** Prune any old data if the database is getting too big. */ Loading Loading @@ -363,6 +392,11 @@ public class UserHistoryDictionary extends ExpandableDictionary { @Override protected Void doInBackground(Void... v) { synchronized(mBigramList) { final long now = PROFILE_SAVE_RESTORE ? System.currentTimeMillis() : 0; int profTotal = 0; int profInsert = 0; int profDelete = 0; SQLiteDatabase db = null; try { db = mDbHelper.getWritableDatabase(); Loading @@ -382,11 +416,24 @@ public class UserHistoryDictionary extends ExpandableDictionary { for (String word1 : mBigramList.keySet()) { final HashMap<String, Byte> word1Bigrams = mBigramList.getBigrams(word1); for (String word2 : word1Bigrams.keySet()) { // Get new frequency. Do not insert shortcuts/bigrams which freq is "-1". if (PROFILE_SAVE_RESTORE) { ++profTotal; } // Get new frequency. Do not insert unigrams/bigrams which freq is "-1". final int freq; // -1, or 0~255 if (word1 == null) { if (word1 == null) { // unigram freq = FREQUENCY_FOR_TYPED; } else { final byte prevFc = word1Bigrams.get(word2); if (prevFc == FREQUENCY_FOR_TYPED) { // No need to update since we found no changes for this entry. // Just skip to the next entry. if (DBG_SAVE_RESTORE) { Log.d(TAG, "Skip update user history: " + word1 + "," + word2 + "," + prevFc); } continue; } } else { // bigram final NextWord nw = mUserHistoryDictionary.getBigramWord(word1, word2); if (nw != null) { final ForgettingCurveParams fcp = nw.getFcParams(); Loading @@ -397,8 +444,8 @@ public class UserHistoryDictionary extends ExpandableDictionary { // No need to update since we found no changes for this entry. // Just skip to the next entry. if (DBG_SAVE_RESTORE) { Log.d(TAG, "Skip update user history: " + word1 + "," + word2 + "," + prevFc); Log.d(TAG, "Skip update user history: " + word1 + "," + word2 + "," + prevFc); } continue; } else if (UserHistoryForgettingCurveUtils. Loading Loading @@ -431,6 +478,9 @@ public class UserHistoryDictionary extends ExpandableDictionary { final int pairId; if (c.moveToFirst()) { if (PROFILE_SAVE_RESTORE) { ++profDelete; } // Delete existing pair pairId = c.getInt(c.getColumnIndex(MAIN_COLUMN_ID)); db.delete(FREQ_TABLE_NAME, FREQ_COLUMN_PAIR_ID + "=?", Loading @@ -442,6 +492,9 @@ public class UserHistoryDictionary extends ExpandableDictionary { pairId = pairIdLong.intValue(); } if (freq > 0) { if (PROFILE_SAVE_RESTORE) { ++profInsert; } if (DBG_SAVE_RESTORE) { Log.d(TAG, "--- Save user history: " + word1 + ", " + word2 + mLocale + "," + this); Loading @@ -449,6 +502,9 @@ public class UserHistoryDictionary extends ExpandableDictionary { // Insert new frequency db.insert(FREQ_TABLE_NAME, null, getFrequencyContentValues(pairId, freq)); // Update an existing bigram entry in mBigramList too in order to // synchronize the SQL DB and mBigramList. mBigramList.updateBigram(word1, word2, (byte)freq); } } finally { if (c != null) { Loading @@ -459,9 +515,17 @@ public class UserHistoryDictionary extends ExpandableDictionary { } checkPruneData(db); // Save the timestamp after we finish writing the SQL DB. SettingsValues.setLastUserHistoryWriteTime(mPrefs, mLocale); sUpdatingDB = false; if (PROFILE_SAVE_RESTORE) { final long diff = System.currentTimeMillis() - now; Log.w(TAG, "PROF: Write User HistoryDictionary: " + mLocale + ", "+ diff + "ms. Total: " + profTotal + ". Insert: " + profInsert + ". Delete: " + profDelete); } return null; } // synchronized } private static ContentValues getContentValues(String word1, String word2, String locale) { Loading java/src/com/android/inputmethod/latin/UserHistoryDictionaryBigramList.java +26 −1 Original line number Diff line number Diff line Loading @@ -39,13 +39,19 @@ public class UserHistoryDictionaryBigramList { mBigramMap.clear(); } /** * Called when the user typed a word. */ public void addBigram(String word1, String word2) { addBigram(word1, word2, FORGETTING_CURVE_INITIAL_VALUE); } /** * Called when loaded from the SQL DB. */ public void addBigram(String word1, String word2, byte fcValue) { if (UserHistoryDictionary.DBG_SAVE_RESTORE) { Log.d(TAG, "--- add bigram: " + word1 + ", " + word2); Log.d(TAG, "--- add bigram: " + word1 + ", " + word2 + ", " + fcValue); } final HashMap<String, Byte> map; if (mBigramMap.containsKey(word1)) { Loading @@ -60,6 +66,25 @@ public class UserHistoryDictionaryBigramList { } } /** * Called when inserted to the SQL DB. */ public void updateBigram(String word1, String word2, byte fcValue) { if (UserHistoryDictionary.DBG_SAVE_RESTORE) { Log.d(TAG, "--- update bigram: " + word1 + ", " + word2 + ", " + fcValue); } final HashMap<String, Byte> map; if (mBigramMap.containsKey(word1)) { map = mBigramMap.get(word1); } else { return; } if (!map.containsKey(word2)) { return; } map.put(word2, fcValue); } public int size() { return mSize; } Loading Loading
java/src/com/android/inputmethod/latin/LatinIME.java +1 −1 Original line number Diff line number Diff line Loading @@ -497,7 +497,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged() // is not guaranteed. It may even be called at the same time on a different thread. if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this); mUserHistoryDictionary = new UserHistoryDictionary( mUserHistoryDictionary = UserHistoryDictionary.getInstance( this, localeStr, Suggest.DIC_USER_HISTORY, mPrefs); mSuggest.setUserHistoryDictionary(mUserHistoryDictionary); } Loading
java/src/com/android/inputmethod/latin/UserHistoryDictionary.java +189 −125 Original line number Diff line number Diff line Loading @@ -29,7 +29,9 @@ import android.util.Log; import com.android.inputmethod.latin.UserHistoryForgettingCurveUtils.ForgettingCurveParams; import java.lang.ref.SoftReference; import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; /** * Locally gathers stats about the words user types and various other signals like auto-correction Loading @@ -38,6 +40,7 @@ import java.util.HashMap; public class UserHistoryDictionary extends ExpandableDictionary { private static final String TAG = "UserHistoryDictionary"; public static final boolean DBG_SAVE_RESTORE = false; public static final boolean PROFILE_SAVE_RESTORE = LatinImeLogger.sDBG; /** Any pair being typed or picked */ private static final int FREQUENCY_FOR_TYPED = 2; Loading Loading @@ -77,13 +80,14 @@ public class UserHistoryDictionary extends ExpandableDictionary { /** Locale for which this user history dictionary is storing words */ private final String mLocale; private UserHistoryDictionaryBigramList mBigramList = private final UserHistoryDictionaryBigramList mBigramList = new UserHistoryDictionaryBigramList(); private final Object mPendingWritesLock = new Object(); private static volatile boolean sUpdatingDB = false; private final SharedPreferences mPrefs; private final static HashMap<String, String> sDictProjectionMap; private final static ConcurrentHashMap<String, SoftReference<UserHistoryDictionary>> sLangDictCache = new ConcurrentHashMap<String, SoftReference<UserHistoryDictionary>>(); static { sDictProjectionMap = new HashMap<String, String>(); Loading @@ -107,7 +111,26 @@ public class UserHistoryDictionary extends ExpandableDictionary { sDeleteHistoryBigrams = deleteHistoryBigram; } public UserHistoryDictionary(final Context context, final String locale, final int dicTypeId, public synchronized static UserHistoryDictionary getInstance( final Context context, final String locale, final int dictTypeId, final SharedPreferences sp) { if (sLangDictCache.containsKey(locale)) { final SoftReference<UserHistoryDictionary> ref = sLangDictCache.get(locale); final UserHistoryDictionary dict = ref == null ? null : ref.get(); if (dict != null) { if (PROFILE_SAVE_RESTORE) { Log.w(TAG, "Use cached UserHistoryDictionary for " + locale); } return dict; } } final UserHistoryDictionary dict = new UserHistoryDictionary(context, locale, dictTypeId, sp); sLangDictCache.put(locale, new SoftReference<UserHistoryDictionary>(dict)); return dict; } private UserHistoryDictionary(final Context context, final String locale, final int dicTypeId, SharedPreferences sp) { super(context, dicTypeId); mLocale = locale; Loading @@ -123,12 +146,13 @@ public class UserHistoryDictionary extends ExpandableDictionary { @Override public void close() { flushPendingWrites(); SettingsValues.setLastUserHistoryWriteTime(mPrefs, mLocale); // Don't close the database as locale changes will require it to be reopened anyway // Also, the database is written to somewhat frequently, so it needs to be kept alive // throughout the life of the process. // mOpenHelper.close(); super.close(); // Ignore close because we cache UserHistoryDictionary for each language. See getInstance() // above. // super.close(); } /** Loading Loading @@ -160,7 +184,7 @@ public class UserHistoryDictionary extends ExpandableDictionary { } else { freq = super.setBigramAndGetFrequency(word1, word2, new ForgettingCurveParams(isValid)); } synchronized (mPendingWritesLock) { synchronized (mBigramList) { mBigramList.addBigram(word1, word2); } Loading @@ -168,7 +192,7 @@ public class UserHistoryDictionary extends ExpandableDictionary { } public boolean cancelAddingUserHistory(String word1, String word2) { synchronized (mPendingWritesLock) { synchronized (mBigramList) { if (mBigramList.removeBigram(word1, word2)) { return super.removeBigram(word1, word2); } Loading @@ -180,19 +204,17 @@ public class UserHistoryDictionary extends ExpandableDictionary { * Schedules a background thread to write any pending words to the database. */ private void flushPendingWrites() { synchronized (mPendingWritesLock) { synchronized (mBigramList) { // Nothing pending? Return if (mBigramList.isEmpty()) return; // Create a background thread to write the pending entries new UpdateDbTask(sOpenHelper, mBigramList, mLocale, this).execute(); // Create a new map for writing new entries into while the old one is written to db mBigramList = new UserHistoryDictionaryBigramList(); new UpdateDbTask(sOpenHelper, mBigramList, mLocale, this, mPrefs).execute(); } } /** Used for testing purpose **/ void waitUntilUpdateDBDone() { synchronized (mPendingWritesLock) { synchronized (mBigramList) { while (sUpdatingDB) { try { Thread.sleep(100); Loading @@ -205,6 +227,7 @@ public class UserHistoryDictionary extends ExpandableDictionary { @Override public void loadDictionaryAsync() { synchronized(mBigramList) { final long last = SettingsValues.getLastUserHistoryWriteTime(mPrefs, mLocale); final long now = System.currentTimeMillis(); // Load the words that correspond to the current input locale Loading Loading @@ -232,14 +255,18 @@ public class UserHistoryDictionary extends ExpandableDictionary { super.setBigramAndGetFrequency( word1, word2, new ForgettingCurveParams(fc, now, last)); } synchronized(mPendingWritesLock) { mBigramList.addBigram(word1, word2, (byte)fc); } cursor.moveToNext(); } } } finally { cursor.close(); if (PROFILE_SAVE_RESTORE) { final long diff = System.currentTimeMillis() - now; Log.w(TAG, "PROF: Load User HistoryDictionary: " + mLocale + ", " + diff + "ms."); } } } } Loading Loading @@ -317,14 +344,16 @@ public class UserHistoryDictionary extends ExpandableDictionary { private final DatabaseHelper mDbHelper; private final String mLocale; private final UserHistoryDictionary mUserHistoryDictionary; private final SharedPreferences mPrefs; public UpdateDbTask( DatabaseHelper openHelper, UserHistoryDictionaryBigramList pendingWrites, String locale, UserHistoryDictionary dict) { String locale, UserHistoryDictionary dict, SharedPreferences prefs) { mBigramList = pendingWrites; mLocale = locale; mDbHelper = openHelper; mUserHistoryDictionary = dict; mPrefs = prefs; } /** Prune any old data if the database is getting too big. */ Loading Loading @@ -363,6 +392,11 @@ public class UserHistoryDictionary extends ExpandableDictionary { @Override protected Void doInBackground(Void... v) { synchronized(mBigramList) { final long now = PROFILE_SAVE_RESTORE ? System.currentTimeMillis() : 0; int profTotal = 0; int profInsert = 0; int profDelete = 0; SQLiteDatabase db = null; try { db = mDbHelper.getWritableDatabase(); Loading @@ -382,11 +416,24 @@ public class UserHistoryDictionary extends ExpandableDictionary { for (String word1 : mBigramList.keySet()) { final HashMap<String, Byte> word1Bigrams = mBigramList.getBigrams(word1); for (String word2 : word1Bigrams.keySet()) { // Get new frequency. Do not insert shortcuts/bigrams which freq is "-1". if (PROFILE_SAVE_RESTORE) { ++profTotal; } // Get new frequency. Do not insert unigrams/bigrams which freq is "-1". final int freq; // -1, or 0~255 if (word1 == null) { if (word1 == null) { // unigram freq = FREQUENCY_FOR_TYPED; } else { final byte prevFc = word1Bigrams.get(word2); if (prevFc == FREQUENCY_FOR_TYPED) { // No need to update since we found no changes for this entry. // Just skip to the next entry. if (DBG_SAVE_RESTORE) { Log.d(TAG, "Skip update user history: " + word1 + "," + word2 + "," + prevFc); } continue; } } else { // bigram final NextWord nw = mUserHistoryDictionary.getBigramWord(word1, word2); if (nw != null) { final ForgettingCurveParams fcp = nw.getFcParams(); Loading @@ -397,8 +444,8 @@ public class UserHistoryDictionary extends ExpandableDictionary { // No need to update since we found no changes for this entry. // Just skip to the next entry. if (DBG_SAVE_RESTORE) { Log.d(TAG, "Skip update user history: " + word1 + "," + word2 + "," + prevFc); Log.d(TAG, "Skip update user history: " + word1 + "," + word2 + "," + prevFc); } continue; } else if (UserHistoryForgettingCurveUtils. Loading Loading @@ -431,6 +478,9 @@ public class UserHistoryDictionary extends ExpandableDictionary { final int pairId; if (c.moveToFirst()) { if (PROFILE_SAVE_RESTORE) { ++profDelete; } // Delete existing pair pairId = c.getInt(c.getColumnIndex(MAIN_COLUMN_ID)); db.delete(FREQ_TABLE_NAME, FREQ_COLUMN_PAIR_ID + "=?", Loading @@ -442,6 +492,9 @@ public class UserHistoryDictionary extends ExpandableDictionary { pairId = pairIdLong.intValue(); } if (freq > 0) { if (PROFILE_SAVE_RESTORE) { ++profInsert; } if (DBG_SAVE_RESTORE) { Log.d(TAG, "--- Save user history: " + word1 + ", " + word2 + mLocale + "," + this); Loading @@ -449,6 +502,9 @@ public class UserHistoryDictionary extends ExpandableDictionary { // Insert new frequency db.insert(FREQ_TABLE_NAME, null, getFrequencyContentValues(pairId, freq)); // Update an existing bigram entry in mBigramList too in order to // synchronize the SQL DB and mBigramList. mBigramList.updateBigram(word1, word2, (byte)freq); } } finally { if (c != null) { Loading @@ -459,9 +515,17 @@ public class UserHistoryDictionary extends ExpandableDictionary { } checkPruneData(db); // Save the timestamp after we finish writing the SQL DB. SettingsValues.setLastUserHistoryWriteTime(mPrefs, mLocale); sUpdatingDB = false; if (PROFILE_SAVE_RESTORE) { final long diff = System.currentTimeMillis() - now; Log.w(TAG, "PROF: Write User HistoryDictionary: " + mLocale + ", "+ diff + "ms. Total: " + profTotal + ". Insert: " + profInsert + ". Delete: " + profDelete); } return null; } // synchronized } private static ContentValues getContentValues(String word1, String word2, String locale) { Loading
java/src/com/android/inputmethod/latin/UserHistoryDictionaryBigramList.java +26 −1 Original line number Diff line number Diff line Loading @@ -39,13 +39,19 @@ public class UserHistoryDictionaryBigramList { mBigramMap.clear(); } /** * Called when the user typed a word. */ public void addBigram(String word1, String word2) { addBigram(word1, word2, FORGETTING_CURVE_INITIAL_VALUE); } /** * Called when loaded from the SQL DB. */ public void addBigram(String word1, String word2, byte fcValue) { if (UserHistoryDictionary.DBG_SAVE_RESTORE) { Log.d(TAG, "--- add bigram: " + word1 + ", " + word2); Log.d(TAG, "--- add bigram: " + word1 + ", " + word2 + ", " + fcValue); } final HashMap<String, Byte> map; if (mBigramMap.containsKey(word1)) { Loading @@ -60,6 +66,25 @@ public class UserHistoryDictionaryBigramList { } } /** * Called when inserted to the SQL DB. */ public void updateBigram(String word1, String word2, byte fcValue) { if (UserHistoryDictionary.DBG_SAVE_RESTORE) { Log.d(TAG, "--- update bigram: " + word1 + ", " + word2 + ", " + fcValue); } final HashMap<String, Byte> map; if (mBigramMap.containsKey(word1)) { map = mBigramMap.get(word1); } else { return; } if (!map.containsKey(word2)) { return; } map.put(word2, fcValue); } public int size() { return mSize; } Loading