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 };
TileRequestCompleter(PinType type,const MetroPinUmaResultCallback & callback)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
Complete(mswr::ComPtr<winfoundtn::IAsyncOperation<bool>> & completion)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
Respond(winfoundtn::IAsyncOperation<bool> * async,AsyncStatus status)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
DeleteTileFromStartScreen(const string16 & tile_id,const MetroPinUmaResultCallback & callback)92 void DeleteTileFromStartScreen(const 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
CreateTileOnStartScreen(const string16 & tile_id,const string16 & title_str,const string16 & url_str,const base::FilePath & logo_path,const MetroPinUmaResultCallback & callback)124 void CreateTileOnStartScreen(const string16& tile_id,
125 const string16& title_str,
126 const 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(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(MakeHString(string16(L"file:///").append(logo_path.value())));
160 mswr::ComPtr<winfoundtn::IUriRuntimeClass> uri;
161 hr = uri_factory->CreateUri(logo_url.Get(), &uri);
162 CheckHR(hr, "Failed to create URI");
163
164 mswr::ComPtr<winui::StartScreen::ISecondaryTile> tile;
165 hr = tile_factory->CreateTile(id.Get(),
166 title.Get(),
167 title.Get(),
168 args.Get(),
169 options,
170 uri.Get(),
171 tile.GetAddressOf());
172 CheckHR(hr, "Failed to create tile");
173
174 hr = tile->put_ForegroundText(winui::StartScreen::ForegroundText_Light);
175 CheckHR(hr, "Failed to change foreground text color");
176
177 mswr::ComPtr<winfoundtn::IAsyncOperation<bool>> completion;
178 hr = tile->RequestCreateAsync(completion.GetAddressOf());
179 CheckHR(hr, "RequestCreateAsync failed");
180
181 if (FAILED(hr)) {
182 callback.Run(base::win::METRO_PIN_REQUEST_SHOW_ERROR);
183 return;
184 }
185
186 // Deleted in TileRequestCompleter::Respond when the async operation
187 // completes.
188 TileRequestCompleter* completer =
189 new TileRequestCompleter(TileRequestCompleter::PIN, callback);
190 completer->Complete(completion);
191 }
192
193 } // namespace
194
MetroIsPinnedToStartScreen(const string16 & tile_id)195 BOOL MetroIsPinnedToStartScreen(const string16& tile_id) {
196 mswr::ComPtr<winui::StartScreen::ISecondaryTileStatics> tile_statics;
197 HRESULT hr = winrt_utils::CreateActivationFactory(
198 RuntimeClass_Windows_UI_StartScreen_SecondaryTile,
199 tile_statics.GetAddressOf());
200 CheckHR(hr, "Failed to create instance of ISecondaryTileStatics");
201
202 boolean exists;
203 hr = tile_statics->Exists(MakeHString(tile_id), &exists);
204 CheckHR(hr, "ISecondaryTileStatics.Exists failed");
205 return exists;
206 }
207
MetroUnPinFromStartScreen(const string16 & tile_id,const MetroPinUmaResultCallback & callback)208 void MetroUnPinFromStartScreen(const string16& tile_id,
209 const MetroPinUmaResultCallback& callback) {
210 globals.appview_msg_loop->PostTask(
211 FROM_HERE, base::Bind(&DeleteTileFromStartScreen,
212 tile_id,
213 callback));
214 }
215
MetroPinToStartScreen(const string16 & tile_id,const string16 & title,const string16 & url,const base::FilePath & logo_path,const MetroPinUmaResultCallback & callback)216 void MetroPinToStartScreen(const string16& tile_id,
217 const string16& title,
218 const string16& url,
219 const base::FilePath& logo_path,
220 const MetroPinUmaResultCallback& callback) {
221 globals.appview_msg_loop->PostTask(
222 FROM_HERE, base::Bind(&CreateTileOnStartScreen,
223 tile_id,
224 title,
225 url,
226 logo_path,
227 callback));
228 }
229