WebBackForwardList.java revision 0b2e84b32af48f4b2b17c72adcf12ad29ec7bb7a
1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.webkit;
18
19import java.io.Serializable;
20import java.util.ArrayList;
21
22/**
23 * This class contains the back/forward list for a WebView.
24 * WebView.copyBackForwardList() will return a copy of this class used to
25 * inspect the entries in the list.
26 */
27public class WebBackForwardList implements Cloneable, Serializable {
28    // Current position in the list.
29    private int mCurrentIndex;
30    // ArrayList of WebHistoryItems for maintaining our copy.
31    private ArrayList<WebHistoryItem> mArray;
32    // Flag to indicate that the list is invalid
33    private boolean mClearPending;
34    // CallbackProxy to issue client callbacks.
35    private final CallbackProxy mCallbackProxy;
36
37    /**
38     * Construct a back/forward list used by clients of WebView.
39     */
40    /*package*/ WebBackForwardList(CallbackProxy proxy) {
41        mCurrentIndex = -1;
42        mArray = new ArrayList<WebHistoryItem>();
43        mCallbackProxy = proxy;
44    }
45
46    /**
47     * Return the current history item. This method returns null if the list is
48     * empty.
49     * @return The current history item.
50     */
51    public synchronized WebHistoryItem getCurrentItem() {
52        return getItemAtIndex(mCurrentIndex);
53    }
54
55    /**
56     * Get the index of the current history item. This index can be used to
57     * directly index into the array list.
58     * @return The current index from 0...n or -1 if the list is empty.
59     */
60    public synchronized int getCurrentIndex() {
61        return mCurrentIndex;
62    }
63
64    /**
65     * Get the history item at the given index. The index range is from 0...n
66     * where 0 is the first item and n is the last item.
67     * @param index The index to retrieve.
68     */
69    public synchronized WebHistoryItem getItemAtIndex(int index) {
70        if (index < 0 || index >= getSize()) {
71            return null;
72        }
73        return mArray.get(index);
74    }
75
76    /**
77     * Get the total size of the back/forward list.
78     * @return The size of the list.
79     */
80    public synchronized int getSize() {
81        return mArray.size();
82    }
83
84    /**
85     * Mark the back/forward list as having a pending clear. This is used on the
86     * UI side to mark the list as being invalid during the clearHistory method.
87     */
88    /*package*/ synchronized void setClearPending() {
89        mClearPending = true;
90    }
91
92    /**
93     * Return the status of the clear flag. This is used on the UI side to
94     * determine if the list is valid for checking things like canGoBack.
95     */
96    /*package*/ synchronized boolean getClearPending() {
97        return mClearPending;
98    }
99
100    /**
101     * Add a new history item to the list. This will remove all items after the
102     * current item and append the new item to the end of the list. Called from
103     * the WebCore thread only. Synchronized because the UI thread may be
104     * reading the array or the current index.
105     * @param item A new history item.
106     */
107    /*package*/ synchronized void addHistoryItem(WebHistoryItem item) {
108        // Update the current position because we are going to add the new item
109        // in that slot.
110        ++mCurrentIndex;
111        // If the current position is not at the end, remove all history items
112        // after the current item.
113        final int size = mArray.size();
114        final int newPos = mCurrentIndex;
115        if (newPos != size) {
116            for (int i = size - 1; i >= newPos; i--) {
117                final WebHistoryItem h = mArray.remove(i);
118            }
119        }
120        // Add the item to the list.
121        mArray.add(item);
122        if (mCallbackProxy != null) {
123            mCallbackProxy.onNewHistoryItem(item);
124        }
125    }
126
127    /**
128     * Clear the back/forward list. Called from the WebCore thread.
129     */
130    /*package*/ synchronized void close(int nativeFrame) {
131        // Clear the array first because nativeClose will call addHistoryItem
132        // with the current item.
133        mArray.clear();
134        mCurrentIndex = -1;
135        nativeClose(nativeFrame);
136        // Reset the clear flag
137        mClearPending = false;
138    }
139
140    /* Remove the item at the given index. Called by JNI only. */
141    private synchronized void removeHistoryItem(int index) {
142        // XXX: This is a special case. Since the callback is only triggered
143        // when removing the first item, we can assert that the index is 0.
144        // This lets us change the current index without having to query the
145        // native BackForwardList.
146        if (DebugFlags.WEB_BACK_FORWARD_LIST && (index != 0)) {
147            throw new AssertionError();
148        }
149        final WebHistoryItem h = mArray.remove(index);
150        // XXX: If we ever add another callback for removing history items at
151        // any index, this will no longer be valid.
152        mCurrentIndex--;
153    }
154
155    /**
156     * Clone the entire object to be used in the UI thread by clients of
157     * WebView. This creates a copy that should never be modified by any of the
158     * webkit package classes.
159     */
160    protected synchronized WebBackForwardList clone() {
161        WebBackForwardList l = new WebBackForwardList(null);
162        if (mClearPending) {
163            // If a clear is pending, return a copy with only the current item.
164            l.addHistoryItem(getCurrentItem());
165            return l;
166        }
167        l.mCurrentIndex = mCurrentIndex;
168        int size = getSize();
169        l.mArray = new ArrayList<WebHistoryItem>(size);
170        for (int i = 0; i < size; i++) {
171            // Add a copy of each WebHistoryItem
172            l.mArray.add(mArray.get(i).clone());
173        }
174        return l;
175    }
176
177    /**
178     * Set the new history index.
179     * @param newIndex The new history index.
180     */
181    /*package*/ synchronized void setCurrentIndex(int newIndex) {
182        mCurrentIndex = newIndex;
183        if (mCallbackProxy != null) {
184            mCallbackProxy.onIndexChanged(getItemAtIndex(newIndex), newIndex);
185        }
186    }
187
188    /**
189     * Restore the history index.
190     */
191    /*package*/ static native synchronized void restoreIndex(int nativeFrame,
192            int index);
193
194    /* Close the native list. */
195    private static native void nativeClose(int nativeFrame);
196}
197