blob: 69e0bd2a12f42a96abfeac01e72e49f18282084c [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;
Michael Kolbebba8b42010-09-30 12:57:59 -070020
Michael Kolb8233fac2010-10-26 16:08:53 -070021import android.app.Activity;
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;
Michael Kolb1bf23132010-11-19 12:55:12 -080043import java.util.List;
Michael Kolba2b2ba82010-08-04 17:54:03 -070044import java.util.Map;
45
46/**
47 * tabbed title bar for xlarge screen browser
48 */
49public class TabBar extends LinearLayout
Michael Kolb8233fac2010-10-26 16:08:53 -070050 implements ScrollListener, OnClickListener {
Michael Kolba2b2ba82010-08-04 17:54:03 -070051
52 private static final int PROGRESS_MAX = 100;
53
Michael Kolb8233fac2010-10-26 16:08:53 -070054 private Activity mActivity;
55 private UiController mUiController;
56 private TabControl mTabControl;
57 private BaseUi mUi;
Michael Kolba2b2ba82010-08-04 17:54:03 -070058
Michael Kolbed217742010-08-10 17:52:34 -070059 private final int mTabWidthSelected;
60 private final int mTabWidthUnselected;
61
Michael Kolba2b2ba82010-08-04 17:54:03 -070062 private TabScrollView mTabs;
Michael Kolb8233fac2010-10-26 16:08:53 -070063
Michael Kolbebba8b42010-09-30 12:57:59 -070064 private ImageButton mNewTab;
65 private int mButtonWidth;
Michael Kolba2b2ba82010-08-04 17:54:03 -070066
67 private Map<Tab, TabViewData> mTabMap;
68
Michael Kolba2b2ba82010-08-04 17:54:03 -070069 private boolean mUserRequestedUrlbar;
70 private boolean mTitleVisible;
Michael Kolbed217742010-08-10 17:52:34 -070071 private boolean mShowUrlMode;
John Reckfb3017f2010-10-26 19:01:24 -070072 private boolean mHasReceivedTitle;
Michael Kolba2b2ba82010-08-04 17:54:03 -070073
John Reckaff60fb2010-10-25 13:47:58 -070074 private Drawable mGenericFavicon;
John Reckfb3017f2010-10-26 19:01:24 -070075 private String mLoadingText;
John Reckaff60fb2010-10-25 13:47:58 -070076
Michael Kolb8233fac2010-10-26 16:08:53 -070077 public TabBar(Activity activity, UiController controller, BaseUi ui) {
78 super(activity);
79 mActivity = activity;
80 mUiController = controller;
81 mTabControl = mUiController.getTabControl();
82 mUi = ui;
83 Resources res = activity.getResources();
Michael Kolbed217742010-08-10 17:52:34 -070084 mTabWidthSelected = (int) res.getDimension(R.dimen.tab_width_selected);
85 mTabWidthUnselected = (int) res.getDimension(R.dimen.tab_width_unselected);
Michael Kolba2b2ba82010-08-04 17:54:03 -070086
Michael Kolba2b2ba82010-08-04 17:54:03 -070087 mTabMap = new HashMap<Tab, TabViewData>();
Michael Kolb8233fac2010-10-26 16:08:53 -070088 Resources resources = activity.getResources();
89 LayoutInflater factory = LayoutInflater.from(activity);
Michael Kolba2b2ba82010-08-04 17:54:03 -070090 factory.inflate(R.layout.tab_bar, this);
91 mTabs = (TabScrollView) findViewById(R.id.tabs);
Michael Kolbebba8b42010-09-30 12:57:59 -070092 mNewTab = (ImageButton) findViewById(R.id.newtab);
93 mNewTab.setOnClickListener(this);
John Reckaff60fb2010-10-25 13:47:58 -070094 mGenericFavicon = res.getDrawable(R.drawable.app_web_browser_sm);
John Reckfb3017f2010-10-26 19:01:24 -070095 mLoadingText = res.getString(R.string.title_bar_loading);
Michael Kolba2b2ba82010-08-04 17:54:03 -070096
97 // TODO: Change enabled states based on whether you can go
98 // back/forward. Probably should be done inside onPageStarted.
99
Michael Kolb1bf23132010-11-19 12:55:12 -0800100 updateTabs(mUiController.getTabs());
Michael Kolba2b2ba82010-08-04 17:54:03 -0700101
Michael Kolba2b2ba82010-08-04 17:54:03 -0700102 mUserRequestedUrlbar = false;
103 mTitleVisible = true;
Michael Kolbebba8b42010-09-30 12:57:59 -0700104 mButtonWidth = -1;
105 }
106
Michael Kolb1bf23132010-11-19 12:55:12 -0800107 void updateTabs(List<Tab> tabs) {
108 mTabs.clearTabs();
109 mTabMap.clear();
110 for (Tab tab : tabs) {
111 TabViewData data = buildTab(tab);
112 TabView tv = buildView(data);
113 }
114 mTabs.setSelectedTab(mTabControl.getCurrentIndex());
115 }
116
Michael Kolbebba8b42010-09-30 12:57:59 -0700117 @Override
118 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
119 if (mButtonWidth == -1) {
120 mButtonWidth = mNewTab.getMeasuredWidth();
121 }
122 int sw = mTabs.getMeasuredWidth();
123 int w = right-left;
124 if (w-sw < mButtonWidth) {
125 sw = w - mButtonWidth;
126 }
127 mTabs.layout(0, 0, sw, bottom-top );
128 mNewTab.layout(sw, 0, sw+mButtonWidth, bottom-top);
Michael Kolba2b2ba82010-08-04 17:54:03 -0700129 }
130
131 public void onClick(View view) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700132 mUi.hideComboView();
Michael Kolbebba8b42010-09-30 12:57:59 -0700133 if (mNewTab == view) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700134 mUiController.openTabToHomePage();
Michael Kolbebba8b42010-09-30 12:57:59 -0700135 } else if (mTabs.getSelectedTab() == view) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700136 if (mUi.isFakeTitleBarShowing() && !isLoading()) {
137 mUi.hideFakeTitleBar();
Michael Kolbed217742010-08-10 17:52:34 -0700138 } else {
139 showUrlBar();
140 }
Michael Kolba2b2ba82010-08-04 17:54:03 -0700141 } else {
Michael Kolbebba8b42010-09-30 12:57:59 -0700142 int ix = mTabs.getChildIndex(view);
143 if (ix >= 0) {
144 mTabs.setSelectedTab(ix);
Michael Kolb8233fac2010-10-26 16:08:53 -0700145 mUiController.switchToTab(ix);
Michael Kolbebba8b42010-09-30 12:57:59 -0700146 }
Michael Kolba2b2ba82010-08-04 17:54:03 -0700147 }
148 }
149
Michael Kolbed217742010-08-10 17:52:34 -0700150 private void showUrlBar() {
Michael Kolb8233fac2010-10-26 16:08:53 -0700151 mUi.stopWebViewScrolling();
152 mUi.showFakeTitleBar();
Michael Kolbed217742010-08-10 17:52:34 -0700153 mUserRequestedUrlbar = true;
Michael Kolba2b2ba82010-08-04 17:54:03 -0700154 }
155
Michael Kolbed217742010-08-10 17:52:34 -0700156 private void setShowUrlMode(boolean showUrl) {
157 mShowUrlMode = showUrl;
Michael Kolbed217742010-08-10 17:52:34 -0700158 }
159
160 // callback after fake titlebar is shown
161 void onShowTitleBar() {
162 setShowUrlMode(false);
163 }
164
165 // callback after fake titlebar is hidden
Michael Kolba2b2ba82010-08-04 17:54:03 -0700166 void onHideTitleBar() {
Michael Kolbed217742010-08-10 17:52:34 -0700167 setShowUrlMode(!mTitleVisible);
Michael Kolb8233fac2010-10-26 16:08:53 -0700168 Tab tab = mTabControl.getCurrentTab();
Michael Kolba2b2ba82010-08-04 17:54:03 -0700169 tab.getWebView().requestFocus();
170 mUserRequestedUrlbar = false;
171 }
172
Michael Kolbed217742010-08-10 17:52:34 -0700173 // webview scroll listener
174
175 @Override
176 public void onScroll(boolean titleVisible) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700177 // isLoading is using the current tab, which initially might not be set yet
178 if (mTabControl.getCurrentTab() != null) {
179 mTitleVisible = titleVisible;
180 if (!mShowUrlMode && !mTitleVisible && !isLoading()) {
181 if (mUserRequestedUrlbar) {
182 mUi.hideFakeTitleBar();
183 } else {
184 setShowUrlMode(true);
185 }
186 } else if (mTitleVisible && !isLoading()) {
187 if (mShowUrlMode) {
188 setShowUrlMode(false);
189 }
Michael Kolbed217742010-08-10 17:52:34 -0700190 }
191 }
192 }
Michael Kolba2b2ba82010-08-04 17:54:03 -0700193
194 @Override
195 public void createContextMenu(ContextMenu menu) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700196 MenuInflater inflater = mActivity.getMenuInflater();
Michael Kolba2b2ba82010-08-04 17:54:03 -0700197 inflater.inflate(R.menu.title_context, menu);
Michael Kolb8233fac2010-10-26 16:08:53 -0700198 mActivity.onCreateContextMenu(menu, this, null);
Michael Kolba2b2ba82010-08-04 17:54:03 -0700199 }
200
201 private TabViewData buildTab(Tab tab) {
202 TabViewData data = new TabViewData(tab);
203 mTabMap.put(tab, data);
204 return data;
205 }
206
207 private TabView buildView(final TabViewData data) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700208 TabView tv = new TabView(mActivity, data);
Michael Kolba2b2ba82010-08-04 17:54:03 -0700209 tv.setTag(data);
210 tv.setOnClickListener(this);
211 mTabs.addTab(tv);
212 return tv;
213 }
214
215 /**
216 * View used in the tab bar
217 */
218 class TabView extends LinearLayout implements OnClickListener {
219
220 TabViewData mTabData;
221 View mTabContent;
222 TextView mTitle;
Michael Kolbae62fd42010-08-18 16:33:28 -0700223 View mIncognito;
Michael Kolba2b2ba82010-08-04 17:54:03 -0700224 ImageView mIconView;
225 ImageView mLock;
226 ImageView mClose;
227 boolean mSelected;
228 boolean mInLoad;
229
230 /**
231 * @param context
232 */
233 public TabView(Context context, TabViewData tab) {
234 super(context);
235 mTabData = tab;
Michael Kolbed217742010-08-10 17:52:34 -0700236 setGravity(Gravity.CENTER_VERTICAL);
237 setOrientation(LinearLayout.HORIZONTAL);
238 setBackgroundResource(R.drawable.tab_background);
Bjorn Bringertb1402a52010-10-12 10:53:12 +0100239 LayoutInflater inflater = LayoutInflater.from(getContext());
Michael Kolbed217742010-08-10 17:52:34 -0700240 mTabContent = inflater.inflate(R.layout.tab_title, this, true);
Michael Kolba2b2ba82010-08-04 17:54:03 -0700241 mTitle = (TextView) mTabContent.findViewById(R.id.title);
242 mIconView = (ImageView) mTabContent.findViewById(R.id.favicon);
243 mLock = (ImageView) mTabContent.findViewById(R.id.lock);
244 mClose = (ImageView) mTabContent.findViewById(R.id.close);
245 mClose.setOnClickListener(this);
Michael Kolbae62fd42010-08-18 16:33:28 -0700246 mIncognito = mTabContent.findViewById(R.id.incognito);
Michael Kolba2b2ba82010-08-04 17:54:03 -0700247 mSelected = false;
248 mInLoad = false;
249 // update the status
250 updateFromData();
251 }
252
253 @Override
254 public void onClick(View v) {
255 if (v == mClose) {
256 closeTab();
257 }
258 }
259
260 private void updateFromData() {
261 mTabData.mTabView = this;
262 if (mTabData.mUrl != null) {
263 setDisplayTitle(mTabData.mUrl);
264 }
265 if (mTabData.mTitle != null) {
266 setDisplayTitle(mTabData.mTitle);
267 }
268 setProgress(mTabData.mProgress);
269 if (mTabData.mIcon != null) {
270 setFavicon(mTabData.mIcon);
271 }
272 if (mTabData.mLock != null) {
273 setLock(mTabData.mLock);
274 }
Michael Kolbae62fd42010-08-18 16:33:28 -0700275 if (mTabData.mTab != null) {
276 mIncognito.setVisibility(
Michael Kolb1bf23132010-11-19 12:55:12 -0800277 mTabData.mTab.isPrivateBrowsingEnabled() ?
Michael Kolbae62fd42010-08-18 16:33:28 -0700278 View.VISIBLE : View.GONE);
279 }
Michael Kolba2b2ba82010-08-04 17:54:03 -0700280 }
281
282 @Override
Michael Kolbb7b115e2010-09-25 16:59:37 -0700283 public void setActivated(boolean selected) {
Michael Kolba2b2ba82010-08-04 17:54:03 -0700284 mSelected = selected;
285 mClose.setVisibility(mSelected ? View.VISIBLE : View.GONE);
Michael Kolb8233fac2010-10-26 16:08:53 -0700286 mTitle.setTextAppearance(mActivity, mSelected ?
Michael Kolbc7485ae2010-09-03 10:10:58 -0700287 R.style.TabTitleSelected : R.style.TabTitleUnselected);
288 setHorizontalFadingEdgeEnabled(!mSelected);
289 setFadingEdgeLength(50);
Michael Kolbb7b115e2010-09-25 16:59:37 -0700290 super.setActivated(selected);
Michael Kolba2b2ba82010-08-04 17:54:03 -0700291 setLayoutParams(new LayoutParams(selected ?
Michael Kolbed217742010-08-10 17:52:34 -0700292 mTabWidthSelected : mTabWidthUnselected,
Michael Kolba2b2ba82010-08-04 17:54:03 -0700293 LayoutParams.MATCH_PARENT));
294 }
295
296 void setDisplayTitle(String title) {
297 mTitle.setText(title);
298 }
299
300 void setFavicon(Drawable d) {
301 mIconView.setImageDrawable(d);
302 }
303
304 void setLock(Drawable d) {
305 if (null == d) {
306 mLock.setVisibility(View.GONE);
307 } else {
308 mLock.setImageDrawable(d);
309 mLock.setVisibility(View.VISIBLE);
310 }
311 }
312
Michael Kolba2b2ba82010-08-04 17:54:03 -0700313 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() {
Michael Kolb8233fac2010-10-26 16:08:53 -0700324 if (mTabData.mTab == mTabControl.getCurrentTab()) {
325 mUiController.closeCurrentTab();
Michael Kolba2b2ba82010-08-04 17:54:03 -0700326 } else {
Michael Kolb8233fac2010-10-26 16:08:53 -0700327 mUiController.closeTab(mTabData.mTab);
Michael Kolba2b2ba82010-08-04 17:54:03 -0700328 }
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
Michael Kolb8233fac2010-10-26 16:08:53 -0700395 public void onSetActiveTab(Tab tab) {
396 mTabs.setSelectedTab(mTabControl.getTabIndex(tab));
Michael Kolba2b2ba82010-08-04 17:54:03 -0700397 TabViewData tvd = mTabMap.get(tab);
398 if (tvd != null) {
399 tvd.setProgress(tvd.mProgress);
400 // update the scroll state
401 WebView webview = tab.getWebView();
402 onScroll(webview.getVisibleTitleHeight() > 0);
403 }
404 }
405
Michael Kolba2b2ba82010-08-04 17:54:03 -0700406 public void onFavicon(Tab tab, Bitmap favicon) {
407 TabViewData tvd = mTabMap.get(tab);
408 if (tvd != null) {
409 tvd.setFavicon(favicon);
410 }
411 }
412
Michael Kolba2b2ba82010-08-04 17:54:03 -0700413 public void onNewTab(Tab tab) {
414 TabViewData tvd = buildTab(tab);
415 buildView(tvd);
Michael Kolba2b2ba82010-08-04 17:54:03 -0700416 }
417
Michael Kolba2b2ba82010-08-04 17:54:03 -0700418 public void onProgress(Tab tab, int progress) {
419 TabViewData tvd = mTabMap.get(tab);
420 if (tvd != null) {
421 tvd.setProgress(progress);
422 }
423 }
424
Michael Kolba2b2ba82010-08-04 17:54:03 -0700425 public void onRemoveTab(Tab tab) {
426 TabViewData tvd = mTabMap.get(tab);
Michael Kolbe2752f72010-10-25 16:50:16 -0700427 if (tvd != null) {
428 TabView tv = tvd.mTabView;
429 if (tv != null) {
430 mTabs.removeTab(tv);
431 }
Michael Kolba2b2ba82010-08-04 17:54:03 -0700432 }
433 mTabMap.remove(tab);
434 }
435
Michael Kolba2b2ba82010-08-04 17:54:03 -0700436 public void onUrlAndTitle(Tab tab, String url, String title) {
John Reckfb3017f2010-10-26 19:01:24 -0700437 mHasReceivedTitle = true;
Michael Kolba2b2ba82010-08-04 17:54:03 -0700438 TabViewData tvd = mTabMap.get(tab);
439 if (tvd != null) {
440 tvd.setUrlAndTitle(url, title);
441 }
442 }
443
Michael Kolba2b2ba82010-08-04 17:54:03 -0700444 public void onPageFinished(Tab tab) {
John Reckfb3017f2010-10-26 19:01:24 -0700445 if (!mHasReceivedTitle) {
446 TabViewData tvd = mTabMap.get(tab);
447 if (tvd != null) {
448 tvd.setUrlAndTitle(tvd.mUrl, null);
449 }
450 }
Michael Kolba2b2ba82010-08-04 17:54:03 -0700451 }
452
John Reckfb3017f2010-10-26 19:01:24 -0700453 public void onPageStarted(Tab tab, String url, Bitmap favicon) {
454 mHasReceivedTitle = false;
John Reckaff60fb2010-10-25 13:47:58 -0700455 TabViewData tvd = mTabMap.get(tab);
456 if (tvd != null) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700457 tvd.setUrlAndTitle(url, null);
John Reckaff60fb2010-10-25 13:47:58 -0700458 tvd.setFavicon(favicon);
John Reckfb3017f2010-10-26 19:01:24 -0700459 tvd.setUrlAndTitle(url, mLoadingText);
John Reckaff60fb2010-10-25 13:47:58 -0700460 }
Michael Kolba2b2ba82010-08-04 17:54:03 -0700461 }
462
Michael Kolba2b2ba82010-08-04 17:54:03 -0700463 private boolean isLoading() {
Michael Kolb8233fac2010-10-26 16:08:53 -0700464 TabViewData tvd = mTabMap.get(mTabControl.getCurrentTab());
465 if ((tvd != null) && (tvd.mTabView != null)) {
466 return tvd.mTabView.mInLoad;
467 } else {
468 return false;
469 }
Michael Kolba2b2ba82010-08-04 17:54:03 -0700470 }
471
Michael Kolba2b2ba82010-08-04 17:54:03 -0700472}