summaryrefslogtreecommitdiffstats
path: root/src/com/android/swe/browser/TabBar.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/swe/browser/TabBar.java')
-rw-r--r--src/com/android/swe/browser/TabBar.java534
1 files changed, 534 insertions, 0 deletions
diff --git a/src/com/android/swe/browser/TabBar.java b/src/com/android/swe/browser/TabBar.java
new file mode 100644
index 00000000..cf82e015
--- /dev/null
+++ b/src/com/android/swe/browser/TabBar.java
@@ -0,0 +1,534 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.browser;
+
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Shader;
+import android.graphics.drawable.Drawable;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * tabbed title bar for xlarge screen browser
+ */
+public class TabBar extends LinearLayout implements OnClickListener {
+
+ private static final int PROGRESS_MAX = 100;
+
+ private Activity mActivity;
+ private UiController mUiController;
+ private TabControl mTabControl;
+ private XLargeUi mUi;
+
+ private int mTabWidth;
+
+ private TabScrollView mTabs;
+
+ private ImageButton mNewTab;
+ private int mButtonWidth;
+
+ private Map<Tab, TabView> mTabMap;
+
+ private int mCurrentTextureWidth = 0;
+ private int mCurrentTextureHeight = 0;
+
+ private Drawable mActiveDrawable;
+ private Drawable mInactiveDrawable;
+
+ private final Paint mActiveShaderPaint = new Paint();
+ private final Paint mInactiveShaderPaint = new Paint();
+ private final Paint mFocusPaint = new Paint();
+ private final Matrix mActiveMatrix = new Matrix();
+ private final Matrix mInactiveMatrix = new Matrix();
+
+ private BitmapShader mActiveShader;
+ private BitmapShader mInactiveShader;
+
+ private int mTabOverlap;
+ private int mAddTabOverlap;
+ private int mTabSliceWidth;
+ private boolean mUseQuickControls;
+
+ public TabBar(Activity activity, UiController controller, XLargeUi ui) {
+ super(activity);
+ mActivity = activity;
+ mUiController = controller;
+ mTabControl = mUiController.getTabControl();
+ mUi = ui;
+ Resources res = activity.getResources();
+ mTabWidth = (int) res.getDimension(R.dimen.tab_width);
+ mActiveDrawable = res.getDrawable(R.drawable.bg_urlbar);
+ mInactiveDrawable = res.getDrawable(R.drawable.browsertab_inactive);
+
+ mTabMap = new HashMap<Tab, TabView>();
+ LayoutInflater factory = LayoutInflater.from(activity);
+ factory.inflate(R.layout.tab_bar, this);
+ setPadding(0, (int) res.getDimension(R.dimen.tab_padding_top), 0, 0);
+ mTabs = (TabScrollView) findViewById(R.id.tabs);
+ mNewTab = (ImageButton) findViewById(R.id.newtab);
+ mNewTab.setOnClickListener(this);
+
+ updateTabs(mUiController.getTabs());
+ mButtonWidth = -1;
+ // tab dimensions
+ mTabOverlap = (int) res.getDimension(R.dimen.tab_overlap);
+ mAddTabOverlap = (int) res.getDimension(R.dimen.tab_addoverlap);
+ mTabSliceWidth = (int) res.getDimension(R.dimen.tab_slice);
+
+ mActiveShaderPaint.setStyle(Paint.Style.FILL);
+ mActiveShaderPaint.setAntiAlias(true);
+
+ mInactiveShaderPaint.setStyle(Paint.Style.FILL);
+ mInactiveShaderPaint.setAntiAlias(true);
+
+ mFocusPaint.setStyle(Paint.Style.STROKE);
+ mFocusPaint.setStrokeWidth(res.getDimension(R.dimen.tab_focus_stroke));
+ mFocusPaint.setAntiAlias(true);
+ mFocusPaint.setColor(res.getColor(R.color.tabFocusHighlight));
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration config) {
+ super.onConfigurationChanged(config);
+ Resources res = mActivity.getResources();
+ mTabWidth = (int) res.getDimension(R.dimen.tab_width);
+ // force update of tab bar
+ mTabs.updateLayout();
+ }
+
+ void setUseQuickControls(boolean useQuickControls) {
+ mUseQuickControls = useQuickControls;
+ mNewTab.setVisibility(mUseQuickControls ? View.GONE
+ : View.VISIBLE);
+ }
+
+ int getTabCount() {
+ return mTabMap.size();
+ }
+
+ void updateTabs(List<Tab> tabs) {
+ mTabs.clearTabs();
+ mTabMap.clear();
+ for (Tab tab : tabs) {
+ TabView tv = buildTabView(tab);
+ mTabs.addTab(tv);
+ }
+ mTabs.setSelectedTab(mTabControl.getCurrentPosition());
+ }
+
+ @Override
+ protected void onMeasure(int hspec, int vspec) {
+ super.onMeasure(hspec, vspec);
+ int w = getMeasuredWidth();
+ // adjust for new tab overlap
+ if (!mUseQuickControls) {
+ w -= mAddTabOverlap;
+ }
+ setMeasuredDimension(w, getMeasuredHeight());
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ // use paddingLeft and paddingTop
+ int pl = getPaddingLeft();
+ int pt = getPaddingTop();
+ int sw = mTabs.getMeasuredWidth();
+ int w = right - left - pl;
+ if (mUseQuickControls) {
+ mButtonWidth = 0;
+ } else {
+ mButtonWidth = mNewTab.getMeasuredWidth() - mAddTabOverlap;
+ if (w-sw < mButtonWidth) {
+ sw = w - mButtonWidth;
+ }
+ }
+ mTabs.layout(pl, pt, pl + sw, bottom - top);
+ // adjust for overlap
+ if (!mUseQuickControls) {
+ mNewTab.layout(pl + sw - mAddTabOverlap, pt,
+ pl + sw + mButtonWidth - mAddTabOverlap, bottom - top);
+ }
+ }
+
+ public void onClick(View view) {
+ if (mNewTab == view) {
+ mUiController.openTabToHomePage();
+ } else if (mTabs.getSelectedTab() == view) {
+ if (mUseQuickControls) {
+ if (mUi.isTitleBarShowing() && !isLoading()) {
+ mUi.stopEditingUrl();
+ mUi.hideTitleBar();
+ } else {
+ mUi.stopWebViewScrolling();
+ mUi.editUrl(false, false);
+ }
+ } else if (mUi.isTitleBarShowing() && !isLoading()) {
+ mUi.stopEditingUrl();
+ mUi.hideTitleBar();
+ } else {
+ showUrlBar();
+ }
+ } else if (view instanceof TabView) {
+ final Tab tab = ((TabView) view).mTab;
+ int ix = mTabs.getChildIndex(view);
+ if (ix >= 0) {
+ mTabs.setSelectedTab(ix);
+ mUiController.switchToTab(tab);
+ }
+ }
+ }
+
+ private void showUrlBar() {
+ mUi.stopWebViewScrolling();
+ mUi.showTitleBar();
+ }
+
+ private TabView buildTabView(Tab tab) {
+ TabView tabview = new TabView(mActivity, tab);
+ mTabMap.put(tab, tabview);
+ tabview.setOnClickListener(this);
+ return tabview;
+ }
+
+ private static Bitmap getDrawableAsBitmap(Drawable drawable, int width, int height) {
+ Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ Canvas c = new Canvas(b);
+ drawable.setBounds(0, 0, width, height);
+ drawable.draw(c);
+ c.setBitmap(null);
+ return b;
+ }
+
+ /**
+ * View used in the tab bar
+ */
+ class TabView extends LinearLayout implements OnClickListener {
+
+ Tab mTab;
+ View mTabContent;
+ TextView mTitle;
+ View mIncognito;
+ View mSnapshot;
+ ImageView mIconView;
+ ImageView mLock;
+ ImageView mClose;
+ boolean mSelected;
+ Path mPath;
+ Path mFocusPath;
+ int[] mWindowPos;
+
+ /**
+ * @param context
+ */
+ public TabView(Context context, Tab tab) {
+ super(context);
+ setWillNotDraw(false);
+ mPath = new Path();
+ mFocusPath = new Path();
+ mWindowPos = new int[2];
+ mTab = tab;
+ setGravity(Gravity.CENTER_VERTICAL);
+ setOrientation(LinearLayout.HORIZONTAL);
+ setPadding(mTabOverlap, 0, mTabSliceWidth, 0);
+ LayoutInflater inflater = LayoutInflater.from(getContext());
+ mTabContent = inflater.inflate(R.layout.tab_title, this, true);
+ mTitle = (TextView) mTabContent.findViewById(R.id.title);
+ mIconView = (ImageView) mTabContent.findViewById(R.id.favicon);
+ mLock = (ImageView) mTabContent.findViewById(R.id.lock);
+ mClose = (ImageView) mTabContent.findViewById(R.id.close);
+ mClose.setOnClickListener(this);
+ mIncognito = mTabContent.findViewById(R.id.incognito);
+ mSnapshot = mTabContent.findViewById(R.id.snapshot);
+ mSelected = false;
+ // update the status
+ updateFromTab();
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v == mClose) {
+ closeTab();
+ }
+ }
+
+ private void updateFromTab() {
+ String displayTitle = mTab.getTitle();
+ if (displayTitle == null) {
+ displayTitle = mTab.getUrl();
+ }
+ setDisplayTitle(displayTitle);
+ if (mTab.getFavicon() != null) {
+ setFavicon(mUi.getFaviconDrawable(mTab.getFavicon()));
+ }
+ updateTabIcons();
+ }
+
+ private void updateTabIcons() {
+ mIncognito.setVisibility(
+ mTab.isPrivateBrowsingEnabled() ?
+ View.VISIBLE : View.GONE);
+ mSnapshot.setVisibility(mTab.isSnapshot()
+ ? View.VISIBLE : View.GONE);
+ }
+
+ @Override
+ public void setActivated(boolean selected) {
+ mSelected = selected;
+ mClose.setVisibility(mSelected ? View.VISIBLE : View.GONE);
+ mIconView.setVisibility(mSelected ? View.GONE : View.VISIBLE);
+ mTitle.setTextAppearance(mActivity, mSelected ?
+ R.style.TabTitleSelected : R.style.TabTitleUnselected);
+ setHorizontalFadingEdgeEnabled(!mSelected);
+ super.setActivated(selected);
+ updateLayoutParams();
+ setFocusable(!selected);
+ postInvalidate();
+ }
+
+ public void updateLayoutParams() {
+ LayoutParams lp = (LinearLayout.LayoutParams) getLayoutParams();
+ lp.width = mTabWidth;
+ lp.height = LayoutParams.MATCH_PARENT;
+ setLayoutParams(lp);
+ }
+
+ void setDisplayTitle(String title) {
+ mTitle.setText(title);
+ }
+
+ void setFavicon(Drawable d) {
+ mIconView.setImageDrawable(d);
+ }
+
+ void setLock(Drawable d) {
+ if (null == d) {
+ mLock.setVisibility(View.GONE);
+ } else {
+ mLock.setImageDrawable(d);
+ mLock.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private void closeTab() {
+ if (mTab == mTabControl.getCurrentTab()) {
+ mUiController.closeCurrentTab();
+ } else {
+ mUiController.closeTab(mTab);
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ setTabPath(mPath, 0, 0, r - l, b - t);
+ setFocusPath(mFocusPath, 0, 0, r - l, b - t);
+ }
+
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ if (mCurrentTextureWidth != mUi.getContentWidth() ||
+ mCurrentTextureHeight != getHeight()) {
+ mCurrentTextureWidth = mUi.getContentWidth();
+ mCurrentTextureHeight = getHeight();
+
+ if (mCurrentTextureWidth > 0 && mCurrentTextureHeight > 0) {
+ Bitmap activeTexture = getDrawableAsBitmap(mActiveDrawable,
+ mCurrentTextureWidth, mCurrentTextureHeight);
+ Bitmap inactiveTexture = getDrawableAsBitmap(mInactiveDrawable,
+ mCurrentTextureWidth, mCurrentTextureHeight);
+
+ mActiveShader = new BitmapShader(activeTexture,
+ Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
+ mActiveShaderPaint.setShader(mActiveShader);
+
+ mInactiveShader = new BitmapShader(inactiveTexture,
+ Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
+ mInactiveShaderPaint.setShader(mInactiveShader);
+ }
+ }
+ // add some monkey protection
+ if ((mActiveShader != null) && (mInactiveShader != null)) {
+ int state = canvas.save();
+ getLocationInWindow(mWindowPos);
+ Paint paint = mSelected ? mActiveShaderPaint : mInactiveShaderPaint;
+ drawClipped(canvas, paint, mPath, mWindowPos[0]);
+ canvas.restoreToCount(state);
+ }
+ super.dispatchDraw(canvas);
+ }
+
+ private void drawClipped(Canvas canvas, Paint paint, Path clipPath, int left) {
+ // TODO: We should change the matrix/shader only when needed
+ final Matrix matrix = mSelected ? mActiveMatrix : mInactiveMatrix;
+ matrix.setTranslate(-left, 0.0f);
+ (mSelected ? mActiveShader : mInactiveShader).setLocalMatrix(matrix);
+ canvas.drawPath(clipPath, paint);
+ if (isFocused()) {
+ canvas.drawPath(mFocusPath, mFocusPaint);
+ }
+ }
+
+ private void setTabPath(Path path, int l, int t, int r, int b) {
+ path.reset();
+ path.moveTo(l, b);
+ path.lineTo(l, t);
+ path.lineTo(r - mTabSliceWidth, t);
+ path.lineTo(r, b);
+ path.close();
+ }
+
+ private void setFocusPath(Path path, int l, int t, int r, int b) {
+ path.reset();
+ path.moveTo(l, b);
+ path.lineTo(l, t);
+ path.lineTo(r - mTabSliceWidth, t);
+ path.lineTo(r, b);
+ }
+
+ }
+
+ private void animateTabOut(final Tab tab, final TabView tv) {
+ ObjectAnimator scalex = ObjectAnimator.ofFloat(tv, "scaleX", 1.0f, 0.0f);
+ ObjectAnimator scaley = ObjectAnimator.ofFloat(tv, "scaleY", 1.0f, 0.0f);
+ ObjectAnimator alpha = ObjectAnimator.ofFloat(tv, "alpha", 1.0f, 0.0f);
+ AnimatorSet animator = new AnimatorSet();
+ animator.playTogether(scalex, scaley, alpha);
+ animator.setDuration(150);
+ animator.addListener(new AnimatorListener() {
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mTabs.removeTab(tv);
+ mTabMap.remove(tab);
+ mUi.onRemoveTabCompleted(tab);
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ }
+
+ });
+ animator.start();
+ }
+
+ private void animateTabIn(final Tab tab, final TabView tv) {
+ ObjectAnimator scalex = ObjectAnimator.ofFloat(tv, "scaleX", 0.0f, 1.0f);
+ scalex.setDuration(150);
+ scalex.addListener(new AnimatorListener() {
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mUi.onAddTabCompleted(tab);
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mTabs.addTab(tv);
+ }
+
+ });
+ scalex.start();
+ }
+
+ // TabChangeListener implementation
+
+ public void onSetActiveTab(Tab tab) {
+ mTabs.setSelectedTab(mTabControl.getTabPosition(tab));
+ }
+
+ public void onFavicon(Tab tab, Bitmap favicon) {
+ TabView tv = mTabMap.get(tab);
+ if (tv != null) {
+ tv.setFavicon(mUi.getFaviconDrawable(favicon));
+ }
+ }
+
+ public void onNewTab(Tab tab) {
+ TabView tv = buildTabView(tab);
+ animateTabIn(tab, tv);
+ }
+
+ public void onRemoveTab(Tab tab) {
+ TabView tv = mTabMap.get(tab);
+ if (tv != null) {
+ animateTabOut(tab, tv);
+ } else {
+ mTabMap.remove(tab);
+ }
+ }
+
+ public void onUrlAndTitle(Tab tab, String url, String title) {
+ TabView tv = mTabMap.get(tab);
+ if (tv != null) {
+ if (title != null) {
+ tv.setDisplayTitle(title);
+ } else if (url != null) {
+ tv.setDisplayTitle(UrlUtils.stripUrl(url));
+ }
+ tv.updateTabIcons();
+ }
+ }
+
+ private boolean isLoading() {
+ Tab tab = mTabControl.getCurrentTab();
+ if (tab != null) {
+ return tab.inPageLoad();
+ } else {
+ return false;
+ }
+ }
+
+}