blob: a939639abd5fce07d1b9d8c8ea2689e671afc65b [file] [log] [blame]
Michael Kolba2b2ba82010-08-04 17:54:03 -07001/*
2 * Copyright (C) 2010 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
Michael Kolbebba8b42010-09-30 12:57:59 -070019import com.android.browser.ScrollWebView.ScrollListener;
20import com.android.browser.TabControl.TabChangeListener;
21
Michael Kolba2b2ba82010-08-04 17:54:03 -070022import android.content.Context;
23import android.content.res.Resources;
24import android.graphics.Bitmap;
25import android.graphics.Color;
26import android.graphics.drawable.BitmapDrawable;
27import android.graphics.drawable.Drawable;
28import android.graphics.drawable.LayerDrawable;
29import android.graphics.drawable.PaintDrawable;
30import android.view.ContextMenu;
Michael Kolbed217742010-08-10 17:52:34 -070031import android.view.Gravity;
Michael Kolba2b2ba82010-08-04 17:54:03 -070032import android.view.LayoutInflater;
33import android.view.MenuInflater;
34import android.view.View;
35import android.view.View.OnClickListener;
36import android.webkit.WebView;
Michael Kolbed217742010-08-10 17:52:34 -070037import android.widget.ImageButton;
Michael Kolba2b2ba82010-08-04 17:54:03 -070038import android.widget.ImageView;
39import android.widget.LinearLayout;
40import android.widget.TextView;
41
Michael Kolba2b2ba82010-08-04 17:54:03 -070042import java.util.HashMap;
43import java.util.Map;
44
45/**
46 * tabbed title bar for xlarge screen browser
47 */
48public class TabBar extends LinearLayout
49 implements TabChangeListener, ScrollListener, OnClickListener {
50
51 private static final int PROGRESS_MAX = 100;
52
Michael Kolba2b2ba82010-08-04 17:54:03 -070053 private BrowserActivity mBrowserActivity;
54
Michael Kolbed217742010-08-10 17:52:34 -070055 private final int mTabWidthSelected;
56 private final int mTabWidthUnselected;
57
Michael Kolba2b2ba82010-08-04 17:54:03 -070058 private TitleBarXLarge mTitleBar;
59
60 private TabScrollView mTabs;
Michael Kolba2b2ba82010-08-04 17:54:03 -070061 private TabControl mControl;
Michael Kolbebba8b42010-09-30 12:57:59 -070062 private ImageButton mNewTab;
63 private int mButtonWidth;
Michael Kolba2b2ba82010-08-04 17:54:03 -070064
65 private Map<Tab, TabViewData> mTabMap;
66
Michael Kolba2b2ba82010-08-04 17:54:03 -070067 private boolean mUserRequestedUrlbar;
68 private boolean mTitleVisible;
Michael Kolbed217742010-08-10 17:52:34 -070069 private boolean mShowUrlMode;
John Reckfb3017f2010-10-26 19:01:24 -070070 private boolean mHasReceivedTitle;
Michael Kolba2b2ba82010-08-04 17:54:03 -070071
John Reckaff60fb2010-10-25 13:47:58 -070072 private Drawable mGenericFavicon;
John Reckfb3017f2010-10-26 19:01:24 -070073 private String mLoadingText;
John Reckaff60fb2010-10-25 13:47:58 -070074
Michael Kolba2b2ba82010-08-04 17:54:03 -070075 public TabBar(BrowserActivity context, TabControl tabcontrol, TitleBarXLarge titlebar) {
76 super(context);
77 Resources res = context.getResources();
Michael Kolbed217742010-08-10 17:52:34 -070078 mTabWidthSelected = (int) res.getDimension(R.dimen.tab_width_selected);
79 mTabWidthUnselected = (int) res.getDimension(R.dimen.tab_width_unselected);
Michael Kolba2b2ba82010-08-04 17:54:03 -070080
81 mTitleBar = titlebar;
82 mTitleBar.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
83 LayoutParams.WRAP_CONTENT));
Michael Kolba2b2ba82010-08-04 17:54:03 -070084 mTabMap = new HashMap<Tab, TabViewData>();
85 mBrowserActivity = context;
86 mControl = tabcontrol;
87 Resources resources = context.getResources();
88 LayoutInflater factory = LayoutInflater.from(context);
89 factory.inflate(R.layout.tab_bar, this);
90 mTabs = (TabScrollView) findViewById(R.id.tabs);
Michael Kolbebba8b42010-09-30 12:57:59 -070091 mNewTab = (ImageButton) findViewById(R.id.newtab);
92 mNewTab.setOnClickListener(this);
John Reckaff60fb2010-10-25 13:47:58 -070093 mGenericFavicon = res.getDrawable(R.drawable.app_web_browser_sm);
John Reckfb3017f2010-10-26 19:01:24 -070094 mLoadingText = res.getString(R.string.title_bar_loading);
Michael Kolba2b2ba82010-08-04 17:54:03 -070095
96 // TODO: Change enabled states based on whether you can go
97 // back/forward. Probably should be done inside onPageStarted.
98
Michael Kolba2b2ba82010-08-04 17:54:03 -070099 // build tabs
100 int tabcount = mControl.getTabCount();
101 for (int i = 0; i < tabcount; i++) {
102 Tab tab = mControl.getTab(i);
103 TabViewData data = buildTab(tab);
104 TabView tv = buildView(data);
105 }
106 mTabs.setSelectedTab(mControl.getCurrentIndex());
107
108 // register the tab change listener
109 mControl.setOnTabChangeListener(this);
110 mUserRequestedUrlbar = false;
111 mTitleVisible = true;
Michael Kolbebba8b42010-09-30 12:57:59 -0700112 mButtonWidth = -1;
113 }
114
115 @Override
116 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
117 if (mButtonWidth == -1) {
118 mButtonWidth = mNewTab.getMeasuredWidth();
119 }
120 int sw = mTabs.getMeasuredWidth();
121 int w = right-left;
122 if (w-sw < mButtonWidth) {
123 sw = w - mButtonWidth;
124 }
125 mTabs.layout(0, 0, sw, bottom-top );
126 mNewTab.layout(sw, 0, sw+mButtonWidth, bottom-top);
Michael Kolba2b2ba82010-08-04 17:54:03 -0700127 }
128
129 public void onClick(View view) {
Michael Kolbe421c242010-10-04 19:29:01 -0700130 mBrowserActivity.removeComboView();
Michael Kolbebba8b42010-09-30 12:57:59 -0700131 if (mNewTab == view) {
132 mBrowserActivity.openTabToHomePage();
133 } else if (mTabs.getSelectedTab() == view) {
Michael Kolbed217742010-08-10 17:52:34 -0700134 if (mBrowserActivity.isFakeTitleBarShowing() && !isLoading()) {
135 mBrowserActivity.hideFakeTitleBar();
136 } else {
137 showUrlBar();
138 }
Michael Kolba2b2ba82010-08-04 17:54:03 -0700139 } else {
Michael Kolbebba8b42010-09-30 12:57:59 -0700140 int ix = mTabs.getChildIndex(view);
141 if (ix >= 0) {
142 mTabs.setSelectedTab(ix);
143 mBrowserActivity.switchToTab(ix);
144 }
Michael Kolba2b2ba82010-08-04 17:54:03 -0700145 }
146 }
147
Michael Kolbed217742010-08-10 17:52:34 -0700148 private void showUrlBar() {
149 mBrowserActivity.stopScrolling();
150 mBrowserActivity.showFakeTitleBar();
151 mUserRequestedUrlbar = true;
Michael Kolba2b2ba82010-08-04 17:54:03 -0700152 }
153
Michael Kolbed217742010-08-10 17:52:34 -0700154 private void setShowUrlMode(boolean showUrl) {
155 mShowUrlMode = showUrl;
Michael Kolbed217742010-08-10 17:52:34 -0700156 }
157
158 // callback after fake titlebar is shown
159 void onShowTitleBar() {
160 setShowUrlMode(false);
161 }
162
163 // callback after fake titlebar is hidden
Michael Kolba2b2ba82010-08-04 17:54:03 -0700164 void onHideTitleBar() {
Michael Kolbed217742010-08-10 17:52:34 -0700165 setShowUrlMode(!mTitleVisible);
Michael Kolba2b2ba82010-08-04 17:54:03 -0700166 Tab tab = mControl.getCurrentTab();
167 tab.getWebView().requestFocus();
168 mUserRequestedUrlbar = false;
169 }
170
Michael Kolbed217742010-08-10 17:52:34 -0700171 // webview scroll listener
172
173 @Override
174 public void onScroll(boolean titleVisible) {
175 mTitleVisible = titleVisible;
176 if (!mShowUrlMode && !mTitleVisible && !isLoading()) {
177 if (mUserRequestedUrlbar) {
178 mBrowserActivity.hideFakeTitleBar();
179 } else {
180 setShowUrlMode(true);
181 }
182 } else if (mTitleVisible && !isLoading()) {
183 if (mShowUrlMode) {
184 setShowUrlMode(false);
185 }
186 }
187 }
Michael Kolba2b2ba82010-08-04 17:54:03 -0700188
189 @Override
190 public void createContextMenu(ContextMenu menu) {
191 MenuInflater inflater = mBrowserActivity.getMenuInflater();
192 inflater.inflate(R.menu.title_context, menu);
193 mBrowserActivity.onCreateContextMenu(menu, this, null);
194 }
195
196 private TabViewData buildTab(Tab tab) {
197 TabViewData data = new TabViewData(tab);
198 mTabMap.put(tab, data);
199 return data;
200 }
201
202 private TabView buildView(final TabViewData data) {
203 TabView tv = new TabView(mBrowserActivity, data);
204 tv.setTag(data);
205 tv.setOnClickListener(this);
206 mTabs.addTab(tv);
207 return tv;
208 }
209
210 /**
211 * View used in the tab bar
212 */
213 class TabView extends LinearLayout implements OnClickListener {
214
215 TabViewData mTabData;
216 View mTabContent;
217 TextView mTitle;
Michael Kolbae62fd42010-08-18 16:33:28 -0700218 View mIncognito;
Michael Kolba2b2ba82010-08-04 17:54:03 -0700219 ImageView mIconView;
220 ImageView mLock;
221 ImageView mClose;
222 boolean mSelected;
223 boolean mInLoad;
224
225 /**
226 * @param context
227 */
228 public TabView(Context context, TabViewData tab) {
229 super(context);
230 mTabData = tab;
Michael Kolbed217742010-08-10 17:52:34 -0700231 setGravity(Gravity.CENTER_VERTICAL);
232 setOrientation(LinearLayout.HORIZONTAL);
233 setBackgroundResource(R.drawable.tab_background);
Bjorn Bringertb1402a52010-10-12 10:53:12 +0100234 LayoutInflater inflater = LayoutInflater.from(getContext());
Michael Kolbed217742010-08-10 17:52:34 -0700235 mTabContent = inflater.inflate(R.layout.tab_title, this, true);
Michael Kolba2b2ba82010-08-04 17:54:03 -0700236 mTitle = (TextView) mTabContent.findViewById(R.id.title);
237 mIconView = (ImageView) mTabContent.findViewById(R.id.favicon);
238 mLock = (ImageView) mTabContent.findViewById(R.id.lock);
239 mClose = (ImageView) mTabContent.findViewById(R.id.close);
240 mClose.setOnClickListener(this);
Michael Kolbae62fd42010-08-18 16:33:28 -0700241 mIncognito = mTabContent.findViewById(R.id.incognito);
Michael Kolba2b2ba82010-08-04 17:54:03 -0700242 mSelected = false;
243 mInLoad = false;
244 // update the status
245 updateFromData();
246 }
247
248 @Override
249 public void onClick(View v) {
250 if (v == mClose) {
251 closeTab();
252 }
253 }
254
255 private void updateFromData() {
256 mTabData.mTabView = this;
257 if (mTabData.mUrl != null) {
258 setDisplayTitle(mTabData.mUrl);
259 }
260 if (mTabData.mTitle != null) {
261 setDisplayTitle(mTabData.mTitle);
262 }
263 setProgress(mTabData.mProgress);
264 if (mTabData.mIcon != null) {
265 setFavicon(mTabData.mIcon);
266 }
267 if (mTabData.mLock != null) {
268 setLock(mTabData.mLock);
269 }
Michael Kolbae62fd42010-08-18 16:33:28 -0700270 if (mTabData.mTab != null) {
271 mIncognito.setVisibility(
272 mTabData.mTab.getWebView().isPrivateBrowsingEnabled() ?
273 View.VISIBLE : View.GONE);
274 }
Michael Kolba2b2ba82010-08-04 17:54:03 -0700275 }
276
277 @Override
Michael Kolbb7b115e2010-09-25 16:59:37 -0700278 public void setActivated(boolean selected) {
Michael Kolba2b2ba82010-08-04 17:54:03 -0700279 mSelected = selected;
280 mClose.setVisibility(mSelected ? View.VISIBLE : View.GONE);
Michael Kolbc7485ae2010-09-03 10:10:58 -0700281 mTitle.setTextAppearance(mBrowserActivity, mSelected ?
282 R.style.TabTitleSelected : R.style.TabTitleUnselected);
283 setHorizontalFadingEdgeEnabled(!mSelected);
284 setFadingEdgeLength(50);
Michael Kolbb7b115e2010-09-25 16:59:37 -0700285 super.setActivated(selected);
Michael Kolba2b2ba82010-08-04 17:54:03 -0700286 setLayoutParams(new LayoutParams(selected ?
Michael Kolbed217742010-08-10 17:52:34 -0700287 mTabWidthSelected : mTabWidthUnselected,
Michael Kolba2b2ba82010-08-04 17:54:03 -0700288 LayoutParams.MATCH_PARENT));
289 }
290
291 void setDisplayTitle(String title) {
292 mTitle.setText(title);
293 }
294
295 void setFavicon(Drawable d) {
296 mIconView.setImageDrawable(d);
297 }
298
299 void setLock(Drawable d) {
300 if (null == d) {
301 mLock.setVisibility(View.GONE);
302 } else {
303 mLock.setImageDrawable(d);
304 mLock.setVisibility(View.VISIBLE);
305 }
306 }
307
308 void setTitleCompoundDrawables(Drawable left, Drawable top,
309 Drawable right, Drawable bottom) {
310 mTitle.setCompoundDrawables(left, top, right, bottom);
311 }
312
313 void setProgress(int newProgress) {
314 if (newProgress >= PROGRESS_MAX) {
315 mInLoad = false;
316 } else {
317 if (!mInLoad && getWindowToken() != null) {
318 mInLoad = true;
319 }
320 }
321 }
322
323 private void closeTab() {
324 if (mTabData.mTab == mControl.getCurrentTab()) {
325 mBrowserActivity.closeCurrentWindow();
326 } else {
327 mBrowserActivity.closeTab(mTabData.mTab);
328 }
329 }
330
331 }
332
333 /**
334 * Store tab state within the title bar
335 */
336 class TabViewData {
337
338 Tab mTab;
339 TabView mTabView;
340 int mProgress;
341 Drawable mIcon;
342 Drawable mLock;
343 String mTitle;
344 String mUrl;
345
346 TabViewData(Tab tab) {
347 mTab = tab;
John Reckd8657622010-10-25 16:20:40 -0700348 WebView web = tab.getWebView();
349 if (web != null) {
350 setUrlAndTitle(web.getUrl(), web.getTitle());
351 }
Michael Kolba2b2ba82010-08-04 17:54:03 -0700352 }
353
354 void setUrlAndTitle(String url, String title) {
355 mUrl = url;
356 mTitle = title;
357 if (mTabView != null) {
358 if (title != null) {
359 mTabView.setDisplayTitle(title);
360 } else if (url != null) {
John Reckfb3017f2010-10-26 19:01:24 -0700361 mTabView.setDisplayTitle(UrlUtils.stripUrl(url));
Michael Kolba2b2ba82010-08-04 17:54:03 -0700362 }
363 }
364 }
365
366 void setProgress(int newProgress) {
367 mProgress = newProgress;
368 if (mTabView != null) {
369 mTabView.setProgress(mProgress);
370 }
371 }
372
373 void setFavicon(Bitmap icon) {
374 Drawable[] array = new Drawable[3];
375 array[0] = new PaintDrawable(Color.BLACK);
376 array[1] = new PaintDrawable(Color.WHITE);
377 if (icon == null) {
John Reckaff60fb2010-10-25 13:47:58 -0700378 array[2] = mGenericFavicon;
Michael Kolba2b2ba82010-08-04 17:54:03 -0700379 } else {
380 array[2] = new BitmapDrawable(icon);
381 }
382 LayerDrawable d = new LayerDrawable(array);
383 d.setLayerInset(1, 1, 1, 1, 1);
384 d.setLayerInset(2, 2, 2, 2, 2);
385 mIcon = d;
386 if (mTabView != null) {
387 mTabView.setFavicon(mIcon);
388 }
389 }
390
391 }
392
393 // TabChangeListener implementation
394
395 @Override
396 public void onCurrentTab(Tab tab) {
397 mTabs.setSelectedTab(mControl.getCurrentIndex());
398 TabViewData tvd = mTabMap.get(tab);
399 if (tvd != null) {
400 tvd.setProgress(tvd.mProgress);
401 // update the scroll state
402 WebView webview = tab.getWebView();
403 onScroll(webview.getVisibleTitleHeight() > 0);
404 }
405 }
406
407 @Override
408 public void onFavicon(Tab tab, Bitmap favicon) {
409 TabViewData tvd = mTabMap.get(tab);
410 if (tvd != null) {
411 tvd.setFavicon(favicon);
412 }
413 }
414
415 @Override
416 public void onNewTab(Tab tab) {
417 TabViewData tvd = buildTab(tab);
418 buildView(tvd);
Michael Kolba2b2ba82010-08-04 17:54:03 -0700419 }
420
421 @Override
422 public void onProgress(Tab tab, int progress) {
423 TabViewData tvd = mTabMap.get(tab);
424 if (tvd != null) {
425 tvd.setProgress(progress);
426 }
427 }
428
429 @Override
430 public void onRemoveTab(Tab tab) {
431 TabViewData tvd = mTabMap.get(tab);
Michael Kolbe2752f72010-10-25 16:50:16 -0700432 if (tvd != null) {
433 TabView tv = tvd.mTabView;
434 if (tv != null) {
435 mTabs.removeTab(tv);
436 }
Michael Kolba2b2ba82010-08-04 17:54:03 -0700437 }
438 mTabMap.remove(tab);
439 }
440
441 @Override
442 public void onUrlAndTitle(Tab tab, String url, String title) {
John Reckfb3017f2010-10-26 19:01:24 -0700443 mHasReceivedTitle = true;
Michael Kolba2b2ba82010-08-04 17:54:03 -0700444 TabViewData tvd = mTabMap.get(tab);
445 if (tvd != null) {
446 tvd.setUrlAndTitle(url, title);
447 }
448 }
449
450 @Override
451 public void onPageFinished(Tab tab) {
John Reckfb3017f2010-10-26 19:01:24 -0700452 if (!mHasReceivedTitle) {
453 TabViewData tvd = mTabMap.get(tab);
454 if (tvd != null) {
455 tvd.setUrlAndTitle(tvd.mUrl, null);
456 }
457 }
Michael Kolba2b2ba82010-08-04 17:54:03 -0700458 }
459
460 @Override
John Reckfb3017f2010-10-26 19:01:24 -0700461 public void onPageStarted(Tab tab, String url, Bitmap favicon) {
462 mHasReceivedTitle = false;
John Reckaff60fb2010-10-25 13:47:58 -0700463 TabViewData tvd = mTabMap.get(tab);
464 if (tvd != null) {
465 tvd.setFavicon(favicon);
John Reckfb3017f2010-10-26 19:01:24 -0700466 tvd.setUrlAndTitle(url, mLoadingText);
John Reckaff60fb2010-10-25 13:47:58 -0700467 }
Michael Kolba2b2ba82010-08-04 17:54:03 -0700468 }
469
470
471 private boolean isLoading() {
472 return mTabMap.get(mControl.getCurrentTab()).mTabView.mInLoad;
473 }
474
Michael Kolba2b2ba82010-08-04 17:54:03 -0700475}