blob: 9d5867540f5d112870cf124dfdc704b489106a76 [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;
Michael Kolba2b2ba82010-08-04 17:54:03 -070070
John Reckaff60fb2010-10-25 13:47:58 -070071 private Drawable mGenericFavicon;
72
Michael Kolba2b2ba82010-08-04 17:54:03 -070073 public TabBar(BrowserActivity context, TabControl tabcontrol, TitleBarXLarge titlebar) {
74 super(context);
75 Resources res = context.getResources();
Michael Kolbed217742010-08-10 17:52:34 -070076 mTabWidthSelected = (int) res.getDimension(R.dimen.tab_width_selected);
77 mTabWidthUnselected = (int) res.getDimension(R.dimen.tab_width_unselected);
Michael Kolba2b2ba82010-08-04 17:54:03 -070078
79 mTitleBar = titlebar;
80 mTitleBar.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
81 LayoutParams.WRAP_CONTENT));
Michael Kolba2b2ba82010-08-04 17:54:03 -070082 mTabMap = new HashMap<Tab, TabViewData>();
83 mBrowserActivity = context;
84 mControl = tabcontrol;
85 Resources resources = context.getResources();
86 LayoutInflater factory = LayoutInflater.from(context);
87 factory.inflate(R.layout.tab_bar, this);
88 mTabs = (TabScrollView) findViewById(R.id.tabs);
Michael Kolbebba8b42010-09-30 12:57:59 -070089 mNewTab = (ImageButton) findViewById(R.id.newtab);
90 mNewTab.setOnClickListener(this);
John Reckaff60fb2010-10-25 13:47:58 -070091 mGenericFavicon = res.getDrawable(R.drawable.app_web_browser_sm);
Michael Kolba2b2ba82010-08-04 17:54:03 -070092
93 // TODO: Change enabled states based on whether you can go
94 // back/forward. Probably should be done inside onPageStarted.
95
Michael Kolba2b2ba82010-08-04 17:54:03 -070096 // build tabs
97 int tabcount = mControl.getTabCount();
98 for (int i = 0; i < tabcount; i++) {
99 Tab tab = mControl.getTab(i);
100 TabViewData data = buildTab(tab);
101 TabView tv = buildView(data);
102 }
103 mTabs.setSelectedTab(mControl.getCurrentIndex());
104
105 // register the tab change listener
106 mControl.setOnTabChangeListener(this);
107 mUserRequestedUrlbar = false;
108 mTitleVisible = true;
Michael Kolbebba8b42010-09-30 12:57:59 -0700109 mButtonWidth = -1;
110 }
111
112 @Override
113 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
114 if (mButtonWidth == -1) {
115 mButtonWidth = mNewTab.getMeasuredWidth();
116 }
117 int sw = mTabs.getMeasuredWidth();
118 int w = right-left;
119 if (w-sw < mButtonWidth) {
120 sw = w - mButtonWidth;
121 }
122 mTabs.layout(0, 0, sw, bottom-top );
123 mNewTab.layout(sw, 0, sw+mButtonWidth, bottom-top);
Michael Kolba2b2ba82010-08-04 17:54:03 -0700124 }
125
126 public void onClick(View view) {
Michael Kolbe421c242010-10-04 19:29:01 -0700127 mBrowserActivity.removeComboView();
Michael Kolbebba8b42010-09-30 12:57:59 -0700128 if (mNewTab == view) {
129 mBrowserActivity.openTabToHomePage();
130 } else if (mTabs.getSelectedTab() == view) {
Michael Kolbed217742010-08-10 17:52:34 -0700131 if (mBrowserActivity.isFakeTitleBarShowing() && !isLoading()) {
132 mBrowserActivity.hideFakeTitleBar();
133 } else {
134 showUrlBar();
135 }
Michael Kolba2b2ba82010-08-04 17:54:03 -0700136 } else {
Michael Kolbebba8b42010-09-30 12:57:59 -0700137 int ix = mTabs.getChildIndex(view);
138 if (ix >= 0) {
139 mTabs.setSelectedTab(ix);
140 mBrowserActivity.switchToTab(ix);
141 }
Michael Kolba2b2ba82010-08-04 17:54:03 -0700142 }
143 }
144
Michael Kolbed217742010-08-10 17:52:34 -0700145 private void showUrlBar() {
146 mBrowserActivity.stopScrolling();
147 mBrowserActivity.showFakeTitleBar();
148 mUserRequestedUrlbar = true;
Michael Kolba2b2ba82010-08-04 17:54:03 -0700149 }
150
Michael Kolbed217742010-08-10 17:52:34 -0700151 private void setShowUrlMode(boolean showUrl) {
152 mShowUrlMode = showUrl;
Michael Kolbed217742010-08-10 17:52:34 -0700153 }
154
155 // callback after fake titlebar is shown
156 void onShowTitleBar() {
157 setShowUrlMode(false);
158 }
159
160 // callback after fake titlebar is hidden
Michael Kolba2b2ba82010-08-04 17:54:03 -0700161 void onHideTitleBar() {
Michael Kolbed217742010-08-10 17:52:34 -0700162 setShowUrlMode(!mTitleVisible);
Michael Kolba2b2ba82010-08-04 17:54:03 -0700163 Tab tab = mControl.getCurrentTab();
164 tab.getWebView().requestFocus();
165 mUserRequestedUrlbar = false;
166 }
167
Michael Kolbed217742010-08-10 17:52:34 -0700168 // webview scroll listener
169
170 @Override
171 public void onScroll(boolean titleVisible) {
172 mTitleVisible = titleVisible;
173 if (!mShowUrlMode && !mTitleVisible && !isLoading()) {
174 if (mUserRequestedUrlbar) {
175 mBrowserActivity.hideFakeTitleBar();
176 } else {
177 setShowUrlMode(true);
178 }
179 } else if (mTitleVisible && !isLoading()) {
180 if (mShowUrlMode) {
181 setShowUrlMode(false);
182 }
183 }
184 }
Michael Kolba2b2ba82010-08-04 17:54:03 -0700185
186 @Override
187 public void createContextMenu(ContextMenu menu) {
188 MenuInflater inflater = mBrowserActivity.getMenuInflater();
189 inflater.inflate(R.menu.title_context, menu);
190 mBrowserActivity.onCreateContextMenu(menu, this, null);
191 }
192
193 private TabViewData buildTab(Tab tab) {
194 TabViewData data = new TabViewData(tab);
195 mTabMap.put(tab, data);
196 return data;
197 }
198
199 private TabView buildView(final TabViewData data) {
200 TabView tv = new TabView(mBrowserActivity, data);
201 tv.setTag(data);
202 tv.setOnClickListener(this);
203 mTabs.addTab(tv);
204 return tv;
205 }
206
207 /**
208 * View used in the tab bar
209 */
210 class TabView extends LinearLayout implements OnClickListener {
211
212 TabViewData mTabData;
213 View mTabContent;
214 TextView mTitle;
Michael Kolbae62fd42010-08-18 16:33:28 -0700215 View mIncognito;
Michael Kolba2b2ba82010-08-04 17:54:03 -0700216 ImageView mIconView;
217 ImageView mLock;
218 ImageView mClose;
219 boolean mSelected;
220 boolean mInLoad;
221
222 /**
223 * @param context
224 */
225 public TabView(Context context, TabViewData tab) {
226 super(context);
227 mTabData = tab;
Michael Kolbed217742010-08-10 17:52:34 -0700228 setGravity(Gravity.CENTER_VERTICAL);
229 setOrientation(LinearLayout.HORIZONTAL);
230 setBackgroundResource(R.drawable.tab_background);
Bjorn Bringertb1402a52010-10-12 10:53:12 +0100231 LayoutInflater inflater = LayoutInflater.from(getContext());
Michael Kolbed217742010-08-10 17:52:34 -0700232 mTabContent = inflater.inflate(R.layout.tab_title, this, true);
Michael Kolba2b2ba82010-08-04 17:54:03 -0700233 mTitle = (TextView) mTabContent.findViewById(R.id.title);
234 mIconView = (ImageView) mTabContent.findViewById(R.id.favicon);
235 mLock = (ImageView) mTabContent.findViewById(R.id.lock);
236 mClose = (ImageView) mTabContent.findViewById(R.id.close);
237 mClose.setOnClickListener(this);
Michael Kolbae62fd42010-08-18 16:33:28 -0700238 mIncognito = mTabContent.findViewById(R.id.incognito);
Michael Kolba2b2ba82010-08-04 17:54:03 -0700239 mSelected = false;
240 mInLoad = false;
241 // update the status
242 updateFromData();
243 }
244
245 @Override
246 public void onClick(View v) {
247 if (v == mClose) {
248 closeTab();
249 }
250 }
251
252 private void updateFromData() {
253 mTabData.mTabView = this;
254 if (mTabData.mUrl != null) {
255 setDisplayTitle(mTabData.mUrl);
256 }
257 if (mTabData.mTitle != null) {
258 setDisplayTitle(mTabData.mTitle);
259 }
260 setProgress(mTabData.mProgress);
261 if (mTabData.mIcon != null) {
262 setFavicon(mTabData.mIcon);
263 }
264 if (mTabData.mLock != null) {
265 setLock(mTabData.mLock);
266 }
Michael Kolbae62fd42010-08-18 16:33:28 -0700267 if (mTabData.mTab != null) {
268 mIncognito.setVisibility(
269 mTabData.mTab.getWebView().isPrivateBrowsingEnabled() ?
270 View.VISIBLE : View.GONE);
271 }
Michael Kolba2b2ba82010-08-04 17:54:03 -0700272 }
273
274 @Override
Michael Kolbb7b115e2010-09-25 16:59:37 -0700275 public void setActivated(boolean selected) {
Michael Kolba2b2ba82010-08-04 17:54:03 -0700276 mSelected = selected;
277 mClose.setVisibility(mSelected ? View.VISIBLE : View.GONE);
Michael Kolbc7485ae2010-09-03 10:10:58 -0700278 mTitle.setTextAppearance(mBrowserActivity, mSelected ?
279 R.style.TabTitleSelected : R.style.TabTitleUnselected);
280 setHorizontalFadingEdgeEnabled(!mSelected);
281 setFadingEdgeLength(50);
Michael Kolbb7b115e2010-09-25 16:59:37 -0700282 super.setActivated(selected);
Michael Kolba2b2ba82010-08-04 17:54:03 -0700283 setLayoutParams(new LayoutParams(selected ?
Michael Kolbed217742010-08-10 17:52:34 -0700284 mTabWidthSelected : mTabWidthUnselected,
Michael Kolba2b2ba82010-08-04 17:54:03 -0700285 LayoutParams.MATCH_PARENT));
286 }
287
288 void setDisplayTitle(String title) {
289 mTitle.setText(title);
290 }
291
292 void setFavicon(Drawable d) {
293 mIconView.setImageDrawable(d);
294 }
295
296 void setLock(Drawable d) {
297 if (null == d) {
298 mLock.setVisibility(View.GONE);
299 } else {
300 mLock.setImageDrawable(d);
301 mLock.setVisibility(View.VISIBLE);
302 }
303 }
304
305 void setTitleCompoundDrawables(Drawable left, Drawable top,
306 Drawable right, Drawable bottom) {
307 mTitle.setCompoundDrawables(left, top, right, bottom);
308 }
309
310 void setProgress(int newProgress) {
311 if (newProgress >= PROGRESS_MAX) {
312 mInLoad = false;
313 } else {
314 if (!mInLoad && getWindowToken() != null) {
315 mInLoad = true;
316 }
317 }
318 }
319
320 private void closeTab() {
321 if (mTabData.mTab == mControl.getCurrentTab()) {
322 mBrowserActivity.closeCurrentWindow();
323 } else {
324 mBrowserActivity.closeTab(mTabData.mTab);
325 }
326 }
327
328 }
329
330 /**
331 * Store tab state within the title bar
332 */
333 class TabViewData {
334
335 Tab mTab;
336 TabView mTabView;
337 int mProgress;
338 Drawable mIcon;
339 Drawable mLock;
340 String mTitle;
341 String mUrl;
342
343 TabViewData(Tab tab) {
344 mTab = tab;
345 }
346
347 void setUrlAndTitle(String url, String title) {
348 mUrl = url;
349 mTitle = title;
350 if (mTabView != null) {
351 if (title != null) {
352 mTabView.setDisplayTitle(title);
353 } else if (url != null) {
354 mTabView.setDisplayTitle(url);
355 }
356 }
357 }
358
359 void setProgress(int newProgress) {
360 mProgress = newProgress;
361 if (mTabView != null) {
362 mTabView.setProgress(mProgress);
363 }
364 }
365
366 void setFavicon(Bitmap icon) {
367 Drawable[] array = new Drawable[3];
368 array[0] = new PaintDrawable(Color.BLACK);
369 array[1] = new PaintDrawable(Color.WHITE);
370 if (icon == null) {
John Reckaff60fb2010-10-25 13:47:58 -0700371 array[2] = mGenericFavicon;
Michael Kolba2b2ba82010-08-04 17:54:03 -0700372 } else {
373 array[2] = new BitmapDrawable(icon);
374 }
375 LayerDrawable d = new LayerDrawable(array);
376 d.setLayerInset(1, 1, 1, 1, 1);
377 d.setLayerInset(2, 2, 2, 2, 2);
378 mIcon = d;
379 if (mTabView != null) {
380 mTabView.setFavicon(mIcon);
381 }
382 }
383
384 }
385
386 // TabChangeListener implementation
387
388 @Override
389 public void onCurrentTab(Tab tab) {
390 mTabs.setSelectedTab(mControl.getCurrentIndex());
391 TabViewData tvd = mTabMap.get(tab);
392 if (tvd != null) {
393 tvd.setProgress(tvd.mProgress);
394 // update the scroll state
395 WebView webview = tab.getWebView();
396 onScroll(webview.getVisibleTitleHeight() > 0);
397 }
398 }
399
400 @Override
401 public void onFavicon(Tab tab, Bitmap favicon) {
402 TabViewData tvd = mTabMap.get(tab);
403 if (tvd != null) {
404 tvd.setFavicon(favicon);
405 }
406 }
407
408 @Override
409 public void onNewTab(Tab tab) {
410 TabViewData tvd = buildTab(tab);
411 buildView(tvd);
Michael Kolba2b2ba82010-08-04 17:54:03 -0700412 }
413
414 @Override
415 public void onProgress(Tab tab, int progress) {
416 TabViewData tvd = mTabMap.get(tab);
417 if (tvd != null) {
418 tvd.setProgress(progress);
419 }
420 }
421
422 @Override
423 public void onRemoveTab(Tab tab) {
424 TabViewData tvd = mTabMap.get(tab);
Michael Kolbe2752f72010-10-25 16:50:16 -0700425 if (tvd != null) {
426 TabView tv = tvd.mTabView;
427 if (tv != null) {
428 mTabs.removeTab(tv);
429 }
Michael Kolba2b2ba82010-08-04 17:54:03 -0700430 }
431 mTabMap.remove(tab);
432 }
433
434 @Override
435 public void onUrlAndTitle(Tab tab, String url, String title) {
436 TabViewData tvd = mTabMap.get(tab);
437 if (tvd != null) {
438 tvd.setUrlAndTitle(url, title);
439 }
440 }
441
442 @Override
443 public void onPageFinished(Tab tab) {
444 }
445
446 @Override
John Reckaff60fb2010-10-25 13:47:58 -0700447 public void onPageStarted(Tab tab, Bitmap favicon) {
448 TabViewData tvd = mTabMap.get(tab);
449 if (tvd != null) {
450 tvd.setFavicon(favicon);
451 }
Michael Kolba2b2ba82010-08-04 17:54:03 -0700452 }
453
454
455 private boolean isLoading() {
456 return mTabMap.get(mControl.getCurrentTab()).mTabView.mInLoad;
457 }
458
Michael Kolba2b2ba82010-08-04 17:54:03 -0700459}