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