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 "stdafx.h" 6 #include "secondary_tile.h" 7 8 #include <windows.ui.startscreen.h> 9 10 #include "base/bind.h" 11 #include "base/logging.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "url/gurl.h" 14 #include "win8/metro_driver/chrome_app_view.h" 15 #include "win8/metro_driver/winrt_utils.h" 16 17 namespace { 18 19 using base::win::MetroPinUmaResultCallback; 20 21 // Callback for asynchronous pin requests. 22 class TileRequestCompleter { 23 public: 24 enum PinType { 25 PIN, 26 UNPIN 27 }; 28 TileRequestCompleter(PinType type, const MetroPinUmaResultCallback& callback) 29 : type_(type), callback_(callback) {} 30 31 void Complete(mswr::ComPtr<winfoundtn::IAsyncOperation<bool>>& completion); 32 33 private: 34 // Callback that responds to user input on the pin request pop-up. This will 35 // run |callback_|, then delete |this| before returning. 36 HRESULT Respond(winfoundtn::IAsyncOperation<bool>* async, 37 AsyncStatus status); 38 39 PinType type_; 40 MetroPinUmaResultCallback callback_; 41 }; 42 43 void TileRequestCompleter::Complete( 44 mswr::ComPtr<winfoundtn::IAsyncOperation<bool>>& completion) { 45 typedef winfoundtn::IAsyncOperationCompletedHandler<bool> RequestDoneType; 46 mswr::ComPtr<RequestDoneType> handler(mswr::Callback<RequestDoneType>( 47 this, &TileRequestCompleter::Respond)); 48 DCHECK(handler.Get() != NULL); 49 HRESULT hr = completion->put_Completed(handler.Get()); 50 CheckHR(hr, "Failed to put_Completed"); 51 } 52 53 HRESULT TileRequestCompleter::Respond(winfoundtn::IAsyncOperation<bool>* async, 54 AsyncStatus status) { 55 base::win::MetroSecondaryTilePinUmaResult pin_state = 56 base::win::METRO_PIN_STATE_NONE; 57 58 if (status == Completed) { 59 unsigned char result; 60 CheckHR(async->GetResults(&result)); 61 LOG(INFO) << __FUNCTION__ << " result " << static_cast<int>(result); 62 switch (result) { 63 case 0: 64 pin_state = type_ == PIN ? 65 base::win::METRO_PIN_RESULT_CANCEL : 66 base::win::METRO_UNPIN_RESULT_CANCEL; 67 break; 68 case 1: 69 pin_state = type_ == PIN ? 70 base::win::METRO_PIN_RESULT_OK : 71 base::win::METRO_UNPIN_RESULT_OK; 72 break; 73 default: 74 pin_state = type_ == PIN ? 75 base::win::METRO_PIN_RESULT_OTHER : 76 base::win::METRO_UNPIN_RESULT_OTHER; 77 break; 78 } 79 } else { 80 LOG(ERROR) << __FUNCTION__ << " Unexpected async status " 81 << static_cast<int>(status); 82 pin_state = type_ == PIN ? 83 base::win::METRO_PIN_RESULT_ERROR : 84 base::win::METRO_UNPIN_RESULT_ERROR; 85 } 86 callback_.Run(pin_state); 87 88 delete this; 89 return S_OK; 90 } 91 92 void DeleteTileFromStartScreen(const base::string16& tile_id, 93 const MetroPinUmaResultCallback& callback) { 94 DVLOG(1) << __FUNCTION__; 95 mswr::ComPtr<winui::StartScreen::ISecondaryTileFactory> tile_factory; 96 HRESULT hr = winrt_utils::CreateActivationFactory( 97 RuntimeClass_Windows_UI_StartScreen_SecondaryTile, 98 tile_factory.GetAddressOf()); 99 CheckHR(hr, "Failed to create instance of ISecondaryTileFactory"); 100 101 mswrw::HString id; 102 id.Attach(MakeHString(tile_id)); 103 104 mswr::ComPtr<winui::StartScreen::ISecondaryTile> tile; 105 hr = tile_factory->CreateWithId(id.Get(), tile.GetAddressOf()); 106 CheckHR(hr, "Failed to create tile"); 107 108 mswr::ComPtr<winfoundtn::IAsyncOperation<bool>> completion; 109 hr = tile->RequestDeleteAsync(completion.GetAddressOf()); 110 CheckHR(hr, "RequestDeleteAsync failed"); 111 112 if (FAILED(hr)) { 113 callback.Run(base::win::METRO_UNPIN_REQUEST_SHOW_ERROR); 114 return; 115 } 116 117 // Deleted in TileRequestCompleter::Respond when the async operation 118 // completes. 119 TileRequestCompleter* completer = 120 new TileRequestCompleter(TileRequestCompleter::UNPIN, callback); 121 completer->Complete(completion); 122 } 123 124 void CreateTileOnStartScreen(const base::string16& tile_id, 125 const base::string16& title_str, 126 const base::string16& url_str, 127 const base::FilePath& logo_path, 128 const MetroPinUmaResultCallback& callback) { 129 VLOG(1) << __FUNCTION__; 130 131 mswr::ComPtr<winui::StartScreen::ISecondaryTileFactory> tile_factory; 132 HRESULT hr = winrt_utils::CreateActivationFactory( 133 RuntimeClass_Windows_UI_StartScreen_SecondaryTile, 134 tile_factory.GetAddressOf()); 135 CheckHR(hr, "Failed to create instance of ISecondaryTileFactory"); 136 137 winui::StartScreen::TileOptions options = 138 winui::StartScreen::TileOptions_ShowNameOnLogo; 139 mswrw::HString title; 140 title.Attach(MakeHString(title_str)); 141 142 mswrw::HString id; 143 id.Attach(MakeHString(tile_id)); 144 145 mswrw::HString args; 146 // The url is just passed into the tile agruments as is. Metro and desktop 147 // chrome will see the arguments as command line parameters. 148 // A GURL is used to ensure any spaces are properly escaped. 149 GURL url(url_str); 150 args.Attach(MakeHString(base::UTF8ToUTF16(url.spec()))); 151 152 mswr::ComPtr<winfoundtn::IUriRuntimeClassFactory> uri_factory; 153 hr = winrt_utils::CreateActivationFactory( 154 RuntimeClass_Windows_Foundation_Uri, 155 uri_factory.GetAddressOf()); 156 CheckHR(hr, "Failed to create URIFactory"); 157 158 mswrw::HString logo_url; 159 logo_url.Attach( 160 MakeHString(base::string16(L"file:///").append(logo_path.value()))); 161 mswr::ComPtr<winfoundtn::IUriRuntimeClass> uri; 162 hr = uri_factory->CreateUri(logo_url.Get(), &uri); 163 CheckHR(hr, "Failed to create URI"); 164 165 mswr::ComPtr<winui::StartScreen::ISecondaryTile> tile; 166 hr = tile_factory->CreateTile(id.Get(), 167 title.Get(), 168 title.Get(), 169 args.Get(), 170 options, 171 uri.Get(), 172 tile.GetAddressOf()); 173 CheckHR(hr, "Failed to create tile"); 174 175 hr = tile->put_ForegroundText(winui::StartScreen::ForegroundText_Light); 176 CheckHR(hr, "Failed to change foreground text color"); 177 178 mswr::ComPtr<winfoundtn::IAsyncOperation<bool>> completion; 179 hr = tile->RequestCreateAsync(completion.GetAddressOf()); 180 CheckHR(hr, "RequestCreateAsync failed"); 181 182 if (FAILED(hr)) { 183 callback.Run(base::win::METRO_PIN_REQUEST_SHOW_ERROR); 184 return; 185 } 186 187 // Deleted in TileRequestCompleter::Respond when the async operation 188 // completes. 189 TileRequestCompleter* completer = 190 new TileRequestCompleter(TileRequestCompleter::PIN, callback); 191 completer->Complete(completion); 192 } 193 194 } // namespace 195 196 BOOL MetroIsPinnedToStartScreen(const base::string16& tile_id) { 197 mswr::ComPtr<winui::StartScreen::ISecondaryTileStatics> tile_statics; 198 HRESULT hr = winrt_utils::CreateActivationFactory( 199 RuntimeClass_Windows_UI_StartScreen_SecondaryTile, 200 tile_statics.GetAddressOf()); 201 CheckHR(hr, "Failed to create instance of ISecondaryTileStatics"); 202 203 boolean exists; 204 hr = tile_statics->Exists(MakeHString(tile_id), &exists); 205 CheckHR(hr, "ISecondaryTileStatics.Exists failed"); 206 return exists; 207 } 208 209 void MetroUnPinFromStartScreen(const base::string16& tile_id, 210 const MetroPinUmaResultCallback& callback) { 211 globals.appview_msg_loop->PostTask( 212 FROM_HERE, base::Bind(&DeleteTileFromStartScreen, 213 tile_id, 214 callback)); 215 } 216 217 void MetroPinToStartScreen(const base::string16& tile_id, 218 const base::string16& title, 219 const base::string16& url, 220 const base::FilePath& logo_path, 221 const MetroPinUmaResultCallback& callback) { 222 globals.appview_msg_loop->PostTask( 223 FROM_HERE, base::Bind(&CreateTileOnStartScreen, 224 tile_id, 225 title, 226 url, 227 logo_path, 228 callback)); 229 } 230