1 // Copyright (c) 2011 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/logging.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/string_piece.h"
12 #include "base/values.h"
13 #include "chrome/browser/chromeos/cros/cros_library.h"
14 #include "chrome/browser/chromeos/cros/network_library.h"
15 #include "chrome/browser/chromeos/sim_dialog_delegate.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/ui/webui/chrome_url_data_manager.h"
18 #include "chrome/common/jstemplate_builder.h"
19 #include "chrome/common/url_constants.h"
20 #include "content/browser/browser_thread.h"
21 #include "content/browser/tab_contents/tab_contents.h"
22 #include "content/common/notification_service.h"
23 #include "content/common/notification_type.h"
24 #include "grit/browser_resources.h"
25 #include "grit/generated_resources.h"
26 #include "ui/base/l10n/l10n_util.h"
27 #include "ui/base/resource/resource_bundle.h"
28
29 namespace {
30
31 // JS API callbacks names.
32 const char kJsApiCancel[] = "cancel";
33 const char kJsApiChangePinCode[] = "changePinCode";
34 const char kJsApiEnterPinCode[] = "enterPinCode";
35 const char kJsApiEnterPukCode[] = "enterPukCode";
36 const char kJsApiProceedToPukInput[] = "proceedToPukInput";
37 const char kJsApiSimStatusInitialize[] = "simStatusInitialize";
38
39 // Page JS API function names.
40 const char kJsApiSimStatusChanged[] = "mobile.SimUnlock.simStateChanged";
41
42 // SIM state variables which are passed to the page.
43 const char kState[] = "state";
44 const char kError[] = "error";
45 const char kTriesLeft[] = "tries";
46
47 // Error constants, passed to the page.
48 const char kErrorPin[] = "incorrectPin";
49 const char kErrorPuk[] = "incorrectPuk";
50 const char kErrorOk[] = "ok";
51
GetCellularDevice()52 const chromeos::NetworkDevice* GetCellularDevice() {
53 chromeos::NetworkLibrary* lib = chromeos::CrosLibrary::Get()->
54 GetNetworkLibrary();
55 CHECK(lib);
56 return lib->FindCellularDevice();
57 }
58
59 } // namespace
60
61 namespace chromeos {
62
63 class SimUnlockUIHTMLSource : public ChromeURLDataManager::DataSource {
64 public:
65 SimUnlockUIHTMLSource();
66
67 // Called when the network layer has requested a resource underneath
68 // the path we registered.
69 virtual void StartDataRequest(const std::string& path,
70 bool is_incognito,
71 int request_id);
GetMimeType(const std::string &) const72 virtual std::string GetMimeType(const std::string&) const {
73 return "text/html";
74 }
75
76 private:
~SimUnlockUIHTMLSource()77 virtual ~SimUnlockUIHTMLSource() {}
78
79 std::string service_path_;
80 DISALLOW_COPY_AND_ASSIGN(SimUnlockUIHTMLSource);
81 };
82
83 // The handler for Javascript messages related to the "sim-unlock" view.
84 class SimUnlockHandler : public WebUIMessageHandler,
85 public base::SupportsWeakPtr<SimUnlockHandler>,
86 public NetworkLibrary::NetworkDeviceObserver,
87 public NetworkLibrary::PinOperationObserver {
88 public:
89 SimUnlockHandler();
90 virtual ~SimUnlockHandler();
91
92 // Init work after Attach.
93 void Init(TabContents* contents);
94
95 // WebUIMessageHandler implementation.
96 virtual WebUIMessageHandler* Attach(WebUI* web_ui);
97 virtual void RegisterMessages();
98
99 // NetworkLibrary::NetworkDeviceObserver implementation.
100 virtual void OnNetworkDeviceChanged(NetworkLibrary* cros,
101 const NetworkDevice* device);
102
103 // NetworkLibrary::PinOperationObserver implementation.
104 virtual void OnPinOperationCompleted(NetworkLibrary* cros,
105 PinOperationError error);
106
107 private:
108 // Should keep this state enum in sync with similar one in JS code.
109 // SIM_NOT_LOCKED_ASK_PIN - SIM card is not locked but we ask user
110 // for PIN input because PinRequired preference change was requested.
111 // SIM_NOT_LOCKED_CHANGE_PIN - SIM card is not locked, ask user for old PIN
112 // and new PIN to change it.
113 typedef enum SimUnlockState {
114 SIM_UNLOCK_LOADING = -1,
115 SIM_ABSENT_NOT_LOCKED = 0,
116 SIM_NOT_LOCKED_ASK_PIN = 1,
117 SIM_NOT_LOCKED_CHANGE_PIN = 2,
118 SIM_LOCKED_PIN = 3,
119 SIM_LOCKED_NO_PIN_TRIES_LEFT = 4,
120 SIM_LOCKED_PUK = 5,
121 SIM_LOCKED_NO_PUK_TRIES_LEFT = 6,
122 SIM_DISABLED = 7,
123 } SimUnlockState;
124
125 // Type of the SIM unlock code.
126 typedef enum SimUnlockCode {
127 CODE_PIN,
128 CODE_PUK,
129 } SimUnlockCode;
130
131 class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> {
132 public:
TaskProxy(const base::WeakPtr<SimUnlockHandler> & handler)133 explicit TaskProxy(const base::WeakPtr<SimUnlockHandler>& handler)
134 : handler_(handler) {
135 }
136
TaskProxy(const base::WeakPtr<SimUnlockHandler> & handler,const std::string & code,SimUnlockCode code_type)137 TaskProxy(const base::WeakPtr<SimUnlockHandler>& handler,
138 const std::string& code,
139 SimUnlockCode code_type)
140 : handler_(handler),
141 code_(code),
142 code_type_(code_type) {
143 }
144
HandleCancel()145 void HandleCancel() {
146 if (handler_)
147 handler_->CancelDialog();
148 }
149
HandleEnterCode()150 void HandleEnterCode() {
151 if (handler_)
152 handler_->EnterCode(code_, code_type_);
153 }
154
HandleInitialize()155 void HandleInitialize() {
156 if (handler_)
157 handler_->InitializeSimStatus();
158 }
159
HandleProceedToPukInput()160 void HandleProceedToPukInput() {
161 if (handler_)
162 handler_->ProceedToPukInput();
163 }
164
165 private:
166 base::WeakPtr<SimUnlockHandler> handler_;
167
168 // Pending code input (PIN/PUK).
169 std::string code_;
170
171 // Pending code type.
172 SimUnlockCode code_type_;
173
174 DISALLOW_COPY_AND_ASSIGN(TaskProxy);
175 };
176
177 // Processing for the cases when dialog was cancelled.
178 void CancelDialog();
179
180 // Pass PIN/PUK code to flimflam and check status.
181 void EnterCode(const std::string& code, SimUnlockCode code_type);
182
183 // Single handler for PIN/PUK code operations.
184 void HandleEnterCode(SimUnlockCode code_type, const std::string& code);
185
186 // Handlers for JS WebUI messages.
187 void HandleCancel(const ListValue* args);
188 void HandleChangePinCode(const ListValue* args);
189 void HandleEnterPinCode(const ListValue* args);
190 void HandleEnterPukCode(const ListValue* args);
191 void HandleProceedToPukInput(const ListValue* args);
192 void HandleSimStatusInitialize(const ListValue* args);
193
194 // Initialize current SIM card status, passes that to page.
195 void InitializeSimStatus();
196
197 // Notifies SIM Security tab handler that RequirePin preference change
198 // has been ended (either updated or cancelled).
199 void NotifyOnRequirePinChangeEnded(bool new_value);
200
201 // Notifies observers that the EnterPin or EnterPuk dialog has been
202 // completed (either cancelled or with entry of PIN/PUK).
203 void NotifyOnEnterPinEnded(bool cancelled);
204
205 // Checks whether SIM card is in PUK locked state and proceeds to PUK input.
206 void ProceedToPukInput();
207
208 // Processes current SIM card state and update internal state/page.
209 void ProcessSimCardState(const chromeos::NetworkDevice* cellular);
210
211 // Updates page with the current state/SIM card info/error.
212 void UpdatePage(const chromeos::NetworkDevice* cellular,
213 const std::string& error_msg);
214
215 TabContents* tab_contents_;
216 SimUnlockState state_;
217
218 // Path of the Cellular device that we monitor property updates from.
219 std::string cellular_device_path_;
220
221 // Type of the dialog: generic unlock/change pin/change PinRequire.
222 SimDialogDelegate::SimDialogMode dialog_mode_;
223
224 // New PIN value for the case when we unblock SIM card or change PIN.
225 std::string new_pin_;
226
227 DISALLOW_COPY_AND_ASSIGN(SimUnlockHandler);
228 };
229
230 // SimUnlockUIHTMLSource -------------------------------------------------------
231
SimUnlockUIHTMLSource()232 SimUnlockUIHTMLSource::SimUnlockUIHTMLSource()
233 : DataSource(chrome::kChromeUISimUnlockHost, MessageLoop::current()) {
234 }
235
StartDataRequest(const std::string & path,bool is_incognito,int request_id)236 void SimUnlockUIHTMLSource::StartDataRequest(const std::string& path,
237 bool is_incognito,
238 int request_id) {
239 DictionaryValue strings;
240 strings.SetString("title",
241 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TITLE));
242 strings.SetString("ok", l10n_util::GetStringUTF16(IDS_OK));
243 strings.SetString("cancel", l10n_util::GetStringUTF16(IDS_CANCEL));
244 strings.SetString("enterPinTitle",
245 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TITLE));
246 strings.SetString("enterPinMessage",
247 l10n_util::GetStringUTF16(IDS_SIM_ENTER_PIN_MESSAGE));
248 strings.SetString("enterPinTriesMessage",
249 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TRIES_MESSAGE));
250 strings.SetString("incorrectPinTriesMessage",
251 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_INCORRECT_PIN_TRIES_MESSAGE));
252 strings.SetString("incorrectPinTitle",
253 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_INCORRECT_PIN_TITLE));
254 // TODO(nkostylev): Pass carrier name if we know that.
255 strings.SetString("noPinTriesLeft", l10n_util::GetStringFUTF16(
256 IDS_SIM_UNLOCK_NO_PIN_TRIES_LEFT_MESSAGE,
257 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_DEFAULT_CARRIER)));
258 strings.SetString("enterPukButton",
259 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_BUTTON));
260 strings.SetString("enterPukTitle",
261 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_TITLE));
262 strings.SetString("enterPukWarning",
263 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_WARNING));
264 // TODO(nkostylev): Pass carrier name if we know that.
265 strings.SetString("enterPukMessage", l10n_util::GetStringFUTF16(
266 IDS_SIM_UNLOCK_ENTER_PUK_MESSAGE,
267 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_DEFAULT_CARRIER)));
268 strings.SetString("choosePinTitle",
269 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_CHOOSE_PIN_TITLE));
270 strings.SetString("choosePinMessage",
271 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_CHOOSE_PIN_MESSAGE));
272 strings.SetString("newPin", l10n_util::GetStringUTF16(
273 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_NEW_PIN));
274 strings.SetString("retypeNewPin", l10n_util::GetStringUTF16(
275 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_RETYPE_PIN));
276 strings.SetString("pinsDontMatchMessage", l10n_util::GetStringUTF16(
277 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_PINS_DONT_MATCH_ERROR));
278 strings.SetString("noPukTriesLeft",
279 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_NO_PUK_TRIES_LEFT_MESSAGE));
280 strings.SetString("simDisabledTitle",
281 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_SIM_DISABLED_TITLE));
282 strings.SetString("simDisabledMessage",
283 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_SIM_DISABLED_MESSAGE));
284
285 strings.SetString("changePinTitle", l10n_util::GetStringUTF16(
286 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_TITLE));
287 strings.SetString("changePinMessage", l10n_util::GetStringUTF16(
288 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_MESSAGE));
289 strings.SetString("oldPin", l10n_util::GetStringUTF16(
290 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_OLD_PIN));
291
292 SetFontAndTextDirection(&strings);
293
294 static const base::StringPiece html(
295 ResourceBundle::GetSharedInstance().GetRawDataResource(
296 IDR_SIM_UNLOCK_HTML));
297
298 const std::string& full_html = jstemplate_builder::GetI18nTemplateHtml(
299 html, &strings);
300
301 scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes());
302 html_bytes->data.resize(full_html.size());
303 std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
304
305 SendResponse(request_id, html_bytes);
306 }
307
308 // SimUnlockHandler ------------------------------------------------------------
309
SimUnlockHandler()310 SimUnlockHandler::SimUnlockHandler()
311 : tab_contents_(NULL),
312 state_(SIM_UNLOCK_LOADING),
313 dialog_mode_(SimDialogDelegate::SIM_DIALOG_UNLOCK) {
314 const chromeos::NetworkDevice* cellular = GetCellularDevice();
315 // One could just call us directly via chrome://sim-unlock.
316 if (cellular) {
317 cellular_device_path_ = cellular->device_path();
318 CrosLibrary::Get()->GetNetworkLibrary()->AddNetworkDeviceObserver(
319 cellular_device_path_, this);
320 CrosLibrary::Get()->GetNetworkLibrary()->AddPinOperationObserver(this);
321 }
322 }
323
~SimUnlockHandler()324 SimUnlockHandler::~SimUnlockHandler() {
325 if (!cellular_device_path_.empty()) {
326 CrosLibrary::Get()->GetNetworkLibrary()->RemoveNetworkDeviceObserver(
327 cellular_device_path_, this);
328 CrosLibrary::Get()->GetNetworkLibrary()->RemovePinOperationObserver(this);
329 }
330 }
331
Attach(WebUI * web_ui)332 WebUIMessageHandler* SimUnlockHandler::Attach(WebUI* web_ui) {
333 return WebUIMessageHandler::Attach(web_ui);
334 }
335
Init(TabContents * contents)336 void SimUnlockHandler::Init(TabContents* contents) {
337 tab_contents_ = contents;
338 }
339
RegisterMessages()340 void SimUnlockHandler::RegisterMessages() {
341 web_ui_->RegisterMessageCallback(kJsApiCancel,
342 NewCallback(this, &SimUnlockHandler::HandleCancel));
343 web_ui_->RegisterMessageCallback(kJsApiChangePinCode,
344 NewCallback(this, &SimUnlockHandler::HandleChangePinCode));
345 web_ui_->RegisterMessageCallback(kJsApiEnterPinCode,
346 NewCallback(this, &SimUnlockHandler::HandleEnterPinCode));
347 web_ui_->RegisterMessageCallback(kJsApiEnterPukCode,
348 NewCallback(this, &SimUnlockHandler::HandleEnterPukCode));
349 web_ui_->RegisterMessageCallback(kJsApiProceedToPukInput,
350 NewCallback(this, &SimUnlockHandler::HandleProceedToPukInput));
351 web_ui_->RegisterMessageCallback(kJsApiSimStatusInitialize,
352 NewCallback(this, &SimUnlockHandler::HandleSimStatusInitialize));
353 }
354
OnNetworkDeviceChanged(NetworkLibrary * cros,const NetworkDevice * device)355 void SimUnlockHandler::OnNetworkDeviceChanged(NetworkLibrary* cros,
356 const NetworkDevice* device) {
357 chromeos::SIMLockState lock_state = device->sim_lock_state();
358 int retries_left = device->sim_retries_left();
359 VLOG(1) << "OnNetworkDeviceChanged, lock: " << lock_state
360 << ", retries: " << retries_left;
361 ProcessSimCardState(GetCellularDevice());
362 }
363
OnPinOperationCompleted(NetworkLibrary * cros,PinOperationError error)364 void SimUnlockHandler::OnPinOperationCompleted(NetworkLibrary* cros,
365 PinOperationError error) {
366 DCHECK(cros);
367 const NetworkDevice* cellular = cros->FindCellularDevice();
368 DCHECK(cellular);
369 VLOG(1) << "OnPinOperationCompleted, error: " << error;
370 if (state_ == SIM_NOT_LOCKED_ASK_PIN && error == PIN_ERROR_NONE) {
371 CHECK(dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON ||
372 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF);
373 // Async change RequirePin operation has finished OK.
374 NotifyOnRequirePinChangeEnded(
375 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON);
376 // Dialog will close itself.
377 state_ = SIM_ABSENT_NOT_LOCKED;
378 } else if (state_ == SIM_NOT_LOCKED_CHANGE_PIN && error == PIN_ERROR_NONE) {
379 CHECK(dialog_mode_ == SimDialogDelegate::SIM_DIALOG_CHANGE_PIN);
380 // Dialog will close itself.
381 state_ = SIM_ABSENT_NOT_LOCKED;
382 }
383 // If previous EnterPIN was last PIN attempt and SIMLock state was already
384 // processed by OnNetworkDeviceChanged, let dialog stay on
385 // NO_PIN_RETRIES_LEFT step.
386 if (!(state_ == SIM_LOCKED_NO_PIN_TRIES_LEFT && error == PIN_ERROR_BLOCKED))
387 ProcessSimCardState(cellular);
388 if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_UNLOCK &&
389 state_ == SIM_ABSENT_NOT_LOCKED)
390 NotifyOnEnterPinEnded(false);
391 }
392
CancelDialog()393 void SimUnlockHandler::CancelDialog() {
394 if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON ||
395 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF) {
396 // When async change RequirePin operation is performed,
397 // dialog UI controls such as Cancel button are disabled.
398 // If dialog was cancelled that means RequirePin preference hasn't been
399 // changed and is not in process of changing at the moment.
400 NotifyOnRequirePinChangeEnded(
401 !(dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON));
402 } else if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_UNLOCK) {
403 NotifyOnEnterPinEnded(true);
404 }
405 }
406
EnterCode(const std::string & code,SimUnlockCode code_type)407 void SimUnlockHandler::EnterCode(const std::string& code,
408 SimUnlockCode code_type) {
409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
410 NetworkLibrary* lib = chromeos::CrosLibrary::Get()->GetNetworkLibrary();
411 CHECK(lib);
412
413 const NetworkDevice* cellular = GetCellularDevice();
414 chromeos::SIMLockState lock_state = cellular->sim_lock_state();
415
416 switch (code_type) {
417 case CODE_PIN:
418 if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON ||
419 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF) {
420 if (lock_state != chromeos::SIM_UNLOCKED) {
421 // If SIM is locked/absent, change RequirePin UI is not accessible.
422 NOTREACHED() <<
423 "Changing RequirePin pref on locked / uninitialized SIM.";
424 }
425 lib->ChangeRequirePin(
426 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON,
427 code);
428 } else if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_CHANGE_PIN) {
429 if (lock_state != chromeos::SIM_UNLOCKED) {
430 // If SIM is locked/absent, changing PIN UI is not accessible.
431 NOTREACHED() << "Changing PIN on locked / uninitialized SIM.";
432 }
433 lib->ChangePin(code, new_pin_);
434 } else {
435 lib->EnterPin(code);
436 }
437 break;
438 case CODE_PUK:
439 DCHECK(!new_pin_.empty());
440 lib->UnblockPin(code, new_pin_);
441 break;
442 }
443 }
444
NotifyOnEnterPinEnded(bool cancelled)445 void SimUnlockHandler::NotifyOnEnterPinEnded(bool cancelled) {
446 NotificationService::current()->Notify(
447 NotificationType::ENTER_PIN_ENDED,
448 NotificationService::AllSources(),
449 Details<bool>(&cancelled));
450 }
451
NotifyOnRequirePinChangeEnded(bool new_value)452 void SimUnlockHandler::NotifyOnRequirePinChangeEnded(bool new_value) {
453 NotificationService::current()->Notify(
454 NotificationType::REQUIRE_PIN_SETTING_CHANGE_ENDED,
455 NotificationService::AllSources(),
456 Details<bool>(&new_value));
457 }
458
HandleCancel(const ListValue * args)459 void SimUnlockHandler::HandleCancel(const ListValue* args) {
460 const size_t kEnterCodeParamCount = 0;
461 if (args->GetSize() != kEnterCodeParamCount) {
462 NOTREACHED();
463 return;
464 }
465 scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr());
466 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
467 NewRunnableMethod(task.get(), &TaskProxy::HandleCancel));
468 }
469
HandleChangePinCode(const ListValue * args)470 void SimUnlockHandler::HandleChangePinCode(const ListValue* args) {
471 const size_t kChangePinParamCount = 2;
472 std::string pin;
473 std::string new_pin;
474 if (args->GetSize() != kChangePinParamCount ||
475 !args->GetString(0, &pin) ||
476 !args->GetString(1, &new_pin)) {
477 NOTREACHED();
478 return;
479 }
480 new_pin_ = new_pin;
481 HandleEnterCode(CODE_PIN, pin);
482 }
483
HandleEnterCode(SimUnlockCode code_type,const std::string & code)484 void SimUnlockHandler::HandleEnterCode(SimUnlockCode code_type,
485 const std::string& code) {
486 scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(), code, code_type);
487 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
488 NewRunnableMethod(task.get(), &TaskProxy::HandleEnterCode));
489 }
490
HandleEnterPinCode(const ListValue * args)491 void SimUnlockHandler::HandleEnterPinCode(const ListValue* args) {
492 const size_t kEnterPinParamCount = 1;
493 std::string pin;
494 if (args->GetSize() != kEnterPinParamCount || !args->GetString(0, &pin)) {
495 NOTREACHED();
496 return;
497 }
498 HandleEnterCode(CODE_PIN, pin);
499 }
500
HandleEnterPukCode(const ListValue * args)501 void SimUnlockHandler::HandleEnterPukCode(const ListValue* args) {
502 const size_t kEnterPukParamCount = 2;
503 std::string puk;
504 std::string new_pin;
505 if (args->GetSize() != kEnterPukParamCount ||
506 !args->GetString(0, &puk) ||
507 !args->GetString(1, &new_pin)) {
508 NOTREACHED();
509 return;
510 }
511 new_pin_ = new_pin;
512 HandleEnterCode(CODE_PUK, puk);
513 }
514
HandleProceedToPukInput(const ListValue * args)515 void SimUnlockHandler::HandleProceedToPukInput(const ListValue* args) {
516 const size_t kProceedToPukInputParamCount = 0;
517 if (args->GetSize() != kProceedToPukInputParamCount) {
518 NOTREACHED();
519 return;
520 }
521 scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr());
522 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
523 NewRunnableMethod(task.get(), &TaskProxy::HandleProceedToPukInput));
524 }
525
HandleSimStatusInitialize(const ListValue * args)526 void SimUnlockHandler::HandleSimStatusInitialize(const ListValue* args) {
527 const size_t kSimStatusInitializeParamCount = 1;
528 double mode;
529 if (args->GetSize() != kSimStatusInitializeParamCount ||
530 !args->GetDouble(0, &mode)) {
531 NOTREACHED();
532 return;
533 }
534 dialog_mode_ = static_cast<SimDialogDelegate::SimDialogMode>(mode);
535 VLOG(1) << "Initializing SIM dialog in mode: " << dialog_mode_;
536 scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr());
537 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
538 NewRunnableMethod(task.get(), &TaskProxy::HandleInitialize));
539 }
540
InitializeSimStatus()541 void SimUnlockHandler::InitializeSimStatus() {
542 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
543 ProcessSimCardState(GetCellularDevice());
544 }
545
ProceedToPukInput()546 void SimUnlockHandler::ProceedToPukInput() {
547 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
548 ProcessSimCardState(GetCellularDevice());
549 }
550
ProcessSimCardState(const chromeos::NetworkDevice * cellular)551 void SimUnlockHandler::ProcessSimCardState(
552 const chromeos::NetworkDevice* cellular) {
553 std::string error_msg;
554 if (cellular) {
555 chromeos::SIMLockState lock_state = cellular->sim_lock_state();
556 int retries_left = cellular->sim_retries_left();
557 VLOG(1) << "Current state: " << state_ << " lock_state: " << lock_state
558 << " retries: " << retries_left;
559 switch (state_) {
560 case SIM_UNLOCK_LOADING:
561 if (lock_state == chromeos::SIM_LOCKED_PIN) {
562 state_ = SIM_LOCKED_PIN;
563 } else if (lock_state == chromeos::SIM_LOCKED_PUK) {
564 if (retries_left > 0)
565 state_ = SIM_LOCKED_PUK;
566 else
567 state_ = SIM_DISABLED;
568 } else if (lock_state == chromeos::SIM_UNLOCKED) {
569 if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON ||
570 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF) {
571 state_ = SIM_NOT_LOCKED_ASK_PIN;
572 } else if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_CHANGE_PIN) {
573 state_ = SIM_NOT_LOCKED_CHANGE_PIN;
574 } else {
575 state_ = SIM_ABSENT_NOT_LOCKED;
576 }
577 } else {
578 // SIM_UNKNOWN: when SIM status is not initialized (should not happen,
579 // since this UI is accessible when SIM is initialized)
580 // or SIM card is absent. In latter case just close dialog.
581 state_ = SIM_ABSENT_NOT_LOCKED;
582 }
583 break;
584 case SIM_ABSENT_NOT_LOCKED:
585 // Dialog will close itself in this case.
586 break;
587 case SIM_NOT_LOCKED_ASK_PIN:
588 case SIM_NOT_LOCKED_CHANGE_PIN:
589 // We always start in these states when SIM is unlocked.
590 // So if we get here while still being UNLOCKED,
591 // that means entered PIN was incorrect.
592 if (lock_state == chromeos::SIM_UNLOCKED) {
593 error_msg = kErrorPin;
594 } else if (lock_state == chromeos::SIM_LOCKED_PUK) {
595 state_ = SIM_LOCKED_NO_PIN_TRIES_LEFT;
596 } else {
597 NOTREACHED()
598 << "Change PIN / Set lock mode with unexpected SIM lock state";
599 state_ = SIM_ABSENT_NOT_LOCKED;
600 }
601 break;
602 case SIM_LOCKED_PIN:
603 if (lock_state == chromeos::SIM_UNLOCKED ||
604 lock_state == chromeos::SIM_UNKNOWN) {
605 state_ = SIM_ABSENT_NOT_LOCKED;
606 } else if (lock_state == chromeos::SIM_LOCKED_PUK) {
607 state_ = SIM_LOCKED_NO_PIN_TRIES_LEFT;
608 } else {
609 // Still blocked with PIN.
610 error_msg = kErrorPin;
611 }
612 break;
613 case SIM_LOCKED_NO_PIN_TRIES_LEFT:
614 // Proceed user to PUK input.
615 state_ = SIM_LOCKED_PUK;
616 break;
617 case SIM_LOCKED_PUK:
618 if (lock_state == chromeos::SIM_UNLOCKED ||
619 lock_state == chromeos::SIM_UNKNOWN) {
620 state_ = SIM_ABSENT_NOT_LOCKED;
621 } else if (retries_left == 0) {
622 state_ = SIM_LOCKED_NO_PUK_TRIES_LEFT;
623 }
624 // Otherwise SIM card is still locked with PUK code.
625 // Dialog will display enter PUK screen with an updated retries count.
626 break;
627 case SIM_LOCKED_NO_PUK_TRIES_LEFT:
628 case SIM_DISABLED:
629 // User will close dialog manually.
630 break;
631 }
632 } else {
633 VLOG(1) << "Cellular device is absent.";
634 // No cellular device, should close dialog.
635 state_ = SIM_ABSENT_NOT_LOCKED;
636 }
637 VLOG(1) << "New state: " << state_;
638 UpdatePage(cellular, error_msg);
639 }
640
UpdatePage(const chromeos::NetworkDevice * cellular,const std::string & error_msg)641 void SimUnlockHandler::UpdatePage(const chromeos::NetworkDevice* cellular,
642 const std::string& error_msg) {
643 DictionaryValue sim_dict;
644 if (cellular)
645 sim_dict.SetInteger(kTriesLeft, cellular->sim_retries_left());
646 sim_dict.SetInteger(kState, state_);
647 if (!error_msg.empty())
648 sim_dict.SetString(kError, error_msg);
649 else
650 sim_dict.SetString(kError, kErrorOk);
651 web_ui_->CallJavascriptFunction(kJsApiSimStatusChanged, sim_dict);
652 }
653
654 // SimUnlockUI -----------------------------------------------------------------
655
SimUnlockUI(TabContents * contents)656 SimUnlockUI::SimUnlockUI(TabContents* contents) : WebUI(contents) {
657 SimUnlockHandler* handler = new SimUnlockHandler();
658 AddMessageHandler((handler)->Attach(this));
659 handler->Init(contents);
660 SimUnlockUIHTMLSource* html_source = new SimUnlockUIHTMLSource();
661
662 // Set up the chrome://sim-unlock/ source.
663 contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
664 }
665
666 } // namespace chromeos
667