Home | History | Annotate | Download | only in browser
      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 
     17 package com.android.browser;
     18 
     19 import android.animation.Animator;
     20 import android.animation.Animator.AnimatorListener;
     21 import android.animation.ObjectAnimator;
     22 import android.content.Context;
     23 import android.content.res.Configuration;
     24 import android.content.res.Resources;
     25 import android.view.LayoutInflater;
     26 import android.view.View;
     27 import android.view.ViewGroup;
     28 import android.view.ViewStub;
     29 import android.view.accessibility.AccessibilityManager;
     30 import android.view.animation.Animation;
     31 import android.view.animation.Animation.AnimationListener;
     32 import android.view.animation.AnimationUtils;
     33 import android.view.animation.DecelerateInterpolator;
     34 import android.webkit.WebView;
     35 import android.widget.FrameLayout;
     36 import android.widget.RelativeLayout;
     37 
     38 
     39 /**
     40  * Base class for a title bar used by the browser.
     41  */
     42 public class TitleBar extends RelativeLayout {
     43 
     44     private static final int PROGRESS_MAX = 100;
     45     private static final float ANIM_TITLEBAR_DECELERATE = 2.5f;
     46 
     47     private UiController mUiController;
     48     private BaseUi mBaseUi;
     49     private FrameLayout mContentView;
     50     private PageProgressView mProgress;
     51     private AccessibilityManager mAccessibilityManager;
     52 
     53     private AutologinBar mAutoLogin;
     54     private NavigationBarBase mNavBar;
     55     private boolean mUseQuickControls;
     56     private SnapshotBar mSnapshotBar;
     57 
     58     //state
     59     private boolean mShowing;
     60     private boolean mInLoad;
     61     private boolean mSkipTitleBarAnimations;
     62     private Animator mTitleBarAnimator;
     63     private boolean mIsFixedTitleBar;
     64 
     65     public TitleBar(Context context, UiController controller, BaseUi ui,
     66             FrameLayout contentView) {
     67         super(context, null);
     68         mUiController = controller;
     69         mBaseUi = ui;
     70         mContentView = contentView;
     71         mAccessibilityManager = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
     72         initLayout(context);
     73         setFixedTitleBar();
     74     }
     75 
     76     private void initLayout(Context context) {
     77         LayoutInflater factory = LayoutInflater.from(context);
     78         factory.inflate(R.layout.title_bar, this);
     79         mProgress = (PageProgressView) findViewById(R.id.progress);
     80         mNavBar = (NavigationBarBase) findViewById(R.id.taburlbar);
     81         mNavBar.setTitleBar(this);
     82     }
     83 
     84     private void inflateAutoLoginBar() {
     85         if (mAutoLogin != null) {
     86             return;
     87         }
     88 
     89         ViewStub stub = (ViewStub) findViewById(R.id.autologin_stub);
     90         mAutoLogin = (AutologinBar) stub.inflate();
     91         mAutoLogin.setTitleBar(this);
     92     }
     93 
     94     private void inflateSnapshotBar() {
     95         if (mSnapshotBar != null) {
     96             return;
     97         }
     98 
     99         ViewStub stub = (ViewStub) findViewById(R.id.snapshotbar_stub);
    100         mSnapshotBar = (SnapshotBar) stub.inflate();
    101         mSnapshotBar.setTitleBar(this);
    102     }
    103 
    104     @Override
    105     protected void onConfigurationChanged(Configuration config) {
    106         super.onConfigurationChanged(config);
    107         setFixedTitleBar();
    108     }
    109 
    110     @Override
    111     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    112         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    113         if (mIsFixedTitleBar) {
    114             int margin = getMeasuredHeight() - calculateEmbeddedHeight();
    115             mBaseUi.setContentViewMarginTop(-margin);
    116         } else {
    117             mBaseUi.setContentViewMarginTop(0);
    118         }
    119     }
    120 
    121     private void setFixedTitleBar() {
    122         boolean isFixed = !mUseQuickControls
    123                 && !mContext.getResources().getBoolean(R.bool.hide_title);
    124         isFixed |= mAccessibilityManager.isEnabled();
    125         isFixed |= !BrowserWebView.isClassic();
    126         // If getParent() returns null, we are initializing
    127         ViewGroup parent = (ViewGroup)getParent();
    128         if (mIsFixedTitleBar == isFixed && parent != null) return;
    129         mIsFixedTitleBar = isFixed;
    130         setSkipTitleBarAnimations(true);
    131         show();
    132         setSkipTitleBarAnimations(false);
    133         if (parent != null) {
    134             parent.removeView(this);
    135         }
    136         if (mIsFixedTitleBar) {
    137             mBaseUi.addFixedTitleBar(this);
    138         } else {
    139             mContentView.addView(this, makeLayoutParams());
    140             mBaseUi.setContentViewMarginTop(0);
    141         }
    142     }
    143 
    144     public BaseUi getUi() {
    145         return mBaseUi;
    146     }
    147 
    148     public UiController getUiController() {
    149         return mUiController;
    150     }
    151 
    152     public void setUseQuickControls(boolean use) {
    153         mUseQuickControls = use;
    154         setFixedTitleBar();
    155         if (use) {
    156             this.setVisibility(View.GONE);
    157         } else {
    158             this.setVisibility(View.VISIBLE);
    159         }
    160     }
    161 
    162     void setShowProgressOnly(boolean progress) {
    163         if (progress && !wantsToBeVisible()) {
    164             mNavBar.setVisibility(View.GONE);
    165         } else {
    166             mNavBar.setVisibility(View.VISIBLE);
    167         }
    168     }
    169 
    170     void setSkipTitleBarAnimations(boolean skip) {
    171         mSkipTitleBarAnimations = skip;
    172     }
    173 
    174     void setupTitleBarAnimator(Animator animator) {
    175         Resources res = mContext.getResources();
    176         int duration = res.getInteger(R.integer.titlebar_animation_duration);
    177         animator.setInterpolator(new DecelerateInterpolator(
    178                 ANIM_TITLEBAR_DECELERATE));
    179         animator.setDuration(duration);
    180     }
    181 
    182     void show() {
    183         cancelTitleBarAnimation(false);
    184         if (mUseQuickControls || mSkipTitleBarAnimations) {
    185             this.setVisibility(View.VISIBLE);
    186             this.setTranslationY(0);
    187         } else {
    188             int visibleHeight = getVisibleTitleHeight();
    189             float startPos = (-getEmbeddedHeight() + visibleHeight);
    190             if (getTranslationY() != 0) {
    191                 startPos = Math.max(startPos, getTranslationY());
    192             }
    193             mTitleBarAnimator = ObjectAnimator.ofFloat(this,
    194                     "translationY",
    195                     startPos, 0);
    196             setupTitleBarAnimator(mTitleBarAnimator);
    197             mTitleBarAnimator.start();
    198         }
    199         mShowing = true;
    200     }
    201 
    202     void hide() {
    203         if (mUseQuickControls) {
    204             this.setVisibility(View.GONE);
    205         } else {
    206             if (mIsFixedTitleBar) return;
    207             if (!mSkipTitleBarAnimations) {
    208                 cancelTitleBarAnimation(false);
    209                 int visibleHeight = getVisibleTitleHeight();
    210                 mTitleBarAnimator = ObjectAnimator.ofFloat(this,
    211                         "translationY", getTranslationY(),
    212                         (-getEmbeddedHeight() + visibleHeight));
    213                 mTitleBarAnimator.addListener(mHideTileBarAnimatorListener);
    214                 setupTitleBarAnimator(mTitleBarAnimator);
    215                 mTitleBarAnimator.start();
    216             } else {
    217                 onScrollChanged();
    218             }
    219         }
    220         mShowing = false;
    221     }
    222 
    223     boolean isShowing() {
    224         return mShowing;
    225     }
    226 
    227     void cancelTitleBarAnimation(boolean reset) {
    228         if (mTitleBarAnimator != null) {
    229             mTitleBarAnimator.cancel();
    230             mTitleBarAnimator = null;
    231         }
    232         if (reset) {
    233             setTranslationY(0);
    234         }
    235     }
    236 
    237     private AnimatorListener mHideTileBarAnimatorListener = new AnimatorListener() {
    238 
    239         @Override
    240         public void onAnimationStart(Animator animation) {
    241         }
    242 
    243         @Override
    244         public void onAnimationRepeat(Animator animation) {
    245         }
    246 
    247         @Override
    248         public void onAnimationEnd(Animator animation) {
    249             // update position
    250             onScrollChanged();
    251         }
    252 
    253         @Override
    254         public void onAnimationCancel(Animator animation) {
    255         }
    256     };
    257 
    258     private int getVisibleTitleHeight() {
    259         Tab tab = mBaseUi.getActiveTab();
    260         WebView webview = tab != null ? tab.getWebView() : null;
    261         return webview != null ? webview.getVisibleTitleHeight() : 0;
    262     }
    263 
    264     /**
    265      * Update the progress, from 0 to 100.
    266      */
    267     public void setProgress(int newProgress) {
    268         if (newProgress >= PROGRESS_MAX) {
    269             mProgress.setProgress(PageProgressView.MAX_PROGRESS);
    270             mProgress.setVisibility(View.GONE);
    271             mInLoad = false;
    272             mNavBar.onProgressStopped();
    273             // check if needs to be hidden
    274             if (!isEditingUrl() && !wantsToBeVisible()) {
    275                 if (mUseQuickControls) {
    276                     hide();
    277                 } else {
    278                     mBaseUi.showTitleBarForDuration();
    279                 }
    280             }
    281         } else {
    282             if (!mInLoad) {
    283                 mProgress.setVisibility(View.VISIBLE);
    284                 mInLoad = true;
    285                 mNavBar.onProgressStarted();
    286             }
    287             mProgress.setProgress(newProgress * PageProgressView.MAX_PROGRESS
    288                     / PROGRESS_MAX);
    289             if (mUseQuickControls && !isEditingUrl()) {
    290                 setShowProgressOnly(true);
    291             }
    292             if (!mShowing) {
    293                 show();
    294             }
    295         }
    296     }
    297 
    298     public int getEmbeddedHeight() {
    299         if (mUseQuickControls || mIsFixedTitleBar) return 0;
    300         return calculateEmbeddedHeight();
    301     }
    302 
    303     private int calculateEmbeddedHeight() {
    304         int height = mNavBar.getHeight();
    305         if (mAutoLogin != null && mAutoLogin.getVisibility() == View.VISIBLE) {
    306             height += mAutoLogin.getHeight();
    307         }
    308         return height;
    309     }
    310 
    311     public void updateAutoLogin(Tab tab, boolean animate) {
    312         if (mAutoLogin == null) {
    313             if  (tab.getDeviceAccountLogin() == null) {
    314                 return;
    315             }
    316             inflateAutoLoginBar();
    317         }
    318         mAutoLogin.updateAutoLogin(tab, animate);
    319     }
    320 
    321     public void showAutoLogin(boolean animate) {
    322         if (mUseQuickControls) {
    323             mBaseUi.showTitleBar();
    324         }
    325         if (mAutoLogin == null) {
    326             inflateAutoLoginBar();
    327         }
    328         mAutoLogin.setVisibility(View.VISIBLE);
    329         if (animate) {
    330             mAutoLogin.startAnimation(AnimationUtils.loadAnimation(
    331                     getContext(), R.anim.autologin_enter));
    332         }
    333     }
    334 
    335     public void hideAutoLogin(boolean animate) {
    336         if (mUseQuickControls) {
    337             mBaseUi.hideTitleBar();
    338             mAutoLogin.setVisibility(View.GONE);
    339             mBaseUi.refreshWebView();
    340         } else {
    341             if (animate) {
    342                 Animation anim = AnimationUtils.loadAnimation(getContext(),
    343                         R.anim.autologin_exit);
    344                 anim.setAnimationListener(new AnimationListener() {
    345                     @Override
    346                     public void onAnimationEnd(Animation a) {
    347                         mAutoLogin.setVisibility(View.GONE);
    348                         mBaseUi.refreshWebView();
    349                     }
    350 
    351                     @Override
    352                     public void onAnimationStart(Animation a) {
    353                     }
    354 
    355                     @Override
    356                     public void onAnimationRepeat(Animation a) {
    357                     }
    358                 });
    359                 mAutoLogin.startAnimation(anim);
    360             } else if (mAutoLogin.getAnimation() == null) {
    361                 mAutoLogin.setVisibility(View.GONE);
    362                 mBaseUi.refreshWebView();
    363             }
    364         }
    365     }
    366 
    367     public boolean wantsToBeVisible() {
    368         return inAutoLogin()
    369             || (mSnapshotBar != null && mSnapshotBar.getVisibility() == View.VISIBLE
    370                     && mSnapshotBar.isAnimating());
    371     }
    372 
    373     private boolean inAutoLogin() {
    374         return mAutoLogin != null && mAutoLogin.getVisibility() == View.VISIBLE;
    375     }
    376 
    377     public boolean isEditingUrl() {
    378         return mNavBar.isEditingUrl();
    379     }
    380 
    381     public WebView getCurrentWebView() {
    382         Tab t = mBaseUi.getActiveTab();
    383         if (t != null) {
    384             return t.getWebView();
    385         } else {
    386             return null;
    387         }
    388     }
    389 
    390     public PageProgressView getProgressView() {
    391         return mProgress;
    392     }
    393 
    394     public NavigationBarBase getNavigationBar() {
    395         return mNavBar;
    396     }
    397 
    398     public boolean useQuickControls() {
    399         return mUseQuickControls;
    400     }
    401 
    402     public boolean isInLoad() {
    403         return mInLoad;
    404     }
    405 
    406     private ViewGroup.LayoutParams makeLayoutParams() {
    407         return new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
    408                 LayoutParams.WRAP_CONTENT);
    409     }
    410 
    411     @Override
    412     public View focusSearch(View focused, int dir) {
    413         WebView web = getCurrentWebView();
    414         if (FOCUS_DOWN == dir && hasFocus() && web != null
    415                 && web.hasFocusable() && web.getParent() != null) {
    416             return web;
    417         }
    418         return super.focusSearch(focused, dir);
    419     }
    420 
    421     public void onTabDataChanged(Tab tab) {
    422         if (mSnapshotBar != null) {
    423             mSnapshotBar.onTabDataChanged(tab);
    424         }
    425 
    426         if (tab.isSnapshot()) {
    427             inflateSnapshotBar();
    428             mSnapshotBar.setVisibility(VISIBLE);
    429             mNavBar.setVisibility(GONE);
    430         } else {
    431             if (mSnapshotBar != null) {
    432                 mSnapshotBar.setVisibility(GONE);
    433             }
    434             mNavBar.setVisibility(VISIBLE);
    435         }
    436     }
    437 
    438     public void onScrollChanged() {
    439         if (!mShowing && !mIsFixedTitleBar) {
    440             setTranslationY(getVisibleTitleHeight() - getEmbeddedHeight());
    441         }
    442     }
    443 
    444     public void onResume() {
    445         setFixedTitleBar();
    446     }
    447 
    448 }
    449