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