PhoneUi.java revision ce8bcb0d8fff390451e9c95acd89cc2bbe0f66f7
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 bm = menu.findItem(R.id.bookmarks_menu_id); 198 if (bm != null) { 199 String url = tab.getUrl(); 200 boolean isDataUrl = DataUri.isDataUri(url); 201 bm.setVisible(!showingNavScreen() && !isDataUrl); 202 } 203 MenuItem nt = menu.findItem(R.id.new_tab_menu_id); 204 if (nt != null) { 205 nt.setVisible(!showingNavScreen()); 206 } 207 MenuItem abm = menu.findItem(R.id.add_bookmark_menu_id); 208 if (abm != null) { 209 abm.setVisible((tab != null) && !tab.isSnapshot() && !showingNavScreen()); 210 } 211 if (showingNavScreen()) { 212 menu.setGroupVisible(R.id.LIVE_MENU, false); 213 menu.setGroupVisible(R.id.SNAPSHOT_MENU, false); 214 menu.findItem(R.id.page_info_menu_id).setVisible(false); 215 menu.setGroupVisible(R.id.NAV_MENU, false); 216 } 217 } 218 219 @Override 220 public boolean onOptionsItemSelected(MenuItem item) { 221 if (showingNavScreen()) { 222 hideNavScreen(mUiController.getTabControl().getCurrentPosition(), false); 223 } 224 return false; 225 } 226 227 @Override 228 public void onContextMenuCreated(Menu menu) { 229 hideTitleBar(); 230 } 231 232 @Override 233 public void onContextMenuClosed(Menu menu, boolean inLoad) { 234 if (inLoad) { 235 showTitleBar(); 236 } 237 } 238 239 // action mode callbacks 240 241 @Override 242 public void onActionModeStarted(ActionMode mode) { 243 if (!isEditingUrl()) { 244 hideTitleBar(); 245 } else { 246 mTitleBar.animate().translationY(mActionBarHeight); 247 } 248 } 249 250 @Override 251 public void onActionModeFinished(boolean inLoad) { 252 mTitleBar.animate().translationY(0); 253 if (inLoad) { 254 if (mUseQuickControls) { 255 mTitleBar.setShowProgressOnly(true); 256 } 257 showTitleBar(); 258 } 259 } 260 261 @Override 262 protected void setTitleGravity(int gravity) { 263 if (mUseQuickControls) { 264 FrameLayout.LayoutParams lp = 265 (FrameLayout.LayoutParams) mTitleBar.getLayoutParams(); 266 lp.gravity = gravity; 267 mTitleBar.setLayoutParams(lp); 268 } else { 269 super.setTitleGravity(gravity); 270 } 271 } 272 273 @Override 274 public void setUseQuickControls(boolean useQuickControls) { 275 mUseQuickControls = useQuickControls; 276 mTitleBar.setUseQuickControls(mUseQuickControls); 277 if (useQuickControls) { 278 mPieControl = new PieControlPhone(mActivity, mUiController, this); 279 mPieControl.attachToContainer(mContentView); 280 WebView web = getWebView(); 281 if (web != null) { 282 web.setEmbeddedTitleBar(null); 283 } 284 } else { 285 if (mPieControl != null) { 286 mPieControl.removeFromContainer(mContentView); 287 } 288 WebView web = getWebView(); 289 if (web != null) { 290 // make sure we can re-parent titlebar 291 if ((mTitleBar != null) && (mTitleBar.getParent() != null)) { 292 ((ViewGroup) mTitleBar.getParent()).removeView(mTitleBar); 293 } 294 web.setEmbeddedTitleBar(mTitleBar); 295 } 296 setTitleGravity(Gravity.NO_GRAVITY); 297 } 298 updateUrlBarAutoShowManagerTarget(); 299 } 300 301 @Override 302 public boolean isWebShowing() { 303 return super.isWebShowing() && !showingNavScreen(); 304 } 305 306 @Override 307 public void showWeb(boolean animate) { 308 super.showWeb(animate); 309 hideNavScreen(mUiController.getTabControl().getCurrentPosition(), animate); 310 } 311 312 void showNavScreen() { 313 mUiController.setBlockEvents(true); 314 if (mNavScreen == null) { 315 mNavScreen = new NavScreen(mActivity, mUiController, this); 316 mCustomViewContainer.addView(mNavScreen, COVER_SCREEN_PARAMS); 317 } else { 318 mNavScreen.setVisibility(View.VISIBLE); 319 mNavScreen.setAlpha(1f); 320 mNavScreen.refreshAdapter(); 321 } 322 mActiveTab.capture(); 323 if (mAnimScreen == null) { 324 mAnimScreen = new AnimScreen(mActivity); 325 } else { 326 mAnimScreen.mMain.setAlpha(1f); 327 mAnimScreen.mTitle.setAlpha(1f); 328 mAnimScreen.setScaleFactor(1f); 329 } 330 mAnimScreen.set(getTitleBar(), getWebView()); 331 mCustomViewContainer.addView(mAnimScreen.mMain, COVER_SCREEN_PARAMS); 332 mCustomViewContainer.setVisibility(View.VISIBLE); 333 mCustomViewContainer.bringToFront(); 334 mAnimScreen.mMain.layout(0, 0, mContentView.getWidth(), 335 mContentView.getHeight()); 336 int fromLeft = 0; 337 int fromTop = getTitleBar().getHeight(); 338 int fromRight = mContentView.getWidth(); 339 int fromBottom = mContentView.getHeight(); 340 int width = mActivity.getResources().getDimensionPixelSize(R.dimen.nav_tab_width); 341 int height = mActivity.getResources().getDimensionPixelSize(R.dimen.nav_tab_height); 342 int ntth = mActivity.getResources().getDimensionPixelSize(R.dimen.nav_tab_titleheight); 343 int toLeft = (mContentView.getWidth() - width) / 2; 344 int toTop = ((fromBottom - (ntth + height)) / 2 + ntth); 345 int toRight = toLeft + width; 346 int toBottom = toTop + height; 347 float scaleFactor = width / (float) mContentView.getWidth(); 348 detachTab(mActiveTab); 349 mContentView.setVisibility(View.GONE); 350 AnimatorSet set1 = new AnimatorSet(); 351 AnimatorSet inanim = new AnimatorSet(); 352 ObjectAnimator tx = ObjectAnimator.ofInt(mAnimScreen.mContent, "left", 353 fromLeft, toLeft); 354 ObjectAnimator ty = ObjectAnimator.ofInt(mAnimScreen.mContent, "top", 355 fromTop, toTop); 356 ObjectAnimator tr = ObjectAnimator.ofInt(mAnimScreen.mContent, "right", 357 fromRight, toRight); 358 ObjectAnimator tb = ObjectAnimator.ofInt(mAnimScreen.mContent, "bottom", 359 fromBottom, toBottom); 360 ObjectAnimator title = ObjectAnimator.ofFloat(mAnimScreen.mTitle, "alpha", 361 1f, 0f); 362 ObjectAnimator sx = ObjectAnimator.ofFloat(mAnimScreen, "scaleFactor", 363 1f, scaleFactor); 364 ObjectAnimator blend1 = ObjectAnimator.ofFloat(mAnimScreen.mMain, 365 "alpha", 1f, 0f); 366 blend1.setDuration(100); 367 368 inanim.playTogether(tx, ty, tr, tb, sx, title); 369 inanim.setDuration(200); 370 set1.addListener(new AnimatorListenerAdapter() { 371 @Override 372 public void onAnimationEnd(Animator anim) { 373 mCustomViewContainer.removeView(mAnimScreen.mMain); 374 finishAnimationIn(); 375 mUiController.setBlockEvents(false); 376 } 377 }); 378 set1.playSequentially(inanim, blend1); 379 set1.start(); 380 } 381 382 private void finishAnimationIn() { 383 if (showingNavScreen()) { 384 // notify accessibility manager about the screen change 385 mNavScreen.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 386 mTabControl.setOnThumbnailUpdatedListener(mNavScreen); 387 } 388 } 389 390 void hideNavScreen(int position, boolean animate) { 391 if (!showingNavScreen()) return; 392 final Tab tab = mUiController.getTabControl().getTab(position); 393 if ((tab == null) || !animate) { 394 if (tab != null) { 395 setActiveTab(tab); 396 } else if (mTabControl.getTabCount() > 0) { 397 // use a fallback tab 398 setActiveTab(mTabControl.getCurrentTab()); 399 } 400 mContentView.setVisibility(View.VISIBLE); 401 finishAnimateOut(); 402 return; 403 } 404 NavTabView tabview = (NavTabView) mNavScreen.getTabView(position); 405 if (tabview == null) { 406 if (mTabControl.getTabCount() > 0) { 407 // use a fallback tab 408 setActiveTab(mTabControl.getCurrentTab()); 409 } 410 mContentView.setVisibility(View.VISIBLE); 411 finishAnimateOut(); 412 return; 413 } 414 mUiController.setBlockEvents(true); 415 mUiController.setActiveTab(tab); 416 mContentView.setVisibility(View.VISIBLE); 417 if (mAnimScreen == null) { 418 mAnimScreen = new AnimScreen(mActivity); 419 } 420 mAnimScreen.set(tab.getScreenshot()); 421 mCustomViewContainer.addView(mAnimScreen.mMain, COVER_SCREEN_PARAMS); 422 mAnimScreen.mMain.layout(0, 0, mContentView.getWidth(), 423 mContentView.getHeight()); 424 mNavScreen.mScroller.finishScroller(); 425 ImageView target = tabview.mImage; 426 int toLeft = 0; 427 int toTop = getTitleBar().getHeight(); 428 int toRight = mContentView.getWidth(); 429 int width = target.getDrawable().getIntrinsicWidth(); 430 int height = target.getDrawable().getIntrinsicHeight(); 431 int fromLeft = tabview.getLeft() + target.getLeft() - mNavScreen.mScroller.getScrollX(); 432 int fromTop = tabview.getTop() + target.getTop() - mNavScreen.mScroller.getScrollY(); 433 int fromRight = fromLeft + width; 434 int fromBottom = fromTop + height; 435 float scaleFactor = mContentView.getWidth() / (float) width; 436 int toBottom = toTop + (int) (height * scaleFactor); 437 mAnimScreen.mContent.setLeft(fromLeft); 438 mAnimScreen.mContent.setTop(fromTop); 439 mAnimScreen.mContent.setRight(fromRight); 440 mAnimScreen.mContent.setBottom(fromBottom); 441 mAnimScreen.setScaleFactor(1f); 442 AnimatorSet set1 = new AnimatorSet(); 443 ObjectAnimator fade2 = ObjectAnimator.ofFloat(mAnimScreen.mMain, "alpha", 0f, 1f); 444 ObjectAnimator fade1 = ObjectAnimator.ofFloat(mNavScreen, "alpha", 1f, 0f); 445 set1.playTogether(fade1, fade2); 446 set1.setDuration(100); 447 AnimatorSet set2 = new AnimatorSet(); 448 ObjectAnimator l = ObjectAnimator.ofInt(mAnimScreen.mContent, "left", 449 fromLeft, toLeft); 450 ObjectAnimator t = ObjectAnimator.ofInt(mAnimScreen.mContent, "top", 451 fromTop, toTop); 452 ObjectAnimator r = ObjectAnimator.ofInt(mAnimScreen.mContent, "right", 453 fromRight, toRight); 454 ObjectAnimator b = ObjectAnimator.ofInt(mAnimScreen.mContent, "bottom", 455 fromBottom, toBottom); 456 ObjectAnimator scale = ObjectAnimator.ofFloat(mAnimScreen, "scaleFactor", 457 1f, scaleFactor); 458 ObjectAnimator otheralpha = ObjectAnimator.ofFloat(mCustomViewContainer, "alpha", 1f, 0f); 459 otheralpha.setDuration(100); 460 set2.playTogether(l, t, r, b, scale); 461 set2.setDuration(200); 462 AnimatorSet combo = new AnimatorSet(); 463 combo.playSequentially(set1, set2, otheralpha); 464 combo.addListener(new AnimatorListenerAdapter() { 465 @Override 466 public void onAnimationEnd(Animator anim) { 467 mCustomViewContainer.removeView(mAnimScreen.mMain); 468 finishAnimateOut(); 469 mUiController.setBlockEvents(false); 470 } 471 }); 472 combo.start(); 473 } 474 475 private void finishAnimateOut() { 476 mTabControl.setOnThumbnailUpdatedListener(null); 477 mNavScreen.setVisibility(View.GONE); 478 mCustomViewContainer.setAlpha(1f); 479 mCustomViewContainer.setVisibility(View.GONE); 480 } 481 482 @Override 483 public boolean needsRestoreAllTabs() { 484 return false; 485 } 486 487 public void toggleNavScreen() { 488 if (!showingNavScreen()) { 489 showNavScreen(); 490 } else { 491 hideNavScreen(mUiController.getTabControl().getCurrentPosition(), false); 492 } 493 } 494 495 @Override 496 public boolean shouldCaptureThumbnails() { 497 return true; 498 } 499 500 static class AnimScreen { 501 502 private View mMain; 503 private ImageView mTitle; 504 private ImageView mContent; 505 private float mScale; 506 private Bitmap mTitleBarBitmap; 507 private Bitmap mContentBitmap; 508 509 public AnimScreen(Context ctx) { 510 mMain = LayoutInflater.from(ctx).inflate(R.layout.anim_screen, 511 null); 512 mTitle = (ImageView) mMain.findViewById(R.id.title); 513 mContent = (ImageView) mMain.findViewById(R.id.content); 514 mContent.setScaleType(ImageView.ScaleType.MATRIX); 515 mContent.setImageMatrix(new Matrix()); 516 mScale = 1.0f; 517 setScaleFactor(getScaleFactor()); 518 } 519 520 public void set(TitleBar tbar, WebView web) { 521 if (tbar.getWidth() > 0 && tbar.getEmbeddedHeight() > 0) { 522 if (mTitleBarBitmap == null 523 || mTitleBarBitmap.getWidth() != tbar.getWidth() 524 || mTitleBarBitmap.getHeight() != tbar.getEmbeddedHeight()) { 525 mTitleBarBitmap = Bitmap.createBitmap(tbar.getWidth(), 526 tbar.getEmbeddedHeight(), Bitmap.Config.RGB_565); 527 } 528 Canvas c = new Canvas(mTitleBarBitmap); 529 tbar.draw(c); 530 c.setBitmap(null); 531 } else { 532 mTitleBarBitmap = null; 533 } 534 mTitle.setImageBitmap(mTitleBarBitmap); 535 mTitle.setVisibility(View.VISIBLE); 536 int h = web.getHeight() - tbar.getEmbeddedHeight(); 537 if (mContentBitmap == null 538 || mContentBitmap.getWidth() != web.getWidth() 539 || mContentBitmap.getHeight() != h) { 540 mContentBitmap = Bitmap.createBitmap(web.getWidth(), h, 541 Bitmap.Config.RGB_565); 542 } 543 Canvas c = new Canvas(mContentBitmap); 544 int tx = web.getScrollX(); 545 int ty = web.getScrollY(); 546 c.translate(-tx, -ty - tbar.getEmbeddedHeight()); 547 web.draw(c); 548 c.setBitmap(null); 549 mContent.setImageBitmap(mContentBitmap); 550 } 551 552 public void set(Bitmap image) { 553 mTitle.setVisibility(View.GONE); 554 mContent.setImageBitmap(image); 555 } 556 557 private void setScaleFactor(float sf) { 558 mScale = sf; 559 Matrix m = new Matrix(); 560 m.postScale(sf,sf); 561 mContent.setImageMatrix(m); 562 } 563 564 private float getScaleFactor() { 565 return mScale; 566 } 567 568 } 569 570} 571