107e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick /* 207e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick * Copyright (C) 2009 The Android Open Source Project 307e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick * 407e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick * Licensed under the Apache License, Version 2.0 (the "License"); 507e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick * you may not use this file except in compliance with the License. 607e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick * You may obtain a copy of the License at 707e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick * 807e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick * http://www.apache.org/licenses/LICENSE-2.0 907e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick * 1007e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick * Unless required by applicable law or agreed to in writing, software 1107e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick * distributed under the License is distributed on an "AS IS" BASIS, 1207e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1307e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick * See the License for the specific language governing permissions and 1407e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick * limitations under the License. 1507e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick */ 1607e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick 1707e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrickpackage com.android.mms.util; 1807e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick 1907e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrickimport java.util.HashSet; 20b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrickimport java.util.Set; 2107e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick 2207e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrickimport android.content.Context; 2307e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrickimport android.database.Cursor; 24d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport android.database.sqlite.SqliteWrapper; 25f7e8281a223af6228e6399055a6197a1edd9bc3aTom Taylorimport android.provider.Telephony.MmsSms; 26f7e8281a223af6228e6399055a6197a1edd9bc3aTom Taylorimport android.provider.Telephony.Sms.Conversations; 2707e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrickimport android.util.Log; 2807e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick 29d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.LogTag; 30d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chen 3107e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick/** 3207e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick * Cache for information about draft messages on conversations. 3307e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick */ 3407e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrickpublic class DraftCache { 35ab845dee6565a8dfc384186bc8f2e801a2b087e1Ye Wen private static final String TAG = LogTag.TAG; 3607e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick 3707e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick private static DraftCache sInstance; 3807e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick 3907e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick private final Context mContext; 4007e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick 41b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev private boolean mSavingDraft; // true when we're in the process of saving a draft. Check this 425fd2543851375fc764495584ddd319f5e7d13cb9Tom Taylor // before deleting any empty threads from the db. 43b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev private final Object mSavingDraftLock = new Object(); 445fd2543851375fc764495584ddd319f5e7d13cb9Tom Taylor 45b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick private HashSet<Long> mDraftSet = new HashSet<Long>(4); 46b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev private final Object mDraftSetLock = new Object(); 47b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick private final HashSet<OnDraftChangedListener> mChangeListeners 48b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick = new HashSet<OnDraftChangedListener>(1); 49b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev private final Object mChangeListenersLock = new Object(); 505fd2543851375fc764495584ddd319f5e7d13cb9Tom Taylor 51b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick public interface OnDraftChangedListener { 52b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick void onDraftChanged(long threadId, boolean hasDraft); 53b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick } 545fd2543851375fc764495584ddd319f5e7d13cb9Tom Taylor 5507e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick private DraftCache(Context context) { 56812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang if (Log.isLoggable(LogTag.APP, Log.DEBUG)) { 57812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang log("DraftCache.constructor"); 58812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang } 59812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang 6007e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick mContext = context; 6107e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick refresh(); 6207e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick } 6307e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick 6407e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick static final String[] DRAFT_PROJECTION = new String[] { 6570c73e05a792832aa28da751cdaf3fa83a7b8113Ficus Kirkpatrick Conversations.THREAD_ID // 0 6607e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick }; 6707e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick 6870c73e05a792832aa28da751cdaf3fa83a7b8113Ficus Kirkpatrick static final int COLUMN_DRAFT_THREAD_ID = 0; 6907e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick 7007e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick /** To be called whenever the draft state might have changed. 7107e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick * Dispatches work to a thread and returns immediately. 7207e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick */ 7307e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick public void refresh() { 74812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang if (Log.isLoggable(LogTag.APP, Log.DEBUG)) { 75812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang log("refresh"); 76812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang } 77812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang 78b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev Thread thread = new Thread(new Runnable() { 79ddd31c4011b4191035bdfbba05a8edb1785f71afTodor Kalaydjiev @Override 8007e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick public void run() { 8107e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick rebuildCache(); 8207e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick } 83b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev }, "DraftCache.refresh"); 84b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev thread.setPriority(Thread.MIN_PRIORITY); 85b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev thread.start(); 8607e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick } 8707e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick 8807e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick /** Does the actual work of rebuilding the draft cache. 8907e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick */ 90b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev private void rebuildCache() { 91812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang if (Log.isLoggable(LogTag.APP, Log.DEBUG)) { 92812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang log("rebuildCache"); 93812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang } 94812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang 95b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev HashSet<Long> newDraftSet = new HashSet<Long>(); 965fd2543851375fc764495584ddd319f5e7d13cb9Tom Taylor 97b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick Cursor cursor = SqliteWrapper.query( 98b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick mContext, 99b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick mContext.getContentResolver(), 100b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick MmsSms.CONTENT_DRAFT_URI, 101b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick DRAFT_PROJECTION, null, null, null); 102b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick 103c6448572ff5c0be247cdb75467e54756f18c3051Tom Taylor if (cursor != null) { 104c6448572ff5c0be247cdb75467e54756f18c3051Tom Taylor try { 105c6448572ff5c0be247cdb75467e54756f18c3051Tom Taylor if (cursor.moveToFirst()) { 106c6448572ff5c0be247cdb75467e54756f18c3051Tom Taylor for (; !cursor.isAfterLast(); cursor.moveToNext()) { 107c6448572ff5c0be247cdb75467e54756f18c3051Tom Taylor long threadId = cursor.getLong(COLUMN_DRAFT_THREAD_ID); 108c6448572ff5c0be247cdb75467e54756f18c3051Tom Taylor newDraftSet.add(threadId); 109c6448572ff5c0be247cdb75467e54756f18c3051Tom Taylor if (Log.isLoggable(LogTag.APP, Log.DEBUG)) { 110c6448572ff5c0be247cdb75467e54756f18c3051Tom Taylor log("rebuildCache: add tid=" + threadId); 111c6448572ff5c0be247cdb75467e54756f18c3051Tom Taylor } 112812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang } 11307e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick } 114c6448572ff5c0be247cdb75467e54756f18c3051Tom Taylor } finally { 115c6448572ff5c0be247cdb75467e54756f18c3051Tom Taylor cursor.close(); 116b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick } 117b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick } 1185fd2543851375fc764495584ddd319f5e7d13cb9Tom Taylor 119b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev Set<Long> added; 120b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev Set<Long> removed; 121b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev synchronized (mDraftSetLock) { 122b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev HashSet<Long> oldDraftSet = mDraftSet; 123b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev mDraftSet = newDraftSet; 1245fd2543851375fc764495584ddd319f5e7d13cb9Tom Taylor 125b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) { 126b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev dump(); 127b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev } 128b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick 129b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev // If nobody's interested in finding out about changes, 130b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev // just bail out early. 131b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev synchronized (mChangeListenersLock) { 132b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev if (mChangeListeners.size() < 1) { 133b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev return; 134b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev } 135b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick } 136b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev 137b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev // Find out which drafts were removed and added and notify 138b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev // listeners. 139b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev added = new HashSet<Long>(newDraftSet); 140b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev added.removeAll(oldDraftSet); 141b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev removed = new HashSet<Long>(oldDraftSet); 142b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev removed.removeAll(newDraftSet); 143b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev } 144b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev 145b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev synchronized (mChangeListenersLock) { 146b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev for (OnDraftChangedListener l : mChangeListeners) { 147b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev for (long threadId : added) { 148b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev l.onDraftChanged(threadId, true); 149b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev } 150b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev for (long threadId : removed) { 151b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev l.onDraftChanged(threadId, false); 152b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev } 15307e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick } 15407e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick } 15507e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick } 1565fd2543851375fc764495584ddd319f5e7d13cb9Tom Taylor 15707e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick /** Updates the has-draft status of a particular thread on 15807e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick * a piecemeal basis, to be called when a draft has appeared 15907e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick * or disappeared. 16007e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick */ 161b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev public void setDraftState(long threadId, boolean hasDraft) { 162598ca14f5d7d26d6d5125d8fe0d07e50f066ff98Ficus Kirkpatrick if (threadId <= 0) { 163598ca14f5d7d26d6d5125d8fe0d07e50f066ff98Ficus Kirkpatrick return; 164598ca14f5d7d26d6d5125d8fe0d07e50f066ff98Ficus Kirkpatrick } 1655fd2543851375fc764495584ddd319f5e7d13cb9Tom Taylor 166b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick boolean changed; 167b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev synchronized (mDraftSetLock) { 168b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev if (hasDraft) { 169b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev changed = mDraftSet.add(threadId); 170b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev } else { 171b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev changed = mDraftSet.remove(threadId); 172b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev } 173b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick } 174b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick 175d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang if (Log.isLoggable(LogTag.APP, Log.DEBUG)) { 176d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang log("setDraftState: tid=" + threadId + ", value=" + hasDraft + ", changed=" + changed); 177d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang } 178d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang 179812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) { 180812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang dump(); 181812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang } 182812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang 183b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick // Notify listeners if there was a change. 184b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick if (changed) { 185b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev synchronized (mChangeListenersLock) { 186b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev for (OnDraftChangedListener l : mChangeListeners) { 187b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev l.onDraftChanged(threadId, hasDraft); 188b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev } 18907e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick } 19007e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick } 19107e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick } 19207e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick 19307e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick /** Returns true if the given thread ID has a draft associated 19407e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick * with it, false if not. 19507e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick */ 196b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev public boolean hasDraft(long threadId) { 197b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev synchronized (mDraftSetLock) { 198b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev return mDraftSet.contains(threadId); 199b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev } 20007e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick } 201b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick 202b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev public void addOnDraftChangedListener(OnDraftChangedListener l) { 203d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang if (Log.isLoggable(LogTag.APP, Log.DEBUG)) { 204d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang log("addOnDraftChangedListener " + l); 205d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang } 206b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev synchronized (mChangeListenersLock) { 207b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev mChangeListeners.add(l); 208b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev } 209b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick } 210b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick 211b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev public void removeOnDraftChangedListener(OnDraftChangedListener l) { 212d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang if (Log.isLoggable(LogTag.APP, Log.DEBUG)) { 213d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang log("removeOnDraftChangedListener " + l); 214d9d7479a8c9e10b7b3f39137e28ed0f283e4a257Wei Huang } 215b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev synchronized (mChangeListenersLock) { 216b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev mChangeListeners.remove(l); 217b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev } 218b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick } 219b530437ceaad97151be691067191f48e1e93b87eFicus Kirkpatrick 220b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev public void setSavingDraft(final boolean savingDraft) { 221b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev synchronized (mSavingDraftLock) { 222b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev mSavingDraft = savingDraft; 223b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev } 2245fd2543851375fc764495584ddd319f5e7d13cb9Tom Taylor } 2255fd2543851375fc764495584ddd319f5e7d13cb9Tom Taylor 226b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev public boolean getSavingDraft() { 227b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev synchronized (mSavingDraftLock) { 228b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev return mSavingDraft; 229b542562125619f1d35958ca11c4ffa34eca55cb1Todor Kalaydjiev } 2305fd2543851375fc764495584ddd319f5e7d13cb9Tom Taylor } 2315fd2543851375fc764495584ddd319f5e7d13cb9Tom Taylor 23207e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick /** 23307e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick * Initialize the global instance. Should call only once. 23407e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick */ 23507e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick public static void init(Context context) { 23607e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick sInstance = new DraftCache(context); 23707e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick } 23807e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick 23907e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick /** 24007e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick * Get the global instance. 24107e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick */ 24207e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick public static DraftCache getInstance() { 24307e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick return sInstance; 24407e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick } 2455fd2543851375fc764495584ddd319f5e7d13cb9Tom Taylor 246812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang public void dump() { 247812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang Log.i(TAG, "dump:"); 248812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang for (Long threadId : mDraftSet) { 249812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang Log.i(TAG, " tid: " + threadId); 250812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang } 251812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang } 2525fd2543851375fc764495584ddd319f5e7d13cb9Tom Taylor 25307e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick private void log(String format, Object... args) { 25407e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick String s = String.format(format, args); 255812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang Log.d(TAG, "[DraftCache/" + Thread.currentThread().getId() + "] " + s); 25607e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick } 25707e7775d5a792334b89436bf5479bfd5abeeb8c4Ficus Kirkpatrick} 258