Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(251)

Side by Side Diff: chrome/browser/android/webapk/webapk_builder.cc

Issue 2138973002: Initial CL for talking to the WebAPK server to generate WebAPK (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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/android/webapk/webapk_builder.h"
6
7 #include "base/android/build_info.h"
8 #include "base/android/jni_android.h"
9 #include "base/android/jni_string.h"
10 #include "base/bind.h"
11 #include "base/command_line.h"
12 #include "base/md5.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "chrome/browser/android/webapk/webapk.pb.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/common/chrome_switches.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "jni/WebApkBuilder_jni.h"
20 #include "net/url_request/url_fetcher.h"
21 #include "ui/gfx/codec/png_codec.h"
22 #include "url/gurl.h"
23
24 namespace {
25
26 // The default WebAPK server URL.
27 const char kDefaultWebApkServerUrl[] = "http://www.awesomeserver.appspot.com";
28
29 // The MIME type of the POST data sent to the server.
30 const char kProtoMimeType[] = "application/octet-stream";
31
32 // The number of milliseconds to wait for a response from the server.
33 const int kTimeoutMs = 4000;
34
35 // Returns the scope from |info| if it is specified. Otherwise, returns the
36 // default scope.
37 GURL GetScope(const ShortcutInfo& info) {
38 return (info.scope.is_valid()) ? info.scope : info.url.GetOrigin();
39 }
40
41 // Computes a MD5 hash of |bitmap|'s PNG encoded bytes.
42 std::string ComputeBitmapHash(const SkBitmap& bitmap) {
43 std::vector<unsigned char> png_bytes;
44 gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &png_bytes);
45 base::MD5Digest digest;
46 base::MD5Sum(&png_bytes.front(), png_bytes.size(), &digest);
47 return base::MD5DigestToBase16(digest);
48 }
49
50 } // anonymous namespace
51
52 WebApkBuilder::WebApkBuilder(content::BrowserContext* browser_context,
53 const ShortcutInfo& shortcut_info,
54 const SkBitmap& shortcut_icon)
55 : browser_context_(browser_context),
56 shortcut_info_(shortcut_info),
57 shortcut_icon_(shortcut_icon) {
58 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
59 server_url_ =
60 GURL(command_line->HasSwitch(switches::kWebApkServerUrl)
61 ? command_line->GetSwitchValueASCII(switches::kWebApkServerUrl)
62 : kDefaultWebApkServerUrl);
63 }
64
65 WebApkBuilder::~WebApkBuilder() {}
66
67 // static
68 bool WebApkBuilder::Register(JNIEnv* env) {
69 return RegisterNativesImpl(env);
70 }
71
72 // static
73 std::string WebApkBuilder::DisplayToString(blink::WebDisplayMode display) {
74 switch (display) {
75 case blink::WebDisplayModeUndefined:
76 return "";
77 case blink::WebDisplayModeBrowser:
78 return "browser";
79 case blink::WebDisplayModeMinimalUi:
80 return "minimal-ui";
81 case blink::WebDisplayModeStandalone:
82 return "standalone";
83 case blink::WebDisplayModeFullscreen:
84 return "fullscreen";
85 }
86 }
87
88 // static
89 std::string WebApkBuilder::OrientationToString(
90 blink::WebScreenOrientationLockType orientation) {
91 switch (orientation) {
92 case blink::WebScreenOrientationLockDefault:
93 return "";
94 case blink::WebScreenOrientationLockPortraitPrimary:
95 return "portrait-primary";
96 case blink::WebScreenOrientationLockPortraitSecondary:
97 return "portrait-secondary";
98 case blink::WebScreenOrientationLockLandscapePrimary:
99 return "landscape-primary";
100 case blink::WebScreenOrientationLockLandscapeSecondary:
101 return "landscape-secondary";
102 case blink::WebScreenOrientationLockAny:
103 return "any";
104 case blink::WebScreenOrientationLockLandscape:
105 return "landscape";
106 case blink::WebScreenOrientationLockPortrait:
107 return "portrait";
108 case blink::WebScreenOrientationLockNatural:
109 return "natural";
110 }
111 }
112
113 void WebApkBuilder::BuildAsync(const FinishCallback& finish_callback) {
114 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
115 finish_callback_ = finish_callback;
116 content::BrowserThread::PostTask(
117 content::BrowserThread::UI, FROM_HERE,
118 base::Bind(&WebApkBuilder::InitializeRequestContextGetterOnUIThread,
119 base::Unretained(this)));
120 }
121
122 void WebApkBuilder::OnURLFetchComplete(const net::URLFetcher* source) {
123 timer_.Stop();
Yaron 2016/07/13 00:24:01 DCHECK ui thread (can you add remaining DCHECKs on
pkotwicz 2016/07/13 02:15:31 Done.
124
125 if (!source->GetStatus().is_success() || source->GetResponseCode() != 200) {
126 OnFailure();
127 return;
128 }
129
130 std::string response_string;
131 source->GetResponseAsString(&response_string);
132
133 std::unique_ptr<webapk::CreateWebApkResponse> response(
134 new webapk::CreateWebApkResponse);
135 if (!response->ParseFromString(response_string)) {
136 OnFailure();
137 return;
138 }
139
140 if (response->signed_market_url().empty()) {
141 OnFailure();
142 return;
143 }
144 OnGotMarketUrl(response->signed_market_url());
145 }
146
147 void WebApkBuilder::InitializeRequestContextGetterOnUIThread() {
148 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
149 // Must be called on UI thread.
150 request_context_getter_ =
151 Profile::FromBrowserContext(browser_context_)->GetRequestContext();
152
153 content::BrowserThread::PostTask(
154 content::BrowserThread::IO, FROM_HERE,
155 base::Bind(&WebApkBuilder::SendCreateWebApkRequest,
156 base::Unretained(this)));
157 }
158
159 void WebApkBuilder::SendCreateWebApkRequest() {
160 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
161 std::unique_ptr<webapk::CreateWebApkRequest> request =
162 MakeCreateWebApkRequest();
163
164 timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kTimeoutMs),
165 base::Bind(&WebApkBuilder::OnFailure, base::Unretained(this)));
166
167 url_fetcher_ =
168 net::URLFetcher::Create(server_url_, net::URLFetcher::POST, this);
169 url_fetcher_->SetRequestContext(request_context_getter_);
170 std::string serialized_request;
171 request->SerializeToString(&serialized_request);
172 url_fetcher_->SetUploadData(kProtoMimeType, serialized_request);
173 url_fetcher_->Start();
174 }
175
176 void WebApkBuilder::OnGotMarketUrl(const std::string& signed_market_url) {
177 JNIEnv* env = base::android::AttachCurrentThread();
178 base::android::ScopedJavaLocalRef<jstring> java_signed_market_url =
179 base::android::ConvertUTF8ToJavaString(env, signed_market_url);
180 bool success = Java_WebApkBuilder_downloadAndInstallAsync(
181 env, java_signed_market_url.obj());
182 if (success)
183 OnSuccess();
184 else
185 OnFailure();
186 }
187
188 std::unique_ptr<webapk::CreateWebApkRequest>
189 WebApkBuilder::MakeCreateWebApkRequest() {
Yaron 2016/07/13 00:24:01 Nit: WebApkBuilder::BuildCreate.. ? (since it's a
pkotwicz 2016/07/13 02:15:31 BuildCreate it is
190 std::unique_ptr<webapk::CreateWebApkRequest> request(
191 new webapk::CreateWebApkRequest);
192
193 webapk::WebApk* webapk = request->mutable_webapk();
194 webapk->set_manifest_url(shortcut_info_.manifest_url.spec());
195 webapk->set_requester_application_package(
196 base::android::BuildInfo::GetInstance()->package_name());
197
198 webapk::WebAppManifest* web_app_manifest = webapk->mutable_manifest();
199 web_app_manifest->set_name(base::UTF16ToUTF8(shortcut_info_.name));
200 web_app_manifest->set_short_name(
201 base::UTF16ToUTF8(shortcut_info_.short_name));
202 web_app_manifest->set_start_url(shortcut_info_.url.spec());
203 web_app_manifest->set_orientation(
204 OrientationToString(shortcut_info_.orientation));
205 web_app_manifest->set_display_mode(DisplayToString(shortcut_info_.display));
206 web_app_manifest->set_background_color(shortcut_info_.background_color);
207 web_app_manifest->set_theme_color(shortcut_info_.theme_color);
208
209 std::string* scope = web_app_manifest->add_scope();
210 scope->assign(GetScope(shortcut_info_).spec());
211 webapk::Image* image = web_app_manifest->add_icon();
212 image->set_src(shortcut_info_.icon_url.spec());
213 // TODO(pkotwicz): Get MD5 hash of untransformed icon's bytes (with no
214 // encoding/decoding).
215 image->set_hash(ComputeBitmapHash(shortcut_icon_));
216 std::vector<unsigned char> png_bytes;
217 gfx::PNGCodec::EncodeBGRASkBitmap(shortcut_icon_, false, &png_bytes);
218 image->set_image_data(&png_bytes.front(), png_bytes.size());
219
220 return request;
221 }
222
223 void WebApkBuilder::OnTimeout() {
224 OnFailure();
Yaron 2016/07/13 00:24:01 what if we have an in-flight request? shouldn't it
pkotwicz 2016/07/13 02:15:31 Yes, I am relying on the destructor to cancel the
225 }
226
227 void WebApkBuilder::OnSuccess() {
228 finish_callback_.Run(true);
229 delete this;
230 }
231
232 void WebApkBuilder::OnFailure() {
233 finish_callback_.Run(false);
234 delete this;
235 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698