TabBar.java revision a2b2ba8da913f26c820e49d3e43158e2fe6ebeba
1a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb/*
2a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb * Copyright (C) 2010 The Android Open Source Project
3a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb *
4a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb * Licensed under the Apache License, Version 2.0 (the "License");
5a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb * you may not use this file except in compliance with the License.
6a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb * You may obtain a copy of the License at
7a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb *
8a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb *      http://www.apache.org/licenses/LICENSE-2.0
9a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb *
10a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb * Unless required by applicable law or agreed to in writing, software
11a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb * distributed under the License is distributed on an "AS IS" BASIS,
12a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb * See the License for the specific language governing permissions and
14a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb * limitations under the License.
15a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb */
16a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
17a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolbpackage com.android.browser;
18a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
19a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolbimport android.content.Context;
20a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolbimport android.content.res.Resources;
21a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolbimport android.graphics.Bitmap;
22a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolbimport android.graphics.Color;
23a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolbimport android.graphics.drawable.BitmapDrawable;
24a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolbimport android.graphics.drawable.Drawable;
25a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolbimport android.graphics.drawable.LayerDrawable;
26a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolbimport android.graphics.drawable.PaintDrawable;
27a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolbimport android.view.ContextMenu;
28a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolbimport android.view.LayoutInflater;
29a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolbimport android.view.MenuInflater;
30a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolbimport android.view.View;
31a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolbimport android.view.View.OnClickListener;
32a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolbimport android.webkit.WebView;
33a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolbimport android.widget.ImageView;
34a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolbimport android.widget.LinearLayout;
35a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolbimport android.widget.TextView;
36a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
37a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolbimport com.android.browser.ScrollWebView.ScrollListener;
38a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolbimport com.android.browser.TabControl.TabChangeListener;
39a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
40a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolbimport java.util.HashMap;
41a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolbimport java.util.Map;
42a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
43a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb/**
44a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb * tabbed title bar for xlarge screen browser
45a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb */
46a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolbpublic class TabBar extends LinearLayout
47a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        implements TabChangeListener, ScrollListener, OnClickListener {
48a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
49a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    private static final int PROGRESS_MAX = 100;
50a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
51a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    private static final int TAB_WIDTH_SELECTED = 300;
52a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    private static final int TAB_WIDTH_UNSELECTED = 300;
53a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
54a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    private BrowserActivity mBrowserActivity;
55a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
56a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    private final float mTabWidthSelected;
57a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    private final float mTabWidthUnselected;
58a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
59a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    private TitleBarXLarge mTitleBar;
60a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
61a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    private TabScrollView mTabs;
62a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    private View mNewButton;
63a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    private View mShowUrlButton;
64a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    private TabControl mControl;
65a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
66a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    private Map<Tab, TabViewData> mTabMap;
67a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
68a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    private float mDensityScale;
69a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    private boolean mUserRequestedUrlbar;
70a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    private boolean mTitleVisible;
71a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
72a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    public TabBar(BrowserActivity context, TabControl tabcontrol, TitleBarXLarge titlebar) {
73a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        super(context);
74a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        Resources res = context.getResources();
75a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mTabWidthSelected = res.getDimension(R.dimen.tab_width_selected);
76a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mTabWidthUnselected = res.getDimension(R.dimen.tab_width_unselected);
77a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
78a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mTitleBar = titlebar;
79a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mTitleBar.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
80a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                LayoutParams.WRAP_CONTENT));
81a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mDensityScale = context.getResources().getDisplayMetrics().density;
82a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mTabMap = new HashMap<Tab, TabViewData>();
83a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mBrowserActivity = context;
84a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mControl = tabcontrol;
85a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        Resources resources = context.getResources();
86a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        LayoutInflater factory = LayoutInflater.from(context);
87a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        factory.inflate(R.layout.tab_bar, this);
88a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mTabs = (TabScrollView) findViewById(R.id.tabs);
89a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mNewButton = findViewById(R.id.newtab);
90a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mShowUrlButton = findViewById(R.id.showurl);
91a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
92a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        // TODO: Change enabled states based on whether you can go
93a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        // back/forward.  Probably should be done inside onPageStarted.
94a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
95a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mNewButton.setOnClickListener(this);
96a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mShowUrlButton.setOnClickListener(this);
97a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
98a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        // build tabs
99a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        int tabcount = mControl.getTabCount();
100a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        for (int i = 0; i < tabcount; i++) {
101a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            Tab tab = mControl.getTab(i);
102a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            TabViewData data = buildTab(tab);
103a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            TabView tv = buildView(data);
104a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        }
105a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mTabs.setSelectedTab(mControl.getCurrentIndex());
106a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
107a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        // register the tab change listener
108a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mControl.setOnTabChangeListener(this);
109a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mUserRequestedUrlbar = false;
110a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mTitleVisible = true;
111a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    }
112a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
113a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    public void onClick(View view) {
114a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        if (mShowUrlButton == view) {
115a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mBrowserActivity.stopScrolling();
116a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mBrowserActivity.showFakeTitleBar();
117a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mUserRequestedUrlbar = true;
118a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        } else if (mNewButton == view) {
119a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mBrowserActivity.openTabToHomePage();
120a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        } else if (mTabs.getSelectedTab() == view) {
121a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mBrowserActivity.showFakeTitleBar();
122a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mTitleBar.requestUrlInputFocus();
123a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        } else {
124a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            TabViewData data = (TabViewData) view.getTag();
125a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            int ix = mControl.getTabIndex(data.mTab);
126a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mTabs.setSelectedTab(ix);
127a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mBrowserActivity.switchToTab(ix);
128a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        }
129a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    }
130a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
131a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    void onShowTitleBar() {
132a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mShowUrlButton.setVisibility(View.INVISIBLE);
133a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    }
134a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
135a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    void onHideTitleBar() {
136a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mShowUrlButton.setVisibility(mTitleVisible ? View.INVISIBLE : View.VISIBLE);
137a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        Tab tab = mControl.getCurrentTab();
138a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        tab.getWebView().requestFocus();
139a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mUserRequestedUrlbar = false;
140a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    }
141a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
142a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    // UrlInputListener implementation
143a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
144a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    @Override
145a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    public void createContextMenu(ContextMenu menu) {
146a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        MenuInflater inflater = mBrowserActivity.getMenuInflater();
147a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        inflater.inflate(R.menu.title_context, menu);
148a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mBrowserActivity.onCreateContextMenu(menu, this, null);
149a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    }
150a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
151a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    private TabViewData buildTab(Tab tab) {
152a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        TabViewData data = new TabViewData(tab);
153a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mTabMap.put(tab, data);
154a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        return data;
155a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    }
156a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
157a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    private TabView buildView(final TabViewData data) {
158a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        TabView tv = new TabView(mBrowserActivity, data);
159a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        tv.setTag(data);
160a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        tv.setOnClickListener(this);
161a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mTabs.addTab(tv);
162a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        return tv;
163a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    }
164a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
165a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    /**
166a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb     * View used in the tab bar
167a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb     */
168a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    class TabView extends LinearLayout implements OnClickListener {
169a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
170a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        TabViewData mTabData;
171a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        View mTabContent;
172a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        TextView mTitle;
173a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        ImageView mIconView;
174a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        ImageView mLock;
175a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        ImageView mClose;
176a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        boolean mSelected;
177a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        boolean mInLoad;
178a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
179a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        /**
180a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb         * @param context
181a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb         */
182a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        public TabView(Context context, TabViewData tab) {
183a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            super(context);
184a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mTabData = tab;
185a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            LayoutInflater inflater = LayoutInflater.from(mContext);
186a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mTabContent = inflater.inflate(R.layout.tab_title, this);
187a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mTitle = (TextView) mTabContent.findViewById(R.id.title);
188a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mIconView = (ImageView) mTabContent.findViewById(R.id.favicon);
189a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mLock = (ImageView) mTabContent.findViewById(R.id.lock);
190a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mClose = (ImageView) mTabContent.findViewById(R.id.close);
191a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mClose.setOnClickListener(this);
192a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mSelected = false;
193a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mInLoad = false;
194a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            // update the status
195a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            updateFromData();
196a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        }
197a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
198a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        @Override
199a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        public void onClick(View v) {
200a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            if (v == mClose) {
201a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                closeTab();
202a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            }
203a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        }
204a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
205a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        private void updateFromData() {
206a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mTabData.mTabView = this;
207a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            if (mTabData.mUrl != null) {
208a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                setDisplayTitle(mTabData.mUrl);
209a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            }
210a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            if (mTabData.mTitle != null) {
211a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                setDisplayTitle(mTabData.mTitle);
212a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            }
213a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            setProgress(mTabData.mProgress);
214a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            if (mTabData.mIcon != null) {
215a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                setFavicon(mTabData.mIcon);
216a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            }
217a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            if (mTabData.mLock != null) {
218a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                setLock(mTabData.mLock);
219a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            }
220a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        }
221a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
222a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        @Override
223a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        public void setSelected(boolean selected) {
224a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mSelected = selected;
225a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mClose.setVisibility(mSelected ? View.VISIBLE : View.GONE);
226a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mTitle.setTextColor(mSelected ? Color.BLACK : Color.GRAY);
227a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            super.setSelected(selected);
228a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            setLayoutParams(new LayoutParams(selected ?
229a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                    (int) (TAB_WIDTH_SELECTED * mDensityScale)
230a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                    : (int) (TAB_WIDTH_UNSELECTED * mDensityScale),
231a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                    LayoutParams.MATCH_PARENT));
232a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        }
233a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
234a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        void setDisplayTitle(String title) {
235a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mTitle.setText(title);
236a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        }
237a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
238a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        void setFavicon(Drawable d) {
239a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mIconView.setImageDrawable(d);
240a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        }
241a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
242a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        void setLock(Drawable d) {
243a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            if (null == d) {
244a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                mLock.setVisibility(View.GONE);
245a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            } else {
246a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                mLock.setImageDrawable(d);
247a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                mLock.setVisibility(View.VISIBLE);
248a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            }
249a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        }
250a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
251a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        void setTitleCompoundDrawables(Drawable left, Drawable top,
252a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                Drawable right, Drawable bottom) {
253a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mTitle.setCompoundDrawables(left, top, right, bottom);
254a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        }
255a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
256a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        void setProgress(int newProgress) {
257a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            if (newProgress >= PROGRESS_MAX) {
258a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                mInLoad = false;
259a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            } else {
260a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                if (!mInLoad && getWindowToken() != null) {
261a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                    mInLoad = true;
262a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                }
263a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            }
264a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        }
265a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
266a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        private void closeTab() {
267a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            if (mTabData.mTab == mControl.getCurrentTab()) {
268a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                mBrowserActivity.closeCurrentWindow();
269a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            } else {
270a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                mBrowserActivity.closeTab(mTabData.mTab);
271a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            }
272a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        }
273a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
274a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    }
275a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
276a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    /**
277a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb     * Store tab state within the title bar
278a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb     */
279a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    class TabViewData {
280a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
281a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        Tab mTab;
282a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        TabView mTabView;
283a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        int mProgress;
284a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        Drawable mIcon;
285a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        Drawable mLock;
286a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        String mTitle;
287a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        String mUrl;
288a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
289a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        TabViewData(Tab tab) {
290a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mTab = tab;
291a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        }
292a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
293a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        void setUrlAndTitle(String url, String title) {
294a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mUrl = url;
295a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mTitle = title;
296a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            if (mTabView != null) {
297a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                if (title != null) {
298a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                    mTabView.setDisplayTitle(title);
299a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                } else if (url != null) {
300a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                    mTabView.setDisplayTitle(url);
301a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                }
302a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            }
303a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        }
304a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
305a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        void setProgress(int newProgress) {
306a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mProgress = newProgress;
307a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            if (mTabView != null) {
308a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                mTabView.setProgress(mProgress);
309a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            }
310a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        }
311a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
312a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        void setFavicon(Bitmap icon) {
313a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            Drawable[] array = new Drawable[3];
314a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            array[0] = new PaintDrawable(Color.BLACK);
315a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            array[1] = new PaintDrawable(Color.WHITE);
316a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            if (icon == null) {
317a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb//                array[2] = mGenericFavicon;
318a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            } else {
319a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                array[2] = new BitmapDrawable(icon);
320a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            }
321a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            LayerDrawable d = new LayerDrawable(array);
322a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            d.setLayerInset(1, 1, 1, 1, 1);
323a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            d.setLayerInset(2, 2, 2, 2, 2);
324a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mIcon = d;
325a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            if (mTabView != null) {
326a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                mTabView.setFavicon(mIcon);
327a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            }
328a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        }
329a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
330a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    }
331a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
332a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    // TabChangeListener implementation
333a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
334a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    @Override
335a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    public void onCurrentTab(Tab tab) {
336a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mTabs.setSelectedTab(mControl.getCurrentIndex());
337a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        TabViewData tvd = mTabMap.get(tab);
338a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        if (tvd != null) {
339a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            tvd.setProgress(tvd.mProgress);
340a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            // update the scroll state
341a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            WebView webview = tab.getWebView();
342a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            onScroll(webview.getVisibleTitleHeight() > 0);
343a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        }
344a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    }
345a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
346a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    @Override
347a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    public void onFavicon(Tab tab, Bitmap favicon) {
348a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        TabViewData tvd = mTabMap.get(tab);
349a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        if (tvd != null) {
350a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            tvd.setFavicon(favicon);
351a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        }
352a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    }
353a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
354a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    @Override
355a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    public void onNewTab(Tab tab) {
356a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        TabViewData tvd = buildTab(tab);
357a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        buildView(tvd);
358a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mShowUrlButton.setVisibility(View.INVISIBLE);
359a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    }
360a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
361a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    @Override
362a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    public void onProgress(Tab tab, int progress) {
363a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        TabViewData tvd = mTabMap.get(tab);
364a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        if (tvd != null) {
365a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            tvd.setProgress(progress);
366a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        }
367a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    }
368a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
369a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    @Override
370a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    public void onRemoveTab(Tab tab) {
371a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        TabViewData tvd = mTabMap.get(tab);
372a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        TabView tv = tvd.mTabView;
373a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        if (tv != null) {
374a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mTabs.removeTab(tv);
375a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        }
376a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mTabMap.remove(tab);
377a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    }
378a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
379a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    @Override
380a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    public void onUrlAndTitle(Tab tab, String url, String title) {
381a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        TabViewData tvd = mTabMap.get(tab);
382a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        if (tvd != null) {
383a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            tvd.setUrlAndTitle(url, title);
384a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        }
385a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    }
386a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
387a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    @Override
388a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    public void onPageFinished(Tab tab) {
389a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    }
390a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
391a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    @Override
392a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    public void onPageStarted(Tab tab) {
393a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    }
394a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
395a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
396a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    private boolean isLoading() {
397a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        return mTabMap.get(mControl.getCurrentTab()).mTabView.mInLoad;
398a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    }
399a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
400a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    // webview scroll listener
401a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
402a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    @Override
403a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    public void onScroll(boolean titleVisible) {
404a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        mTitleVisible = titleVisible;
405a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        boolean buttonVisible = (mShowUrlButton.getVisibility() == View.VISIBLE);
406a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        if (!buttonVisible && !mTitleVisible && !isLoading()) {
407a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mShowUrlButton.setVisibility(View.VISIBLE);
408a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            if (mUserRequestedUrlbar) {
409a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb                mBrowserActivity.hideFakeTitleBar();
410a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            }
411a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        } else if (mTitleVisible && !isLoading()) {
412a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb            mShowUrlButton.setVisibility(View.INVISIBLE);
413a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb        }
414a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb    }
415a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb
416a2b2ba8da913f26c820e49d3e43158e2fe6ebebaMichael Kolb}
417