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