blob: c71cfa7012f58a0fd0d58172529be6e7c240f7c7 [file] [log] [blame]
Leon Scroggins1f005d32009-08-10 17:36:42 -04001/*
2 * Copyright (C) 2009 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 com.android.browser;
18
19import android.content.Context;
20import android.database.DataSetObserver;
21import android.graphics.drawable.Drawable;
22import android.util.AttributeSet;
23import android.util.Log;
24import android.view.LayoutInflater;
25import android.view.MotionEvent;
26import android.view.View;
27import android.view.ViewGroup;
28import android.webkit.WebView;
29import android.widget.AdapterView;
30import android.widget.Gallery;
31import android.widget.SpinnerAdapter;
32
33import java.util.Vector;
34
35/**
36 * The TitleBarSet holds a TitleBar for each open "tab" in the browser.
37 */
38public class TitleBarSet extends Gallery
39 implements AdapterView.OnItemSelectedListener {
40 private Vector<TitleBar> mTitleBars;
41 private BrowserActivity mBrowserActivity;
Leon Scroggins1f005d32009-08-10 17:36:42 -040042 private int mCount;
43 private TitleAdapter mTitleAdapter;
44 private boolean mIgnoreSelectedListener;
45 private MotionEvent mLastTouchUp;
46
47 public TitleBarSet(Context context) {
48 this(context, null);
49 }
50
51 public TitleBarSet(Context context, AttributeSet attrs) {
52 super(context, attrs);
53 mTitleBars = new Vector<TitleBar>(TabControl.MAX_TABS);
54 mCount = 0;
Leon Scroggins1f005d32009-08-10 17:36:42 -040055 mTitleAdapter = new TitleAdapter();
56 setAdapter(mTitleAdapter);
57 setCallbackDuringFling(false);
58 setCallbackOnUnselectedItemClick(true);
59 setSpacing(0);
60 setOnItemSelectedListener(this);
Leon Scroggins62e8f942009-09-03 15:08:54 -040061 setBackgroundResource(R.drawable.tab_browser_unselected);
62 setPadding(0,0,0,0);
Leon Scroggins1f005d32009-08-10 17:36:42 -040063 }
64
65 /**
66 * Add a tab/titlebar to our set. Called when BrowserActivity adds a new
67 * Tab to its TabControl.
68 * @param view WebView associated with this tab. Used to determine whether
69 * updates are going to the correct place.
70 * @param selected Whether to set the new tab to be selected.
71 */
72 /* package */ void addTab(WebView view, boolean selected) {
73 if (TabControl.MAX_TABS == mCount) {
74 return;
75 }
76 int newSelection = mCount;
Leon Scrogginsa81a7642009-08-31 17:05:41 -040077 TitleBar titleBar = new TitleBar(getContext(), view, mBrowserActivity);
Leon Scroggins1f005d32009-08-10 17:36:42 -040078 mTitleBars.add(titleBar);
79 mCount++;
Leon Scroggins1f005d32009-08-10 17:36:42 -040080 // Need to refresh our list
81 setAdapter(mTitleAdapter);
82 mIgnoreSelectedListener = true;
83 // No need to call onItemSelected, since the Tab in BrowserActivity has
84 // already been changed.
85 if (selected) {
86 setSelection(newSelection);
87 }
88 mIgnoreSelectedListener = false;
89 }
90
91 /**
92 * Convenience method to get a particular title bar.
93 */
94 private TitleBar getTitleBarAt(int position) {
95 if (position < 0 || position >= mCount) {
96 return null;
97 }
98 return (TitleBar) mTitleBars.elementAt(position);
99 }
100
101 /**
102 * Implementation for OnItemSelectedListener
103 */
104 public void onItemSelected(AdapterView<?> parent, View view, int position,
105 long id) {
106 if (mIgnoreSelectedListener || !(view instanceof TitleBar)) {
107 return;
108 }
109 mBrowserActivity.switchToTab(position);
110 // In case the WebView finished loading while this TitleBar was out of
111 // focus, make sure all its data is up to date
112 TitleBar titleBar = getTitleBarAt(position);
113 WebView webview = titleBar.getWebView();
114 if (webview == null) {
115 // FIXME: Possible that the tab needs to be restored.
116 return;
117 }
118 if (webview.getProgress() == 100) {
119 titleBar.setProgress(100);
120 titleBar.setTitleAndUrl(webview.getTitle(), webview.getUrl());
121 // FIXME: Pass in a bitmap, so we can always update the bitmap
122 // properly
123 //titleBar.setFavicon(webview.getFavicon());
124 }
125 }
126
127 /**
128 * Implementation for OnItemSelectedListener
129 */
130 public void onNothingSelected(AdapterView<?> parent) {
131 // do nothing
132 }
133
134 /**
135 * Override from GestureDetector.OnGestureListener. Store the MotionEvent
136 * so performItemClick can know how to handle the click.
137 */
138 public boolean onSingleTapUp(MotionEvent e) {
139 mLastTouchUp = e;
140 // super.onSingleTapUp will call performItemClick
141 boolean result = super.onSingleTapUp(e);
142 mLastTouchUp = null;
143 return result;
144 }
145
146 /**
147 * Override from View to ensure that the TitleBars get resized to match
148 * the new screen width
149 */
150 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
151 super.onSizeChanged(w, h, oldw, oldh);
Leon Scroggins5a7e6c62009-08-14 16:32:43 -0400152 int selection = getSelectedItemPosition();
Leon Scroggins1f005d32009-08-10 17:36:42 -0400153 // Need to make sure getView gets called again
Leon Scroggins1f005d32009-08-10 17:36:42 -0400154 setAdapter(mTitleAdapter);
Leon Scroggins5a7e6c62009-08-14 16:32:43 -0400155 // Stay on the same tab
156 setCurrentTab(selection);
Leon Scroggins1f005d32009-08-10 17:36:42 -0400157 }
158
159 /**
160 * Override from AdapterView. Using simple OnClickListeners overrides
161 * the GestureDetector.OnGestureListener, so we handle it here.
162 */
163 public boolean performItemClick(View view, int position, long id) {
164 if (!(view instanceof TitleBar)) {
Leon Scroggins1f005d32009-08-10 17:36:42 -0400165 return super.performItemClick(view, position, id);
166 }
167 // If we have no mLastTouchUp, this was not called from onSingleTapUp,
168 // so ignore it.
169 if (null == mLastTouchUp) {
170 return false;
171 }
172 TitleBar titleBar = (TitleBar) view;
173 // If the user clicks on a view which is not selected, the Gallery will
174 // take care of making it selected.
175 if (titleBar != getTitleBarAt(position)) {
176 return false;
177 }
Leon Scrogginsa81a7642009-08-31 17:05:41 -0400178 mBrowserActivity.onSearchRequested();
Leon Scroggins1f005d32009-08-10 17:36:42 -0400179 return true;
180 }
181
182 /**
183 * Remove the tab at the given position.
184 */
185 /* package */ void removeTab(int position) {
Leon Scroggins53fe5812009-09-01 12:33:07 -0400186 int selection = getSelectedItemPosition();
Leon Scroggins1f005d32009-08-10 17:36:42 -0400187 mTitleBars.remove(position);
188 mCount--;
189 // Need to refresh our list
190 setAdapter(mTitleAdapter);
Leon Scroggins53fe5812009-09-01 12:33:07 -0400191 setCurrentTab(selection);
Leon Scroggins1f005d32009-08-10 17:36:42 -0400192 }
193
194 /**
195 * Convenience method to get the currently selected title bar.
196 */
197 private TitleBar selectedTitleBar() {
198 return getTitleBarAt(getSelectedItemPosition());
199 }
200
201 /**
202 * Set the owning BrowserActivity. Necessary so that we can call methods
Leon Scrogginsa81a7642009-08-31 17:05:41 -0400203 * on it. Only called once before adding any title bars.
Leon Scroggins1f005d32009-08-10 17:36:42 -0400204 */
Leon Scrogginsa81a7642009-08-31 17:05:41 -0400205 /* package */ void init(final BrowserActivity ba) {
Leon Scroggins1f005d32009-08-10 17:36:42 -0400206 mBrowserActivity = ba;
Leon Scroggins1f005d32009-08-10 17:36:42 -0400207 }
208
209 /**
210 * Change to the tab at the new position.
211 */
212 /* package */ void setCurrentTab(int position) {
Leon Scroggins53fe5812009-09-01 12:33:07 -0400213 if (position < 0 || position >= mCount) return;
Leon Scroggins1f005d32009-08-10 17:36:42 -0400214 mIgnoreSelectedListener = true;
215 setSelection(position);
216 mIgnoreSelectedListener = false;
217 }
218
219 /**
220 * Update the Favicon of the currently selected tab.
221 * @param d The new Drawable for the Favicon
222 * @param topWindow The WebView which posted the update. If it does not
223 * match the WebView of the currently selected tab, do
224 * nothing, since that tab is not being displayed.
225 */
226 /* package */ void setFavicon(Drawable d, WebView topWindow) {
227 TitleBar current = selectedTitleBar();
228 if (current != null && current.getWebView() == topWindow) {
229 current.setFavicon(d);
230 }
231 }
232
233 /**
234 * Update the lock icon of the currently selected tab.
235 * @param d The new Drawable for the lock icon
236 * @param topWindow The WebView which posted the update. If it does not
237 * match the WebView of the currently selected tab, do
238 * nothing, since that tab is not being displayed.
239 */
240 /* package */ void setLock(Drawable d, WebView topWindow) {
241 TitleBar current = selectedTitleBar();
242 if (current != null && current.getWebView() == topWindow) {
243 current.setLock(d);
244 }
245 }
246 /**
247 * Update the progress of the currently selected tab.
248 * @param newProgress The progress, between 0 and 100, of the current tab.
249 * @param topWindow The WebView which posted the update. If it does not
250 * match the WebView of the currently selected tab, do
251 * nothing, since that tab is not being displayed.
252 */
253 /* package */ void setProgress(int newProgress, WebView topWindow) {
254 TitleBar current = selectedTitleBar();
255 if (current != null && current.getWebView() == topWindow) {
256 current.setProgress(newProgress);
257 }
258 }
259 /**
260 * Update the title and URL of the currently selected tab.
261 * @param title The title of the webpage
262 * @param url The URL of the webpage
263 * @param topWindow The WebView which posted the update. If it does not
264 * match the WebView of the currently selected tab, do
265 * nothing, since that tab is not being displayed.
266 */
267 /* package */ void setTitleAndUrl(CharSequence title, CharSequence url,
268 WebView topWindow) {
269 TitleBar current = selectedTitleBar();
270 if (current != null && current.getWebView() == topWindow) {
271 current.setTitleAndUrl(title, url);
272 }
273 }
274
275 // FIXME: Remove
276 /* package */ void setToTabPicker() {
277 TitleBar current = selectedTitleBar();
278 if (current != null) {
279 current.setToTabPicker();
280 }
281 }
282
283 /**
284 * Custom adapter which provides the TitleBars and the NewButton to the
285 * Gallery.
286 */
287 private class TitleAdapter implements SpinnerAdapter {
288 public View getDropDownView(int position, View convertView,
289 ViewGroup parent) {
290 return null;
291 }
292 public void registerDataSetObserver(DataSetObserver observer) {}
293 public void unregisterDataSetObserver(DataSetObserver observer) {}
294 public int getCount() {
Leon Scrogginsa81a7642009-08-31 17:05:41 -0400295 return mCount;
Leon Scroggins1f005d32009-08-10 17:36:42 -0400296 }
297 public Object getItem(int position) {
298 return null;
299 }
300 public long getItemId(int position) {
301 return position;
302 }
303 public boolean hasStableIds() {
304 return true;
305 }
306 public View getView(int position, View convertView, ViewGroup parent) {
Leon Scroggins1f005d32009-08-10 17:36:42 -0400307 TitleBar titleBar = getTitleBarAt(position);
308 Gallery.LayoutParams lp;
Leon Scrogginsa81a7642009-08-31 17:05:41 -0400309 int desiredWidth = TitleBarSet.this.getWidth();
Leon Scroggins1f005d32009-08-10 17:36:42 -0400310 ViewGroup.LayoutParams old = titleBar.getLayoutParams();
311 if (old == null || !(old instanceof Gallery.LayoutParams)) {
312 lp = new Gallery.LayoutParams(desiredWidth,
313 ViewGroup.LayoutParams.WRAP_CONTENT);
314 titleBar.setLayoutParams(lp);
315 } else {
316 lp = (Gallery.LayoutParams) old;
317 if (lp.width != desiredWidth) {
318 lp.width = desiredWidth;
319 titleBar.setLayoutParams(lp);
320 requestLayout();
321 }
322 }
323 return titleBar;
324 }
325 public int getItemViewType(int position) {
326 // We are managing our own views.
327 return AdapterView.ITEM_VIEW_TYPE_IGNORE;
328 }
329 public int getViewTypeCount() {
330 return 1;
331 }
332 public boolean isEmpty() {
333 // Will never be empty, because the NewButton is always there
334 // (though sometimes disabled).
335 return false;
336 }
337 }
338}