PhoneUi.java revision 4d2fcaba7fb8eb1723943ac9a10e76d509330bd1
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.AnimatorListenerAdapter; 21import android.animation.AnimatorSet; 22import android.animation.ObjectAnimator; 23import android.app.Activity; 24import android.content.Context; 25import android.graphics.Bitmap; 26import android.graphics.Canvas; 27import android.graphics.Matrix; 28import android.os.Message; 29import android.util.Log; 30import android.util.TypedValue; 31import android.view.ActionMode; 32import android.view.Gravity; 33import android.view.KeyEvent; 34import android.view.LayoutInflater; 35import android.view.Menu; 36import android.view.MenuItem; 37import android.view.View; 38import android.view.ViewGroup; 39import android.view.accessibility.AccessibilityEvent; 40import android.webkit.WebView; 41import android.webkit.WebViewClassic; 42import android.widget.FrameLayout; 43import android.widget.ImageView; 44 45import com.android.browser.UrlInputView.StateListener; 46 47/** 48 * Ui for regular phone screen sizes 49 */ 50public class PhoneUi extends BaseUi { 51 52 private static final String LOGTAG = "PhoneUi"; 53 private static final int MSG_INIT_NAVSCREEN = 100; 54 55 private PieControlPhone mPieControl; 56 private NavScreen mNavScreen; 57 private AnimScreen mAnimScreen; 58 private NavigationBarPhone mNavigationBar; 59 private int mActionBarHeight; 60 61 boolean mExtendedMenuOpen; 62 boolean mOptionsMenuOpen; 63 boolean mAnimating; 64 65 /** 66 * @param browser 67 * @param controller 68 */ 69 public PhoneUi(Activity browser, UiController controller) { 70 super(browser, controller); 71 setUseQuickControls(BrowserSettings.getInstance().useQuickControls()); 72 mNavigationBar = (NavigationBarPhone) mTitleBar.getNavigationBar(); 73 TypedValue heightValue = new TypedValue(); 74 browser.getTheme().resolveAttribute( 75 com.android.internal.R.attr.actionBarSize, heightValue, true); 76 mActionBarHeight = TypedValue.complexToDimensionPixelSize(heightValue.data, 77 browser.getResources().getDisplayMetrics()); 78 } 79 80 @Override 81 public void onDestroy() { 82 hideTitleBar(); 83 } 84 85 @Override 86 public void editUrl(boolean clearInput) { 87 if (mUseQuickControls) { 88 mTitleBar.setShowProgressOnly(false); 89 } 90 super.editUrl(clearInput); 91 } 92 93 @Override 94 public boolean onBackKey() { 95 if (showingNavScreen()) { 96 mNavScreen.close(mUiController.getTabControl().getCurrentPosition()); 97 return true; 98 } 99 return super.onBackKey(); 100 } 101 102 private boolean showingNavScreen() { 103 return mNavScreen != null && mNavScreen.getVisibility() == View.VISIBLE; 104 } 105 106 @Override 107 public boolean dispatchKey(int code, KeyEvent event) { 108 return false; 109 } 110 111 @Override 112 public void onProgressChanged(Tab tab) { 113 if (tab.inForeground()) { 114 int progress = tab.getLoadProgress(); 115 mTitleBar.setProgress(progress); 116 if (progress == 100) { 117 if (!mOptionsMenuOpen || !mExtendedMenuOpen) { 118 suggestHideTitleBar(); 119 if (mUseQuickControls) { 120 mTitleBar.setShowProgressOnly(false); 121 } 122 } 123 } else { 124 if (!mOptionsMenuOpen || mExtendedMenuOpen) { 125 if (mUseQuickControls && !mTitleBar.isEditingUrl()) { 126 mTitleBar.setShowProgressOnly(true); 127 setTitleGravity(Gravity.TOP); 128 } 129 showTitleBar(); 130 } 131 } 132 } 133 if (mNavScreen == null && getTitleBar().getHeight() > 0) { 134 mHandler.sendEmptyMessage(MSG_INIT_NAVSCREEN); 135 } 136 } 137 138 @Override 139 protected void handleMessage(Message msg) { 140 super.handleMessage(msg); 141 if (msg.what == MSG_INIT_NAVSCREEN) { 142 if (mNavScreen == null) { 143 mNavScreen = new NavScreen(mActivity, mUiController, this); 144 mCustomViewContainer.addView(mNavScreen, COVER_SCREEN_PARAMS); 145 mNavScreen.setVisibility(View.GONE); 146 } 147 if (mAnimScreen == null) { 148 mAnimScreen = new AnimScreen(mActivity); 149 // initialize bitmaps 150 mAnimScreen.set(getTitleBar(), getWebView()); 151 } 152 } 153 } 154 155 @Override 156 public void setActiveTab(final Tab tab) { 157 mTitleBar.cancelTitleBarAnimation(true); 158 mTitleBar.setSkipTitleBarAnimations(true); 159 super.setActiveTab(tab); 160 BrowserWebView view = (BrowserWebView) tab.getWebView(); 161 // TabControl.setCurrentTab has been called before this, 162 // so the tab is guaranteed to have a webview 163 if (view == null) { 164 Log.e(LOGTAG, "active tab with no webview detected"); 165 return; 166 } 167 // Request focus on the top window. 168 if (mUseQuickControls) { 169 mPieControl.forceToTop(mContentView); 170 } else { 171 // check if title bar is already attached by animation 172 if (mTitleBar.getParent() == null) { 173 WebViewClassic.fromWebView(view).setEmbeddedTitleBar(mTitleBar); 174 } 175 } 176 if (tab.isInVoiceSearchMode()) { 177 showVoiceTitleBar(tab.getVoiceDisplayTitle(), tab.getVoiceSearchResults()); 178 } else { 179 revertVoiceTitleBar(tab); 180 } 181 // update nav bar state 182 mNavigationBar.onStateChanged(StateListener.STATE_NORMAL); 183 updateLockIconToLatest(tab); 184 tab.getTopWindow().requestFocus(); 185 mTitleBar.setSkipTitleBarAnimations(false); 186 } 187 188 // menu handling callbacks 189 190 @Override 191 public boolean onPrepareOptionsMenu(Menu menu) { 192 updateMenuState(mActiveTab, menu); 193 return true; 194 } 195 196 @Override 197 public void updateMenuState(Tab tab, Menu menu) { 198 MenuItem bm = menu.findItem(R.id.bookmarks_menu_id); 199 if (bm != null) { 200 bm.setVisible(!showingNavScreen()); 201 } 202 MenuItem abm = menu.findItem(R.id.add_bookmark_menu_id); 203 if (abm != null) { 204 abm.setVisible((tab != null) && !tab.isSnapshot() && !showingNavScreen()); 205 } 206 MenuItem info = menu.findItem(R.id.page_info_menu_id); 207 if (info != null) { 208 info.setVisible(false); 209 } 210 MenuItem newtab = menu.findItem(R.id.new_tab_menu_id); 211 if (newtab != null && !mUseQuickControls) { 212 newtab.setVisible(false); 213 } 214 MenuItem incognito = menu.findItem(R.id.incognito_menu_id); 215 if (incognito != null) { 216 incognito.setVisible(showingNavScreen() || mUseQuickControls); 217 } 218 if (showingNavScreen()) { 219 menu.setGroupVisible(R.id.LIVE_MENU, false); 220 menu.setGroupVisible(R.id.SNAPSHOT_MENU, false); 221 menu.setGroupVisible(R.id.NAV_MENU, false); 222 menu.setGroupVisible(R.id.COMBO_MENU, true); 223 } 224 } 225 226 @Override 227 public boolean onOptionsItemSelected(MenuItem item) { 228 if (showingNavScreen() 229 && (item.getItemId() != R.id.history_menu_id) 230 && (item.getItemId() != R.id.snapshots_menu_id)) { 231 hideNavScreen(mUiController.getTabControl().getCurrentPosition(), false); 232 } 233 return false; 234 } 235 236 @Override 237 public void onContextMenuCreated(Menu menu) { 238 hideTitleBar(); 239 } 240 241 @Override 242 public void onContextMenuClosed(Menu menu, boolean inLoad) { 243 if (inLoad) { 244 showTitleBar(); 245 } 246 } 247 248 // action mode callbacks 249 250 @Override 251 public void onActionModeStarted(ActionMode mode) { 252 if (!isEditingUrl()) { 253 hideTitleBar(); 254 } else { 255 mTitleBar.animate().translationY(mActionBarHeight); 256 } 257 } 258 259 @Override 260 public void onActionModeFinished(boolean inLoad) { 261 mTitleBar.animate().translationY(0); 262 if (inLoad) { 263 if (mUseQuickControls) { 264 mTitleBar.setShowProgressOnly(true); 265 } 266 showTitleBar(); 267 } 268 } 269 270 @Override 271 protected void setTitleGravity(int gravity) { 272 if (mUseQuickControls) { 273 FrameLayout.LayoutParams lp = 274 (FrameLayout.LayoutParams) mTitleBar.getLayoutParams(); 275 lp.gravity = gravity; 276 mTitleBar.setLayoutParams(lp); 277 } else { 278 super.setTitleGravity(gravity); 279 } 280 } 281 282 @Override 283 public void setUseQuickControls(boolean useQuickControls) { 284 mUseQuickControls = useQuickControls; 285 mTitleBar.setUseQuickControls(mUseQuickControls); 286 if (useQuickControls) { 287 mPieControl = new PieControlPhone(mActivity, mUiController, this); 288 mPieControl.attachToContainer(mContentView); 289 WebView web = getWebView(); 290 if (web != null) { 291 WebViewClassic.fromWebView(web).setEmbeddedTitleBar(null); 292 } 293 } else { 294 if (mPieControl != null) { 295 mPieControl.removeFromContainer(mContentView); 296 } 297 WebView web = getWebView(); 298 if (web != null) { 299 // make sure we can re-parent titlebar 300 if ((mTitleBar != null) && (mTitleBar.getParent() != null)) { 301 ((ViewGroup) mTitleBar.getParent()).removeView(mTitleBar); 302 } 303 WebViewClassic.fromWebView(web).setEmbeddedTitleBar(mTitleBar); 304 } 305 setTitleGravity(Gravity.NO_GRAVITY); 306 } 307 updateUrlBarAutoShowManagerTarget(); 308 } 309 310 @Override 311 public boolean isWebShowing() { 312 return super.isWebShowing() && !showingNavScreen(); 313 } 314 315 @Override 316 public void showWeb(boolean animate) { 317 super.showWeb(animate); 318 hideNavScreen(mUiController.getTabControl().getCurrentPosition(), animate); 319 } 320 321 void showNavScreen() { 322 mUiController.setBlockEvents(true); 323 if (mNavScreen == null) { 324 mNavScreen = new NavScreen(mActivity, mUiController, this); 325 mCustomViewContainer.addView(mNavScreen, COVER_SCREEN_PARAMS); 326 } else { 327 mNavScreen.setVisibility(View.VISIBLE); 328 mNavScreen.setAlpha(1f); 329 mNavScreen.refreshAdapter(); 330 } 331 mActiveTab.capture(); 332 if (mAnimScreen == null) { 333 mAnimScreen = new AnimScreen(mActivity); 334 } else { 335 mAnimScreen.mMain.setAlpha(1f); 336 mAnimScreen.mTitle.setAlpha(1f); 337 mAnimScreen.setScaleFactor(1f); 338 } 339 mAnimScreen.set(getTitleBar(), getWebView()); 340 if (mAnimScreen.mMain.getParent() == null) { 341 mCustomViewContainer.addView(mAnimScreen.mMain, COVER_SCREEN_PARAMS); 342 } 343 mCustomViewContainer.setVisibility(View.VISIBLE); 344 mCustomViewContainer.bringToFront(); 345 mAnimScreen.mMain.layout(0, 0, mContentView.getWidth(), 346 mContentView.getHeight()); 347 int fromLeft = 0; 348 int fromTop = getTitleBar().getHeight(); 349 int fromRight = mContentView.getWidth(); 350 int fromBottom = mContentView.getHeight(); 351 int width = mActivity.getResources().getDimensionPixelSize(R.dimen.nav_tab_width); 352 int height = mActivity.getResources().getDimensionPixelSize(R.dimen.nav_tab_height); 353 int ntth = mActivity.getResources().getDimensionPixelSize(R.dimen.nav_tab_titleheight); 354 int toLeft = (mContentView.getWidth() - width) / 2; 355 int toTop = ((fromBottom - (ntth + height)) / 2 + ntth); 356 int toRight = toLeft + width; 357 int toBottom = toTop + height; 358 float scaleFactor = width / (float) mContentView.getWidth(); 359 detachTab(mActiveTab); 360 mContentView.setVisibility(View.GONE); 361 AnimatorSet set1 = new AnimatorSet(); 362 AnimatorSet inanim = new AnimatorSet(); 363 ObjectAnimator tx = ObjectAnimator.ofInt(mAnimScreen.mContent, "left", 364 fromLeft, toLeft); 365 ObjectAnimator ty = ObjectAnimator.ofInt(mAnimScreen.mContent, "top", 366 fromTop, toTop); 367 ObjectAnimator tr = ObjectAnimator.ofInt(mAnimScreen.mContent, "right", 368 fromRight, toRight); 369 ObjectAnimator tb = ObjectAnimator.ofInt(mAnimScreen.mContent, "bottom", 370 fromBottom, toBottom); 371 ObjectAnimator title = ObjectAnimator.ofFloat(mAnimScreen.mTitle, "alpha", 372 1f, 0f); 373 ObjectAnimator sx = ObjectAnimator.ofFloat(mAnimScreen, "scaleFactor", 374 1f, scaleFactor); 375 ObjectAnimator blend1 = ObjectAnimator.ofFloat(mAnimScreen.mMain, 376 "alpha", 1f, 0f); 377 blend1.setDuration(100); 378 379 inanim.playTogether(tx, ty, tr, tb, sx, title); 380 inanim.setDuration(200); 381 set1.addListener(new AnimatorListenerAdapter() { 382 @Override 383 public void onAnimationEnd(Animator anim) { 384 mCustomViewContainer.removeView(mAnimScreen.mMain); 385 finishAnimationIn(); 386 mUiController.setBlockEvents(false); 387 } 388 }); 389 set1.playSequentially(inanim, blend1); 390 set1.start(); 391 } 392 393 private void finishAnimationIn() { 394 if (showingNavScreen()) { 395 // notify accessibility manager about the screen change 396 mNavScreen.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 397 mTabControl.setOnThumbnailUpdatedListener(mNavScreen); 398 } 399 } 400 401 void hideNavScreen(int position, boolean animate) { 402 if (!showingNavScreen()) return; 403 final Tab tab = mUiController.getTabControl().getTab(position); 404 if ((tab == null) || !animate) { 405 if (tab != null) { 406 setActiveTab(tab); 407 } else if (mTabControl.getTabCount() > 0) { 408 // use a fallback tab 409 setActiveTab(mTabControl.getCurrentTab()); 410 } 411 mContentView.setVisibility(View.VISIBLE); 412 finishAnimateOut(); 413 return; 414 } 415 NavTabView tabview = (NavTabView) mNavScreen.getTabView(position); 416 if (tabview == null) { 417 if (mTabControl.getTabCount() > 0) { 418 // use a fallback tab 419 setActiveTab(mTabControl.getCurrentTab()); 420 } 421 mContentView.setVisibility(View.VISIBLE); 422 finishAnimateOut(); 423 return; 424 } 425 mUiController.setBlockEvents(true); 426 mUiController.setActiveTab(tab); 427 mContentView.setVisibility(View.VISIBLE); 428 if (mAnimScreen == null) { 429 mAnimScreen = new AnimScreen(mActivity); 430 } 431 mAnimScreen.set(tab.getScreenshot()); 432 if (mAnimScreen.mMain.getParent() == null) { 433 mCustomViewContainer.addView(mAnimScreen.mMain, COVER_SCREEN_PARAMS); 434 } 435 mAnimScreen.mMain.layout(0, 0, mContentView.getWidth(), 436 mContentView.getHeight()); 437 mNavScreen.mScroller.finishScroller(); 438 ImageView target = tabview.mImage; 439 int toLeft = 0; 440 int toTop = (tab.getWebView() != null) ? tab.getWebView().getVisibleTitleHeight() : 0; 441 int toRight = mContentView.getWidth(); 442 int width = target.getDrawable().getIntrinsicWidth(); 443 int height = target.getDrawable().getIntrinsicHeight(); 444 int fromLeft = tabview.getLeft() + target.getLeft() - mNavScreen.mScroller.getScrollX(); 445 int fromTop = tabview.getTop() + target.getTop() - mNavScreen.mScroller.getScrollY(); 446 int fromRight = fromLeft + width; 447 int fromBottom = fromTop + height; 448 float scaleFactor = mContentView.getWidth() / (float) width; 449 int toBottom = toTop + (int) (height * scaleFactor); 450 mAnimScreen.mContent.setLeft(fromLeft); 451 mAnimScreen.mContent.setTop(fromTop); 452 mAnimScreen.mContent.setRight(fromRight); 453 mAnimScreen.mContent.setBottom(fromBottom); 454 mAnimScreen.setScaleFactor(1f); 455 AnimatorSet set1 = new AnimatorSet(); 456 ObjectAnimator fade2 = ObjectAnimator.ofFloat(mAnimScreen.mMain, "alpha", 0f, 1f); 457 ObjectAnimator fade1 = ObjectAnimator.ofFloat(mNavScreen, "alpha", 1f, 0f); 458 set1.playTogether(fade1, fade2); 459 set1.setDuration(100); 460 AnimatorSet set2 = new AnimatorSet(); 461 ObjectAnimator l = ObjectAnimator.ofInt(mAnimScreen.mContent, "left", 462 fromLeft, toLeft); 463 ObjectAnimator t = ObjectAnimator.ofInt(mAnimScreen.mContent, "top", 464 fromTop, toTop); 465 ObjectAnimator r = ObjectAnimator.ofInt(mAnimScreen.mContent, "right", 466 fromRight, toRight); 467 ObjectAnimator b = ObjectAnimator.ofInt(mAnimScreen.mContent, "bottom", 468 fromBottom, toBottom); 469 ObjectAnimator scale = ObjectAnimator.ofFloat(mAnimScreen, "scaleFactor", 470 1f, scaleFactor); 471 ObjectAnimator otheralpha = ObjectAnimator.ofFloat(mCustomViewContainer, "alpha", 1f, 0f); 472 otheralpha.setDuration(100); 473 set2.playTogether(l, t, r, b, scale); 474 set2.setDuration(200); 475 AnimatorSet combo = new AnimatorSet(); 476 combo.playSequentially(set1, set2, otheralpha); 477 combo.addListener(new AnimatorListenerAdapter() { 478 @Override 479 public void onAnimationEnd(Animator anim) { 480 mCustomViewContainer.removeView(mAnimScreen.mMain); 481 finishAnimateOut(); 482 mUiController.setBlockEvents(false); 483 } 484 }); 485 combo.start(); 486 } 487 488 private void finishAnimateOut() { 489 mTabControl.setOnThumbnailUpdatedListener(null); 490 mNavScreen.setVisibility(View.GONE); 491 mCustomViewContainer.setAlpha(1f); 492 mCustomViewContainer.setVisibility(View.GONE); 493 } 494 495 @Override 496 public boolean needsRestoreAllTabs() { 497 return false; 498 } 499 500 public void toggleNavScreen() { 501 if (!showingNavScreen()) { 502 showNavScreen(); 503 } else { 504 hideNavScreen(mUiController.getTabControl().getCurrentPosition(), false); 505 } 506 } 507 508 @Override 509 public boolean shouldCaptureThumbnails() { 510 return true; 511 } 512 513 static class AnimScreen { 514 515 private View mMain; 516 private ImageView mTitle; 517 private ImageView mContent; 518 private float mScale; 519 private Bitmap mTitleBarBitmap; 520 private Bitmap mContentBitmap; 521 522 public AnimScreen(Context ctx) { 523 mMain = LayoutInflater.from(ctx).inflate(R.layout.anim_screen, 524 null); 525 mTitle = (ImageView) mMain.findViewById(R.id.title); 526 mContent = (ImageView) mMain.findViewById(R.id.content); 527 mContent.setScaleType(ImageView.ScaleType.MATRIX); 528 mContent.setImageMatrix(new Matrix()); 529 mScale = 1.0f; 530 setScaleFactor(getScaleFactor()); 531 } 532 533 public void set(TitleBar tbar, WebView web) { 534 if (tbar == null || web == null) { 535 return; 536 } 537 if (tbar.getWidth() > 0 && tbar.getEmbeddedHeight() > 0) { 538 if (mTitleBarBitmap == null 539 || mTitleBarBitmap.getWidth() != tbar.getWidth() 540 || mTitleBarBitmap.getHeight() != tbar.getEmbeddedHeight()) { 541 mTitleBarBitmap = safeCreateBitmap(tbar.getWidth(), 542 tbar.getEmbeddedHeight()); 543 } 544 if (mTitleBarBitmap != null) { 545 Canvas c = new Canvas(mTitleBarBitmap); 546 tbar.draw(c); 547 c.setBitmap(null); 548 } 549 } else { 550 mTitleBarBitmap = null; 551 } 552 mTitle.setImageBitmap(mTitleBarBitmap); 553 mTitle.setVisibility(View.VISIBLE); 554 int h = web.getHeight() - tbar.getEmbeddedHeight(); 555 if (mContentBitmap == null 556 || mContentBitmap.getWidth() != web.getWidth() 557 || mContentBitmap.getHeight() != h) { 558 mContentBitmap = safeCreateBitmap(web.getWidth(), h); 559 } 560 if (mContentBitmap != null) { 561 Canvas c = new Canvas(mContentBitmap); 562 int tx = web.getScrollX(); 563 int ty = web.getScrollY(); 564 c.translate(-tx, -ty - tbar.getEmbeddedHeight()); 565 web.draw(c); 566 c.setBitmap(null); 567 } 568 mContent.setImageBitmap(mContentBitmap); 569 } 570 571 private Bitmap safeCreateBitmap(int width, int height) { 572 if (width <= 0 || height <= 0) { 573 Log.w(LOGTAG, "safeCreateBitmap failed! width: " + width 574 + ", height: " + height); 575 return null; 576 } 577 return Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); 578 } 579 580 public void set(Bitmap image) { 581 mTitle.setVisibility(View.GONE); 582 mContent.setImageBitmap(image); 583 } 584 585 private void setScaleFactor(float sf) { 586 mScale = sf; 587 Matrix m = new Matrix(); 588 m.postScale(sf,sf); 589 mContent.setImageMatrix(m); 590 } 591 592 private float getScaleFactor() { 593 return mScale; 594 } 595 596 } 597 598} 599