ConversationSelectionSet.java revision 866d319dd23ec8b7b7d5476c65f7f83469d55d2d
14a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal/*******************************************************************************
24a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal *      Copyright (C) 2012 Google Inc.
34a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal *      Licensed to The Android Open Source Project.
44a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal *
54a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal *      Licensed under the Apache License, Version 2.0 (the "License");
64a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal *      you may not use this file except in compliance with the License.
74a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal *      You may obtain a copy of the License at
84a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal *
94a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal *           http://www.apache.org/licenses/LICENSE-2.0
104a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal *
114a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal *      Unless required by applicable law or agreed to in writing, software
124a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal *      distributed under the License is distributed on an "AS IS" BASIS,
134a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
144a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal *      See the License for the specific language governing permissions and
154a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal *      limitations under the License.
164a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal *******************************************************************************/
174a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal
184a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwalpackage com.android.mail.ui;
194a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal
204a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwalimport com.google.common.annotations.VisibleForTesting;
214a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwalimport com.google.common.collect.Lists;
224a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal
234a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwalimport android.os.Parcel;
244a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwalimport android.os.Parcelable;
254a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal
26866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereiraimport com.android.mail.browse.ConversationItemView;
271ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwalimport com.android.mail.providers.Conversation;
284a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwalimport java.util.ArrayList;
294a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwalimport java.util.Collection;
304a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwalimport java.util.HashMap;
314a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal
324a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal/**
334a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal * A simple thread-safe wrapper over a set of conversations representing a
344a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal * selection set (e.g. in a conversation list). This class dispatches changes
354a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal * when the set goes empty, and when it becomes unempty. For simplicity, this
364a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal * class <b>does not allow modifications</b> to the collection in observers when
374a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal * responding to change events.
384a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal */
394a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwalpublic class ConversationSelectionSet implements Parcelable {
401ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal    public static final Parcelable.Creator<ConversationSelectionSet> CREATOR =
411ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal            new Parcelable.Creator<ConversationSelectionSet>() {
421ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal
431ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal        @Override
441ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal        public ConversationSelectionSet createFromParcel(Parcel source) {
451ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal            ConversationSelectionSet result = new ConversationSelectionSet();
461ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal            Parcelable[] conversations = source.readParcelableArray(
471ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal                            Conversation.class.getClassLoader());
481ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal            for (Parcelable parceled : conversations) {
49866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira                Conversation conversation = (Conversation) parceled;
50866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira                result.put(conversation.id, conversation);
511ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal            }
521ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal            return result;
531ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal        }
541ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal
551ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal        @Override
561ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal        public ConversationSelectionSet[] newArray(int size) {
571ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal            return new ConversationSelectionSet[size];
581ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal        }
591ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal    };
601ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal
611ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal    private final HashMap<Long, Conversation> mInternalMap =
621ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal            new HashMap<Long, Conversation>();
634a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal
64866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    private final HashMap<Long, ConversationItemView> mInternalViewMap =
65866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira            new HashMap<Long, ConversationItemView>();
66866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
674a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal    @VisibleForTesting
684a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal    final ArrayList<ConversationSetObserver> mObservers = new ArrayList<ConversationSetObserver>();
694a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal
704a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal    /**
714a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal     * Registers an observer to listen for interesting changes on this set.
724a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal     *
734a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal     * @param observer the observer to register.
744a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal     */
754a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal    public synchronized void addObserver(ConversationSetObserver observer) {
764a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal        mObservers.add(observer);
774a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal    }
784a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal
79d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal    /**
80d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal     * Clear the selected set entirely.
81d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal     */
821ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal    public synchronized void clear() {
831ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal        boolean initiallyNotEmpty = !mInternalMap.isEmpty();
84866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira        mInternalViewMap.clear();
851ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal        mInternalMap.clear();
861ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal
871ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal        if (mInternalMap.isEmpty() && initiallyNotEmpty) {
881ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal            ArrayList<ConversationSetObserver> observersCopy = Lists.newArrayList(mObservers);
891ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal            dispatchOnChange(observersCopy);
901ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal            dispatchOnEmpty(observersCopy);
911ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal        }
921ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal    }
931ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal
94d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal    /**
95d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal     * Returns true if the given key exists in the conversation selection set. This assumes
96d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal     * the internal representation holds conversation.id values.
97d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal     * @param key the id of the conversation
98d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal     * @return true if the key exists in this selected set.
99d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal     */
100d3818654c103802704fc788cf9c6775d25b65bffMindy Pereira    public synchronized boolean containsKey(Long key) {
1011ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal        return mInternalMap.containsKey(key);
1021ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal    }
1031ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal
104d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal    /**
105d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal     * Returns true if the given conversation is stored in the selection set.
106d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal     * @param conversation
107d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal     * @return true if the conversation exists in the selected set.
108d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal     */
109d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal    public synchronized boolean contains(Conversation conversation) {
110d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal        return mInternalMap.containsKey(conversation.id);
111d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal    }
112d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal
1131ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal    @Override
1141ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal    public int describeContents() {
1151ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal        return 0;
1161ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal    }
1171ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal
1181ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal    private synchronized void dispatchOnBecomeUnempty(
1191ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal            ArrayList<ConversationSetObserver> observers) {
1201ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal        for (ConversationSetObserver observer : observers) {
1211ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal            observer.onSetPopulated(this);
1221ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal        }
1234a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal    }
1244a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal
1254a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal    private synchronized void dispatchOnChange(ArrayList<ConversationSetObserver> observers) {
1264a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal        // Copy observers so that they may unregister themselves as listeners on
1274a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal        // event handling.
1284a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal        for (ConversationSetObserver observer : observers) {
1294a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal            observer.onSetChanged(this);
1304a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal        }
1314a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal    }
1324a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal
1334a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal    private synchronized void dispatchOnEmpty(ArrayList<ConversationSetObserver> observers) {
1344a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal        for (ConversationSetObserver observer : observers) {
1351ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal            observer.onSetEmpty();
1364a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal        }
1374a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal    }
1384a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal
1391ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal    /**
1401ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal     * Is this conversation set empty?
1411ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal     * @return true if the conversation selection set is empty. False otherwise.
1421ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal     */
1431ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal    public synchronized boolean isEmpty() {
1441ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal        return mInternalMap.isEmpty();
1451ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal    }
1461ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal
1471ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal    private synchronized void put(Long id, Conversation info) {
1484556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang        final boolean initiallyEmpty = mInternalMap.isEmpty();
1494a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal        mInternalMap.put(id, info);
150866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira        // Fill out the view map with null. The sizes will match, but
151866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira        // we won't have any views available yet to store.
152866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira        mInternalViewMap.put(id, null);
153866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
154866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira        ArrayList<ConversationSetObserver> observersCopy = Lists.newArrayList(mObservers);
155866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira        dispatchOnChange(observersCopy);
156866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira        if (initiallyEmpty) {
157866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira            dispatchOnBecomeUnempty(observersCopy);
158866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira        }
159866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    }
160866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
161866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    /** @see java.util.HashMap#put */
162866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    private synchronized void put(Long id, ConversationItemView info) {
163866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira        boolean initiallyEmpty = mInternalMap.isEmpty();
164866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira        mInternalViewMap.put(id, info);
165866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira        mInternalMap.put(id, info.mHeader.conversation);
1664a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal
1674a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal        ArrayList<ConversationSetObserver> observersCopy = Lists.newArrayList(mObservers);
1684a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal        dispatchOnChange(observersCopy);
1694a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal        if (initiallyEmpty) {
1704a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal            dispatchOnBecomeUnempty(observersCopy);
1714a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal        }
1724a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal    }
1734a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal
1744a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal    /** @see java.util.HashMap#remove */
1754a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal    private synchronized void remove(Long id) {
1764556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang        final boolean initiallyNotEmpty = !mInternalMap.isEmpty();
177866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
178866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira        mInternalViewMap.remove(id);
1794a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal        mInternalMap.remove(id);
1804a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal
1814a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal        ArrayList<ConversationSetObserver> observersCopy = Lists.newArrayList(mObservers);
1824a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal        dispatchOnChange(observersCopy);
1834a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal        if (mInternalMap.isEmpty() && initiallyNotEmpty) {
1844a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal            dispatchOnEmpty(observersCopy);
1854a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal        }
1864a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal    }
1874a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal
1881ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal    /**
1891ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal     * Unregisters an observer for change events.
1901ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal     *
1911ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal     * @param observer the observer to unregister.
1921ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal     */
1931ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal    public synchronized void removeObserver(ConversationSetObserver observer) {
1941ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal        mObservers.remove(observer);
1954a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal    }
1964a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal
197d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal    /**
198d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal     * Returns the number of conversations that are currently selected
199d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal     * @return the number of selected conversations.
200d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal     */
2011ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal    public synchronized int size() {
2021ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal        return mInternalMap.size();
2034a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal    }
2044a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal
2054a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal    /**
206d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal     * Toggles the existence of the given conversation in the selection set. If the conversation is
207d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal     * currently selected, it is deselected. If it doesn't exist in the selection set, then it is
208d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal     * selected.
2091ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal     * @param conversation
2104a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal     */
211866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    public void toggle(ConversationItemView view, Conversation conversation) {
2121ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal        long conversationId = conversation.id;
2131ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal        if (containsKey(conversationId)) {
2141ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal            remove(conversationId);
2154a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal        } else {
216866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira            put(conversationId, view);
2174a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal        }
2184a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal    }
2194a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal
2201ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal    /** @see java.util.HashMap#values */
2211ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal    public synchronized Collection<Conversation> values() {
2221ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal        return mInternalMap.values();
2234a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal    }
2244a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal
2254556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang    /** @see java.util.HashMap#putAll(java.util.Map) */
2264556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang    public void putAll(ConversationSelectionSet other) {
2274556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang        if (other == null) {
2284556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang            return;
2294556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang        }
2304556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang
2314556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang        final boolean initiallyEmpty = mInternalMap.isEmpty();
2324556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang        mInternalMap.putAll(other.mInternalMap);
2334556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang
2344556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang        ArrayList<ConversationSetObserver> observersCopy = Lists.newArrayList(mObservers);
2354556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang        dispatchOnChange(observersCopy);
2364556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang        if (initiallyEmpty) {
2374556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang            dispatchOnBecomeUnempty(observersCopy);
2384556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang        }
2394556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang    }
2404556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang
2414a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal    @Override
2424a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal    public void writeToParcel(Parcel dest, int flags) {
2431ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal        Conversation[] values = values().toArray(new Conversation[size()]);
2444a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal        dest.writeParcelableArray(values, flags);
2454a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal    }
246866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
247866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    public Collection<ConversationItemView> views() {
248866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira        return mInternalViewMap.values();
249866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    }
2504a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal}
251