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