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