Chromium Code Reviews| Index: ios/chrome/browser/physical_web/physical_web_initial_state_recorder.mm |
| diff --git a/ios/chrome/browser/physical_web/physical_web_initial_state_recorder.mm b/ios/chrome/browser/physical_web/physical_web_initial_state_recorder.mm |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..29b23cf3987cc292ebf9f7539bbc1a0035c771fd |
| --- /dev/null |
| +++ b/ios/chrome/browser/physical_web/physical_web_initial_state_recorder.mm |
| @@ -0,0 +1,150 @@ |
| +// 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/physical_web/physical_web_initial_state_recorder.h" |
| + |
| +#import <CoreBluetooth/CoreBluetooth.h> |
| +#import <CoreLocation/CoreLocation.h> |
| + |
| +#include "base/mac/scoped_nsobject.h" |
| +#include "base/metrics/histogram.h" |
| +#include "components/prefs/pref_service.h" |
| +#include "ios/chrome/browser/physical_web/physical_web_constants.h" |
| +#include "ios/chrome/browser/pref_names.h" |
| + |
| +namespace { |
| + |
| +// Initial state of settings relevant to the Physical Web feature. These are |
| +// ordered so that bits 2:0 encode the Bluetooth enabled state, the Location |
| +// Services enabled state, and whether Chrome has been granted the Location app |
| +// permission. Bits 4:3 encode the Physical Web preference tristate. |
|
Olivier
2016/11/10 18:08:08
Can you add that this enum is used in histogram an
mattreynolds
2016/11/11 02:26:10
Done.
|
| +enum PhysicalWebInitialStateIosChrome { |
| + OPTOUT_BTOFF_LOCOFF_UNAUTH, |
| + OPTOUT_BTOFF_LOCOFF_AUTH, |
| + OPTOUT_BTOFF_LOCON_UNAUTH, |
| + OPTOUT_BTOFF_LOCON_AUTH, |
| + OPTOUT_BTON_LOCOFF_UNAUTH, |
| + OPTOUT_BTON_LOCOFF_AUTH, |
| + OPTOUT_BTON_LOCON_UNAUTH, |
| + OPTOUT_BTON_LOCON_AUTH, |
| + OPTIN_BTOFF_LOCOFF_UNAUTH, |
| + OPTIN_BTOFF_LOCOFF_AUTH, |
| + OPTIN_BTOFF_LOCON_UNAUTH, |
| + OPTIN_BTOFF_LOCON_AUTH, |
| + OPTIN_BTON_LOCOFF_UNAUTH, |
| + OPTIN_BTON_LOCOFF_AUTH, |
| + OPTIN_BTON_LOCON_UNAUTH, |
| + OPTIN_BTON_LOCON_AUTH, |
| + ONBOARDING_BTOFF_LOCOFF_UNAUTH, |
| + ONBOARDING_BTOFF_LOCOFF_AUTH, |
| + ONBOARDING_BTOFF_LOCON_UNAUTH, |
| + ONBOARDING_BTOFF_LOCON_AUTH, |
| + ONBOARDING_BTON_LOCOFF_UNAUTH, |
| + ONBOARDING_BTON_LOCOFF_AUTH, |
| + ONBOARDING_BTON_LOCON_UNAUTH, |
| + ONBOARDING_BTON_LOCON_AUTH, |
| + PHYSICAL_WEB_INITIAL_STATE_COUNT, |
| + |
| + // Helper flag values |
| + LOCATION_AUTHORIZED_FLAG = 1 << 0, |
| + LOCATION_SERVICES_FLAG = 1 << 1, |
| + BLUETOOTH_FLAG = 1 << 2, |
| + OPTIN_FLAG = 1 << 3, |
| + ONBOARDING_FLAG = 1 << 4, |
| +}; |
| +} // namespace |
| + |
| +@implementation PhysicalWebInitialStateRecorder { |
| + PrefService* prefService_; |
| + BOOL recordedState_; |
| + base::scoped_nsobject<CBCentralManager> centralManager_; |
| +} |
| + |
| +- (instancetype)initWithPrefService:(PrefService*)prefService { |
| + self = [super init]; |
| + if (self) { |
| + prefService_ = prefService; |
|
rohitrao (ping after 24h)
2016/11/10 13:01:44
Instead of caching the prefService, could you extr
mattreynolds
2016/11/11 02:26:10
Done.
|
| + } |
| + return self; |
| +} |
| + |
| +- (instancetype)init { |
| + NOTREACHED(); |
| + return nil; |
| +} |
| + |
| +- (void)dealloc { |
| + [centralManager_ setDelegate:nil]; |
| + centralManager_.reset(); |
| + [super dealloc]; |
| +} |
| + |
| +- (void)centralManagerDidUpdateState:(CBCentralManager*)central { |
| + // Remove ourselves as a delegate so we won't get notified for later changes |
| + // to the Bluetooth enabled state. |
| + [centralManager_ setDelegate:nil]; |
| + |
| + int preferenceState = prefService_->GetInteger(prefs::kIosPhysicalWebEnabled); |
| + |
| + BOOL bluetoothEnabled = [centralManager_ state] == CBManagerStatePoweredOn; |
| + |
| + BOOL locationServicesEnabled = [CLLocationManager locationServicesEnabled]; |
| + |
| + CLAuthorizationStatus authStatus = [CLLocationManager authorizationStatus]; |
| + BOOL locationAuthorized = |
| + authStatus == kCLAuthorizationStatusAuthorizedWhenInUse || |
| + authStatus == kCLAuthorizationStatusAuthorizedAlways; |
| + |
| + [self recordStateWithPreferenceState:preferenceState |
| + bluetoothEnabled:bluetoothEnabled |
| + locationServicesEnabled:locationServicesEnabled |
| + locationAuthorized:locationAuthorized]; |
| +} |
| + |
| +- (void)collectAndRecordState { |
| + if (recordedState_) { |
| + return; |
| + } |
| + recordedState_ = YES; |
| + |
| + // The Bluetooth enabled state must be checked asynchronously. When the state |
| + // is ready, it will call our centralManagerDidUpdateState method. |
| + centralManager_.reset([[CBCentralManager alloc] |
| + initWithDelegate:self |
| + queue:dispatch_get_main_queue() |
| + options:@{ |
| + // By default, creating a CBCentralManager object with |
| + // Bluetooth disabled will prompt the user to enable Bluetooth. |
| + // Passing ShowPowerAlert=NO disables the prompt so we can |
| + // check the Bluetooth enabled state silently. |
| + CBCentralManagerOptionShowPowerAlertKey : @NO |
| + }]); |
| +} |
| + |
| +- (void)recordStateWithPreferenceState:(int)preferenceState |
| + bluetoothEnabled:(BOOL)bluetoothEnabled |
| + locationServicesEnabled:(BOOL)locationServicesEnabled |
| + locationAuthorized:(BOOL)locationAuthorized { |
| + int state = 0; |
| + if (preferenceState == physical_web::kPhysicalWebOn) { |
| + state |= OPTIN_FLAG; |
| + } else if (preferenceState == physical_web::kPhysicalWebOnboarding) { |
| + state |= ONBOARDING_FLAG; |
| + } |
| + if (locationServicesEnabled) { |
| + state |= LOCATION_SERVICES_FLAG; |
| + } |
| + if (locationAuthorized) { |
| + state |= LOCATION_AUTHORIZED_FLAG; |
| + } |
| + if (bluetoothEnabled) { |
| + state |= BLUETOOTH_FLAG; |
| + } |
| + |
| + DCHECK(state < PHYSICAL_WEB_INITIAL_STATE_COUNT); |
| + UMA_HISTOGRAM_ENUMERATION("PhysicalWeb.InitialState.IosChrome", state, |
| + PHYSICAL_WEB_INITIAL_STATE_COUNT); |
| +} |
| + |
| +@end |