Commit 9ee8fcb2 authored by Olivier Robin's avatar Olivier Robin Committed by Chromium LUCI CQ

Create an ErrorPageController and persist dino game high score.

Bug: 1147387
Change-Id: Ic26d9b1910c9a8b11da0364331d4f39c74bd2499
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2574746
Commit-Queue: Olivier Robin <olivierrobin@chromium.org>
Reviewed-by: default avatarRohit Rao <rohitrao@chromium.org>
Reviewed-by: default avatarCathy Li <chili@chromium.org>
Reviewed-by: default avatarMike Dougherty <michaeldo@chromium.org>
Reviewed-by: default avatarGauthier Ambard <gambard@chromium.org>
Cr-Commit-Position: refs/heads/master@{#838029}
parent e1975986
......@@ -11,6 +11,9 @@ js_type_check("closure_compile") {
"//components/security_interstitials/core/common/resources:interstitial_mobile_nav",
"//ui/webui/resources/js:load_time_data",
]
if (is_ios) {
deps += [ ":error_page_controller_ios" ]
}
}
js_library("neterror") {
......@@ -22,3 +25,8 @@ js_library("neterror") {
js_library("offline") {
}
if (is_ios) {
js_library("error_page_controller_ios") {
}
}
// Copyright (c) 2020 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.
window.errorPageController = {
// Execute a button click to download page later.
downloadButtonClick: function() {},
// Execute a click on the reload button.
reloadButtonClick: function() {},
// Execute a "Details" button click.
detailsButtonClick: function() {},
// Execute a "Diagnose Errors" button click.
diagnoseErrorsButtonClick: function() {},
// ???
launchOfflineItem: function() {},
savePageForLater: function() {},
cancelSavePage: function() {},
listVisibilityChange: function() {},
// Track easter egg plays and high scores.
trackEasterEgg: function() {
__gCrWeb.message.invokeOnHost(
{'command': 'errorPageController.trackEasterEgg'});
},
updateEasterEggHighScore: function(highScore) {
__gCrWeb.message.invokeOnHost({
'command': 'errorPageController.updateEasterEggHighScore',
'highScore': highScore.toString()
});
},
resetEasterEggHighScore: function() {
__gCrWeb.message.invokeOnHost(
{'command': 'errorPageController.resetEasterEggHighScore'});
}
};
// Create a __gCrWeb binding of initializeEasterEggHighScore so it can be
// called using JS messaging.
__gCrWeb.errorPageController = {};
__gCrWeb['errorPageController'] = __gCrWeb.errorPageController;
__gCrWeb.errorPageController['initializeEasterEggHighScore'] = function(
highscore) {
initializeEasterEggHighScore(highscore);
};
......@@ -13,6 +13,9 @@
<script src="neterror.js"></script>
<script src="../../../components/security_interstitials/core/common/resources/interstitial_mobile_nav.js"></script>
<script src="offline.js"></script>
<if expr="is_ios">
<script src="error_page_controller_ios.js"></script>
</if>
</head>
<body id="t" style="font-family: $i18n{fontfamily}; font-size: $i18n{fontsize}">
<div id="main-frame-error" class="interstitial-wrapper">
......
......@@ -67,6 +67,7 @@
#import "ios/chrome/browser/ui/ui_feature_flags.h"
#import "ios/chrome/browser/voice/voice_search_navigations_tab_helper.h"
#import "ios/chrome/browser/web/blocked_popup_tab_helper.h"
#include "ios/chrome/browser/web/error_page_controller_bridge.h"
#import "ios/chrome/browser/web/features.h"
#import "ios/chrome/browser/web/font_size_tab_helper.h"
#import "ios/chrome/browser/web/image_fetch_tab_helper.h"
......@@ -120,6 +121,7 @@ void AttachTabHelpers(web::WebState* web_state, bool for_prerender) {
web_state);
password_manager::WellKnownChangePasswordTabHelper::CreateForWebState(
web_state);
ErrorPageControllerBridge::CreateForWebState(web_state);
if (base::FeatureList::IsEnabled(web::features::kUseJSForErrorPage)) {
InvalidUrlTabHelper::CreateForWebState(web_state);
......
......@@ -9,6 +9,8 @@ source_set("web") {
sources = [
"dom_altering_lock.h",
"dom_altering_lock.mm",
"error_page_controller_bridge.h",
"error_page_controller_bridge.mm",
"error_page_util.h",
"error_page_util.mm",
"font_size_tab_helper.h",
......
......@@ -29,6 +29,7 @@
#include "ios/chrome/browser/ssl/ios_ssl_error_handler.h"
#import "ios/chrome/browser/ui/elements/windowed_container_view.h"
#include "ios/chrome/browser/ui/ui_feature_flags.h"
#include "ios/chrome/browser/web/error_page_controller_bridge.h"
#import "ios/chrome/browser/web/error_page_util.h"
#include "ios/chrome/browser/web/features.h"
#import "ios/components/security_interstitials/ios_blocking_page_tab_helper.h"
......@@ -378,6 +379,13 @@ void ChromeWebClient::PrepareErrorPage(
} else {
std::move(error_html_callback)
.Run(GetErrorPage(url, error, is_post, is_off_the_record));
ErrorPageControllerBridge* error_page_controller =
ErrorPageControllerBridge::FromWebState(web_state);
if (error_page_controller) {
// ErrorPageControllerBridge may not be created for web_state not attached
// to a tab.
error_page_controller->StartHandlingJavascriptCommands();
}
}
}
......
......@@ -27,6 +27,7 @@
#import "ios/chrome/browser/safe_browsing/safe_browsing_unsafe_resource_container.h"
#import "ios/chrome/browser/ssl/captive_portal_detector_tab_helper.h"
#import "ios/chrome/browser/ssl/captive_portal_detector_tab_helper_delegate.h"
#include "ios/chrome/browser/web/error_page_controller_bridge.h"
#import "ios/chrome/browser/web/error_page_util.h"
#include "ios/chrome/browser/web/features.h"
#import "ios/components/security_interstitials/ios_blocking_page_tab_helper.h"
......@@ -187,6 +188,7 @@ TEST_F(ChromeWebClientTest, PrepareErrorPageNonPostNonOtr) {
page = error_html;
});
web::FakeWebState web_state;
ErrorPageControllerBridge::CreateForWebState(&web_state);
web_client.PrepareErrorPage(&web_state, GURL(kTestUrl), error,
/*is_post=*/false,
/*is_off_the_record=*/false,
......@@ -213,6 +215,7 @@ TEST_F(ChromeWebClientTest, PrepareErrorPagePostNonOtr) {
page = error_html;
});
web::FakeWebState web_state;
ErrorPageControllerBridge::CreateForWebState(&web_state);
web_client.PrepareErrorPage(&web_state, GURL(kTestUrl), error,
/*is_post=*/true,
/*is_off_the_record=*/false,
......@@ -239,6 +242,7 @@ TEST_F(ChromeWebClientTest, PrepareErrorPageNonPostOtr) {
page = error_html;
});
web::FakeWebState web_state;
ErrorPageControllerBridge::CreateForWebState(&web_state);
web_client.PrepareErrorPage(&web_state, GURL(kTestUrl), error,
/*is_post=*/false,
/*is_off_the_record=*/true,
......@@ -265,6 +269,7 @@ TEST_F(ChromeWebClientTest, PrepareErrorPagePostOtr) {
page = error_html;
});
web::FakeWebState web_state;
ErrorPageControllerBridge::CreateForWebState(&web_state);
web_client.PrepareErrorPage(&web_state, GURL(kTestUrl), error,
/*is_post=*/true,
/*is_off_the_record=*/true,
......
// Copyright 2020 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 IOS_CHROME_BROWSER_WEB_ERROR_PAGE_CONTROLLER_BRIDGE_H_
#define IOS_CHROME_BROWSER_WEB_ERROR_PAGE_CONTROLLER_BRIDGE_H_
#include "ios/web/public/web_state_observer.h"
#import "ios/web/public/web_state_user_data.h"
namespace web {
class WebState;
}
// A class to bridge the JS errorPageController object in the error page.
// The class receives the JS messages and handle/dispatch them when needed.
// Messages are sent in
// components/neterror/resources/error_page_controller_ios.js.
class ErrorPageControllerBridge
: public web::WebStateObserver,
public web::WebStateUserData<ErrorPageControllerBridge> {
public:
~ErrorPageControllerBridge() override;
// Start observing "errorPageController" commands until next navigation.
void StartHandlingJavascriptCommands();
// WebStateObserver overrides
void DidStartNavigation(web::WebState* web_state,
web::NavigationContext* navigation_context) override;
void WebStateDestroyed(web::WebState* web_state) override;
private:
friend class WebStateUserData<ErrorPageControllerBridge>;
ErrorPageControllerBridge(web::WebState* web_state);
// Handler for "errorPageController.*" JavaScript command.
void OnErrorPageCommand(const base::DictionaryValue& message,
const GURL& url,
bool user_is_interacting,
web::WebFrame* sender_frame);
// The WebState this instance is observing. Will be null after
// WebStateDestroyed has been called.
web::WebState* web_state_ = nullptr;
// Subscription for JS message.
base::CallbackListSubscription subscription_;
WEB_STATE_USER_DATA_KEY_DECL();
};
#endif // IOS_CHROME_BROWSER_WEB_ERROR_PAGE_CONTROLLER_BRIDGE_H_
// Copyright 2020 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 "ios/chrome/browser/web/error_page_controller_bridge.h"
#import <Foundation/Foundation.h>
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
#include "ios/web/public/js_messaging/web_frame.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// Prefix for the errorPageController activity event commands.
// Must be kept in sync with
// components/neterror/resources/error_page_controller_ios.js.
const char kCommandPrefix[] = "errorPageController";
// The NSUserDefault key to store the easter egg game on error page high score.
NSString* const kEasterEggHighScore = @"EasterEggHighScore";
} // namespace
ErrorPageControllerBridge::ErrorPageControllerBridge(web::WebState* web_state)
: web_state_(web_state) {}
ErrorPageControllerBridge::~ErrorPageControllerBridge() {}
void ErrorPageControllerBridge::StartHandlingJavascriptCommands() {
web_state_->AddObserver(this);
subscription_ = web_state_->AddScriptCommandCallback(
base::BindRepeating(&ErrorPageControllerBridge::OnErrorPageCommand,
base::Unretained(this)),
kCommandPrefix);
}
void ErrorPageControllerBridge::OnErrorPageCommand(
const base::DictionaryValue& message,
const GURL& url,
bool user_is_interacting,
web::WebFrame* sender_frame) {
std::string command;
if (!message.GetString("command", &command)) {
return;
}
if (command == "errorPageController.updateEasterEggHighScore") {
std::string high_score_string;
if (!message.GetString("highScore", &high_score_string)) {
return;
}
int high_score;
if (!base::StringToInt(high_score_string, &high_score)) {
return;
}
[[NSUserDefaults standardUserDefaults] setInteger:high_score
forKey:kEasterEggHighScore];
}
if (command == "errorPageController.resetEasterEggHighScore") {
[[NSUserDefaults standardUserDefaults]
removeObjectForKey:kEasterEggHighScore];
}
if (command == "errorPageController.trackEasterEgg") {
int high_score = [[NSUserDefaults standardUserDefaults]
integerForKey:kEasterEggHighScore];
std::vector<base::Value> parameters;
parameters.push_back(base::Value(high_score));
sender_frame->CallJavaScriptFunction(
"errorPageController.initializeEasterEggHighScore", parameters);
}
}
#pragma mark WebStateObserver
void ErrorPageControllerBridge::DidStartNavigation(
web::WebState* web_state,
web::NavigationContext* navigation_context) {
subscription_ = base::CallbackListSubscription();
web_state_->RemoveObserver(this);
}
void ErrorPageControllerBridge::WebStateDestroyed(web::WebState* web_state) {
web_state_->RemoveObserver(this);
}
WEB_STATE_USER_DATA_KEY_IMPL(ErrorPageControllerBridge)
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