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         // If getParent() returns null, we are initializing
    126         ViewGroup parent = (ViewGroup)getParent();
    127         if (mIsFixedTitleBar == isFixed && parent != null) return;
    128         mIsFixedTitleBar = isFixed;
    129         setSkipTitleBarAnimations(true);
    130         show();
    131         setSkipTitleBarAnimations(false);
    132         if (parent != null) {
    133             parent.removeView(this);
    134         }
    135         if (mIsFixedTitleBar) {
    136             mBaseUi.addFixedTitleBar(this);
    137         } else {
    138             mContentView.addView(this, makeLayoutParams());
    139             mBaseUi.setContentViewMarginTop(0);
    140         }
    141     }
    142 
    143     public BaseUi getUi() {
    144         return mBaseUi;
    145     }
    146 
    147     public UiController getUiController() {
    148         return mUiController;
    149     }
    150 
    151     public void setUseQuickControls(boolean use) {
    152         mUseQuickControls = use;
    153         setFixedTitleBar();
    154         if (use) {
    155             this.setVisibility(View.GONE);
    156         } else {
    157             this.setVisibility(View.VISIBLE);
    158         }
    159     }
    160 
    161     void setShowProgressOnly(boolean progress) {
    162         if (progress && !wantsToBeVisible()) {
    163             mNavBar.setVisibility(View.GONE);
    164         } else {
    165             mNavBar.setVisibility(View.VISIBLE);
    166         }
    167     }
    168 
    169     void setSkipTitleBarAnimations(boolean skip) {
    170         mSkipTitleBarAnimations = skip;
    171     }
    172 
    173     void setupTitleBarAnimator(Animator animator) {
    174         Resources res = mContext.getResources();
    175         int duration = res.getInteger(R.integer.titlebar_animation_duration);
    176         animator.setInterpolator(new DecelerateInterpolator(
    177                 ANIM_TITLEBAR_DECELERATE));
    178         animator.setDuration(duration);
    179     }
    180 
    181     void show() {
    182         cancelTitleBarAnimation(false);
    183         if (mUseQuickControls || mSkipTitleBarAnimations) {
    184             this.setVisibility(View.VISIBLE);
    185             this.setTranslationY(0);
    186         } else {
    187             int visibleHeight = getVisibleTitleHeight();
    188             float startPos = (-getEmbeddedHeight() + visibleHeight);
    189             if (getTranslationY() != 0) {
    190                 startPos = Math.max(startPos, getTranslationY());
    191             }
    192             mTitleBarAnimator = ObjectAnimator.ofFloat(this,
    193                     "translationY",
    194                     startPos, 0);
    195             setupTitleBarAnimator(mTitleBarAnimator);
    196             mTitleBarAnimator.start();
    197         }
    198         mShowing = true;
    199     }
    200 
    201     void hide() {
    202         if (mUseQuickControls) {
    203             this.setVisibility(View.GONE);
    204         } else {
    205             if (mIsFixedTitleBar) return;
    206             if (!mSkipTitleBarAnimations) {
    207                 cancelTitleBarAnimation(false);
    208                 int visibleHeight = getVisibleTitleHeight();
    209                 mTitleBarAnimator = ObjectAnimator.ofFloat(this,
    210                         "translationY", getTranslationY(),
    211                         (-getEmbeddedHeight() + visibleHeight));
    212                 mTitleBarAnimator.addListener(mHideTileBarAnimatorListener);
    213                 setupTitleBarAnimator(mTitleBarAnimator);
    214                 mTitleBarAnimator.start();
    215             } else {
    216                 onScrollChanged();
    217             }
    218         }
    219         mShowing = false;
    220     }
    221 
    222     boolean isShowing() {
    223         return mShowing;
    224     }
    225 
    226     void cancelTitleBarAnimation(boolean reset) {
    227         if (mTitleBarAnimator != null) {
    228             mTitleBarAnimator.cancel();
    229             mTitleBarAnimator = null;
    230         }
    231         if (reset) {
    232             setTranslationY(0);
    233         }
    234     }
    235 
    236     private AnimatorListener mHideTileBarAnimatorListener = new AnimatorListener() {
    237 
    238         @Override
    239         public void onAnimationStart(Animator animation) {
    240         }
    241 
    242         @Override
    243         public void onAnimationRepeat(Animator animation) {
    244         }
    245 
    246         @Override
    247         public void onAnimationEnd(Animator animation) {
    248             // update position
    249             onScrollChanged();
    250         }
    251 
    252         @Override
    253         public void onAnimationCancel(Animator animation) {
    254         }
    255     };
    256 
    257     private int getVisibleTitleHeight() {
    258         Tab tab = mBaseUi.getActiveTab();
    259         WebView webview = tab != null ? tab.getWebView() : null;
    260         return webview != null ? webview.getVisibleTitleHeight() : 0;
    261     }
    262 
    263     /**
    264      * Update the progress, from 0 to 100.
    265      */
    266     public void setProgress(int newProgress) {
    267         if (newProgress >= PROGRESS_MAX) {
    268             mProgress.setProgress(PageProgressView.MAX_PROGRESS);
    269             mProgress.setVisibility(View.GONE);
    270             mInLoad = false;
    271             mNavBar.onProgressStopped();
    272             // check if needs to be hidden
    273             if (!isEditingUrl() && !wantsToBeVisible()) {
    274                 if (mUseQuickControls) {
    275                     hide();
    276                 } else {
    277                     mBaseUi.showTitleBarForDuration();
    278                 }
    279             }
    280         } else {
    281             if (!mInLoad) {
    282                 mProgress.setVisibility(View.VISIBLE);
    283                 mInLoad = true;
    284                 mNavBar.onProgressStarted();
    285             }
    286             mProgress.setProgress(newProgress * PageProgressView.MAX_PROGRESS
    287                     / PROGRESS_MAX);
    288             if (mUseQuickControls && !isEditingUrl()) {
    289                 setShowProgressOnly(true);
    290             }
    291             if (!mShowing) {
    292                 show();
    293             }
    294         }
    295     }
    296 
    297     public int getEmbeddedHeight() {
    298         if (mUseQuickControls || mIsFixedTitleBar) return 0;
    299         return calculateEmbeddedHeight();
    300     }
    301 
    302     private int calculateEmbeddedHeight() {
    303         int height = mNavBar.getHeight();
    304         if (mAutoLogin != null && mAutoLogin.getVisibility() == View.VISIBLE) {
    305             height += mAutoLogin.getHeight();
    306         }
    307         return height;
    308     }
    309 
    310     public void updateAutoLogin(Tab tab, boolean animate) {
    311         if (mAutoLogin == null) {
    312             if  (tab.getDeviceAccountLogin() == null) {
    313                 return;
    314             }
    315             inflateAutoLoginBar();
    316         }
    317         mAutoLogin.updateAutoLogin(tab, animate);
    318     }
    319 
    320     public void showAutoLogin(boolean animate) {
    321         if (mUseQuickControls) {
    322             mBaseUi.showTitleBar();
    323         }
    324         if (mAutoLogin == null) {
    325             inflateAutoLoginBar();
    326         }
    327         mAutoLogin.setVisibility(View.VISIBLE);
    328         if (animate) {
    329             mAutoLogin.startAnimation(AnimationUtils.loadAnimation(
    330                     getContext(), R.anim.autologin_enter));
    331         }
    332     }
    333 
    334     public void hideAutoLogin(boolean animate) {
    335         if (mUseQuickControls) {
    336             mBaseUi.hideTitleBar();
    337             mAutoLogin.setVisibility(View.GONE);
    338             mBaseUi.refreshWebView();
    339         } else {
    340             if (animate) {
    341                 Animation anim = AnimationUtils.loadAnimation(getContext(),
    342                         R.anim.autologin_exit);
    343                 anim.setAnimationListener(new AnimationListener() {
    344                     @Override
    345                     public void onAnimationEnd(Animation a) {
    346                         mAutoLogin.setVisibility(View.GONE);
    347                         mBaseUi.refreshWebView();
    348                     }
    349 
    350                     @Override
    351                     public void onAnimationStart(Animation a) {
    352                     }
    353 
    354                     @Override
    355                     public void onAnimationRepeat(Animation a) {
    356                     }
    357                 });
    358                 mAutoLogin.startAnimation(anim);
    359             } else if (mAutoLogin.getAnimation() == null) {
    360                 mAutoLogin.setVisibility(View.GONE);
    361                 mBaseUi.refreshWebView();
    362             }
    363         }
    364     }
    365 
    366     public boolean wantsToBeVisible() {
    367         return inAutoLogin()
    368             || (mSnapshotBar != null && mSnapshotBar.getVisibility() == View.VISIBLE
    369                     && mSnapshotBar.isAnimating());
    370     }
    371 
    372     private boolean inAutoLogin() {
    373         return mAutoLogin != null && mAutoLogin.getVisibility() == View.VISIBLE;
    374     }
    375 
    376     public boolean isEditingUrl() {
    377         return mNavBar.isEditingUrl();
    378     }
    379 
    380     public WebView getCurrentWebView() {
    381         Tab t = mBaseUi.getActiveTab();
    382         if (t != null) {
    383             return t.getWebView();
    384         } else {
    385             return null;
    386         }
    387     }
    388 
    389     public PageProgressView getProgressView() {
    390         return mProgress;
    391     }
    392 
    393     public NavigationBarBase getNavigationBar() {
    394         return mNavBar;
    395     }
    396 
    397     public boolean useQuickControls() {
    398         return mUseQuickControls;
    399     }
    400 
    401     public boolean isInLoad() {
    402         return mInLoad;
    403     }
    404 
    405     private ViewGroup.LayoutParams makeLayoutParams() {
    406         return new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
    407                 LayoutParams.WRAP_CONTENT);
    408     }
    409 
    410     @Override
    411     public View focusSearch(View focused, int dir) {
    412         WebView web = getCurrentWebView();
    413         if (FOCUS_DOWN == dir && hasFocus() && web != null
    414                 && web.hasFocusable() && web.getParent() != null) {
    415             return web;
    416         }
    417         return super.focusSearch(focused, dir);
    418     }
    419 
    420     public void onTabDataChanged(Tab tab) {
    421         if (mSnapshotBar != null) {
    422             mSnapshotBar.onTabDataChanged(tab);
    423         }
    424 
    425         if (tab.isSnapshot()) {
    426             inflateSnapshotBar();
    427             mSnapshotBar.setVisibility(VISIBLE);
    428             mNavBar.setVisibility(GONE);
    429         } else {
    430             if (mSnapshotBar != null) {
    431                 mSnapshotBar.setVisibility(GONE);
    432             }
    433             mNavBar.setVisibility(VISIBLE);
    434         }
    435     }
    436 
    437     public void onScrollChanged() {
    438         if (!mShowing && !mIsFixedTitleBar) {
    439             setTranslationY(getVisibleTitleHeight() - getEmbeddedHeight());
    440         }
    441     }
    442 
    443     public void onResume() {
    444         setFixedTitleBar();
    445     }
    446 
    447 }
    448