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 
TitleBar(Context context, UiController controller, BaseUi ui, FrameLayout contentView)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 
initLayout(Context context)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 
inflateAutoLoginBar()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
onConfigurationChanged(Configuration config)94     protected void onConfigurationChanged(Configuration config) {
95         super.onConfigurationChanged(config);
96         setFixedTitleBar();
97     }
98 
99     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)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 
setFixedTitleBar()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 
getUi()129     public BaseUi getUi() {
130         return mBaseUi;
131     }
132 
getUiController()133     public UiController getUiController() {
134         return mUiController;
135     }
136 
setUseQuickControls(boolean use)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 
setShowProgressOnly(boolean progress)147     void setShowProgressOnly(boolean progress) {
148         if (progress && !wantsToBeVisible()) {
149             mNavBar.setVisibility(View.GONE);
150         } else {
151             mNavBar.setVisibility(View.VISIBLE);
152         }
153     }
154 
setSkipTitleBarAnimations(boolean skip)155     void setSkipTitleBarAnimations(boolean skip) {
156         mSkipTitleBarAnimations = skip;
157     }
158 
setupTitleBarAnimator(Animator animator)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 
show()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 
hide()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 
isShowing()208     boolean isShowing() {
209         return mShowing;
210     }
211 
cancelTitleBarAnimation(boolean reset)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 
getVisibleTitleHeight()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      */
setProgress(int newProgress)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 
getEmbeddedHeight()283     public int getEmbeddedHeight() {
284         if (mUseQuickControls || mIsFixedTitleBar) return 0;
285         return calculateEmbeddedHeight();
286     }
287 
calculateEmbeddedHeight()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 
updateAutoLogin(Tab tab, boolean animate)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 
showAutoLogin(boolean animate)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 
hideAutoLogin(boolean animate)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 
wantsToBeVisible()352     public boolean wantsToBeVisible() {
353         return inAutoLogin();
354     }
355 
inAutoLogin()356     private boolean inAutoLogin() {
357         return mAutoLogin != null && mAutoLogin.getVisibility() == View.VISIBLE;
358     }
359 
isEditingUrl()360     public boolean isEditingUrl() {
361         return mNavBar.isEditingUrl();
362     }
363 
getCurrentWebView()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 
getProgressView()373     public PageProgressView getProgressView() {
374         return mProgress;
375     }
376 
getNavigationBar()377     public NavigationBarBase getNavigationBar() {
378         return mNavBar;
379     }
380 
useQuickControls()381     public boolean useQuickControls() {
382         return mUseQuickControls;
383     }
384 
isInLoad()385     public boolean isInLoad() {
386         return mInLoad;
387     }
388 
makeLayoutParams()389     private ViewGroup.LayoutParams makeLayoutParams() {
390         return new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
391                 LayoutParams.WRAP_CONTENT);
392     }
393 
394     @Override
focusSearch(View focused, int dir)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 
onTabDataChanged(Tab tab)404     public void onTabDataChanged(Tab tab) {
405         mNavBar.setVisibility(VISIBLE);
406     }
407 
onScrollChanged()408     public void onScrollChanged() {
409         if (!mShowing && !mIsFixedTitleBar) {
410             setTranslationY(getVisibleTitleHeight() - getEmbeddedHeight());
411         }
412     }
413 
onResume()414     public void onResume() {
415         setFixedTitleBar();
416     }
417 
418 }
419