Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(954)

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelBase.java

Issue 1050163004: [Contextual Search] Implements Opt-out promo. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Sync and rebase Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelBase.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelBase.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelBase.java
index 33f83bb7b26b807ca2c90bc1d9dc7e17b82fa2b5..62fb59bd59f8e30ff8e141257b94fd2407dea7f0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelBase.java
@@ -5,17 +5,26 @@
package org.chromium.chrome.browser.compositor.bottombar.contextualsearch;
import android.content.Context;
+import android.os.Handler;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.R;
+import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchOptOutPromo.ContextualSearchPromoHost;
import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanel.PanelState;
import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanel.StateChangeReason;
+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.resources.dynamics.DynamicResourceLoader;
/**
* Base abstract class for the Contextual Search Panel.
*/
-abstract class ContextualSearchPanelBase extends ContextualSearchPanelStateHandler {
+abstract class ContextualSearchPanelBase extends ContextualSearchPanelStateHandler
+ implements ContextualSearchPromoHost {
/**
* The height of the expanded Contextual Search Panel relative to the height
@@ -165,6 +174,11 @@ abstract class ContextualSearchPanelBase extends ContextualSearchPanelStateHandl
*/
private boolean mIsShowing;
+ /**
+ * The current context.
+ */
+ private final Context mContext;
+
// ============================================================================================
// Constructor
// ============================================================================================
@@ -173,6 +187,8 @@ abstract class ContextualSearchPanelBase extends ContextualSearchPanelStateHandl
* @param context The current Android {@link Context}.
*/
public ContextualSearchPanelBase(Context context) {
+ mContext = context;
+
mPxToDp = 1.f / context.getResources().getDisplayMetrics().density;
mSearchBarHeightPeeking = context.getResources().getDimension(
@@ -186,6 +202,22 @@ abstract class ContextualSearchPanelBase extends ContextualSearchPanelStateHandl
}
// ============================================================================================
+ // General API
+ // ============================================================================================
+
+ /**
+ * Animates the Contextual Search Panel to its closed state.
+ *
+ * @param reason The reason for the change of panel state.
+ */
+ protected abstract void closePanel(StateChangeReason reason, boolean animate);
+
+ /**
+ * @return Whether the Panel Promo is available.
+ */
+ protected abstract boolean isPanelPromoAvailable();
+
+ // ============================================================================================
// Layout Integration
// ============================================================================================
@@ -353,6 +385,10 @@ abstract class ContextualSearchPanelBase extends ContextualSearchPanelStateHandl
private boolean mIsSearchBarBorderVisible;
private float mSearchBarBorderY;
private float mSearchBarBorderHeight;
+
+ boolean mSearchBarShadowVisible = false;
+ float mSearchBarShadowOpacity = 0.f;
+
private float mSearchProviderIconOpacity;
private float mSearchIconPaddingLeft;
private float mSearchIconOpacity;
@@ -400,6 +436,20 @@ abstract class ContextualSearchPanelBase extends ContextualSearchPanelStateHandl
}
/**
+ * @return Whether the Search Bar shadow is visible.
+ */
+ public boolean getSearchBarShadowVisible() {
+ return mSearchBarShadowVisible;
+ }
+
+ /**
+ * @return The opacity of the Search Bar shadow.
+ */
+ public float getSearchBarShadowOpacity() {
+ return mSearchBarShadowOpacity;
+ }
+
+ /**
* @return The opacity of the search provider's icon.
*/
public float getSearchProviderIconOpacity() {
@@ -504,10 +554,68 @@ abstract class ContextualSearchPanelBase extends ContextualSearchPanelStateHandl
// Promo states
// --------------------------------------------------------------------------------------------
+ private boolean mPromoVisible = false;
+ private float mPromoContentHeightPx = 0.f;
+ private float mPromoHeightPx;
+ private float mPromoOpacity;
+
+ /**
+ * @param visible Whether the promo will be set to visible.
+ */
+ protected void setPromoVisible(boolean visible) {
+ mPromoVisible = visible;
+ }
+
+ /**
+ * @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;
+ }
+
+ /**
+ * @return Y coordinate of the promo in pixels.
+ */
+ protected float getPromoYPx() {
+ return Math.round((getOffsetY() + getSearchBarHeight()) / mPxToDp);
+ }
+
+ // --------------------------------------------------------------------------------------------
+ // Opt In Promo states
+ // --------------------------------------------------------------------------------------------
+
private float mPromoContentHeight;
private boolean mShouldHidePromoHeader;
- /**
+ /**
* Sets the height of the promo content.
*/
protected void setPromoContentHeight(float height) {
@@ -634,6 +742,10 @@ abstract class ContextualSearchPanelBase extends ContextualSearchPanelStateHandl
if (state == PanelState.CLOSED) {
mIsShowing = false;
+ destroySearchPromo();
+ destroyContextualSearchControl();
+ } else if (state == PanelState.EXPANDED) {
+ showPromoViewAtYPosition(getPromoYPx());
}
}
@@ -643,6 +755,12 @@ abstract class ContextualSearchPanelBase extends ContextualSearchPanelStateHandl
* @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);
}
@@ -750,6 +868,9 @@ abstract class ContextualSearchPanelBase extends ContextualSearchPanelStateHandl
* @param percentage The completion percentage.
*/
private void updatePanelForCloseOrPeek(float percentage) {
+ // Update the opt out promo.
+ updatePromo(1.f);
+
// Base page offset.
mBasePageY = 0.f;
@@ -773,6 +894,9 @@ abstract class ContextualSearchPanelBase extends ContextualSearchPanelStateHandl
// Progress Bar.
mProgressBarOpacity = 0.f;
+
+ // Update the Search Bar Shadow.
+ updateSearchBarShadow();
}
/**
@@ -782,6 +906,9 @@ abstract class ContextualSearchPanelBase extends ContextualSearchPanelStateHandl
* @param percentage The completion percentage.
*/
private void updatePanelForExpansion(float percentage) {
+ // Update the opt out promo.
+ updatePromo(1.f);
+
// Base page offset.
float baseBaseY = MathUtils.interpolate(
0.f,
@@ -825,6 +952,9 @@ abstract class ContextualSearchPanelBase extends ContextualSearchPanelStateHandl
float progressBarOpacity = MathUtils.interpolate(0.f, 1.f, diff / threshold);
mProgressBarOpacity = progressBarOpacity;
mProgressBarY = searchBarHeight - PROGRESS_BAR_HEIGHT_DP + 1;
+
+ // Update the Search Bar Shadow.
+ updateSearchBarShadow();
}
/**
@@ -834,6 +964,9 @@ abstract class ContextualSearchPanelBase extends ContextualSearchPanelStateHandl
* @param percentage The completion percentage.
*/
private void updatePanelForMaximization(float percentage) {
+ // Update the opt out promo.
+ updatePromo(1.f - percentage);
+
// Base page offset.
mBasePageY = getBasePageTargetY();
@@ -875,6 +1008,9 @@ abstract class ContextualSearchPanelBase extends ContextualSearchPanelStateHandl
// Progress Bar.
mProgressBarOpacity = 1.f;
mProgressBarY = searchBarHeight - PROGRESS_BAR_HEIGHT_DP + 1;
+
+ // Update the Search Bar Shadow.
+ updateSearchBarShadow();
}
/**
@@ -928,6 +1064,40 @@ abstract class ContextualSearchPanelBase extends ContextualSearchPanelStateHandl
mProgressBarY = searchBarHeight - PROGRESS_BAR_HEIGHT_DP + 1;
}
+ /**
+ * 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 updatePromo(float percentage) {
+ if (isPanelPromoAvailable()) {
+ mPromoVisible = true;
+
+ mPromoHeightPx = Math.round(MathUtils.clamp(percentage * mPromoContentHeightPx,
+ 0.f, mPromoContentHeightPx));
+ mPromoOpacity = percentage;
+ } else {
+ mPromoVisible = false;
+ }
+ }
+
+ /**
+ * Updates the UI state for Search Bar Shadow.
+ */
+ public void updateSearchBarShadow() {
+ float searchBarShadowHeightPx = 9 / mPxToDp;
+ if (mPromoVisible && mPromoHeightPx > 0.f) {
+ mSearchBarShadowVisible = true;
+ float threshold = 2 * searchBarShadowHeightPx;
+ mSearchBarShadowOpacity = mPromoHeightPx > searchBarShadowHeightPx ? 1.f :
+ MathUtils.interpolate(0.f, 1.f, mPromoHeightPx / threshold);
+ } else {
+ // TODO(pedrosimonetti): Calculate shadow when promo is not displayed.
+ }
+ }
+
// ============================================================================================
// Base Page Offset
// ============================================================================================
@@ -1003,7 +1173,198 @@ abstract class ContextualSearchPanelBase extends ContextualSearchPanelStateHandl
}
// ============================================================================================
- // Promo
+ // Resource Loader
+ // ============================================================================================
+
+ private ViewGroup mContainerView;
+ private DynamicResourceLoader mResourceLoader;
+
+ /**
+ * @param resourceLoader The {@link DynamicResourceLoader} to register and unregister the view.
+ */
+ public void setDynamicResourceLoader(DynamicResourceLoader resourceLoader) {
+ mResourceLoader = resourceLoader;
+
+ if (mControl != null) {
+ mResourceLoader.registerResource(R.id.contextual_search_view,
+ mControl.getResourceAdapter());
+ }
+
+ if (mSearchPromoView != null) {
+ mResourceLoader.registerResource(R.id.contextual_search_opt_out_promo,
+ mSearchPromoView.getResourceAdapter());
+ }
+ }
+
+ /**
+ * Sets the container ViewGroup to which the auxiliary Views will be attached to.
+ *
+ * @param container The {@link ViewGroup} container.
+ */
+ public void setContainerView(ViewGroup container) {
+ mContainerView = container;
+ }
+
+ // ============================================================================================
+ // ContextualSearchControl
+ // ============================================================================================
+
+ // TODO(pedrosimonetti): rename this to something more generic (e.g. BottomBarTextView).
+
+ private ContextualSearchControl mControl;
+
+ /**
+ * Inflates the Contextual Search control, if needed. The View will be set to INVISIBLE
+ * after being inflated, because it won't actually be displayed on the screen (its
+ * snapshot will be displayed instead).
+ */
+ protected ContextualSearchControl getContextualSearchControl() {
+ assert mContainerView != null;
+
+ if (mControl == null) {
+ LayoutInflater.from(mContext).inflate(R.layout.contextual_search_view, mContainerView);
+ mControl = (ContextualSearchControl)
+ mContainerView.findViewById(R.id.contextual_search_view);
+ if (mResourceLoader != null) {
+ mResourceLoader.registerResource(R.id.contextual_search_view,
+ mControl.getResourceAdapter());
+ }
+ }
+
+ assert mControl != null;
+ // TODO(pedrosimonetti): For now, we're still relying on a Android View
+ // to render the text that appears in the Search Bar. The View will be
+ // invisible and will not capture events. Consider rendering the text
+ // in the Compositor and get rid of the View entirely.
+ mControl.setVisibility(View.INVISIBLE);
+ return mControl;
+ }
+
+ protected void destroyContextualSearchControl() {
+ if (mControl != null) {
+ mContainerView.removeView(mControl);
+ mControl = null;
+ if (mResourceLoader != null) {
+ mResourceLoader.unregisterResource(R.id.contextual_search_view);
+ }
+ }
+ }
+
+ // ============================================================================================
+ // Promo Host
+ // ============================================================================================
+
+ @Override
+ public void onPromoPreferenceClick() {
+ closePanel(StateChangeReason.UNKNOWN, true);
+
+ new Handler().post(new Runnable() {
+ @Override
+ public void run() {
+ PreferencesLauncher.launchSettingsPage(mContext,
+ ContextualSearchPreferenceFragment.class.getName());
+ }
+ });
+ }
+
+ @Override
+ public void onPromoButtonClick(boolean accepted) {
+ // TODO(pedrosimonetti): Implement this!
+ }
+
+ // ============================================================================================
+ // 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.
+
+ /**
+ * The {@link ContextualSearchOptOutPromo} instance.
+ */
+ private ContextualSearchOptOutPromo mSearchPromoView;
+
+ /**
+ * Whether the Search Promo View is visible.
+ */
+ private boolean mIsSearchPromoViewVisible = false;
+
+ /**
+ * Creates the Search Promo View.
+ */
+ public void createSearchPromo() {
+ if (!isPanelPromoAvailable()) return;
+
+ assert mContainerView != null;
+
+ if (mSearchPromoView == null) {
+ LayoutInflater.from(mContext).inflate(
+ R.layout.contextual_search_opt_out_promo, mContainerView);
+ mSearchPromoView = (ContextualSearchOptOutPromo)
+ mContainerView.findViewById(R.id.contextual_search_opt_out_promo);
+ if (mResourceLoader != null) {
+ mResourceLoader.registerResource(R.id.contextual_search_opt_out_promo,
+ mSearchPromoView.getResourceAdapter());
+ }
+
+ mSearchPromoView.setPromoHost(this);
+ setPromoContentHeightPx(
+ mSearchPromoView.getHeightForGivenWidth(mContainerView.getWidth()));
+ }
+
+ assert mSearchPromoView != null;
+ }
+
+ /**
+ * Destroys the Search Promo View.
+ */
+ protected void destroySearchPromo() {
+ if (!isPanelPromoAvailable()) return;
+
+ if (mSearchPromoView != null) {
+ mContainerView.removeView(mSearchPromoView);
+ mSearchPromoView = 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.
+ */
+ public void showPromoViewAtYPosition(float y) {
+ if (mSearchPromoView == null || !isPanelPromoAvailable()) return;
+
+ mSearchPromoView.setTranslationY(y);
+ mSearchPromoView.setVisibility(View.VISIBLE);
+
+ // NOTE(pedrosimonetti): We need to call requestLayout, otherwise
+ // the Promo View will not become visible.
+ mSearchPromoView.requestLayout();
+
+ mIsSearchPromoViewVisible = true;
+ }
+
+ /**
+ * Hides the Search Promo View.
+ */
+ public void hidePromoView() {
+ if (mSearchPromoView == null
+ || !mIsSearchPromoViewVisible
+ || !isPanelPromoAvailable()) {
+ return;
+ }
+
+ mSearchPromoView.setVisibility(View.INVISIBLE);
+
+ mIsSearchPromoViewVisible = false;
+ }
+
+ // ============================================================================================
+ // Opt In Promo
// ============================================================================================
/**

Powered by Google App Engine
This is Rietveld 408576698