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