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

Unified Diff: ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.mm

Issue 2589803002: Upstream Chrome on iOS source code [6/11]. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.mm
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.mm
new file mode 100644
index 0000000000000000000000000000000000000000..12d521ed35f6d59688e3661c1268e02c392ca3e5
--- /dev/null
+++ b/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.mm
@@ -0,0 +1,304 @@
+// 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.
+
+#include "ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.h"
+
+#import <QuartzCore/QuartzCore.h>
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/user_metrics.h"
+#include "base/metrics/user_metrics_action.h"
+#include "components/omnibox/browser/autocomplete_match.h"
+#include "components/omnibox/browser/omnibox_edit_model.h"
+#include "components/omnibox/browser/omnibox_popup_model.h"
+#include "components/open_from_clipboard/clipboard_recent_content.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#import "ios/chrome/browser/experimental_flags.h"
+#import "ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.h"
+#import "ios/chrome/browser/ui/omnibox/omnibox_popup_positioner.h"
+#include "ios/chrome/browser/ui/omnibox/omnibox_util.h"
+#include "ios/chrome/browser/ui/omnibox/omnibox_view_ios.h"
+#include "ios/chrome/browser/ui/ui_util.h"
+#include "ios/chrome/grit/ios_theme_resources.h"
+#include "ios/web/public/image_fetcher/image_data_fetcher.h"
+#include "ios/web/public/web_thread.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/image/image.h"
+
+namespace {
+const CGFloat kExpandAnimationDuration = 0.1;
+const CGFloat kCollapseAnimationDuration = 0.05;
+const CGFloat kWhiteBackgroundHeight = 74;
+NS_INLINE CGFloat ShadowHeight() {
+ return IsIPadIdiom() ? 10 : 0;
+}
+} // namespace
+
+using base::UserMetricsAction;
+
+OmniboxPopupViewIOS::OmniboxPopupViewIOS(OmniboxViewIOS* edit_view,
+ OmniboxEditModel* edit_model,
+ id<OmniboxPopupPositioner> positioner)
+ : model_(new OmniboxPopupModel(this, edit_model)),
+ edit_view_(edit_view),
+ positioner_(positioner),
+ is_open_(false) {
+ DCHECK(edit_view);
+ DCHECK(edit_model);
+
+ std::unique_ptr<web::ImageDataFetcher> imageFetcher =
+ base::MakeUnique<web::ImageDataFetcher>(
+ web::WebThread::GetBlockingPool());
+ imageFetcher->SetRequestContextGetter(
+ edit_view->browser_state()->GetRequestContext());
+
+ popup_controller_.reset([[OmniboxPopupMaterialViewController alloc]
+ initWithPopupView:this
+ withFetcher:std::move(imageFetcher)]);
+ [popup_controller_ setIncognito:edit_view->browser_state()->IsOffTheRecord()];
+ popupView_.reset([[UIView alloc] initWithFrame:CGRectZero]);
+ [popupView_ setClipsToBounds:YES];
+ CALayer* popupLayer = [popupView_ layer];
+ // Adjust popupView_'s anchor point and height so that it animates down
+ // from the top when it appears.
+ popupLayer.anchorPoint = CGPointMake(0.5, 0);
+ UIView* popupControllerView = [popup_controller_ view];
+ CGRect popupControllerFrame = popupControllerView.frame;
+ popupControllerFrame.origin = CGPointZero;
+ popupControllerView.frame = popupControllerFrame;
+ [popupView_ addSubview:popupControllerView];
+ if (IsIPadIdiom()) {
+ [popupView_ setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ gfx::Image shadowImage =
+ rb.GetNativeImageNamed(IDR_IOS_TOOLBAR_SHADOW_FULL_BLEED);
+ base::scoped_nsobject<UIImageView> shadowView(
+ [[UIImageView alloc] initWithImage:shadowImage.ToUIImage()]);
+ [shadowView setUserInteractionEnabled:NO];
+ [shadowView setTranslatesAutoresizingMaskIntoConstraints:NO];
+ [popupView_ addSubview:shadowView];
+
+ // Add constraints to position |shadowView| at the bottom of |popupView_|
+ // with the same width as |popupView_|.
+ NSDictionary* views = NSDictionaryOfVariableBindings(shadowView);
+ [popupView_
+ addConstraints:[NSLayoutConstraint
+ constraintsWithVisualFormat:@"H:|[shadowView]|"
+ options:0
+ metrics:nil
+ views:views]];
+ [popupView_ addConstraint:[NSLayoutConstraint
+ constraintWithItem:shadowView
+ attribute:NSLayoutAttributeBottom
+ relatedBy:NSLayoutRelationEqual
+ toItem:popupView_
+ attribute:NSLayoutAttributeBottom
+ multiplier:1
+ constant:0]];
+ } else {
+ // Add a white background to prevent seing the logo scroll through the
+ // omnibox.
+ base::scoped_nsobject<UIView> whiteBackground(
+ [[UIView alloc] initWithFrame:CGRectZero]);
+ [popupView_ addSubview:whiteBackground];
+ [whiteBackground setBackgroundColor:[UIColor whiteColor]];
+
+ // Set constraints to |whiteBackground|.
+ [whiteBackground setTranslatesAutoresizingMaskIntoConstraints:NO];
+ NSDictionary* metrics = @{ @"height" : @(kWhiteBackgroundHeight) };
+ NSDictionary* views = NSDictionaryOfVariableBindings(whiteBackground);
+ [popupView_
+ addConstraints:[NSLayoutConstraint
+ constraintsWithVisualFormat:@"H:|[whiteBackground]|"
+ options:0
+ metrics:nil
+ views:views]];
+ [popupView_
+ addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:
+ @"V:[whiteBackground(==height)]"
+ options:0
+ metrics:metrics
+ views:views]];
+ [popupView_ addConstraint:[NSLayoutConstraint
+ constraintWithItem:whiteBackground
+ attribute:NSLayoutAttributeBottom
+ relatedBy:NSLayoutRelationEqual
+ toItem:popupView_
+ attribute:NSLayoutAttributeTop
+ multiplier:1
+ constant:0]];
+ // |whiteBackground| extends out of |popupView_|
+ [popupView_ setClipsToBounds:NO];
+ }
+}
+
+OmniboxPopupViewIOS::~OmniboxPopupViewIOS() {
+ // Destroy the model, in case it tries to call back into us when destroyed.
+ model_.reset();
+}
+
+// Set left image to globe or magnifying glass depending on which autocomplete
+// option comes first.
+void OmniboxPopupViewIOS::UpdateEditViewIcon() {
+ const AutocompleteResult& result = model_->result();
+ const AutocompleteMatch& match = result.match_at(0); // 0 for first result.
+ int image_id = GetIconForAutocompleteMatchType(
+ match.type, /* is_starred */ false, /* is_incognito */ false);
+ edit_view_->SetLeftImage(image_id);
+}
+
+void OmniboxPopupViewIOS::UpdatePopupAppearance() {
+ const AutocompleteResult& result = model_->result();
+ UIView* view = popupView_;
+
+ if (!is_open_ && !result.empty()) {
+ // The popup is not currently open and there are results to display. Update
+ // and animate the cells
+ [popup_controller_ updateMatches:result withAnimation:YES];
+ } else {
+ // The popup is already displayed or there are no results to display. Update
+ // the cells without animating.
+ [popup_controller_ updateMatches:result withAnimation:NO];
+ }
+ is_open_ = !result.empty();
+
+ if (is_open_) {
+ // Show |result.size| on iPad. Since iPhone can dismiss keyboard, set
+ // height to frame height.
+ CGFloat height = [[popup_controller_ tableView] contentSize].height;
+ UIEdgeInsets insets = [[popup_controller_ tableView] contentInset];
+ // Note the calculation |insets.top * 2| is correct, it should not be
+ // insets.top + insets.bottom. |insets.bottom| will be larger than
+ // |insets.top| when the keyboard is visible, but |parentHeight| should stay
+ // the same.
+ CGFloat parentHeight = height + insets.top * 2 + ShadowHeight();
+ UIView* siblingView = [positioner_ popupAnchorView];
+ if (!IsIPadIdiom()) {
+ [view setAutoresizingMask:UIViewAutoresizingFlexibleWidth |
+ UIViewAutoresizingFlexibleHeight];
+ [[siblingView superview] insertSubview:view belowSubview:siblingView];
+ } else {
+ [[siblingView superview] insertSubview:view aboveSubview:siblingView];
+ }
+ CGFloat currentHeight = view.layer.bounds.size.height;
+ if (currentHeight == 0)
+ AnimateDropdownExpansion(parentHeight);
+ else
+ [view setFrame:[positioner_ popupFrame:parentHeight]];
+ UIView* popupControllerView = [popup_controller_ view];
+ CGRect popupControllerFrame = popupControllerView.frame;
+ popupControllerFrame.size.height = view.frame.size.height - ShadowHeight();
+ popupControllerView.frame = popupControllerFrame;
+ UpdateEditViewIcon();
+ } else {
+ AnimateDropdownCollapse();
+ }
+
+ edit_view_->OnPopupResultsChanged(result);
+}
+
+void OmniboxPopupViewIOS::AnimateDropdownExpansion(CGFloat parentHeight) {
+ CGRect popupFrame = [positioner_ popupFrame:parentHeight];
+ CALayer* popupLayer = [popupView_ layer];
+ CGRect bounds = popupLayer.bounds;
+ bounds.size.height = popupFrame.size.height;
+ popupLayer.bounds = bounds;
+
+ CGRect frame = [popupView_ frame];
+ frame.size.width = popupFrame.size.width;
+ frame.origin.y = popupFrame.origin.y;
+ [popupView_ setFrame:frame];
+
+ CABasicAnimation* growHeight =
+ [CABasicAnimation animationWithKeyPath:@"bounds.size.height"];
+ growHeight.fromValue = @0;
+ growHeight.toValue = [NSNumber numberWithFloat:popupFrame.size.height];
+ growHeight.duration = kExpandAnimationDuration;
+ growHeight.timingFunction =
+ [CAMediaTimingFunction functionWithControlPoints:0.4:0:0.2:1];
+ [popupLayer addAnimation:growHeight forKey:@"growHeight"];
+}
+
+void OmniboxPopupViewIOS::AnimateDropdownCollapse() {
+ CALayer* popupLayer = [popupView_ layer];
+ CGRect bounds = popupLayer.bounds;
+ CGFloat currentHeight = bounds.size.height;
+ bounds.size.height = 0;
+ popupLayer.bounds = bounds;
+
+ UIView* retainedPopupView = popupView_;
+ [CATransaction begin];
+ [CATransaction setCompletionBlock:^{
+ [retainedPopupView removeFromSuperview];
+ }];
+ CABasicAnimation* shrinkHeight =
+ [CABasicAnimation animationWithKeyPath:@"bounds.size.height"];
+ shrinkHeight.fromValue = [NSNumber numberWithFloat:currentHeight];
+ shrinkHeight.toValue = @0;
+ shrinkHeight.duration = kCollapseAnimationDuration;
+ shrinkHeight.timingFunction =
+ [CAMediaTimingFunction functionWithControlPoints:0.4:0:1:1];
+ [popupLayer addAnimation:shrinkHeight forKey:@"shrinkHeight"];
+ [CATransaction commit];
+}
+
+gfx::Rect OmniboxPopupViewIOS::GetTargetBounds() {
+ return gfx::Rect();
+}
+
+// For phone, allow popup to take focus (and dismiss the keyboard) on scroll.
+void OmniboxPopupViewIOS::DidScroll() {
+ if (!IsIPadIdiom()) {
+ edit_view_->HideKeyboard();
+ }
+}
+
+// Puts omnibox back into focus with suggested search terms.
+void OmniboxPopupViewIOS::CopyToOmnibox(const base::string16& str) {
+ edit_view_->SetUserText(str);
+ edit_view_->FocusOmnibox();
+}
+
+void OmniboxPopupViewIOS::SetTextAlignment(NSTextAlignment alignment) {
+ [popup_controller_ setTextAlignment:alignment];
+}
+
+bool OmniboxPopupViewIOS::IsStarredMatch(const AutocompleteMatch& match) const {
+ return model_->IsStarredMatch(match);
+}
+
+void OmniboxPopupViewIOS::DeleteMatch(const AutocompleteMatch& match) const {
+ model_->autocomplete_controller()->DeleteMatch(match);
+}
+
+void OmniboxPopupViewIOS::OpenURLForRow(size_t row) {
+ // Crash reports tell us that |row| is sometimes indexed past the end of
+ // the results array. In those cases, just ignore the request and return
+ // early. See b/5813291.
+ if (row >= model_->result().size())
+ return;
+
+ WindowOpenDisposition disposition = WindowOpenDisposition::CURRENT_TAB;
+ base::RecordAction(UserMetricsAction("MobileOmniboxUse"));
+
+ // OpenMatch() may close the popup, which will clear the result set and, by
+ // extension, |match| and its contents. So copy the relevant match out to
+ // make sure it stays alive until the call completes.
+ AutocompleteMatch match = model_->result().match_at(row);
+ if (match.type == AutocompleteMatchType::CLIPBOARD) {
+ base::RecordAction(UserMetricsAction("MobileOmniboxClipboardToURL"));
+ UMA_HISTOGRAM_LONG_TIMES_100(
+ "MobileOmnibox.PressedClipboardSuggestionAge",
+ ClipboardRecentContent::GetInstance()->GetClipboardContentAge());
+ }
+ edit_view_->OpenMatch(match, disposition, GURL(), base::string16(), row);
+}
+
+bool OmniboxPopupViewIOS::IsOpen() const {
+ return is_open_;
+}
« no previous file with comments | « ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.h ('k') | ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698