OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 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 #include "chromeos/pairing/fake_controller_pairing_flow.h" |
| 6 |
| 7 #include <map> |
| 8 |
| 9 #include "base/bind.h" |
| 10 #include "base/logging.h" |
| 11 #include "base/message_loop/message_loop.h" |
| 12 #include "base/rand_util.h" |
| 13 #include "base/strings/string_number_conversions.h" |
| 14 #include "base/strings/string_split.h" |
| 15 #include "base/strings/string_util.h" |
| 16 |
| 17 namespace chromeos { |
| 18 |
| 19 FakeControllerPairingFlow::FakeControllerPairingFlow(const std::string& config) |
| 20 : current_stage_(STAGE_NONE), |
| 21 should_fail_on_connecting_(false), |
| 22 connection_lost_begin_(STAGE_NONE), |
| 23 connection_lost_end_(STAGE_NONE), |
| 24 enrollment_should_fail_(false) { |
| 25 ApplyConfig(config); |
| 26 AddObserver(this); |
| 27 } |
| 28 |
| 29 FakeControllerPairingFlow::~FakeControllerPairingFlow() { |
| 30 RemoveObserver(this); |
| 31 } |
| 32 |
| 33 void FakeControllerPairingFlow::ApplyConfig(const std::string& config) { |
| 34 typedef std::vector<std::string> Tokens; |
| 35 |
| 36 base::StringPairs kv_pairs; |
| 37 CHECK(base::SplitStringIntoKeyValuePairs(config, ':', ',', &kv_pairs)) |
| 38 << "Wrong config format."; |
| 39 std::map<std::string, std::string> dict(kv_pairs.begin(), kv_pairs.end()); |
| 40 |
| 41 if (dict.count("async_duration")) { |
| 42 int ms = 0; |
| 43 CHECK(base::StringToInt(dict["async_duration"], &ms)) |
| 44 << "Wrong 'async_duration' format."; |
| 45 async_duration_ = base::TimeDelta::FromMilliseconds(ms); |
| 46 } else { |
| 47 async_duration_ = base::TimeDelta::FromMilliseconds(3000); |
| 48 } |
| 49 |
| 50 should_fail_on_connecting_ = |
| 51 dict.count("fail_connecting") && (dict["fail_connecting"] == "1"); |
| 52 |
| 53 enrollment_should_fail_ = |
| 54 dict.count("fail_enrollment") && (dict["fail_enrollment"] == "1"); |
| 55 |
| 56 if (dict.count("connection_lost")) { |
| 57 Tokens lost_begin_end; |
| 58 CHECK(Tokenize(dict["connection_lost"], "-", &lost_begin_end) == 2) |
| 59 << "Wrong 'connection_lost' format."; |
| 60 int begin = 0; |
| 61 int end = 0; |
| 62 CHECK(base::StringToInt(lost_begin_end[0], &begin) && |
| 63 base::StringToInt(lost_begin_end[1], &end)) |
| 64 << "Wrong 'connection_lost' format."; |
| 65 CHECK((begin == 0 && end == 0) || |
| 66 (STAGE_WAITING_FOR_CODE_CONFIRMATION <= begin && begin <= end && |
| 67 end <= STAGE_HOST_ENROLLMENT_ERROR)) |
| 68 << "Wrong 'connection_lost' interval."; |
| 69 connection_lost_begin_ = static_cast<Stage>(begin); |
| 70 connection_lost_end_ = static_cast<Stage>(end); |
| 71 } else { |
| 72 connection_lost_begin_ = connection_lost_end_ = STAGE_NONE; |
| 73 } |
| 74 |
| 75 if (!dict.count("discovery")) { |
| 76 dict["discovery"] = |
| 77 "F-Device_1~F-Device_5~F-Device_3~L-Device_3~L-Device_1~F-Device_1"; |
| 78 } |
| 79 base::StringPairs events; |
| 80 CHECK( |
| 81 base::SplitStringIntoKeyValuePairs(dict["discovery"], '-', '~', &events)) |
| 82 << "Wrong 'discovery' format."; |
| 83 DiscoveryScenario scenario; |
| 84 for (base::StringPairs::const_iterator event = events.begin(); |
| 85 event != events.end(); |
| 86 ++event) { |
| 87 std::string type = event->first; |
| 88 std::string device_id = event->second; |
| 89 CHECK(type == "F" || type == "L" || type == "N") |
| 90 << "Wrong discovery event type."; |
| 91 CHECK(!device_id.empty() || type == "N") << "Empty device ID."; |
| 92 scenario.push_back(DiscoveryEvent( |
| 93 type == "F" ? DEVICE_FOUND : type == "L" ? DEVICE_LOST : NOTHING_FOUND, |
| 94 device_id)); |
| 95 } |
| 96 SetDiscoveryScenario(scenario); |
| 97 |
| 98 preset_confirmation_code_ = dict["code"]; |
| 99 CHECK(preset_confirmation_code_.empty() || |
| 100 (preset_confirmation_code_.length() == 6 && |
| 101 preset_confirmation_code_.find_first_not_of("0123456789") == |
| 102 std::string::npos)) |
| 103 << "Wrong 'code' format."; |
| 104 } |
| 105 |
| 106 void FakeControllerPairingFlow::SetShouldFailOnConnecting() { |
| 107 should_fail_on_connecting_ = true; |
| 108 } |
| 109 |
| 110 void FakeControllerPairingFlow::SetShouldLoseConnection(Stage stage_begin, |
| 111 Stage stage_end) { |
| 112 connection_lost_begin_ = stage_begin; |
| 113 connection_lost_end_ = stage_end; |
| 114 } |
| 115 |
| 116 void FakeControllerPairingFlow::SetEnrollmentShouldFail() { |
| 117 enrollment_should_fail_ = true; |
| 118 } |
| 119 |
| 120 void FakeControllerPairingFlow::SetDiscoveryScenario( |
| 121 const DiscoveryScenario& discovery_scenario) { |
| 122 discovery_scenario_ = discovery_scenario; |
| 123 // Check that scenario is valid. |
| 124 std::set<std::string> devices; |
| 125 for (DiscoveryScenario::const_iterator event = discovery_scenario_.begin(); |
| 126 event != discovery_scenario_.end(); |
| 127 ++event) { |
| 128 switch (event->first) { |
| 129 case DEVICE_FOUND: { |
| 130 devices.insert(event->second); |
| 131 break; |
| 132 } |
| 133 case DEVICE_LOST: { |
| 134 CHECK(devices.count(event->second)); |
| 135 devices.erase(event->second); |
| 136 break; |
| 137 } |
| 138 case NOTHING_FOUND: { |
| 139 CHECK(++event == discovery_scenario_.end()); |
| 140 return; |
| 141 } |
| 142 } |
| 143 } |
| 144 } |
| 145 |
| 146 void FakeControllerPairingFlow::AddObserver(Observer* observer) { |
| 147 observers_.AddObserver(observer); |
| 148 } |
| 149 |
| 150 void FakeControllerPairingFlow::RemoveObserver(Observer* observer) { |
| 151 observers_.RemoveObserver(observer); |
| 152 } |
| 153 |
| 154 ControllerPairingFlow::Stage FakeControllerPairingFlow::GetCurrentStage() { |
| 155 return current_stage_; |
| 156 } |
| 157 |
| 158 void FakeControllerPairingFlow::StartFlow() { |
| 159 CHECK(current_stage_ == STAGE_NONE); |
| 160 ChangeStage(STAGE_DEVICES_DISCOVERY); |
| 161 } |
| 162 |
| 163 ControllerPairingFlow::DeviceIdList |
| 164 FakeControllerPairingFlow::GetDiscoveredDevices() { |
| 165 CHECK(current_stage_ == STAGE_DEVICES_DISCOVERY); |
| 166 return DeviceIdList(discovered_devices_.begin(), discovered_devices_.end()); |
| 167 } |
| 168 |
| 169 void FakeControllerPairingFlow::ChooseDeviceForPairing( |
| 170 const std::string& device_id) { |
| 171 CHECK(current_stage_ == STAGE_DEVICES_DISCOVERY); |
| 172 CHECK(discovered_devices_.count(device_id)); |
| 173 choosen_device_ = device_id; |
| 174 ChangeStage(STAGE_ESTABLISHING_CONNECTION); |
| 175 } |
| 176 |
| 177 void FakeControllerPairingFlow::RepeatDiscovery() { |
| 178 CHECK(current_stage_ == STAGE_DEVICE_NOT_FOUND || |
| 179 current_stage_ == STAGE_ESTABLISHING_CONNECTION_ERROR || |
| 180 current_stage_ == STAGE_HOST_ENROLLMENT_ERROR); |
| 181 ChangeStage(STAGE_DEVICES_DISCOVERY); |
| 182 } |
| 183 |
| 184 std::string FakeControllerPairingFlow::GetConfirmationCode() { |
| 185 CHECK(current_stage_ == STAGE_WAITING_FOR_CODE_CONFIRMATION); |
| 186 if (confirmation_code_.empty()) { |
| 187 if (preset_confirmation_code_.empty()) { |
| 188 for (int i = 0; i < 6; ++i) |
| 189 confirmation_code_.push_back(base::RandInt('0', '9')); |
| 190 } else { |
| 191 confirmation_code_ = preset_confirmation_code_; |
| 192 } |
| 193 } |
| 194 return confirmation_code_; |
| 195 } |
| 196 |
| 197 void FakeControllerPairingFlow::SetConfirmationCodeIsCorrect(bool correct) { |
| 198 CHECK(current_stage_ == STAGE_WAITING_FOR_CODE_CONFIRMATION); |
| 199 if (correct) |
| 200 ChangeStage(STAGE_HOST_UPDATE_IN_PROGRESS); |
| 201 else |
| 202 ChangeStage(STAGE_DEVICES_DISCOVERY); |
| 203 } |
| 204 |
| 205 void FakeControllerPairingFlow::OnAuthenticationDone( |
| 206 const chromeos::UserContext& user_context, |
| 207 content::BrowserContext* browser_context) { |
| 208 CHECK(current_stage_ == STAGE_WAITING_FOR_CREDENTIALS); |
| 209 ChangeStage(STAGE_HOST_ENROLLMENT_IN_PROGRESS); |
| 210 } |
| 211 |
| 212 void FakeControllerPairingFlow::StartSession() { |
| 213 CHECK(current_stage_ == STAGE_PAIRING_DONE); |
| 214 ChangeStage(STAGE_FINISHED); |
| 215 } |
| 216 |
| 217 void FakeControllerPairingFlow::ChangeStage(Stage new_stage) { |
| 218 if (current_stage_ == new_stage) |
| 219 return; |
| 220 current_stage_ = new_stage; |
| 221 FOR_EACH_OBSERVER(Observer, observers_, PairingStageChanged(new_stage)); |
| 222 } |
| 223 |
| 224 void FakeControllerPairingFlow::ChangeStageLater(Stage new_stage) { |
| 225 base::MessageLoop::current()->PostDelayedTask( |
| 226 FROM_HERE, |
| 227 base::Bind(&FakeControllerPairingFlow::ChangeStage, |
| 228 base::Unretained(this), |
| 229 new_stage), |
| 230 async_duration_); |
| 231 } |
| 232 |
| 233 void FakeControllerPairingFlow::ExecuteDiscoveryEvent(size_t event_position) { |
| 234 if (current_stage_ != STAGE_DEVICES_DISCOVERY) |
| 235 return; |
| 236 CHECK(event_position < discovery_scenario_.size()); |
| 237 const DiscoveryEvent& event = discovery_scenario_[event_position]; |
| 238 switch (event.first) { |
| 239 case DEVICE_FOUND: { |
| 240 DeviceFound(event.second); |
| 241 break; |
| 242 } |
| 243 case DEVICE_LOST: { |
| 244 DeviceLost(event.second); |
| 245 break; |
| 246 } |
| 247 case NOTHING_FOUND: { |
| 248 ChangeStage(STAGE_DEVICE_NOT_FOUND); |
| 249 break; |
| 250 } |
| 251 } |
| 252 if (++event_position == discovery_scenario_.size()) { |
| 253 return; |
| 254 } |
| 255 base::MessageLoop::current()->PostDelayedTask( |
| 256 FROM_HERE, |
| 257 base::Bind(&FakeControllerPairingFlow::ExecuteDiscoveryEvent, |
| 258 base::Unretained(this), |
| 259 event_position), |
| 260 async_duration_); |
| 261 } |
| 262 |
| 263 void FakeControllerPairingFlow::DeviceFound(const std::string& device_id) { |
| 264 CHECK(current_stage_ == STAGE_DEVICES_DISCOVERY); |
| 265 discovered_devices_.insert(device_id); |
| 266 FOR_EACH_OBSERVER(Observer, observers_, DiscoveredDevicesListChanged()); |
| 267 } |
| 268 |
| 269 void FakeControllerPairingFlow::DeviceLost(const std::string& device_id) { |
| 270 CHECK(current_stage_ == STAGE_DEVICES_DISCOVERY); |
| 271 discovered_devices_.erase(device_id); |
| 272 FOR_EACH_OBSERVER(Observer, observers_, DiscoveredDevicesListChanged()); |
| 273 } |
| 274 |
| 275 void FakeControllerPairingFlow::PairingStageChanged(Stage new_stage) { |
| 276 Stage next_stage = STAGE_NONE; |
| 277 switch (new_stage) { |
| 278 case STAGE_DEVICES_DISCOVERY: { |
| 279 discovered_devices_.clear(); |
| 280 base::MessageLoop::current()->PostDelayedTask( |
| 281 FROM_HERE, |
| 282 base::Bind(&FakeControllerPairingFlow::ExecuteDiscoveryEvent, |
| 283 base::Unretained(this), |
| 284 0), |
| 285 async_duration_); |
| 286 break; |
| 287 } |
| 288 case STAGE_ESTABLISHING_CONNECTION: { |
| 289 if (should_fail_on_connecting_) { |
| 290 next_stage = STAGE_ESTABLISHING_CONNECTION_ERROR; |
| 291 should_fail_on_connecting_ = false; |
| 292 } else { |
| 293 confirmation_code_.clear(); |
| 294 next_stage = STAGE_WAITING_FOR_CODE_CONFIRMATION; |
| 295 } |
| 296 break; |
| 297 } |
| 298 case STAGE_HOST_UPDATE_IN_PROGRESS: { |
| 299 next_stage = STAGE_WAITING_FOR_CREDENTIALS; |
| 300 break; |
| 301 } |
| 302 case STAGE_HOST_ENROLLMENT_IN_PROGRESS: { |
| 303 if (enrollment_should_fail_) { |
| 304 enrollment_should_fail_ = false; |
| 305 next_stage = STAGE_HOST_ENROLLMENT_ERROR; |
| 306 } else { |
| 307 next_stage = STAGE_PAIRING_DONE; |
| 308 } |
| 309 break; |
| 310 } |
| 311 case STAGE_HOST_CONNECTION_LOST: { |
| 312 next_stage = connection_lost_end_; |
| 313 connection_lost_end_ = STAGE_NONE; |
| 314 break; |
| 315 } |
| 316 default: |
| 317 break; |
| 318 } |
| 319 if (new_stage == connection_lost_begin_) { |
| 320 connection_lost_begin_ = STAGE_NONE; |
| 321 next_stage = STAGE_HOST_CONNECTION_LOST; |
| 322 } |
| 323 if (next_stage != STAGE_NONE) |
| 324 ChangeStageLater(next_stage); |
| 325 } |
| 326 |
| 327 void FakeControllerPairingFlow::DiscoveredDevicesListChanged() { |
| 328 } |
| 329 |
| 330 } // namespace chromeos |
OLD | NEW |