UI revision for tabbed browsing
     bug # http://b/issue?id=2712871

     separated tab bar from url bar
     subclassed webview for scroll listener
     added search button support

Change-Id: Ib9bd0c7e815e2ef08cdd20334daf61263cd52938
diff --git a/src/com/android/browser/TabBar.java b/src/com/android/browser/TabBar.java
new file mode 100644
index 0000000..f73185f
--- /dev/null
+++ b/src/com/android/browser/TabBar.java
@@ -0,0 +1,416 @@
+/*
+ * 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.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.graphics.drawable.PaintDrawable;
+import android.view.ContextMenu;
+import android.view.LayoutInflater;
+import android.view.MenuInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.webkit.WebView;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.browser.ScrollWebView.ScrollListener;
+import com.android.browser.TabControl.TabChangeListener;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * tabbed title bar for xlarge screen browser
+ */
+public class TabBar extends LinearLayout
+        implements TabChangeListener, ScrollListener, OnClickListener {
+
+    private static final int PROGRESS_MAX = 100;
+
+    private static final int TAB_WIDTH_SELECTED = 300;
+    private static final int TAB_WIDTH_UNSELECTED = 300;
+
+    private BrowserActivity mBrowserActivity;
+
+    private final float mTabWidthSelected;
+    private final float mTabWidthUnselected;
+
+    private TitleBarXLarge mTitleBar;
+
+    private TabScrollView mTabs;
+    private View mNewButton;
+    private View mShowUrlButton;
+    private TabControl mControl;
+
+    private Map<Tab, TabViewData> mTabMap;
+
+    private float mDensityScale;
+    private boolean mUserRequestedUrlbar;
+    private boolean mTitleVisible;
+
+    public TabBar(BrowserActivity context, TabControl tabcontrol, TitleBarXLarge titlebar) {
+        super(context);
+        Resources res = context.getResources();
+        mTabWidthSelected = res.getDimension(R.dimen.tab_width_selected);
+        mTabWidthUnselected = res.getDimension(R.dimen.tab_width_unselected);
+
+        mTitleBar = titlebar;
+        mTitleBar.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
+                LayoutParams.WRAP_CONTENT));
+        mDensityScale = context.getResources().getDisplayMetrics().density;
+        mTabMap = new HashMap<Tab, TabViewData>();
+        mBrowserActivity = context;
+        mControl = tabcontrol;
+        Resources resources = context.getResources();
+        LayoutInflater factory = LayoutInflater.from(context);
+        factory.inflate(R.layout.tab_bar, this);
+        mTabs = (TabScrollView) findViewById(R.id.tabs);
+        mNewButton = findViewById(R.id.newtab);
+        mShowUrlButton = findViewById(R.id.showurl);
+
+        // TODO: Change enabled states based on whether you can go
+        // back/forward.  Probably should be done inside onPageStarted.
+
+        mNewButton.setOnClickListener(this);
+        mShowUrlButton.setOnClickListener(this);
+
+        // build tabs
+        int tabcount = mControl.getTabCount();
+        for (int i = 0; i < tabcount; i++) {
+            Tab tab = mControl.getTab(i);
+            TabViewData data = buildTab(tab);
+            TabView tv = buildView(data);
+        }
+        mTabs.setSelectedTab(mControl.getCurrentIndex());
+
+        // register the tab change listener
+        mControl.setOnTabChangeListener(this);
+        mUserRequestedUrlbar = false;
+        mTitleVisible = true;
+    }
+
+    public void onClick(View view) {
+        if (mShowUrlButton == view) {
+            mBrowserActivity.stopScrolling();
+            mBrowserActivity.showFakeTitleBar();
+            mUserRequestedUrlbar = true;
+        } else if (mNewButton == view) {
+            mBrowserActivity.openTabToHomePage();
+        } else if (mTabs.getSelectedTab() == view) {
+            mBrowserActivity.showFakeTitleBar();
+            mTitleBar.requestUrlInputFocus();
+        } else {
+            TabViewData data = (TabViewData) view.getTag();
+            int ix = mControl.getTabIndex(data.mTab);
+            mTabs.setSelectedTab(ix);
+            mBrowserActivity.switchToTab(ix);
+        }
+    }
+
+    void onShowTitleBar() {
+        mShowUrlButton.setVisibility(View.INVISIBLE);
+    }
+
+    void onHideTitleBar() {
+        mShowUrlButton.setVisibility(mTitleVisible ? View.INVISIBLE : View.VISIBLE);
+        Tab tab = mControl.getCurrentTab();
+        tab.getWebView().requestFocus();
+        mUserRequestedUrlbar = false;
+    }
+
+    // UrlInputListener implementation
+
+    @Override
+    public void createContextMenu(ContextMenu menu) {
+        MenuInflater inflater = mBrowserActivity.getMenuInflater();
+        inflater.inflate(R.menu.title_context, menu);
+        mBrowserActivity.onCreateContextMenu(menu, this, null);
+    }
+
+    private TabViewData buildTab(Tab tab) {
+        TabViewData data = new TabViewData(tab);
+        mTabMap.put(tab, data);
+        return data;
+    }
+
+    private TabView buildView(final TabViewData data) {
+        TabView tv = new TabView(mBrowserActivity, data);
+        tv.setTag(data);
+        tv.setOnClickListener(this);
+        mTabs.addTab(tv);
+        return tv;
+    }
+
+    /**
+     * View used in the tab bar
+     */
+    class TabView extends LinearLayout implements OnClickListener {
+
+        TabViewData mTabData;
+        View mTabContent;
+        TextView mTitle;
+        ImageView mIconView;
+        ImageView mLock;
+        ImageView mClose;
+        boolean mSelected;
+        boolean mInLoad;
+
+        /**
+         * @param context
+         */
+        public TabView(Context context, TabViewData tab) {
+            super(context);
+            mTabData = tab;
+            LayoutInflater inflater = LayoutInflater.from(mContext);
+            mTabContent = inflater.inflate(R.layout.tab_title, this);
+            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);
+            mSelected = false;
+            mInLoad = false;
+            // update the status
+            updateFromData();
+        }
+
+        @Override
+        public void onClick(View v) {
+            if (v == mClose) {
+                closeTab();
+            }
+        }
+
+        private void updateFromData() {
+            mTabData.mTabView = this;
+            if (mTabData.mUrl != null) {
+                setDisplayTitle(mTabData.mUrl);
+            }
+            if (mTabData.mTitle != null) {
+                setDisplayTitle(mTabData.mTitle);
+            }
+            setProgress(mTabData.mProgress);
+            if (mTabData.mIcon != null) {
+                setFavicon(mTabData.mIcon);
+            }
+            if (mTabData.mLock != null) {
+                setLock(mTabData.mLock);
+            }
+        }
+
+        @Override
+        public void setSelected(boolean selected) {
+            mSelected = selected;
+            mClose.setVisibility(mSelected ? View.VISIBLE : View.GONE);
+            mTitle.setTextColor(mSelected ? Color.BLACK : Color.GRAY);
+            super.setSelected(selected);
+            setLayoutParams(new LayoutParams(selected ?
+                    (int) (TAB_WIDTH_SELECTED * mDensityScale)
+                    : (int) (TAB_WIDTH_UNSELECTED * mDensityScale),
+                    LayoutParams.MATCH_PARENT));
+        }
+
+        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);
+            }
+        }
+
+        void setTitleCompoundDrawables(Drawable left, Drawable top,
+                Drawable right, Drawable bottom) {
+            mTitle.setCompoundDrawables(left, top, right, bottom);
+        }
+
+        void setProgress(int newProgress) {
+            if (newProgress >= PROGRESS_MAX) {
+                mInLoad = false;
+            } else {
+                if (!mInLoad && getWindowToken() != null) {
+                    mInLoad = true;
+                }
+            }
+        }
+
+        private void closeTab() {
+            if (mTabData.mTab == mControl.getCurrentTab()) {
+                mBrowserActivity.closeCurrentWindow();
+            } else {
+                mBrowserActivity.closeTab(mTabData.mTab);
+            }
+        }
+
+    }
+
+    /**
+     * Store tab state within the title bar
+     */
+    class TabViewData {
+
+        Tab mTab;
+        TabView mTabView;
+        int mProgress;
+        Drawable mIcon;
+        Drawable mLock;
+        String mTitle;
+        String mUrl;
+
+        TabViewData(Tab tab) {
+            mTab = tab;
+        }
+
+        void setUrlAndTitle(String url, String title) {
+            mUrl = url;
+            mTitle = title;
+            if (mTabView != null) {
+                if (title != null) {
+                    mTabView.setDisplayTitle(title);
+                } else if (url != null) {
+                    mTabView.setDisplayTitle(url);
+                }
+            }
+        }
+
+        void setProgress(int newProgress) {
+            mProgress = newProgress;
+            if (mTabView != null) {
+                mTabView.setProgress(mProgress);
+            }
+        }
+
+        void setFavicon(Bitmap icon) {
+            Drawable[] array = new Drawable[3];
+            array[0] = new PaintDrawable(Color.BLACK);
+            array[1] = new PaintDrawable(Color.WHITE);
+            if (icon == null) {
+//                array[2] = mGenericFavicon;
+            } else {
+                array[2] = new BitmapDrawable(icon);
+            }
+            LayerDrawable d = new LayerDrawable(array);
+            d.setLayerInset(1, 1, 1, 1, 1);
+            d.setLayerInset(2, 2, 2, 2, 2);
+            mIcon = d;
+            if (mTabView != null) {
+                mTabView.setFavicon(mIcon);
+            }
+        }
+
+    }
+
+    // TabChangeListener implementation
+
+    @Override
+    public void onCurrentTab(Tab tab) {
+        mTabs.setSelectedTab(mControl.getCurrentIndex());
+        TabViewData tvd = mTabMap.get(tab);
+        if (tvd != null) {
+            tvd.setProgress(tvd.mProgress);
+            // update the scroll state
+            WebView webview = tab.getWebView();
+            onScroll(webview.getVisibleTitleHeight() > 0);
+        }
+    }
+
+    @Override
+    public void onFavicon(Tab tab, Bitmap favicon) {
+        TabViewData tvd = mTabMap.get(tab);
+        if (tvd != null) {
+            tvd.setFavicon(favicon);
+        }
+    }
+
+    @Override
+    public void onNewTab(Tab tab) {
+        TabViewData tvd = buildTab(tab);
+        buildView(tvd);
+        mShowUrlButton.setVisibility(View.INVISIBLE);
+    }
+
+    @Override
+    public void onProgress(Tab tab, int progress) {
+        TabViewData tvd = mTabMap.get(tab);
+        if (tvd != null) {
+            tvd.setProgress(progress);
+        }
+    }
+
+    @Override
+    public void onRemoveTab(Tab tab) {
+        TabViewData tvd = mTabMap.get(tab);
+        TabView tv = tvd.mTabView;
+        if (tv != null) {
+            mTabs.removeTab(tv);
+        }
+        mTabMap.remove(tab);
+    }
+
+    @Override
+    public void onUrlAndTitle(Tab tab, String url, String title) {
+        TabViewData tvd = mTabMap.get(tab);
+        if (tvd != null) {
+            tvd.setUrlAndTitle(url, title);
+        }
+    }
+
+    @Override
+    public void onPageFinished(Tab tab) {
+    }
+
+    @Override
+    public void onPageStarted(Tab tab) {
+    }
+
+
+    private boolean isLoading() {
+        return mTabMap.get(mControl.getCurrentTab()).mTabView.mInLoad;
+    }
+
+    // webview scroll listener
+
+    @Override
+    public void onScroll(boolean titleVisible) {
+        mTitleVisible = titleVisible;
+        boolean buttonVisible = (mShowUrlButton.getVisibility() == View.VISIBLE);
+        if (!buttonVisible && !mTitleVisible && !isLoading()) {
+            mShowUrlButton.setVisibility(View.VISIBLE);
+            if (mUserRequestedUrlbar) {
+                mBrowserActivity.hideFakeTitleBar();
+            }
+        } else if (mTitleVisible && !isLoading()) {
+            mShowUrlButton.setVisibility(View.INVISIBLE);
+        }
+    }
+
+}