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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import "ios/chrome/browser/geolocation/omnibox_geolocation_controller.h"
6
7 #import <CoreLocation/CoreLocation.h>
8 #import <UIKit/UIKit.h>
9
10 #include <string>
11
12 #import "base/ios/weak_nsobject.h"
13 #include "base/logging.h"
14 #include "base/mac/scoped_nsobject.h"
15 #include "base/metrics/histogram.h"
16 #include "base/version.h"
17 #include "components/google/core/browser/google_util.h"
18 #include "components/version_info/version_info.h"
19 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
20 #import "ios/chrome/browser/geolocation/CLLocation+OmniboxGeolocation.h"
21 #import "ios/chrome/browser/geolocation/CLLocation+XGeoHeader.h"
22 #import "ios/chrome/browser/geolocation/location_manager.h"
23 #import "ios/chrome/browser/geolocation/omnibox_geolocation_authorization_alert. h"
24 #import "ios/chrome/browser/geolocation/omnibox_geolocation_config.h"
25 #import "ios/chrome/browser/geolocation/omnibox_geolocation_controller+Testing.h "
26 #import "ios/chrome/browser/geolocation/omnibox_geolocation_local_state.h"
27 #import "ios/chrome/browser/tabs/tab.h"
28 #include "ios/web/public/navigation_item.h"
29 #import "ios/web/public/navigation_manager.h"
30 #include "url/gurl.h"
31
32 namespace {
33
34 // Values for the histogram that records whether we sent the X-Geo header for
35 // an Omnibox query or why we did not do so. These match the definition of
36 // GeolocationHeaderSentOrNot in Chromium
37 // src-internal/tools/histograms/histograms.xml.
38 typedef enum {
39 // The user disabled location for Google.com (not used by Chrome iOS).
40 kHeaderStateNotSentAuthorizationGoogleDenied = 0,
41 // The user has not yet determined Chrome's access to the current device
42 // location or Chrome's use of geolocation for Omnibox queries.
43 kHeaderStateNotSentAuthorizationNotDetermined,
44 // The current device location is not available.
45 kHeaderStateNotSentLocationNotAvailable,
46 // The current device location is stale.
47 kHeaderStateNotSentLocationStale,
48 // The X-Geo header was sent.
49 kHeaderStateSent,
50 // The user denied Chrome from accessing the current device location.
51 kHeaderStateNotSentAuthorizationChromeDenied,
52 // The user denied Chrome from using geolocation for Omnibox queries.
53 kHeaderStateNotSentAuthorizationOmniboxDenied,
54 // The user's Google search domain is not whitelisted.
55 kHeaderStateNotSentDomainNotWhitelisted,
56 // The number of possible of HeaderState values to report.
57 kHeaderStateCount,
58 } HeaderState;
59
60 // Values for the histograms that record the user's action when prompted to
61 // authorize the use of location by Chrome. These match the definition of
62 // GeolocationAuthorizationAction in Chromium
63 // src-internal/tools/histograms/histograms.xml.
64 typedef enum {
65 // The user authorized use of location.
66 kAuthorizationActionAuthorized = 0,
67 // The user permanently denied use of location (Don't Allow).
68 kAuthorizationActionPermanentlyDenied,
69 // The user denied use of location at this prompt (Not Now).
70 kAuthorizationActionDenied,
71 // The number of possible AuthorizationAction values to report.
72 kAuthorizationActionCount,
73 } AuthorizationAction;
74
75 // Name of the histogram recording HeaderState.
76 const char* const kGeolocationHeaderSentOrNotHistogram =
77 "Geolocation.HeaderSentOrNot";
78
79 // Name of the histogram recording location acquisition time.
80 const char* const kOmniboxQueryGeolocationAcquisitionTimeHistogram =
81 "Omnibox.QueryGeolocationAcquisitionTime";
82
83 // Name of the histogram recording estimated location accuracy.
84 const char* const kOmniboxQueryGeolocationHorizontalAccuracyHistogram =
85 "Omnibox.QueryGeolocationHorizontalAccuracy";
86
87 // Name of the histogram recording AuthorizationAction for an existing user.
88 const char* const kGeolocationAuthorizationActionExistingUser =
89 "Geolocation.AuthorizationActionExistingUser";
90
91 // Name of the histogram recording AuthorizationAction for a new user.
92 const char* const kGeolocationAuthorizationActionNewUser =
93 "Geolocation.AuthorizationActionNewUser";
94
95 } // anonymous namespace
96
97 @interface OmniboxGeolocationController ()<
98 LocationManagerDelegate,
99 OmniboxGeolocationAuthorizationAlertDelegate> {
100 base::scoped_nsobject<OmniboxGeolocationLocalState> localState_;
101 base::scoped_nsobject<LocationManager> locationManager_;
102 base::scoped_nsobject<OmniboxGeolocationAuthorizationAlert>
103 authorizationAlert_;
104 base::WeakNSObject<Tab> weakTabToReload_;
105
106 // Records whether we have deliberately presented the system prompt, so that
107 // we can record the user's action in
108 // locationManagerDidChangeAuthorizationStatus:.
109 BOOL systemPrompt_;
110
111 // Records whether we are prompting for a new user, so that we can record the
112 // user's action to the right histogram (either
113 // kGeolocationAuthorizationActionExistingUser or
114 // kGeolocationAuthorizationActionNewUser).
115 BOOL newUser_;
116 }
117
118 // Boolean value indicating whether geolocation is enabled for Omnibox queries.
119 @property(nonatomic, readonly) BOOL enabled;
120
121 // Convenience property lazily initializes |localState_|.
122 @property(nonatomic, readonly) OmniboxGeolocationLocalState* localState;
123
124 // Convenience property lazily initializes |locationManager_|.
125 @property(nonatomic, readonly) LocationManager* locationManager;
126
127 // Returns YES if and only if |url| and |transition| specify an Omnibox query
128 // that is eligible for geolocation.
129 - (BOOL)URLIsEligibleQueryURL:(const GURL&)url
130 transition:(ui::PageTransition)transition;
131
132 // Returns YES if and only if |url| and |transition| specify an Omnibox query.
133 //
134 // Note: URLIsQueryURL:transition: is more liberal than
135 // URLIsEligibleQueryURL:transition:. Use URLIsEligibleQueryURL:transition: and
136 // not URLIsQueryURL:transition: to test Omnibox query URLs with respect to
137 // sending location to Google.
138 - (BOOL)URLIsQueryURL:(const GURL&)url
139 transition:(ui::PageTransition)transition;
140
141 // Returns YES if and only if |url| specifies a page for which we will prompt
142 // the user to authorize the use of geolocation for Omnibox queries.
143 - (BOOL)URLIsAuthorizationPromptingURL:(const GURL&)url;
144
145 // Starts updating device location if needed.
146 - (void)startUpdatingLocation;
147 // Stops updating device location.
148 - (void)stopUpdatingLocation;
149 // If the current location is not stale, then adds the current location to the
150 // current session entry for |tab| and reloads |tab|. If the current location
151 // is stale, then does nothing.
152 - (void)addLocationAndReloadTab:(Tab*)tab;
153 // Returns YES if and only if we should show an alert that prompts the user to
154 // authorize using geolocation for Omnibox queries.
155 - (BOOL)shouldShowAuthorizationAlert;
156 // Shows an alert that prompts the user to authorize using geolocation for
157 // Omnibox queries. Sets |weakTabToReload_| from |tab|, so that we can reload
158 // |tab| if the user authorizes using geolocation.
159 - (void)showAuthorizationAlertForTab:(Tab*)tab;
160 // Records |headerState| for the |kGeolocationHeaderSentOrNotHistogram|
161 // histogram.
162 - (void)recordHeaderState:(HeaderState)headerState;
163 // Records |authorizationAction|.
164 - (void)recordAuthorizationAction:(AuthorizationAction)authorizationAction;
165
166 @end
167
168 @implementation OmniboxGeolocationController
169
170 + (OmniboxGeolocationController*)sharedInstance {
171 static OmniboxGeolocationController* instance =
172 [[OmniboxGeolocationController alloc] init];
173 return instance;
174 }
175
176 - (void)triggerSystemPromptForNewUser:(BOOL)newUser {
177 if (self.locationManager.locationServicesEnabled &&
178 self.locationManager.authorizationStatus ==
179 kCLAuthorizationStatusNotDetermined) {
180 // Set |systemPrompt_|, so that
181 // locationManagerDidChangeAuthorizationStatus: will know to handle any
182 // CLAuthorizationStatus changes.
183 //
184 // TODO(crbug.com/661996): Remove the now useless
185 // kAuthorizationStateNotDeterminedSystemPrompt from
186 // omnibox_geolocation_local_state.h.
187 systemPrompt_ = YES;
188 self.localState.authorizationState =
189 geolocation::kAuthorizationStateNotDeterminedSystemPrompt;
190
191 // Turn on location updates, so that iOS will prompt the user.
192 [self startUpdatingLocation];
193
194 weakTabToReload_.reset();
195 newUser_ = newUser;
196 }
197 }
198
199 - (void)locationBarDidBecomeFirstResponder:
200 (ios::ChromeBrowserState*)browserState {
201 if (self.enabled && browserState && !browserState->IsOffTheRecord()) {
202 [self startUpdatingLocation];
203 }
204 }
205
206 - (void)locationBarDidResignFirstResponder:
207 (ios::ChromeBrowserState*)browserState {
208 // It's always okay to stop updating location.
209 [self stopUpdatingLocation];
210 }
211
212 - (void)locationBarDidSubmitURL:(const GURL&)url
213 transition:(ui::PageTransition)transition
214 browserState:(ios::ChromeBrowserState*)browserState {
215 // Stop updating the location when the user submits a query from the Omnibox.
216 // We're not interested in further updates until the next time the user puts
217 // the focus on the Omnbox.
218 [self stopUpdatingLocation];
219 }
220
221 - (BOOL)addLocationToNavigationItem:(web::NavigationItem*)item
222 browserState:(ios::ChromeBrowserState*)browserState {
223 // If this is incognito mode or is not an Omnibox query, then do nothing.
224 //
225 // Check the URL with URLIsQueryURL:transition: here and not
226 // URLIsEligibleQueryURL:transition:, because we want to log the cases where
227 // we did not send the X-Geo header due to the Google search domain not being
228 // whitelisted.
229 DCHECK(item);
230 const GURL& url = item->GetURL();
231 if (!browserState || browserState->IsOffTheRecord() ||
232 ![self URLIsQueryURL:url transition:item->GetTransitionType()]) {
233 return NO;
234 }
235
236 if (![[OmniboxGeolocationConfig sharedInstance] URLHasEligibleDomain:url]) {
237 [self recordHeaderState:kHeaderStateNotSentDomainNotWhitelisted];
238 return NO;
239 }
240
241 // At this point, we should only have Omnibox query URLs that are eligible
242 // for geolocation.
243 DCHECK([self URLIsEligibleQueryURL:url transition:item->GetTransitionType()]);
244
245 HeaderState headerState;
246 if (!self.locationManager.locationServicesEnabled) {
247 headerState = kHeaderStateNotSentAuthorizationChromeDenied;
248 } else {
249 switch (self.localState.authorizationState) {
250 case geolocation::kAuthorizationStateNotDeterminedWaiting:
251 case geolocation::kAuthorizationStateNotDeterminedSystemPrompt:
252 if (self.locationManager.authorizationStatus ==
253 kCLAuthorizationStatusNotDetermined ||
254 [self shouldShowAuthorizationAlert]) {
255 headerState = kHeaderStateNotSentAuthorizationNotDetermined;
256 } else {
257 DCHECK(self.locationManager.authorizationStatus ==
258 kCLAuthorizationStatusAuthorizedAlways ||
259 self.locationManager.authorizationStatus ==
260 kCLAuthorizationStatusAuthorizedWhenInUse);
261 headerState = kHeaderStateNotSentAuthorizationOmniboxDenied;
262 }
263 break;
264
265 case geolocation::kAuthorizationStateDenied:
266 switch (self.locationManager.authorizationStatus) {
267 case kCLAuthorizationStatusNotDetermined:
268 NOTREACHED();
269 // To keep the compiler quiet about headerState not being
270 // initialized in this switch case.
271 headerState = kHeaderStateNotSentAuthorizationChromeDenied;
272 break;
273 case kCLAuthorizationStatusRestricted:
274 case kCLAuthorizationStatusDenied:
275 headerState = kHeaderStateNotSentAuthorizationChromeDenied;
276 break;
277 case kCLAuthorizationStatusAuthorizedAlways:
278 case kCLAuthorizationStatusAuthorizedWhenInUse:
279 headerState = kHeaderStateNotSentAuthorizationOmniboxDenied;
280 break;
281 }
282 break;
283
284 case geolocation::kAuthorizationStateAuthorized: {
285 DCHECK(self.enabled);
286 CLLocation* currentLocation = [self.locationManager currentLocation];
287 if (!currentLocation) {
288 headerState = kHeaderStateNotSentLocationNotAvailable;
289 } else if (![currentLocation cr_isFreshEnough]) {
290 headerState = kHeaderStateNotSentLocationStale;
291 } else {
292 NSDictionary* locationHTTPHeaders =
293 @{ @"X-Geo" : [currentLocation cr_xGeoString] };
294 item->AddHttpRequestHeaders(locationHTTPHeaders);
295 headerState = kHeaderStateSent;
296
297 NSTimeInterval acquisitionInterval =
298 currentLocation.cr_acquisitionInterval;
299 base::TimeDelta acquisitionTime = base::TimeDelta::FromMilliseconds(
300 acquisitionInterval * base::Time::kMillisecondsPerSecond);
301 UMA_HISTOGRAM_TIMES(kOmniboxQueryGeolocationAcquisitionTimeHistogram,
302 acquisitionTime);
303
304 double horizontalAccuracy = currentLocation.horizontalAccuracy;
305 UMA_HISTOGRAM_COUNTS_10000(
306 kOmniboxQueryGeolocationHorizontalAccuracyHistogram,
307 horizontalAccuracy);
308 }
309 break;
310 }
311 }
312 }
313
314 [self recordHeaderState:headerState];
315 return headerState == kHeaderStateSent;
316 }
317
318 - (void)finishPageLoadForTab:(Tab*)tab loadSuccess:(BOOL)loadSuccess {
319 if (tab.isPrerenderTab || !loadSuccess || !tab.browserState ||
320 tab.browserState->IsOffTheRecord()) {
321 return;
322 }
323
324 DCHECK(tab.webState->GetNavigationManager());
325 web::NavigationItem* item =
326 tab.webState->GetNavigationManager()->GetVisibleItem();
327 if (![self URLIsAuthorizationPromptingURL:item->GetURL()] ||
328 !self.locationManager.locationServicesEnabled) {
329 return;
330 }
331
332 switch (self.locationManager.authorizationStatus) {
333 case kCLAuthorizationStatusNotDetermined:
334 // Prompt the user with the iOS system location authorization alert.
335 //
336 // Set |systemPrompt_|, so that
337 // locationManagerDidChangeAuthorizationStatus: will know that any
338 // CLAuthorizationStatus changes are coming from this specific prompt.
339 systemPrompt_ = YES;
340 self.localState.authorizationState =
341 geolocation::kAuthorizationStateNotDeterminedSystemPrompt;
342 [self startUpdatingLocation];
343
344 // Save this tab in case we're able to transition to
345 // kAuthorizationStateAuthorized.
346 weakTabToReload_.reset(tab);
347 break;
348
349 case kCLAuthorizationStatusRestricted:
350 case kCLAuthorizationStatusDenied:
351 break;
352
353 case kCLAuthorizationStatusAuthorizedAlways:
354 case kCLAuthorizationStatusAuthorizedWhenInUse:
355 // We might be in state kAuthorizationStateNotDeterminedSystemPrompt here
356 // if we presented the iOS system location alert when
357 // [CLLocationManager authorizationStatus] was
358 // kCLAuthorizationStatusNotDetermined but the user managed to authorize
359 // the app through some other flow; this might happen if the user
360 // backgrounded the app or the app crashed. If so, then reset the state.
361 if (self.localState.authorizationState ==
362 geolocation::kAuthorizationStateNotDeterminedSystemPrompt) {
363 self.localState.authorizationState =
364 geolocation::kAuthorizationStateNotDeterminedWaiting;
365 }
366 // If the user has authorized the app to use location but not yet
367 // explicitly authorized or denied using geolocation for Omnibox queries,
368 // then present an alert.
369 if (self.localState.authorizationState ==
370 geolocation::kAuthorizationStateNotDeterminedWaiting &&
371 [self shouldShowAuthorizationAlert]) {
372 [self showAuthorizationAlertForTab:tab];
373 }
374 break;
375 }
376 }
377
378 #pragma mark - Private
379
380 - (BOOL)enabled {
381 return self.locationManager.locationServicesEnabled &&
382 self.localState.authorizationState ==
383 geolocation::kAuthorizationStateAuthorized;
384 }
385
386 - (OmniboxGeolocationLocalState*)localState {
387 if (!localState_) {
388 localState_.reset([[OmniboxGeolocationLocalState alloc]
389 initWithLocationManager:self.locationManager]);
390 }
391 return localState_;
392 }
393
394 - (LocationManager*)locationManager {
395 if (!locationManager_) {
396 locationManager_.reset([[LocationManager alloc] init]);
397 [locationManager_ setDelegate:self];
398 }
399 return locationManager_;
400 }
401
402 - (BOOL)URLIsEligibleQueryURL:(const GURL&)url
403 transition:(ui::PageTransition)transition {
404 return [self URLIsQueryURL:url transition:transition] &&
405 [[OmniboxGeolocationConfig sharedInstance] URLHasEligibleDomain:url];
406 }
407
408 - (BOOL)URLIsQueryURL:(const GURL&)url
409 transition:(ui::PageTransition)transition {
410 if (google_util::IsGoogleSearchUrl(url) &&
411 (transition & ui::PAGE_TRANSITION_FROM_ADDRESS_BAR) != 0) {
412 ui::PageTransition coreTransition = static_cast<ui::PageTransition>(
413 transition & ui::PAGE_TRANSITION_CORE_MASK);
414 if (PageTransitionCoreTypeIs(coreTransition,
415 ui::PAGE_TRANSITION_GENERATED) ||
416 PageTransitionCoreTypeIs(coreTransition, ui::PAGE_TRANSITION_RELOAD)) {
417 return YES;
418 }
419 }
420 return NO;
421 }
422
423 - (BOOL)URLIsAuthorizationPromptingURL:(const GURL&)url {
424 // Per PRD: "Show a modal dialog upon reaching google.com or a search results
425 // page..." However, we only want to do this for domains where we will send
426 // location.
427 return (google_util::IsGoogleHomePageUrl(url) ||
428 google_util::IsGoogleSearchUrl(url)) &&
429 [[OmniboxGeolocationConfig sharedInstance] URLHasEligibleDomain:url];
430 }
431
432 - (void)startUpdatingLocation {
433 // Note that GeolocationUpdater will stop itself automatically after 5
434 // seconds.
435 [self.locationManager startUpdatingLocation];
436 }
437
438 - (void)stopUpdatingLocation {
439 // Note that we don't need to initialize |locationManager_| here. If it's
440 // nil, then it's not running.
441 [locationManager_ stopUpdatingLocation];
442 }
443
444 - (void)addLocationAndReloadTab:(Tab*)tab {
445 if (self.enabled && [tab navigationManager]) {
446 // Make sure that GeolocationUpdater is running the first time we request
447 // the current location.
448 //
449 // If GeolocationUpdater is not running, then it returns nil for the
450 // current location. That's normally okay, because we cache the most recent
451 // location in LocationManager. However, we arrive here when the user first
452 // authorizes us to use location, so we may not have ever started
453 // GeolocationUpdater.
454 [self startUpdatingLocation];
455
456 web::NavigationItem* item =
457 tab.webState->GetNavigationManager()->GetVisibleItem();
458 if ([self addLocationToNavigationItem:item browserState:tab.browserState]) {
459 [tab reload];
460 }
461 }
462 }
463
464 - (BOOL)shouldShowAuthorizationAlert {
465 base::Version previousVersion(self.localState.lastAuthorizationAlertVersion);
466 if (!previousVersion.IsValid())
467 return YES;
468
469 base::Version currentVersion(version_info::GetVersionNumber());
470 DCHECK(currentVersion.IsValid());
471 return currentVersion.components()[0] != previousVersion.components()[0];
472 }
473
474 - (void)showAuthorizationAlertForTab:(Tab*)tab {
475 // Save this tab in case we're able to transition to
476 // kAuthorizationStateAuthorized.
477 weakTabToReload_.reset(tab);
478
479 authorizationAlert_.reset(
480 [[OmniboxGeolocationAuthorizationAlert alloc] initWithDelegate:self]);
481 [authorizationAlert_ showAuthorizationAlert];
482
483 self.localState.lastAuthorizationAlertVersion =
484 version_info::GetVersionNumber();
485 }
486
487 - (void)recordHeaderState:(HeaderState)headerState {
488 UMA_HISTOGRAM_ENUMERATION(kGeolocationHeaderSentOrNotHistogram, headerState,
489 kHeaderStateCount);
490 }
491
492 - (void)recordAuthorizationAction:(AuthorizationAction)authorizationAction {
493 if (newUser_) {
494 newUser_ = NO;
495
496 UMA_HISTOGRAM_ENUMERATION(kGeolocationAuthorizationActionNewUser,
497 authorizationAction, kAuthorizationActionCount);
498 } else {
499 UMA_HISTOGRAM_ENUMERATION(kGeolocationAuthorizationActionExistingUser,
500 authorizationAction, kAuthorizationActionCount);
501 }
502 }
503
504 #pragma mark - LocationManagerDelegate
505
506 - (void)locationManagerDidChangeAuthorizationStatus:
507 (LocationManager*)locationManager {
508 if (systemPrompt_) {
509 switch (self.locationManager.authorizationStatus) {
510 case kCLAuthorizationStatusNotDetermined:
511 // We may get a spurious notification about a transition to
512 // |kCLAuthorizationStatusNotDetermined| when we first start location
513 // services. Ignore it and don't reset |systemPrompt_| until we get a
514 // real change.
515 break;
516
517 case kCLAuthorizationStatusRestricted:
518 case kCLAuthorizationStatusDenied:
519 self.localState.authorizationState =
520 geolocation::kAuthorizationStateDenied;
521 systemPrompt_ = NO;
522
523 [self recordAuthorizationAction:kAuthorizationActionPermanentlyDenied];
524 break;
525
526 case kCLAuthorizationStatusAuthorizedAlways:
527 case kCLAuthorizationStatusAuthorizedWhenInUse:
528 self.localState.authorizationState =
529 geolocation::kAuthorizationStateAuthorized;
530 systemPrompt_ = NO;
531
532 base::scoped_nsobject<Tab> tab([weakTabToReload_ retain]);
533 [self addLocationAndReloadTab:tab];
534 weakTabToReload_.reset();
535
536 [self recordAuthorizationAction:kAuthorizationActionAuthorized];
537 break;
538 }
539 }
540 }
541
542 #pragma mark - OmniboxGeolocationAuthorizationAlertDelegate
543
544 - (void)authorizationAlertDidAuthorize:
545 (OmniboxGeolocationAuthorizationAlert*)authorizationAlert {
546 self.localState.authorizationState =
547 geolocation::kAuthorizationStateAuthorized;
548
549 base::scoped_nsobject<Tab> tab([weakTabToReload_ retain]);
550 [self addLocationAndReloadTab:tab];
551
552 // Just resetting |authorizationAlert_| leads to a user-after-free crash
553 // presumably due to a UIKit bug. Making authorizationAlert_ autorelease
554 // will keep it alive long enough to avoid the crash. See crbug.com/381235
555 authorizationAlert_.autorelease();
556 weakTabToReload_.reset();
557
558 [self recordAuthorizationAction:kAuthorizationActionAuthorized];
559 }
560
561 - (void)authorizationAlertDidCancel:
562 (OmniboxGeolocationAuthorizationAlert*)authorizationAlert {
563 // Leave authorization state as undetermined (not kAuthorizationStateDenied).
564 // We won't use location, but we'll still be able to prompt at the next
565 // application update.
566
567 // Just resetting |authorizationAlert_| leads to a user-after-free crash
568 // presumably due to a UIKit bug. Making authorizationAlert_ autorelease
569 // will keep it alive long enough to avoid the crash. See crbug.com/381235
570 authorizationAlert_.autorelease();
571 weakTabToReload_.reset();
572
573 [self recordAuthorizationAction:kAuthorizationActionDenied];
574 }
575
576 #pragma mark - OmniboxGeolocationController+Testing
577
578 - (void)setLocalState:(OmniboxGeolocationLocalState*)localState {
579 localState_.reset([localState retain]);
580 }
581
582 - (void)setLocationManager:(LocationManager*)locationManager {
583 locationManager_.reset([locationManager retain]);
584 }
585
586 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698