OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package org.chromium.chrome.browser.compositor.bottombar.contextualsearch; |
| 6 |
| 7 import android.content.Context; |
| 8 |
| 9 import org.chromium.base.VisibleForTesting; |
| 10 import org.chromium.chrome.R; |
| 11 import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.Context
ualSearchPanel.PanelState; |
| 12 import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.Context
ualSearchPanel.StateChangeReason; |
| 13 import org.chromium.chrome.browser.util.MathUtils; |
| 14 |
| 15 /** |
| 16 * Base abstract class for the Contextual Search Panel. |
| 17 */ |
| 18 abstract class ContextualSearchPanelBase extends ContextualSearchPanelStateHandl
er { |
| 19 |
| 20 /** |
| 21 * The height of the expanded Contextual Search Panel relative to the height |
| 22 * of the screen. |
| 23 */ |
| 24 private static final float EXPANDED_PANEL_HEIGHT_PERCENTAGE = .7f; |
| 25 |
| 26 /** |
| 27 * The height of the Toolbar in dps. |
| 28 */ |
| 29 private static final float TOOLBAR_HEIGHT_DP = 56.f; |
| 30 |
| 31 /** |
| 32 * The height of the Contextual Search Panel's Shadow in dps. |
| 33 */ |
| 34 private static final float PANEL_SHADOW_HEIGHT_DP = 16.f; |
| 35 |
| 36 /** |
| 37 * The brightness of the base page when the Panel is peeking. |
| 38 */ |
| 39 private static final float BASE_PAGE_BRIGHTNESS_STATE_PEEKED = 1.f; |
| 40 |
| 41 /** |
| 42 * The brightness of the base page when the Panel is expanded. |
| 43 */ |
| 44 private static final float BASE_PAGE_BRIGHTNESS_STATE_EXPANDED = .7f; |
| 45 |
| 46 /** |
| 47 * The brightness of the base page when the Panel is maximized. |
| 48 */ |
| 49 private static final float BASE_PAGE_BRIGHTNESS_STATE_MAXIMIZED = .3f; |
| 50 |
| 51 /** |
| 52 * The opacity of the search provider icon when the Panel is peeking. |
| 53 */ |
| 54 private static final float SEARCH_PROVIDER_ICON_OPACITY_STATE_PEEKED = 1.f; |
| 55 |
| 56 /** |
| 57 * The opacity of the search provider icon when the Panel is expanded. |
| 58 */ |
| 59 private static final float SEARCH_PROVIDER_ICON_OPACITY_STATE_EXPANDED = 1.f
; |
| 60 |
| 61 /** |
| 62 * The opacity of the search provider icon when the Panel is maximized. |
| 63 */ |
| 64 private static final float SEARCH_PROVIDER_ICON_OPACITY_STATE_MAXIMIZED = 0.
f; |
| 65 |
| 66 /** |
| 67 * The opacity of the search icon when the Panel is peeking. |
| 68 */ |
| 69 private static final float SEARCH_ICON_OPACITY_PEEKED = 0.f; |
| 70 |
| 71 /** |
| 72 * The opacity of the search icon when the Panel is expanded. |
| 73 */ |
| 74 private static final float SEARCH_ICON_OPACITY_EXPANDED = 0.f; |
| 75 |
| 76 /** |
| 77 * The opacity of the search icon when the Panel is maximized. |
| 78 */ |
| 79 private static final float SEARCH_ICON_OPACITY_MAXIMIZED = 1.f; |
| 80 |
| 81 /** |
| 82 * The margin top of the Contextual Search Bar in dps. |
| 83 */ |
| 84 private static final float SEARCH_BAR_MARGIN_TOP_DP = 16.f; |
| 85 |
| 86 /** |
| 87 * The padding left of the Search Icon in dps. |
| 88 */ |
| 89 private static final float SEARCH_ICON_PADDING_LEFT_DP = 16.f; |
| 90 |
| 91 /** |
| 92 * The height of the promo state Contextual Search Panel search bar, in dps. |
| 93 */ |
| 94 private static final float SEARCH_BAR_HEIGHT_STATE_PROMO = 24.f; |
| 95 |
| 96 /** |
| 97 * How much the Promo Panel should displace in order to make some elements |
| 98 * invisible (like the Search Provider Icon and the Search Bar Text). |
| 99 */ |
| 100 private static final float DISAPPEARING_ELEMENT_THRESHOLD_DP = 10.f; |
| 101 |
| 102 /** |
| 103 * The height of the Search Bar's border in dps. |
| 104 */ |
| 105 private static final float SEARCH_BAR_BORDER_HEIGHT_DP = 1.f; |
| 106 |
| 107 /** |
| 108 * The height of the Progress Bar in dps. |
| 109 */ |
| 110 private static final float PROGRESS_BAR_HEIGHT_DP = 2.f; |
| 111 |
| 112 /** |
| 113 * The distance from the Progress Bar must be away from the bottom of the |
| 114 * screen in order to be completely visible. The closer the Progress Bar |
| 115 * gets to the bottom of the screen, the lower its opacity will be. When the |
| 116 * Progress Bar is at the very bottom of the screen (when the Search Panel |
| 117 * is peeking) it will be completely invisible. |
| 118 */ |
| 119 private static final float PROGRESS_BAR_VISIBILITY_THRESHOLD_DP = 10.f; |
| 120 |
| 121 /** |
| 122 * The height of the Search Bar when the Panel is peeking, in dps. |
| 123 */ |
| 124 private final float mSearchBarHeightPeeking; |
| 125 |
| 126 /** |
| 127 * The height of the Search Bar when the Panel is displaying the Promo, in d
ps. |
| 128 */ |
| 129 private final float mSearchBarHeightPromo; |
| 130 |
| 131 /** |
| 132 * The height of the Search Bar when the Panel is expanded, in dps. |
| 133 */ |
| 134 private final float mSearchBarHeightExpanded; |
| 135 |
| 136 /** |
| 137 * The height of the Search Bar when the Panel is maximized, in dps. |
| 138 */ |
| 139 private final float mSearchBarHeightMaximized; |
| 140 |
| 141 /** |
| 142 * Ratio of dps per pixel. |
| 143 */ |
| 144 private final float mPxToDp; |
| 145 |
| 146 /** |
| 147 * The approximate Y coordinate of the selection in pixels. |
| 148 */ |
| 149 private float mBasePageSelectionYPx = -1.f; |
| 150 |
| 151 /** |
| 152 * The Y coordinate to apply to the Base Page in order to keep the selection |
| 153 * in view when the Search Panel is in its EXPANDED state. |
| 154 */ |
| 155 private float mBasePageTargetY = 0.f; |
| 156 |
| 157 /** |
| 158 * The Y coordinate to apply to the Base Page in order to keep the selection |
| 159 * in view when the Search Panel is in its PROMO state. |
| 160 */ |
| 161 private float mPromoBasePageTargetY = 0.f; |
| 162 |
| 163 /** |
| 164 * Whether the Panel is showing. |
| 165 */ |
| 166 private boolean mIsShowing; |
| 167 |
| 168 // =========================================================================
=================== |
| 169 // Constructor |
| 170 // =========================================================================
=================== |
| 171 |
| 172 /** |
| 173 * @param context The current Android {@link Context}. |
| 174 */ |
| 175 public ContextualSearchPanelBase(Context context) { |
| 176 mPxToDp = 1.f / context.getResources().getDisplayMetrics().density; |
| 177 |
| 178 mSearchBarHeightPeeking = context.getResources().getDimension( |
| 179 R.dimen.contextual_search_bar_height) * mPxToDp; |
| 180 mSearchBarHeightMaximized = TOOLBAR_HEIGHT_DP + PANEL_SHADOW_HEIGHT_DP; |
| 181 mSearchBarHeightExpanded = |
| 182 Math.round((mSearchBarHeightPeeking + mSearchBarHeightMaximized)
/ 2.f); |
| 183 mSearchBarHeightPromo = SEARCH_BAR_HEIGHT_STATE_PROMO + PANEL_SHADOW_HEI
GHT_DP; |
| 184 |
| 185 initializeUiState(); |
| 186 } |
| 187 |
| 188 // =========================================================================
=================== |
| 189 // Layout Integration |
| 190 // =========================================================================
=================== |
| 191 |
| 192 private float mLayoutWidth; |
| 193 private float mLayoutHeight; |
| 194 private boolean mIsToolbarShowing; |
| 195 |
| 196 /** |
| 197 * Called when the size of the view has changed. |
| 198 * |
| 199 * @param width The new width in dp. |
| 200 * @param height The new width in dp. |
| 201 * @param isToolbarShowing Whether the Toolbar is showing. |
| 202 */ |
| 203 public final void onSizeChanged(float width, float height, boolean isToolbar
Showing) { |
| 204 mLayoutWidth = width; |
| 205 mLayoutHeight = height; |
| 206 mIsToolbarShowing = isToolbarShowing; |
| 207 } |
| 208 |
| 209 /** |
| 210 * Returns the Y position of the Contextual Search Panel. |
| 211 * Layouts supporting Contextual Search should override this method. |
| 212 * |
| 213 * @return The current Y-position of the Contextual Search Panel. |
| 214 */ |
| 215 public float getContextualSearchPanelY() { |
| 216 return getFullscreenHeight() - mHeight; |
| 217 } |
| 218 |
| 219 /** |
| 220 * @param y The y coordinate. |
| 221 * @return The Y coordinate relative the fullscreen height. |
| 222 */ |
| 223 public float getFullscreenY(float y) { |
| 224 if (mIsToolbarShowing) { |
| 225 y += TOOLBAR_HEIGHT_DP / mPxToDp; |
| 226 } |
| 227 return y; |
| 228 } |
| 229 |
| 230 /** |
| 231 * @return Whether the Panel is showing. |
| 232 */ |
| 233 public boolean isShowing() { |
| 234 return mIsShowing; |
| 235 } |
| 236 |
| 237 /** |
| 238 * Starts showing the Panel. |
| 239 */ |
| 240 protected void startShowing() { |
| 241 mIsShowing = true; |
| 242 } |
| 243 |
| 244 /** |
| 245 * @return The fullscreen width. |
| 246 */ |
| 247 private float getFullscreenWidth() { |
| 248 return mLayoutWidth; |
| 249 } |
| 250 |
| 251 /** |
| 252 * @return The fullscreen height. |
| 253 */ |
| 254 private float getFullscreenHeight() { |
| 255 float height = mLayoutHeight; |
| 256 // NOTE(pedrosimonetti): getHeight() only returns the content height |
| 257 // when the Toolbar is not showing. If we don't add the Toolbar height |
| 258 // here, there will be a "jump" when swiping the Search Panel around. |
| 259 // TODO(pedrosimonetti): Find better way to get the fullscreen height. |
| 260 if (mIsToolbarShowing) { |
| 261 height += TOOLBAR_HEIGHT_DP; |
| 262 } |
| 263 return height; |
| 264 } |
| 265 |
| 266 // =========================================================================
=================== |
| 267 // UI States |
| 268 // =========================================================================
=================== |
| 269 |
| 270 // -------------------------------------------------------------------------
------------------- |
| 271 // Test Infrastructure |
| 272 // -------------------------------------------------------------------------
------------------- |
| 273 |
| 274 /** |
| 275 * @param offsetY The vertical offset of the Contextual Search Panel to be |
| 276 * set. |
| 277 */ |
| 278 @VisibleForTesting |
| 279 public void setOffsetYForTesting(float offsetY) { |
| 280 mOffsetY = offsetY; |
| 281 } |
| 282 |
| 283 /** |
| 284 * @param isMaximized The setting for whether the Search Panel is fully |
| 285 * maximized. |
| 286 */ |
| 287 @VisibleForTesting |
| 288 public void setMaximizedForTesting(boolean isMaximized) { |
| 289 mIsMaximized = isMaximized; |
| 290 } |
| 291 |
| 292 /** |
| 293 * @param searchBarHeight The height of the Contextual Search Bar to be set. |
| 294 */ |
| 295 @VisibleForTesting |
| 296 public void setSearchBarHeightForTesting(float searchBarHeight) { |
| 297 mSearchBarHeight = searchBarHeight; |
| 298 } |
| 299 |
| 300 /** |
| 301 * @param searchBarBorderHeight The height of the Search Bar border to be |
| 302 * set. |
| 303 */ |
| 304 @VisibleForTesting |
| 305 public void setSearchBarBorderHeight(float searchBarBorderHeight) { |
| 306 mSearchBarBorderHeight = searchBarBorderHeight; |
| 307 } |
| 308 |
| 309 // -------------------------------------------------------------------------
------------------- |
| 310 // Contextual Search Panel states |
| 311 // -------------------------------------------------------------------------
------------------- |
| 312 |
| 313 private float mOffsetY; |
| 314 private float mHeight; |
| 315 private float mWidth; |
| 316 private boolean mIsMaximized; |
| 317 |
| 318 /** |
| 319 * @return The vertical offset of the Contextual Search Panel. |
| 320 */ |
| 321 public float getOffsetY() { |
| 322 return mOffsetY; |
| 323 } |
| 324 |
| 325 /** |
| 326 * @return The height of the Contextual Search Panel. |
| 327 */ |
| 328 public float getHeight() { |
| 329 return mHeight; |
| 330 } |
| 331 |
| 332 /** |
| 333 * @return The width of the Contextual Search Panel. |
| 334 */ |
| 335 public float getWidth() { |
| 336 return mWidth; |
| 337 } |
| 338 |
| 339 /** |
| 340 * @return Whether the Search Panel is fully maximized. |
| 341 */ |
| 342 public boolean isMaximized() { |
| 343 return mIsMaximized; |
| 344 } |
| 345 |
| 346 // -------------------------------------------------------------------------
------------------- |
| 347 // Contextual Search Bar states |
| 348 // -------------------------------------------------------------------------
------------------- |
| 349 |
| 350 private float mSearchBarMarginTop; |
| 351 private float mSearchBarHeight; |
| 352 private float mSearchBarTextOpacity; |
| 353 private boolean mIsSearchBarBorderVisible; |
| 354 private float mSearchBarBorderY; |
| 355 private float mSearchBarBorderHeight; |
| 356 private float mSearchProviderIconOpacity; |
| 357 private float mSearchIconPaddingLeft; |
| 358 private float mSearchIconOpacity; |
| 359 |
| 360 /** |
| 361 * @return The top margin of the Contextual Search Bar. |
| 362 */ |
| 363 public float getSearchBarMarginTop() { |
| 364 return mSearchBarMarginTop; |
| 365 } |
| 366 |
| 367 /** |
| 368 * @return The height of the Contextual Search Bar. |
| 369 */ |
| 370 public float getSearchBarHeight() { |
| 371 return mSearchBarHeight; |
| 372 } |
| 373 |
| 374 /** |
| 375 * @return The opacity of the Contextual Search Bar text. |
| 376 */ |
| 377 public float getSearchBarTextOpacity() { |
| 378 return mSearchBarTextOpacity; |
| 379 } |
| 380 |
| 381 /** |
| 382 * @return Whether the Search Bar border is visible. |
| 383 */ |
| 384 public boolean isSearchBarBorderVisible() { |
| 385 return mIsSearchBarBorderVisible; |
| 386 } |
| 387 |
| 388 /** |
| 389 * @return The Y coordinate of the Search Bar border. |
| 390 */ |
| 391 public float getSearchBarBorderY() { |
| 392 return mSearchBarBorderY; |
| 393 } |
| 394 |
| 395 /** |
| 396 * @return The height of the Search Bar border. |
| 397 */ |
| 398 public float getSearchBarBorderHeight() { |
| 399 return mSearchBarBorderHeight; |
| 400 } |
| 401 |
| 402 /** |
| 403 * @return The opacity of the search provider's icon. |
| 404 */ |
| 405 public float getSearchProviderIconOpacity() { |
| 406 return mSearchProviderIconOpacity; |
| 407 } |
| 408 |
| 409 /** |
| 410 * @return The left padding of the search icon. |
| 411 */ |
| 412 public float getSearchIconPaddingLeft() { |
| 413 return mSearchIconPaddingLeft; |
| 414 } |
| 415 |
| 416 /** |
| 417 * @return The opacity of the search icon. |
| 418 */ |
| 419 public float getSearchIconOpacity() { |
| 420 return mSearchIconOpacity; |
| 421 } |
| 422 |
| 423 // -------------------------------------------------------------------------
------------------- |
| 424 // Base Page states |
| 425 // -------------------------------------------------------------------------
------------------- |
| 426 |
| 427 private float mBasePageY; |
| 428 private float mBasePageBrightness; |
| 429 |
| 430 /** |
| 431 * @return The vertical offset of the base page. |
| 432 */ |
| 433 public float getBasePageY() { |
| 434 return mBasePageY; |
| 435 } |
| 436 |
| 437 /** |
| 438 * @return The brightness of the base page. |
| 439 */ |
| 440 public float getBasePageBrightness() { |
| 441 return mBasePageBrightness; |
| 442 } |
| 443 |
| 444 // -------------------------------------------------------------------------
------------------- |
| 445 // Progress Bar states |
| 446 // -------------------------------------------------------------------------
------------------- |
| 447 |
| 448 private float mProgressBarOpacity; |
| 449 private boolean mIsProgressBarVisible; |
| 450 private float mProgressBarY; |
| 451 private float mProgressBarHeight; |
| 452 private int mProgressBarCompletion; |
| 453 |
| 454 /** |
| 455 * @return Whether the Progress Bar is visible. |
| 456 */ |
| 457 public boolean isProgressBarVisible() { |
| 458 return mIsProgressBarVisible; |
| 459 } |
| 460 |
| 461 /** |
| 462 * @param isVisible Whether the Progress Bar should be visible. |
| 463 */ |
| 464 protected void setProgressBarVisible(boolean isVisible) { |
| 465 mIsProgressBarVisible = isVisible; |
| 466 } |
| 467 |
| 468 /** |
| 469 * @return The Y coordinate of the Progress Bar. |
| 470 */ |
| 471 public float getProgressBarY() { |
| 472 return mProgressBarY; |
| 473 } |
| 474 |
| 475 /** |
| 476 * @return The Progress Bar height. |
| 477 */ |
| 478 public float getProgressBarHeight() { |
| 479 return mProgressBarHeight; |
| 480 } |
| 481 |
| 482 /** |
| 483 * @return The Progress Bar opacity. |
| 484 */ |
| 485 public float getProgressBarOpacity() { |
| 486 return mProgressBarOpacity; |
| 487 } |
| 488 |
| 489 /** |
| 490 * @return The completion percentage of the Progress Bar. |
| 491 */ |
| 492 public int getProgressBarCompletion() { |
| 493 return mProgressBarCompletion; |
| 494 } |
| 495 |
| 496 /** |
| 497 * @param completion The completion percentage to be set. |
| 498 */ |
| 499 protected void setProgressBarCompletion(int completion) { |
| 500 mProgressBarCompletion = completion; |
| 501 } |
| 502 |
| 503 // -------------------------------------------------------------------------
------------------- |
| 504 // Promo states |
| 505 // -------------------------------------------------------------------------
------------------- |
| 506 |
| 507 private float mPromoContentHeight; |
| 508 private boolean mShouldHidePromoHeader; |
| 509 private static final float DEFAULT_PROMO_HEIGHT_DP = 250.f; |
| 510 |
| 511 /** |
| 512 * Sets the height of the promo content. |
| 513 */ |
| 514 protected void setPromoContentHeight(float height) { |
| 515 mPromoContentHeight = height; |
| 516 updateBasePageTargetY(); |
| 517 } |
| 518 |
| 519 /** |
| 520 * Gets the height of the promo content. |
| 521 */ |
| 522 public float getPromoContentHeight() { |
| 523 return mPromoContentHeight > 0.0f |
| 524 ? mPromoContentHeight : DEFAULT_PROMO_HEIGHT_DP; |
| 525 } |
| 526 |
| 527 /** |
| 528 * @param shouldHidePromoHeader Sets whether the promo's header should be hi
dden. |
| 529 */ |
| 530 protected void setShouldHidePromoHeader(boolean shouldHidePromoHeader) { |
| 531 mShouldHidePromoHeader = shouldHidePromoHeader; |
| 532 } |
| 533 |
| 534 /** |
| 535 * @return Gets whether the promo's header should be hidden. |
| 536 */ |
| 537 public boolean shouldHidePromoHeader() { |
| 538 return mShouldHidePromoHeader; |
| 539 } |
| 540 |
| 541 // =========================================================================
=================== |
| 542 // Helpers |
| 543 // =========================================================================
=================== |
| 544 |
| 545 /** |
| 546 * Initializes the UI state. |
| 547 */ |
| 548 private void initializeUiState() { |
| 549 mIsShowing = false; |
| 550 |
| 551 // Static values. |
| 552 mSearchBarMarginTop = SEARCH_BAR_MARGIN_TOP_DP; |
| 553 mSearchIconPaddingLeft = SEARCH_ICON_PADDING_LEFT_DP; |
| 554 mProgressBarHeight = PROGRESS_BAR_HEIGHT_DP; |
| 555 mSearchBarBorderHeight = SEARCH_BAR_BORDER_HEIGHT_DP; |
| 556 |
| 557 // Dynamic values. |
| 558 mSearchBarHeight = mSearchBarHeightPeeking; |
| 559 } |
| 560 |
| 561 /** |
| 562 * Gets the height of the Contextual Search Panel in dps for a given |
| 563 * |state|. |
| 564 * |
| 565 * @param state The state whose height will be calculated. |
| 566 * @return The height of the Contextual Search Panel in dps for a given |
| 567 * |state|. |
| 568 */ |
| 569 protected float getPanelHeightFromState(PanelState state) { |
| 570 float fullscreenHeight = getFullscreenHeight(); |
| 571 float panelHeight = 0; |
| 572 |
| 573 if (state == PanelState.UNDEFINED) { |
| 574 panelHeight = 0; |
| 575 } else if (state == PanelState.CLOSED) { |
| 576 panelHeight = 0; |
| 577 } else if (state == PanelState.PEEKED) { |
| 578 panelHeight = mSearchBarHeightPeeking; |
| 579 } else if (state == PanelState.PROMO) { |
| 580 panelHeight = getPromoContentHeight() |
| 581 + mSearchBarHeightPromo; |
| 582 } else if (state == PanelState.EXPANDED) { |
| 583 panelHeight = fullscreenHeight * EXPANDED_PANEL_HEIGHT_PERCENTAGE |
| 584 + PANEL_SHADOW_HEIGHT_DP; |
| 585 } else if (state == PanelState.MAXIMIZED) { |
| 586 panelHeight = fullscreenHeight + PANEL_SHADOW_HEIGHT_DP; |
| 587 } |
| 588 |
| 589 return panelHeight; |
| 590 } |
| 591 |
| 592 /** |
| 593 * Finds the state which has the nearest height compared to a given |
| 594 * |desiredPanelHeight|. |
| 595 * |
| 596 * @param desiredPanelHeight The height to compare to. |
| 597 * @return The nearest panel state. |
| 598 */ |
| 599 protected PanelState findNearestPanelStateFromHeight(float desiredPanelHeigh
t) { |
| 600 PanelState closestPanelState = PanelState.CLOSED; |
| 601 float smallestHeightDiff = Float.POSITIVE_INFINITY; |
| 602 |
| 603 // Iterate over all states and find the one which has the nearest |
| 604 // height. |
| 605 for (PanelState state : PanelState.values()) { |
| 606 if (!isValidState(state)) { |
| 607 continue; |
| 608 } |
| 609 |
| 610 float height = getPanelHeightFromState(state); |
| 611 float heightDiff = Math.abs(desiredPanelHeight - height); |
| 612 if (heightDiff < smallestHeightDiff) { |
| 613 closestPanelState = state; |
| 614 smallestHeightDiff = heightDiff; |
| 615 } |
| 616 } |
| 617 |
| 618 return closestPanelState; |
| 619 } |
| 620 |
| 621 /** |
| 622 * Sets the last panel height within the limits allowable by our UI. |
| 623 * |
| 624 * @param height The height of the panel in dps. |
| 625 */ |
| 626 protected void setClampedPanelHeight(float height) { |
| 627 final float clampedHeight = MathUtils.clamp(height, |
| 628 getPanelHeightFromState(getMaximumState()), |
| 629 getPanelHeightFromState(PanelState.PEEKED)); |
| 630 setPanelHeight(clampedHeight); |
| 631 } |
| 632 |
| 633 @Override |
| 634 protected void setPanelState(PanelState state, StateChangeReason reason) { |
| 635 super.setPanelState(state, reason); |
| 636 |
| 637 if (state == PanelState.CLOSED) { |
| 638 mIsShowing = false; |
| 639 } |
| 640 } |
| 641 |
| 642 /** |
| 643 * Sets the panel height. |
| 644 * |
| 645 * @param height The height of the panel in dps. |
| 646 */ |
| 647 protected void setPanelHeight(float height) { |
| 648 updatePanelForHeight(height); |
| 649 } |
| 650 |
| 651 /** |
| 652 * @param state The Panel state. |
| 653 * @return Whether the Panel height matches the one from the given state. |
| 654 */ |
| 655 protected boolean doesPanelHeightMatchState(PanelState state) { |
| 656 return state == getPanelState() && getHeight() == getPanelHeightFromStat
e(state); |
| 657 } |
| 658 |
| 659 // =========================================================================
=================== |
| 660 // UI Update Handling |
| 661 // =========================================================================
=================== |
| 662 |
| 663 /** |
| 664 * Updates the UI state for a given |height|. |
| 665 * |
| 666 * @param height The Contextual Search Panel height. |
| 667 */ |
| 668 private void updatePanelForHeight(float height) { |
| 669 PanelState endState = findLargestPanelStateFromHeight(height); |
| 670 PanelState startState = getPreviousPanelState(endState); |
| 671 float percentage = getStateCompletion(height, startState, endState); |
| 672 |
| 673 updatePanelSize(height, endState, percentage); |
| 674 |
| 675 if (endState == PanelState.CLOSED || endState == PanelState.PEEKED) { |
| 676 updatePanelForCloseOrPeek(percentage); |
| 677 } else if (endState == PanelState.EXPANDED) { |
| 678 updatePanelForExpansion(percentage); |
| 679 } else if (endState == PanelState.MAXIMIZED) { |
| 680 updatePanelForMaximization(percentage); |
| 681 } else if (endState == PanelState.PROMO) { |
| 682 updatePanelForOpeningPromo(percentage); |
| 683 } |
| 684 } |
| 685 |
| 686 /** |
| 687 * Updates the Panel size information. |
| 688 * |
| 689 * @param height The Contextual Search Panel height. |
| 690 * @param endState The final state of transition being executed. |
| 691 * @param percentage The completion percentage of the transition. |
| 692 */ |
| 693 private void updatePanelSize(float height, PanelState endState, float percen
tage) { |
| 694 mWidth = getFullscreenWidth(); |
| 695 mHeight = height; |
| 696 mOffsetY = getContextualSearchPanelY(); |
| 697 mIsMaximized = height == getPanelHeightFromState(PanelState.MAXIMIZED); |
| 698 } |
| 699 |
| 700 /** |
| 701 * Finds the largest Panel state which is being transitioned to/from. |
| 702 * Whenever the Panel is in between states, let's say, when resizing the |
| 703 * Panel from its peeked to expanded state, we need to know those two states |
| 704 * in order to calculate how closely we are from one of them. This method |
| 705 * will always return the nearest state with the largest height, and |
| 706 * together with the state preceding it, it's possible to calculate how far |
| 707 * the Panel is from them. |
| 708 * |
| 709 * @param panelHeight The height to compare to. |
| 710 * @return The panel state which is being transitioned to/from. |
| 711 */ |
| 712 private PanelState findLargestPanelStateFromHeight(float panelHeight) { |
| 713 PanelState stateFound = PanelState.CLOSED; |
| 714 |
| 715 // Iterate over all states and find the largest one which is being |
| 716 // transitioned to/from. |
| 717 for (PanelState state : PanelState.values()) { |
| 718 if (!isValidState(state)) { |
| 719 continue; |
| 720 } |
| 721 if (panelHeight <= getPanelHeightFromState(state)) { |
| 722 stateFound = state; |
| 723 break; |
| 724 } |
| 725 } |
| 726 |
| 727 return stateFound; |
| 728 } |
| 729 |
| 730 /** |
| 731 * Gets the state completion percentage, taking into consideration the |
| 732 * |height| of the Contextual Search Panel, and the initial and final |
| 733 * states. A completion of 0 means the Panel is in the initial state and a |
| 734 * completion of 1 means the Panel is in the final state. |
| 735 * |
| 736 * @param height The height of the Contextual Search Panel. |
| 737 * @param startState The initial state of the Panel. |
| 738 * @param endState The final state of the Panel. |
| 739 * @return The completion percentage. |
| 740 */ |
| 741 private float getStateCompletion(float height, PanelState startState, PanelS
tate endState) { |
| 742 float startSize = getPanelHeightFromState(startState); |
| 743 float endSize = getPanelHeightFromState(endState); |
| 744 float percentage = (height - startSize) / (endSize - startSize); |
| 745 return percentage; |
| 746 } |
| 747 |
| 748 /** |
| 749 * Updates the UI state for the closed to peeked transition (and vice |
| 750 * versa), according to a completion |percentage|. |
| 751 * |
| 752 * @param percentage The completion percentage. |
| 753 */ |
| 754 private void updatePanelForCloseOrPeek(float percentage) { |
| 755 // Base page offset. |
| 756 mBasePageY = 0.f; |
| 757 |
| 758 // Base page brightness. |
| 759 mBasePageBrightness = BASE_PAGE_BRIGHTNESS_STATE_PEEKED; |
| 760 |
| 761 // Search Bar height. |
| 762 mSearchBarHeight = mSearchBarHeightPeeking; |
| 763 |
| 764 // Search Bar border. |
| 765 mIsSearchBarBorderVisible = false; |
| 766 |
| 767 // Search Bar text opacity. |
| 768 mSearchBarTextOpacity = 1.f; |
| 769 |
| 770 // Search provider icon opacity. |
| 771 mSearchProviderIconOpacity = SEARCH_PROVIDER_ICON_OPACITY_STATE_PEEKED; |
| 772 |
| 773 // Search icon opacity. |
| 774 mSearchIconOpacity = SEARCH_ICON_OPACITY_PEEKED; |
| 775 |
| 776 // Progress Bar. |
| 777 mProgressBarOpacity = 0.f; |
| 778 } |
| 779 |
| 780 /** |
| 781 * Updates the UI state for the peeked to expanded transition (and vice |
| 782 * versa), according to a completion |percentage|. |
| 783 * |
| 784 * @param percentage The completion percentage. |
| 785 */ |
| 786 private void updatePanelForExpansion(float percentage) { |
| 787 // Base page offset. |
| 788 float baseBaseY = MathUtils.interpolate( |
| 789 0.f, |
| 790 getBasePageTargetY(), |
| 791 percentage); |
| 792 mBasePageY = baseBaseY; |
| 793 |
| 794 // Base page brightness. |
| 795 float brightness = MathUtils.interpolate( |
| 796 BASE_PAGE_BRIGHTNESS_STATE_PEEKED, |
| 797 BASE_PAGE_BRIGHTNESS_STATE_EXPANDED, |
| 798 percentage); |
| 799 mBasePageBrightness = brightness; |
| 800 |
| 801 // Search Bar height. |
| 802 float searchBarHeight = Math.round(MathUtils.interpolate( |
| 803 mSearchBarHeightPeeking, |
| 804 mSearchBarHeightExpanded, |
| 805 percentage)); |
| 806 mSearchBarHeight = searchBarHeight; |
| 807 |
| 808 // Search Bar text opacity. |
| 809 mSearchBarTextOpacity = 1.f; |
| 810 |
| 811 // Search Bar border. |
| 812 mIsSearchBarBorderVisible = true; |
| 813 mSearchBarBorderY = searchBarHeight - SEARCH_BAR_BORDER_HEIGHT_DP + 1; |
| 814 |
| 815 // Search provider icon opacity. |
| 816 mSearchProviderIconOpacity = SEARCH_PROVIDER_ICON_OPACITY_STATE_PEEKED; |
| 817 |
| 818 // Search icon opacity. |
| 819 mSearchIconOpacity = SEARCH_ICON_OPACITY_PEEKED; |
| 820 |
| 821 // Progress Bar. |
| 822 float peekedHeight = getPanelHeightFromState(PanelState.PEEKED); |
| 823 float threshold = PROGRESS_BAR_VISIBILITY_THRESHOLD_DP / mPxToDp; |
| 824 float diff = Math.min(mHeight - peekedHeight, threshold); |
| 825 // Fades the Progress Bar the closer it gets to the bottom of the |
| 826 // screen. |
| 827 float progressBarOpacity = MathUtils.interpolate(0.f, 1.f, diff / thresh
old); |
| 828 mProgressBarOpacity = progressBarOpacity; |
| 829 mProgressBarY = searchBarHeight - PROGRESS_BAR_HEIGHT_DP + 1; |
| 830 } |
| 831 |
| 832 /** |
| 833 * Updates the UI state for the expanded to maximized transition (and vice |
| 834 * versa), according to a completion |percentage|. |
| 835 * |
| 836 * @param percentage The completion percentage. |
| 837 */ |
| 838 private void updatePanelForMaximization(float percentage) { |
| 839 // Base page offset. |
| 840 mBasePageY = getBasePageTargetY(); |
| 841 |
| 842 // Base page brightness. |
| 843 float brightness = MathUtils.interpolate( |
| 844 BASE_PAGE_BRIGHTNESS_STATE_EXPANDED, |
| 845 BASE_PAGE_BRIGHTNESS_STATE_MAXIMIZED, |
| 846 percentage); |
| 847 mBasePageBrightness = brightness; |
| 848 |
| 849 // Search Bar height. |
| 850 float searchBarHeight = Math.round(MathUtils.interpolate( |
| 851 mSearchBarHeightExpanded, |
| 852 mSearchBarHeightMaximized, |
| 853 percentage)); |
| 854 mSearchBarHeight = searchBarHeight; |
| 855 |
| 856 // Search Bar border. |
| 857 mIsSearchBarBorderVisible = true; |
| 858 mSearchBarBorderY = searchBarHeight - SEARCH_BAR_BORDER_HEIGHT_DP + 1; |
| 859 |
| 860 // Search Bar text opacity. |
| 861 mSearchBarTextOpacity = 1.f; |
| 862 |
| 863 // Search provider icon opacity. |
| 864 float searchProviderIconOpacity = MathUtils.interpolate( |
| 865 SEARCH_PROVIDER_ICON_OPACITY_STATE_EXPANDED, |
| 866 SEARCH_PROVIDER_ICON_OPACITY_STATE_MAXIMIZED, |
| 867 percentage); |
| 868 mSearchProviderIconOpacity = searchProviderIconOpacity; |
| 869 |
| 870 // Search icon opacity. |
| 871 float searchIconOpacity = MathUtils.interpolate( |
| 872 SEARCH_ICON_OPACITY_EXPANDED, |
| 873 SEARCH_ICON_OPACITY_MAXIMIZED, |
| 874 percentage); |
| 875 mSearchIconOpacity = searchIconOpacity; |
| 876 |
| 877 // Progress Bar. |
| 878 mProgressBarOpacity = 1.f; |
| 879 mProgressBarY = searchBarHeight - PROGRESS_BAR_HEIGHT_DP + 1; |
| 880 } |
| 881 |
| 882 /** |
| 883 * Updates the UI state for the peeked to promo transition (and vice versa), |
| 884 * according to a completion |percentage|. |
| 885 * |
| 886 * @param percentage The completion percentage. |
| 887 */ |
| 888 private void updatePanelForOpeningPromo(float percentage) { |
| 889 // Base page offset. |
| 890 float baseBaseY = MathUtils.interpolate( |
| 891 0, |
| 892 getPromoBasePageOffsetY(), |
| 893 percentage); |
| 894 mBasePageY = baseBaseY; |
| 895 |
| 896 // Base page brightness. |
| 897 float brightness = MathUtils.interpolate( |
| 898 BASE_PAGE_BRIGHTNESS_STATE_PEEKED, |
| 899 BASE_PAGE_BRIGHTNESS_STATE_EXPANDED, |
| 900 percentage); |
| 901 mBasePageBrightness = brightness; |
| 902 |
| 903 // Search Bar height. |
| 904 float searchBarHeight = Math.round(MathUtils.interpolate( |
| 905 mSearchBarHeightPeeking, |
| 906 mSearchBarHeightPromo, |
| 907 percentage)); |
| 908 mSearchBarHeight = searchBarHeight; |
| 909 |
| 910 // Search Bar border. |
| 911 mIsSearchBarBorderVisible = false; |
| 912 |
| 913 // Search Bar text opacity. |
| 914 float peekedHeight = getPanelHeightFromState(PanelState.PEEKED); |
| 915 float threshold = DISAPPEARING_ELEMENT_THRESHOLD_DP / mPxToDp; |
| 916 float diff = Math.min(mHeight - peekedHeight, threshold); |
| 917 float disappearingElementOpacity = MathUtils.interpolate(1.f, 0.f, diff
/ threshold); |
| 918 mSearchBarTextOpacity = disappearingElementOpacity; |
| 919 |
| 920 // Search provider icon opacity. |
| 921 boolean shouldDisplaySearchProviderIcon = shouldHidePromoHeader(); |
| 922 mSearchProviderIconOpacity = |
| 923 shouldDisplaySearchProviderIcon ? 1.f : disappearingElementOpaci
ty; |
| 924 |
| 925 // Search icon opacity. |
| 926 mSearchIconOpacity = SEARCH_ICON_OPACITY_PEEKED; |
| 927 |
| 928 // Progress Bar. |
| 929 mProgressBarOpacity = 0.f; |
| 930 mProgressBarY = searchBarHeight - PROGRESS_BAR_HEIGHT_DP + 1; |
| 931 } |
| 932 |
| 933 // =========================================================================
=================== |
| 934 // Base Page Offset |
| 935 // =========================================================================
=================== |
| 936 |
| 937 /** |
| 938 * Updates the coordinate of the existing selection. |
| 939 * @param y The y coordinate of the selection in pixels. |
| 940 */ |
| 941 protected void updateBasePageSelectionYPx(float y) { |
| 942 mBasePageSelectionYPx = y; |
| 943 updateBasePageTargetY(); |
| 944 } |
| 945 |
| 946 /** |
| 947 * Updates the target offset of the Base Page in order to keep the selection
in view |
| 948 * after expanding the Panel. |
| 949 */ |
| 950 private void updateBasePageTargetY() { |
| 951 mBasePageTargetY = calculateBasePageTargetY(PanelState.EXPANDED); |
| 952 mPromoBasePageTargetY = calculateBasePageTargetY(PanelState.PROMO); |
| 953 } |
| 954 |
| 955 /** |
| 956 * Calculates the target offset of the Base Page in order to keep the select
ion in view |
| 957 * after expanding the Panel to the given |expandedState|. |
| 958 * |
| 959 * @param expandedState |
| 960 * @return The target offset Y. |
| 961 */ |
| 962 private float calculateBasePageTargetY(PanelState expandedState) { |
| 963 // Convert from px to dp. |
| 964 final float selectionY = mBasePageSelectionYPx * mPxToDp; |
| 965 |
| 966 // Calculate the exact height of the expanded Panel without taking into |
| 967 // consideration the height of the shadow (what is returned by the |
| 968 // getPanelFromHeight method). We need the measurement of the portion |
| 969 // of the Panel that occludes the page. |
| 970 final float expandedHeight = getPanelHeightFromState(expandedState) |
| 971 - PANEL_SHADOW_HEIGHT_DP; |
| 972 |
| 973 // Calculate the offset to center the selection on the available area. |
| 974 final float fullscreenHeight = getFullscreenHeight(); |
| 975 final float availableHeight = fullscreenHeight - expandedHeight; |
| 976 float offset = -selectionY + availableHeight / 2; |
| 977 |
| 978 // Make sure offset is negative to prevent Base Page from moving down, |
| 979 // because there's nothing to render above the Page. |
| 980 offset = Math.min(offset, 0.f); |
| 981 // If visible, the Toolbar will be hidden. Therefore, we need to adjust |
| 982 // the offset to account for this difference. |
| 983 if (mIsToolbarShowing) |
| 984 offset -= TOOLBAR_HEIGHT_DP; |
| 985 // Make sure the offset is not greater than the expanded height, because |
| 986 // there's nothing to render below the Page. |
| 987 offset = Math.max(offset, -expandedHeight); |
| 988 |
| 989 return offset; |
| 990 } |
| 991 |
| 992 /** |
| 993 * @return The Y coordinate to apply to the Base Page in order to keep the s
election |
| 994 * in view when the Search Panel is in EXPANDED state. |
| 995 */ |
| 996 public float getBasePageTargetY() { |
| 997 return mBasePageTargetY; |
| 998 } |
| 999 |
| 1000 /** |
| 1001 * @return The Y coordinate to apply to the Base Page in order to keep the |
| 1002 * selection in view when the Search Panel is in PROMO state. |
| 1003 */ |
| 1004 private float getPromoBasePageOffsetY() { |
| 1005 return mPromoBasePageTargetY; |
| 1006 } |
| 1007 |
| 1008 // =========================================================================
=================== |
| 1009 // Promo |
| 1010 // =========================================================================
=================== |
| 1011 |
| 1012 /** |
| 1013 * Updates the UI state for a given |height| when performing the opt-in anim
ation. |
| 1014 * |
| 1015 * @param height The Contextual Search Panel height. |
| 1016 */ |
| 1017 protected void setPanelHeightForPromoOptInAnimation(float height) { |
| 1018 PanelState endState = PanelState.EXPANDED; |
| 1019 PanelState startState = PanelState.PROMO; |
| 1020 float percentage = getStateCompletion(height, startState, endState); |
| 1021 |
| 1022 updatePanelSize(height, endState, percentage); |
| 1023 |
| 1024 updatePanelForPromoOptInAnimation(percentage); |
| 1025 } |
| 1026 |
| 1027 /** |
| 1028 * Updates the UI state for the PROMO to EXPANDED transition (and vice versa
), |
| 1029 * according to a completion |percentage|. |
| 1030 * |
| 1031 * @param percentage The completion percentage. |
| 1032 */ |
| 1033 private void updatePanelForPromoOptInAnimation(float percentage) { |
| 1034 // Base page offset. |
| 1035 float baseBaseY = MathUtils.interpolate( |
| 1036 getPromoBasePageOffsetY(), |
| 1037 getBasePageTargetY(), |
| 1038 percentage); |
| 1039 mBasePageY = baseBaseY; |
| 1040 |
| 1041 // Base page brightness. |
| 1042 mBasePageBrightness = BASE_PAGE_BRIGHTNESS_STATE_EXPANDED; |
| 1043 |
| 1044 // Search Bar height. |
| 1045 float searchBarHeight = Math.round(MathUtils.interpolate( |
| 1046 mSearchBarHeightPromo, |
| 1047 mSearchBarHeightExpanded, |
| 1048 percentage)); |
| 1049 mSearchBarHeight = searchBarHeight; |
| 1050 |
| 1051 // Search Bar border. |
| 1052 mIsSearchBarBorderVisible = false; |
| 1053 |
| 1054 // Search Bar text opacity. |
| 1055 final float threshold = 0.5f; |
| 1056 float searchBarTextOpacity = MathUtils.interpolate(0.f, 1.f, |
| 1057 Math.max(percentage - threshold, 0) / threshold); |
| 1058 mSearchBarTextOpacity = searchBarTextOpacity; |
| 1059 |
| 1060 // Search provider icon opacity. |
| 1061 boolean shouldDisplaySearchProviderIcon = shouldHidePromoHeader(); |
| 1062 mSearchProviderIconOpacity = shouldDisplaySearchProviderIcon |
| 1063 ? 1.f : MathUtils.interpolate(0.f, 1.f, percentage); |
| 1064 |
| 1065 // Search icon opacity. |
| 1066 mSearchIconOpacity = SEARCH_ICON_OPACITY_PEEKED; |
| 1067 |
| 1068 // Progress Bar. |
| 1069 mProgressBarOpacity = percentage == 1.f ? 1.f : 0.f; |
| 1070 mProgressBarY = searchBarHeight - PROGRESS_BAR_HEIGHT_DP + 1; |
| 1071 } |
| 1072 } |
OLD | NEW |