diff options
author | pedrosimonetti <pedrosimonetti@chromium.org> | 2016-03-24 16:28:49 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-24 23:30:21 +0000 |
commit | 0e4fa5d4eee260a074fdef4f44ad7383238453c6 (patch) | |
tree | 62ab231245b93b1ea659ff17bca55e00f97087f1 | |
parent | b7c77495ebdbc0f96dd6cd92341e7c1c08a1c5e3 (diff) | |
download | chromium_src-0e4fa5d4eee260a074fdef4f44ad7383238453c6.zip chromium_src-0e4fa5d4eee260a074fdef4f44ad7383238453c6.tar.gz chromium_src-0e4fa5d4eee260a074fdef4f44ad7383238453c6.tar.bz2 |
[Contextual Search] Moving logic out of OverlayPanel classes.
This CL moves almost all of Contextual Search logic out of
the OverlayPanel classes.
The remaining piece consists of the Promo animation code
that still lies in OverlayPanelAnimation. In order to
remove the code from this class, all the Promo should
be encapsulated in its own Control, similar to how
the Peek Promo is implemented.
BUG=595139
TBR=changwan
Review URL: https://codereview.chromium.org/1808913002
Cr-Commit-Position: refs/heads/master@{#383184}
9 files changed, 620 insertions, 616 deletions
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java index 997f31b..deaff7e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java @@ -43,20 +43,20 @@ public class OverlayPanel extends OverlayPanelAnimation implements ActivityState /** * State of the Overlay Panel. */ - public static enum PanelState { + public enum PanelState { // TODO(pedrosimonetti): consider removing the UNDEFINED state UNDEFINED, CLOSED, PEEKED, EXPANDED, - MAXIMIZED; + MAXIMIZED } /** * The reason for a change in the Overlay Panel's state. * TODO(mdjones): Separate generic reasons from Contextual Search reasons. */ - public static enum StateChangeReason { + public enum StateChangeReason { UNKNOWN, RESET, BACK_PRESS, @@ -85,7 +85,7 @@ public class OverlayPanel extends OverlayPanelAnimation implements ActivityState KEYBOARD_SHOWN, KEYBOARD_HIDDEN, TAB_NAVIGATION, - PROMO_ACCEPTED; + PROMO_ACCEPTED } /** The activity this panel is in. */ @@ -237,6 +237,12 @@ public class OverlayPanel extends OverlayPanelAnimation implements ActivityState if (mActivity != null) { ApplicationStatus.registerStateListenerForActivity(this, mActivity); } + + // TODO(pedrosimonetti): Coordinate with mdjones@ to move this to the OverlayPanelBase + // constructor, once we are able to get the Activity during instantiation. The Activity + // is needed in order to get the correct height of the Toolbar, which varies depending + // on the Activity (WebApps have a smaller toolbar for example). + initializeUiState(); } /** @@ -492,8 +498,8 @@ public class OverlayPanel extends OverlayPanelAnimation implements ActivityState // ============================================================================================ /** - * Sets the {@OverlayPanelHost} used to communicate with the supported layout. - * @param host The {@OverlayPanelHost}. + * Sets the {@link OverlayPanelHost} used to communicate with the supported layout. + * @param host The {@link OverlayPanelHost}. */ public void setHost(OverlayPanelHost host) { mOverlayPanelHost = host; @@ -541,11 +547,6 @@ public class OverlayPanel extends OverlayPanelAnimation implements ActivityState * Updates the Panel so it preserves its state when the orientation changes. */ protected void updatePanelForOrientationChange() { - // NOTE(pedrosimonetti): We cannot tell where the selection will be after the - // orientation change, so we are setting the selection position to zero, which - // means the base page will be positioned in its original state and we won't - // try to keep the selection in view. - updateBasePageSelectionYPx(0.f); resizePanelToState(getPanelState(), StateChangeReason.UNKNOWN); } @@ -700,7 +701,7 @@ public class OverlayPanel extends OverlayPanelAnimation implements ActivityState * @return The vertical offset of the Overlay Content View in dp. */ public float getContentY() { - return getOffsetY() + getBarContainerHeight() + getPromoHeight(); + return getOffsetY() + getBarContainerHeight(); } /** diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelAnimation.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelAnimation.java index 86a01ec..6d99cdc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelAnimation.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelAnimation.java @@ -28,8 +28,8 @@ public abstract class OverlayPanelAnimation extends OverlayPanelBase */ protected enum Property { PANEL_HEIGHT, - PROMO_VISIBILITY, - BOTTOM_BAR_TEXT_VISIBILITY + // TODO(pedrosimonetti): Move Promo logic to its own control class. + PROMO_VISIBILITY } /** @@ -69,11 +69,6 @@ public abstract class OverlayPanelAnimation extends OverlayPanelBase private ChromeAnimation<Animatable<?>> mLayoutAnimations; /** - * Whether the Promo's acceptance animation is running. - */ - private boolean mIsAnimatingPromoAcceptance; - - /** * The {@link LayoutUpdateHost} used to request a new frame to be updated and rendered. */ private final LayoutUpdateHost mUpdateHost; @@ -110,11 +105,8 @@ public abstract class OverlayPanelAnimation extends OverlayPanelBase // Animation API // ============================================================================================ - /** - * Notifies that the acceptance animation has finished. - */ - protected void onPromoAcceptanceAnimationFinished() { - } + // TODO(pedrosimonetti): Move Promo logic to its own control class. + protected void setPromoVisibilityForOptInAnimation(float percentage) {} /** * Animates the Overlay Panel to its maximized state. @@ -142,6 +134,8 @@ public abstract class OverlayPanelAnimation extends OverlayPanelBase * @param reason The reason for the change of panel state. */ protected void peekPanel(StateChangeReason reason) { + updateBasePageTargetY(); + // Indicate to the Compositor that for now on the Panel should be // rendered, until it's closed. startShowing(); @@ -233,26 +227,6 @@ public abstract class OverlayPanelAnimation extends OverlayPanelBase // Animation Helpers // ============================================================================================ - @Override - protected void animatePromoAcceptance() { - hidePromoView(); - mIsAnimatingPromoAcceptance = true; - animateProperty(Property.PROMO_VISIBILITY, 1.f, 0.f, BASE_ANIMATION_DURATION_MS); - } - - @Override - protected void animateSearchTermResolution() { - animateProperty(Property.BOTTOM_BAR_TEXT_VISIBILITY, 0.f, 1.f, - MAXIMUM_ANIMATION_DURATION_MS); - } - - @Override - protected void cancelSearchTermResolutionAnimation() { - if (animationIsRunning()) { - cancelAnimation(this, Property.BOTTOM_BAR_TEXT_VISIBILITY); - } - } - /** * Animates the Panel to its nearest state. */ @@ -274,6 +248,19 @@ public abstract class OverlayPanelAnimation extends OverlayPanelBase * @param velocity The velocity of the gesture in dps per second. */ protected void animateToProjectedState(float velocity) { + PanelState projectedState = getProjectedState(velocity); + + final float displacement = getPanelHeightFromState(projectedState) - getHeight(); + final long duration = calculateAnimationDuration(velocity, displacement); + + animatePanelToState(projectedState, StateChangeReason.FLING, duration); + } + + /** + * @param velocity The given velocity. + * @return The projected state the Panel will be if the given velocity is applied. + */ + protected PanelState getProjectedState(float velocity) { final float kickY = calculateAnimationDisplacement(velocity, BASE_ANIMATION_DURATION_MS); final float projectedHeight = getHeight() - kickY; @@ -281,21 +268,7 @@ public abstract class OverlayPanelAnimation extends OverlayPanelBase // duration of the animation given the current velocity and the projected displacement. PanelState projectedState = findNearestPanelStateFromHeight(projectedHeight, velocity); - // Prevent the fling gesture from moving the Panel from PEEKED to MAXIMIZED if the Panel - // Promo is available and we are running in full screen panel mode. This is to make sure - // the Promo will be visible, considering that the EXPANDED state is the only one that will - // show the Promo in full screen panel mode. In narrow panel UI the Promo is visible in - // maximized so this project state change is not needed. - if (projectedState == PanelState.MAXIMIZED - && getPanelState() == PanelState.PEEKED - && isPromoVisible()) { - projectedState = PanelState.EXPANDED; - } - - final float displacement = getPanelHeightFromState(projectedState) - getHeight(); - final long duration = calculateAnimationDuration(velocity, displacement); - - animatePanelToState(projectedState, StateChangeReason.FLING, duration); + return projectedState; } /** @@ -403,6 +376,7 @@ public abstract class OverlayPanelAnimation extends OverlayPanelBase if (prop == Property.PANEL_HEIGHT) { setPanelHeight(value); } else if (prop == Property.PROMO_VISIBILITY) { + // TODO(pedrosimonetti): Move Promo logic to its own control class. setPromoVisibilityForOptInAnimation(value); } } @@ -445,11 +419,6 @@ public abstract class OverlayPanelAnimation extends OverlayPanelBase * Called when layout-specific actions are needed after the animation finishes. */ protected void onAnimationFinished() { - if (mIsAnimatingPromoAcceptance) { - mIsAnimatingPromoAcceptance = false; - onPromoAcceptanceAnimationFinished(); - } - mIsAnimatingPanelClosing = false; mIsAnimatingPanelExpanding = false; @@ -528,7 +497,7 @@ public abstract class OverlayPanelAnimation extends OverlayPanelBase /** * @return whether or not the animation is currently being run. */ - protected boolean animationIsRunning() { + public boolean animationIsRunning() { return mLayoutAnimations != null && !mLayoutAnimations.finished(); } @@ -537,7 +506,7 @@ public abstract class OverlayPanelAnimation extends OverlayPanelBase * @param object The object being animated. * @param prop The property to search for. */ - protected <T extends Enum<?>> void cancelAnimation(Animatable<T> object, T prop) { + public <T extends Enum<?>> void cancelAnimation(Animatable<T> object, T prop) { if (mLayoutAnimations != null) { mLayoutAnimations.cancel(object, prop); } diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java index 3c25658..d645c91 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java @@ -6,9 +6,6 @@ package org.chromium.chrome.browser.compositor.bottombar; import android.content.Context; import android.graphics.Color; -import android.os.Handler; -import android.view.LayoutInflater; -import android.view.View; import android.view.ViewGroup; import org.chromium.base.ApiCompatibilityUtils; @@ -16,10 +13,6 @@ import org.chromium.base.VisibleForTesting; import org.chromium.chrome.R; import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.PanelState; import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChangeReason; -import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchOptOutPromo; -import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchOptOutPromo.ContextualSearchPromoHost; -import org.chromium.chrome.browser.preferences.PreferencesLauncher; -import org.chromium.chrome.browser.preferences.privacy.ContextualSearchPreferenceFragment; import org.chromium.chrome.browser.util.MathUtils; import org.chromium.ui.base.LocalizationUtils; import org.chromium.ui.resources.dynamics.DynamicResourceLoader; @@ -30,9 +23,8 @@ import java.util.Map; /** * Base abstract class for the Overlay Panel. - * TODO(mdjones): Remove contextual search dependencies from this class. */ -abstract class OverlayPanelBase implements ContextualSearchPromoHost { +abstract class OverlayPanelBase { /** The side padding of Bar icons in dps. */ private static final float BAR_ICON_SIDE_PADDING_DP = 12.f; @@ -113,9 +105,6 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { /** Ratio of dps per pixel. */ protected float mPxToDp; - /** The approximate Y coordinate of the selection in pixels. */ - private float mBasePageSelectionYPx = -1.f; - /** * The Y coordinate to apply to the Base Page in order to keep the selection * in view when the Overlay Panel is in its EXPANDED state. @@ -136,7 +125,7 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { */ protected static final Map<PanelState, PanelState> PREVIOUS_STATES; static { - Map<PanelState, PanelState> states = new HashMap<PanelState, PanelState>(); + Map<PanelState, PanelState> states = new HashMap<>(); // Pairs are of the form <Current, Previous>. states.put(PanelState.PEEKED, PanelState.CLOSED); states.put(PanelState.EXPANDED, PanelState.PEEKED); @@ -167,21 +156,6 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { protected abstract void closePanel(StateChangeReason reason, boolean animate); /** - * Animates the acceptance of the Promo. - */ - protected abstract void animatePromoAcceptance(); - - /** - * Animates the search term resolution. - */ - protected abstract void animateSearchTermResolution(); - - /** - * Cancels the search term resolution animation if it is in progress. - */ - protected abstract void cancelSearchTermResolutionAnimation(); - - /** * Event notification that the Panel did get closed. * @param reason The reason the panel is closing. */ @@ -199,24 +173,6 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { protected abstract int getControlContainerHeightResource(); // ============================================================================================ - // Peeking promo methods - // ============================================================================================ - - /** - * @return The height of the Peek Promo in the peeked state, in pixels. - */ - protected float getPeekPromoHeightPeekingPx() { - return 0; - } - - /** - * @return The height of the Peek Promo, in pixels. - */ - protected float getPeekPromoHeight() { - return 0; - } - - // ============================================================================================ // Layout Integration // ============================================================================================ @@ -253,17 +209,6 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { } /** - * Overrides the FullWidthSizePanel state for testing. - * - * @param isFullWidthSizePanel - */ - @VisibleForTesting - public void setIsFullWidthSizePanelForTesting(boolean isFullWidthSizePanel) { - mOverrideIsFullWidthSizePanelForTesting = true; - mIsFullWidthSizePanelForTesting = isFullWidthSizePanel; - } - - /** * @return Whether the Panel is in full width size. */ protected boolean isFullWidthSizePanel() { @@ -368,7 +313,7 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { * @return The Panel Bar Container in dps. */ protected float getBarContainerHeight() { - return getBarHeight() + getPeekPromoHeight(); + return getBarHeight(); } /** @@ -392,52 +337,6 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { // ============================================================================================ // -------------------------------------------------------------------------------------------- - // Test Infrastructure - // -------------------------------------------------------------------------------------------- - - /** - * @param height The height of the Overlay Panel to be set. - */ - @VisibleForTesting - public void setHeightForTesting(float height) { - mHeight = height; - } - - /** - * @param offsetY The vertical offset of the Overlay Panel to be - * set. - */ - @VisibleForTesting - public void setOffsetYForTesting(float offsetY) { - mOffsetY = offsetY; - } - - /** - * @param isMaximized The setting for whether the Overlay Panel is fully - * maximized. - */ - @VisibleForTesting - public void setMaximizedForTesting(boolean isMaximized) { - mIsMaximized = isMaximized; - } - - /** - * @param barHeight The height of the Overlay Bar to be set. - */ - @VisibleForTesting - public void setSearchBarHeightForTesting(float barHeight) { - mBarHeight = barHeight; - } - - /** - * @param barBorderHeight The height of the Bar border to be set. - */ - @VisibleForTesting - public void setSearchBarBorderHeight(float barBorderHeight) { - mBarBorderHeight = barBorderHeight; - } - - // -------------------------------------------------------------------------------------------- // Overlay Panel states // -------------------------------------------------------------------------------------------- @@ -666,64 +565,6 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { mProgressBarCompletion = completion; } - // -------------------------------------------------------------------------------------------- - // Promo states - // -------------------------------------------------------------------------------------------- - - private boolean mPromoVisible = false; - private float mPromoContentHeightPx = 0.f; - private float mPromoHeightPx; - private float mPromoOpacity; - - /** - * @return Whether the promo is visible. - */ - public boolean getPromoVisible() { - return mPromoVisible; - } - - /** - * Sets the height of the promo content. - */ - public void setPromoContentHeightPx(float heightPx) { - mPromoContentHeightPx = heightPx; - } - - /** - * @return Height of the promo in dps. - */ - public float getPromoHeight() { - return mPromoHeightPx * mPxToDp; - } - - /** - * @return Height of the promo in pixels. - */ - public float getPromoHeightPx() { - return mPromoHeightPx; - } - - /** - * @return The opacity of the promo. - */ - public float getPromoOpacity() { - return mPromoOpacity; - } - - /** - * Gets the height of the promo content. - */ - protected float getPromoContentHeight() { - return mPromoContentHeightPx * mPxToDp; - } - - /** - * @return Y coordinate of the promo in pixels. - */ - protected float getPromoYPx() { - return Math.round((getOffsetY() + getBarContainerHeight()) / mPxToDp); - } - // ============================================================================================ // State Handler // ============================================================================================ @@ -744,8 +585,6 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { if (state == PanelState.CLOSED) { mIsShowing = false; onClosed(reason); - } else if (state == PanelState.EXPANDED) { - showPromoViewAtYPosition(getPromoYPx()); } // We should only set the state at the end of this method, in oder to make sure that @@ -827,7 +666,7 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { * @return The peeked height of the panel in dps. */ protected float getPeekedHeight() { - return mBarHeightPeeking + getPeekPromoHeightPeekingPx() * mPxToDp; + return mBarHeightPeeking; } /** @@ -858,7 +697,6 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { protected void initializeUiState() { mIsShowing = false; - // Static values. mPxToDp = 1.f / mContext.getResources().getDisplayMetrics().density; mToolbarHeight = mContext.getResources().getDimension( @@ -870,11 +708,11 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { R.dimen.toolbar_height_no_shadow) * mPxToDp; mBarHeightExpanded = Math.round((mBarHeightPeeking + mBarHeightMaximized) / 2.f); + mBarMarginSide = BAR_ICON_SIDE_PADDING_DP; mProgressBarHeight = PROGRESS_BAR_HEIGHT_DP; mBarBorderHeight = BAR_BORDER_HEIGHT_DP; - // Dynamic values. mBarHeight = mBarHeightPeeking; } @@ -946,12 +784,6 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { * @param height The height of the panel in dps. */ protected void setPanelHeight(float height) { - // As soon as we resize the Panel to a different height than the expanded one, - // then we should hide the Promo View once the snapshot will be shown in its place. - if (height != getPanelHeightFromState(PanelState.EXPANDED)) { - hidePromoView(); - } - updatePanelForHeight(height); } @@ -977,7 +809,7 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { PanelState startState = getPreviousPanelState(endState); float percentage = getStateCompletion(height, startState, endState); - updatePanelSize(height, endState, percentage); + updatePanelSize(height); if (endState == PanelState.CLOSED || endState == PanelState.PEEKED) { updatePanelForCloseOrPeek(percentage); @@ -992,10 +824,8 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { * Updates the Panel size information. * * @param height The Overlay Panel height. - * @param endState The final state of transition being executed. - * @param percentage The completion percentage of the transition. */ - private void updatePanelSize(float height, PanelState endState, float percentage) { + private void updatePanelSize(float height) { mHeight = height; mOffsetX = calculateOverlayPanelX(); mOffsetY = calculateOverlayPanelY(); @@ -1045,14 +875,11 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { private float getStateCompletion(float height, PanelState startState, PanelState endState) { float startSize = getPanelHeightFromState(startState); float endSize = getPanelHeightFromState(endState); - float percentage = - // NOTE(pedrosimonetti): Handle special case from PanelState.UNDEFINED - // to PanelState.CLOSED, where both have a height of zero. Returning - // zero here means the Panel will be reset to its CLOSED state. - startSize == 0.f && endSize == 0.f ? 0.f - : (height - startSize) / (endSize - startSize); - - return percentage; + // NOTE(pedrosimonetti): Handle special case from PanelState.UNDEFINED + // to PanelState.CLOSED, where both have a height of zero. Returning + // zero here means the Panel will be reset to its CLOSED state. + return startSize == 0.f && endSize == 0.f ? 0.f + : (height - startSize) / (endSize - startSize); } /** @@ -1062,9 +889,6 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { * @param percentage The completion percentage. */ protected void updatePanelForCloseOrPeek(float percentage) { - // Update the opt out promo. - updatePromoVisibility(1.f); - // Base page offset. mBasePageY = 0.f; @@ -1097,29 +921,23 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { * @param percentage The completion percentage. */ protected void updatePanelForExpansion(float percentage) { - // Update the opt out promo. - updatePromoVisibility(1.f); - // Base page offset. - float baseBaseY = MathUtils.interpolate( + mBasePageY = MathUtils.interpolate( 0.f, getBasePageTargetY(), percentage); - mBasePageY = baseBaseY; // Base page brightness. - float brightness = MathUtils.interpolate( + mBasePageBrightness = MathUtils.interpolate( BASE_PAGE_BRIGHTNESS_STATE_PEEKED, BASE_PAGE_BRIGHTNESS_STATE_EXPANDED, percentage); - mBasePageBrightness = brightness; // Bar height. - float barHeight = Math.round(MathUtils.interpolate( + mBarHeight = Math.round(MathUtils.interpolate( mBarHeightPeeking, getBarHeightExpanded(), percentage)); - mBarHeight = barHeight; // Bar border. mIsBarBorderVisible = true; @@ -1148,8 +966,7 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { float diff = Math.min(mHeight - peekedHeight, threshold); // Fades the Progress Bar the closer it gets to the bottom of the // screen. - float progressBarOpacity = MathUtils.interpolate(0.f, 1.f, diff / threshold); - mProgressBarOpacity = progressBarOpacity; + mProgressBarOpacity = MathUtils.interpolate(0.f, 1.f, diff / threshold); // Update the Bar Shadow. updateBarShadow(); @@ -1162,9 +979,6 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { * @param percentage The completion percentage. */ protected void updatePanelForMaximization(float percentage) { - // Update the opt out promo. - updatePromoVisibility(1.f - percentage); - boolean supportsExpandedState = isSupportedState(PanelState.EXPANDED); // Base page offset. @@ -1230,47 +1044,25 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { } /** - * @return Whether the Panel Promo is visible. - */ - protected boolean isPromoVisible() { - return false; - } - - /** - * Updates the UI state for Opt Out Promo. - * - * @param percentage The visibility percentage of the Promo. A visibility of 0 means the - * Promo is not visible. A visibility of 1 means the Promo is fully visible. And - * visibility between 0 and 1 means the Promo is partially visible. + * Updates the UI state for Bar Shadow. */ - private void updatePromoVisibility(float percentage) { - if (isPromoVisible()) { - mPromoVisible = true; + protected void updateBarShadow() { + float barShadowOpacity = calculateBarShadowOpacity(); - mPromoHeightPx = Math.round(MathUtils.clamp(percentage * mPromoContentHeightPx, - 0.f, mPromoContentHeightPx)); - mPromoOpacity = percentage; + if (barShadowOpacity > 0.f) { + mBarShadowVisible = true; + mBarShadowOpacity = barShadowOpacity; } else { - mPromoVisible = false; - mPromoHeightPx = 0.f; - mPromoOpacity = 0.f; + mBarShadowVisible = false; + mBarShadowOpacity = 0.f; } } /** - * Updates the UI state for Bar Shadow. + * @return The new opacity value for the Bar Shadow. */ - private void updateBarShadow() { - float barShadowHeightPx = 9.f / mPxToDp; - if (mPromoVisible && mPromoHeightPx > 0.f) { - mBarShadowVisible = true; - float threshold = 2 * barShadowHeightPx; - mBarShadowOpacity = mPromoHeightPx > barShadowHeightPx ? 1.f - : MathUtils.interpolate(0.f, 1.f, mPromoHeightPx / threshold); - } else { - mBarShadowVisible = false; - mBarShadowOpacity = 0.f; - } + protected float calculateBarShadowOpacity() { + return 0.f; } // ============================================================================================ @@ -1278,12 +1070,15 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { // ============================================================================================ /** - * Updates the coordinate of the existing selection. - * @param y The y coordinate of the selection in pixels. + * Calculates the desired offset for the Base Page. The purpose of this method is to allow + * subclasses to provide an specific offset, which can be useful for keeping a certain + * portion of the Base Page visible when a Panel is in expanded state. To facilitate the + * calculation, the first argument contains the height of the Panel in the expanded state. + * + * @return The desired offset for the Base Page */ - protected void updateBasePageSelectionYPx(float y) { - mBasePageSelectionYPx = y; - updateBasePageTargetY(); + protected float calculateBasePageDesiredOffset() { + return 0.f; } /** @@ -1291,34 +1086,26 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { * after expanding the Panel. */ protected void updateBasePageTargetY() { - mBasePageTargetY = calculateBasePageTargetY(PanelState.EXPANDED); + mBasePageTargetY = calculateBasePageTargetY(); } /** - * Calculates the target offset of the Base Page in order to keep the selection in view - * after expanding the Panel to the given |expandedState|. + * Calculates the target offset of the Base Page in order to achieve the desired offset + * specified by {@link #calculateBasePageDesiredOffset} while assuring that the Base + * Page will always fill the gap between the Panel and the top of the screen, because + * there's nothing to see below the Base Page layer. This method will take into + * consideration the Toolbar height, and adjust the offset accordingly, in order to + * move the Toolbar out of the view as the Panel expands. * - * @param expandedState * @return The target offset Y. */ - protected float calculateBasePageTargetY(PanelState expandedState) { + private float calculateBasePageTargetY() { // Only a fullscreen wide Panel should offset the base page. A small panel should // always return zero to ensure the Base Page remains in the same position. if (!isFullWidthSizePanel()) return 0.f; - // Convert from px to dp. - final float selectionY = mBasePageSelectionYPx * mPxToDp; - - // Calculate the exact height of the expanded Panel without taking into - // consideration the height of the shadow (what is returned by the - // getPanelFromHeight method). We need the measurement of the portion - // of the Panel that occludes the page. - final float expandedHeight = getPanelHeightFromState(expandedState); - - // Calculate the offset to center the selection on the available area. - final float tabHeight = getTabHeight(); - final float availableHeight = tabHeight - expandedHeight; - float offset = -selectionY + availableHeight / 2; + // Start with the desired offset. + float offset = calculateBasePageDesiredOffset(); // Make sure offset is negative to prevent Base Page from moving down, // because there's nothing to render above the Page. @@ -1328,7 +1115,7 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { offset -= (mToolbarHeight - getTopControlsOffsetDp()); // Make sure the offset is not greater than the expanded height, because // there's nothing to render below the Page. - offset = Math.max(offset, -expandedHeight); + offset = Math.max(offset, -getExpandedHeight()); return offset; } @@ -1353,11 +1140,6 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { */ public void setDynamicResourceLoader(DynamicResourceLoader resourceLoader) { mResourceLoader = resourceLoader; - - if (mPromoView != null) { - mResourceLoader.registerResource(R.id.contextual_search_opt_out_promo, - mPromoView.getResourceAdapter()); - } } /** @@ -1370,157 +1152,51 @@ abstract class OverlayPanelBase implements ContextualSearchPromoHost { } // ============================================================================================ - // Promo Host - // ============================================================================================ - - @Override - public void onPromoPreferenceClick() { - new Handler().post(new Runnable() { - @Override - public void run() { - PreferencesLauncher.launchSettingsPage(mContext, - ContextualSearchPreferenceFragment.class.getName()); - } - }); - } - - /** - * @param enabled Whether the preference should be enabled. - */ - public void setPreferenceState(boolean enabled) { - } - - @Override - public void onPromoButtonClick(boolean accepted) { - if (accepted) { - animatePromoAcceptance(); - } else { - hidePromoView(); - // NOTE(pedrosimonetti): If the user has opted out of Contextual Search, we should set - // the preference right away because the preference state controls whether the promo - // will be visible, and we want to hide the promo immediately when the user opts out. - setPreferenceState(false); - closePanel(StateChangeReason.OPTOUT, true); - } - } - - // ============================================================================================ - // Opt Out Promo View + // Test Infrastructure // ============================================================================================ - // TODO(pedrosimonetti): Consider maybe adding a 9.patch to avoid the hacky nested layouts in - // order to have the transparent gap at the top of the Promo View. - - /** - * The {@link ContextualSearchOptOutPromo} instance. - */ - private ContextualSearchOptOutPromo mPromoView; - /** - * Whether the Search Promo View is visible. - */ - private boolean mIsSearchPromoViewVisible = false; - - /** - * Creates the Search Promo View. - */ - protected void createPromoView() { - if (isPromoVisible() && mPromoView == null) { - assert mContainerView != null; - - // TODO(pedrosimonetti): Refactor promo code to use ViewResourceInflater. - LayoutInflater.from(mContext).inflate( - R.layout.contextual_search_opt_out_promo, mContainerView); - mPromoView = (ContextualSearchOptOutPromo) - mContainerView.findViewById(R.id.contextual_search_opt_out_promo); - - if (mResourceLoader != null) { - mResourceLoader.registerResource(R.id.contextual_search_opt_out_promo, - mPromoView.getResourceAdapter()); - } - - mPromoView.setPromoHost(this); - - updatePromoLayout(); - - assert mPromoView != null; - } - } - - /** - * Destroys the Search Promo View. + * @param height The height of the Overlay Panel to be set. */ - protected void destroyPromoView() { - if (mPromoView != null) { - mContainerView.removeView(mPromoView); - mPromoView = null; - if (mResourceLoader != null) { - mResourceLoader.unregisterResource(R.id.contextual_search_opt_out_promo); - } - } + @VisibleForTesting + public void setHeightForTesting(float height) { + mHeight = height; } /** - * Updates the Promo layout. + * @param offsetY The vertical offset of the Overlay Panel to be + * set. */ - protected void updatePromoLayout() { - final int maximumWidth = getMaximumWidthPx(); - - // Adjust size for small Panel. - if (!isFullWidthSizePanel()) { - mPromoView.getLayoutParams().width = maximumWidth; - mPromoView.requestLayout(); - } - - setPromoContentHeightPx(mPromoView.getHeightForGivenWidth(maximumWidth)); + @VisibleForTesting + public void setOffsetYForTesting(float offsetY) { + mOffsetY = offsetY; } /** - * Displays the Search Promo View at the given Y position. - * - * @param y The Y position. + * @param isMaximized The setting for whether the Overlay Panel is fully + * maximized. */ - private void showPromoViewAtYPosition(float y) { - if (mPromoView == null || !isPromoVisible()) return; - - float offsetX = getOffsetX() / mPxToDp; - if (LocalizationUtils.isLayoutRtl()) { - offsetX = -offsetX; - } - - mPromoView.setTranslationX(offsetX); - mPromoView.setTranslationY(y); - mPromoView.setVisibility(View.VISIBLE); - - // NOTE(pedrosimonetti): We need to call requestLayout, otherwise - // the Promo View will not become visible. - mPromoView.requestLayout(); - - mIsSearchPromoViewVisible = true; + @VisibleForTesting + public void setMaximizedForTesting(boolean isMaximized) { + mIsMaximized = isMaximized; } /** - * Hides the Search Promo View. + * @param barHeight The height of the Overlay Bar to be set. */ - protected void hidePromoView() { - if (mPromoView == null - || !mIsSearchPromoViewVisible - || !isPromoVisible()) { - return; - } - - mPromoView.setVisibility(View.INVISIBLE); - - mIsSearchPromoViewVisible = false; + @VisibleForTesting + public void setSearchBarHeightForTesting(float barHeight) { + mBarHeight = barHeight; } /** - * Updates the UI state for Opt In Promo animation. + * Overrides the FullWidthSizePanel state for testing. * - * @param percentage The visibility percentage of the Promo. + * @param isFullWidthSizePanel Whether the Panel has a full width size. */ - protected void setPromoVisibilityForOptInAnimation(float percentage) { - updatePromoVisibility(percentage); - updateBarShadow(); + @VisibleForTesting + public void setIsFullWidthSizePanelForTesting(boolean isFullWidthSizePanel) { + mOverrideIsFullWidthSizePanelForTesting = true; + mIsFullWidthSizePanelForTesting = isFullWidthSizePanel; } } diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelInflater.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelInflater.java index 27c5705..bc0dd09 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelInflater.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelInflater.java @@ -17,7 +17,7 @@ import org.chromium.ui.resources.dynamics.ViewResourceInflater; public abstract class OverlayPanelInflater extends ViewResourceInflater { /** - * The panel delegate used to get information about the panel layout. + * The panel used to get information about the panel layout. */ protected OverlayPanel mOverlayPanel; diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchBarControl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchBarControl.java index a9a6e7f..5d9b341 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchBarControl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchBarControl.java @@ -8,12 +8,28 @@ import android.content.Context; import android.view.ViewGroup; import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel; +import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelAnimation; +import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation; import org.chromium.ui.resources.dynamics.DynamicResourceLoader; /** * Controls the Search Bar in the Contextual Search Panel. */ -public class ContextualSearchBarControl { +public class ContextualSearchBarControl + implements ChromeAnimation.Animatable<ContextualSearchBarControl.AnimationType> { + + /** + * Animation properties. + */ + protected enum AnimationType { + TEXT_OPACITY + } + + /** + * The panel used to get information about the panel layout. + */ + protected OverlayPanel mOverlayPanel; + /** * The {@link ContextualSearchContextControl} used to control the Search Context View. */ @@ -25,6 +41,16 @@ public class ContextualSearchBarControl { private final ContextualSearchTermControl mSearchTermControl; /** + * The opacity of the Bar's Search Context. + */ + private float mSearchBarContextOpacity = 1.f; + + /** + * The opacity of the Bar's Search Term. + */ + private float mSearchBarTermOpacity = 1.f; + + /** * Constructs a new bottom bar control container by inflating views from XML. * * @param panel The panel. @@ -36,6 +62,7 @@ public class ContextualSearchBarControl { Context context, ViewGroup container, DynamicResourceLoader loader) { + mOverlayPanel = panel; mContextControl = new ContextualSearchContextControl(panel, context, container, loader); mSearchTermControl = new ContextualSearchTermControl(panel, context, container, loader); } @@ -54,7 +81,9 @@ public class ContextualSearchBarControl { * @param end The portion of the context after the selection. */ public void setSearchContext(String selection, String end) { + cancelSearchTermResolutionAnimation(); mContextControl.setSearchContext(selection, end); + resetSearchBarContextOpacity(); } /** @@ -62,7 +91,10 @@ public class ContextualSearchBarControl { * @param searchTerm The string that represents the search term. */ public void setSearchTerm(String searchTerm) { + cancelSearchTermResolutionAnimation(); mSearchTermControl.setSearchTerm(searchTerm); + resetSearchBarTermOpacity(); + animateSearchTermResolution(); } /** @@ -78,4 +110,85 @@ public class ContextualSearchBarControl { public int getSearchTermViewId() { return mSearchTermControl.getViewId(); } + + /** + * @return The opacity of the SearchBar's search context. + */ + public float getSearchBarContextOpacity() { + return mSearchBarContextOpacity; + } + + /** + * @return The opacity of the SearchBar's search term. + */ + public float getSearchBarTermOpacity() { + return mSearchBarTermOpacity; + } + + /** + * Resets the SearchBar text opacity when a new search context is set. The search + * context is made visible and the search term invisible. + */ + private void resetSearchBarContextOpacity() { + mSearchBarContextOpacity = 1.f; + mSearchBarTermOpacity = 0.f; + } + + /** + * Resets the SearchBar text opacity when a new search term is set. The search + * term is made visible and the search context invisible. + */ + private void resetSearchBarTermOpacity() { + mSearchBarContextOpacity = 0.f; + mSearchBarTermOpacity = 1.f; + } + + // ============================================================================================ + // Search Bar Animation + // ============================================================================================ + + /** + * Animates the search term resolution. + */ + public void animateSearchTermResolution() { + mOverlayPanel.addToAnimation(this, AnimationType.TEXT_OPACITY, 0.f, 1.f, + OverlayPanelAnimation.MAXIMUM_ANIMATION_DURATION_MS, 0); + } + + /** + * Cancels the search term resolution animation if it is in progress. + */ + public void cancelSearchTermResolutionAnimation() { + if (mOverlayPanel.animationIsRunning()) { + mOverlayPanel.cancelAnimation(this, AnimationType.TEXT_OPACITY); + } + } + + @Override + public void setProperty(AnimationType type, float value) { + if (type == AnimationType.TEXT_OPACITY) { + updateSearchBarTextOpacity(value); + } + } + + @Override + public void onPropertyAnimationFinished(AnimationType prop) {} + + /** + * Updates the UI state for the SearchBar text. The search context view will fade out + * while the search term fades in. + * + * @param percentage The visibility percentage of the search term view. + */ + private void updateSearchBarTextOpacity(float percentage) { + // The search context will start fading out before the search term starts fading in. + // They will both be partially visible for overlapPercentage of the animation duration. + float overlapPercentage = .75f; + float fadingOutPercentage = Math.max(1 - (percentage / overlapPercentage), 0.f); + float fadingInPercentage = + Math.max(percentage - (1 - overlapPercentage), 0.f) / overlapPercentage; + + mSearchBarContextOpacity = fadingOutPercentage; + mSearchBarTermOpacity = fadingInPercentage; + } } diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java index 0cd2578..6d540d5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java @@ -7,9 +7,12 @@ package org.chromium.chrome.browser.compositor.bottombar.contextualsearch; import android.app.Activity; import android.content.Context; import android.os.Handler; +import android.view.LayoutInflater; +import android.view.View; import org.chromium.base.ActivityState; import org.chromium.base.VisibleForTesting; +import org.chromium.chrome.R; import org.chromium.chrome.browser.compositor.bottombar.OverlayContentProgressObserver; import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel; import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelContent; @@ -20,12 +23,17 @@ import org.chromium.chrome.browser.compositor.scene_layer.ContextualSearchSceneL import org.chromium.chrome.browser.compositor.scene_layer.SceneLayer; import org.chromium.chrome.browser.contextualsearch.ContextualSearchManagementDelegate; import org.chromium.chrome.browser.preferences.PrefServiceBridge; +import org.chromium.chrome.browser.preferences.PreferencesLauncher; +import org.chromium.chrome.browser.preferences.privacy.ContextualSearchPreferenceFragment; +import org.chromium.chrome.browser.util.MathUtils; +import org.chromium.ui.base.LocalizationUtils; import org.chromium.ui.resources.ResourceManager; /** * Controls the Contextual Search Panel. */ -public class ContextualSearchPanel extends OverlayPanel { +public class ContextualSearchPanel extends OverlayPanel + implements ContextualSearchOptOutPromo.ContextualSearchPromoHost { /** * The delay after which the hide progress will be hidden. @@ -125,11 +133,8 @@ public class ContextualSearchPanel extends OverlayPanel { if (mSceneLayer == null) return; mSceneLayer.update(resourceManager, this, - getSearchContextViewId(), - getSearchTermViewId(), + getSearchBarControl(), getPeekPromoControl(), - getSearchBarContextOpacity(), - getSearchBarTermOpacity(), getIconSpriteControl()); } @@ -153,7 +158,6 @@ public class ContextualSearchPanel extends OverlayPanel { mManagementDelegate = delegate; if (delegate != null) { setChromeActivity(mManagementDelegate.getChromeActivity()); - initializeUiState(); } } } @@ -186,6 +190,10 @@ public class ContextualSearchPanel extends OverlayPanel { } } + if (toState == PanelState.EXPANDED) { + showPromoViewAtYPosition(getPromoYPx()); + } + if (fromState == PanelState.PEEKED && (toState == PanelState.EXPANDED || toState == PanelState.MAXIMIZED)) { // After opening the Panel to either expanded or maximized state, @@ -204,29 +212,17 @@ public class ContextualSearchPanel extends OverlayPanel { if (canDisplayContentInPanel()) { return super.getExpandedHeight(); } else { - return getBarHeightPeeking() + getPromoContentHeight(); + return getBarHeightPeeking() + mPromoContentHeightPx * mPxToDp; } } // ============================================================================================ - // Promo Host - // ============================================================================================ - - @Override - public void onPromoPreferenceClick() { - super.onPromoPreferenceClick(); - } - - @Override - public void onPromoButtonClick(boolean accepted) { - super.onPromoButtonClick(accepted); - } - - // ============================================================================================ // Contextual Search Manager Integration // ============================================================================================ - @Override + /** + * @param enabled Whether the preference should be enabled. + */ public void setPreferenceState(boolean enabled) { if (mManagementDelegate != null) { PrefServiceBridge.getInstance().setContextualSearchState(enabled); @@ -335,20 +331,17 @@ public class ContextualSearchPanel extends OverlayPanel { protected void onAnimationFinished() { super.onAnimationFinished(); + if (mIsAnimatingPromoAcceptance) { + mIsAnimatingPromoAcceptance = false; + onPromoAcceptanceAnimationFinished(); + } + if (mShouldPromoteToTabAfterMaximizing && getPanelState() == PanelState.MAXIMIZED) { mShouldPromoteToTabAfterMaximizing = false; mManagementDelegate.promoteToTab(); } } - @Override - public void setProperty(Property prop, float value) { - super.setProperty(prop, value); - if (prop == Property.BOTTOM_BAR_TEXT_VISIBILITY) { - updateSearchBarTextOpacity(value); - } - } - // ============================================================================================ // Contextual Search Panel API // ============================================================================================ @@ -439,12 +432,6 @@ public class ContextualSearchPanel extends OverlayPanel { } @Override - public void updateBasePageSelectionYPx(float y) { - // NOTE(pedrosimonetti): exposing superclass method. - super.updateBasePageSelectionYPx(y); - } - - @Override public PanelState getPanelState() { // NOTE(pedrosimonetti): exposing superclass method to the interface. return super.getPanelState(); @@ -463,9 +450,7 @@ public class ContextualSearchPanel extends OverlayPanel { * @param searchTerm The string that represents the search term. */ public void displaySearchTerm(String searchTerm) { - cancelSearchTermResolutionAnimation(); getSearchBarControl().setSearchTerm(searchTerm); - resetSearchBarTermOpacity(); mPanelMetrics.onSearchRequestStarted(); } @@ -475,9 +460,7 @@ public class ContextualSearchPanel extends OverlayPanel { * @param end The portion of the context from the selection to its end. */ public void displaySearchContext(String selection, String end) { - cancelSearchTermResolutionAnimation(); getSearchBarControl().setSearchContext(selection, end); - resetSearchBarContextOpacity(); mPanelMetrics.onSearchRequestStarted(); } @@ -488,7 +471,6 @@ public class ContextualSearchPanel extends OverlayPanel { public void onSearchTermResolved(String searchTerm) { mPanelMetrics.onSearchTermResolved(); getSearchBarControl().setSearchTerm(searchTerm); - animateSearchTermResolution(); } /** @@ -508,6 +490,9 @@ public class ContextualSearchPanel extends OverlayPanel { protected void updatePanelForCloseOrPeek(float percentage) { super.updatePanelForCloseOrPeek(percentage); + // Update the opt out promo. + updatePromoVisibility(1.f); + getPeekPromoControl().onUpdateFromCloseToPeek(percentage); } @@ -515,6 +500,9 @@ public class ContextualSearchPanel extends OverlayPanel { protected void updatePanelForExpansion(float percentage) { super.updatePanelForExpansion(percentage); + // Update the opt out promo. + updatePromoVisibility(1.f); + getPeekPromoControl().onUpdateFromPeekToExpand(percentage); } @@ -522,6 +510,9 @@ public class ContextualSearchPanel extends OverlayPanel { protected void updatePanelForMaximization(float percentage) { super.updatePanelForMaximization(percentage); + // Update the opt out promo. + updatePromoVisibility(1.f - percentage); + getPeekPromoControl().onUpdateFromExpandToMaximize(percentage); } @@ -531,44 +522,50 @@ public class ContextualSearchPanel extends OverlayPanel { updatePromoLayout(); } + // NOTE(pedrosimonetti): We cannot tell where the selection will be after the + // orientation change, so we are setting the selection position to zero, which + // means the base page will be positioned in its original state and we won't + // try to keep the selection in view. + updateBasePageSelectionYPx(0.f); + updateBasePageTargetY(); + super.updatePanelForOrientationChange(); } // ============================================================================================ - // ContextualSearchBarControl + // Selection position // ============================================================================================ - private ContextualSearchBarControl mContextualSearchBarControl; - private float mSearchBarContextOpacity = 1.f; - private float mSearchBarTermOpacity = 1.f; + /** The approximate Y coordinate of the selection in pixels. */ + private float mBasePageSelectionYPx = -1.f; /** - * @return The opacity of the SearchBar's search context. + * Updates the coordinate of the existing selection. + * @param y The y coordinate of the selection in pixels. */ - public float getSearchBarContextOpacity() { - return mSearchBarContextOpacity; + public void updateBasePageSelectionYPx(float y) { + mBasePageSelectionYPx = y; } - /** - * @return The opacity of the SearchBar's search term. - */ - public float getSearchBarTermOpacity() { - return mSearchBarTermOpacity; + @Override + protected float calculateBasePageDesiredOffset() { + float offset = 0.f; + if (mBasePageSelectionYPx > 0.f) { + // Convert from px to dp. + final float selectionY = mBasePageSelectionYPx * mPxToDp; + + // Calculate the offset to center the selection on the available area. + final float availableHeight = getTabHeight() - getExpandedHeight(); + offset = -selectionY + availableHeight / 2; + } + return offset; } - /** - * @return The Id of the Search Context View. - */ - public int getSearchContextViewId() { - return getSearchBarControl().getSearchContextViewId(); - } + // ============================================================================================ + // ContextualSearchBarControl + // ============================================================================================ - /** - * @return The Id of the Search Term View. - */ - public int getSearchTermViewId() { - return getSearchBarControl().getSearchTermViewId(); - } + private ContextualSearchBarControl mSearchBarControl; /** * Creates the ContextualSearchBarControl, if needed. The Views are set to INVISIBLE, because @@ -578,61 +575,24 @@ public class ContextualSearchPanel extends OverlayPanel { assert mContainerView != null; assert mResourceLoader != null; - if (mContextualSearchBarControl == null) { - mContextualSearchBarControl = + if (mSearchBarControl == null) { + mSearchBarControl = new ContextualSearchBarControl(this, mContext, mContainerView, mResourceLoader); } - assert mContextualSearchBarControl != null; - return mContextualSearchBarControl; + return mSearchBarControl; } /** * Destroys the ContextualSearchBarControl. */ protected void destroySearchBarControl() { - if (mContextualSearchBarControl != null) { - mContextualSearchBarControl.destroy(); - mContextualSearchBarControl = null; + if (mSearchBarControl != null) { + mSearchBarControl.destroy(); + mSearchBarControl = null; } } - /** - * Updates the UI state for the SearchBar text. The search context view will fade out - * while the search term fades in. - * - * @param percentage The visibility percentage of the search term view. - */ - protected void updateSearchBarTextOpacity(float percentage) { - // The search context will start fading out before the search term starts fading in. - // They will both be partially visible for overlapPercentage of the animation duration. - float overlapPercentage = .75f; - float fadingOutPercentage = Math.max(1 - (percentage / overlapPercentage), 0.f); - float fadingInPercentage = - Math.max(percentage - (1 - overlapPercentage), 0.f) / overlapPercentage; - - mSearchBarContextOpacity = fadingOutPercentage; - mSearchBarTermOpacity = fadingInPercentage; - } - - /** - * Resets the SearchBar text opacity when a new search context is set. The search - * context is made visible and the search term invisible. - */ - private void resetSearchBarContextOpacity() { - mSearchBarContextOpacity = 1.f; - mSearchBarTermOpacity = 0.f; - } - - /** - * Resets the SearchBar text opacity when a new search term is set. The search - * term is made visible and the search context invisible. - */ - private void resetSearchBarTermOpacity() { - mSearchBarContextOpacity = 0.f; - mSearchBarTermOpacity = 1.f; - } - // ============================================================================================ // Search Provider Icon Sprite // ============================================================================================ @@ -666,12 +626,16 @@ public class ContextualSearchPanel extends OverlayPanel { private ContextualSearchPeekPromoControl mPeekPromoControl; - @Override + /** + * @return The height of the Peek Promo in the peeked state, in pixels. + */ protected float getPeekPromoHeightPeekingPx() { return getPeekPromoControl().getHeightPeekingPx(); } - @Override + /** + * @return The height of the Peek Promo, in pixels. + */ protected float getPeekPromoHeight() { return getPeekPromoControl().getHeightPx(); } @@ -723,23 +687,16 @@ public class ContextualSearchPanel extends OverlayPanel { */ private boolean mIsAnimatingMandatoryPromoAcceptance; - @Override + /** + * @return Whether the Panel Promo is visible. + */ protected boolean isPromoVisible() { return mIsPromoVisible; } - @Override - protected void animatePromoAcceptance() { - if (mIsPromoMandatory) { - mIsAnimatingMandatoryPromoAcceptance = true; - getOverlayPanelContent().showContent(); - expandPanel(StateChangeReason.PROMO_ACCEPTED); - } - - super.animatePromoAcceptance(); - } - - @Override + /** + * Notifies that the acceptance animation has finished. + */ protected void onPromoAcceptanceAnimationFinished() { mIsAnimatingMandatoryPromoAcceptance = false; @@ -785,4 +742,309 @@ public class ContextualSearchPanel extends OverlayPanel { public void destroyContent() { super.destroyOverlayPanelContent(); } + + // ============================================================================================ + // Promo Host + // ============================================================================================ + + @Override + public void onPromoPreferenceClick() { + new Handler().post(new Runnable() { + @Override + public void run() { + PreferencesLauncher.launchSettingsPage(mContext, + ContextualSearchPreferenceFragment.class.getName()); + } + }); + } + + @Override + public void onPromoButtonClick(boolean accepted) { + if (accepted) { + animatePromoAcceptance(); + } else { + hidePromoView(); + // NOTE(pedrosimonetti): If the user has opted out of Contextual Search, we should set + // the preference right away because the preference state controls whether the promo + // will be visible, and we want to hide the promo immediately when the user opts out. + setPreferenceState(false); + closePanel(StateChangeReason.OPTOUT, true); + } + } + + // ============================================================================================ + // Opt Out Promo View + // ============================================================================================ + + // TODO(pedrosimonetti): Consider maybe adding a 9.patch to avoid the hacky nested layouts in + // order to have the transparent gap at the top of the Promo View. Currently, the Promo View + // has a gap at the top where a shadow will be rendered. The gap is needed because the shadow + // needs to be rendered with the Compositor, which cannot be rendered on top of the Promo's + // Android View. The suggestion here is to try to use a 9.patch to render the background of + // the Promo View, which would include the gap at the top. This would allow us simplify the + // Promo View, by removing the extra nested layout used to leave a gap at the top of the View. + + /** + * The {@link ContextualSearchOptOutPromo} instance. + */ + private ContextualSearchOptOutPromo mPromoView; + + /** + * Whether the Search Promo View is visible. + */ + private boolean mIsSearchPromoViewVisible = false; + + /** + * Whether the Promo's acceptance animation is running. + */ + private boolean mIsAnimatingPromoAcceptance; + + /** + * Creates the Search Promo View. + */ + protected void createPromoView() { + if (isPromoVisible() && mPromoView == null) { + assert mContainerView != null; + + // TODO(pedrosimonetti): Refactor promo code to use ViewResourceInflater. + LayoutInflater.from(mContext).inflate( + R.layout.contextual_search_opt_out_promo, mContainerView); + mPromoView = (ContextualSearchOptOutPromo) + mContainerView.findViewById(R.id.contextual_search_opt_out_promo); + + if (mResourceLoader != null) { + mResourceLoader.registerResource(R.id.contextual_search_opt_out_promo, + mPromoView.getResourceAdapter()); + } + + mPromoView.setPromoHost(this); + + updatePromoLayout(); + + assert mPromoView != null; + } + } + + /** + * Updates the Promo layout. + */ + protected void updatePromoLayout() { + final int maximumWidth = getMaximumWidthPx(); + + // Adjust size for small Panel. + if (!isFullWidthSizePanel()) { + mPromoView.getLayoutParams().width = maximumWidth; + mPromoView.requestLayout(); + } + + setPromoContentHeightPx(mPromoView.getHeightForGivenWidth(maximumWidth)); + } + + /** + * Destroys the Search Promo View. + */ + protected void destroyPromoView() { + if (mPromoView != null) { + mContainerView.removeView(mPromoView); + mPromoView = null; + if (mResourceLoader != null) { + mResourceLoader.unregisterResource(R.id.contextual_search_opt_out_promo); + } + } + } + + /** + * Displays the Search Promo View at the given Y position. + * + * @param y The Y position. + */ + private void showPromoViewAtYPosition(float y) { + if (mPromoView == null + || mIsSearchPromoViewVisible + || mIsAnimatingMandatoryPromoAcceptance + || !isPromoVisible()) return; + + float offsetX = getOffsetX() / mPxToDp; + if (LocalizationUtils.isLayoutRtl()) { + offsetX = -offsetX; + } + + mPromoView.setTranslationX(offsetX); + mPromoView.setTranslationY(y); + mPromoView.setVisibility(View.VISIBLE); + + // NOTE(pedrosimonetti): We need to call requestLayout, otherwise + // the Promo View will not become visible. + mPromoView.requestLayout(); + + mIsSearchPromoViewVisible = true; + } + + /** + * Hides the Search Promo View. + */ + protected void hidePromoView() { + if (mPromoView == null + || !mIsSearchPromoViewVisible + || !isPromoVisible()) { + return; + } + + mPromoView.setVisibility(View.INVISIBLE); + + mIsSearchPromoViewVisible = false; + } + + /** + * Animates the acceptance of the Promo. + */ + protected void animatePromoAcceptance() { + hidePromoView(); + + if (mIsPromoMandatory) { + mIsAnimatingMandatoryPromoAcceptance = true; + getOverlayPanelContent().showContent(); + expandPanel(StateChangeReason.PROMO_ACCEPTED); + } + + mIsAnimatingPromoAcceptance = true; + animateProperty(Property.PROMO_VISIBILITY, 1.f, 0.f, BASE_ANIMATION_DURATION_MS); + } + + /** + * Updates the UI state for Opt In Promo animation. + * + * @param percentage The visibility percentage of the Promo. + */ + @Override + protected void setPromoVisibilityForOptInAnimation(float percentage) { + updatePromoVisibility(percentage); + updateBarShadow(); + } + + /** + * Updates the UI state for Opt Out Promo. + * + * @param percentage The visibility percentage of the Promo. A visibility of 0 means the + * Promo is not visible. A visibility of 1 means the Promo is fully visible. And + * visibility between 0 and 1 means the Promo is partially visible. + */ + private void updatePromoVisibility(float percentage) { + if (isPromoVisible()) { + mPromoVisible = true; + + mPromoHeightPx = Math.round(MathUtils.clamp(percentage * mPromoContentHeightPx, + 0.f, mPromoContentHeightPx)); + mPromoOpacity = percentage; + } else { + mPromoVisible = false; + mPromoHeightPx = 0.f; + mPromoOpacity = 0.f; + } + } + + // -------------------------------------------------------------------------------------------- + // Promo states + // -------------------------------------------------------------------------------------------- + + private boolean mPromoVisible = false; + private float mPromoContentHeightPx = 0.f; + private float mPromoHeightPx; + private float mPromoOpacity; + + /** + * @return Whether the promo is visible. + */ + public boolean getPromoVisible() { + return mPromoVisible; + } + + /** + * Sets the height of the promo content. + */ + public void setPromoContentHeightPx(float heightPx) { + mPromoContentHeightPx = heightPx; + } + + /** + * @return Height of the promo in pixels. + */ + public float getPromoHeightPx() { + return mPromoHeightPx; + } + + /** + * @return The opacity of the promo. + */ + public float getPromoOpacity() { + return mPromoOpacity; + } + + /** + * @return Y coordinate of the promo in pixels. + */ + protected float getPromoYPx() { + return Math.round((getOffsetY() + getBarContainerHeight()) / mPxToDp); + } + + // ============================================================================================ + // Changes made to the OverlayPanel methods in order to support the Promo. + // TODO(pedrosimonetti): Re-organize this code once Promo is implemented in its own Control. + // ============================================================================================ + + @Override + protected void setPanelHeight(float height) { + // As soon as we resize the Panel to a different height than the expanded one, + // then we should hide the Promo View once the snapshot will be shown in its place. + if (height != getPanelHeightFromState(PanelState.EXPANDED)) { + hidePromoView(); + } + + super.setPanelHeight(height); + } + + @Override + protected PanelState getProjectedState(float velocity) { + PanelState projectedState = super.getProjectedState(velocity); + + // Prevent the fling gesture from moving the Panel from PEEKED to MAXIMIZED if the Panel + // Promo is available and we are running in full screen panel mode. This is to make sure + // the Promo will be visible, considering that the EXPANDED state is the only one that will + // show the Promo in full screen panel mode. In narrow panel UI the Promo is visible in + // maximized so this project state change is not needed. + if (isPromoVisible() + && projectedState == PanelState.MAXIMIZED + && getPanelState() == PanelState.PEEKED) { + projectedState = PanelState.EXPANDED; + } + + return projectedState; + } + + @Override + public float getContentY() { + return getOffsetY() + getBarContainerHeight() + getPromoHeightPx() * mPxToDp; + } + + @Override + protected float getBarContainerHeight() { + return getBarHeight() + getPeekPromoHeight(); + } + + @Override + protected float getPeekedHeight() { + return getBarHeightPeeking() + getPeekPromoHeightPeekingPx() * mPxToDp; + } + + @Override + protected float calculateBarShadowOpacity() { + float barShadowOpacity = 0.f; + float barShadowHeightPx = 9.f / mPxToDp; + if (getPromoHeightPx() > 0.f) { + float threshold = 2 * barShadowHeightPx; + barShadowOpacity = getPromoHeightPx() > barShadowHeightPx ? 1.f + : MathUtils.interpolate(0.f, 1.f, getPromoHeightPx() / threshold); + } + return barShadowOpacity; + } } diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/ReaderModePanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/ReaderModePanel.java index a461405..51e3f90 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/ReaderModePanel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/ReaderModePanel.java @@ -155,10 +155,6 @@ public class ReaderModePanel extends OverlayPanel { mManagerDelegate = delegate; if (mManagerDelegate != null) { setChromeActivity(mManagerDelegate.getChromeActivity()); - initializeUiState(); - // TODO(mdjones): Improve the base page movement API so that the default behavior - // is to hide the toolbar; this function call should not be necessary here. - updateBasePageTargetY(); } } } @@ -291,12 +287,6 @@ public class ReaderModePanel extends OverlayPanel { } @Override - protected float calculateBasePageTargetY(PanelState state) { - // In the case of reader mode the base page will always need to move the same amount. - return -getToolbarHeight(); - } - - @Override public void onSizeChanged(float width, float height) { super.onSizeChanged(width, height); if (mManagerDelegate != null) { diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java index 99aee3c..c65bfdc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java @@ -6,7 +6,7 @@ package org.chromium.chrome.browser.compositor.scene_layer; import org.chromium.base.annotations.JNINamespace; import org.chromium.chrome.R; -import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel; +import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchBarControl; import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchIconSpriteControl; import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanel; import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPeekPromoControl; @@ -33,24 +33,20 @@ public class ContextualSearchSceneLayer extends SceneLayer { * Update the scene layer to draw an OverlayPanel. * @param resourceManager Manager to get view and image resources. * @param panel The OverlayPanel to render. - * @param searchContextViewId The ID of the view for Contextual Search's context. - * @param searchTermViewId The ID of the view containing the Contextual Search search term. - * @param peekPromoControl The peeking promotion for Contextual Search; optional if - * "panelType" is READER_MODE_PANEL. - * @param searchContextOpacity The opacity of the text specified by "searchContextViewId". - * @param searchTermOpacity The opacity of the text specified by "searchTermViewId". - * @param spriteControl The object controling the "G" animation for Contextual Search; optional - * if "panelType" is READER_MODE_PANEL. + * @param searchBarControl The Search Bar control. + * @param peekPromoControl The peeking promotion for Contextual Search. + * @param spriteControl The object controlling the "G" animation for Contextual Search. */ public void update(ResourceManager resourceManager, - OverlayPanel panel, - int searchContextViewId, - int searchTermViewId, + ContextualSearchPanel panel, + ContextualSearchBarControl searchBarControl, ContextualSearchPeekPromoControl peekPromoControl, - float searchContextOpacity, - float searchTermOpacity, ContextualSearchIconSpriteControl spriteControl) { + int searchContextViewId = searchBarControl.getSearchContextViewId(); + int searchTermViewId = searchBarControl.getSearchTermViewId(); + + // TODO(pedrosimonetti): Move to Promo logic to its own control class. boolean searchPromoVisible = panel.getPromoVisible(); float searchPromoHeightPx = panel.getPromoHeightPx(); float searchPromoOpacity = panel.getPromoOpacity(); @@ -74,6 +70,9 @@ public class ContextualSearchSceneLayer extends SceneLayer { float searchBarMarginSide = panel.getBarMarginSide(); float searchBarHeight = panel.getBarHeight(); + float searchContextOpacity = searchBarControl.getSearchBarContextOpacity(); + float searchTermOpacity = searchBarControl.getSearchBarTermOpacity(); + boolean searchBarBorderVisible = panel.isBarBorderVisible(); float searchBarBorderHeight = panel.getBarBorderHeight(); diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelManagerTest.java index 50f2f1c..b65a094 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelManagerTest.java @@ -106,12 +106,6 @@ public class OverlayPanelManagerTest extends InstrumentationTestCase { @Override public void removeLastHistoryEntry(String url, long timeInMs) {} } - - @Override - protected float getPeekPromoHeight() { - // Android Views are not used in this test so we cannot get the actual height. - return 0.f; - } } // -------------------------------------------------------------------------------------------- |