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