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

Side by Side Diff: chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.cc

Issue 2540013004: Allow an external URL with FROM_API qualifier to be forwarded to ARC (Closed)
Patch Set: address comment Created 4 years 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
1 // Copyright 2016 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog .h" 5 #include "chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog .h"
6 6
7 #include <memory> 7 #include <memory>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/lazy_instance.h"
10 #include "base/memory/ref_counted.h" 11 #include "base/memory/ref_counted.h"
11 #include "chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.h" 12 #include "chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.h"
12 #include "chrome/browser/chromeos/external_protocol_dialog.h" 13 #include "chrome/browser/chromeos/external_protocol_dialog.h"
13 #include "chrome/browser/tab_contents/tab_util.h" 14 #include "chrome/browser/tab_contents/tab_util.h"
14 #include "chrome/browser/ui/browser_dialogs.h" 15 #include "chrome/browser/ui/browser_dialogs.h"
15 #include "components/arc/arc_bridge_service.h" 16 #include "components/arc/arc_bridge_service.h"
16 #include "components/arc/arc_service_manager.h" 17 #include "components/arc/arc_service_manager.h"
17 #include "components/arc/intent_helper/activity_icon_loader.h" 18 #include "components/arc/intent_helper/activity_icon_loader.h"
18 #include "components/arc/intent_helper/arc_intent_helper_bridge.h" 19 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
19 #include "components/arc/intent_helper/page_transition_util.h" 20 #include "components/arc/intent_helper/page_transition_util.h"
(...skipping 10 matching lines...) Expand all
30 using content::WebContents; 31 using content::WebContents;
31 32
32 namespace arc { 33 namespace arc {
33 34
34 namespace { 35 namespace {
35 36
36 constexpr uint32_t kMinVersionForHandleUrl = 2; 37 constexpr uint32_t kMinVersionForHandleUrl = 2;
37 constexpr uint32_t kMinVersionForRequestUrlHandlerList = 2; 38 constexpr uint32_t kMinVersionForRequestUrlHandlerList = 2;
38 constexpr uint32_t kMinVersionForAddPreferredPackage = 7; 39 constexpr uint32_t kMinVersionForAddPreferredPackage = 7;
39 40
41 // TODO(yusukes|djacobo): Find a better way to detect a request loop and remove
42 // the global variables.
43 base::LazyInstance<GURL> g_last_url = LAZY_INSTANCE_INITIALIZER;
44 ui::PageTransition g_last_page_transition;
45
40 // Shows the Chrome OS' original external protocol dialog as a fallback. 46 // Shows the Chrome OS' original external protocol dialog as a fallback.
41 void ShowFallbackExternalProtocolDialog(int render_process_host_id, 47 void ShowFallbackExternalProtocolDialog(int render_process_host_id,
42 int routing_id, 48 int routing_id,
43 const GURL& url) { 49 const GURL& url) {
44 WebContents* web_contents = 50 WebContents* web_contents =
45 tab_util::GetWebContentsByID(render_process_host_id, routing_id); 51 tab_util::GetWebContentsByID(render_process_host_id, routing_id);
46 new ExternalProtocolDialog(web_contents, url); 52 new ExternalProtocolDialog(web_contents, url);
47 } 53 }
48 54
49 scoped_refptr<ActivityIconLoader> GetIconLoader() { 55 scoped_refptr<ActivityIconLoader> GetIconLoader() {
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 if (!instance) 95 if (!instance)
90 return; 96 return;
91 97
92 instance->HandleUrl(url_and_package.first.spec(), url_and_package.second); 98 instance->HandleUrl(url_and_package.first.spec(), url_and_package.second);
93 CloseTabIfNeeded(render_process_host_id, routing_id); 99 CloseTabIfNeeded(render_process_host_id, routing_id);
94 } 100 }
95 101
96 // A helper function called by GetAction(). 102 // A helper function called by GetAction().
97 GetActionResult GetActionInternal( 103 GetActionResult GetActionInternal(
98 const GURL& original_url, 104 const GURL& original_url,
105 bool always_ask_user,
99 const mojom::IntentHandlerInfoPtr& handler, 106 const mojom::IntentHandlerInfoPtr& handler,
100 std::pair<GURL, std::string>* out_url_and_package) { 107 std::pair<GURL, std::string>* out_url_and_package) {
101 if (handler->fallback_url.has_value()) { 108 if (handler->fallback_url.has_value()) {
102 *out_url_and_package = 109 *out_url_and_package =
103 std::make_pair(GURL(*handler->fallback_url), handler->package_name); 110 std::make_pair(GURL(*handler->fallback_url), handler->package_name);
104 if (ArcIntentHelperBridge::IsIntentHelperPackage(handler->package_name)) { 111 if (ArcIntentHelperBridge::IsIntentHelperPackage(handler->package_name)) {
105 // Since |package_name| is "Chrome", and |fallback_url| is not null, the 112 // Since |package_name| is "Chrome", and |fallback_url| is not null, the
106 // URL must be either http or https. Check it just in case, and if not, 113 // URL must be either http or https. Check it just in case, and if not,
107 // fallback to HANDLE_URL_IN_ARC; 114 // fallback to HANDLE_URL_IN_ARC;
108 if (out_url_and_package->first.SchemeIsHTTPOrHTTPS()) 115 if (out_url_and_package->first.SchemeIsHTTPOrHTTPS())
109 return GetActionResult::OPEN_URL_IN_CHROME; 116 return GetActionResult::OPEN_URL_IN_CHROME;
110 117
111 LOG(WARNING) << "Failed to handle " << out_url_and_package->first 118 LOG(WARNING) << "Failed to handle " << out_url_and_package->first
112 << " in Chrome. Falling back to ARC..."; 119 << " in Chrome. Falling back to ARC...";
113 } 120 }
114 // |fallback_url| which Chrome doesn't support is passed (e.g. market:). 121 // |fallback_url| which Chrome doesn't support is passed (e.g. market:).
115 return GetActionResult::HANDLE_URL_IN_ARC; 122 return always_ask_user ? GetActionResult::ASK_USER
123 : GetActionResult::HANDLE_URL_IN_ARC;
116 } 124 }
117 125
118 // Unlike |handler->fallback_url|, the |original_url| should always be handled 126 // Unlike |handler->fallback_url|, the |original_url| should always be handled
119 // in ARC since it's external to Chrome. 127 // in ARC since it's external to Chrome.
120 *out_url_and_package = std::make_pair(original_url, handler->package_name); 128 *out_url_and_package = std::make_pair(original_url, handler->package_name);
121 return GetActionResult::HANDLE_URL_IN_ARC; 129 return always_ask_user ? GetActionResult::ASK_USER
130 : GetActionResult::HANDLE_URL_IN_ARC;
122 } 131 }
123 132
124 // Gets an action that should be done when ARC has the |handlers| for the 133 // Gets an action that should be done when ARC has the |handlers| for the
125 // |original_url| and the user selects |selected_app_index|. When the user 134 // |original_url| and the user selects |selected_app_index|. When the user
126 // hasn't selected any app, |selected_app_index| must be set to 135 // hasn't selected any app, |selected_app_index| must be set to
127 // |handlers.size()|. 136 // |handlers.size()|. When |always_ask_user| is true, the function never
137 // returns HANDLE_URL_IN_ARC.
128 // 138 //
129 // When the returned action is either OPEN_URL_IN_CHROME or HANDLE_URL_IN_ARC, 139 // When the returned action is either OPEN_URL_IN_CHROME or HANDLE_URL_IN_ARC,
130 // |out_url_and_package| is filled accordingly. 140 // |out_url_and_package| is filled accordingly.
131 GetActionResult GetAction( 141 GetActionResult GetAction(
132 const GURL& original_url, 142 const GURL& original_url,
143 bool always_ask_user,
133 const std::vector<mojom::IntentHandlerInfoPtr>& handlers, 144 const std::vector<mojom::IntentHandlerInfoPtr>& handlers,
134 size_t selected_app_index, 145 size_t selected_app_index,
135 std::pair<GURL, std::string>* out_url_and_package) { 146 std::pair<GURL, std::string>* out_url_and_package) {
136 DCHECK(out_url_and_package); 147 DCHECK(out_url_and_package);
137 if (!handlers.size()) 148 if (!handlers.size())
138 return GetActionResult::SHOW_CHROME_OS_DIALOG; // no apps found. 149 return GetActionResult::SHOW_CHROME_OS_DIALOG; // no apps found.
139 150
140 if (selected_app_index == handlers.size()) { 151 if (selected_app_index == handlers.size()) {
141 // The user hasn't made the selection yet. 152 // The user hasn't made the selection yet.
142 153
143 // If |handlers| has only one element and its package is "Chrome", open 154 // If |handlers| has only one element and its package is "Chrome", open
144 // the fallback URL in the current tab without showing the dialog. 155 // the fallback URL in the current tab without showing the dialog.
145 if (handlers.size() == 1) { 156 if (handlers.size() == 1) {
146 if (GetActionInternal(original_url, handlers[0], out_url_and_package) == 157 if (GetActionInternal(original_url, always_ask_user, handlers[0],
158 out_url_and_package) ==
147 GetActionResult::OPEN_URL_IN_CHROME) { 159 GetActionResult::OPEN_URL_IN_CHROME) {
148 return GetActionResult::OPEN_URL_IN_CHROME; 160 return GetActionResult::OPEN_URL_IN_CHROME;
149 } 161 }
150 } 162 }
151 163
152 // If one of the apps is marked as preferred, use it right away without 164 // If one of the apps is marked as preferred, use it right away without
153 // showing the UI. |is_preferred| will never be true unless the user 165 // showing the UI. |is_preferred| will never be true unless the user
154 // explicitly makes it the default with the "always" button. 166 // explicitly makes it the default with the "always" button.
155 for (size_t i = 0; i < handlers.size(); ++i) { 167 for (size_t i = 0; i < handlers.size(); ++i) {
156 const mojom::IntentHandlerInfoPtr& handler = handlers[i]; 168 const mojom::IntentHandlerInfoPtr& handler = handlers[i];
157 if (!handler->is_preferred) 169 if (!handler->is_preferred)
158 continue; 170 continue;
159 // A preferred activity is found. Decide how to open it, either in Chrome 171 // A preferred activity is found. Decide how to open it, either in Chrome
160 // or ARC. 172 // or ARC.
161 return GetActionInternal(original_url, handler, out_url_and_package); 173 return GetActionInternal(original_url, always_ask_user, handler,
174 out_url_and_package);
162 } 175 }
163 // Ask the user to pick one. 176 // Ask the user to pick one.
164 return GetActionResult::ASK_USER; 177 return GetActionResult::ASK_USER;
165 } 178 }
166 179
167 // The user has already made the selection. Decide how to open it, either in 180 // The user has already made the selection. Decide how to open it, either in
168 // Chrome or ARC. 181 // Chrome or ARC.
169 return GetActionInternal(original_url, handlers[selected_app_index], 182 DCHECK(!always_ask_user)
183 << "|always_ask_user| must be false when |selected_app_index| is valid.";
184 return GetActionInternal(original_url, false, handlers[selected_app_index],
170 out_url_and_package); 185 out_url_and_package);
171 } 186 }
172 187
173 // Handles |url| if possible. Returns true if it is actually handled. 188 // Handles |url| if possible. Returns true if it is actually handled.
174 bool HandleUrl(int render_process_host_id, 189 bool HandleUrl(int render_process_host_id,
175 int routing_id, 190 int routing_id,
176 const GURL& url, 191 const GURL& url,
192 bool always_ask_user,
177 const std::vector<mojom::IntentHandlerInfoPtr>& handlers, 193 const std::vector<mojom::IntentHandlerInfoPtr>& handlers,
178 size_t selected_app_index, 194 size_t selected_app_index,
179 GetActionResult* out_result) { 195 GetActionResult* out_result) {
180 std::pair<GURL, std::string> url_and_package; 196 std::pair<GURL, std::string> url_and_package;
181 const GetActionResult result = 197 const GetActionResult result = GetAction(
182 GetAction(url, handlers, selected_app_index, &url_and_package); 198 url, always_ask_user, handlers, selected_app_index, &url_and_package);
183 if (out_result) 199 if (out_result)
184 *out_result = result; 200 *out_result = result;
185 201
186 switch (result) { 202 switch (result) {
187 case GetActionResult::SHOW_CHROME_OS_DIALOG: 203 case GetActionResult::SHOW_CHROME_OS_DIALOG:
188 ShowFallbackExternalProtocolDialog(render_process_host_id, routing_id, 204 ShowFallbackExternalProtocolDialog(render_process_host_id, routing_id,
189 url); 205 url);
190 return true; 206 return true;
191 case GetActionResult::OPEN_URL_IN_CHROME: 207 case GetActionResult::OPEN_URL_IN_CHROME:
192 OpenUrlInChrome(render_process_host_id, routing_id, 208 OpenUrlInChrome(render_process_host_id, routing_id,
193 url_and_package.first); 209 url_and_package.first);
194 return true; 210 return true;
195 case GetActionResult::HANDLE_URL_IN_ARC: 211 case GetActionResult::HANDLE_URL_IN_ARC:
196 HandleUrlInArc(render_process_host_id, routing_id, url_and_package); 212 HandleUrlInArc(render_process_host_id, routing_id, url_and_package);
197 return true; 213 return true;
198 case GetActionResult::ASK_USER: 214 case GetActionResult::ASK_USER:
199 break; 215 break;
200 } 216 }
201 return false; 217 return false;
202 } 218 }
203 219
204 // Returns a fallback http(s) in |handlers| which Chrome can handle. Returns 220 // Returns a fallback http(s) in |handlers| which Chrome can handle. Returns
205 // an empty GURL if none found. 221 // an empty GURL if none found.
206 GURL GetUrlToNavigateOnDeactivate( 222 GURL GetUrlToNavigateOnDeactivate(
207 const std::vector<mojom::IntentHandlerInfoPtr>& handlers) { 223 const std::vector<mojom::IntentHandlerInfoPtr>& handlers) {
208 const GURL empty_url; 224 const GURL empty_url;
209 for (size_t i = 0; i < handlers.size(); ++i) { 225 for (size_t i = 0; i < handlers.size(); ++i) {
210 std::pair<GURL, std::string> url_and_package; 226 std::pair<GURL, std::string> url_and_package;
211 if (GetActionInternal(empty_url, handlers[i], &url_and_package) == 227 if (GetActionInternal(empty_url, false, handlers[i], &url_and_package) ==
212 GetActionResult::OPEN_URL_IN_CHROME) { 228 GetActionResult::OPEN_URL_IN_CHROME) {
213 DCHECK(url_and_package.first.SchemeIsHTTPOrHTTPS()); 229 DCHECK(url_and_package.first.SchemeIsHTTPOrHTTPS());
214 return url_and_package.first; 230 return url_and_package.first;
215 } 231 }
216 } 232 }
217 return empty_url; // nothing found. 233 return empty_url; // nothing found.
218 } 234 }
219 235
220 // Called when the dialog is just deactivated without pressing one of the 236 // Called when the dialog is just deactivated without pressing one of the
221 // buttons. 237 // buttons.
(...skipping 24 matching lines...) Expand all
246 ArcNavigationThrottle::GetAppIndex(handlers, selected_app_package); 262 ArcNavigationThrottle::GetAppIndex(handlers, selected_app_package);
247 // Make sure that the instance at least supports HandleUrl. 263 // Make sure that the instance at least supports HandleUrl.
248 auto* instance = ArcIntentHelperBridge::GetIntentHelperInstance( 264 auto* instance = ArcIntentHelperBridge::GetIntentHelperInstance(
249 "HandleUrl", kMinVersionForHandleUrl); 265 "HandleUrl", kMinVersionForHandleUrl);
250 if (!instance) { 266 if (!instance) {
251 close_reason = ArcNavigationThrottle::CloseReason::ERROR; 267 close_reason = ArcNavigationThrottle::CloseReason::ERROR;
252 } else if (close_reason == 268 } else if (close_reason ==
253 ArcNavigationThrottle::CloseReason::JUST_ONCE_PRESSED || 269 ArcNavigationThrottle::CloseReason::JUST_ONCE_PRESSED ||
254 close_reason == 270 close_reason ==
255 ArcNavigationThrottle::CloseReason::ALWAYS_PRESSED) { 271 ArcNavigationThrottle::CloseReason::ALWAYS_PRESSED) {
256 if (selected_app_index == handlers.size()) 272 if (selected_app_index == handlers.size()) {
257 close_reason = ArcNavigationThrottle::CloseReason::ERROR; 273 close_reason = ArcNavigationThrottle::CloseReason::ERROR;
274 } else {
275 // The user has made a selection. Clear g_last_* variables.
276 g_last_url.Get() = GURL();
277 g_last_page_transition = ui::PageTransition();
278 }
258 } 279 }
259 280
260 switch (close_reason) { 281 switch (close_reason) {
261 case ArcNavigationThrottle::CloseReason::ALWAYS_PRESSED: { 282 case ArcNavigationThrottle::CloseReason::ALWAYS_PRESSED: {
262 if (ArcIntentHelperBridge::GetIntentHelperInstance( 283 if (ArcIntentHelperBridge::GetIntentHelperInstance(
263 "AddPreferredPackage", kMinVersionForAddPreferredPackage)) { 284 "AddPreferredPackage", kMinVersionForAddPreferredPackage)) {
264 instance->AddPreferredPackage( 285 instance->AddPreferredPackage(
265 handlers[selected_app_index]->package_name); 286 handlers[selected_app_index]->package_name);
266 } 287 }
267 // fall through. 288 // fall through.
268 } 289 }
269 case ArcNavigationThrottle::CloseReason::JUST_ONCE_PRESSED: { 290 case ArcNavigationThrottle::CloseReason::JUST_ONCE_PRESSED: {
270 // Launch the selected app. 291 // Launch the selected app.
271 HandleUrl(render_process_host_id, routing_id, url, handlers, 292 HandleUrl(render_process_host_id, routing_id, url, false, handlers,
272 selected_app_index, nullptr); 293 selected_app_index, nullptr);
273 break; 294 break;
274 } 295 }
275 case ArcNavigationThrottle::CloseReason::PREFERRED_ACTIVITY_FOUND: 296 case ArcNavigationThrottle::CloseReason::PREFERRED_ACTIVITY_FOUND:
276 case ArcNavigationThrottle::CloseReason::INVALID: { 297 case ArcNavigationThrottle::CloseReason::INVALID: {
277 NOTREACHED(); 298 NOTREACHED();
278 return; // no UMA recording. 299 return; // no UMA recording.
279 } 300 }
280 case ArcNavigationThrottle::CloseReason::ERROR: { 301 case ArcNavigationThrottle::CloseReason::ERROR: {
281 LOG(ERROR) << "IntentPickerBubbleView returned CloseReason::ERROR: " 302 LOG(ERROR) << "IntentPickerBubbleView returned CloseReason::ERROR: "
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
324 tab_util::GetWebContentsByID(render_process_host_id, routing_id); 345 tab_util::GetWebContentsByID(render_process_host_id, routing_id);
325 show_bubble_cb.Run(web_contents, app_info, 346 show_bubble_cb.Run(web_contents, app_info,
326 base::Bind(OnIntentPickerClosed, render_process_host_id, 347 base::Bind(OnIntentPickerClosed, render_process_host_id,
327 routing_id, url, base::Passed(&handlers))); 348 routing_id, url, base::Passed(&handlers)));
328 } 349 }
329 350
330 // Called when ARC returned a handler list for the |url|. 351 // Called when ARC returned a handler list for the |url|.
331 void OnUrlHandlerList(int render_process_host_id, 352 void OnUrlHandlerList(int render_process_host_id,
332 int routing_id, 353 int routing_id,
333 const GURL& url, 354 const GURL& url,
355 bool always_ask_user,
334 std::vector<mojom::IntentHandlerInfoPtr> handlers) { 356 std::vector<mojom::IntentHandlerInfoPtr> handlers) {
335 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 357 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
336 358
337 auto* instance = ArcIntentHelperBridge::GetIntentHelperInstance( 359 auto* instance = ArcIntentHelperBridge::GetIntentHelperInstance(
338 "HandleUrl", kMinVersionForHandleUrl); 360 "HandleUrl", kMinVersionForHandleUrl);
339 scoped_refptr<ActivityIconLoader> icon_loader = GetIconLoader(); 361 scoped_refptr<ActivityIconLoader> icon_loader = GetIconLoader();
340 362
341 if (!instance || !icon_loader) { 363 if (!instance || !icon_loader) {
342 // ARC is not running anymore. Show the Chrome OS dialog. 364 // ARC is not running anymore. Show the Chrome OS dialog.
343 ShowFallbackExternalProtocolDialog(render_process_host_id, routing_id, url); 365 ShowFallbackExternalProtocolDialog(render_process_host_id, routing_id, url);
344 return; 366 return;
345 } 367 }
346 368
347 // Check if the |url| should be handled right away without showing the UI. 369 // Check if the |url| should be handled right away without showing the UI.
348 GetActionResult result; 370 GetActionResult result;
349 if (HandleUrl(render_process_host_id, routing_id, url, handlers, 371 if (HandleUrl(render_process_host_id, routing_id, url, always_ask_user,
350 handlers.size(), &result)) { 372 handlers, handlers.size(), &result)) {
351 if (result == GetActionResult::HANDLE_URL_IN_ARC) { 373 if (result == GetActionResult::HANDLE_URL_IN_ARC) {
352 ArcNavigationThrottle::RecordUma( 374 ArcNavigationThrottle::RecordUma(
353 ArcNavigationThrottle::CloseReason::PREFERRED_ACTIVITY_FOUND, 375 ArcNavigationThrottle::CloseReason::PREFERRED_ACTIVITY_FOUND,
354 ArcNavigationThrottle::Platform::ARC); 376 ArcNavigationThrottle::Platform::ARC);
355 } 377 }
356 return; // the |url| has been handled. 378 return; // the |url| has been handled.
357 } 379 }
358 380
359 // Otherwise, retrieve icons of the activities. First, swap |handler| elements 381 // Otherwise, retrieve icons of the activities. First, swap |handler| elements
360 // to ensure Chrome is visible in the UI by default. Since this function is 382 // to ensure Chrome is visible in the UI by default. Since this function is
361 // for handling external protocols, Chrome is rarely in the list, but if the 383 // for handling external protocols, Chrome is rarely in the list, but if the
362 // |url| is intent: with fallback or geo:, for example, it may be. 384 // |url| is intent: with fallback or geo:, for example, it may be.
363 std::pair<size_t, size_t> indices; 385 std::pair<size_t, size_t> indices;
364 if (ArcNavigationThrottle::IsSwapElementsNeeded(handlers, &indices)) 386 if (ArcNavigationThrottle::IsSwapElementsNeeded(handlers, &indices))
365 std::swap(handlers[indices.first], handlers[indices.second]); 387 std::swap(handlers[indices.first], handlers[indices.second]);
366 388
367 // Then request the icons. 389 // Then request the icons.
368 std::vector<ActivityIconLoader::ActivityName> activities; 390 std::vector<ActivityIconLoader::ActivityName> activities;
369 for (const auto& handler : handlers) { 391 for (const auto& handler : handlers) {
370 activities.emplace_back(handler->package_name, handler->activity_name); 392 activities.emplace_back(handler->package_name, handler->activity_name);
371 } 393 }
372 icon_loader->GetActivityIcons( 394 icon_loader->GetActivityIcons(
373 activities, base::Bind(OnAppIconsReceived, render_process_host_id, 395 activities, base::Bind(OnAppIconsReceived, render_process_host_id,
374 routing_id, url, base::Passed(&handlers))); 396 routing_id, url, base::Passed(&handlers)));
375 } 397 }
376 398
399 // Returns true if the |url| is safe to be forwarded to ARC without showing the
400 // disambig dialog when there is a preferred app on ARC for the |url|. Note that
401 // this function almost always returns true (i.e. "safe") except for very rare
402 // situations mentioned below.
403 // TODO(yusukes|djacobo): Find a better way to detect a request loop and remove
404 // these heuristics.
405 bool IsSafeToRedirectToArcWithoutUserConfirmation(
406 const GURL& url,
407 ui::PageTransition page_transition,
408 const GURL& last_url,
409 ui::PageTransition last_page_transition) {
410 // Return "safe" unless both transition flags are FROM_API because the only
411 // unsafe situation we know is infinite tab creation loop with FROM_API
412 // (b/30125340).
413 if (!(page_transition & ui::PAGE_TRANSITION_FROM_API) ||
414 !(last_page_transition & ui::PAGE_TRANSITION_FROM_API)) {
415 return true;
416 }
417
418 // Return "safe" unless both URLs are for the same app.
419 return url.scheme() != last_url.scheme();
420 }
421
377 } // namespace 422 } // namespace
378 423
379 bool RunArcExternalProtocolDialog(const GURL& url, 424 bool RunArcExternalProtocolDialog(const GURL& url,
380 int render_process_host_id, 425 int render_process_host_id,
381 int routing_id, 426 int routing_id,
382 ui::PageTransition page_transition, 427 ui::PageTransition page_transition,
383 bool has_user_gesture) { 428 bool has_user_gesture) {
384 // This function is for external protocols that Chrome cannot handle. 429 // This function is for external protocols that Chrome cannot handle.
385 DCHECK(!url.SchemeIsHTTPOrHTTPS()) << url; 430 DCHECK(!url.SchemeIsHTTPOrHTTPS()) << url;
386 431
387 if (ShouldIgnoreNavigation(page_transition, true /* allow_form_submit */, 432 const bool always_ask_user = !IsSafeToRedirectToArcWithoutUserConfirmation(
433 url, page_transition, g_last_url.Get(), g_last_page_transition);
434 LOG_IF(WARNING, always_ask_user)
435 << "RunArcExternalProtocolDialog: repeatedly handling external protocol "
436 << "redirection to " << url
437 << " started from API: last_url=" << g_last_url.Get();
438
439 // This function is called only on the UI thread. Updating g_last_* variables
440 // without a lock is safe.
441 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
442 g_last_url.Get() = url;
443 g_last_page_transition = page_transition;
444
445 // For external protocol navigation, always ignore the FROM_API qualifier.
446 // We sometimes do need to forward a request with FROM_API to ARC, or
447 // AppAuth may not work (b/33208965). This is safe as long as we properly
448 // use |always_ask_user|.
449 const ui::PageTransition masked_page_transition =
450 MaskOutPageTransition(page_transition, ui::PAGE_TRANSITION_FROM_API);
451
452 if (ShouldIgnoreNavigation(masked_page_transition,
453 true /* allow_form_submit */,
388 true /* allow_client_redirect */)) { 454 true /* allow_client_redirect */)) {
389 LOG(WARNING) << "RunArcExternalProtocolDialog: ignoring " << url 455 LOG(WARNING) << "RunArcExternalProtocolDialog: ignoring " << url
390 << " with PageTransition=" << page_transition; 456 << " with PageTransition=" << masked_page_transition;
391 return false; 457 return false;
392 } 458 }
393 459
394 auto* instance = ArcIntentHelperBridge::GetIntentHelperInstance( 460 auto* instance = ArcIntentHelperBridge::GetIntentHelperInstance(
395 "RequestUrlHandlerList", kMinVersionForRequestUrlHandlerList); 461 "RequestUrlHandlerList", kMinVersionForRequestUrlHandlerList);
396 if (!instance) 462 if (!instance)
397 return false; // ARC is either not supported or not yet ready. 463 return false; // ARC is either not supported or not yet ready.
398 464
399 WebContents* web_contents = 465 WebContents* web_contents =
400 tab_util::GetWebContentsByID(render_process_host_id, routing_id); 466 tab_util::GetWebContentsByID(render_process_host_id, routing_id);
401 if (!web_contents || !web_contents->GetBrowserContext() || 467 if (!web_contents || !web_contents->GetBrowserContext() ||
402 web_contents->GetBrowserContext()->IsOffTheRecord()) { 468 web_contents->GetBrowserContext()->IsOffTheRecord()) {
403 return false; 469 return false;
404 } 470 }
405 471
406 // Show ARC version of the dialog, which is IntentPickerBubbleView. To show 472 // Show ARC version of the dialog, which is IntentPickerBubbleView. To show
407 // the bubble view, we need to ask ARC for a handler list first. 473 // the bubble view, we need to ask ARC for a handler list first.
408 instance->RequestUrlHandlerList( 474 instance->RequestUrlHandlerList(
409 url.spec(), 475 url.spec(), base::Bind(OnUrlHandlerList, render_process_host_id,
410 base::Bind(OnUrlHandlerList, render_process_host_id, routing_id, url)); 476 routing_id, url, always_ask_user));
411 return true; 477 return true;
412 } 478 }
413 479
414 GetActionResult GetActionForTesting( 480 GetActionResult GetActionForTesting(
415 const GURL& original_url, 481 const GURL& original_url,
482 bool always_ask_user,
416 const std::vector<mojom::IntentHandlerInfoPtr>& handlers, 483 const std::vector<mojom::IntentHandlerInfoPtr>& handlers,
417 size_t selected_app_index, 484 size_t selected_app_index,
418 std::pair<GURL, std::string>* out_url_and_package) { 485 std::pair<GURL, std::string>* out_url_and_package) {
419 return GetAction(original_url, handlers, selected_app_index, 486 return GetAction(original_url, always_ask_user, handlers, selected_app_index,
420 out_url_and_package); 487 out_url_and_package);
421 } 488 }
422 489
423 GURL GetUrlToNavigateOnDeactivateForTesting( 490 GURL GetUrlToNavigateOnDeactivateForTesting(
424 const std::vector<mojom::IntentHandlerInfoPtr>& handlers) { 491 const std::vector<mojom::IntentHandlerInfoPtr>& handlers) {
425 return GetUrlToNavigateOnDeactivate(handlers); 492 return GetUrlToNavigateOnDeactivate(handlers);
426 } 493 }
427 494
495 bool IsSafeToRedirectToArcWithoutUserConfirmationForTesting(
496 const GURL& url,
497 ui::PageTransition page_transition,
498 const GURL& last_url,
499 ui::PageTransition last_page_transition) {
500 return IsSafeToRedirectToArcWithoutUserConfirmation(
501 url, page_transition, last_url, last_page_transition);
502 }
503
428 } // namespace arc 504 } // namespace arc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698