Commit 13b8fad9 authored by sdefresne's avatar sdefresne Committed by Commit bot

Upstream Chrome on iOS source code [5/11].

Upstream part of Chrome on iOS source code. Nothing is built yet,
just new files added. The files will be added to the build as part
of the last CL to avoid breaking downstream tree.

BUG=653086

Review-Url: https://codereview.chromium.org/2590473002
Cr-Commit-Position: refs/heads/master@{#439462}
parent e65fd878
// Copyright 2016 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/ui/fancy_ui/tinted_button.h"
#import "base/mac/scoped_nsobject.h"
@interface TintedButton () {
base::scoped_nsobject<UIColor> normalStateTint_;
base::scoped_nsobject<UIColor> highlightedTint_;
}
// Makes the button's tint color reflect its current state.
- (void)updateTint;
@end
@implementation TintedButton
- (void)setTintColor:(UIColor*)color forState:(UIControlState)state {
switch (state) {
case UIControlStateNormal:
normalStateTint_.reset([color copy]);
break;
case UIControlStateHighlighted:
highlightedTint_.reset([color copy]);
break;
default:
return;
}
if (normalStateTint_ || highlightedTint_)
self.adjustsImageWhenHighlighted = NO;
else
self.adjustsImageWhenHighlighted = YES;
[self updateTint];
}
#pragma mark - UIControl
- (void)setHighlighted:(BOOL)highlighted {
[super setHighlighted:highlighted];
[self updateTint];
}
#pragma mark - Private
- (void)updateTint {
UIColor* newTint = nil;
switch (self.state) {
case UIControlStateNormal:
newTint = normalStateTint_.get();
break;
case UIControlStateHighlighted:
newTint = highlightedTint_.get();
break;
default:
newTint = normalStateTint_.get();
break;
}
self.tintColor = newTint;
}
@end
// Copyright 2012 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/ui/file_locations.h"
#include "base/mac/foundation_util.h"
#include "base/strings/sys_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
extern std::string GetLocalizedFileName(const std::string& base_name,
const std::string& locale,
const std::string& ext);
extern std::string GetIOSLocaleMapping(const std::string& locale);
namespace {
class FileLocationsTest : public PlatformTest {
protected:
void SetUp() override {
// These files must exist for this unit test to pass.
termsBaseName_ = "terms";
extension_ = "html";
enFile_ = "terms_en.html";
frFile_ = "terms_fr.html";
}
std::string termsBaseName_;
std::string extension_;
std::string enFile_;
std::string frFile_;
};
TEST_F(FileLocationsTest, TestTermsOfServiceUrl) {
std::string filename(GetTermsOfServicePath());
EXPECT_FALSE(filename.empty());
}
TEST_F(FileLocationsTest, TestIOSLocaleMapping) {
EXPECT_EQ("en-US", GetIOSLocaleMapping("en-US"));
EXPECT_EQ("es", GetIOSLocaleMapping("es"));
EXPECT_EQ("es-419", GetIOSLocaleMapping("es-MX"));
EXPECT_EQ("pt-BR", GetIOSLocaleMapping("pt"));
EXPECT_EQ("pt-PT", GetIOSLocaleMapping("pt-PT"));
EXPECT_EQ("zh-CN", GetIOSLocaleMapping("zh-Hans"));
EXPECT_EQ("zh-TW", GetIOSLocaleMapping("zh-Hant"));
}
TEST_F(FileLocationsTest, TestFileNameLocaleWithExtension) {
EXPECT_EQ(enFile_, GetLocalizedFileName(termsBaseName_, "en", extension_));
EXPECT_EQ(frFile_, GetLocalizedFileName(termsBaseName_, "fr", extension_));
EXPECT_EQ(frFile_, GetLocalizedFileName(termsBaseName_, "fr-XX", extension_));
// No ToS for "xx" locale so expect default "en" ToS. Unlikely, but this
// test will fail once the ToS for "xx" locale is added.
EXPECT_EQ(enFile_, GetLocalizedFileName(termsBaseName_, "xx", extension_));
}
// Tests that locale/languages available on iOS are mapped to either a
// translated Chrome Terms of Service or to English.
TEST_F(FileLocationsTest, TestTermsOfServiceForSupportedLanguages) {
// List of available localized terms_*.html files. Note that this list is
// hardcoded and needs to be manually maintained as new locales are added
// to Chrome. See http://crbug/522638
NSSet* localizedTermsHtml =
[NSSet setWithObjects:@"ar", @"bg", @"ca", @"cs", @"da", @"de", @"el",
@"en-GB", @"en", @"es-419", @"es", @"fa", @"fi",
@"fr", @"he", @"hi", @"hr", @"hu", @"id", @"it",
@"ja", @"ko", @"lt", @"nb", @"nl", @"pl", @"pt-BR",
@"pt-PT", @"ro", @"ru", @"sk", @"sr", @"sv", @"th",
@"tr", @"uk", @"vi", @"zh-CN", @"zh-TW", nil];
for (NSString* locale in [NSLocale availableLocaleIdentifiers]) {
NSString* normalizedLocale =
[locale stringByReplacingOccurrencesOfString:@"_" withString:@"-"];
NSArray* parts = [normalizedLocale componentsSeparatedByString:@"-"];
NSString* language = [parts objectAtIndex:0];
std::string filename = GetLocalizedFileName(
termsBaseName_,
GetIOSLocaleMapping(base::SysNSStringToUTF8(normalizedLocale)),
extension_);
if (filename == enFile_ && ![language isEqualToString:@"en"]) {
NSLog(@"OK: Locale %@ using language %@ falls back to use English ToS",
locale, language);
EXPECT_FALSE([localizedTermsHtml containsObject:language]);
}
}
}
} // namespace
// Copyright 2012 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_UI_FIND_BAR_FIND_BAR_CONTROLLER_IOS_H_
#define IOS_CHROME_BROWSER_UI_FIND_BAR_FIND_BAR_CONTROLLER_IOS_H_
#import <UIKit/UIKit.h>
@class FindInPageModel;
// The a11y ID of the find-in-page bar.
extern NSString* const kFindInPageContainerViewId;
@interface FindBarControllerIOS : NSObject
// The main view, for both iPhone or iPad.
@property(nonatomic, readonly) IBOutlet UIView* view;
// Init with incognito style.
- (instancetype)initWithIncognito:(BOOL)isIncognito;
// Current input search term.
- (NSString*)searchTerm;
// Update view based on model. If |focusTextfield| is YES, focus the
// textfield. Updates the results count and, if |initialUpdate| is true, fills
// the text field with search term from the model.
- (void)updateView:(FindInPageModel*)model
initialUpdate:(BOOL)initialUpdate
focusTextfield:(BOOL)focusTextfield;
// Updates the results count in Find Bar.
- (void)updateResultsCount:(FindInPageModel*)model;
// Display find bar view. On iPad, it makes best effort to horizontally align
// find bar with alignment frame, unless alignment frame is too wide or too
// narrow. When too wide, the find bar is shorter and right-aligned. When
// |alignmentFrame| is too narrow, the find bar will horizontally fill |view|.
// If |selectText| flag is YES, the text in the text input field will be
// selected.
- (void)addFindBarView:(BOOL)animate
intoView:(UIView*)view
withFrame:(CGRect)frame
alignWithFrame:(CGRect)alignmentFrame
selectText:(BOOL)selectText;
// Hide find bar view.
- (void)hideFindBarView:(BOOL)animate;
// Hide the keyboard when the find next/previous buttons are pressed.
- (IBAction)hideKeyboard:(id)sender;
// Indicates that Find in Page is shown. When true, |view| is guaranteed not to
// be nil.
- (BOOL)isFindInPageShown;
// Indicates that the Find in Page text field is first responder.
- (BOOL)isFocused;
@end
#endif // IOS_CHROME_BROWSER_UI_FIND_BAR_FIND_BAR_CONTROLLER_IOS_H_
This diff is collapsed.
// Copyright 2016 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_UI_FIND_BAR_FIND_BAR_TEXT_FIELD_H_
#define IOS_CHROME_BROWSER_UI_FIND_BAR_FIND_BAR_TEXT_FIELD_H_
#import <UIKit/UIKit.h>
// FindBarTextField is a textfield that provides a space within its editing rect
// to show an overlay. This space is in the trailing side of the editing rect.
// It is used in Find Bar to show "X of Y" results count overlay next to the
// search term.
@interface FindBarTextField : UITextField
@property(nonatomic, readwrite) CGFloat overlayWidth;
@end
#endif // IOS_CHROME_BROWSER_UI_FIND_BAR_FIND_BAR_TEXT_FIELD_H_
// Copyright 2016 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.
#import "ios/chrome/browser/ui/find_bar/find_bar_text_field.h"
#include "base/i18n/rtl.h"
#import "ios/chrome/browser/find_in_page/find_in_page_controller.h"
#include "ios/chrome/grit/ios_strings.h"
#include "ui/base/l10n/l10n_util_mac.h"
namespace {
// Find bar left padding
const CGFloat kFindBarLeftPadding = 16;
} // anonymous namespace
@implementation FindBarTextField
@synthesize overlayWidth = _overlayWidth;
#pragma mark - UIView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.textAlignment = NSTextAlignmentNatural;
self.accessibilityLabel =
l10n_util::GetNSStringWithFixup(IDS_IOS_PLACEHOLDER_FIND_IN_PAGE);
}
return self;
}
#pragma mark - Public methods
- (void)setOverlayWidth:(CGFloat)overlayWidth {
_overlayWidth = overlayWidth;
[self setNeedsLayout];
}
#pragma mark - UITextField
- (CGRect)textRectForBounds:(CGRect)bounds {
return [self editingRectForBounds:bounds];
}
- (CGRect)editingRectForBounds:(CGRect)bounds {
// Reduce the width by the width of the overlay + padding for both sides of
// the text.
bounds.size.width -= _overlayWidth + 2 * kFindBarLeftPadding;
bounds.origin.x += kFindBarLeftPadding;
// Shift the text to the right side of the overlay for RTL languages.
if (base::i18n::IsRTL())
bounds.origin.x += _overlayWidth;
return bounds;
}
@end
// Copyright 2016 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_UI_FIND_BAR_FIND_BAR_TOUCH_FORWARDING_VIEW_H_
#define IOS_CHROME_BROWSER_UI_FIND_BAR_FIND_BAR_TOUCH_FORWARDING_VIEW_H_
#import <UIKit/UIKit.h>
// View that forwards all touch events inside itself to a given |targetView|.
@interface FindBarTouchForwardingView : UIView
// View to forward touch events to.
@property(nonatomic, assign) UIView* targetView;
@end
#endif // IOS_CHROME_BROWSER_UI_FIND_BAR_FIND_BAR_TOUCH_FORWARDING_VIEW_H_
// Copyright 2016 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.
#import "ios/chrome/browser/ui/find_bar/find_bar_touch_forwarding_view.h"
@implementation FindBarTouchForwardingView
@synthesize targetView = _targetView;
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event {
if (self.targetView && [self pointInside:point withEvent:event]) {
return self.targetView;
}
return [super hitTest:point withEvent:event];
}
@end
// Copyright 2016 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_UI_FIND_BAR_FIND_BAR_VIEW_H_
#define IOS_CHROME_BROWSER_UI_FIND_BAR_FIND_BAR_VIEW_H_
#import <UIKit/UIKit.h>
// The a11y ID of the text input field in the find-in-page bar.
extern NSString* const kFindInPageInputFieldId;
// The a11y ID of the "next" button in the find-in-page bar.
extern NSString* const kFindInPageNextButtonId;
// The a11y ID of the "previous" button in the find-in-page bar.
extern NSString* const kFindInPagePreviousButtonId;
// The a11y ID of the "close" button in the find-in-page bar.
extern NSString* const kFindInPageCloseButtonId;
// Find bar view.
// It shows a textfield that hosts the search term, a label with results count
// in format of "1 of 13", and next/previous/close buttons.
@interface FindBarView : UIView
// Designated initializer.
// |darkAppearance| makes the background to dark color and changes font colors
// to lighter colors.
- (instancetype)initWithDarkAppearance:(BOOL)darkAppearance
NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
- (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
// Updates |resultsLabel| with |text|. Updates |inputField| layout so that input
// text does not overlap with results count. |text| can be nil.
- (void)updateResultsLabelWithText:(NSString*)text;
// The textfield with search term.
@property(nonatomic, assign) UITextField* inputField;
// Button to go to previous search result.
@property(nonatomic, assign) UIButton* previousButton;
// Button to go to next search result.
@property(nonatomic, assign) UIButton* nextButton;
// Button to dismiss Find in Page.
@property(nonatomic, assign) UIButton* closeButton;
@end
#endif // IOS_CHROME_BROWSER_UI_FIND_BAR_FIND_BAR_VIEW_H_
This diff is collapsed.
// Copyright 2016 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.
#import <XCTest/XCTest.h>
#include "base/strings/string_number_conversions.h"
#include "components/strings/grit/components_strings.h"
#import "ios/chrome/browser/find_in_page/find_in_page_controller.h"
#import "ios/chrome/browser/ui/find_bar/find_bar_controller_ios.h"
#import "ios/chrome/browser/ui/find_bar/find_bar_view.h"
#import "ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.h"
#import "ios/chrome/test/app/tab_test_util.h"
#import "ios/chrome/test/earl_grey/accessibility_util.h"
#import "ios/chrome/test/earl_grey/chrome_assertions.h"
#import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
#import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
#import "ios/chrome/test/earl_grey/chrome_matchers.h"
#import "ios/chrome/test/earl_grey/chrome_test_case.h"
#import "ios/testing/wait_util.h"
#import "ios/web/public/test/http_server.h"
#import "ios/web/public/test/http_server_util.h"
#include "ui/base/l10n/l10n_util_mac.h"
namespace {
// Test web page content.
const std::string kFindInPageResponse = "Find in page. Find in page.";
} // namespace
using chrome_test_util::buttonWithAccessibilityLabel;
using chrome_test_util::webViewContainingText;
// Tests for Find in Page.
@interface FindInPageTestCase : ChromeTestCase
// URL for a test page with |kFindInPageResponse|.
@property(nonatomic, assign) GURL testURL;
// Opens Find in Page.
- (void)openFindInPage;
// Closes Find in page.
- (void)closeFindInPage;
// Types text into Find in page textfield.
- (void)typeFindInPageText:(NSString*)text;
// Matcher for find in page textfield.
- (id<GREYMatcher>)findInPageInputField;
// Asserts that there is a string "|resultIndex| of |resultCount|" present on
// screen. Waits for up to 2 seconds for this to happen.
- (void)assertResultStringIsResult:(int)resultIndex outOfTotal:(int)resultCount;
// Taps Next button in Find in page.
- (void)advanceToNextResult;
// Taps Previous button in Find in page.
- (void)advanceToPreviousResult;
// Navigates to |self.testURL| and waits for the page to load.
- (void)navigateToTestPage;
@end
@implementation FindInPageTestCase
@synthesize testURL = _testURL;
#pragma mark - XCTest.
// After setup, a page with |kFindInPageResponse| is displayed and Find In Page
// bar is opened.
- (void)setUp {
[super setUp];
// Clear saved search term
[FindInPageController setSearchTerm:nil];
// Setup find in page test URL.
std::map<GURL, std::string> responses;
self.testURL = web::test::HttpServer::MakeUrl("http://findinpage");
responses[self.testURL] = kFindInPageResponse;
web::test::SetUpSimpleHttpServer(responses);
[self navigateToTestPage];
// Open Find in Page view.
[self openFindInPage];
}
- (void)tearDown {
// Close find in page view.
[self closeFindInPage];
[super tearDown];
}
#pragma mark - Tests.
// Tests that find in page allows iteration between search results and displays
// correct number of results.
- (void)testFindInPage {
// Type "find".
[self typeFindInPageText:@"find"];
// Should be highlighting result 1 of 2.
[self assertResultStringIsResult:1 outOfTotal:2];
// Tap Next.
[self advanceToNextResult];
// Should now read "2 of 2".
[self assertResultStringIsResult:2 outOfTotal:2];
// Go to previous.
[self advanceToPreviousResult];
[self assertResultStringIsResult:1 outOfTotal:2];
}
// Tests that Find In Page search term retention is working as expected, e.g.
// the search term is persisted between FIP runs, but in incognito search term
// is not retained and not autofilled.
- (void)testFindInPageRetainsSearchTerm {
// Type "find".
[self typeFindInPageText:@"find"];
[self assertResultStringIsResult:1 outOfTotal:2];
[self closeFindInPage];
// Verify it's closed.
ConditionBlock condition = ^{
NSError* error = nil;
[[EarlGrey selectElementWithMatcher:grey_accessibilityID(
kFindInPageContainerViewId)]
assertWithMatcher:grey_nil()
error:&error];
return (error == nil);
};
GREYAssert(testing::WaitUntilConditionOrTimeout(2.0, condition),
@"Timeout while waiting for Find Bar to close");
// Open incognito page.
[ChromeEarlGreyUI openNewIncognitoTab];
[self navigateToTestPage];
[self openFindInPage];
// Check that no search term is prefilled.
[[EarlGrey selectElementWithMatcher:[self findInPageInputField]]
assertWithMatcher:grey_text(@"")];
[self typeFindInPageText:@"in"];
[self assertResultStringIsResult:1 outOfTotal:4];
[self closeFindInPage];
// Navigate to a new non-incognito tab.
[ChromeEarlGreyUI openNewTab];
[self navigateToTestPage];
[self openFindInPage];
// Check that search term is retained from normal tab, not incognito tab.
[[EarlGrey selectElementWithMatcher:[self findInPageInputField]]
assertWithMatcher:grey_text(@"find")];
[self assertResultStringIsResult:1 outOfTotal:2];
}
// Tests accessibility of the Find in Page screen.
- (void)testAccessibilityOnFindInPage {
[self typeFindInPageText:@"find"];
// Wait for UI to finish loading screen, before programatically verifying
// accessibility.
[[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
chrome_test_util::VerifyAccessibilityForCurrentScreen();
}
#pragma mark - Steps.
- (void)openFindInPage {
[ChromeEarlGreyUI openToolsMenu];
[[EarlGrey
selectElementWithMatcher:grey_accessibilityID(kToolsMenuFindInPageId)]
performAction:grey_tap()];
}
- (void)closeFindInPage {
[[EarlGrey
selectElementWithMatcher:grey_accessibilityID(kFindInPageCloseButtonId)]
performAction:grey_tap()];
}
- (void)typeFindInPageText:(NSString*)text {
[[EarlGrey selectElementWithMatcher:[self findInPageInputField]]
performAction:grey_typeText(text)];
}
- (id<GREYMatcher>)findInPageInputField {
return grey_accessibilityID(kFindInPageInputFieldId);
}
- (void)assertResultStringIsResult:(int)resultIndex
outOfTotal:(int)resultCount {
// Returns "<current> of <total>" search results label (e.g "1 of 5").
NSString* expectedResultsString = l10n_util::GetNSStringF(
IDS_FIND_IN_PAGE_COUNT, base::IntToString16(resultIndex),
base::IntToString16(resultCount));
ConditionBlock condition = ^{
NSError* error = nil;
[[EarlGrey
selectElementWithMatcher:grey_accessibilityLabel(expectedResultsString)]
assertWithMatcher:grey_notNil()
error:&error];
return (error == nil);
};
GREYAssert(
testing::WaitUntilConditionOrTimeout(2.0, condition),
@"Timeout waiting for correct Find in Page results string to appear");
}
- (void)advanceToNextResult {
[[EarlGrey
selectElementWithMatcher:grey_accessibilityID(kFindInPageNextButtonId)]
performAction:grey_tap()];
}
- (void)advanceToPreviousResult {
[[EarlGrey selectElementWithMatcher:grey_accessibilityID(
kFindInPagePreviousButtonId)]
performAction:grey_tap()];
}
- (void)navigateToTestPage {
// Navigate to a page with some text.
[ChromeEarlGrey loadURL:self.testURL];
// Verify web page finished loading.
[[EarlGrey
selectElementWithMatcher:webViewContainingText(kFindInPageResponse)]
assertWithMatcher:grey_notNil()];
}
@end
// 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 IOS_CHROME_BROWSER_UI_FIRST_RUN_FIRST_RUN_CHROME_SIGNIN_VIEW_CONTROLLER_H_
#define IOS_CHROME_BROWSER_UI_FIRST_RUN_FIRST_RUN_CHROME_SIGNIN_VIEW_CONTROLLER_H_
#import "ios/chrome/browser/ui/authentication/chrome_signin_view_controller.h"
extern NSString* const kSignInButtonAccessibilityIdentifier;
extern NSString* const kSignInSkipButtonAccessibilityIdentifier;
@class FirstRunConfiguration;
@class TabModel;
namespace ios {
class ChromeBrowserState;
}
// A ChromeSigninViewController that is used during the run.
@interface FirstRunChromeSigninViewController : ChromeSigninViewController
// Designated initialzer.
- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
tabModel:(TabModel*)tabModel
firstRunConfig:(FirstRunConfiguration*)firstRunConfig
signInIdentity:(ChromeIdentity*)identity;
@end
#endif // IOS_CHROME_BROWSER_UI_FIRST_RUN_FIRST_RUN_CHROME_SIGNIN_VIEW_CONTROLLER_H_
// 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.
#import "ios/chrome/browser/ui/first_run/first_run_chrome_signin_view_controller.h"
#import "base/mac/scoped_nsobject.h"
#include "base/metrics/user_metrics.h"
#include "components/signin/core/browser/signin_metrics.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#import "ios/chrome/browser/first_run/first_run_configuration.h"
#import "ios/chrome/browser/tabs/tab_model.h"
#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
#import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
#import "ios/chrome/browser/ui/first_run/first_run_util.h"
#import "ios/chrome/browser/ui/promos/signin_promo_view_controller.h"
#include "ios/chrome/browser/ui/ui_util.h"
#include "ios/chrome/grit/ios_strings.h"
#import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
#import "ios/public/provider/chrome/browser/signin/chrome_identity.h"
#import "ios/public/provider/chrome/browser/signin/chrome_identity_service.h"
#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
#import "ui/base/l10n/l10n_util.h"
NSString* const kSignInButtonAccessibilityIdentifier =
@"SignInButtonAccessibilityIdentifier";
NSString* const kSignInSkipButtonAccessibilityIdentifier =
@"SkipButtonAccessibilityIdentifier";
@interface FirstRunChromeSigninViewController ()<
ChromeSigninViewControllerDelegate> {
TabModel* _tabModel; // weak
base::scoped_nsobject<FirstRunConfiguration> _firstRunConfig;
ChromeIdentity* _identity;
BOOL _hasRecordedSigninStarted;
}
@end
@implementation FirstRunChromeSigninViewController
- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
tabModel:(TabModel*)tabModel
firstRunConfig:(FirstRunConfiguration*)firstRunConfig
signInIdentity:(ChromeIdentity*)identity {
self = [super
initWithBrowserState:browserState
isPresentedOnSettings:NO
signInAccessPoint:signin_metrics::AccessPoint::ACCESS_POINT_START_PAGE
signInIdentity:identity];
if (self) {
_tabModel = tabModel;
_firstRunConfig.reset([firstRunConfig retain]);
_identity = identity;
self.delegate = self;
}
return self;
}
- (void)dealloc {
self.delegate = nil;
_tabModel = nil;
[super dealloc];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self.navigationController setNavigationBarHidden:YES];
self.primaryButton.accessibilityIdentifier =
kSignInButtonAccessibilityIdentifier;
self.secondaryButton.accessibilityIdentifier =
kSignInSkipButtonAccessibilityIdentifier;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (!_hasRecordedSigninStarted) {
_hasRecordedSigninStarted = YES;
base::RecordAction(base::UserMetricsAction("Signin_Signin_FromStartPage"));
signin_metrics::LogSigninAccessPointStarted(
signin_metrics::AccessPoint::ACCESS_POINT_START_PAGE);
}
// Save the version number to prevent showing the SSO Recall promo on the next
// cold start.
[SigninPromoViewController recordVersionSeen];
}
- (BOOL)shouldAutorotate {
return IsIPadIdiom() ? [super shouldAutorotate] : NO;
}
- (void)finishFirstRunAndDismiss {
DCHECK(self.presentingViewController);
ios_internal::FinishFirstRun(self.browserState, [_tabModel currentTab],
_firstRunConfig);
[self.presentingViewController
dismissViewControllerAnimated:YES
completion:^{
ios_internal::FirstRunDismissed();
}];
}
#pragma mark ChromeSigninViewControllerDelegate
- (void)willStartSignIn:(ChromeSigninViewController*)controller {
DCHECK_EQ(self, controller);
controller.shouldClearData = SHOULD_CLEAR_DATA_CLEAR_DATA;
[_firstRunConfig setSignInAttempted:YES];
}
- (void)willStartAddAccount:(ChromeSigninViewController*)controller {
DCHECK_EQ(self, controller);
[_firstRunConfig setSignInAttempted:YES];
}
- (void)didSkipSignIn:(ChromeSigninViewController*)controller {
DCHECK_EQ(self, controller);
// User is done with First Run after explicit skip.
[self finishFirstRunAndDismiss];
}
- (void)didFailSignIn:(ChromeSigninViewController*)controller {
DCHECK_EQ(self, controller);
}
- (void)didSignIn:(ChromeSigninViewController*)controller {
DCHECK_EQ(self, controller);
// User is considered done with First Run only after successful sign-in.
ios_internal::WriteFirstRunSentinelAndRecordMetrics(
self.browserState, YES, [_firstRunConfig hasSSOAccount]);
}
- (void)didUndoSignIn:(ChromeSigninViewController*)controller
identity:(ChromeIdentity*)identity {
DCHECK_EQ(self, controller);
if ([_identity isEqual:identity]) {
_identity = nil;
// This is best effort. If the operation fails, the account will be left on
// the device. The user will not be warned either as this call is
// asynchronous (but undo is not), the application might be in an unknown
// state when the forget identity operation finishes.
ios::GetChromeBrowserProvider()->GetChromeIdentityService()->ForgetIdentity(
identity, nil);
[self.navigationController popViewControllerAnimated:YES];
}
}
- (void)didAcceptSignIn:(ChromeSigninViewController*)controller
executeCommand:(GenericChromeCommand*)command {
DCHECK_EQ(self, controller);
// User is done with First Run after explicit sign-in accept.
[self finishFirstRunAndDismiss];
[command executeOnMainWindow];
}
#pragma mark ChromeSigninViewController
- (NSString*)skipSigninButtonTitle {
return l10n_util::GetNSString(
IDS_IOS_FIRSTRUN_ACCOUNT_CONSISTENCY_SKIP_BUTTON);
}
@end
// Copyright 2016 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.
#import <EarlGrey/EarlGrey.h>
#import <XCTest/XCTest.h>
#include "base/mac/scoped_nsobject.h"
#include "base/strings/sys_string_conversions.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/metrics/metrics_reporting_default_state.h"
#include "components/prefs/pref_member.h"
#include "components/prefs/pref_service.h"
#include "components/signin/core/browser/signin_manager.h"
#import "ios/chrome/app/main_controller.h"
#include "ios/chrome/browser/application_context.h"
#import "ios/chrome/browser/geolocation/omnibox_geolocation_controller+Testing.h"
#import "ios/chrome/browser/geolocation/omnibox_geolocation_controller.h"
#import "ios/chrome/browser/geolocation/test_location_manager.h"
#include "ios/chrome/browser/signin/signin_manager_factory.h"
#include "ios/chrome/browser/sync/sync_setup_service.h"
#include "ios/chrome/browser/sync/sync_setup_service_factory.h"
#import "ios/chrome/browser/ui/first_run/first_run_chrome_signin_view_controller.h"
#include "ios/chrome/browser/ui/first_run/welcome_to_chrome_view_controller.h"
#include "ios/chrome/grit/ios_strings.h"
#import "ios/chrome/test/app/chrome_test_util.h"
#import "ios/chrome/test/earl_grey/chrome_matchers.h"
#import "ios/chrome/test/earl_grey/chrome_test_case.h"
#import "ios/public/provider/chrome/browser/signin/fake_chrome_identity.h"
#import "ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.h"
#include "ui/base/l10n/l10n_util.h"
namespace {
// Returns a fake identity.
ChromeIdentity* GetFakeIdentity() {
return [FakeChromeIdentity identityWithEmail:@"foo@gmail.com"
gaiaID:@"fooID"
name:@"Fake Foo"];
}
// Taps the button with accessibility labelId |message_id|.
void TapButtonWithLabelId(int message_id) {
id<GREYMatcher> matcher = chrome_test_util::buttonWithAccessibilityLabel(
l10n_util::GetNSString(message_id));
[[EarlGrey selectElementWithMatcher:matcher] performAction:grey_tap()];
}
// Asserts that |identity| is actually signed in to the active profile.
void AssertAuthenticatedIdentityInActiveProfile(ChromeIdentity* identity) {
[[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
ios::ChromeBrowserState* browser_state =
chrome_test_util::GetOriginalBrowserState();
AccountInfo info =
ios::SigninManagerFactory::GetForBrowserState(browser_state)
->GetAuthenticatedAccountInfo();
GREYAssertEqual(base::SysNSStringToUTF8(identity.gaiaID), info.gaia,
@"Unexpected Gaia ID of the signed in user [expected = "
@"\"%@\", actual = \"%s\"]",
identity.gaiaID, info.gaia.c_str());
}
}
@interface MainController (ExposedForTesting)
- (void)showFirstRunUI;
@end
// Tests first run settings and navigation.
@interface FirstRunTestCase : ChromeTestCase
@end
@implementation FirstRunTestCase
- (void)setUp {
[super setUp];
BooleanPrefMember metricsEnabledPref;
metricsEnabledPref.Init(metrics::prefs::kMetricsReportingEnabled,
GetApplicationContext()->GetLocalState());
metricsEnabledPref.SetValue(NO);
IntegerPrefMember defaultOptInPref;
defaultOptInPref.Init(metrics::prefs::kMetricsDefaultOptIn,
GetApplicationContext()->GetLocalState());
defaultOptInPref.SetValue(metrics::EnableMetricsDefault::DEFAULT_UNKNOWN);
base::scoped_nsobject<TestLocationManager> locationManager(
[[TestLocationManager alloc] init]);
[locationManager setLocationServicesEnabled:NO];
[[OmniboxGeolocationController sharedInstance]
setLocationManager:locationManager];
}
+ (void)tearDown {
IntegerPrefMember defaultOptInPref;
defaultOptInPref.Init(metrics::prefs::kMetricsDefaultOptIn,
GetApplicationContext()->GetLocalState());
defaultOptInPref.SetValue(metrics::EnableMetricsDefault::DEFAULT_UNKNOWN);
[[OmniboxGeolocationController sharedInstance] setLocationManager:nil];
[super tearDown];
}
// Navigates to the terms of service and back.
- (void)testTermsAndConditions {
[chrome_test_util::GetMainController() showFirstRunUI];
id<GREYMatcher> termsOfServiceLink =
grey_accessibilityLabel(@"Terms of Service");
[[EarlGrey selectElementWithMatcher:termsOfServiceLink]
performAction:grey_tap()];
[[EarlGrey selectElementWithMatcher:grey_text(@"Chromium Terms of Service")]
assertWithMatcher:grey_sufficientlyVisible()];
[[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"back_bar_button")]
performAction:grey_tap()];
// Ensure we went back to the First Run screen.
[[EarlGrey selectElementWithMatcher:termsOfServiceLink]
assertWithMatcher:grey_sufficientlyVisible()];
}
// Toggle the UMA checkbox.
- (void)testToggleMetricsOn {
[chrome_test_util::GetMainController() showFirstRunUI];
id<GREYMatcher> metrics =
grey_accessibilityID(kUMAMetricsButtonAccessibilityIdentifier);
[[EarlGrey selectElementWithMatcher:metrics] performAction:grey_tap()];
id<GREYMatcher> optInAccept = chrome_test_util::buttonWithAccessibilityLabel(
l10n_util::GetNSString(IDS_IOS_FIRSTRUN_OPT_IN_ACCEPT_BUTTON));
[[EarlGrey selectElementWithMatcher:optInAccept] performAction:grey_tap()];
BOOL metricsOptIn = GetApplicationContext()->GetLocalState()->GetBoolean(
metrics::prefs::kMetricsReportingEnabled);
GREYAssert(
metricsOptIn != [WelcomeToChromeViewController defaultStatsCheckboxValue],
@"Metrics reporting pref is incorrect.");
}
// Dismisses the first run screens.
- (void)testDismissFirstRun {
[chrome_test_util::GetMainController() showFirstRunUI];
id<GREYMatcher> optInAccept = chrome_test_util::buttonWithAccessibilityLabel(
l10n_util::GetNSString(IDS_IOS_FIRSTRUN_OPT_IN_ACCEPT_BUTTON));
[[EarlGrey selectElementWithMatcher:optInAccept] performAction:grey_tap()];
PrefService* preferences = GetApplicationContext()->GetLocalState();
GREYAssert(
preferences->GetBoolean(metrics::prefs::kMetricsReportingEnabled) ==
[WelcomeToChromeViewController defaultStatsCheckboxValue],
@"Metrics reporting does not match.");
id<GREYMatcher> skipSignIn =
grey_accessibilityID(kSignInSkipButtonAccessibilityIdentifier);
[[EarlGrey selectElementWithMatcher:skipSignIn] performAction:grey_tap()];
id<GREYMatcher> newTab =
grey_kindOfClass(NSClassFromString(@"NewTabPageView"));
[[EarlGrey selectElementWithMatcher:newTab]
assertWithMatcher:grey_sufficientlyVisible()];
}
// Signs in to an account and then taps the Undo button to sign out.
- (void)testSignInAndUndo {
ChromeIdentity* identity = GetFakeIdentity();
ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()->AddIdentity(
identity);
// Launch First Run and accept tems of services.
[chrome_test_util::GetMainController() showFirstRunUI];
TapButtonWithLabelId(IDS_IOS_FIRSTRUN_OPT_IN_ACCEPT_BUTTON);
// Sign In |identity|.
TapButtonWithLabelId(IDS_IOS_ACCOUNT_CONSISTENCY_SETUP_SIGNIN_BUTTON);
AssertAuthenticatedIdentityInActiveProfile(identity);
// Undo the sign-in and dismiss the Sign In screen.
TapButtonWithLabelId(IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_UNDO_BUTTON);
TapButtonWithLabelId(IDS_IOS_FIRSTRUN_ACCOUNT_CONSISTENCY_SKIP_BUTTON);
// |identity| shouldn't be signed in.
AssertAuthenticatedIdentityInActiveProfile(nil);
}
// Signs in to an account and then taps the Advanced link to go to settings.
- (void)testSignInAndTapSettingsLink {
ChromeIdentity* identity = GetFakeIdentity();
ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()->AddIdentity(
identity);
// Launch First Run and accept tems of services.
[chrome_test_util::GetMainController() showFirstRunUI];
TapButtonWithLabelId(IDS_IOS_FIRSTRUN_OPT_IN_ACCEPT_BUTTON);
// Sign In |identity|.
TapButtonWithLabelId(IDS_IOS_ACCOUNT_CONSISTENCY_SETUP_SIGNIN_BUTTON);
AssertAuthenticatedIdentityInActiveProfile(identity);
// Tap Settings link.
id<GREYMatcher> settings_link_matcher = grey_allOf(
grey_accessibilityLabel(@"Settings"), grey_sufficientlyVisible(), nil);
[[EarlGrey selectElementWithMatcher:settings_link_matcher]
performAction:grey_tap()];
// Check Sync hasn't started yet, allowing the user to change somes settings.
SyncSetupService* sync_service = SyncSetupServiceFactory::GetForBrowserState(
chrome_test_util::GetOriginalBrowserState());
GREYAssertFalse(sync_service->HasFinishedInitialSetup(),
@"Sync shouldn't have finished its original setup yet");
// Close Settings, user is still signed in and sync is now starting.
TapButtonWithLabelId(IDS_IOS_NAVIGATION_BAR_DONE_BUTTON);
AssertAuthenticatedIdentityInActiveProfile(identity);
GREYAssertTrue(sync_service->HasFinishedInitialSetup(),
@"Sync should have finished its original setup");
}
@end
// Copyright 2016 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_UI_FIRST_RUN_FIRST_RUN_HISTOGRAMS_H_
#define IOS_CHROME_BROWSER_UI_FIRST_RUN_FIRST_RUN_HISTOGRAMS_H_
#include "base/metrics/histogram.h"
// HISTOGRAM_POINTER_BLOCK differ from STATIC_HISTOGRAM_POINTER_BLOCK
// on using static histogram pointer, in this one we create a new histogram
// from the histogram_factory_get_invocation each time this is called.
// This is needed on the first run because the same funciton try to log
// different histogram names, also we don't need static histogram as first run
// logging only happens once (may be little more in some cases).
#define HISTOGRAM_POINTER_BLOCK(constant_histogram_name, \
histogram_add_method_invocation, \
histogram_factory_get_invocation) \
do { \
base::HistogramBase* histogram_pointer = histogram_factory_get_invocation; \
histogram_pointer->histogram_add_method_invocation; \
} while (0)
// This UMA_HISTOGRAM_CUSTOM_TIMES_FIRST_RUN uses the HISTOGRAM_POINTER_BLOCK
// instead of STATIC_HISTOGRAM_POINTER_BLOCK which handles being called with
// different names from same function.
#define UMA_HISTOGRAM_CUSTOM_TIMES_FIRST_RUN(name, sample, min, max, \
bucket_count) \
HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \
base::Histogram::FactoryTimeGet( \
name, min, max, bucket_count, \
base::HistogramBase::kUmaTargetedHistogramFlag))
#endif // IOS_CHROME_BROWSER_UI_FIRST_RUN_FIRST_RUN_HISTOGRAMS_H_
// 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 IOS_CHROME_BROWSER_UI_FIRST_RUN_FIRST_RUN_UTIL_H_
#define IOS_CHROME_BROWSER_UI_FIRST_RUN_FIRST_RUN_UTIL_H_
#import <UIKit/UIKit.h>
@class FirstRunConfiguration;
@class Tab;
namespace base {
class TimeTicks;
}
namespace ios {
class ChromeBrowserState;
}
// Notification sent when the first run ends, right before dimissing the Terms
// of Service modal view.
extern NSString* const kChromeFirstRunUIWillFinishNotification;
// Notification sent when the first run has finished and has dismissed the Terms
// of Service modal view.
extern NSString* const kChromeFirstRunUIDidFinishNotification;
namespace ios_internal {
// Checks if the last line of the label only contains one word and if so, insert
// a newline character before the second to last word so that there are two
// words on the last line. Should only be called on labels that span multiple
// lines. Returns YES if a newline was added.
BOOL FixOrphanWord(UILabel* label);
// Creates the First Run sentinel file so that the user will not be shown First
// Run on subsequent cold starts. The user is considered done with First Run
// only after a successful sign-in or explicitly skipping signing in. First Run
// metrics are recorded iff the sentinel file didn't previous exist and was
// successfully created.
void WriteFirstRunSentinelAndRecordMetrics(
ios::ChromeBrowserState* browserState,
BOOL sign_in_attempted,
BOOL has_sso_account);
// Methods for writing sentinel and recording metrics and posting notifications
void FinishFirstRun(ios::ChromeBrowserState* browserState,
Tab* tab,
FirstRunConfiguration* config);
// Records Product tour timing metrics using histogram.
void RecordProductTourTimingMetrics(NSString* timer_name,
base::TimeTicks start_time);
// Posts a notification that First Run did finish.
void FirstRunDismissed();
// Enables or disables the data reduction proxy and also sets a key indicating
// application is using Data Reduction Proxy.
void SetDataReductionProxyEnabled(ios::ChromeBrowserState* browserState,
BOOL enabled,
BOOL toggled_switch);
} // namespace ios_internal
#endif // IOS_CHROME_BROWSER_UI_FIRST_RUN_FIRST_RUN_UTIL_H_
// 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.
#import "ios/chrome/browser/ui/first_run/first_run_util.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/strings/sys_string_conversions.h"
#include "base/time/time.h"
#include "components/signin/core/browser/signin_manager.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#import "ios/chrome/browser/crash_report/breakpad_helper.h"
#include "ios/chrome/browser/first_run/first_run.h"
#import "ios/chrome/browser/first_run/first_run_configuration.h"
#include "ios/chrome/browser/first_run/first_run_metrics.h"
#include "ios/chrome/browser/signin/signin_manager_factory.h"
#include "ios/chrome/browser/tabs/tab.h"
#include "ios/chrome/browser/ui/first_run/first_run_histograms.h"
#import "ios/chrome/browser/ui/settings/settings_utils.h"
#import "ios/chrome/browser/ui/sync/sync_util.h"
#include "ios/chrome/browser/ui/ui_util.h"
#include "ios/web/public/web_thread.h"
#import "ui/gfx/ios/NSString+CrStringDrawing.h"
NSString* const kChromeFirstRunUIWillFinishNotification =
@"kChromeFirstRunUIWillFinishNotification";
NSString* const kChromeFirstRunUIDidFinishNotification =
@"kChromeFirstRunUIDidFinishNotification";
namespace {
NSString* RemoveLastWord(NSString* text) {
__block NSRange range = NSMakeRange(0, [text length]);
NSStringEnumerationOptions options = NSStringEnumerationByWords |
NSStringEnumerationReverse |
NSStringEnumerationSubstringNotRequired;
// Enumerate backwards through the words in |text| to get the range of the
// last word.
[text
enumerateSubstringsInRange:range
options:options
usingBlock:^(NSString* substring, NSRange substringRange,
NSRange enclosingRange, BOOL* stop) {
range = substringRange;
*stop = YES;
}];
return [text substringToIndex:range.location];
}
NSString* InsertNewlineBeforeNthToLastWord(NSString* text, int index) {
__block NSRange range = NSMakeRange(0, [text length]);
__block int count = 0;
NSStringEnumerationOptions options = NSStringEnumerationByWords |
NSStringEnumerationReverse |
NSStringEnumerationSubstringNotRequired;
[text
enumerateSubstringsInRange:range
options:options
usingBlock:^(NSString* substring, NSRange substringRange,
NSRange enclosingRange, BOOL* stop) {
range = substringRange;
count++;
*stop = count == index;
}];
NSMutableString* textWithNewline = [[text mutableCopy] autorelease];
[textWithNewline insertString:@"\n" atIndex:range.location];
return textWithNewline;
}
// Trampoline method for Bind to create the sentinel file.
bool CreateSentinel() {
return FirstRun::CreateSentinel();
}
// Helper function for recording first run metrics. Takes an additional
// |to_record| argument which is the returned value from CreateSentinel().
void RecordFirstRunMetricsInternal(ios::ChromeBrowserState* browserState,
bool sign_in_attempted,
bool has_sso_accounts,
bool to_record) {
// |to_record| is false if the sentinel file was not created which indicates
// that the sentinel already exists and metrics were already recorded.
// Note: If the user signs in and then signs out during first run, it will be
// recorded as a successful sign in.
if (!to_record)
return;
bool user_signed_in =
ios::SigninManagerFactory::GetForBrowserState(browserState)
->IsAuthenticated();
first_run::SignInStatus sign_in_status;
if (user_signed_in) {
sign_in_status = has_sso_accounts
? first_run::HAS_SSO_ACCOUNT_SIGNIN_SUCCESSFUL
: first_run::SIGNIN_SUCCESSFUL;
} else {
if (sign_in_attempted) {
sign_in_status = has_sso_accounts
? first_run::HAS_SSO_ACCOUNT_SIGNIN_SKIPPED_GIVEUP
: first_run::SIGNIN_SKIPPED_GIVEUP;
} else {
sign_in_status = has_sso_accounts
? first_run::HAS_SSO_ACCOUNT_SIGNIN_SKIPPED_QUICK
: first_run::SIGNIN_SKIPPED_QUICK;
}
}
UMA_HISTOGRAM_ENUMERATION("FirstRun.SignIn", sign_in_status,
first_run::SIGNIN_SIZE);
}
} // namespace
namespace ios_internal {
BOOL FixOrphanWord(UILabel* label) {
// Calculate the height of the label's text.
NSString* text = label.text;
CGSize textSize =
[text cr_boundingSizeWithSize:label.frame.size font:label.font];
CGFloat textHeight = AlignValueToPixel(textSize.height);
// Remove the last word and calculate the height of the new text.
NSString* textMinusLastWord = RemoveLastWord(text);
CGSize minusLastWordSize =
[textMinusLastWord cr_boundingSizeWithSize:label.frame.size
font:label.font];
CGFloat minusLastWordHeight = AlignValueToPixel(minusLastWordSize.height);
// Check if removing the last word results in a smaller height.
if (minusLastWordHeight < textHeight) {
// The last word was the only word on its line. Add a newline before the
// second to last word.
label.text = InsertNewlineBeforeNthToLastWord(text, 2);
return true;
}
return false;
}
void WriteFirstRunSentinelAndRecordMetrics(
ios::ChromeBrowserState* browserState,
BOOL sign_in_attempted,
BOOL has_sso_account) {
// Call CreateSentinel() and pass the result into RecordFirstRunMetrics().
base::Callback<bool(void)> task = base::Bind(&CreateSentinel);
base::Callback<void(bool)> reply =
base::Bind(&RecordFirstRunMetricsInternal, browserState,
sign_in_attempted, has_sso_account);
base::PostTaskAndReplyWithResult(web::WebThread::GetBlockingPool(), FROM_HERE,
task, reply);
}
void FinishFirstRun(ios::ChromeBrowserState* browserState,
Tab* tab,
FirstRunConfiguration* config) {
[[NSNotificationCenter defaultCenter]
postNotificationName:kChromeFirstRunUIWillFinishNotification
object:nil];
WriteFirstRunSentinelAndRecordMetrics(browserState, config.signInAttempted,
config.hasSSOAccount);
// Display the sync errors infobar.
ios_internal::sync::displaySyncErrors(browserState, tab);
}
void RecordProductTourTimingMetrics(NSString* timer_name,
base::TimeTicks start_time) {
base::TimeDelta delta = base::TimeTicks::Now() - start_time;
NSString* histogramName =
[NSString stringWithFormat:@"ProductTour.IOSScreens%@", timer_name];
UMA_HISTOGRAM_CUSTOM_TIMES_FIRST_RUN(base::SysNSStringToUTF8(histogramName),
delta,
base::TimeDelta::FromMilliseconds(10),
base::TimeDelta::FromMinutes(3), 50);
}
void FirstRunDismissed() {
[[NSNotificationCenter defaultCenter]
postNotificationName:kChromeFirstRunUIDidFinishNotification
object:nil];
}
} // namespace ios_internal
// 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.
#import <UIKit/UIKit.h>
#include "base/mac/scoped_nsobject.h"
#include "ios/chrome/browser/ui/first_run/first_run_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
TEST(UICommonTest, TestFixOrphanWord) {
NSString* englishString =
@"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tempus"
" dignissim congue. Morbi pulvinar vitae purus at mollis. Sed laoreet "
"euismod neque, eget laoreet nisi porttitor sed.";
NSString* englishStringWithOrphan =
@"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tempus"
" dignissim congue. Morbi pulvinar vitae purus at mollis. Sed laoreet "
"euismod neque, eget laoreet nisi.";
// TODO(crbug.com/675342): clang_format does a poor job here. Remove when
// fixed in clang_format.
// clang-format off
NSString* chineseString =
@"那只敏捷的棕色狐狸跃过那只懒狗。那只敏捷的棕色狐狸跃过那只懒狗。"
"那只敏捷的棕色狐狸跃过那只懒狗。那只敏捷的棕色狐狸跃过那只懒狗。"
"那只敏捷的棕色狐狸跃过那只懒狗。那只敏捷的棕色狐狸跃过那只懒狗。";
NSString* chineseStringWithOrphan =
@"那只敏捷的棕色狐狸跃过那只懒狗。那只敏捷的棕色狐狸跃过那只懒狗。"
"那只敏捷的棕色狐狸跃过那只懒狗。快速狐狸";
// clang-format on
base::scoped_nsobject<UILabel> label(
[[UILabel alloc] initWithFrame:CGRectMake(0, 0, 300, 500)]);
[label setText:englishString];
ios_internal::FixOrphanWord(label);
NSRange range = [[label text] rangeOfString:@"\n"];
// Check that the label's text does not contain a newline.
EXPECT_EQ(NSNotFound, static_cast<NSInteger>(range.location));
[label setText:englishStringWithOrphan];
ios_internal::FixOrphanWord(label);
range = [[label text] rangeOfString:@"\n"];
// Check that the label's text contains a newline.
EXPECT_NE(NSNotFound, static_cast<NSInteger>(range.location));
// Check the words after the newline.
NSString* wordsAfterNewline =
[[label text] substringFromIndex:(range.location + range.length)];
EXPECT_TRUE([@"laoreet nisi." isEqualToString:wordsAfterNewline]);
[label setText:chineseString];
ios_internal::FixOrphanWord(label);
range = [[label text] rangeOfString:@"\n"];
// Check that the label's text does not contain a newline.
EXPECT_EQ(NSNotFound, static_cast<NSInteger>(range.location));
[label setText:chineseStringWithOrphan];
ios_internal::FixOrphanWord(label);
range = [[label text] rangeOfString:@"\n"];
// Check that the label's text contains a newline.
ASSERT_NE(NSNotFound, static_cast<NSInteger>(range.location));
// Check the words after the newline.
wordsAfterNewline =
[[label text] substringFromIndex:(range.location + range.length)];
EXPECT_TRUE([@"快速狐狸" isEqualToString:wordsAfterNewline]);
}
}
// Copyright 2013 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_UI_FIRST_RUN_STATIC_FILE_VIEW_CONTROLLER_H_
#define IOS_CHROME_BROWSER_UI_FIRST_RUN_STATIC_FILE_VIEW_CONTROLLER_H_
#import <UIKit/UIKit.h>
namespace ios {
class ChromeBrowserState;
}
// View controller used to display a bundled file in a web view with a shadow
// below the navigation bar when the user scrolls.
@interface StaticFileViewController : UIViewController
// Initializes with the given URL to display and browser state. Neither
// |browserState| nor |URL| may be nil.
- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
URL:(NSURL*)URL;
@end
#endif // IOS_CHROME_BROWSER_UI_FIRST_RUN_STATIC_FILE_VIEW_CONTROLLER_H_
// Copyright 2013 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/ui/first_run/static_file_view_controller.h"
#include <WebKit/WebKit.h>
#include "base/logging.h"
#include "base/mac/scoped_nsobject.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#import "ios/chrome/browser/ui/material_components/utils.h"
#include "ios/chrome/browser/ui/rtl_geometry.h"
#import "ios/third_party/material_components_ios/src/components/AppBar/src/MaterialAppBar.h"
#import "ios/third_party/material_components_ios/src/components/FlexibleHeader/src/MaterialFlexibleHeader.h"
#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
#import "ios/web/public/web_view_creation_util.h"
@interface StaticFileViewController ()<UIScrollViewDelegate> {
ios::ChromeBrowserState* _browserState; // weak
base::scoped_nsobject<NSURL> _URL;
// YES if the header has been configured for RTL.
BOOL _headerLaidOutForRTL;
// The web view used to display the static content.
base::scoped_nsobject<WKWebView> _webView;
// The header.
base::scoped_nsobject<MDCAppBar> _appBar;
}
@end
@implementation StaticFileViewController
- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
URL:(NSURL*)URL {
DCHECK(browserState);
DCHECK(URL);
self = [super init];
if (self) {
_appBar.reset([[MDCAppBar alloc] init]);
[self addChildViewController:[_appBar headerViewController]];
_browserState = browserState;
_URL.reset([URL retain]);
}
return self;
}
- (void)dealloc {
[_webView scrollView].delegate = nil;
[super dealloc];
}
#pragma mark - UIViewController
- (void)viewDidLoad {
[super viewDidLoad];
_webView.reset([web::BuildWKWebView(self.view.bounds, _browserState) retain]);
[_webView setAutoresizingMask:UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight];
// Loads terms of service into the web view.
[_webView loadRequest:[NSURLRequest requestWithURL:_URL]];
[_webView setBackgroundColor:[UIColor whiteColor]];
[self.view addSubview:_webView];
ConfigureAppBarWithCardStyle(_appBar);
[_appBar headerViewController].headerView.trackingScrollView =
[_webView scrollView];
[_webView scrollView].delegate = [_appBar headerViewController];
// Add the app bar at the end.
[_appBar addSubviewsToParent];
}
@end
// Copyright 2015 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_UI_FIRST_RUN_WELCOME_TO_CHROME_VIEW_H_
#define IOS_CHROME_BROWSER_UI_FIRST_RUN_WELCOME_TO_CHROME_VIEW_H_
#import <UIKit/UIKit.h>
@class WelcomeToChromeView;
// Delegate for WelcomeToChromeViews.
@protocol WelcomeToChromeViewDelegate<NSObject>
// Called when the user taps on the "Terms of Service" link.
- (void)welcomeToChromeViewDidTapTOSLink:(WelcomeToChromeView*)view;
// Called when the user taps the "Accept & Continue" button.
- (void)welcomeToChromeViewDidTapOKButton:(WelcomeToChromeView*)view;
@end
// The first view shown to the user after fresh installs.
@interface WelcomeToChromeView : UIView
@property(nonatomic, assign) id<WelcomeToChromeViewDelegate> delegate;
// Whether the stats reporting check box is selected.
@property(nonatomic, assign, getter=isCheckBoxSelected) BOOL checkBoxSelected;
// Runs the transition animation from Launch Screen to the Welcome to Chrome
// View. This method must be called after the view is added to a superview and
// the view's subviews have been laid out.
- (void)runLaunchAnimation;
@end
#endif // IOS_CHROME_BROWSER_UI_FIRST_RUN_WELCOME_TO_CHROME_VIEW_H_
This diff is collapsed.
// Copyright 2013 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_UI_FIRST_RUN_WELCOME_TO_CHROME_VIEW_CONTROLLER_H_
#define IOS_CHROME_BROWSER_UI_FIRST_RUN_WELCOME_TO_CHROME_VIEW_CONTROLLER_H_
#import <UIKit/UIKit.h>
extern NSString* const kUMAMetricsButtonAccessibilityIdentifier;
@class TabModel;
namespace ios {
class ChromeBrowserState;
}
// The first screen displayed to the user on First Run. User must agree to the
// Chrome Terms of Service before proceeding to use Chrome.
//
// Note: On iPhone, this controller supports portrait orientation only. It
// should always be presented in an |OrientationLimitingNavigationController|.
@interface WelcomeToChromeViewController : UIViewController
// True when the stats checkbox should be checked by default.
+ (BOOL)defaultStatsCheckboxValue;
// Initializes with the given browser state object and tab model, neither of
// which can be nil.
- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
tabModel:(TabModel*)tabModel
NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithNibName:(NSString*)nibNameOrNil
bundle:(NSBundle*)nibBundleOrNil NS_UNAVAILABLE;
- (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
@end
#endif // IOS_CHROME_BROWSER_UI_FIRST_RUN_WELCOME_TO_CHROME_VIEW_CONTROLLER_H_
// Copyright 2013 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/ui/first_run/welcome_to_chrome_view_controller.h"
#include "base/i18n/rtl.h"
#include "base/ios/weak_nsobject.h"
#include "base/logging.h"
#include "base/mac/bundle_locations.h"
#include "base/mac/foundation_util.h"
#include "base/mac/objc_property_releaser.h"
#include "base/mac/scoped_nsobject.h"
#include "base/strings/sys_string_conversions.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/metrics/metrics_reporting_default_state.h"
#include "components/prefs/pref_service.h"
#include "ios/chrome/browser/application_context.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#include "ios/chrome/browser/first_run/first_run_configuration.h"
#include "ios/chrome/browser/tabs/tab_model.h"
#include "ios/chrome/browser/ui/fancy_ui/primary_action_button.h"
#include "ios/chrome/browser/ui/file_locations.h"
#import "ios/chrome/browser/ui/first_run/first_run_chrome_signin_view_controller.h"
#include "ios/chrome/browser/ui/first_run/first_run_util.h"
#include "ios/chrome/browser/ui/first_run/static_file_view_controller.h"
#import "ios/chrome/browser/ui/first_run/welcome_to_chrome_view.h"
#include "ios/chrome/browser/ui/ui_util.h"
#import "ios/chrome/browser/ui/uikit_ui_util.h"
#include "ios/chrome/common/string_util.h"
#include "ios/chrome/grit/ios_chromium_strings.h"
#include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
#import "ios/public/provider/chrome/browser/signin/chrome_identity_service.h"
#include "ui/base/l10n/l10n_util.h"
NSString* const kUMAMetricsButtonAccessibilityIdentifier =
@"UMAMetricsButtonAccessibilityIdentifier";
namespace {
const CGFloat kFadeOutAnimationDuration = 0.16f;
// Default value for metrics reporting state. "YES" corresponding to "opt-out"
// state.
const BOOL kDefaultStatsCheckboxValue = YES;
}
@interface WelcomeToChromeViewController ()<WelcomeToChromeViewDelegate> {
ios::ChromeBrowserState* browserState_; // weak
TabModel* tabModel_; // weak
base::mac::ObjCPropertyReleaser
propertyReleaser_WelcomeToChromeViewController_;
}
// The animation which occurs at launch has run.
@property(nonatomic, assign) BOOL ranLaunchAnimation;
@end
@implementation WelcomeToChromeViewController
@synthesize ranLaunchAnimation = _ranLaunchAnimation;
+ (BOOL)defaultStatsCheckboxValue {
// Record metrics reporting as opt-in/opt-out only once.
static dispatch_once_t once;
dispatch_once(&once, ^{
metrics::RecordMetricsReportingDefaultState(
GetApplicationContext()->GetLocalState(),
kDefaultStatsCheckboxValue ? metrics::EnableMetricsDefault::OPT_OUT
: metrics::EnableMetricsDefault::OPT_IN);
});
return kDefaultStatsCheckboxValue;
}
- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
tabModel:(TabModel*)tabModel {
DCHECK(browserState);
DCHECK(tabModel);
self = [super initWithNibName:nil bundle:nil];
if (self) {
browserState_ = browserState;
tabModel_ = tabModel;
propertyReleaser_WelcomeToChromeViewController_.Init(
self, [WelcomeToChromeViewController class]);
}
return self;
}
- (instancetype)initWithNibName:(nullable NSString*)nibNameOrNil
bundle:(nullable NSBundle*)nibBundleOrNil {
NOTREACHED();
return nil;
}
- (instancetype)initWithCoder:(nonnull NSCoder*)aDecoder {
NOTREACHED();
return nil;
}
- (void)loadView {
base::scoped_nsobject<WelcomeToChromeView> welcomeToChromeView(
[[WelcomeToChromeView alloc] initWithFrame:CGRectZero]);
[welcomeToChromeView setDelegate:self];
[welcomeToChromeView
setCheckBoxSelected:[[self class] defaultStatsCheckboxValue]];
self.view = welcomeToChromeView;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self.navigationController setNavigationBarHidden:YES];
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
if (self.ranLaunchAnimation)
return;
WelcomeToChromeView* view =
base::mac::ObjCCastStrict<WelcomeToChromeView>(self.view);
[view runLaunchAnimation];
self.ranLaunchAnimation = YES;
}
- (BOOL)prefersStatusBarHidden {
return YES;
}
- (NSURL*)newTermsOfServiceUrl {
std::string tos = GetTermsOfServicePath();
NSString* path = [[base::mac::FrameworkBundle() bundlePath]
stringByAppendingPathComponent:base::SysUTF8ToNSString(tos)];
base::scoped_nsobject<NSURLComponents> components(
[[NSURLComponents alloc] init]);
[components setScheme:@"file"];
[components setHost:@""];
[components setPath:path];
return [[components URL] retain];
}
// Displays the file at the given URL in a StaticFileViewController.
- (void)openStaticFileWithURL:(NSURL*)url title:(NSString*)title {
base::scoped_nsobject<StaticFileViewController> staticViewController(
[[StaticFileViewController alloc] initWithBrowserState:browserState_
URL:url]);
[staticViewController setTitle:title];
[self.navigationController pushViewController:staticViewController
animated:YES];
}
#pragma mark - WelcomeToChromeViewDelegate
- (void)welcomeToChromeViewDidTapTOSLink:(WelcomeToChromeView*)view {
NSString* title = l10n_util::GetNSString(IDS_IOS_FIRSTRUN_TERMS_TITLE);
base::scoped_nsobject<NSURL> tosUrl([self newTermsOfServiceUrl]);
[self openStaticFileWithURL:tosUrl title:title];
}
- (void)welcomeToChromeViewDidTapOKButton:(WelcomeToChromeView*)view {
GetApplicationContext()->GetLocalState()->SetBoolean(
metrics::prefs::kMetricsReportingEnabled, view.checkBoxSelected);
base::scoped_nsobject<FirstRunConfiguration> firstRunConfig(
[[FirstRunConfiguration alloc] init]);
bool hasSSOAccounts = ios::GetChromeBrowserProvider()
->GetChromeIdentityService()
->HasIdentities();
[firstRunConfig setHasSSOAccount:hasSSOAccounts];
base::scoped_nsobject<FirstRunChromeSigninViewController> signInController(
[[FirstRunChromeSigninViewController alloc]
initWithBrowserState:browserState_
tabModel:tabModel_
firstRunConfig:firstRunConfig
signInIdentity:nil]);
CATransition* transition = [CATransition animation];
transition.duration = kFadeOutAnimationDuration;
transition.type = kCATransitionFade;
[self.navigationController.view.layer addAnimation:transition
forKey:kCATransition];
[self.navigationController pushViewController:signInController animated:NO];
}
@end
// 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.
#import <UIKit/UIKit.h>
#include <memory>
#include "base/mac/scoped_nsobject.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
#include "ios/chrome/browser/tabs/tab_model.h"
#include "ios/chrome/browser/ui/fancy_ui/primary_action_button.h"
#import "ios/chrome/browser/ui/first_run/welcome_to_chrome_view.h"
#import "ios/chrome/browser/ui/first_run/welcome_to_chrome_view_controller.h"
#include "ios/chrome/browser/ui/ui_util.h"
#include "ios/chrome/test/ios_chrome_scoped_testing_local_state.h"
#include "ios/web/public/test/test_web_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gtest_mac.h"
#include "testing/platform_test.h"
#include "third_party/ocmock/OCMock/OCMock.h"
#include "third_party/ocmock/gtest_support.h"
@interface WelcomeToChromeView (ExposedForTesting)
@property(nonatomic, retain, readonly) UIButton* checkBoxButton;
- (void)checkBoxButtonWasTapped;
@end
namespace {
class WelcomeToChromeViewControllerTest : public PlatformTest {
protected:
void SetUp() override {
PlatformTest::SetUp();
TestChromeBrowserState::Builder test_cbs_builder;
chrome_browser_state_ = test_cbs_builder.Build();
id tabModel = [OCMockObject mockForClass:[TabModel class]];
controller_.reset([[WelcomeToChromeViewController alloc]
initWithBrowserState:chrome_browser_state_.get()
tabModel:tabModel]);
[controller_ loadView];
}
void TearDown() override {
controller_.reset();
PlatformTest::TearDown();
}
web::TestWebThreadBundle thread_bundle_;
IOSChromeScopedTestingLocalState local_state_;
std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
base::scoped_nsobject<WelcomeToChromeViewController> controller_;
};
TEST_F(WelcomeToChromeViewControllerTest, TestDefaultStatsCheckBoxValue) {
BOOL checkbox_value =
[WelcomeToChromeViewController defaultStatsCheckboxValue];
ASSERT_TRUE(checkbox_value);
}
TEST_F(WelcomeToChromeViewControllerTest, TestConstructorDestructor) {
EXPECT_TRUE(controller_.get());
EXPECT_TRUE([controller_ view]);
}
TEST_F(WelcomeToChromeViewControllerTest, TestToggleCheckbox) {
WelcomeToChromeView* welcome_view =
static_cast<WelcomeToChromeView*>([controller_ view]);
EXPECT_TRUE(welcome_view.checkBoxButton.selected);
[welcome_view checkBoxButtonWasTapped];
EXPECT_FALSE(welcome_view.checkBoxButton.selected);
[welcome_view checkBoxButtonWasTapped];
EXPECT_TRUE(welcome_view.checkBoxButton.selected);
}
} // namespace
// Copyright 2013 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_UI_FULLSCREEN_CONTROLLER_H_
#define IOS_CHROME_BROWSER_UI_FULLSCREEN_CONTROLLER_H_
#import <UIKit/UIKit.h>
#import "ios/web/public/web_state/crw_web_controller_observer.h"
#import "ios/web/public/web_state/crw_web_view_scroll_view_proxy.h"
namespace ios_internal {
// Duration of the toolbar animation.
const NSTimeInterval kToolbarAnimationDuration = 0.3;
} // namespace ios_internal
@class CRWWebViewScrollViewProxy;
@class FullScreenController;
namespace web {
class NavigationManager;
}
// Notification when the application is set up for testing.
extern NSString* const kSetupForTestingWillCloseAllTabsNotification;
@protocol FullScreenControllerDelegate<NSObject>
@required
// Called every time the header view needs to be moved in place according to
// the offset. The offset is a value between 0.0 (fully visible) and
// headerHeight (fully hidden). If animate is YES it is preferable for the
// delegate to slide the view in place instead of simply snapping it there. If
// animate is NO the view tracks touches on the screen and as such should be
// immediate.
- (void)fullScreenController:(FullScreenController*)fullscreenController
drawHeaderViewFromOffset:(CGFloat)headerOffset
animate:(BOOL)animate;
// Called when there is a need to move the header in place and scroll the
// webViewProxy's scroll view at the same time. Should always be animated.
// Only happens during a call to -setHeaderHeight:visible:onScrollView:. If
// |changeTopContentPadding| is YES, then in addition to scrolling, delegate
// should also update webViewProxy's topContentPadding.
- (void)fullScreenController:(FullScreenController*)fullScreenController
drawHeaderViewFromOffset:(CGFloat)headerOffset
onWebViewProxy:(id<CRWWebViewProxy>)webViewProxy
changeTopContentPadding:(BOOL)changeTopContentPadding
scrollingToOffset:(CGFloat)contentOffset;
// Called to retrieve the current height of the header. Only called from
// -setHeaderVisible:, so that method needs to be explicitly called when the
// height changes.
- (CGFloat)headerHeight;
// Tests if the session ID matches the current tab.
- (BOOL)isTabWithIDCurrent:(NSString*)sessionID;
// Current offset of the header. A value between 0.0 (fully visible) and
// headerHeight (fully hidden).
- (CGFloat)currentHeaderOffset;
@end
// This class will track a scrollview to make a header disappear on scroll down
// and reappear on scroll up. This class expects the scrollview to have the
// FullScreenController instance set as an observer right after the call to
// -initWithDelegate:scrollView:
//
// It also assumes the header is a view rendering itself on top of the scroll
// view, the delegate will simply move it out of view as needed. The delegate is
// called every time the header view needs to be moved.
@interface FullScreenController
: NSObject<CRWWebControllerObserver, CRWWebViewScrollViewProxyObserver>
// If set to YES this slightly alters the behaviour on drag down to pull the
// header to visible on the fist pixel moved. If set to NO (the default) there
// is a slight threshold before activating.
@property(nonatomic, assign) BOOL immediateDragDown;
// Designated initializer.
- (id)initWithDelegate:(id<FullScreenControllerDelegate>)delegate
navigationManager:(web::NavigationManager*)navigationManager
sessionID:(NSString*)sessionID;
// Used to clear state maintained by the controller and de-register from
// notifications. After this call the controller cease to function and will
// clear its delegate.
- (void)invalidate;
// Shows or hides the header as directed by |visible|. If necessary the delegate
// will be called synchronously with the desired offset and animate set to YES.
// This method can be called when it is desirable to show or hide the header
// programmatically. It must be called when the header size changes.
- (void)moveHeaderToRestingPosition:(BOOL)visible;
// Disabling full screen will pull the header to visible and keep it there no
// matter what the scrollview is doing.
- (void)disableFullScreen;
// Enabling fullscreen will reverse the effect of a call to -disableFullScreen.
// The toolbar will stay on screen until a move pushes it out.
- (void)enableFullScreen;
// Skip next attempt to correct the scroll offset for the toolbar height. This
// is necessary when programatically scrolling down the y offset.
- (void)shouldSkipNextScrollOffsetForHeader;
// Update the insets during animation. When |forceUpdate| is set to NO, a faster
// workaround implemention is used to update the content's offset. That
// implemention does not cause a full update. |forceUpdate| should only be set
// to |NO| when -setToolbarInsetsForHeaderOffset is called
// in quick succession during scroll callbacks.
- (void)setToolbarInsetsForHeaderOffset:(CGFloat)headerOffset
forceUpdate:(BOOL)forceUpdate;
// Set the content offset of the underlying UIScrollView so that the content
// is not hidden by the header. The header will be moved to its visible position
// without animation if it is not already fully visible.
- (void)moveContentBelowHeader;
@end
@interface FullScreenController (UsedForTesting)
// Enables/Disables the FullScreenController in tests. The unit tests do not set
// the delegate which is crucial for methods to work on the controller.
// This a temporary solution.
// TODO(shreyasv): Find a better solution/remove this when FullScreenController
// moves to Tab.
+ (void)setEnabledForTests:(BOOL)enabled;
// Sets the hide omnibox delay. If set to 0.0, the omnibox is hidden
// synchronously.
+ (void)setHideOmniboxDelaySeconds:(double)hideOmniboxDelaySeconds;
// Resets the hide omnibox delay to its default value.
+ (void)resetHideOmniboxDelaySeconds;
@end
#endif // IOS_CHROME_BROWSER_UI_FULLSCREEN_CONTROLLER_H_
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
// Copyright 2016 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_UI_HISTORY_CLEAR_BROWSING_BAR_H_
#define IOS_CHROME_BROWSER_UI_HISTORY_CLEAR_BROWSING_BAR_H_
#import <UIKit/UIKit.h>
// View at the bottom of the history panel that presents options to clear
// browsing data or enter edit mode. When in edit mode, the bar displays a
// delete button and a cancel button instead.
@interface ClearBrowsingBar : UIView
// Yes if in edit mode. Setting to |editing| ClearBrowsingBar for edit
// mode or non-edit mode accordingly.
@property(nonatomic, getter=isEditing) BOOL editing;
// Yes if the edit button is enabled. Setting |editButtonEnabled| enables or
// disables the edit button accordingly.
@property(nonatomic, getter=isEditButtonEnabled) BOOL editButtonEnabled;
// Yes if the delete button is enabled. Setting |deleteButtonEnabled| enables or
// disables the delete button accordingly.
@property(nonatomic, getter=isDeleteButtonEnabled) BOOL deleteButtonEnabled;
// Sets the target/action of the "Clear Browsing Data..." button.
- (void)setClearBrowsingDataTarget:(id)target action:(SEL)action;
// Sets the target/action of the "Edit" button.
- (void)setEditTarget:(id)target action:(SEL)action;
// Sets the target/action of the "Delete" button.
- (void)setDeleteTarget:(id)taret action:(SEL)action;
// Sets the target/action of the "Cancel" button.
- (void)setCancelTarget:(id)target action:(SEL)action;
@end
#endif // IOS_CHROME_BROWSER_UI_HISTORY_CLEAR_BROWSING_BAR_H_
This diff is collapsed.
// Copyright 2016 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_UI_HISTORY_FAVICON_VIEW_H_
#define IOS_CHROME_BROWSER_UI_HISTORY_FAVICON_VIEW_H_
#import <UIKit/UIKit.h>
@interface FaviconView : UIView
// Size for the favicon.
@property(nonatomic) CGFloat size;
// Image view for the favicon.
@property(nonatomic, retain) UIImageView* faviconImage;
// Label for fallback favicon placeholder.
@property(nonatomic, retain) UILabel* faviconFallbackLabel;
@end
#endif // IOS_CHROME_BROWSER_UI_HISTORY_FAVICON_VIEW_H_
This diff is collapsed.
// Copyright 2016 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_UI_HISTORY_FAVICON_VIEW_PROVIDER_H_
#define IOS_CHROME_BROWSER_UI_HISTORY_FAVICON_VIEW_PROVIDER_H_
#import <UIKit/UIKit.h>
namespace favicon {
class LargeIconService;
} // namespace favicon
@class FaviconView;
@class FaviconViewProvider;
class GURL;
// Delegate protocol for FaviconViewProvider.
@protocol FaviconViewProviderDelegate<NSObject>
// Called when favicon or fallback format has been fetched.
- (void)faviconViewProviderFaviconDidLoad:(FaviconViewProvider*)provider;
@end
// Object to fetch and configure the view for a favicon, or a fallback icon if
// there is no favicon image available with large enough resolution.
@interface FaviconViewProvider : NSObject
// A favicon or fallback format associated with |URL| will be fetched using
// |largeIconService|. The favicon will be rendered with height and width equal
// to |faviconSize|, and the image will be fetched if the source size is greater
// than or equal to |minFaviconSize|. The |delegate| is notified when the
// favicon has been loaded, and may be nil.
- (instancetype)initWithURL:(const GURL&)URL
faviconSize:(CGFloat)faviconSize
minFaviconSize:(CGFloat)minFaviconSize
largeIconService:(favicon::LargeIconService*)largeIconService
delegate:(id<FaviconViewProviderDelegate>)delegate
NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
// View that displays a favicon or fallback icon.
@property(nonatomic, readonly) FaviconView* faviconView;
@end
#endif // IOS_CHROME_BROWSER_UI_HISTORY_FAVICON_VIEW_PROVIDER_H_
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
// Copyright (c) 2012 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_UI_INFOBARS_INFOBAR_VIEW_H_
#define IOS_CHROME_BROWSER_UI_INFOBARS_INFOBAR_VIEW_H_
#import <UIKit/UIKit.h>
#import "ios/chrome/browser/ui/fancy_ui/bidi_container_view.h"
#import "ios/public/provider/chrome/browser/ui/infobar_view_protocol.h"
class InfoBarViewDelegate;
@protocol InfoBarViewProtocol;
// UIView representing a single infobar.
@interface InfoBarView : BidiContainerView<InfoBarViewProtocol>
- (instancetype)initWithFrame:(CGRect)frame
delegate:(InfoBarViewDelegate*)delegate;
@end
#endif // IOS_CHROME_BROWSER_UI_INFOBARS_INFOBAR_VIEW_H_
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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