15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/chromeos/login/network_dropdown.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h" 11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/chromeos/login/ui/login_display_host.h" 12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/chromeos/login/ui/login_display_host_impl.h" 13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chromeos/network/network_state_handler.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_ui.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/models/menu_model.h" 164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ui/base/webui/web_ui_util.h" 17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "ui/chromeos/network/network_icon.h" 18116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "ui/chromeos/network/network_icon_animation.h" 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/gfx/font_list.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image_skia.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Timeout between consecutive requests to network library for network 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// scan. 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kNetworkScanIntervalSecs = 60; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace chromeos { 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// WebUI specific implementation of the NetworkMenu class. 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class NetworkMenuWebUI : public NetworkMenu { 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NetworkMenuWebUI(NetworkMenu::Delegate* delegate, content::WebUI* web_ui); 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NetworkMenu override: 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void UpdateMenu() OVERRIDE; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Called when item with command |id| is chosen. 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void OnItemChosen(int id); 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Converts menu model into the ListValue, ready for passing to WebUI. 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::ListValue* ConvertMenuModel(ui::MenuModel* model); 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // WebUI where network menu is located. 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::WebUI* web_ui_; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(NetworkMenuWebUI); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NetworkMenuWebUI ------------------------------------------------------------ 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NetworkMenuWebUI::NetworkMenuWebUI(NetworkMenu::Delegate* delegate, 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::WebUI* web_ui) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : NetworkMenu(delegate), 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_ui_(web_ui) { 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NetworkMenuWebUI::UpdateMenu() { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NetworkMenu::UpdateMenu(); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (web_ui_) { 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<base::ListValue> list(ConvertMenuModel(GetMenuModel())); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_ui_->CallJavascriptFunction("cr.ui.DropDown.updateNetworks", *list); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NetworkMenuWebUI::OnItemChosen(int id) { 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::MenuModel* model = GetMenuModel(); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) model->ActivatedAt(index); 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::ListValue* NetworkMenuWebUI::ConvertMenuModel(ui::MenuModel* model) { 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::ListValue* list = new base::ListValue(); 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < model->GetItemCount(); ++i) { 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::MenuModel::ItemType type = model->GetTypeAt(i); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int id; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type == ui::MenuModel::TYPE_SEPARATOR) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) id = -2; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) id = model->GetCommandIdAt(i); 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::DictionaryValue* item = new base::DictionaryValue(); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) item->SetInteger("id", id); 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) item->SetString("label", model->GetLabelAt(i)); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Image icon; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (model->GetIconAt(i, &icon)) { 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkBitmap icon_bitmap = icon.ToImageSkia()->GetRepresentation( 93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) web_ui_->GetDeviceScaleFactor()).sk_bitmap(); 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) item->SetString("icon", webui::GetBitmapDataUrl(icon_bitmap)); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (id >= 0) { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) item->SetBoolean("enabled", model->IsEnabledAt(i)); 985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const gfx::FontList* font_list = model->GetLabelFontListAt(i); 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (font_list) 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) item->SetBoolean("bold", font_list->GetFontStyle() == gfx::Font::BOLD); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type == ui::MenuModel::TYPE_SUBMENU) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) item->Set("sub", ConvertMenuModel(model->GetSubmenuModelAt(i))); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) list->Append(item); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return list; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NetworkDropdown ------------------------------------------------------------- 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1112385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen MurdochNetworkDropdown::NetworkDropdown(Actor* actor, 1122385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch content::WebUI* web_ui, 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool oobe) 1142385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch : actor_(actor), 1152385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch web_ui_(web_ui), 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) oobe_(oobe) { 1172385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch DCHECK(actor_); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) network_menu_.reset(new NetworkMenuWebUI(this, web_ui)); 119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(NetworkHandler::IsInitialized()); 120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); 121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) handler->RequestScan(); 1227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) handler->AddObserver(this, FROM_HERE); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Refresh(); 124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) network_scan_timer_.Start( 125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) FROM_HERE, 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::TimeDelta::FromSeconds(kNetworkScanIntervalSecs), 127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) this, &NetworkDropdown::RequestNetworkScan); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NetworkDropdown::~NetworkDropdown() { 131116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch ui::network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); 1327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (NetworkHandler::IsInitialized()) { 1337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) NetworkHandler::Get()->network_state_handler()->RemoveObserver( 1347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) this, FROM_HERE); 1357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NetworkDropdown::OnItemChosen(int id) { 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) network_menu_->OnItemChosen(id); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::NativeWindow NetworkDropdown::GetNativeWindow() const { 143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return LoginDisplayHostImpl::default_host()->GetNativeWindow(); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NetworkDropdown::OpenButtonOptions() { 147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) LoginDisplayHostImpl::default_host()->OpenProxySettings(); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NetworkDropdown::ShouldOpenButtonOptions() const { 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !oobe_; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 154116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid NetworkDropdown::OnConnectToNetworkRequested() { 155116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch actor_->OnConnectToNetworkRequested(); 1562385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch} 1572385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch 158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void NetworkDropdown::DefaultNetworkChanged(const NetworkState* network) { 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Refresh(); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 162868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void NetworkDropdown::NetworkConnectionStateChanged( 163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const NetworkState* network) { 164868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Refresh(); 165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void NetworkDropdown::NetworkListChanged() { 168868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Refresh(); 169868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void NetworkDropdown::NetworkIconChanged() { 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetNetworkIconAndText(); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void NetworkDropdown::Refresh() { 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetNetworkIconAndText(); 177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) network_menu_->UpdateMenu(); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NetworkDropdown::SetNetworkIconAndText() { 181a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 text; 182868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) gfx::ImageSkia icon_image; 183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool animating = false; 184116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch ui::network_icon::GetDefaultNetworkImageAndLabel( 185116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch ui::network_icon::ICON_TYPE_LIST, &icon_image, &text, &animating); 186868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (animating) { 187116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch ui::network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this); 188868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } else { 189116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch ui::network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); 190868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkBitmap icon_bitmap = icon_image.GetRepresentation( 192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) web_ui_->GetDeviceScaleFactor()).sk_bitmap(); 193868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::string icon_str; 194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!icon_image.isNull()) 195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) icon_str = webui::GetBitmapDataUrl(icon_bitmap); 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::StringValue title(text); 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::StringValue icon(icon_str); 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_ui_->CallJavascriptFunction("cr.ui.DropDown.updateNetworkTitle", 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) title, icon); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 202868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void NetworkDropdown::RequestNetworkScan() { 203868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) NetworkHandler::Get()->network_state_handler()->RequestScan(); 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Refresh(); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace chromeos 208