1645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// Copyright 2013 The Chromium Authors. All rights reserved.
2645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// Use of this source code is governed by a BSD-style license that can be
3645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// found in the LICENSE file.
4645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
5645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezpackage org.chromium.base;
6645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
7645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezimport java.util.ArrayList;
8645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezimport java.util.Iterator;
9645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezimport java.util.List;
10645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezimport java.util.NoSuchElementException;
11645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
12645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezimport javax.annotation.concurrent.NotThreadSafe;
13645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
14645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez/**
15645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez * A container for a list of observers.
16645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez * <p/>
17645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez * This container can be modified during iteration without invalidating the iterator.
18645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez * So, it safely handles the case of an observer removing itself or other observers from the list
19645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez * while observers are being notified.
20645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez * <p/>
21645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez * The implementation (and the interface) is heavily influenced by the C++ ObserverList.
22645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez * Notable differences:
23645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez *   - The iterator implements NOTIFY_EXISTING_ONLY.
24645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez *   - The FOR_EACH_OBSERVER closure is left to the clients to implement in terms of iterator().
25645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez * <p/>
26645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez * This class is not threadsafe. Observers MUST be added, removed and will be notified on the same
27645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez * thread this is created.
28645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez *
29645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez * @param <E> The type of observers that this list should hold.
30645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez */
31645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez@NotThreadSafe
32645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezpublic class ObserverList<E> implements Iterable<E> {
33645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    /**
34645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     * Extended iterator interface that provides rewind functionality.
35645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     */
36645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    public interface RewindableIterator<E> extends Iterator<E> {
37645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        /**
38645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez         * Rewind the iterator back to the beginning.
39645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez         *
40645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez         * If we need to iterate multiple times, we can avoid iterator object reallocation by using
41645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez         * this method.
42645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez         */
43645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        public void rewind();
44645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
45645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
46645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    public final List<E> mObservers = new ArrayList<E>();
47645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    private int mIterationDepth = 0;
48645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    private int mCount = 0;
49645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    private boolean mNeedsCompact = false;
50645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
51645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    public ObserverList() {}
52645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
53645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    /**
54645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     * Add an observer to the list.
55645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     * <p/>
56645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     * An observer should not be added to the same list more than once. If an iteration is already
57645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     * in progress, this observer will be not be visible during that iteration.
58645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     *
59645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     * @return true if the observer list changed as a result of the call.
60645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     */
61645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    public boolean addObserver(E obs) {
62645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        // Avoid adding null elements to the list as they may be removed on a compaction.
63645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if (obs == null || mObservers.contains(obs)) {
64645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return false;
65645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        }
66645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
67645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        // Structurally modifying the underlying list here. This means we
68645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        // cannot use the underlying list's iterator to iterate over the list.
69645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        boolean result = mObservers.add(obs);
70645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        assert result;
71645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
72645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        ++mCount;
73645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return true;
74645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
75645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
76645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    /**
77645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     * Remove an observer from the list if it is in the list.
78645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     *
79645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     * @return true if an element was removed as a result of this call.
80645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     */
81645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    public boolean removeObserver(E obs) {
82645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if (obs == null) {
83645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return false;
84645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        }
85645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
86645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        int index = mObservers.indexOf(obs);
87645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if (index == -1) {
88645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return false;
89645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        }
90645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
91645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if (mIterationDepth == 0) {
92645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            // No one is iterating over the list.
93645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            mObservers.remove(index);
94645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        } else {
95645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            mNeedsCompact = true;
96645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            mObservers.set(index, null);
97645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        }
98645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        --mCount;
99645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        assert mCount >= 0;
100645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
101645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return true;
102645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
103645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
104645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    public boolean hasObserver(E obs) {
105645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return mObservers.contains(obs);
106645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
107645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
108645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    public void clear() {
109645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        mCount = 0;
110645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
111645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if (mIterationDepth == 0) {
112645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            mObservers.clear();
113645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return;
114645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        }
115645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
116645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        int size = mObservers.size();
117645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        mNeedsCompact |= size != 0;
118645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        for (int i = 0; i < size; i++) {
119645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            mObservers.set(i, null);
120645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        }
121645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
122645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
123645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    @Override
124645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    public Iterator<E> iterator() {
125645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return new ObserverListIterator();
126645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
127645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
128645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    /**
129645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     * It's the same as {@link ObserverList#iterator()} but the return type is
130645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     * {@link RewindableIterator}. Use this iterator type if you need to use
131645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     * {@link RewindableIterator#rewind()}.
132645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     */
133645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    public RewindableIterator<E> rewindableIterator() {
134645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return new ObserverListIterator();
135645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
136645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
137645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    /**
138645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     * Returns the number of observers currently registered in the ObserverList.
139645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     * This is equivalent to the number of non-empty spaces in |mObservers|.
140645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     */
141645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    public int size() {
142645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return mCount;
143645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
144645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
145645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    /**
146645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     * Returns true if the ObserverList contains no observers.
147645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     */
148645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    public boolean isEmpty() {
149645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return mCount == 0;
150645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
151645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
152645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    /**
153645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     * Compact the underlying list be removing null elements.
154645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     * <p/>
155645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     * Should only be called when mIterationDepth is zero.
156645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     */
157645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    private void compact() {
158645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        assert mIterationDepth == 0;
159645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        for (int i = mObservers.size() - 1; i >= 0; i--) {
160645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            if (mObservers.get(i) == null) {
161645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                mObservers.remove(i);
162645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            }
163645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        }
164645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
165645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
166645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    private void incrementIterationDepth() {
167645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        mIterationDepth++;
168645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
169645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
170645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    private void decrementIterationDepthAndCompactIfNeeded() {
171645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        mIterationDepth--;
172645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        assert mIterationDepth >= 0;
173645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if (mIterationDepth > 0) return;
174645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if (!mNeedsCompact) return;
175645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        mNeedsCompact = false;
176645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        compact();
177645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
178645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
179645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    /**
180645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     * Returns the size of the underlying storage of the ObserverList.
181645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     * It will take into account the empty spaces inside |mObservers|.
182645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     */
183645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    private int capacity() {
184645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return mObservers.size();
185645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
186645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
187645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    private E getObserverAt(int index) {
188645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return mObservers.get(index);
189645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
190645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
191645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    private class ObserverListIterator implements RewindableIterator<E> {
192645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        private int mListEndMarker;
193645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        private int mIndex = 0;
194645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        private boolean mIsExhausted = false;
195645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
196645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        private ObserverListIterator() {
197645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            ObserverList.this.incrementIterationDepth();
198645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            mListEndMarker = ObserverList.this.capacity();
199645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        }
200645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
201645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        @Override
202645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        public void rewind() {
203645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            compactListIfNeeded();
204645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            ObserverList.this.incrementIterationDepth();
205645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            mListEndMarker = ObserverList.this.capacity();
206645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            mIsExhausted = false;
207645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            mIndex = 0;
208645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        }
209645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
210645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        @Override
211645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        public boolean hasNext() {
212645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            int lookupIndex = mIndex;
213645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            while (lookupIndex < mListEndMarker
214645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                    && ObserverList.this.getObserverAt(lookupIndex) == null) {
215645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                lookupIndex++;
216645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            }
217645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            if (lookupIndex < mListEndMarker) return true;
218645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
219645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            // We have reached the end of the list, allow for compaction.
220645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            compactListIfNeeded();
221645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return false;
222645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        }
223645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
224645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        @Override
225645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        public E next() {
226645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            // Advance if the current element is null.
227645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            while (mIndex < mListEndMarker && ObserverList.this.getObserverAt(mIndex) == null) {
228645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                mIndex++;
229645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            }
230645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            if (mIndex < mListEndMarker) return ObserverList.this.getObserverAt(mIndex++);
231645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
232645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            // We have reached the end of the list, allow for compaction.
233645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            compactListIfNeeded();
234645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            throw new NoSuchElementException();
235645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        }
236645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
237645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        @Override
238645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        public void remove() {
239645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            throw new UnsupportedOperationException();
240645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        }
241645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
242645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        private void compactListIfNeeded() {
243645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            if (!mIsExhausted) {
244645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                mIsExhausted = true;
245645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                ObserverList.this.decrementIterationDepthAndCompactIfNeeded();
246645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            }
247645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        }
248645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
249645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
250