10f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck/*
20f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck * Copyright (C) 2010 The Android Open Source Project
30f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck *
40f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck * Licensed under the Apache License, Version 2.0 (the "License");
50f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck * you may not use this file except in compliance with the License.
60f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck * You may obtain a copy of the License at
70f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck *
80f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck *      http://www.apache.org/licenses/LICENSE-2.0
90f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck *
100f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck * Unless required by applicable law or agreed to in writing, software
110f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck * distributed under the License is distributed on an "AS IS" BASIS,
120f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck * See the License for the specific language governing permissions and
140f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck * limitations under the License.
150f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck */
160f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
170f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reckpackage com.android.browser;
180f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
190f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reckimport android.animation.Animator;
200f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reckimport android.animation.Animator.AnimatorListener;
210f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reckimport android.animation.ObjectAnimator;
220f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reckimport android.content.Context;
2357059a8360e3b9872f4f6cbdaa8b5af4ac1c901dMichael Kolbimport android.content.res.Configuration;
240f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reckimport android.content.res.Resources;
250f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reckimport android.view.LayoutInflater;
260f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reckimport android.view.View;
270f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reckimport android.view.ViewGroup;
28d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdochimport android.view.ViewStub;
291cc1d1d08c50211e4f9f8407978d0435a0110375John Reckimport android.view.accessibility.AccessibilityManager;
300f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reckimport android.view.animation.Animation;
310f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reckimport android.view.animation.Animation.AnimationListener;
320f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reckimport android.view.animation.AnimationUtils;
330f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reckimport android.view.animation.DecelerateInterpolator;
340f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reckimport android.webkit.WebView;
350f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reckimport android.widget.FrameLayout;
360f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reckimport android.widget.RelativeLayout;
370f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
380f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
390f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck/**
400f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck * Base class for a title bar used by the browser.
410f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck */
420f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reckpublic class TitleBar extends RelativeLayout {
430f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
440f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    private static final int PROGRESS_MAX = 100;
450f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    private static final float ANIM_TITLEBAR_DECELERATE = 2.5f;
460f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
470f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    private UiController mUiController;
480f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    private BaseUi mBaseUi;
492711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck    private FrameLayout mContentView;
500f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    private PageProgressView mProgress;
511cc1d1d08c50211e4f9f8407978d0435a0110375John Reck    private AccessibilityManager mAccessibilityManager;
520f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
530f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    private AutologinBar mAutoLogin;
540f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    private NavigationBarBase mNavBar;
550f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    private boolean mUseQuickControls;
56ef654f1dd80f55609060005342fc4f2cde62990cJohn Reck    private SnapshotBar mSnapshotBar;
570f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
580f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    //state
590f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    private boolean mShowing;
600f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    private boolean mInLoad;
610f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    private boolean mSkipTitleBarAnimations;
620f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    private Animator mTitleBarAnimator;
632711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck    private boolean mIsFixedTitleBar;
640f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
650f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    public TitleBar(Context context, UiController controller, BaseUi ui,
662711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck            FrameLayout contentView) {
670f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        super(context, null);
680f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        mUiController = controller;
690f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        mBaseUi = ui;
702711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck        mContentView = contentView;
711cc1d1d08c50211e4f9f8407978d0435a0110375John Reck        mAccessibilityManager = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
720f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        initLayout(context);
730f9aaebdf2b1fbf230cf497598c684d7cff66653John Reck        setFixedTitleBar();
740f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
750f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
760f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    private void initLayout(Context context) {
770f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        LayoutInflater factory = LayoutInflater.from(context);
780f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        factory.inflate(R.layout.title_bar, this);
790f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        mProgress = (PageProgressView) findViewById(R.id.progress);
800f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        mNavBar = (NavigationBarBase) findViewById(R.id.taburlbar);
810f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        mNavBar.setTitleBar(this);
82d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch    }
83d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch
84d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch    private void inflateAutoLoginBar() {
85d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch        if (mAutoLogin != null) {
86d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch            return;
87d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch        }
88d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch
89d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch        ViewStub stub = (ViewStub) findViewById(R.id.autologin_stub);
90d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch        mAutoLogin = (AutologinBar) stub.inflate();
91d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch        mAutoLogin.setTitleBar(this);
92d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch    }
93d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch
94d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch    private void inflateSnapshotBar() {
95d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch        if (mSnapshotBar != null) {
96d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch            return;
97d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch        }
98d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch
99d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch        ViewStub stub = (ViewStub) findViewById(R.id.snapshotbar_stub);
100d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch        mSnapshotBar = (SnapshotBar) stub.inflate();
101ef654f1dd80f55609060005342fc4f2cde62990cJohn Reck        mSnapshotBar.setTitleBar(this);
1020f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
1030f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
10457059a8360e3b9872f4f6cbdaa8b5af4ac1c901dMichael Kolb    @Override
10557059a8360e3b9872f4f6cbdaa8b5af4ac1c901dMichael Kolb    protected void onConfigurationChanged(Configuration config) {
10657059a8360e3b9872f4f6cbdaa8b5af4ac1c901dMichael Kolb        super.onConfigurationChanged(config);
1070f9aaebdf2b1fbf230cf497598c684d7cff66653John Reck        setFixedTitleBar();
1082711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck    }
1092711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck
1102711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck    @Override
1112711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
1122711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
1132711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck        if (mIsFixedTitleBar) {
1142711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck            int margin = getMeasuredHeight() - calculateEmbeddedHeight();
1152711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck            mBaseUi.setContentViewMarginTop(-margin);
1160f9aaebdf2b1fbf230cf497598c684d7cff66653John Reck        } else {
1170f9aaebdf2b1fbf230cf497598c684d7cff66653John Reck            mBaseUi.setContentViewMarginTop(0);
1182711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck        }
1192711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck    }
1202711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck
1210f9aaebdf2b1fbf230cf497598c684d7cff66653John Reck    private void setFixedTitleBar() {
1220f9aaebdf2b1fbf230cf497598c684d7cff66653John Reck        boolean isFixed = !mUseQuickControls
1230f9aaebdf2b1fbf230cf497598c684d7cff66653John Reck                && !mContext.getResources().getBoolean(R.bool.hide_title);
1241cc1d1d08c50211e4f9f8407978d0435a0110375John Reck        isFixed |= mAccessibilityManager.isEnabled();
1252711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck        // If getParent() returns null, we are initializing
1262711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck        ViewGroup parent = (ViewGroup)getParent();
1272711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck        if (mIsFixedTitleBar == isFixed && parent != null) return;
1282711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck        mIsFixedTitleBar = isFixed;
1292711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck        setSkipTitleBarAnimations(true);
1302711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck        show();
1312711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck        setSkipTitleBarAnimations(false);
1322711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck        if (parent != null) {
1332711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck            parent.removeView(this);
1342711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck        }
1352711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck        if (mIsFixedTitleBar) {
1362711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck            mBaseUi.addFixedTitleBar(this);
1372711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck        } else {
1382711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck            mContentView.addView(this, makeLayoutParams());
1392711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck            mBaseUi.setContentViewMarginTop(0);
14057059a8360e3b9872f4f6cbdaa8b5af4ac1c901dMichael Kolb        }
14157059a8360e3b9872f4f6cbdaa8b5af4ac1c901dMichael Kolb    }
14257059a8360e3b9872f4f6cbdaa8b5af4ac1c901dMichael Kolb
1430f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    public BaseUi getUi() {
1440f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        return mBaseUi;
1450f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
1460f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
1470f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    public UiController getUiController() {
1480f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        return mUiController;
1490f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
1500f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
1510f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    public void setUseQuickControls(boolean use) {
1520f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        mUseQuickControls = use;
1530f9aaebdf2b1fbf230cf497598c684d7cff66653John Reck        setFixedTitleBar();
1544923c22cb79296a9624a599cf8874323cdbc6cbcMichael Kolb        if (use) {
1554923c22cb79296a9624a599cf8874323cdbc6cbcMichael Kolb            this.setVisibility(View.GONE);
1564923c22cb79296a9624a599cf8874323cdbc6cbcMichael Kolb        } else {
1574923c22cb79296a9624a599cf8874323cdbc6cbcMichael Kolb            this.setVisibility(View.VISIBLE);
1584923c22cb79296a9624a599cf8874323cdbc6cbcMichael Kolb        }
1590f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
1600f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
1610f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    void setShowProgressOnly(boolean progress) {
162ef654f1dd80f55609060005342fc4f2cde62990cJohn Reck        if (progress && !wantsToBeVisible()) {
1630f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            mNavBar.setVisibility(View.GONE);
1640f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        } else {
1650f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            mNavBar.setVisibility(View.VISIBLE);
1660f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        }
1670f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
1680f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
1690f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    void setSkipTitleBarAnimations(boolean skip) {
1700f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        mSkipTitleBarAnimations = skip;
1710f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
1720f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
1730f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    void setupTitleBarAnimator(Animator animator) {
1740f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        Resources res = mContext.getResources();
1750f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        int duration = res.getInteger(R.integer.titlebar_animation_duration);
1760f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        animator.setInterpolator(new DecelerateInterpolator(
1770f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                ANIM_TITLEBAR_DECELERATE));
1780f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        animator.setDuration(duration);
1790f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
1800f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
1810f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    void show() {
1822711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck        cancelTitleBarAnimation(false);
1832711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck        if (mUseQuickControls || mSkipTitleBarAnimations) {
1844923c22cb79296a9624a599cf8874323cdbc6cbcMichael Kolb            this.setVisibility(View.VISIBLE);
1854923c22cb79296a9624a599cf8874323cdbc6cbcMichael Kolb            this.setTranslationY(0);
1860f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        } else {
1872711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck            int visibleHeight = getVisibleTitleHeight();
1882711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck            float startPos = (-getEmbeddedHeight() + visibleHeight);
1892711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck            if (getTranslationY() != 0) {
1902711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck                startPos = Math.max(startPos, getTranslationY());
1910f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            }
1922711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck            mTitleBarAnimator = ObjectAnimator.ofFloat(this,
1932711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck                    "translationY",
1942711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck                    startPos, 0);
1952711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck            setupTitleBarAnimator(mTitleBarAnimator);
1962711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck            mTitleBarAnimator.start();
1970f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        }
1980f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        mShowing = true;
1990f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
2000f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
2010f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    void hide() {
2020f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        if (mUseQuickControls) {
2034923c22cb79296a9624a599cf8874323cdbc6cbcMichael Kolb            this.setVisibility(View.GONE);
2040f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        } else {
2052711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck            if (mIsFixedTitleBar) return;
2060f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            if (!mSkipTitleBarAnimations) {
2070f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                cancelTitleBarAnimation(false);
2080f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                int visibleHeight = getVisibleTitleHeight();
2090f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                mTitleBarAnimator = ObjectAnimator.ofFloat(this,
2100f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                        "translationY", getTranslationY(),
2110f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                        (-getEmbeddedHeight() + visibleHeight));
2120f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                mTitleBarAnimator.addListener(mHideTileBarAnimatorListener);
2130f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                setupTitleBarAnimator(mTitleBarAnimator);
2140f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                mTitleBarAnimator.start();
2150f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            } else {
2164923c22cb79296a9624a599cf8874323cdbc6cbcMichael Kolb                onScrollChanged();
2170f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            }
2180f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        }
2190f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        mShowing = false;
2200f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
2210f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
2220f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    boolean isShowing() {
2230f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        return mShowing;
2240f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
2250f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
2260f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    void cancelTitleBarAnimation(boolean reset) {
2270f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        if (mTitleBarAnimator != null) {
2280f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            mTitleBarAnimator.cancel();
2290f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            mTitleBarAnimator = null;
2300f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        }
2310f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        if (reset) {
2320f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            setTranslationY(0);
2330f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        }
2340f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
2350f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
2360f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    private AnimatorListener mHideTileBarAnimatorListener = new AnimatorListener() {
2370f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
2380f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        @Override
2390f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        public void onAnimationStart(Animator animation) {
2400f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        }
2410f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
2420f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        @Override
2430f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        public void onAnimationRepeat(Animator animation) {
2440f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        }
2450f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
2460f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        @Override
2470f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        public void onAnimationEnd(Animator animation) {
2484923c22cb79296a9624a599cf8874323cdbc6cbcMichael Kolb            // update position
2494923c22cb79296a9624a599cf8874323cdbc6cbcMichael Kolb            onScrollChanged();
2500f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        }
2510f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
2520f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        @Override
2530f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        public void onAnimationCancel(Animator animation) {
2540f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        }
2550f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    };
2560f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
2570f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    private int getVisibleTitleHeight() {
2580f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        Tab tab = mBaseUi.getActiveTab();
2590f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        WebView webview = tab != null ? tab.getWebView() : null;
2600f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        return webview != null ? webview.getVisibleTitleHeight() : 0;
2610f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
2620f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
2630f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    /**
2640f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck     * Update the progress, from 0 to 100.
2650f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck     */
2660f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    public void setProgress(int newProgress) {
2670f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        if (newProgress >= PROGRESS_MAX) {
2680f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            mProgress.setProgress(PageProgressView.MAX_PROGRESS);
2690f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            mProgress.setVisibility(View.GONE);
2700f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            mInLoad = false;
2710f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            mNavBar.onProgressStopped();
2720f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            // check if needs to be hidden
273ef654f1dd80f55609060005342fc4f2cde62990cJohn Reck            if (!isEditingUrl() && !wantsToBeVisible()) {
2740f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                if (mUseQuickControls) {
275e8a823329e004c4261ee5f810e1ca3ebd90914ddMichael Kolb                    hide();
276bc82ec97530f9ee4fc1f33e7d1d6050575c22a21John Reck                } else {
277bc82ec97530f9ee4fc1f33e7d1d6050575c22a21John Reck                    mBaseUi.showTitleBarForDuration();
2780f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                }
2790f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            }
2800f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        } else {
2810f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            if (!mInLoad) {
2820f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                mProgress.setVisibility(View.VISIBLE);
2830f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                mInLoad = true;
2840f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                mNavBar.onProgressStarted();
2850f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            }
2860f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            mProgress.setProgress(newProgress * PageProgressView.MAX_PROGRESS
2870f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                    / PROGRESS_MAX);
288e8a823329e004c4261ee5f810e1ca3ebd90914ddMichael Kolb            if (mUseQuickControls && !isEditingUrl()) {
289e8a823329e004c4261ee5f810e1ca3ebd90914ddMichael Kolb                setShowProgressOnly(true);
290e8a823329e004c4261ee5f810e1ca3ebd90914ddMichael Kolb            }
2910f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            if (!mShowing) {
2920f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                show();
2930f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            }
2940f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        }
2950f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
2960f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
2970f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    public int getEmbeddedHeight() {
2982711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck        if (mUseQuickControls || mIsFixedTitleBar) return 0;
2992711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck        return calculateEmbeddedHeight();
3002711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck    }
3012711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck
3022711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck    private int calculateEmbeddedHeight() {
3030f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        int height = mNavBar.getHeight();
304d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch        if (mAutoLogin != null && mAutoLogin.getVisibility() == View.VISIBLE) {
3050f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            height += mAutoLogin.getHeight();
3060f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        }
3070f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        return height;
3080f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
3090f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
3100f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    public void updateAutoLogin(Tab tab, boolean animate) {
311d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch        if (mAutoLogin == null) {
312d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch            if  (tab.getDeviceAccountLogin() == null) {
313d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch                return;
314d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch            }
315d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch            inflateAutoLoginBar();
316d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch        }
3170f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        mAutoLogin.updateAutoLogin(tab, animate);
3180f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
3190f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
3200f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    public void showAutoLogin(boolean animate) {
3210f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        if (mUseQuickControls) {
3220f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            mBaseUi.showTitleBar();
3230f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        }
324d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch        if (mAutoLogin == null) {
325d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch            inflateAutoLoginBar();
326d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch        }
3270f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        mAutoLogin.setVisibility(View.VISIBLE);
3280f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        if (animate) {
3290f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            mAutoLogin.startAnimation(AnimationUtils.loadAnimation(
3300f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                    getContext(), R.anim.autologin_enter));
3310f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        }
3320f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
3330f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
3340f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    public void hideAutoLogin(boolean animate) {
3350f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        if (mUseQuickControls) {
3360f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            mBaseUi.hideTitleBar();
3370f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            mAutoLogin.setVisibility(View.GONE);
3380f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            mBaseUi.refreshWebView();
3390f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        } else {
3400f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            if (animate) {
3410f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                Animation anim = AnimationUtils.loadAnimation(getContext(),
3420f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                        R.anim.autologin_exit);
3430f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                anim.setAnimationListener(new AnimationListener() {
3440f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                    @Override
3450f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                    public void onAnimationEnd(Animation a) {
3460f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                        mAutoLogin.setVisibility(View.GONE);
3470f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                        mBaseUi.refreshWebView();
3480f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                    }
3490f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
3500f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                    @Override
3510f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                    public void onAnimationStart(Animation a) {
3520f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                    }
3530f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
3540f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                    @Override
3550f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                    public void onAnimationRepeat(Animation a) {
3560f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                    }
3570f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                });
3580f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                mAutoLogin.startAnimation(anim);
3590f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            } else if (mAutoLogin.getAnimation() == null) {
3600f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                mAutoLogin.setVisibility(View.GONE);
3610f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck                mBaseUi.refreshWebView();
3620f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            }
3630f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        }
3640f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
3650f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
366ef654f1dd80f55609060005342fc4f2cde62990cJohn Reck    public boolean wantsToBeVisible() {
367ef654f1dd80f55609060005342fc4f2cde62990cJohn Reck        return inAutoLogin()
368d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch            || (mSnapshotBar != null && mSnapshotBar.getVisibility() == View.VISIBLE
369ef654f1dd80f55609060005342fc4f2cde62990cJohn Reck                    && mSnapshotBar.isAnimating());
370ef654f1dd80f55609060005342fc4f2cde62990cJohn Reck    }
371ef654f1dd80f55609060005342fc4f2cde62990cJohn Reck
372ef654f1dd80f55609060005342fc4f2cde62990cJohn Reck    private boolean inAutoLogin() {
373d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch        return mAutoLogin != null && mAutoLogin.getVisibility() == View.VISIBLE;
3740f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
3750f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
3760f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    public boolean isEditingUrl() {
3770f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        return mNavBar.isEditingUrl();
3780f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
3790f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
3800f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    public WebView getCurrentWebView() {
3810f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        Tab t = mBaseUi.getActiveTab();
3820f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        if (t != null) {
3830f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            return t.getWebView();
3840f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        } else {
3850f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck            return null;
3860f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        }
3870f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
3880f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
3890f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    public PageProgressView getProgressView() {
3900f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        return mProgress;
3910f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
3920f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
3930f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    public NavigationBarBase getNavigationBar() {
3940f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        return mNavBar;
3950f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
3960f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
3970f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    public boolean useQuickControls() {
3980f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        return mUseQuickControls;
3990f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
4000f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
4010f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    public boolean isInLoad() {
4020f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        return mInLoad;
4030f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
4040f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
4050f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    private ViewGroup.LayoutParams makeLayoutParams() {
4064923c22cb79296a9624a599cf8874323cdbc6cbcMichael Kolb        return new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
4074923c22cb79296a9624a599cf8874323cdbc6cbcMichael Kolb                LayoutParams.WRAP_CONTENT);
4080f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
4090f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
4100f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    @Override
4110f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    public View focusSearch(View focused, int dir) {
412fcb6095b9140296cf3b5a4af3107500ee943baccJohn Reck        WebView web = getCurrentWebView();
413d70419abc78bbf76f21ea7e85c551d20e9fd1685John Reck        if (FOCUS_DOWN == dir && hasFocus() && web != null
414fcb6095b9140296cf3b5a4af3107500ee943baccJohn Reck                && web.hasFocusable() && web.getParent() != null) {
415fcb6095b9140296cf3b5a4af3107500ee943baccJohn Reck            return web;
4160f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        }
4170f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck        return super.focusSearch(focused, dir);
4180f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck    }
4190f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck
420ef654f1dd80f55609060005342fc4f2cde62990cJohn Reck    public void onTabDataChanged(Tab tab) {
421d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch        if (mSnapshotBar != null) {
422d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch            mSnapshotBar.onTabDataChanged(tab);
423d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch        }
424d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch
425ef654f1dd80f55609060005342fc4f2cde62990cJohn Reck        if (tab.isSnapshot()) {
426d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch            inflateSnapshotBar();
427ef654f1dd80f55609060005342fc4f2cde62990cJohn Reck            mSnapshotBar.setVisibility(VISIBLE);
428ef654f1dd80f55609060005342fc4f2cde62990cJohn Reck            mNavBar.setVisibility(GONE);
429ef654f1dd80f55609060005342fc4f2cde62990cJohn Reck        } else {
430d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch            if (mSnapshotBar != null) {
431d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch                mSnapshotBar.setVisibility(GONE);
432d51bb570d4806d9e6b3c997bb0868d094f481bf2Ben Murdoch            }
433ef654f1dd80f55609060005342fc4f2cde62990cJohn Reck            mNavBar.setVisibility(VISIBLE);
434ef654f1dd80f55609060005342fc4f2cde62990cJohn Reck        }
435ef654f1dd80f55609060005342fc4f2cde62990cJohn Reck    }
436ef654f1dd80f55609060005342fc4f2cde62990cJohn Reck
4374923c22cb79296a9624a599cf8874323cdbc6cbcMichael Kolb    public void onScrollChanged() {
4382711fab2fa2eb798e3aea90368f7ac5af1fbe523John Reck        if (!mShowing && !mIsFixedTitleBar) {
4394923c22cb79296a9624a599cf8874323cdbc6cbcMichael Kolb            setTranslationY(getVisibleTitleHeight() - getEmbeddedHeight());
4404923c22cb79296a9624a599cf8874323cdbc6cbcMichael Kolb        }
4414923c22cb79296a9624a599cf8874323cdbc6cbcMichael Kolb    }
4424923c22cb79296a9624a599cf8874323cdbc6cbcMichael Kolb
4431cc1d1d08c50211e4f9f8407978d0435a0110375John Reck    public void onResume() {
4441cc1d1d08c50211e4f9f8407978d0435a0110375John Reck        setFixedTitleBar();
4451cc1d1d08c50211e4f9f8407978d0435a0110375John Reck    }
4461cc1d1d08c50211e4f9f8407978d0435a0110375John Reck
4470f602f3933dcd88702fdb514b6611e3066ca7a2bJohn Reck}
448