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 TitleBar(Context context, UiController controller, BaseUi ui, FrameLayout contentView)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 initLayout(Context context)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 inflateAutoLoginBar()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 inflateSnapshotBar()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 onConfigurationChanged(Configuration config)105 protected void onConfigurationChanged(Configuration config) { 106 super.onConfigurationChanged(config); 107 setFixedTitleBar(); 108 } 109 110 @Override onMeasure(int widthMeasureSpec, int heightMeasureSpec)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 setFixedTitleBar()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 getUi()143 public BaseUi getUi() { 144 return mBaseUi; 145 } 146 getUiController()147 public UiController getUiController() { 148 return mUiController; 149 } 150 setUseQuickControls(boolean use)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 setShowProgressOnly(boolean progress)161 void setShowProgressOnly(boolean progress) { 162 if (progress && !wantsToBeVisible()) { 163 mNavBar.setVisibility(View.GONE); 164 } else { 165 mNavBar.setVisibility(View.VISIBLE); 166 } 167 } 168 setSkipTitleBarAnimations(boolean skip)169 void setSkipTitleBarAnimations(boolean skip) { 170 mSkipTitleBarAnimations = skip; 171 } 172 setupTitleBarAnimator(Animator animator)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 show()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 hide()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 isShowing()222 boolean isShowing() { 223 return mShowing; 224 } 225 cancelTitleBarAnimation(boolean reset)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 getVisibleTitleHeight()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 */ setProgress(int newProgress)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 getEmbeddedHeight()297 public int getEmbeddedHeight() { 298 if (mUseQuickControls || mIsFixedTitleBar) return 0; 299 return calculateEmbeddedHeight(); 300 } 301 calculateEmbeddedHeight()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 updateAutoLogin(Tab tab, boolean animate)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 showAutoLogin(boolean animate)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 hideAutoLogin(boolean animate)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 wantsToBeVisible()366 public boolean wantsToBeVisible() { 367 return inAutoLogin() 368 || (mSnapshotBar != null && mSnapshotBar.getVisibility() == View.VISIBLE 369 && mSnapshotBar.isAnimating()); 370 } 371 inAutoLogin()372 private boolean inAutoLogin() { 373 return mAutoLogin != null && mAutoLogin.getVisibility() == View.VISIBLE; 374 } 375 isEditingUrl()376 public boolean isEditingUrl() { 377 return mNavBar.isEditingUrl(); 378 } 379 getCurrentWebView()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 getProgressView()389 public PageProgressView getProgressView() { 390 return mProgress; 391 } 392 getNavigationBar()393 public NavigationBarBase getNavigationBar() { 394 return mNavBar; 395 } 396 useQuickControls()397 public boolean useQuickControls() { 398 return mUseQuickControls; 399 } 400 isInLoad()401 public boolean isInLoad() { 402 return mInLoad; 403 } 404 makeLayoutParams()405 private ViewGroup.LayoutParams makeLayoutParams() { 406 return new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, 407 LayoutParams.WRAP_CONTENT); 408 } 409 410 @Override focusSearch(View focused, int dir)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 onTabDataChanged(Tab tab)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 onScrollChanged()437 public void onScrollChanged() { 438 if (!mShowing && !mIsFixedTitleBar) { 439 setTranslationY(getVisibleTitleHeight() - getEmbeddedHeight()); 440 } 441 } 442 onResume()443 public void onResume() { 444 setFixedTitleBar(); 445 } 446 447 } 448