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
17package com.android.browser;
18
19import android.animation.Animator;
20import android.animation.Animator.AnimatorListener;
21import android.animation.ObjectAnimator;
22import android.content.Context;
23import android.content.res.Configuration;
24import android.content.res.Resources;
25import android.view.LayoutInflater;
26import android.view.View;
27import android.view.ViewGroup;
28import android.view.ViewStub;
29import android.view.accessibility.AccessibilityManager;
30import android.view.animation.Animation;
31import android.view.animation.Animation.AnimationListener;
32import android.view.animation.AnimationUtils;
33import android.view.animation.DecelerateInterpolator;
34import android.webkit.WebView;
35import android.widget.FrameLayout;
36import android.widget.RelativeLayout;
37
38
39/**
40 * Base class for a title bar used by the browser.
41 */
42public 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