| OLD | NEW |
| 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 #include <utility> | |
| 9 #include <vector> | |
| 10 | 8 |
| 11 #include "base/bind.h" | 9 #include "base/bind.h" |
| 12 #include "base/memory/ref_counted.h" | 10 #include "base/memory/ref_counted.h" |
| 13 #include "chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.h" | 11 #include "chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.h" |
| 14 #include "chrome/browser/chromeos/external_protocol_dialog.h" | 12 #include "chrome/browser/chromeos/external_protocol_dialog.h" |
| 15 #include "chrome/browser/tab_contents/tab_util.h" | 13 #include "chrome/browser/tab_contents/tab_util.h" |
| 16 #include "chrome/browser/ui/browser_dialogs.h" | 14 #include "chrome/browser/ui/browser_dialogs.h" |
| 17 #include "components/arc/arc_bridge_service.h" | 15 #include "components/arc/arc_bridge_service.h" |
| 18 #include "components/arc/arc_service_manager.h" | 16 #include "components/arc/arc_service_manager.h" |
| 19 #include "components/arc/intent_helper/activity_icon_loader.h" | 17 #include "components/arc/intent_helper/activity_icon_loader.h" |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 93 | 91 |
| 94 instance->HandleUrl(url_and_package.first.spec(), url_and_package.second); | 92 instance->HandleUrl(url_and_package.first.spec(), url_and_package.second); |
| 95 CloseTabIfNeeded(render_process_host_id, routing_id); | 93 CloseTabIfNeeded(render_process_host_id, routing_id); |
| 96 } | 94 } |
| 97 | 95 |
| 98 // A helper function called by GetAction(). | 96 // A helper function called by GetAction(). |
| 99 GetActionResult GetActionInternal( | 97 GetActionResult GetActionInternal( |
| 100 const GURL& original_url, | 98 const GURL& original_url, |
| 101 const mojom::IntentHandlerInfoPtr& handler, | 99 const mojom::IntentHandlerInfoPtr& handler, |
| 102 std::pair<GURL, std::string>* out_url_and_package) { | 100 std::pair<GURL, std::string>* out_url_and_package) { |
| 103 if (!handler->fallback_url.is_null()) { | 101 if (handler->fallback_url.has_value()) { |
| 104 *out_url_and_package = std::make_pair(GURL(handler->fallback_url.get()), | 102 *out_url_and_package = |
| 105 handler->package_name.get()); | 103 std::make_pair(GURL(*handler->fallback_url), handler->package_name); |
| 106 if (ArcIntentHelperBridge::IsIntentHelperPackage(handler->package_name)) { | 104 if (ArcIntentHelperBridge::IsIntentHelperPackage(handler->package_name)) { |
| 107 // Since |package_name| is "Chrome", and |fallback_url| is not null, the | 105 // Since |package_name| is "Chrome", and |fallback_url| is not null, the |
| 108 // URL must be either http or https. Check it just in case, and if not, | 106 // URL must be either http or https. Check it just in case, and if not, |
| 109 // fallback to HANDLE_URL_IN_ARC; | 107 // fallback to HANDLE_URL_IN_ARC; |
| 110 if (out_url_and_package->first.SchemeIsHTTPOrHTTPS()) | 108 if (out_url_and_package->first.SchemeIsHTTPOrHTTPS()) |
| 111 return GetActionResult::OPEN_URL_IN_CHROME; | 109 return GetActionResult::OPEN_URL_IN_CHROME; |
| 112 | 110 |
| 113 LOG(WARNING) << "Failed to handle " << out_url_and_package->first | 111 LOG(WARNING) << "Failed to handle " << out_url_and_package->first |
| 114 << " in Chrome. Falling back to ARC..."; | 112 << " in Chrome. Falling back to ARC..."; |
| 115 } | 113 } |
| 116 // |fallback_url| which Chrome doesn't support is passed (e.g. market:). | 114 // |fallback_url| which Chrome doesn't support is passed (e.g. market:). |
| 117 return GetActionResult::HANDLE_URL_IN_ARC; | 115 return GetActionResult::HANDLE_URL_IN_ARC; |
| 118 } | 116 } |
| 119 | 117 |
| 120 // Unlike |handler->fallback_url|, the |original_url| should always be handled | 118 // Unlike |handler->fallback_url|, the |original_url| should always be handled |
| 121 // in ARC since it's external to Chrome. | 119 // in ARC since it's external to Chrome. |
| 122 *out_url_and_package = | 120 *out_url_and_package = std::make_pair(original_url, handler->package_name); |
| 123 std::make_pair(original_url, handler->package_name.get()); | |
| 124 return GetActionResult::HANDLE_URL_IN_ARC; | 121 return GetActionResult::HANDLE_URL_IN_ARC; |
| 125 } | 122 } |
| 126 | 123 |
| 127 // Gets an action that should be done when ARC has the |handlers| for the | 124 // Gets an action that should be done when ARC has the |handlers| for the |
| 128 // |original_url| and the user selects |selected_app_index|. When the user | 125 // |original_url| and the user selects |selected_app_index|. When the user |
| 129 // hasn't selected any app, |selected_app_index| must be set to | 126 // hasn't selected any app, |selected_app_index| must be set to |
| 130 // |handlers.size()|. | 127 // |handlers.size()|. |
| 131 // | 128 // |
| 132 // When the returned action is either OPEN_URL_IN_CHROME or HANDLE_URL_IN_ARC, | 129 // When the returned action is either OPEN_URL_IN_CHROME or HANDLE_URL_IN_ARC, |
| 133 // |out_url_and_package| is filled accordingly. | 130 // |out_url_and_package| is filled accordingly. |
| 134 GetActionResult GetAction( | 131 GetActionResult GetAction( |
| 135 const GURL& original_url, | 132 const GURL& original_url, |
| 136 const mojo::Array<mojom::IntentHandlerInfoPtr>& handlers, | 133 const std::vector<mojom::IntentHandlerInfoPtr>& handlers, |
| 137 size_t selected_app_index, | 134 size_t selected_app_index, |
| 138 std::pair<GURL, std::string>* out_url_and_package) { | 135 std::pair<GURL, std::string>* out_url_and_package) { |
| 139 DCHECK(out_url_and_package); | 136 DCHECK(out_url_and_package); |
| 140 if (!handlers.size()) | 137 if (!handlers.size()) |
| 141 return GetActionResult::SHOW_CHROME_OS_DIALOG; // no apps found. | 138 return GetActionResult::SHOW_CHROME_OS_DIALOG; // no apps found. |
| 142 | 139 |
| 143 if (selected_app_index == handlers.size()) { | 140 if (selected_app_index == handlers.size()) { |
| 144 // The user hasn't made the selection yet. | 141 // The user hasn't made the selection yet. |
| 145 | 142 |
| 146 // If |handlers| has only one element and its package is "Chrome", open | 143 // If |handlers| has only one element and its package is "Chrome", open |
| (...skipping 23 matching lines...) Expand all Loading... |
| 170 // The user has already made the selection. Decide how to open it, either in | 167 // The user has already made the selection. Decide how to open it, either in |
| 171 // Chrome or ARC. | 168 // Chrome or ARC. |
| 172 return GetActionInternal(original_url, handlers[selected_app_index], | 169 return GetActionInternal(original_url, handlers[selected_app_index], |
| 173 out_url_and_package); | 170 out_url_and_package); |
| 174 } | 171 } |
| 175 | 172 |
| 176 // Handles |url| if possible. Returns true if it is actually handled. | 173 // Handles |url| if possible. Returns true if it is actually handled. |
| 177 bool HandleUrl(int render_process_host_id, | 174 bool HandleUrl(int render_process_host_id, |
| 178 int routing_id, | 175 int routing_id, |
| 179 const GURL& url, | 176 const GURL& url, |
| 180 const mojo::Array<mojom::IntentHandlerInfoPtr>& handlers, | 177 const std::vector<mojom::IntentHandlerInfoPtr>& handlers, |
| 181 size_t selected_app_index, | 178 size_t selected_app_index, |
| 182 GetActionResult* out_result) { | 179 GetActionResult* out_result) { |
| 183 std::pair<GURL, std::string> url_and_package; | 180 std::pair<GURL, std::string> url_and_package; |
| 184 const GetActionResult result = | 181 const GetActionResult result = |
| 185 GetAction(url, handlers, selected_app_index, &url_and_package); | 182 GetAction(url, handlers, selected_app_index, &url_and_package); |
| 186 if (out_result) | 183 if (out_result) |
| 187 *out_result = result; | 184 *out_result = result; |
| 188 | 185 |
| 189 switch (result) { | 186 switch (result) { |
| 190 case GetActionResult::SHOW_CHROME_OS_DIALOG: | 187 case GetActionResult::SHOW_CHROME_OS_DIALOG: |
| 191 ShowFallbackExternalProtocolDialog(render_process_host_id, routing_id, | 188 ShowFallbackExternalProtocolDialog(render_process_host_id, routing_id, |
| 192 url); | 189 url); |
| 193 return true; | 190 return true; |
| 194 case GetActionResult::OPEN_URL_IN_CHROME: | 191 case GetActionResult::OPEN_URL_IN_CHROME: |
| 195 OpenUrlInChrome(render_process_host_id, routing_id, | 192 OpenUrlInChrome(render_process_host_id, routing_id, |
| 196 url_and_package.first); | 193 url_and_package.first); |
| 197 return true; | 194 return true; |
| 198 case GetActionResult::HANDLE_URL_IN_ARC: | 195 case GetActionResult::HANDLE_URL_IN_ARC: |
| 199 HandleUrlInArc(render_process_host_id, routing_id, url_and_package); | 196 HandleUrlInArc(render_process_host_id, routing_id, url_and_package); |
| 200 return true; | 197 return true; |
| 201 case GetActionResult::ASK_USER: | 198 case GetActionResult::ASK_USER: |
| 202 break; | 199 break; |
| 203 } | 200 } |
| 204 return false; | 201 return false; |
| 205 } | 202 } |
| 206 | 203 |
| 207 // Returns a fallback http(s) in |handlers| which Chrome can handle. Returns | 204 // Returns a fallback http(s) in |handlers| which Chrome can handle. Returns |
| 208 // an empty GURL if none found. | 205 // an empty GURL if none found. |
| 209 GURL GetUrlToNavigateOnDeactivate( | 206 GURL GetUrlToNavigateOnDeactivate( |
| 210 const mojo::Array<mojom::IntentHandlerInfoPtr>& handlers) { | 207 const std::vector<mojom::IntentHandlerInfoPtr>& handlers) { |
| 211 const GURL empty_url; | 208 const GURL empty_url; |
| 212 for (size_t i = 0; i < handlers.size(); ++i) { | 209 for (size_t i = 0; i < handlers.size(); ++i) { |
| 213 std::pair<GURL, std::string> url_and_package; | 210 std::pair<GURL, std::string> url_and_package; |
| 214 if (GetActionInternal(empty_url, handlers[i], &url_and_package) == | 211 if (GetActionInternal(empty_url, handlers[i], &url_and_package) == |
| 215 GetActionResult::OPEN_URL_IN_CHROME) { | 212 GetActionResult::OPEN_URL_IN_CHROME) { |
| 216 DCHECK(url_and_package.first.SchemeIsHTTPOrHTTPS()); | 213 DCHECK(url_and_package.first.SchemeIsHTTPOrHTTPS()); |
| 217 return url_and_package.first; | 214 return url_and_package.first; |
| 218 } | 215 } |
| 219 } | 216 } |
| 220 return empty_url; // nothing found. | 217 return empty_url; // nothing found. |
| 221 } | 218 } |
| 222 | 219 |
| 223 // Called when the dialog is just deactivated without pressing one of the | 220 // Called when the dialog is just deactivated without pressing one of the |
| 224 // buttons. | 221 // buttons. |
| 225 void OnIntentPickerDialogDeactivated( | 222 void OnIntentPickerDialogDeactivated( |
| 226 int render_process_host_id, | 223 int render_process_host_id, |
| 227 int routing_id, | 224 int routing_id, |
| 228 const mojo::Array<mojom::IntentHandlerInfoPtr>& handlers) { | 225 const std::vector<mojom::IntentHandlerInfoPtr>& handlers) { |
| 229 const GURL url_to_open_in_chrome = GetUrlToNavigateOnDeactivate(handlers); | 226 const GURL url_to_open_in_chrome = GetUrlToNavigateOnDeactivate(handlers); |
| 230 if (url_to_open_in_chrome.is_empty()) | 227 if (url_to_open_in_chrome.is_empty()) |
| 231 CloseTabIfNeeded(render_process_host_id, routing_id); | 228 CloseTabIfNeeded(render_process_host_id, routing_id); |
| 232 else | 229 else |
| 233 OpenUrlInChrome(render_process_host_id, routing_id, url_to_open_in_chrome); | 230 OpenUrlInChrome(render_process_host_id, routing_id, url_to_open_in_chrome); |
| 234 } | 231 } |
| 235 | 232 |
| 236 // Called when the dialog is closed. Note that once we show the UI, we should | 233 // Called when the dialog is closed. Note that once we show the UI, we should |
| 237 // never show the Chrome OS' fallback dialog. | 234 // never show the Chrome OS' fallback dialog. |
| 238 void OnIntentPickerClosed(int render_process_host_id, | 235 void OnIntentPickerClosed(int render_process_host_id, |
| 239 int routing_id, | 236 int routing_id, |
| 240 const GURL& url, | 237 const GURL& url, |
| 241 mojo::Array<mojom::IntentHandlerInfoPtr> handlers, | 238 std::vector<mojom::IntentHandlerInfoPtr> handlers, |
| 242 const std::string& selected_app_package, | 239 const std::string& selected_app_package, |
| 243 ArcNavigationThrottle::CloseReason close_reason) { | 240 ArcNavigationThrottle::CloseReason close_reason) { |
| 244 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 241 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 245 | 242 |
| 246 // If the user selected an app to continue the navigation, confirm that the | 243 // If the user selected an app to continue the navigation, confirm that the |
| 247 // |package_name| matches a valid option and return the index. | 244 // |package_name| matches a valid option and return the index. |
| 248 const size_t selected_app_index = | 245 const size_t selected_app_index = |
| 249 ArcNavigationThrottle::GetAppIndex(handlers, selected_app_package); | 246 ArcNavigationThrottle::GetAppIndex(handlers, selected_app_package); |
| 250 // Make sure that the instance at least supports HandleUrl. | 247 // Make sure that the instance at least supports HandleUrl. |
| 251 auto* instance = ArcIntentHelperBridge::GetIntentHelperInstance( | 248 auto* instance = ArcIntentHelperBridge::GetIntentHelperInstance( |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 299 ArcNavigationThrottle::GetDestinationPlatform(selected_app_package, | 296 ArcNavigationThrottle::GetDestinationPlatform(selected_app_package, |
| 300 close_reason); | 297 close_reason); |
| 301 ArcNavigationThrottle::RecordUma(close_reason, platform); | 298 ArcNavigationThrottle::RecordUma(close_reason, platform); |
| 302 } | 299 } |
| 303 | 300 |
| 304 // Called when ARC returned activity icons for the |handlers|. | 301 // Called when ARC returned activity icons for the |handlers|. |
| 305 void OnAppIconsReceived( | 302 void OnAppIconsReceived( |
| 306 int render_process_host_id, | 303 int render_process_host_id, |
| 307 int routing_id, | 304 int routing_id, |
| 308 const GURL& url, | 305 const GURL& url, |
| 309 mojo::Array<mojom::IntentHandlerInfoPtr> handlers, | 306 std::vector<mojom::IntentHandlerInfoPtr> handlers, |
| 310 std::unique_ptr<ActivityIconLoader::ActivityToIconsMap> icons) { | 307 std::unique_ptr<ActivityIconLoader::ActivityToIconsMap> icons) { |
| 311 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 308 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 312 | 309 |
| 313 using AppInfo = arc::ArcNavigationThrottle::AppInfo; | 310 using AppInfo = arc::ArcNavigationThrottle::AppInfo; |
| 314 std::vector<AppInfo> app_info; | 311 std::vector<AppInfo> app_info; |
| 315 | 312 |
| 316 for (const auto& handler : handlers) { | 313 for (const auto& handler : handlers) { |
| 317 const ActivityIconLoader::ActivityName activity(handler->package_name, | 314 const ActivityIconLoader::ActivityName activity(handler->package_name, |
| 318 handler->activity_name); | 315 handler->activity_name); |
| 319 const auto it = icons->find(activity); | 316 const auto it = icons->find(activity); |
| 320 app_info.emplace_back( | 317 app_info.emplace_back( |
| 321 AppInfo(it != icons->end() ? it->second.icon20 : gfx::Image(), | 318 AppInfo(it != icons->end() ? it->second.icon20 : gfx::Image(), |
| 322 handler->package_name, handler->name)); | 319 handler->package_name, handler->name)); |
| 323 } | 320 } |
| 324 | 321 |
| 325 auto show_bubble_cb = base::Bind(ShowIntentPickerBubble()); | 322 auto show_bubble_cb = base::Bind(ShowIntentPickerBubble()); |
| 326 WebContents* web_contents = | 323 WebContents* web_contents = |
| 327 tab_util::GetWebContentsByID(render_process_host_id, routing_id); | 324 tab_util::GetWebContentsByID(render_process_host_id, routing_id); |
| 328 show_bubble_cb.Run(web_contents, app_info, | 325 show_bubble_cb.Run(web_contents, app_info, |
| 329 base::Bind(OnIntentPickerClosed, render_process_host_id, | 326 base::Bind(OnIntentPickerClosed, render_process_host_id, |
| 330 routing_id, url, base::Passed(&handlers))); | 327 routing_id, url, base::Passed(&handlers))); |
| 331 } | 328 } |
| 332 | 329 |
| 333 // Called when ARC returned a handler list for the |url|. | 330 // Called when ARC returned a handler list for the |url|. |
| 334 void OnUrlHandlerList(int render_process_host_id, | 331 void OnUrlHandlerList(int render_process_host_id, |
| 335 int routing_id, | 332 int routing_id, |
| 336 const GURL& url, | 333 const GURL& url, |
| 337 mojo::Array<mojom::IntentHandlerInfoPtr> handlers) { | 334 std::vector<mojom::IntentHandlerInfoPtr> handlers) { |
| 338 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 335 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 339 | 336 |
| 340 auto* instance = ArcIntentHelperBridge::GetIntentHelperInstance( | 337 auto* instance = ArcIntentHelperBridge::GetIntentHelperInstance( |
| 341 "HandleUrl", kMinVersionForHandleUrl); | 338 "HandleUrl", kMinVersionForHandleUrl); |
| 342 scoped_refptr<ActivityIconLoader> icon_loader = GetIconLoader(); | 339 scoped_refptr<ActivityIconLoader> icon_loader = GetIconLoader(); |
| 343 | 340 |
| 344 if (!instance || !icon_loader) { | 341 if (!instance || !icon_loader) { |
| 345 // ARC is not running anymore. Show the Chrome OS dialog. | 342 // ARC is not running anymore. Show the Chrome OS dialog. |
| 346 ShowFallbackExternalProtocolDialog(render_process_host_id, routing_id, url); | 343 ShowFallbackExternalProtocolDialog(render_process_host_id, routing_id, url); |
| 347 return; | 344 return; |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 426 base::Bind(OnUrlHandlerList, render_process_host_id, routing_id, url)); | 423 base::Bind(OnUrlHandlerList, render_process_host_id, routing_id, url)); |
| 427 return true; | 424 return true; |
| 428 } | 425 } |
| 429 | 426 |
| 430 bool ShouldIgnoreNavigationForTesting(ui::PageTransition page_transition) { | 427 bool ShouldIgnoreNavigationForTesting(ui::PageTransition page_transition) { |
| 431 return ShouldIgnoreNavigation(page_transition); | 428 return ShouldIgnoreNavigation(page_transition); |
| 432 } | 429 } |
| 433 | 430 |
| 434 GetActionResult GetActionForTesting( | 431 GetActionResult GetActionForTesting( |
| 435 const GURL& original_url, | 432 const GURL& original_url, |
| 436 const mojo::Array<mojom::IntentHandlerInfoPtr>& handlers, | 433 const std::vector<mojom::IntentHandlerInfoPtr>& handlers, |
| 437 size_t selected_app_index, | 434 size_t selected_app_index, |
| 438 std::pair<GURL, std::string>* out_url_and_package) { | 435 std::pair<GURL, std::string>* out_url_and_package) { |
| 439 return GetAction(original_url, handlers, selected_app_index, | 436 return GetAction(original_url, handlers, selected_app_index, |
| 440 out_url_and_package); | 437 out_url_and_package); |
| 441 } | 438 } |
| 442 | 439 |
| 443 GURL GetUrlToNavigateOnDeactivateForTesting( | 440 GURL GetUrlToNavigateOnDeactivateForTesting( |
| 444 const mojo::Array<mojom::IntentHandlerInfoPtr>& handlers) { | 441 const std::vector<mojom::IntentHandlerInfoPtr>& handlers) { |
| 445 return GetUrlToNavigateOnDeactivate(handlers); | 442 return GetUrlToNavigateOnDeactivate(handlers); |
| 446 } | 443 } |
| 447 | 444 |
| 448 } // namespace arc | 445 } // namespace arc |
| OLD | NEW |