Commit 3104ff6d authored by pedrosimonetti's avatar pedrosimonetti Committed by Commit bot

Revert of [Contextual Search] Remove opt-in code. (patchset #6 id:100001 of...

Revert of [Contextual Search] Remove opt-in code. (patchset #6 id:100001 of https://codereview.chromium.org/1103163004/)

Reason for revert:
It broke Clank bots.

Original issue's description:
> [Contextual Search] Remove opt-in code.
>
> This CL requires a downstream change:
> https://chrome-internal-review.googlesource.com/#/c/214963/
>
> BUG=482618
> R=donnd@chromium.org, dtrainor@chromium.org, thakis@chromium.org
>
> Committed: https://chromium.googlesource.com/chromium/src/+/277f043bb56fb1e4bb93d9d17fc3de4ada0eb81b

TBR=donnd@chromium.org,mathp@chromium.org,dtrainor@chromium.org,thakis@chromium.org
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=482618

Review URL: https://codereview.chromium.org/1123313006

Cr-Commit-Position: refs/heads/master@{#330248}
parent 28c1b109
......@@ -69,6 +69,10 @@ public abstract class ChromeSwitches {
/** Enable Contextual Search. */
public static final String ENABLE_CONTEXTUAL_SEARCH = "enable-contextual-search";
/** Disable Contextual Search first-run flow, for testing. Not exposed to user. */
public static final String DISABLE_CONTEXTUAL_SEARCH_PROMO_FOR_TESTING =
"disable-contextual-search-promo-for-testing";
/** Enable Contextual Search for instrumentation testing. Not exposed to user. */
public static final String ENABLE_CONTEXTUAL_SEARCH_FOR_TESTING =
"enable-contextual-search-for-testing";
......
......@@ -81,6 +81,23 @@ public class ContextualSearchControl extends LinearLayout {
return parent;
}
/**
* Sets the text to display on top of the first-run promo.
* @param selection The portion of the text that represents the user's selection.
*/
public void setFirstRunText(String selection) {
// TODO(pedrosimonetti): confirm that is okay to remove the experimental text
// String firstRunText = ContextualSearchFieldTrial.getEnglishExperimentFirstRunText(
// selection);
// if (firstRunText == null) {
// firstRunText =
// getContext().getString(R.string.contextual_search_action_bar, selection);
// }
String firstRunText =
getContext().getString(R.string.contextual_search_action_bar, selection);
setCentralText(firstRunText);
}
/**
* Sets the search context to display in the control.
* @param selection The portion of the context that represents the user's selection.
......
......@@ -23,6 +23,7 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation
UNDEFINED,
CLOSED,
PEEKED,
PROMO,
EXPANDED,
MAXIMIZED;
}
......@@ -145,7 +146,7 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation
}
@Override
protected boolean isPromoAvailable() {
protected boolean isPanelPromoAvailable() {
return mManagementDelegate != null && mManagementDelegate.isOptOutPromoAvailable();
}
......@@ -153,7 +154,6 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation
public void onPromoButtonClick(boolean accepted) {
super.onPromoButtonClick(accepted);
mManagementDelegate.logPromoOutcome();
setIsPromoActive(false);
}
@Override
......@@ -236,7 +236,19 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation
if (mManagementDelegate.isRunningInCompatibilityMode()) {
mManagementDelegate.openResolvedSearchUrlInNewTab();
} else {
expandPanel(StateChangeReason.SEARCH_BAR_TAP);
// NOTE(pedrosimonetti): If the promo is active and getPromoContentHeight()
// returns -1 that means that the promo page hasn't finished loading, and
// therefore it wasn't possible to calculate the height of the promo contents.
// This will only happen if the user taps on a word that will trigger the
// promo, and then quickly taps on the peeking bar, before the promo page
// (which is local) finishes loading.
//
// TODO(pedrosimonetti): For now, we're simply ignoring the tap action in
// that case. Consider implementing a better approach, where the Panel
// would auto-expand once the height is calculated.
if (!getIsPromoActive() || getPromoContentHeight() != -1) {
expandPanel(StateChangeReason.SEARCH_BAR_TAP);
}
}
} else if (isExpanded()) {
peekPanel(StateChangeReason.SEARCH_BAR_TAP);
......@@ -385,6 +397,24 @@ public class ContextualSearchPanel extends ContextualSearchPanelAnimation
super.updateBasePageSelectionYPx(y);
}
@Override
public void setPromoContentHeight(float height) {
// NOTE(pedrosimonetti): exposing superclass method to the interface.
super.setPromoContentHeight(height);
}
@Override
public void setShouldHidePromoHeader(boolean shouldHidePromoHeader) {
// NOTE(pedrosimonetti): exposing superclass method to the interface.
super.setShouldHidePromoHeader(shouldHidePromoHeader);
}
@Override
public void animateAfterFirstRunSuccess() {
// NOTE(pedrosimonetti): exposing superclass method to the interface.
super.animateAfterFirstRunSuccess();
}
@Override
public void onLoadStarted() {
setProgressBarCompletion(0);
......
......@@ -28,7 +28,8 @@ abstract class ContextualSearchPanelAnimation extends ContextualSearchPanelBase
*/
protected enum Property {
PANEL_HEIGHT,
PROMO_VISIBILITY
PROMO_VISIBILITY,
FIRST_RUN_PANEL_HEIGHT,
}
/**
......@@ -109,7 +110,7 @@ abstract class ContextualSearchPanelAnimation extends ContextualSearchPanelBase
* @param reason The reason for the change of panel state.
*/
protected void expandPanel(StateChangeReason reason) {
animatePanelToState(PanelState.EXPANDED, reason);
animatePanelToState(getIntermediaryState(), reason);
}
/**
......@@ -192,6 +193,19 @@ abstract class ContextualSearchPanelAnimation extends ContextualSearchPanelBase
animateProperty(Property.PROMO_VISIBILITY, 1.f, 0.f, BASE_ANIMATION_DURATION_MS);
}
/**
* Animates the Contextual Search panel after first-run success.
*/
protected void animateAfterFirstRunSuccess() {
final PanelState desiredState = PanelState.EXPANDED;
mAnimatingState = desiredState;
mAnimatingStateReason = StateChangeReason.OPTIN;
final float desiredHeight = getPanelHeightFromState(desiredState);
animateProperty(Property.FIRST_RUN_PANEL_HEIGHT, getHeight(), desiredHeight,
BASE_ANIMATION_DURATION_MS);
}
/**
* Animates the Panel to its nearest state.
*/
......@@ -225,7 +239,7 @@ abstract class ContextualSearchPanelAnimation extends ContextualSearchPanelBase
// the EXPANDED state is the only one that will show the Promo.
if (projectedState == PanelState.MAXIMIZED
&& getPanelState() == PanelState.PEEKED
&& isPromoAvailable()) {
&& isPanelPromoAvailable()) {
projectedState = PanelState.EXPANDED;
}
......@@ -341,6 +355,8 @@ abstract class ContextualSearchPanelAnimation extends ContextualSearchPanelBase
setPanelHeight(value);
} else if (prop == Property.PROMO_VISIBILITY) {
setPromoVisibilityForOptInAnimation(value);
} else if (prop == Property.FIRST_RUN_PANEL_HEIGHT) {
setPanelHeightForPromoOptInAnimation(value);
}
}
......
......@@ -53,6 +53,23 @@ public interface ContextualSearchPanelDelegate {
*/
void updateBasePageSelectionYPx(float y);
/**
* Sets the content height of the First Run Flow Panel.
* @param height The content height of the First Run Flow Panel.
*/
void setPromoContentHeight(float height);
/**
* @param shouldHidePromoHeader Sets whether the First Run Flow's header
* should be hidden.
*/
void setShouldHidePromoHeader(boolean shouldHidePromoHeader);
/**
* Animates the Contextual Search panel after first-run success.
*/
void animateAfterFirstRunSuccess();
/**
* Handles the onLoadStarted event in the WebContents.
*/
......
......@@ -18,7 +18,18 @@ import java.util.Map;
*/
abstract class ContextualSearchPanelStateHandler {
// Valid previous states for the Panel.
// Valid previous states for when the promo is active.
private static final Map<PanelState, PanelState> PREVIOUS_STATES_PROMO;
static {
Map<PanelState, PanelState> states = new HashMap<PanelState, PanelState>();
// Pairs are of the form <Current, Previous>.
states.put(PanelState.PEEKED, PanelState.CLOSED);
states.put(PanelState.PROMO, PanelState.PEEKED);
states.put(PanelState.EXPANDED, PanelState.PROMO);
PREVIOUS_STATES_PROMO = Collections.unmodifiableMap(states);
}
// Valid previous states for when the promo is not active (normal flow).
private static final Map<PanelState, PanelState> PREVIOUS_STATES_NORMAL;
static {
Map<PanelState, PanelState> states = new HashMap<PanelState, PanelState>();
......@@ -60,10 +71,28 @@ abstract class ContextualSearchPanelStateHandler {
* @return The {@code PanelState} that is before the |state| in the order of states.
*/
PanelState getPreviousPanelState(PanelState state) {
PanelState prevState = PREVIOUS_STATES_NORMAL.get(state);
PanelState prevState = mIsPromoActive
? PREVIOUS_STATES_PROMO.get(state)
: PREVIOUS_STATES_NORMAL.get(state);
return prevState != null ? prevState : PanelState.UNDEFINED;
}
/**
* Return the maximum state that the panel can be in, depending on whether the promo is
* active.
*/
PanelState getMaximumState() {
return mIsPromoActive ? PanelState.PROMO : PanelState.MAXIMIZED;
}
/**
* Return the intermediary state that the panel can be in, depending on whether the promo is
* active.
*/
PanelState getIntermediaryState() {
return mIsPromoActive ? PanelState.PROMO : PanelState.EXPANDED;
}
/**
* Sets the panel's state.
* @param toState The panel state to transition to.
......@@ -169,10 +198,14 @@ abstract class ContextualSearchPanelStateHandler {
* @return whether the state is valid.
*/
boolean isValidState(PanelState state) {
ArrayList<PanelState> validStates =
new ArrayList<PanelState>(PREVIOUS_STATES_NORMAL.values());
// MAXIMIZED is not the previous state of anything, but it's a valid state.
validStates.add(PanelState.MAXIMIZED);
ArrayList<PanelState> validStates;
if (mIsPromoActive) {
validStates = new ArrayList<PanelState>(PREVIOUS_STATES_PROMO.values());
} else {
validStates = new ArrayList<PanelState>(PREVIOUS_STATES_NORMAL.values());
// MAXIMIZED is not the previous state of anything, but it's a valid state.
validStates.add(PanelState.MAXIMIZED);
}
return validStates.contains(state);
}
......
......@@ -21,7 +21,6 @@ public interface ContextualSearchManagementDelegate {
public void setPreferenceState(boolean enabled);
/**
* TODO(pedrosimonetti): rename to isPromoAvailable (requires upstream and downstream changes).
* @return Whether the Opt-out promo is available to be be shown in the panel.
*/
boolean isOptOutPromoAvailable();
......
......@@ -408,6 +408,17 @@ public class ContextualSearchUma {
PROMO_BY_GESTURE_CODES = Collections.unmodifiableMap(codes);
}
/**
* Logs the state of the Contextual Search preference. This function should be called if the
* Contextual Search feature is enabled, and will track the different preference settings
* (disabled, enabled or uninitialized). Calling more than once is fine.
* This is deprecated; pass the number of taps remaining to logPreferenceState.
*/
@Deprecated
public static void logPreferenceState() {
logPreferenceState(PROMO_TAPS_REMAINING_INVALID);
}
/**
* Logs the state of the Contextual Search preference. This function should be called if the
* Contextual Search feature is enabled, and will track the different preference settings
......@@ -433,6 +444,16 @@ public class ContextualSearchUma {
enabled ? PREFERENCE_ENABLED : PREFERENCE_DISABLED, PREFERENCE_HISTOGRAM_BOUNDARY);
}
/**
* Logs the outcome of a first run flow.
* This is deprecated; call logPromoOutcome instead.
*/
@Deprecated
public static void logFirstRunFlowOutcome() {
RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchFirstRunFlowOutcome",
getPreferenceValue(), PREFERENCE_HISTOGRAM_BOUNDARY);
}
/**
* Logs the outcome of the promo (first run flow).
* Logs multiple histograms; with and without the originating gesture.
......
......@@ -24,6 +24,10 @@
<structure name="IDR_APP_LIST_START_PAGE_HTML" file="resources\app_list\start_page.html" flattenhtml="true" type="chrome_html" />
<structure name="IDR_APP_LIST_START_PAGE_JS" file="resources\app_list\start_page.js" flattenhtml="true" type="chrome_html" />
</if>
<if expr="is_android">
<structure name="IDR_CONTEXTUAL_SEARCH_PROMO_CSS" file="resources\contextual_search\promo.css" flattenhtml="true" type="chrome_html" />
<structure name="IDR_CONTEXTUAL_SEARCH_PROMO_HTML" file="resources\contextual_search\promo.html" flattenhtml="true" type="chrome_html" />
</if>
<if expr="not is_android">
<structure name="IDR_DOWNLOADS_CSS" file="resources\downloads\downloads.css" flattenhtml="true" type="chrome_html" />
<structure name="IDR_DOWNLOADS_HTML" file="resources\downloads\downloads.html" flattenhtml="true" allowexternalscript="true" type="chrome_html" />
......@@ -106,6 +110,10 @@
<if expr="enable_app_list">
<include name="IDR_CHROME_APP_MANIFEST" file="resources\chrome_app\manifest.json" type="BINDATA" />
</if>
<if expr="is_android">
<include name="IDR_CONTEXTUAL_SEARCH_PROMO_JS" file="resources\contextual_search\promo.js" flattenhtml="true" type="BINDATA" />
<include name="IDR_CONTEXTUAL_SEARCH_PROMO_HEADER_SVG" file="resources\contextual_search\header.svg" type="BINDATA" />
</if>
<if expr="not is_android and not is_ios">
<include name="IDR_COPRESENCE_CSS" file="resources\copresence.css" type="BINDATA" />
<include name="IDR_COPRESENCE_HTML" file="resources\copresence.html" type="BINDATA" />
......
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 156 99" enable-background="new 0 0 156 99" xml:space="preserve">
<g>
<rect x="48.2" y="55" fill="#51C1FF" width="108" height="26.7"/>
<path fill="#D4DDE1" d="M64,44c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4v-1c0-2.2,1.8-4,4-4h56c2.2,0,4,1.8,4,4V44z"/>
<path fill="#D4DDE1" d="M138,44c0,2.2-1.8,4-4,4H78c-2.2,0-4-1.8-4-4v-1c0-2.2,1.8-4,4-4h56c2.2,0,4,1.8,4,4V44z"/>
<path fill="#17F9FF" d="M145.9,69c0,2.2-1.8,4-4,4H62.2c-2.2,0-4-1.8-4-4v-1c0-2.2,1.8-4,4-4h79.7c2.2,0,4,1.8,4,4V69z"/>
<path fill="#D4DDE1" d="M37.8,69c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4v-1c0-2.2,1.8-4,4-4h29.8c2.2,0,4,1.8,4,4V69z"/>
<path fill="#D4DDE1" d="M79,95c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4v-1c0-2.2,1.8-4,4-4h71c2.2,0,4,1.8,4,4V95z"/>
<path fill="#D4DDE1" d="M119.1,95c0,2.2-1.8,4-4,4H93c-2.2,0-4-1.8-4-4v-1c0-2.2,1.8-4,4-4h22.1c2.2,0,4,1.8,4,4V95z"/>
<g>
<path fill="#448AFF" d="M122.2,21c0-11-9-20-20-20s-20,9-20,20c0,4.8,1.7,9.1,4.5,12.6c0,0,0,0,0,0l15.5,20l15.9-20.4c0,0,0,0,0,0
C120.6,29.8,122.2,25.6,122.2,21z"/>
</g>
<path fill="#FFFFFF" d="M106.2,23.1l-0.9-0.7c-0.3-0.3-0.7-0.6-0.7-1.2c0-0.6,0.4-1.1,0.9-1.4c1.1-0.9,2.2-1.8,2.2-3.7
c0-1.8-1.1-2.8-1.7-3.3h1.5l1-1.2h-5.3c-3.8,0-5.6,2.4-5.6,5c0,2,1.5,4.1,4.3,4.1h0.7c-0.1,0.3-0.3,0.7-0.3,1.1
c0,0.9,0.3,1.2,0.8,1.7c-1.2,0.1-3.4,0.3-5,1.4c-1.5,0.9-2,2.2-2,3.2c0,2,1.8,3.8,5.6,3.8c4.6,0,6.8-2.6,6.8-5
C108.4,25.1,107.4,24.1,106.2,23.1z M99.7,15.3c0-1.9,1.1-2.7,2.3-2.7c2.2,0,3.4,3,3.4,4.7c0,2.2-1.8,2.7-2.5,2.7
C100.9,19.9,99.7,17.3,99.7,15.3z M102.8,30.7c-2.8,0-4.6-1.3-4.6-3.2c0-1.9,1.7-2.5,2.2-2.7c1.1-0.3,2.6-0.4,2.8-0.4h0.6
c2.1,1.5,2.9,2.1,2.9,3.4C106.8,29.4,105.1,30.7,102.8,30.7z"/>
</g>
</svg>
/* Copyright 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. */
/* TODO: Need to clean up @font-face after we remove font-family from body. */
@font-face {
font-family: 'Roboto2';
font-weight: 400;
src: local('Roboto'), local('Roboto2-Regular'),
url(chrome://resources/roboto/roboto.woff2) format('woff2'),
url(chrome://resources/roboto/roboto.woff) format('woff');
}
/* TODO(pedrosimonetti): Find a better way to fix the problem when the
* text scaling preference is set to a high value.
*
* This CSS rule prevents the promo text from scaling as explained here:
* https://code.google.com/p/chromium/issues/detail?id=252828#c10
*
* For for background about the problem, see:
* https://code.google.com/p/chromium/issues/detail?id=466773
*/
#heading,
#description {
max-height: 999999px;
}
body {
font-family: 'Roboto2', sans-serif;
margin: 0;
}
a {
text-decoration: none;
}
a.colored-link {
color: rgb(66, 133, 244);
}
#container {
/* NOTE(pedrosimonetti): There's an implicit extra top margin that is
* rendered natively (currently using 24dp). So, the total padding will
* be 38dp (24dp + 14dp). For more info, see SEARCH_BAR_HEIGHT_STATE_PROMO
* in ContextualSearchPanelBase.java.
*
* We're also setting the side and bottom paddings to ensure to make sure
* that when computing the height of the container all margins/paddings will
* be considered.
*/
padding: 14px 16px 12px;
}
#button-container {
margin-top: 24px;
text-align: end;
width: 100%;
}
#container.hide {
-webkit-transform: scale(0.95);
-webkit-transition-duration: 130ms;
-webkit-transition-property: opacity, -webkit-transform;
opacity: 0;
}
#description {
color: #7E7E7E;
font-size: 16px;
line-height: 1.38em;
margin: 12px 0 24px;
}
/* Some properties below can be overridden in landscape orientation. */
#heading {
font-size: 23px;
margin: 20px 0 12px;
text-align: center;
}
.header-image {
background-image: url(header.svg);
background-repeat: no-repeat;
height: 98px;
margin: 0 auto 38px auto;
width: 156px;
}
.portrait {
display: block;
}
.landscape {
display: none;
}
/* Landscape */
@media screen and (orientation:landscape) {
#heading {
margin-top: 0;
/* The heading text and description text should be aligned, therefore
* the left margin here will be equal to the header image width (156px)
* plus its right margin (24px). Therefore the total left should be
* 156px + 24px = 180px.
*/
margin-left: 180px;
padding-top: 8px;
text-align: left;
}
.header-image {
/* The header image is supposed to be vertically centered when the promo
* is in landscape mode. For now, we're forcefully moving the image 4
* pixels up to make it centered. A better approach would be using CSS
* flexbox to properly center it, but this will require changing the
* markup and styling of the whole promo, and it could be tricky coming
* up with a single markup that works in both portrait and lanscape modes.
*/
margin: 0 24px 0 0;
position: relative;
top: -4px;
}
.portrait {
display: none;
}
.landscape {
display: block;
float: left;
}
html[dir='rtl'] .landscape {
float: right;
}
}
button {
background: none;
border: none;
display: inline-block;
font-family: 'Roboto2', sans-serif;
font-size: 14px;
margin: 6px 0;
/* We use a slightly different top-bottom padding because Roboto has a
* rendering bug which makes an extra padding to be rendered at the bottom of
* text.
*/
padding: 12px 16px 8px;
white-space: nowrap;
}
button .caption {
text-transform: uppercase;
}
#optin-button {
background: rgb(66, 133, 244);
background-clip: padding-box;
border-radius: 3px;
}
#optin-button .caption {
color: white;
}
#optout-button .caption {
color: rgb(66, 133, 244);
}
<!doctype html>
<html>
<!-- Copyright 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no">
<title>Contextual Search First-Run</title>
<link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
<link rel="stylesheet" href="promo.css">
<script src="chrome://contextual-search-promo/config.js"></script>
<script src="chrome://contextual-search-promo/promo.js"></script>
</head>
<body>
<div id="container">
<div class="header-image portrait"></div>
<div id="heading" i18n-content="heading"></div>
<div class="header-image landscape"></div>
<div id="description">
<span i18n-content="description-1"></span>
<a class="colored-link" href="#learn-more"
i18n-content="feature-name">
</a>
<span i18n-content="description-2"></span>
</div>
<div id="button-container">
<button id="optout-button">
<span class="caption" i18n-content="optOut"></span>
</button>
<button id="optin-button">
<span class="caption" i18n-content="optIn"></span>
</button>
</div>
</div>
</body>
</html>
/* Copyright 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
*/
<include src="../../../../ui/webui/resources/js/util.js">
<include src="../../../../ui/webui/resources/js/load_time_data.js">
/**
* The amount of delay to use in the opt-in action in order to give time for
* the fade-out animation to execute, before navigating to the opt-in URL,
* in milliseconds.
* @const
*/
var OPT_IN_DELAY_MS = 65;
/**
* Once the DOM is loaded, determine if the header image is to be kept and
* register a handler to add the 'hide' class to the container element in order
* to hide it.
*/
document.addEventListener('DOMContentLoaded', function(event) {
if (config['hideHeader']) {
removeHeaderImages();
}
$('optin-button').addEventListener('click', function() {
$('container').classList.add('hide');
setTimeout(function() {
location.hash = 'optin';
}, OPT_IN_DELAY_MS);
});
$('optout-button').addEventListener('click', function() {
location.hash = 'optout';
});
});
/**
* Returns the height of the content. Method called from Chrome to properly size
* the view embedding it.
* @return {number} The height of the content, in pixels.
*/
function getContentHeight() {
return $('container').clientHeight;
}
/**
* Removes all header images from the promo.
*/
function removeHeaderImages() {
var images = document.querySelectorAll('.header-image');
for (var i = 0, length = images.length; i < length; i++) {
var image = images[i];
var parent = image.parentElement;
if (parent) {
parent.removeChild(image);
}
}
}
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/search/contextual_search_promo_source_android.h"
#include <string>
#include "base/json/json_string_value_serializer.h"
#include "base/memory/ref_counted_memory.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "chrome/common/url_constants.h"
#include "chrome/grit/chromium_strings.h"
#include "components/variations/variations_associated_data.h"
#include "grit/browser_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/webui/jstemplate_builder.h"
#include "url/gurl.h"
namespace {
const char kPromoConfigPath[] = "/config.js";
const char kPromoHTMLPath[] = "/promo.html";
const char kPromoCSSPath[] = "/promo.css";
const char kPromoJSPath[] = "/promo.js";
// Field trial related constants.
const char kContextualSearchFieldTrialName[] = "ContextualSearch";
const char kContextualSearchHidePromoHeaderParam[] = "hide_promo_header";
const char kContextualSearchEnabledValue[] = "enabled";
// Returns whether we should hide the first-run promo header.
bool ShouldHidePromoHeader() {
return variations::GetVariationParamValue(
kContextualSearchFieldTrialName, kContextualSearchHidePromoHeaderParam) ==
kContextualSearchEnabledValue;
}
// Returns a JS dictionary of configuration data for the Contextual Search
// promo.
std::string GetConfigData() {
base::DictionaryValue config_data;
config_data.SetBoolean("hideHeader", ShouldHidePromoHeader());
// Serialize the dictionary.
std::string js_text;
JSONStringValueSerializer serializer(&js_text);
serializer.Serialize(config_data);
std::string config_data_js;
config_data_js.append("var config = ");
config_data_js.append(js_text);
config_data_js.append(";");
return config_data_js;
}
} // namespace
ContextualSearchPromoSourceAndroid::ContextualSearchPromoSourceAndroid() {}
ContextualSearchPromoSourceAndroid::~ContextualSearchPromoSourceAndroid() {}
void ContextualSearchPromoSourceAndroid::StartDataRequest(
const std::string& path_and_query, int render_process_id,
int render_frame_id,
const content::URLDataSource::GotDataCallback& callback) {
GURL url(std::string(chrome::kChromeUIContextualSearchPromoURL) + "/" +
path_and_query);
std::string path(url.path());
if (path == kPromoHTMLPath) {
SendHtmlWithStrings(callback);
} else if (path == kPromoCSSPath) {
SendResource(IDR_CONTEXTUAL_SEARCH_PROMO_CSS, callback);
} else if (path == kPromoJSPath) {
SendResource(IDR_CONTEXTUAL_SEARCH_PROMO_JS, callback);
} else if (path == kPromoConfigPath) {
SendConfigResource(callback);
} else {
callback.Run(NULL);
}
}
std::string ContextualSearchPromoSourceAndroid::GetSource() const {
return chrome::kChromeUIContextualSearchPromoHost;
}
std::string ContextualSearchPromoSourceAndroid::GetMimeType(
const std::string& path_and_query) const {
std::string path(GURL("chrome://host/" + path_and_query).path());
if (EndsWith(path, ".js", false)) return "application/javascript";
if (EndsWith(path, ".png", false)) return "image/png";
if (EndsWith(path, ".css", false)) return "text/css";
if (EndsWith(path, ".html", false)) return "text/html";
if (EndsWith(path, ".woff", false)) return "font/woff";
if (EndsWith(path, ".woff2", false)) return "font/woff2";
return "";
}
bool ContextualSearchPromoSourceAndroid::ShouldDenyXFrameOptions() const {
return false;
}
bool
ContextualSearchPromoSourceAndroid::ShouldAddContentSecurityPolicy() const {
return false;
}
void ContextualSearchPromoSourceAndroid::SendResource(
int resource_id, const content::URLDataSource::GotDataCallback& callback) {
scoped_refptr<base::RefCountedStaticMemory> response(
ResourceBundle::GetSharedInstance().LoadDataResourceBytes(resource_id));
callback.Run(response.get());
}
void ContextualSearchPromoSourceAndroid::SendConfigResource(
const content::URLDataSource::GotDataCallback& callback) {
std::string response = GetConfigData();
callback.Run(base::RefCountedString::TakeString(&response));
}
void ContextualSearchPromoSourceAndroid::SendHtmlWithStrings(
const content::URLDataSource::GotDataCallback& callback) {
base::DictionaryValue strings_data;
// The three following statements are part of the description paragraph.
strings_data.SetString(
"description-1",
l10n_util::GetStringUTF16(IDS_CONTEXTUAL_SEARCH_PROMO_DESCRIPTION_1));
strings_data.SetString(
"feature-name",
l10n_util::GetStringUTF16(IDS_CONTEXTUAL_SEARCH_PROMO_FEATURE_NAME));
strings_data.SetString(
"description-2",
l10n_util::GetStringUTF16(IDS_CONTEXTUAL_SEARCH_PROMO_DESCRIPTION_2));
strings_data.SetString(
"heading", l10n_util::GetStringUTF16(IDS_CONTEXTUAL_SEARCH_HEADER));
strings_data.SetString(
"optIn", l10n_util::GetStringUTF16(IDS_CONTEXTUAL_SEARCH_PROMO_OPTIN));
strings_data.SetString(
"optOut", l10n_util::GetStringUTF16(IDS_CONTEXTUAL_SEARCH_PROMO_OPTOUT));
base::StringPiece html(
ResourceBundle::GetSharedInstance().GetRawDataResource(
IDR_CONTEXTUAL_SEARCH_PROMO_HTML));
std::string response(webui::GetI18nTemplateHtml(html, &strings_data));
callback.Run(base::RefCountedString::TakeString(&response));
}
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_SEARCH_CONTEXTUAL_SEARCH_PROMO_SOURCE_ANDROID_H_
#define CHROME_BROWSER_SEARCH_CONTEXTUAL_SEARCH_PROMO_SOURCE_ANDROID_H_
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "content/public/browser/url_data_source.h"
// Serves HTML for displaying the contextual search first-run promo.
class ContextualSearchPromoSourceAndroid : public content::URLDataSource {
public:
ContextualSearchPromoSourceAndroid();
~ContextualSearchPromoSourceAndroid() override;
protected:
// Overridden from content::URLDataSource:
void StartDataRequest(
const std::string& path_and_query,
int render_process_id,
int render_frame_id,
const content::URLDataSource::GotDataCallback& callback) override;
std::string GetSource() const override;
std::string GetMimeType(const std::string& path_and_query) const override;
bool ShouldDenyXFrameOptions() const override;
bool ShouldAddContentSecurityPolicy() const override;
// Sends unmodified resource bytes.
void SendResource(
int resource_id,
const content::URLDataSource::GotDataCallback& callback);
// Sends the config JS resource.
void SendConfigResource(
const content::URLDataSource::GotDataCallback& callback);
// Sends HTML with localized strings.
void SendHtmlWithStrings(
const content::URLDataSource::GotDataCallback& callback);
private:
DISALLOW_COPY_AND_ASSIGN(ContextualSearchPromoSourceAndroid);
};
#endif // CHROME_BROWSER_SEARCH_CONTEXTUAL_SEARCH_PROMO_SOURCE_ANDROID_H_
......@@ -664,6 +664,8 @@
'browser/safe_json_parser.h',
'browser/search/contextual_search_policy_handler_android.cc',
'browser/search/contextual_search_policy_handler_android.h',
'browser/search/contextual_search_promo_source_android.cc',
'browser/search/contextual_search_promo_source_android.h',
'browser/search/iframe_source.cc',
'browser/search/iframe_source.h',
'browser/search/instant_io_context.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment