blob: 316436be5c80c315d484e6c8c2ba8f5fd684e588 [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;
Leon Scroggins3bbb6ca2009-09-09 12:51:10 -040021import android.graphics.Bitmap;
Leon Scroggins1f005d32009-08-10 17:36:42 -040022import android.graphics.drawable.Drawable;
23import android.util.AttributeSet;
24import android.util.Log;
25import android.view.LayoutInflater;
26import android.view.MotionEvent;
27import android.view.View;
28import android.view.ViewGroup;
29import android.webkit.WebView;
30import android.widget.AdapterView;
31import android.widget.Gallery;
32import android.widget.SpinnerAdapter;
33
34import java.util.Vector;
35
36/**
37 * The TitleBarSet holds a TitleBar for each open "tab" in the browser.
38 */
39public class TitleBarSet extends Gallery
40 implements AdapterView.OnItemSelectedListener {
41 private Vector<TitleBar> mTitleBars;
42 private BrowserActivity mBrowserActivity;
Leon Scroggins1f005d32009-08-10 17:36:42 -040043 private int mCount;
44 private TitleAdapter mTitleAdapter;
45 private boolean mIgnoreSelectedListener;
46 private MotionEvent mLastTouchUp;
47
48 public TitleBarSet(Context context) {
49 this(context, null);
50 }
51
52 public TitleBarSet(Context context, AttributeSet attrs) {
53 super(context, attrs);
54 mTitleBars = new Vector<TitleBar>(TabControl.MAX_TABS);
55 mCount = 0;
Leon Scroggins1f005d32009-08-10 17:36:42 -040056 mTitleAdapter = new TitleAdapter();
57 setAdapter(mTitleAdapter);
58 setCallbackDuringFling(false);
59 setCallbackOnUnselectedItemClick(true);
60 setSpacing(0);
61 setOnItemSelectedListener(this);
Leon Scroggins62e8f942009-09-03 15:08:54 -040062 setBackgroundResource(R.drawable.tab_browser_unselected);
63 setPadding(0,0,0,0);
Leon Scroggins1f005d32009-08-10 17:36:42 -040064 }
65
66 /**
67 * Add a tab/titlebar to our set. Called when BrowserActivity adds a new
68 * Tab to its TabControl.
69 * @param view WebView associated with this tab. Used to determine whether
70 * updates are going to the correct place.
71 * @param selected Whether to set the new tab to be selected.
72 */
73 /* package */ void addTab(WebView view, boolean selected) {
74 if (TabControl.MAX_TABS == mCount) {
75 return;
76 }
77 int newSelection = mCount;
Leon Scroggins9246d362009-09-14 19:47:24 -040078 int oldSelection = getSelectedItemPosition();
Leon Scroggins3bbb6ca2009-09-09 12:51:10 -040079 TitleBar titleBar = new TitleBar(mBrowserActivity, view);
Leon Scroggins1f005d32009-08-10 17:36:42 -040080 mTitleBars.add(titleBar);
81 mCount++;
Leon Scroggins1f005d32009-08-10 17:36:42 -040082 // Need to refresh our list
83 setAdapter(mTitleAdapter);
Leon Scroggins9246d362009-09-14 19:47:24 -040084 setCurrentTab(selected ? newSelection : oldSelection);
Leon Scroggins1f005d32009-08-10 17:36:42 -040085 }
86
87 /**
88 * Convenience method to get a particular title bar.
89 */
90 private TitleBar getTitleBarAt(int position) {
91 if (position < 0 || position >= mCount) {
92 return null;
93 }
94 return (TitleBar) mTitleBars.elementAt(position);
95 }
96
97 /**
98 * Implementation for OnItemSelectedListener
99 */
100 public void onItemSelected(AdapterView<?> parent, View view, int position,
101 long id) {
102 if (mIgnoreSelectedListener || !(view instanceof TitleBar)) {
103 return;
104 }
105 mBrowserActivity.switchToTab(position);
106 // In case the WebView finished loading while this TitleBar was out of
107 // focus, make sure all its data is up to date
108 TitleBar titleBar = getTitleBarAt(position);
109 WebView webview = titleBar.getWebView();
110 if (webview == null) {
111 // FIXME: Possible that the tab needs to be restored.
112 return;
113 }
114 if (webview.getProgress() == 100) {
115 titleBar.setProgress(100);
116 titleBar.setTitleAndUrl(webview.getTitle(), webview.getUrl());
Leon Scroggins3bbb6ca2009-09-09 12:51:10 -0400117 // FIXME: BrowserActivity looks at the back forward list. Is this
118 // better?
119 titleBar.setFavicon(webview.getFavicon());
120 mBrowserActivity.updateLockIconToLatest();
Leon Scroggins1f005d32009-08-10 17:36:42 -0400121 }
122 }
123
124 /**
125 * Implementation for OnItemSelectedListener
126 */
127 public void onNothingSelected(AdapterView<?> parent) {
128 // do nothing
129 }
130
131 /**
132 * Override from GestureDetector.OnGestureListener. Store the MotionEvent
133 * so performItemClick can know how to handle the click.
134 */
135 public boolean onSingleTapUp(MotionEvent e) {
136 mLastTouchUp = e;
137 // super.onSingleTapUp will call performItemClick
138 boolean result = super.onSingleTapUp(e);
139 mLastTouchUp = null;
140 return result;
141 }
142
143 /**
144 * Override from View to ensure that the TitleBars get resized to match
145 * the new screen width
146 */
147 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
148 super.onSizeChanged(w, h, oldw, oldh);
Leon Scroggins5a7e6c62009-08-14 16:32:43 -0400149 int selection = getSelectedItemPosition();
Leon Scroggins1f005d32009-08-10 17:36:42 -0400150 // Need to make sure getView gets called again
Leon Scroggins1f005d32009-08-10 17:36:42 -0400151 setAdapter(mTitleAdapter);
Leon Scroggins5a7e6c62009-08-14 16:32:43 -0400152 // Stay on the same tab
153 setCurrentTab(selection);
Leon Scroggins1f005d32009-08-10 17:36:42 -0400154 }
155
156 /**
157 * Override from AdapterView. Using simple OnClickListeners overrides
158 * the GestureDetector.OnGestureListener, so we handle it here.
159 */
160 public boolean performItemClick(View view, int position, long id) {
161 if (!(view instanceof TitleBar)) {
Leon Scroggins1f005d32009-08-10 17:36:42 -0400162 return super.performItemClick(view, position, id);
163 }
164 // If we have no mLastTouchUp, this was not called from onSingleTapUp,
165 // so ignore it.
166 if (null == mLastTouchUp) {
167 return false;
168 }
169 TitleBar titleBar = (TitleBar) view;
170 // If the user clicks on a view which is not selected, the Gallery will
171 // take care of making it selected.
172 if (titleBar != getTitleBarAt(position)) {
173 return false;
174 }
Leon Scrogginsf4bb18a2009-09-11 18:37:53 -0400175 View textfield = titleBar.findViewById(R.id.title);
176 // Interpret all touches past the right edge of the search field as
177 // a touch on the icon on the right.
178 if ((int) mLastTouchUp.getX() > textfield.getRight()) {
179 WebView webView = titleBar.getWebView();
180 if (webView != null && webView.getProgress() < 100) {
181 webView.stopLoading();
182 } else {
183 mBrowserActivity.bookmarksOrHistoryPicker(false);
184 }
185 return true;
186 }
Leon Scrogginsa81a7642009-08-31 17:05:41 -0400187 mBrowserActivity.onSearchRequested();
Leon Scroggins1f005d32009-08-10 17:36:42 -0400188 return true;
189 }
190
191 /**
192 * Remove the tab at the given position.
193 */
194 /* package */ void removeTab(int position) {
Leon Scroggins53fe5812009-09-01 12:33:07 -0400195 int selection = getSelectedItemPosition();
Leon Scroggins1f005d32009-08-10 17:36:42 -0400196 mTitleBars.remove(position);
197 mCount--;
198 // Need to refresh our list
199 setAdapter(mTitleAdapter);
Leon Scroggins53fe5812009-09-01 12:33:07 -0400200 setCurrentTab(selection);
Leon Scroggins1f005d32009-08-10 17:36:42 -0400201 }
202
203 /**
204 * Convenience method to get the currently selected title bar.
205 */
206 private TitleBar selectedTitleBar() {
207 return getTitleBarAt(getSelectedItemPosition());
208 }
209
210 /**
211 * Set the owning BrowserActivity. Necessary so that we can call methods
Leon Scrogginsa81a7642009-08-31 17:05:41 -0400212 * on it. Only called once before adding any title bars.
Leon Scroggins1f005d32009-08-10 17:36:42 -0400213 */
Leon Scrogginsa81a7642009-08-31 17:05:41 -0400214 /* package */ void init(final BrowserActivity ba) {
Leon Scroggins1f005d32009-08-10 17:36:42 -0400215 mBrowserActivity = ba;
Leon Scroggins1f005d32009-08-10 17:36:42 -0400216 }
217
218 /**
219 * Change to the tab at the new position.
220 */
221 /* package */ void setCurrentTab(int position) {
Leon Scroggins53fe5812009-09-01 12:33:07 -0400222 if (position < 0 || position >= mCount) return;
Leon Scroggins1f005d32009-08-10 17:36:42 -0400223 mIgnoreSelectedListener = true;
224 setSelection(position);
225 mIgnoreSelectedListener = false;
226 }
227
228 /**
229 * Update the Favicon of the currently selected tab.
Leon Scroggins3bbb6ca2009-09-09 12:51:10 -0400230 * @param icon The new bitmap for the favicon
Leon Scroggins1f005d32009-08-10 17:36:42 -0400231 * @param topWindow The WebView which posted the update. If it does not
232 * match the WebView of the currently selected tab, do
233 * nothing, since that tab is not being displayed.
234 */
Leon Scroggins3bbb6ca2009-09-09 12:51:10 -0400235 /* package */ void setFavicon(Bitmap icon, WebView topWindow) {
Leon Scroggins1f005d32009-08-10 17:36:42 -0400236 TitleBar current = selectedTitleBar();
237 if (current != null && current.getWebView() == topWindow) {
Leon Scroggins3bbb6ca2009-09-09 12:51:10 -0400238 current.setFavicon(icon);
Leon Scroggins1f005d32009-08-10 17:36:42 -0400239 }
240 }
241
242 /**
243 * Update the lock icon of the currently selected tab.
244 * @param d The new Drawable for the lock icon
245 * @param topWindow The WebView which posted the update. If it does not
246 * match the WebView of the currently selected tab, do
247 * nothing, since that tab is not being displayed.
248 */
249 /* package */ void setLock(Drawable d, WebView topWindow) {
250 TitleBar current = selectedTitleBar();
251 if (current != null && current.getWebView() == topWindow) {
252 current.setLock(d);
253 }
254 }
255 /**
256 * Update the progress of the currently selected tab.
257 * @param newProgress The progress, between 0 and 100, of the current tab.
258 * @param topWindow The WebView which posted the update. If it does not
259 * match the WebView of the currently selected tab, do
260 * nothing, since that tab is not being displayed.
261 */
262 /* package */ void setProgress(int newProgress, WebView topWindow) {
263 TitleBar current = selectedTitleBar();
264 if (current != null && current.getWebView() == topWindow) {
265 current.setProgress(newProgress);
266 }
267 }
268 /**
269 * Update the title and URL of the currently selected tab.
270 * @param title The title of the webpage
271 * @param url The URL of the webpage
272 * @param topWindow The WebView which posted the update. If it does not
273 * match the WebView of the currently selected tab, do
274 * nothing, since that tab is not being displayed.
275 */
276 /* package */ void setTitleAndUrl(CharSequence title, CharSequence url,
277 WebView topWindow) {
278 TitleBar current = selectedTitleBar();
279 if (current != null && current.getWebView() == topWindow) {
280 current.setTitleAndUrl(title, url);
281 }
282 }
283
284 // FIXME: Remove
285 /* package */ void setToTabPicker() {
286 TitleBar current = selectedTitleBar();
287 if (current != null) {
288 current.setToTabPicker();
289 }
290 }
291
292 /**
293 * Custom adapter which provides the TitleBars and the NewButton to the
294 * Gallery.
295 */
296 private class TitleAdapter implements SpinnerAdapter {
297 public View getDropDownView(int position, View convertView,
298 ViewGroup parent) {
299 return null;
300 }
301 public void registerDataSetObserver(DataSetObserver observer) {}
302 public void unregisterDataSetObserver(DataSetObserver observer) {}
303 public int getCount() {
Leon Scrogginsa81a7642009-08-31 17:05:41 -0400304 return mCount;
Leon Scroggins1f005d32009-08-10 17:36:42 -0400305 }
306 public Object getItem(int position) {
307 return null;
308 }
309 public long getItemId(int position) {
310 return position;
311 }
312 public boolean hasStableIds() {
313 return true;
314 }
315 public View getView(int position, View convertView, ViewGroup parent) {
Leon Scroggins1f005d32009-08-10 17:36:42 -0400316 TitleBar titleBar = getTitleBarAt(position);
317 Gallery.LayoutParams lp;
Leon Scrogginsa81a7642009-08-31 17:05:41 -0400318 int desiredWidth = TitleBarSet.this.getWidth();
Leon Scroggins1f005d32009-08-10 17:36:42 -0400319 ViewGroup.LayoutParams old = titleBar.getLayoutParams();
320 if (old == null || !(old instanceof Gallery.LayoutParams)) {
321 lp = new Gallery.LayoutParams(desiredWidth,
322 ViewGroup.LayoutParams.WRAP_CONTENT);
323 titleBar.setLayoutParams(lp);
324 } else {
325 lp = (Gallery.LayoutParams) old;
326 if (lp.width != desiredWidth) {
327 lp.width = desiredWidth;
328 titleBar.setLayoutParams(lp);
329 requestLayout();
330 }
331 }
332 return titleBar;
333 }
334 public int getItemViewType(int position) {
335 // We are managing our own views.
336 return AdapterView.ITEM_VIEW_TYPE_IGNORE;
337 }
338 public int getViewTypeCount() {
339 return 1;
340 }
341 public boolean isEmpty() {
342 // Will never be empty, because the NewButton is always there
343 // (though sometimes disabled).
344 return false;
345 }
346 }
347}