TabBar.java revision fb3017ffd8aa3f2342380270cf468e3a68914e69
1/* 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 19import com.android.browser.ScrollWebView.ScrollListener; 20import com.android.browser.TabControl.TabChangeListener; 21 22import 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; 31import android.view.Gravity; 32import android.view.LayoutInflater; 33import android.view.MenuInflater; 34import android.view.View; 35import android.view.View.OnClickListener; 36import android.webkit.WebView; 37import android.widget.ImageButton; 38import android.widget.ImageView; 39import android.widget.LinearLayout; 40import android.widget.TextView; 41 42import 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 53 private BrowserActivity mBrowserActivity; 54 55 private final int mTabWidthSelected; 56 private final int mTabWidthUnselected; 57 58 private TitleBarXLarge mTitleBar; 59 60 private TabScrollView mTabs; 61 private TabControl mControl; 62 private ImageButton mNewTab; 63 private int mButtonWidth; 64 65 private Map<Tab, TabViewData> mTabMap; 66 67 private boolean mUserRequestedUrlbar; 68 private boolean mTitleVisible; 69 private boolean mShowUrlMode; 70 private boolean mHasReceivedTitle; 71 72 private Drawable mGenericFavicon; 73 private String mLoadingText; 74 75 public TabBar(BrowserActivity context, TabControl tabcontrol, TitleBarXLarge titlebar) { 76 super(context); 77 Resources res = context.getResources(); 78 mTabWidthSelected = (int) res.getDimension(R.dimen.tab_width_selected); 79 mTabWidthUnselected = (int) res.getDimension(R.dimen.tab_width_unselected); 80 81 mTitleBar = titlebar; 82 mTitleBar.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, 83 LayoutParams.WRAP_CONTENT)); 84 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); 91 mNewTab = (ImageButton) findViewById(R.id.newtab); 92 mNewTab.setOnClickListener(this); 93 mGenericFavicon = res.getDrawable(R.drawable.app_web_browser_sm); 94 mLoadingText = res.getString(R.string.title_bar_loading); 95 96 // TODO: Change enabled states based on whether you can go 97 // back/forward. Probably should be done inside onPageStarted. 98 99 // 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; 112 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); 127 } 128 129 public void onClick(View view) { 130 mBrowserActivity.removeComboView(); 131 if (mNewTab == view) { 132 mBrowserActivity.openTabToHomePage(); 133 } else if (mTabs.getSelectedTab() == view) { 134 if (mBrowserActivity.isFakeTitleBarShowing() && !isLoading()) { 135 mBrowserActivity.hideFakeTitleBar(); 136 } else { 137 showUrlBar(); 138 } 139 } else { 140 int ix = mTabs.getChildIndex(view); 141 if (ix >= 0) { 142 mTabs.setSelectedTab(ix); 143 mBrowserActivity.switchToTab(ix); 144 } 145 } 146 } 147 148 private void showUrlBar() { 149 mBrowserActivity.stopScrolling(); 150 mBrowserActivity.showFakeTitleBar(); 151 mUserRequestedUrlbar = true; 152 } 153 154 private void setShowUrlMode(boolean showUrl) { 155 mShowUrlMode = showUrl; 156 } 157 158 // callback after fake titlebar is shown 159 void onShowTitleBar() { 160 setShowUrlMode(false); 161 } 162 163 // callback after fake titlebar is hidden 164 void onHideTitleBar() { 165 setShowUrlMode(!mTitleVisible); 166 Tab tab = mControl.getCurrentTab(); 167 tab.getWebView().requestFocus(); 168 mUserRequestedUrlbar = false; 169 } 170 171 // 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 } 188 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; 218 View mIncognito; 219 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; 231 setGravity(Gravity.CENTER_VERTICAL); 232 setOrientation(LinearLayout.HORIZONTAL); 233 setBackgroundResource(R.drawable.tab_background); 234 LayoutInflater inflater = LayoutInflater.from(getContext()); 235 mTabContent = inflater.inflate(R.layout.tab_title, this, true); 236 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); 241 mIncognito = mTabContent.findViewById(R.id.incognito); 242 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 } 270 if (mTabData.mTab != null) { 271 mIncognito.setVisibility( 272 mTabData.mTab.getWebView().isPrivateBrowsingEnabled() ? 273 View.VISIBLE : View.GONE); 274 } 275 } 276 277 @Override 278 public void setActivated(boolean selected) { 279 mSelected = selected; 280 mClose.setVisibility(mSelected ? View.VISIBLE : View.GONE); 281 mTitle.setTextAppearance(mBrowserActivity, mSelected ? 282 R.style.TabTitleSelected : R.style.TabTitleUnselected); 283 setHorizontalFadingEdgeEnabled(!mSelected); 284 setFadingEdgeLength(50); 285 super.setActivated(selected); 286 setLayoutParams(new LayoutParams(selected ? 287 mTabWidthSelected : mTabWidthUnselected, 288 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; 348 WebView web = tab.getWebView(); 349 if (web != null) { 350 setUrlAndTitle(web.getUrl(), web.getTitle()); 351 } 352 } 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) { 361 mTabView.setDisplayTitle(UrlUtils.stripUrl(url)); 362 } 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) { 378 array[2] = mGenericFavicon; 379 } 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); 419 } 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); 432 if (tvd != null) { 433 TabView tv = tvd.mTabView; 434 if (tv != null) { 435 mTabs.removeTab(tv); 436 } 437 } 438 mTabMap.remove(tab); 439 } 440 441 @Override 442 public void onUrlAndTitle(Tab tab, String url, String title) { 443 mHasReceivedTitle = true; 444 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) { 452 if (!mHasReceivedTitle) { 453 TabViewData tvd = mTabMap.get(tab); 454 if (tvd != null) { 455 tvd.setUrlAndTitle(tvd.mUrl, null); 456 } 457 } 458 } 459 460 @Override 461 public void onPageStarted(Tab tab, String url, Bitmap favicon) { 462 mHasReceivedTitle = false; 463 TabViewData tvd = mTabMap.get(tab); 464 if (tvd != null) { 465 tvd.setFavicon(favicon); 466 tvd.setUrlAndTitle(url, mLoadingText); 467 } 468 } 469 470 471 private boolean isLoading() { 472 return mTabMap.get(mControl.getCurrentTab()).mTabView.mInLoad; 473 } 474 475} 476