1 // Copyright (c) 2012 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 "chrome/browser/ui/webui/chromeos/sim_unlock_ui.h"
6
7 #include <string>
8
9 #include "base/basictypes.h"
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/location.h"
13 #include "base/logging.h"
14 #include "base/memory/ref_counted_memory.h"
15 #include "base/memory/weak_ptr.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/strings/string_piece.h"
18 #include "base/values.h"
19 #include "chrome/browser/chrome_notification_types.h"
20 #include "chrome/browser/chromeos/sim_dialog_delegate.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/common/url_constants.h"
23 #include "chromeos/network/device_state.h"
24 #include "chromeos/network/network_device_handler.h"
25 #include "chromeos/network/network_event_log.h"
26 #include "chromeos/network/network_state_handler.h"
27 #include "chromeos/network/network_state_handler_observer.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "content/public/browser/notification_service.h"
30 #include "content/public/browser/url_data_source.h"
31 #include "content/public/browser/web_contents.h"
32 #include "content/public/browser/web_ui.h"
33 #include "content/public/browser/web_ui_message_handler.h"
34 #include "grit/browser_resources.h"
35 #include "grit/generated_resources.h"
36 #include "third_party/cros_system_api/dbus/service_constants.h"
37 #include "ui/base/l10n/l10n_util.h"
38 #include "ui/base/resource/resource_bundle.h"
39 #include "ui/base/webui/jstemplate_builder.h"
40 #include "ui/base/webui/web_ui_util.h"
41
42 using content::BrowserThread;
43 using content::WebContents;
44 using content::WebUIMessageHandler;
45
46 namespace {
47
48 // JS API callbacks names.
49 const char kJsApiCancel[] = "cancel";
50 const char kJsApiChangePinCode[] = "changePinCode";
51 const char kJsApiEnterPinCode[] = "enterPinCode";
52 const char kJsApiEnterPukCode[] = "enterPukCode";
53 const char kJsApiProceedToPukInput[] = "proceedToPukInput";
54 const char kJsApiSimStatusInitialize[] = "simStatusInitialize";
55
56 // Page JS API function names.
57 const char kJsApiSimStatusChanged[] = "mobile.SimUnlock.simStateChanged";
58
59 // SIM state variables which are passed to the page.
60 const char kState[] = "state";
61 const char kError[] = "error";
62 const char kTriesLeft[] = "tries";
63
64 // Error constants, passed to the page.
65 const char kErrorPin[] = "incorrectPin";
66 const char kErrorOk[] = "ok";
67
GetNetworkDeviceHandler()68 chromeos::NetworkDeviceHandler* GetNetworkDeviceHandler() {
69 return chromeos::NetworkHandler::Get()->network_device_handler();
70 }
71
GetNetworkStateHandler()72 chromeos::NetworkStateHandler* GetNetworkStateHandler() {
73 return chromeos::NetworkHandler::Get()->network_state_handler();
74 }
75
76 } // namespace
77
78 namespace chromeos {
79
80 class SimUnlockUIHTMLSource : public content::URLDataSource {
81 public:
82 SimUnlockUIHTMLSource();
83
84 // content::URLDataSource implementation.
85 virtual std::string GetSource() const OVERRIDE;
86 virtual void StartDataRequest(
87 const std::string& path,
88 int render_process_id,
89 int render_frame_id,
90 const content::URLDataSource::GotDataCallback& callback) OVERRIDE;
GetMimeType(const std::string &) const91 virtual std::string GetMimeType(const std::string&) const OVERRIDE {
92 return "text/html";
93 }
ShouldAddContentSecurityPolicy() const94 virtual bool ShouldAddContentSecurityPolicy() const OVERRIDE {
95 return false;
96 }
97
98 private:
~SimUnlockUIHTMLSource()99 virtual ~SimUnlockUIHTMLSource() {}
100
101 std::string service_path_;
102 DISALLOW_COPY_AND_ASSIGN(SimUnlockUIHTMLSource);
103 };
104
105 // The handler for Javascript messages related to the "sim-unlock" view.
106 class SimUnlockHandler : public WebUIMessageHandler,
107 public base::SupportsWeakPtr<SimUnlockHandler>,
108 public NetworkStateHandlerObserver {
109 public:
110 SimUnlockHandler();
111 virtual ~SimUnlockHandler();
112
113 // WebUIMessageHandler implementation.
114 virtual void RegisterMessages() OVERRIDE;
115
116 // NetworkStateHandlerObserver implementation.
117 virtual void DeviceListChanged() OVERRIDE;
118
119 private:
120 // Should keep this state enum in sync with similar one in JS code.
121 // SIM_NOT_LOCKED_ASK_PIN - SIM card is not locked but we ask user
122 // for PIN input because PinRequired preference change was requested.
123 // SIM_NOT_LOCKED_CHANGE_PIN - SIM card is not locked, ask user for old PIN
124 // and new PIN to change it.
125 typedef enum SimUnlockState {
126 SIM_UNLOCK_LOADING = -1,
127 SIM_ABSENT_NOT_LOCKED = 0,
128 SIM_NOT_LOCKED_ASK_PIN = 1,
129 SIM_NOT_LOCKED_CHANGE_PIN = 2,
130 SIM_LOCKED_PIN = 3,
131 SIM_LOCKED_NO_PIN_TRIES_LEFT = 4,
132 SIM_LOCKED_PUK = 5,
133 SIM_LOCKED_NO_PUK_TRIES_LEFT = 6,
134 SIM_DISABLED = 7,
135 } SimUnlockState;
136
137 // Type of the SIM unlock code.
138 enum SimUnlockCode {
139 CODE_PIN,
140 CODE_PUK
141 };
142
143 enum PinOperationError {
144 PIN_ERROR_NONE = 0,
145 PIN_ERROR_UNKNOWN = 1,
146 PIN_ERROR_INCORRECT_CODE = 2,
147 PIN_ERROR_BLOCKED = 3
148 };
149
150 class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> {
151 public:
TaskProxy(const base::WeakPtr<SimUnlockHandler> & handler)152 explicit TaskProxy(const base::WeakPtr<SimUnlockHandler>& handler)
153 : handler_(handler),
154 code_type_() {
155 }
156
TaskProxy(const base::WeakPtr<SimUnlockHandler> & handler,const std::string & code,SimUnlockCode code_type)157 TaskProxy(const base::WeakPtr<SimUnlockHandler>& handler,
158 const std::string& code,
159 SimUnlockCode code_type)
160 : handler_(handler),
161 code_(code),
162 code_type_(code_type) {
163 }
164
HandleCancel()165 void HandleCancel() {
166 if (handler_)
167 handler_->CancelDialog();
168 }
169
HandleEnterCode()170 void HandleEnterCode() {
171 if (handler_)
172 handler_->EnterCode(code_, code_type_);
173 }
174
HandleInitialize()175 void HandleInitialize() {
176 if (handler_)
177 handler_->InitializeSimStatus();
178 }
179
HandleProceedToPukInput()180 void HandleProceedToPukInput() {
181 if (handler_)
182 handler_->ProceedToPukInput();
183 }
184
185 private:
186 friend class base::RefCountedThreadSafe<TaskProxy>;
187
~TaskProxy()188 ~TaskProxy() {}
189
190 base::WeakPtr<SimUnlockHandler> handler_;
191
192 // Pending code input (PIN/PUK).
193 std::string code_;
194
195 // Pending code type.
196 SimUnlockCode code_type_;
197
198 DISALLOW_COPY_AND_ASSIGN(TaskProxy);
199 };
200
201 // Returns the cellular device that this dialog currently corresponds to.
202 const DeviceState* GetCellularDevice();
203
204 // Processing for the cases when dialog was cancelled.
205 void CancelDialog();
206
207 // Pass PIN/PUK code to shill and check status.
208 void EnterCode(const std::string& code, SimUnlockCode code_type);
209
210 // Methods to invoke shill PIN/PUK D-Bus operations.
211 void ChangeRequirePin(bool require_pin, const std::string& pin);
212 void EnterPin(const std::string& pin);
213 void ChangePin(const std::string& old_pin, const std::string& new_pin);
214 void UnblockPin(const std::string& puk, const std::string& new_pin);
215 void PinOperationSuccessCallback(const std::string& operation_name);
216 void PinOperationErrorCallback(const std::string& operation_name,
217 const std::string& error_name,
218 scoped_ptr<base::DictionaryValue> error_data);
219
220 // Called when an asynchronous PIN operation has completed.
221 void OnPinOperationCompleted(PinOperationError error);
222
223 // Single handler for PIN/PUK code operations.
224 void HandleEnterCode(SimUnlockCode code_type, const std::string& code);
225
226 // Handlers for JS WebUI messages.
227 void HandleCancel(const base::ListValue* args);
228 void HandleChangePinCode(const base::ListValue* args);
229 void HandleEnterPinCode(const base::ListValue* args);
230 void HandleEnterPukCode(const base::ListValue* args);
231 void HandleProceedToPukInput(const base::ListValue* args);
232 void HandleSimStatusInitialize(const base::ListValue* args);
233
234 // Initialize current SIM card status, passes that to page.
235 void InitializeSimStatus();
236
237 // Notifies SIM Security tab handler that RequirePin preference change
238 // has been ended (either updated or cancelled).
239 void NotifyOnRequirePinChangeEnded(bool new_value);
240
241 // Notifies observers that the EnterPin or EnterPuk dialog has been
242 // completed (either cancelled or with entry of PIN/PUK).
243 void NotifyOnEnterPinEnded(bool cancelled);
244
245 // Checks whether SIM card is in PUK locked state and proceeds to PUK input.
246 void ProceedToPukInput();
247
248 // Processes current SIM card state and update internal state/page.
249 void ProcessSimCardState(const DeviceState* cellular);
250
251 // Updates page with the current state/SIM card info/error.
252 void UpdatePage(const DeviceState* cellular, const std::string& error_msg);
253
254 // Dialog internal state.
255 SimUnlockState state_;
256
257 // Path of the Cellular device that we monitor property updates from.
258 std::string cellular_device_path_;
259
260 // Type of the dialog: generic unlock/change pin/change PinRequire.
261 SimDialogDelegate::SimDialogMode dialog_mode_;
262
263 // New PIN value for the case when we unblock SIM card or change PIN.
264 std::string new_pin_;
265
266 // The initial lock type value, used to observe changes to lock status;
267 std::string sim_lock_type_;
268
269 // True if there's a pending PIN operation.
270 // That means that SIM lock state change will be received 2 times:
271 // OnNetworkDeviceSimLockChanged and OnPinOperationCompleted.
272 // First one should be ignored.
273 bool pending_pin_operation_;
274
275 base::WeakPtrFactory<SimUnlockHandler> weak_ptr_factory_;
276
277 DISALLOW_COPY_AND_ASSIGN(SimUnlockHandler);
278 };
279
280 // SimUnlockUIHTMLSource -------------------------------------------------------
281
SimUnlockUIHTMLSource()282 SimUnlockUIHTMLSource::SimUnlockUIHTMLSource() {
283 }
284
GetSource() const285 std::string SimUnlockUIHTMLSource::GetSource() const {
286 return chrome::kChromeUISimUnlockHost;
287 }
288
StartDataRequest(const std::string & path,int render_process_id,int render_frame_id,const content::URLDataSource::GotDataCallback & callback)289 void SimUnlockUIHTMLSource::StartDataRequest(
290 const std::string& path,
291 int render_process_id,
292 int render_frame_id,
293 const content::URLDataSource::GotDataCallback& callback) {
294 base::DictionaryValue strings;
295 strings.SetString("title",
296 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TITLE));
297 strings.SetString("ok", l10n_util::GetStringUTF16(IDS_OK));
298 strings.SetString("cancel", l10n_util::GetStringUTF16(IDS_CANCEL));
299 strings.SetString("enterPinTitle",
300 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TITLE));
301 strings.SetString("enterPinMessage",
302 l10n_util::GetStringUTF16(IDS_SIM_ENTER_PIN_MESSAGE));
303 strings.SetString("enterPinTriesMessage",
304 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TRIES_MESSAGE));
305 strings.SetString("incorrectPinTriesMessage",
306 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_INCORRECT_PIN_TRIES_MESSAGE));
307 strings.SetString("incorrectPinTitle",
308 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_INCORRECT_PIN_TITLE));
309 // TODO(nkostylev): Pass carrier name if we know that.
310 strings.SetString("noPinTriesLeft", l10n_util::GetStringFUTF16(
311 IDS_SIM_UNLOCK_NO_PIN_TRIES_LEFT_MESSAGE,
312 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_DEFAULT_CARRIER)));
313 strings.SetString("enterPukButton",
314 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_BUTTON));
315 strings.SetString("enterPukTitle",
316 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_TITLE));
317 strings.SetString("enterPukWarning",
318 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_WARNING));
319 // TODO(nkostylev): Pass carrier name if we know that.
320 strings.SetString("enterPukMessage", l10n_util::GetStringFUTF16(
321 IDS_SIM_UNLOCK_ENTER_PUK_MESSAGE,
322 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_DEFAULT_CARRIER)));
323 strings.SetString("choosePinTitle",
324 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_CHOOSE_PIN_TITLE));
325 strings.SetString("choosePinMessage",
326 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_CHOOSE_PIN_MESSAGE));
327 strings.SetString("newPin", l10n_util::GetStringUTF16(
328 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_NEW_PIN));
329 strings.SetString("retypeNewPin", l10n_util::GetStringUTF16(
330 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_RETYPE_PIN));
331 strings.SetString("pinsDontMatchMessage", l10n_util::GetStringUTF16(
332 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_PINS_DONT_MATCH_ERROR));
333 strings.SetString("noPukTriesLeft",
334 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_NO_PUK_TRIES_LEFT_MESSAGE));
335 strings.SetString("simDisabledTitle",
336 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_SIM_DISABLED_TITLE));
337 strings.SetString("simDisabledMessage",
338 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_SIM_DISABLED_MESSAGE));
339
340 strings.SetString("changePinTitle", l10n_util::GetStringUTF16(
341 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_TITLE));
342 strings.SetString("changePinMessage", l10n_util::GetStringUTF16(
343 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_MESSAGE));
344 strings.SetString("oldPin", l10n_util::GetStringUTF16(
345 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_OLD_PIN));
346
347 webui::SetFontAndTextDirection(&strings);
348
349 static const base::StringPiece html(
350 ResourceBundle::GetSharedInstance().GetRawDataResource(
351 IDR_SIM_UNLOCK_HTML));
352
353 std::string full_html = webui::GetI18nTemplateHtml(html, &strings);
354
355 callback.Run(base::RefCountedString::TakeString(&full_html));
356 }
357
358 // SimUnlockHandler ------------------------------------------------------------
359
SimUnlockHandler()360 SimUnlockHandler::SimUnlockHandler()
361 : state_(SIM_UNLOCK_LOADING),
362 dialog_mode_(SimDialogDelegate::SIM_DIALOG_UNLOCK),
363 pending_pin_operation_(false),
364 weak_ptr_factory_(this) {
365 if (GetNetworkStateHandler()
366 ->GetTechnologyState(NetworkTypePattern::Cellular()) !=
367 NetworkStateHandler::TECHNOLOGY_UNAVAILABLE)
368 GetNetworkStateHandler()->AddObserver(this, FROM_HERE);
369 }
370
~SimUnlockHandler()371 SimUnlockHandler::~SimUnlockHandler() {
372 GetNetworkStateHandler()->RemoveObserver(this, FROM_HERE);
373 }
374
RegisterMessages()375 void SimUnlockHandler::RegisterMessages() {
376 web_ui()->RegisterMessageCallback(kJsApiCancel,
377 base::Bind(&SimUnlockHandler::HandleCancel,
378 base::Unretained(this)));
379 web_ui()->RegisterMessageCallback(kJsApiChangePinCode,
380 base::Bind(&SimUnlockHandler::HandleChangePinCode,
381 base::Unretained(this)));
382 web_ui()->RegisterMessageCallback(kJsApiEnterPinCode,
383 base::Bind(&SimUnlockHandler::HandleEnterPinCode,
384 base::Unretained(this)));
385 web_ui()->RegisterMessageCallback(kJsApiEnterPukCode,
386 base::Bind(&SimUnlockHandler::HandleEnterPukCode,
387 base::Unretained(this)));
388 web_ui()->RegisterMessageCallback(kJsApiProceedToPukInput,
389 base::Bind(&SimUnlockHandler::HandleProceedToPukInput,
390 base::Unretained(this)));
391 web_ui()->RegisterMessageCallback(kJsApiSimStatusInitialize,
392 base::Bind(&SimUnlockHandler::HandleSimStatusInitialize,
393 base::Unretained(this)));
394 }
395
DeviceListChanged()396 void SimUnlockHandler::DeviceListChanged() {
397 const DeviceState* cellular_device = GetCellularDevice();
398 if (!cellular_device) {
399 LOG(WARNING) << "Cellular device with path '" << cellular_device_path_
400 << "' disappeared.";
401 ProcessSimCardState(NULL);
402 return;
403 }
404
405 // Process the SIM card state only if the lock state changed.
406 if (cellular_device->sim_lock_type() == sim_lock_type_)
407 return;
408
409 sim_lock_type_ = cellular_device->sim_lock_type();
410 uint32 retries_left = cellular_device->sim_retries_left();
411 VLOG(1) << "OnNetworkDeviceSimLockChanged, lock: " << sim_lock_type_
412 << ", retries: " << retries_left;
413 // There's a pending PIN operation.
414 // Wait for it to finish and refresh state then.
415 if (!pending_pin_operation_)
416 ProcessSimCardState(cellular_device);
417 }
418
OnPinOperationCompleted(PinOperationError error)419 void SimUnlockHandler::OnPinOperationCompleted(PinOperationError error) {
420 pending_pin_operation_ = false;
421 VLOG(1) << "OnPinOperationCompleted, error: " << error;
422 const DeviceState* cellular = GetCellularDevice();
423 if (!cellular) {
424 VLOG(1) << "Cellular device disappeared. Dismissing dialog.";
425 ProcessSimCardState(NULL);
426 return;
427 }
428 if (state_ == SIM_NOT_LOCKED_ASK_PIN && error == PIN_ERROR_NONE) {
429 CHECK(dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON ||
430 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF);
431 // Async change RequirePin operation has finished OK.
432 NotifyOnRequirePinChangeEnded(
433 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON);
434 // Dialog will close itself.
435 state_ = SIM_ABSENT_NOT_LOCKED;
436 } else if (state_ == SIM_NOT_LOCKED_CHANGE_PIN && error == PIN_ERROR_NONE) {
437 CHECK(dialog_mode_ == SimDialogDelegate::SIM_DIALOG_CHANGE_PIN);
438 // Dialog will close itself.
439 state_ = SIM_ABSENT_NOT_LOCKED;
440 }
441 // If previous EnterPIN was last PIN attempt and SIMLock state was already
442 // processed by OnNetworkDeviceChanged, let dialog stay on
443 // NO_PIN_RETRIES_LEFT step.
444 if (!(state_ == SIM_LOCKED_NO_PIN_TRIES_LEFT && error == PIN_ERROR_BLOCKED))
445 ProcessSimCardState(cellular);
446 if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_UNLOCK &&
447 state_ == SIM_ABSENT_NOT_LOCKED)
448 NotifyOnEnterPinEnded(false);
449 }
450
GetCellularDevice()451 const DeviceState* SimUnlockHandler::GetCellularDevice() {
452 return GetNetworkStateHandler()->GetDeviceState(cellular_device_path_);
453 }
454
CancelDialog()455 void SimUnlockHandler::CancelDialog() {
456 if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON ||
457 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF) {
458 // When async change RequirePin operation is performed,
459 // dialog UI controls such as Cancel button are disabled.
460 // If dialog was cancelled that means RequirePin preference hasn't been
461 // changed and is not in process of changing at the moment.
462 NotifyOnRequirePinChangeEnded(
463 !(dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON));
464 } else if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_UNLOCK) {
465 NotifyOnEnterPinEnded(true);
466 }
467 }
468
EnterCode(const std::string & code,SimUnlockCode code_type)469 void SimUnlockHandler::EnterCode(const std::string& code,
470 SimUnlockCode code_type) {
471 DCHECK_CURRENTLY_ON(BrowserThread::UI);
472
473 pending_pin_operation_ = true;
474
475 switch (code_type) {
476 case CODE_PIN:
477 if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON ||
478 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF) {
479 if (!sim_lock_type_.empty()) {
480 // If SIM is locked/absent, change RequirePin UI is not accessible.
481 NOTREACHED() <<
482 "Changing RequirePin pref on locked / uninitialized SIM.";
483 }
484 ChangeRequirePin(
485 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON,
486 code);
487 } else if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_CHANGE_PIN) {
488 if (!sim_lock_type_.empty()) {
489 // If SIM is locked/absent, changing PIN UI is not accessible.
490 NOTREACHED() << "Changing PIN on locked / uninitialized SIM.";
491 }
492 ChangePin(code, new_pin_);
493 } else {
494 EnterPin(code);
495 }
496 break;
497 case CODE_PUK:
498 DCHECK(!new_pin_.empty());
499 UnblockPin(code, new_pin_);
500 break;
501 }
502 }
503
ChangeRequirePin(bool require_pin,const std::string & pin)504 void SimUnlockHandler::ChangeRequirePin(bool require_pin,
505 const std::string& pin) {
506 const DeviceState* cellular = GetCellularDevice();
507 if (!cellular) {
508 NOTREACHED() << "Calling RequirePin method w/o cellular device.";
509 return;
510 }
511 std::string operation_name = "ChangeRequirePin";
512 NET_LOG_USER(operation_name, cellular->path());
513 GetNetworkDeviceHandler()->RequirePin(
514 cellular->path(),
515 require_pin,
516 pin,
517 base::Bind(&SimUnlockHandler::PinOperationSuccessCallback,
518 weak_ptr_factory_.GetWeakPtr(),
519 operation_name),
520 base::Bind(&SimUnlockHandler::PinOperationErrorCallback,
521 weak_ptr_factory_.GetWeakPtr(),
522 operation_name));
523 }
524
EnterPin(const std::string & pin)525 void SimUnlockHandler::EnterPin(const std::string& pin) {
526 const DeviceState* cellular = GetCellularDevice();
527 if (!cellular) {
528 NOTREACHED() << "Calling RequirePin method w/o cellular device.";
529 return;
530 }
531 std::string operation_name = "EnterPin";
532 NET_LOG_USER(operation_name, cellular->path());
533 GetNetworkDeviceHandler()->EnterPin(
534 cellular->path(),
535 pin,
536 base::Bind(&SimUnlockHandler::PinOperationSuccessCallback,
537 weak_ptr_factory_.GetWeakPtr(),
538 operation_name),
539 base::Bind(&SimUnlockHandler::PinOperationErrorCallback,
540 weak_ptr_factory_.GetWeakPtr(),
541 operation_name));
542 }
543
ChangePin(const std::string & old_pin,const std::string & new_pin)544 void SimUnlockHandler::ChangePin(const std::string& old_pin,
545 const std::string& new_pin) {
546 const DeviceState* cellular = GetCellularDevice();
547 if (!cellular) {
548 NOTREACHED() << "Calling RequirePin method w/o cellular device.";
549 return;
550 }
551 std::string operation_name = "ChangePin";
552 NET_LOG_USER(operation_name, cellular->path());
553 GetNetworkDeviceHandler()->ChangePin(
554 cellular->path(),
555 old_pin,
556 new_pin,
557 base::Bind(&SimUnlockHandler::PinOperationSuccessCallback,
558 weak_ptr_factory_.GetWeakPtr(),
559 operation_name),
560 base::Bind(&SimUnlockHandler::PinOperationErrorCallback,
561 weak_ptr_factory_.GetWeakPtr(),
562 operation_name));
563 }
564
UnblockPin(const std::string & puk,const std::string & new_pin)565 void SimUnlockHandler::UnblockPin(const std::string& puk,
566 const std::string& new_pin) {
567 const DeviceState* cellular = GetCellularDevice();
568 if (!cellular) {
569 NOTREACHED() << "Calling RequirePin method w/o cellular device.";
570 return;
571 }
572 std::string operation_name = "UnblockPin";
573 NET_LOG_USER(operation_name, cellular->path());
574 GetNetworkDeviceHandler()->UnblockPin(
575 cellular->path(),
576 puk,
577 new_pin,
578 base::Bind(&SimUnlockHandler::PinOperationSuccessCallback,
579 weak_ptr_factory_.GetWeakPtr(),
580 operation_name),
581 base::Bind(&SimUnlockHandler::PinOperationErrorCallback,
582 weak_ptr_factory_.GetWeakPtr(),
583 operation_name));
584 }
585
PinOperationSuccessCallback(const std::string & operation_name)586 void SimUnlockHandler::PinOperationSuccessCallback(
587 const std::string& operation_name) {
588 NET_LOG_DEBUG("Pin operation successful.", operation_name);
589 OnPinOperationCompleted(PIN_ERROR_NONE);
590 }
591
PinOperationErrorCallback(const std::string & operation_name,const std::string & error_name,scoped_ptr<base::DictionaryValue> error_data)592 void SimUnlockHandler::PinOperationErrorCallback(
593 const std::string& operation_name,
594 const std::string& error_name,
595 scoped_ptr<base::DictionaryValue> error_data) {
596 NET_LOG_ERROR("Pin operation failed: " + error_name, operation_name);
597 PinOperationError pin_error;
598 if (error_name == NetworkDeviceHandler::kErrorIncorrectPin ||
599 error_name == NetworkDeviceHandler::kErrorPinRequired)
600 pin_error = PIN_ERROR_INCORRECT_CODE;
601 else if (error_name == NetworkDeviceHandler::kErrorPinBlocked)
602 pin_error = PIN_ERROR_BLOCKED;
603 else
604 pin_error = PIN_ERROR_UNKNOWN;
605 OnPinOperationCompleted(pin_error);
606 }
607
NotifyOnEnterPinEnded(bool cancelled)608 void SimUnlockHandler::NotifyOnEnterPinEnded(bool cancelled) {
609 content::NotificationService::current()->Notify(
610 chrome::NOTIFICATION_ENTER_PIN_ENDED,
611 content::NotificationService::AllSources(),
612 content::Details<bool>(&cancelled));
613 }
614
NotifyOnRequirePinChangeEnded(bool new_value)615 void SimUnlockHandler::NotifyOnRequirePinChangeEnded(bool new_value) {
616 content::NotificationService::current()->Notify(
617 chrome::NOTIFICATION_REQUIRE_PIN_SETTING_CHANGE_ENDED,
618 content::NotificationService::AllSources(),
619 content::Details<bool>(&new_value));
620 }
621
HandleCancel(const base::ListValue * args)622 void SimUnlockHandler::HandleCancel(const base::ListValue* args) {
623 const size_t kEnterCodeParamCount = 0;
624 if (args->GetSize() != kEnterCodeParamCount) {
625 NOTREACHED();
626 return;
627 }
628 scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr());
629 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
630 base::Bind(&TaskProxy::HandleCancel, task.get()));
631 }
632
HandleChangePinCode(const base::ListValue * args)633 void SimUnlockHandler::HandleChangePinCode(const base::ListValue* args) {
634 const size_t kChangePinParamCount = 2;
635 std::string pin;
636 std::string new_pin;
637 if (args->GetSize() != kChangePinParamCount ||
638 !args->GetString(0, &pin) ||
639 !args->GetString(1, &new_pin)) {
640 NOTREACHED();
641 return;
642 }
643 new_pin_ = new_pin;
644 HandleEnterCode(CODE_PIN, pin);
645 }
646
HandleEnterCode(SimUnlockCode code_type,const std::string & code)647 void SimUnlockHandler::HandleEnterCode(SimUnlockCode code_type,
648 const std::string& code) {
649 scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(), code, code_type);
650 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
651 base::Bind(&TaskProxy::HandleEnterCode, task.get()));
652 }
653
HandleEnterPinCode(const base::ListValue * args)654 void SimUnlockHandler::HandleEnterPinCode(const base::ListValue* args) {
655 const size_t kEnterPinParamCount = 1;
656 std::string pin;
657 if (args->GetSize() != kEnterPinParamCount || !args->GetString(0, &pin)) {
658 NOTREACHED();
659 return;
660 }
661 HandleEnterCode(CODE_PIN, pin);
662 }
663
HandleEnterPukCode(const base::ListValue * args)664 void SimUnlockHandler::HandleEnterPukCode(const base::ListValue* args) {
665 const size_t kEnterPukParamCount = 2;
666 std::string puk;
667 std::string new_pin;
668 if (args->GetSize() != kEnterPukParamCount ||
669 !args->GetString(0, &puk) ||
670 !args->GetString(1, &new_pin)) {
671 NOTREACHED();
672 return;
673 }
674 new_pin_ = new_pin;
675 HandleEnterCode(CODE_PUK, puk);
676 }
677
HandleProceedToPukInput(const base::ListValue * args)678 void SimUnlockHandler::HandleProceedToPukInput(const base::ListValue* args) {
679 const size_t kProceedToPukInputParamCount = 0;
680 if (args->GetSize() != kProceedToPukInputParamCount) {
681 NOTREACHED();
682 return;
683 }
684 scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr());
685 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
686 base::Bind(&TaskProxy::HandleProceedToPukInput, task.get()));
687 }
688
HandleSimStatusInitialize(const base::ListValue * args)689 void SimUnlockHandler::HandleSimStatusInitialize(const base::ListValue* args) {
690 const size_t kSimStatusInitializeParamCount = 1;
691 double mode;
692 if (args->GetSize() != kSimStatusInitializeParamCount ||
693 !args->GetDouble(0, &mode)) {
694 NOTREACHED();
695 return;
696 }
697 dialog_mode_ = static_cast<SimDialogDelegate::SimDialogMode>(mode);
698 VLOG(1) << "Initializing SIM dialog in mode: " << dialog_mode_;
699 scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr());
700 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
701 base::Bind(&TaskProxy::HandleInitialize, task.get()));
702 }
703
InitializeSimStatus()704 void SimUnlockHandler::InitializeSimStatus() {
705 DCHECK_CURRENTLY_ON(BrowserThread::UI);
706 // TODO(armansito): For now, we're initializing the device path to the first
707 // available cellular device. We should try to obtain a specific device here,
708 // as there can be multiple cellular devices present.
709 const DeviceState* cellular_device =
710 GetNetworkStateHandler()
711 ->GetDeviceStateByType(NetworkTypePattern::Cellular());
712 if (cellular_device) {
713 cellular_device_path_ = cellular_device->path();
714 sim_lock_type_ = cellular_device->sim_lock_type();
715 }
716 ProcessSimCardState(cellular_device);
717 }
718
ProceedToPukInput()719 void SimUnlockHandler::ProceedToPukInput() {
720 DCHECK_CURRENTLY_ON(BrowserThread::UI);
721 ProcessSimCardState(GetCellularDevice());
722 }
723
ProcessSimCardState(const DeviceState * cellular)724 void SimUnlockHandler::ProcessSimCardState(
725 const DeviceState* cellular) {
726 std::string error_msg;
727 if (cellular) {
728 uint32 retries_left = cellular->sim_retries_left();
729 VLOG(1) << "Current state: " << state_ << " lock_type: " << sim_lock_type_
730 << " retries: " << retries_left;
731 switch (state_) {
732 case SIM_UNLOCK_LOADING:
733 if (sim_lock_type_ == shill::kSIMLockPin) {
734 state_ = SIM_LOCKED_PIN;
735 } else if (sim_lock_type_ == shill::kSIMLockPuk) {
736 if (retries_left > 0)
737 state_ = SIM_LOCKED_PUK;
738 else
739 state_ = SIM_DISABLED;
740 } else if (sim_lock_type_.empty()) {
741 if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON ||
742 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF) {
743 state_ = SIM_NOT_LOCKED_ASK_PIN;
744 } else if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_CHANGE_PIN) {
745 state_ = SIM_NOT_LOCKED_CHANGE_PIN;
746 } else {
747 state_ = SIM_ABSENT_NOT_LOCKED;
748 }
749 } else {
750 // SIM_UNKNOWN: when SIM status is not initialized (should not happen,
751 // since this UI is accessible when SIM is initialized)
752 // or SIM card is absent. In latter case just close dialog.
753 state_ = SIM_ABSENT_NOT_LOCKED;
754 }
755 break;
756 case SIM_ABSENT_NOT_LOCKED:
757 // Dialog will close itself in this case.
758 break;
759 case SIM_NOT_LOCKED_ASK_PIN:
760 case SIM_NOT_LOCKED_CHANGE_PIN:
761 // We always start in these states when SIM is unlocked.
762 // So if we get here while still being UNLOCKED,
763 // that means entered PIN was incorrect.
764 if (sim_lock_type_.empty()) {
765 error_msg = kErrorPin;
766 } else if (sim_lock_type_ == shill::kSIMLockPuk) {
767 state_ = SIM_LOCKED_NO_PIN_TRIES_LEFT;
768 } else {
769 NOTREACHED()
770 << "Change PIN / Set lock mode with unexpected SIM lock state";
771 state_ = SIM_ABSENT_NOT_LOCKED;
772 }
773 break;
774 case SIM_LOCKED_PIN:
775 if (sim_lock_type_ == shill::kSIMLockPuk) {
776 state_ = SIM_LOCKED_NO_PIN_TRIES_LEFT;
777 } else if (sim_lock_type_ == shill::kSIMLockPin) {
778 // Still locked with PIN.
779 error_msg = kErrorPin;
780 } else {
781 state_ = SIM_ABSENT_NOT_LOCKED;
782 }
783 break;
784 case SIM_LOCKED_NO_PIN_TRIES_LEFT:
785 // Proceed user to PUK input.
786 state_ = SIM_LOCKED_PUK;
787 break;
788 case SIM_LOCKED_PUK:
789 if (sim_lock_type_ != shill::kSIMLockPin &&
790 sim_lock_type_ != shill::kSIMLockPuk) {
791 state_ = SIM_ABSENT_NOT_LOCKED;
792 } else if (retries_left == 0) {
793 state_ = SIM_LOCKED_NO_PUK_TRIES_LEFT;
794 }
795 // Otherwise SIM card is still locked with PUK code.
796 // Dialog will display enter PUK screen with an updated retries count.
797 break;
798 case SIM_LOCKED_NO_PUK_TRIES_LEFT:
799 case SIM_DISABLED:
800 // User will close dialog manually.
801 break;
802 }
803 } else {
804 VLOG(1) << "Cellular device is absent.";
805 // No cellular device, should close dialog.
806 state_ = SIM_ABSENT_NOT_LOCKED;
807 }
808 VLOG(1) << "New state: " << state_;
809 UpdatePage(cellular, error_msg);
810 }
811
UpdatePage(const DeviceState * cellular,const std::string & error_msg)812 void SimUnlockHandler::UpdatePage(const DeviceState* cellular,
813 const std::string& error_msg) {
814 base::DictionaryValue sim_dict;
815 if (cellular)
816 sim_dict.SetInteger(kTriesLeft, cellular->sim_retries_left());
817 sim_dict.SetInteger(kState, state_);
818 if (!error_msg.empty())
819 sim_dict.SetString(kError, error_msg);
820 else
821 sim_dict.SetString(kError, kErrorOk);
822 web_ui()->CallJavascriptFunction(kJsApiSimStatusChanged, sim_dict);
823 }
824
825 // SimUnlockUI -----------------------------------------------------------------
826
SimUnlockUI(content::WebUI * web_ui)827 SimUnlockUI::SimUnlockUI(content::WebUI* web_ui) : WebUIController(web_ui) {
828 SimUnlockHandler* handler = new SimUnlockHandler();
829 web_ui->AddMessageHandler(handler);
830 SimUnlockUIHTMLSource* html_source = new SimUnlockUIHTMLSource();
831
832 // Set up the chrome://sim-unlock/ source.
833 Profile* profile = Profile::FromWebUI(web_ui);
834 content::URLDataSource::Add(profile, html_source);
835 }
836
837 } // namespace chromeos
838