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