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

Unified Diff: ios/chrome/browser/geolocation/omnibox_geolocation_controller.mm

Issue 2585233003: Upstream Chrome on iOS source code [2/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/geolocation/omnibox_geolocation_controller.mm
diff --git a/ios/chrome/browser/geolocation/omnibox_geolocation_controller.mm b/ios/chrome/browser/geolocation/omnibox_geolocation_controller.mm
new file mode 100644
index 0000000000000000000000000000000000000000..b0a42beb2934208331dcd6a64cea9da8568726bd
--- /dev/null
+++ b/ios/chrome/browser/geolocation/omnibox_geolocation_controller.mm
@@ -0,0 +1,586 @@
+// 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.
+
+#import "ios/chrome/browser/geolocation/omnibox_geolocation_controller.h"
+
+#import <CoreLocation/CoreLocation.h>
+#import <UIKit/UIKit.h>
+
+#include <string>
+
+#import "base/ios/weak_nsobject.h"
+#include "base/logging.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/metrics/histogram.h"
+#include "base/version.h"
+#include "components/google/core/browser/google_util.h"
+#include "components/version_info/version_info.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#import "ios/chrome/browser/geolocation/CLLocation+OmniboxGeolocation.h"
+#import "ios/chrome/browser/geolocation/CLLocation+XGeoHeader.h"
+#import "ios/chrome/browser/geolocation/location_manager.h"
+#import "ios/chrome/browser/geolocation/omnibox_geolocation_authorization_alert.h"
+#import "ios/chrome/browser/geolocation/omnibox_geolocation_config.h"
+#import "ios/chrome/browser/geolocation/omnibox_geolocation_controller+Testing.h"
+#import "ios/chrome/browser/geolocation/omnibox_geolocation_local_state.h"
+#import "ios/chrome/browser/tabs/tab.h"
+#include "ios/web/public/navigation_item.h"
+#import "ios/web/public/navigation_manager.h"
+#include "url/gurl.h"
+
+namespace {
+
+// Values for the histogram that records whether we sent the X-Geo header for
+// an Omnibox query or why we did not do so. These match the definition of
+// GeolocationHeaderSentOrNot in Chromium
+// src-internal/tools/histograms/histograms.xml.
+typedef enum {
+ // The user disabled location for Google.com (not used by Chrome iOS).
+ kHeaderStateNotSentAuthorizationGoogleDenied = 0,
+ // The user has not yet determined Chrome's access to the current device
+ // location or Chrome's use of geolocation for Omnibox queries.
+ kHeaderStateNotSentAuthorizationNotDetermined,
+ // The current device location is not available.
+ kHeaderStateNotSentLocationNotAvailable,
+ // The current device location is stale.
+ kHeaderStateNotSentLocationStale,
+ // The X-Geo header was sent.
+ kHeaderStateSent,
+ // The user denied Chrome from accessing the current device location.
+ kHeaderStateNotSentAuthorizationChromeDenied,
+ // The user denied Chrome from using geolocation for Omnibox queries.
+ kHeaderStateNotSentAuthorizationOmniboxDenied,
+ // The user's Google search domain is not whitelisted.
+ kHeaderStateNotSentDomainNotWhitelisted,
+ // The number of possible of HeaderState values to report.
+ kHeaderStateCount,
+} HeaderState;
+
+// Values for the histograms that record the user's action when prompted to
+// authorize the use of location by Chrome. These match the definition of
+// GeolocationAuthorizationAction in Chromium
+// src-internal/tools/histograms/histograms.xml.
+typedef enum {
+ // The user authorized use of location.
+ kAuthorizationActionAuthorized = 0,
+ // The user permanently denied use of location (Don't Allow).
+ kAuthorizationActionPermanentlyDenied,
+ // The user denied use of location at this prompt (Not Now).
+ kAuthorizationActionDenied,
+ // The number of possible AuthorizationAction values to report.
+ kAuthorizationActionCount,
+} AuthorizationAction;
+
+// Name of the histogram recording HeaderState.
+const char* const kGeolocationHeaderSentOrNotHistogram =
+ "Geolocation.HeaderSentOrNot";
+
+// Name of the histogram recording location acquisition time.
+const char* const kOmniboxQueryGeolocationAcquisitionTimeHistogram =
+ "Omnibox.QueryGeolocationAcquisitionTime";
+
+// Name of the histogram recording estimated location accuracy.
+const char* const kOmniboxQueryGeolocationHorizontalAccuracyHistogram =
+ "Omnibox.QueryGeolocationHorizontalAccuracy";
+
+// Name of the histogram recording AuthorizationAction for an existing user.
+const char* const kGeolocationAuthorizationActionExistingUser =
+ "Geolocation.AuthorizationActionExistingUser";
+
+// Name of the histogram recording AuthorizationAction for a new user.
+const char* const kGeolocationAuthorizationActionNewUser =
+ "Geolocation.AuthorizationActionNewUser";
+
+} // anonymous namespace
+
+@interface OmniboxGeolocationController ()<
+ LocationManagerDelegate,
+ OmniboxGeolocationAuthorizationAlertDelegate> {
+ base::scoped_nsobject<OmniboxGeolocationLocalState> localState_;
+ base::scoped_nsobject<LocationManager> locationManager_;
+ base::scoped_nsobject<OmniboxGeolocationAuthorizationAlert>
+ authorizationAlert_;
+ base::WeakNSObject<Tab> weakTabToReload_;
+
+ // Records whether we have deliberately presented the system prompt, so that
+ // we can record the user's action in
+ // locationManagerDidChangeAuthorizationStatus:.
+ BOOL systemPrompt_;
+
+ // Records whether we are prompting for a new user, so that we can record the
+ // user's action to the right histogram (either
+ // kGeolocationAuthorizationActionExistingUser or
+ // kGeolocationAuthorizationActionNewUser).
+ BOOL newUser_;
+}
+
+// Boolean value indicating whether geolocation is enabled for Omnibox queries.
+@property(nonatomic, readonly) BOOL enabled;
+
+// Convenience property lazily initializes |localState_|.
+@property(nonatomic, readonly) OmniboxGeolocationLocalState* localState;
+
+// Convenience property lazily initializes |locationManager_|.
+@property(nonatomic, readonly) LocationManager* locationManager;
+
+// Returns YES if and only if |url| and |transition| specify an Omnibox query
+// that is eligible for geolocation.
+- (BOOL)URLIsEligibleQueryURL:(const GURL&)url
+ transition:(ui::PageTransition)transition;
+
+// Returns YES if and only if |url| and |transition| specify an Omnibox query.
+//
+// Note: URLIsQueryURL:transition: is more liberal than
+// URLIsEligibleQueryURL:transition:. Use URLIsEligibleQueryURL:transition: and
+// not URLIsQueryURL:transition: to test Omnibox query URLs with respect to
+// sending location to Google.
+- (BOOL)URLIsQueryURL:(const GURL&)url
+ transition:(ui::PageTransition)transition;
+
+// Returns YES if and only if |url| specifies a page for which we will prompt
+// the user to authorize the use of geolocation for Omnibox queries.
+- (BOOL)URLIsAuthorizationPromptingURL:(const GURL&)url;
+
+// Starts updating device location if needed.
+- (void)startUpdatingLocation;
+// Stops updating device location.
+- (void)stopUpdatingLocation;
+// If the current location is not stale, then adds the current location to the
+// current session entry for |tab| and reloads |tab|. If the current location
+// is stale, then does nothing.
+- (void)addLocationAndReloadTab:(Tab*)tab;
+// Returns YES if and only if we should show an alert that prompts the user to
+// authorize using geolocation for Omnibox queries.
+- (BOOL)shouldShowAuthorizationAlert;
+// Shows an alert that prompts the user to authorize using geolocation for
+// Omnibox queries. Sets |weakTabToReload_| from |tab|, so that we can reload
+// |tab| if the user authorizes using geolocation.
+- (void)showAuthorizationAlertForTab:(Tab*)tab;
+// Records |headerState| for the |kGeolocationHeaderSentOrNotHistogram|
+// histogram.
+- (void)recordHeaderState:(HeaderState)headerState;
+// Records |authorizationAction|.
+- (void)recordAuthorizationAction:(AuthorizationAction)authorizationAction;
+
+@end
+
+@implementation OmniboxGeolocationController
+
++ (OmniboxGeolocationController*)sharedInstance {
+ static OmniboxGeolocationController* instance =
+ [[OmniboxGeolocationController alloc] init];
+ return instance;
+}
+
+- (void)triggerSystemPromptForNewUser:(BOOL)newUser {
+ if (self.locationManager.locationServicesEnabled &&
+ self.locationManager.authorizationStatus ==
+ kCLAuthorizationStatusNotDetermined) {
+ // Set |systemPrompt_|, so that
+ // locationManagerDidChangeAuthorizationStatus: will know to handle any
+ // CLAuthorizationStatus changes.
+ //
+ // TODO(crbug.com/661996): Remove the now useless
+ // kAuthorizationStateNotDeterminedSystemPrompt from
+ // omnibox_geolocation_local_state.h.
+ systemPrompt_ = YES;
+ self.localState.authorizationState =
+ geolocation::kAuthorizationStateNotDeterminedSystemPrompt;
+
+ // Turn on location updates, so that iOS will prompt the user.
+ [self startUpdatingLocation];
+
+ weakTabToReload_.reset();
+ newUser_ = newUser;
+ }
+}
+
+- (void)locationBarDidBecomeFirstResponder:
+ (ios::ChromeBrowserState*)browserState {
+ if (self.enabled && browserState && !browserState->IsOffTheRecord()) {
+ [self startUpdatingLocation];
+ }
+}
+
+- (void)locationBarDidResignFirstResponder:
+ (ios::ChromeBrowserState*)browserState {
+ // It's always okay to stop updating location.
+ [self stopUpdatingLocation];
+}
+
+- (void)locationBarDidSubmitURL:(const GURL&)url
+ transition:(ui::PageTransition)transition
+ browserState:(ios::ChromeBrowserState*)browserState {
+ // Stop updating the location when the user submits a query from the Omnibox.
+ // We're not interested in further updates until the next time the user puts
+ // the focus on the Omnbox.
+ [self stopUpdatingLocation];
+}
+
+- (BOOL)addLocationToNavigationItem:(web::NavigationItem*)item
+ browserState:(ios::ChromeBrowserState*)browserState {
+ // If this is incognito mode or is not an Omnibox query, then do nothing.
+ //
+ // Check the URL with URLIsQueryURL:transition: here and not
+ // URLIsEligibleQueryURL:transition:, because we want to log the cases where
+ // we did not send the X-Geo header due to the Google search domain not being
+ // whitelisted.
+ DCHECK(item);
+ const GURL& url = item->GetURL();
+ if (!browserState || browserState->IsOffTheRecord() ||
+ ![self URLIsQueryURL:url transition:item->GetTransitionType()]) {
+ return NO;
+ }
+
+ if (![[OmniboxGeolocationConfig sharedInstance] URLHasEligibleDomain:url]) {
+ [self recordHeaderState:kHeaderStateNotSentDomainNotWhitelisted];
+ return NO;
+ }
+
+ // At this point, we should only have Omnibox query URLs that are eligible
+ // for geolocation.
+ DCHECK([self URLIsEligibleQueryURL:url transition:item->GetTransitionType()]);
+
+ HeaderState headerState;
+ if (!self.locationManager.locationServicesEnabled) {
+ headerState = kHeaderStateNotSentAuthorizationChromeDenied;
+ } else {
+ switch (self.localState.authorizationState) {
+ case geolocation::kAuthorizationStateNotDeterminedWaiting:
+ case geolocation::kAuthorizationStateNotDeterminedSystemPrompt:
+ if (self.locationManager.authorizationStatus ==
+ kCLAuthorizationStatusNotDetermined ||
+ [self shouldShowAuthorizationAlert]) {
+ headerState = kHeaderStateNotSentAuthorizationNotDetermined;
+ } else {
+ DCHECK(self.locationManager.authorizationStatus ==
+ kCLAuthorizationStatusAuthorizedAlways ||
+ self.locationManager.authorizationStatus ==
+ kCLAuthorizationStatusAuthorizedWhenInUse);
+ headerState = kHeaderStateNotSentAuthorizationOmniboxDenied;
+ }
+ break;
+
+ case geolocation::kAuthorizationStateDenied:
+ switch (self.locationManager.authorizationStatus) {
+ case kCLAuthorizationStatusNotDetermined:
+ NOTREACHED();
+ // To keep the compiler quiet about headerState not being
+ // initialized in this switch case.
+ headerState = kHeaderStateNotSentAuthorizationChromeDenied;
+ break;
+ case kCLAuthorizationStatusRestricted:
+ case kCLAuthorizationStatusDenied:
+ headerState = kHeaderStateNotSentAuthorizationChromeDenied;
+ break;
+ case kCLAuthorizationStatusAuthorizedAlways:
+ case kCLAuthorizationStatusAuthorizedWhenInUse:
+ headerState = kHeaderStateNotSentAuthorizationOmniboxDenied;
+ break;
+ }
+ break;
+
+ case geolocation::kAuthorizationStateAuthorized: {
+ DCHECK(self.enabled);
+ CLLocation* currentLocation = [self.locationManager currentLocation];
+ if (!currentLocation) {
+ headerState = kHeaderStateNotSentLocationNotAvailable;
+ } else if (![currentLocation cr_isFreshEnough]) {
+ headerState = kHeaderStateNotSentLocationStale;
+ } else {
+ NSDictionary* locationHTTPHeaders =
+ @{ @"X-Geo" : [currentLocation cr_xGeoString] };
+ item->AddHttpRequestHeaders(locationHTTPHeaders);
+ headerState = kHeaderStateSent;
+
+ NSTimeInterval acquisitionInterval =
+ currentLocation.cr_acquisitionInterval;
+ base::TimeDelta acquisitionTime = base::TimeDelta::FromMilliseconds(
+ acquisitionInterval * base::Time::kMillisecondsPerSecond);
+ UMA_HISTOGRAM_TIMES(kOmniboxQueryGeolocationAcquisitionTimeHistogram,
+ acquisitionTime);
+
+ double horizontalAccuracy = currentLocation.horizontalAccuracy;
+ UMA_HISTOGRAM_COUNTS_10000(
+ kOmniboxQueryGeolocationHorizontalAccuracyHistogram,
+ horizontalAccuracy);
+ }
+ break;
+ }
+ }
+ }
+
+ [self recordHeaderState:headerState];
+ return headerState == kHeaderStateSent;
+}
+
+- (void)finishPageLoadForTab:(Tab*)tab loadSuccess:(BOOL)loadSuccess {
+ if (tab.isPrerenderTab || !loadSuccess || !tab.browserState ||
+ tab.browserState->IsOffTheRecord()) {
+ return;
+ }
+
+ DCHECK(tab.webState->GetNavigationManager());
+ web::NavigationItem* item =
+ tab.webState->GetNavigationManager()->GetVisibleItem();
+ if (![self URLIsAuthorizationPromptingURL:item->GetURL()] ||
+ !self.locationManager.locationServicesEnabled) {
+ return;
+ }
+
+ switch (self.locationManager.authorizationStatus) {
+ case kCLAuthorizationStatusNotDetermined:
+ // Prompt the user with the iOS system location authorization alert.
+ //
+ // Set |systemPrompt_|, so that
+ // locationManagerDidChangeAuthorizationStatus: will know that any
+ // CLAuthorizationStatus changes are coming from this specific prompt.
+ systemPrompt_ = YES;
+ self.localState.authorizationState =
+ geolocation::kAuthorizationStateNotDeterminedSystemPrompt;
+ [self startUpdatingLocation];
+
+ // Save this tab in case we're able to transition to
+ // kAuthorizationStateAuthorized.
+ weakTabToReload_.reset(tab);
+ break;
+
+ case kCLAuthorizationStatusRestricted:
+ case kCLAuthorizationStatusDenied:
+ break;
+
+ case kCLAuthorizationStatusAuthorizedAlways:
+ case kCLAuthorizationStatusAuthorizedWhenInUse:
+ // We might be in state kAuthorizationStateNotDeterminedSystemPrompt here
+ // if we presented the iOS system location alert when
+ // [CLLocationManager authorizationStatus] was
+ // kCLAuthorizationStatusNotDetermined but the user managed to authorize
+ // the app through some other flow; this might happen if the user
+ // backgrounded the app or the app crashed. If so, then reset the state.
+ if (self.localState.authorizationState ==
+ geolocation::kAuthorizationStateNotDeterminedSystemPrompt) {
+ self.localState.authorizationState =
+ geolocation::kAuthorizationStateNotDeterminedWaiting;
+ }
+ // If the user has authorized the app to use location but not yet
+ // explicitly authorized or denied using geolocation for Omnibox queries,
+ // then present an alert.
+ if (self.localState.authorizationState ==
+ geolocation::kAuthorizationStateNotDeterminedWaiting &&
+ [self shouldShowAuthorizationAlert]) {
+ [self showAuthorizationAlertForTab:tab];
+ }
+ break;
+ }
+}
+
+#pragma mark - Private
+
+- (BOOL)enabled {
+ return self.locationManager.locationServicesEnabled &&
+ self.localState.authorizationState ==
+ geolocation::kAuthorizationStateAuthorized;
+}
+
+- (OmniboxGeolocationLocalState*)localState {
+ if (!localState_) {
+ localState_.reset([[OmniboxGeolocationLocalState alloc]
+ initWithLocationManager:self.locationManager]);
+ }
+ return localState_;
+}
+
+- (LocationManager*)locationManager {
+ if (!locationManager_) {
+ locationManager_.reset([[LocationManager alloc] init]);
+ [locationManager_ setDelegate:self];
+ }
+ return locationManager_;
+}
+
+- (BOOL)URLIsEligibleQueryURL:(const GURL&)url
+ transition:(ui::PageTransition)transition {
+ return [self URLIsQueryURL:url transition:transition] &&
+ [[OmniboxGeolocationConfig sharedInstance] URLHasEligibleDomain:url];
+}
+
+- (BOOL)URLIsQueryURL:(const GURL&)url
+ transition:(ui::PageTransition)transition {
+ if (google_util::IsGoogleSearchUrl(url) &&
+ (transition & ui::PAGE_TRANSITION_FROM_ADDRESS_BAR) != 0) {
+ ui::PageTransition coreTransition = static_cast<ui::PageTransition>(
+ transition & ui::PAGE_TRANSITION_CORE_MASK);
+ if (PageTransitionCoreTypeIs(coreTransition,
+ ui::PAGE_TRANSITION_GENERATED) ||
+ PageTransitionCoreTypeIs(coreTransition, ui::PAGE_TRANSITION_RELOAD)) {
+ return YES;
+ }
+ }
+ return NO;
+}
+
+- (BOOL)URLIsAuthorizationPromptingURL:(const GURL&)url {
+ // Per PRD: "Show a modal dialog upon reaching google.com or a search results
+ // page..." However, we only want to do this for domains where we will send
+ // location.
+ return (google_util::IsGoogleHomePageUrl(url) ||
+ google_util::IsGoogleSearchUrl(url)) &&
+ [[OmniboxGeolocationConfig sharedInstance] URLHasEligibleDomain:url];
+}
+
+- (void)startUpdatingLocation {
+ // Note that GeolocationUpdater will stop itself automatically after 5
+ // seconds.
+ [self.locationManager startUpdatingLocation];
+}
+
+- (void)stopUpdatingLocation {
+ // Note that we don't need to initialize |locationManager_| here. If it's
+ // nil, then it's not running.
+ [locationManager_ stopUpdatingLocation];
+}
+
+- (void)addLocationAndReloadTab:(Tab*)tab {
+ if (self.enabled && [tab navigationManager]) {
+ // Make sure that GeolocationUpdater is running the first time we request
+ // the current location.
+ //
+ // If GeolocationUpdater is not running, then it returns nil for the
+ // current location. That's normally okay, because we cache the most recent
+ // location in LocationManager. However, we arrive here when the user first
+ // authorizes us to use location, so we may not have ever started
+ // GeolocationUpdater.
+ [self startUpdatingLocation];
+
+ web::NavigationItem* item =
+ tab.webState->GetNavigationManager()->GetVisibleItem();
+ if ([self addLocationToNavigationItem:item browserState:tab.browserState]) {
+ [tab reload];
+ }
+ }
+}
+
+- (BOOL)shouldShowAuthorizationAlert {
+ base::Version previousVersion(self.localState.lastAuthorizationAlertVersion);
+ if (!previousVersion.IsValid())
+ return YES;
+
+ base::Version currentVersion(version_info::GetVersionNumber());
+ DCHECK(currentVersion.IsValid());
+ return currentVersion.components()[0] != previousVersion.components()[0];
+}
+
+- (void)showAuthorizationAlertForTab:(Tab*)tab {
+ // Save this tab in case we're able to transition to
+ // kAuthorizationStateAuthorized.
+ weakTabToReload_.reset(tab);
+
+ authorizationAlert_.reset(
+ [[OmniboxGeolocationAuthorizationAlert alloc] initWithDelegate:self]);
+ [authorizationAlert_ showAuthorizationAlert];
+
+ self.localState.lastAuthorizationAlertVersion =
+ version_info::GetVersionNumber();
+}
+
+- (void)recordHeaderState:(HeaderState)headerState {
+ UMA_HISTOGRAM_ENUMERATION(kGeolocationHeaderSentOrNotHistogram, headerState,
+ kHeaderStateCount);
+}
+
+- (void)recordAuthorizationAction:(AuthorizationAction)authorizationAction {
+ if (newUser_) {
+ newUser_ = NO;
+
+ UMA_HISTOGRAM_ENUMERATION(kGeolocationAuthorizationActionNewUser,
+ authorizationAction, kAuthorizationActionCount);
+ } else {
+ UMA_HISTOGRAM_ENUMERATION(kGeolocationAuthorizationActionExistingUser,
+ authorizationAction, kAuthorizationActionCount);
+ }
+}
+
+#pragma mark - LocationManagerDelegate
+
+- (void)locationManagerDidChangeAuthorizationStatus:
+ (LocationManager*)locationManager {
+ if (systemPrompt_) {
+ switch (self.locationManager.authorizationStatus) {
+ case kCLAuthorizationStatusNotDetermined:
+ // We may get a spurious notification about a transition to
+ // |kCLAuthorizationStatusNotDetermined| when we first start location
+ // services. Ignore it and don't reset |systemPrompt_| until we get a
+ // real change.
+ break;
+
+ case kCLAuthorizationStatusRestricted:
+ case kCLAuthorizationStatusDenied:
+ self.localState.authorizationState =
+ geolocation::kAuthorizationStateDenied;
+ systemPrompt_ = NO;
+
+ [self recordAuthorizationAction:kAuthorizationActionPermanentlyDenied];
+ break;
+
+ case kCLAuthorizationStatusAuthorizedAlways:
+ case kCLAuthorizationStatusAuthorizedWhenInUse:
+ self.localState.authorizationState =
+ geolocation::kAuthorizationStateAuthorized;
+ systemPrompt_ = NO;
+
+ base::scoped_nsobject<Tab> tab([weakTabToReload_ retain]);
+ [self addLocationAndReloadTab:tab];
+ weakTabToReload_.reset();
+
+ [self recordAuthorizationAction:kAuthorizationActionAuthorized];
+ break;
+ }
+ }
+}
+
+#pragma mark - OmniboxGeolocationAuthorizationAlertDelegate
+
+- (void)authorizationAlertDidAuthorize:
+ (OmniboxGeolocationAuthorizationAlert*)authorizationAlert {
+ self.localState.authorizationState =
+ geolocation::kAuthorizationStateAuthorized;
+
+ base::scoped_nsobject<Tab> tab([weakTabToReload_ retain]);
+ [self addLocationAndReloadTab:tab];
+
+ // Just resetting |authorizationAlert_| leads to a user-after-free crash
+ // presumably due to a UIKit bug. Making authorizationAlert_ autorelease
+ // will keep it alive long enough to avoid the crash. See crbug.com/381235
+ authorizationAlert_.autorelease();
+ weakTabToReload_.reset();
+
+ [self recordAuthorizationAction:kAuthorizationActionAuthorized];
+}
+
+- (void)authorizationAlertDidCancel:
+ (OmniboxGeolocationAuthorizationAlert*)authorizationAlert {
+ // Leave authorization state as undetermined (not kAuthorizationStateDenied).
+ // We won't use location, but we'll still be able to prompt at the next
+ // application update.
+
+ // Just resetting |authorizationAlert_| leads to a user-after-free crash
+ // presumably due to a UIKit bug. Making authorizationAlert_ autorelease
+ // will keep it alive long enough to avoid the crash. See crbug.com/381235
+ authorizationAlert_.autorelease();
+ weakTabToReload_.reset();
+
+ [self recordAuthorizationAction:kAuthorizationActionDenied];
+}
+
+#pragma mark - OmniboxGeolocationController+Testing
+
+- (void)setLocalState:(OmniboxGeolocationLocalState*)localState {
+ localState_.reset([localState retain]);
+}
+
+- (void)setLocationManager:(LocationManager*)locationManager {
+ locationManager_.reset([locationManager retain]);
+}
+
+@end

Powered by Google App Engine
This is Rietveld 408576698